EekBoek-2.030.1/0000755000400000040000000000000013151742350010761 5ustar jvjvEekBoek-2.030.1/lib/0000755000400000040000000000000013151742350011527 5ustar jvjvEekBoek-2.030.1/lib/EekBoek.pm0000644000400000040000000000334112725476602013405 0ustar jvjv#! perl package EekBoek; # NOTE: This is a documentation-only module. use strict; use utf8; # Minimal version to prevent many Unicode bugs. use 5.008003; require EB::Version; our $PACKAGE = 'EekBoek'; our $VERSION = $EB::Version::VERSION; =head1 NAME EekBoek - Bookkeeping software for small and medium-size businesses =head1 SYNOPSIS EekBoek is a bookkeeping package for small and medium-size businesses. Unlike other accounting software, EekBoek has both a command-line interface (CLI) and a graphical user-interface (GUI). Furthermore, it has a complete Perl API to create your own custom applications. EekBoek is designed for the Dutch/European market and currently available in Dutch only. An English translation is in the works (help appreciated). =head1 DESCRIPTION For a description how to use the program, see L. =head1 BUGS AND PROBLEMS Please use the eekboek-users mailing list at SourceForge. =head1 AUTHOR AND CREDITS Johan Vromans (jvromans@squirrel.nl) wrote this module. Web site: L. =head1 COPYRIGHT AND DISCLAIMER This program is Copyright 2005-2011 by Squirrel Consultancy. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of either: a) the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version, or b) the "Artistic License" which comes with Perl. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See either the GNU General Public License or the Artistic License for more details. =cut 1; EekBoek-2.030.1/lib/EB.pm0000644000400000040000000001155713151740560012365 0ustar jvjv#! perl -- -*- coding: utf-8 -*- use utf8; # EB.pm -- EekBoek Base module. # Author : Johan Vromans # Created On : Fri Sep 16 18:38:45 2005 # Last Modified By: Johan Vromans # Last Modified On: Thu Aug 31 09:57:36 2017 # Update Count : 331 # Status : Unknown, Use with caution! package main; our $app; our $cfg; package EB; use strict; use base qw(Exporter); use EekBoek; our @EXPORT; our @EXPORT_OK; # Establish location of our run-time resources. my $lib; sub libfile { my ($f) = @_; unless ( $lib ) { # Packaged. if ( $App::Packager::PACKAGED ) { return App::Packager::GetResourcePath()."/$f"; } else { $lib = $INC{"EB.pm"}; $lib =~ s/EB\.pm$//; } } $lib."EB/res/$f"; } sub findlib { my ( $file, $section ) = @_; # The two-argument form supports locale-dependent paths, but # we hard-wire this to 'nl'. if ( $section ) { my $lang = 'nl'; my $found = findlib( "$section/$lang/$file" ); return $found if $found; $found = findlib( "$section/$file" ); return $found if $found; return undef; } # Packaged. if ( $App::Packager::PACKAGED ) { my $found = App::Packager::GetUserFile($file); return $found if -e $found; $found = App::Packager::GetResource($file); return $found if -e $found; } foreach ( @INC ) { return "$_/EB/user/$file" if -e "$_/EB/user/$file"; return "$_/EB/res/$file" if -e "$_/EB/res/$file"; return "$_/EB/$file" if -e "$_/EB/$file"; } undef; } use lib ( grep { defined } findlib("CPAN") ); # Some standard modules (locale-free). use EB::Globals; use Carp; use Data::Dumper; use EB::Utils; # We need a glob() that deals with spaces. use File::Glob ( $] >= 5.016 ? ":bsd_glob" : ":glob" ); # Even though we do not use translations, most of the code is in place. sub _T { $_[0] } # Export our and the imported globals. @EXPORT = ( @EB::Globals::EXPORT, @EB::Utils::EXPORT, "_T", qw(carp croak confess), # Carp qw(glob), # File::Glob qw(Dumper), # Data::Dumper qw(findlib libfile), # ); our $ident; our $imsg; my $imsg_saved; our $url = "http://www.eekboek.nl"; sub __init__ { $imsg_saved = $imsg || ""; my $year = 2005; my $thisyear = (localtime(time))[5] + 1900; $year .= "-$thisyear" unless $year == $thisyear; $ident = __x("{name} {version}", name => $EekBoek::PACKAGE, version => $EekBoek::VERSION); $imsg = __x("{ident}{extra} -- Copyright {year} Squirrel Consultancy", ident => $ident, extra => ($app ? " Wx" : ""), year => $year); if ( $imsg ne $imsg_saved && !( @ARGV && $ARGV[0] =~ /-(P|-?printconfig)$/ ) ) { warn($imsg, "\n"); } eval { require Win32; my @a = Win32::GetOSVersion(); my ($id, $major) = @a[4,1]; die unless defined $id; warn(_T("EekBoek is VRIJE software, ontwikkeld om vrij over uw eigen gegevens te kunnen beschikken.")."\n"); warn(_T("Met uw keuze voor het Microsoft Windows besturingssysteem geeft u echter alle vrijheden weer uit handen. Dat is erg triest.")."\n"); } unless $imsg_saved eq $imsg || $ENV{AUTOMATED_TESTING}; } sub app_init { shift; # 'EB' # Load a config file. require EB::Config; undef $::cfg; EB::Config->init_config( @_ ); # Main initialisation. __init__(); # Initialise locale-dependent formats. require EB::Format; EB::Format->init_formats(); return $::cfg; # until we've got something better } sub EB::Config::Handler::connect_db { # Connect to the data base. require EB::DB; EB::DB::->connect; } 1; __END__ =head1 NAME EB - EekBoek * Bookkeeping software for small and medium-size businesses =head1 SYNOPSIS EekBoek is a bookkeeping package for small and medium-size businesses. Unlike other accounting software, EekBoek has both a command-line interface (CLI) and a graphical user-interface (GUI). Furthermore, it has a complete Perl API to create your own custom applications. =head1 DESCRIPTION For a description how to use the program, see L. =head1 BUGS AND PROBLEMS Please use the eekboek-users mailing list at SourceForge. =head1 AUTHOR AND CREDITS Johan Vromans (jvromans@squirrel.nl) wrote this module. Web site: L. =head1 COPYRIGHT AND DISCLAIMER This program is Copyright 2005-2011 by Squirrel Consultancy. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of either: a) the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version, or b) the "Artistic License" which comes with Perl. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See either the GNU General Public License or the Artistic License for more details. EekBoek-2.030.1/lib/EB/0000755000400000040000000000000013151742350012015 5ustar jvjvEekBoek-2.030.1/lib/EB/Report/0000755000400000040000000000000013151742350013270 5ustar jvjvEekBoek-2.030.1/lib/EB/Report/Grootboek/0000755000400000040000000000000013151742350015223 5ustar jvjvEekBoek-2.030.1/lib/EB/Report/Grootboek/Wxhtml.pm0000644000400000040000000000205512725476602017060 0ustar jvjv#! perl # Author : Johan Vromans # Created On : Thu Mar 6 14:36:36 2008 # Last Modified By: Johan Vromans # Last Modified On: Sat Jun 19 00:36:54 2010 # Update Count : 12 # Status : Unknown, Use with caution! package EB::Report::Grootboek::Wxhtml; use strict; use warnings; use base qw(EB::Report::Reporter::WxHtml); sub style { my ($self, $row, $cell) = @_; my $stylesheet = { d => { bsk => { link => "jnl://" }, desc => { indent => 2 }, }, h1 => { _style => { colour => 'red', size => '+2', } }, h2 => { _style => { colour => 'red' }, desc => { indent => 1,}, }, t1 => { _style => { colour => 'blue', size => '+1', } }, t2 => { _style => { colour => 'blue' }, desc => { indent => 1 }, }, tm => { _style => { colour => 'red', size => '+2', } }, tg => { _style => { colour => 'blue' } }, }; $cell = "_style" unless defined($cell); return $stylesheet->{$row}->{$cell}; } 1; EekBoek-2.030.1/lib/EB/Report/BTWAangifte/0000755000400000040000000000000013151742350015363 5ustar jvjvEekBoek-2.030.1/lib/EB/Report/BTWAangifte/Wxhtml.pm0000644000400000040000000000200612725476602017214 0ustar jvjv#! perl # Wxhtml.pm -- WxHtml backend for BTW Aangifte # Author : Johan Vromans # Created On : Thu Mar 6 14:20:53 2008 # Last Modified By: Johan Vromans # Last Modified On: Sat Jun 19 00:33:22 2010 # Update Count : 12 # Status : Unknown, Use with caution! package EB::Report::BTWAangifte::Wxhtml; use strict; use warnings; use base qw(EB::Report::Reporter::WxHtml); sub style { my ($self, $row, $cell) = @_; my $stylesheet = { h1 => { _style => { weight => 'bold', size => '+2',}, num => { colspan => 2 }, }, h2 => { _style => { weight => 'bold' }, num => { colspan => 2 }, }, }; $cell = "_style" unless defined($cell); return $stylesheet->{$row}->{$cell}; } sub finish { my $self = shift; if ( @_ ) { $self->_print("\n"); $self->_print("

\n"); $self->_print(join("
\n", map { $self->html($_) } @_) ); $self->_print("

\n"); $self->_print("\n"); } $self->SUPER::finish; } 1; EekBoek-2.030.1/lib/EB/Report/Open/0000755000400000040000000000000013151742350014171 5ustar jvjvEekBoek-2.030.1/lib/EB/Report/Open/Wxhtml.pm0000644000400000040000000000166712725476602016036 0ustar jvjv#! perl # Author : Johan Vromans # Created On : Thu Mar 6 14:36:36 2008 # Last Modified By: Johan Vromans # Last Modified On: Tue Oct 26 14:14:32 2010 # Update Count : 12 # Status : Unknown, Use with caution! package EB::Report::Open::Wxhtml; use strict; use warnings; use base qw(EB::Report::Reporter::WxHtml); sub style { my ($self, $row, $cell) = @_; my $stylesheet = { tdebcrd => { _style => { colour => 'red' }, }, trelatie => { _style => { colour => 'blue' }, }, data => { bsk => { link => "jnl://" }, }, cdata => { bsk => { link => "jnl://" }, rel => { link => "crd://" }, }, ddata => { bsk => { link => "jnl://" }, rel => { link => "deb://" }, }, prevdata => { bsk => { colour => 'red' }, }, }; $cell = "_style" unless defined($cell); return $stylesheet->{$row}->{$cell}; } 1; EekBoek-2.030.1/lib/EB/Report/Balres.pm0000644000400000040000000002142113044346163015041 0ustar jvjv#! perl package main; our $cfg; our $dbh; package EB::Report::Balres; # Author : Johan Vromans # Created On : Sat Jun 11 13:44:43 2005 # Last Modified By: Johan Vromans # Last Modified On: Fri Feb 7 21:42:15 2014 # Update Count : 424 # Status : Unknown, Use with caution! ################ Common stuff ################ use strict; use warnings; ################ The Process ################ use EB; use EB::Report; use EB::Format; ################ Subroutines ################ sub new { my ($class, $opts) = @_; $class = ref($class) || $class; $opts = {} unless $opts; bless { %$opts }, $class; } sub balans { my ($self, $opts) = @_; $opts->{balans} = 1; $self->perform($opts); } sub openingsbalans { my ($self, $opts) = @_; $opts->{balans} = -1; $self->perform($opts); } sub result { my ($self, $opts) = @_; $opts->{balans} = 0; $self->perform($opts); } sub perform { my ($self, $opts) = @_; my $balans = $opts->{balans}; my $opening = $opts->{opening}; my $detail = $opts->{detail}; $detail = $opts->{verdicht} ? 2 : -1 unless defined $detail; $opts->{detail} = $detail; my $dtot = 0; my $ctot = 0; $opts->{STYLE} = $opts->{balans} ? "balans" : "result"; $opts->{LAYOUT} = [ { name => "acct", title => _T("RekNr"), width => 6 }, { name => "desc", title => $detail >= 0 ? _T("Verdichting/Grootboekrekening") : _T("Grootboekrekening"), width => 40 }, { name => "deb", title => _T("Debet"), width => $amount_width, align => ">" }, { name => "crd", title => _T("Credit"), width => $amount_width, align => ">" }, ]; my $rep = EB::Report::GenBase->backend($self, $opts); my ($begin, $end) = @{$rep->{periode}}; my $now = $opts->{per} || $end; #### CHECK: $end is already always $opt->{per} if ( my $t = $cfg->val(qw(internal now), 0) ) { $now = $t if $t lt $now; } $now = iso8601date() if $now gt iso8601date(); $rep->{periodex} = 1 if $rep->{periodex} == 3 && $opts->{balans}; my $sth; my $rr; my $table = "Accounts"; my $need_rollback = 0; if ( $balans < 0 ) { my $date = $dbh->adm("begin"); $rep->start(_T("Openingsbalans"), __x("Datum: {date}", date => datefmt_full($now))); } elsif ( $opening ) { my $date = $begin; $rep->start(_T("Openingsbalans"), __x("Datum: {date}", date => datefmt_full($date))); $dbh->begin_work; $need_rollback++; $table = EB::Report->GetTAccountsBal($date, 1); } else { $dbh->begin_work; $need_rollback++; if ( $balans ) { $table = EB::Report->GetTAccountsBal($end); } elsif ( !$balans ) { $table = EB::Report->GetTAccountsRes($begin, $end); } $rep->start($balans ? _T("Balans") : _T("Verlies/Winst")); } my $sql = "SELECT acc_id, acc_desc, acc_balance, acc_ibalance, acc_debcrd, acc_dcfixed". " FROM ${table}"; if ( $balans ) { $sql .= " WHERE acc_balres". " AND acc_balance <> 0"; $sql .= " AND acc_struct = ?" if $detail >= 0; } else { $sql .= ",Journal". " WHERE acc_id = jnl_acc_id". " AND jnl_date >= '$begin' AND jnl_date <= '$end'". " AND NOT acc_balres". " AND acc_balance <> acc_ibalance"; $sql .= " AND acc_struct = ?" if $detail >= 0; $sql =~ /SELECT\s+(.*)\s+FROM/; $sql .= " GROUP BY $1"; } $sql .= " ORDER BY acc_id"; if ( $detail >= 0 ) { # Verdicht my @vd; my @hvd; $sth = $dbh->sql_exec("SELECT vdi_id, vdi_desc". " FROM Verdichtingen". " WHERE".($balans ? "" : " NOT")." vdi_balres". " AND vdi_struct IS NULL". " ORDER BY vdi_id"); while ( $rr = $sth->fetchrow_arrayref ) { $hvd[$rr->[0]] = [ @$rr, []]; } $sth->finish; @vd = @hvd; $sth = $dbh->sql_exec("SELECT vdi_id, vdi_desc, vdi_struct". " FROM Verdichtingen". " WHERE".($balans ? "" : " NOT")." vdi_balres". " AND vdi_struct IS NOT NULL". " ORDER BY vdi_id"); while ( $rr = $sth->fetchrow_arrayref ) { push(@{$hvd[$rr->[2]]->[2]}, [@$rr]); @vd[$rr->[0]] = [@$rr]; } $sth->finish; foreach my $hvd ( @hvd ) { next unless defined $hvd; my $did_hvd = 0; my $dstot = 0; my $cstot = 0; foreach my $vd ( @{$hvd->[2]} ) { my $did_vd = 0; $sth = $dbh->sql_exec($sql, $vd->[0]); my $dsstot = 0; my $csstot = 0; while ( $rr = $sth->fetchrow_arrayref ) { $rep->add({ _style => 'h1', acct => $hvd->[0], desc => $hvd->[1], }) unless $detail < 1 || $did_hvd++; $rep->add({ _style => 'h2', acct => $vd->[0], desc => $vd->[1] }) unless $detail < 2 || $did_vd++; my ($acc_id, $acc_desc, $acc_balance, $acc_ibalance, $acc_debcrd, $acc_dcfixed) = @$rr; $acc_balance -= $acc_ibalance unless $opts->{balans}; $acc_balance = -$acc_balance if $acc_dcfixed && !$acc_debcrd; if ( $acc_dcfixed ? $acc_debcrd : ($acc_balance >= 0) ) { $dsstot += $acc_balance; $rep->add({ _style => 'd2', acct => $acc_id, desc => $acc_desc, deb => numfmt($acc_balance), }) if $detail >= 2; } else { $acc_balance = -$acc_balance unless $acc_dcfixed; $csstot += $acc_balance; $rep->add({ _style => 'd2', acct => $acc_id, desc => $acc_desc, crd => numfmt($acc_balance), }) if $detail >= 2; } } $sth->finish; if ( $detail >= 1 && ($csstot || $dsstot) ) { $rep->add({ _style => 't2', acct => $vd->[0], desc => ($detail > 1 ? __x("Totaal {vrd}", vrd => $vd->[1]) : $vd->[1]), $dsstot >= $csstot ? ( deb => numfmt($dsstot-$csstot)) : ( crd => numfmt($csstot-$dsstot) ), }); } $cstot += $csstot-$dsstot if $csstot>$dsstot; $dstot += $dsstot-$csstot if $dsstot>$csstot; } if ( $detail >= 0 && ($cstot || $dstot) ) { $rep->add({ _style => 't1', acct => $hvd->[0], desc => ($detail > 0 ? __x("Totaal {vrd}", vrd => $hvd->[1]) : $hvd->[1]), $dstot >= $cstot ? ( deb => numfmt($dstot-$cstot) ) : ( crd => numfmt($cstot-$dstot) ), }); } $ctot += $cstot-$dstot if $cstot>$dstot; $dtot += $dstot-$cstot if $dstot>$cstot; } } else { # Op Grootboek $sth = $dbh->sql_exec($sql); while ( $rr = $sth->fetchrow_arrayref ) { my ($acc_id, $acc_desc, $acc_balance, $acc_ibalance, $acc_debcrd, $acc_dcfixed) = @$rr; #warn("|", join("|", @$rr), "|\n"); $acc_balance -= $acc_ibalance unless $opts->{balans}; $acc_balance = -$acc_balance if $acc_dcfixed && !$acc_debcrd; if ( $acc_dcfixed ? $acc_debcrd : ($acc_balance >= 0) ) { $dtot += $acc_balance; $rep->add({ _style => 'd', acct => $acc_id, desc => $acc_desc, deb => numfmt($acc_balance), }); } else { $acc_balance = -$acc_balance unless $acc_dcfixed; $ctot += $acc_balance; $rep->add({ _style => 'd', acct => $acc_id, desc => $acc_desc, crd => numfmt($acc_balance), }); } } $sth->finish; } my ($w, $v) = (_T("Winst"), _T("Verlies")); ($w, $v) = ($v, $w) unless $balans; if ( $dtot != $ctot ) { if ( $dtot >= $ctot ) { $rep->add({ _style => 'v', desc => "<< $w >>", crd => numfmt($dtot - $ctot), }); $ctot = $dtot; } else { $rep->add({ _style => 'v', desc => "<< $v >>", deb => numfmt($ctot - $dtot), }); $dtot = $ctot; } } $rep->add({ _style => 'grand', desc => __x("TOTAAL {rep}", rep => $balans ? _T("Balans") : _T("Resultaten")), deb => numfmt($dtot), crd => numfmt($ctot), }); $rep->finish; # Rollback temp table. $dbh->rollback if $need_rollback; } package EB::Report::Balres::Text; use EB; use base qw(EB::Report::Reporter::Text); sub new { my ($class, $opts) = @_; my $self = $class->SUPER::new($opts->{STYLE}, $opts->{LAYOUT}); $self->{detail} = $opts->{detail}; return $self; } # Style mods. sub style { my ($self, $row, $cell) = @_; my $stylesheet = { d2 => { desc => { indent => 2 }, }, h2 => { desc => { indent => 1 }, }, t1 => { _style => { skip_after => (1 <= $self->{detail}) }, }, t2 => { _style => { skip_after => (2 <= $self->{detail}) }, desc => { indent => 1 }, }, grand => { _style => { line_before => 1 } }, }; $cell = "_style" unless defined($cell); return $stylesheet->{$row}->{$cell}; } package EB::Report::Balres::Html; use EB; use base qw(EB::Report::Reporter::Html); sub new { my ($class, $opts) = @_; my $self = $class->SUPER::new($opts->{STYLE}, $opts->{LAYOUT}); return $self; } package EB::Report::Balres::Csv; use EB; use base qw(EB::Report::Reporter::Csv); sub new { my ($class, $opts) = @_; $class->SUPER::new($opts->{STYLE}, $opts->{LAYOUT}); } 1; EekBoek-2.030.1/lib/EB/Report/Balres/0000755000400000040000000000000013151742350014500 5ustar jvjvEekBoek-2.030.1/lib/EB/Report/Balres/Wxhtml.pm0000644000400000040000000000223212725476602016332 0ustar jvjv#! perl # Wxhtml.pm -- WxHtml backend for Balans/Result reports # Author : Johan Vromans # Created On : Thu Feb 7 14:20:53 2008 # Last Modified By: Johan Vromans # Last Modified On: Sat Jun 19 00:34:10 2010 # Update Count : 7 # Status : Unknown, Use with caution! package EB::Report::Balres::Wxhtml; use strict; use warnings; use base qw(EB::Report::Reporter::WxHtml); sub style { my ($self, $row, $cell) = @_; my $stylesheet = { d => { acct => { link => "gbk://" }, }, d2 => { acct => { link => "gbk://" }, desc => { indent => 2 }, }, h1 => { _style => { colour => 'red', size => '+2', } }, h2 => { _style => { colour => 'red' }, desc => { indent => 1,}, }, t1 => { _style => { colour => 'blue', size => '+1', } }, t2 => { _style => { colour => 'blue' }, desc => { indent => 1 }, }, v => { _style => { colour => 'red', size => '+2', } }, grand => { _style => { colour => 'blue' } }, }; $cell = "_style" unless defined($cell); return $stylesheet->{$row}->{$cell}; } 1; EekBoek-2.030.1/lib/EB/Report/Journal/0000755000400000040000000000000013151742350014702 5ustar jvjvEekBoek-2.030.1/lib/EB/Report/Journal/Wxhtml.pm0000644000400000040000000000302713044346163016530 0ustar jvjv#! perl # Wxhtml.pm -- WxHtml backend for Journal reports. # Author : Johan Vromans # Created On : Thu Feb 7 14:21:31 2008 # Last Modified By: Johan Vromans # Last Modified On: Fri Oct 9 20:13:02 2015 # Update Count : 11 # Status : Unknown, Use with caution! package EB::Report::Journal::Wxhtml; use strict; use warnings; use base qw(EB::Report::Reporter::WxHtml); sub style { my ($self, $row, $cell) = @_; my $stylesheet = { head => { _style => { colour => 'red' }, }, chead => { _style => { colour => 'red' }, rel => { link => "crd://" }, }, cheada => { _style => { colour => 'red' }, desc => { att => "att://" }, rel => { link => "crd://" }, }, dhead => { _style => { colour => 'red' }, rel => { link => "deb://" }, }, dheada => { _style => { colour => 'red' }, desc => { att => "att://" }, rel => { link => "deb://" }, }, total => { _style => { colour => 'blue', } }, data => { desc => { indent => '+2' }, acct => { link => "gbk://" }, bsk => { indent => '+2' }, }, cdata => { desc => { indent => '+2' }, acct => { link => "gbk://" }, bsk => { indent => '+2' }, rel => { link => "crd://" }, }, ddata => { desc => { indent => '+2' }, acct => { link => "gbk://" }, bsk => { indent => '+2' }, rel => { link => "deb://" }, }, }; $cell = "_style" unless defined($cell); return $stylesheet->{$row}->{$cell}; } 1; EekBoek-2.030.1/lib/EB/Report/Proof.pm0000644000400000040000000002161512725476602014732 0ustar jvjv#! perl package main; our $cfg; our $dbh; package EB::Report::Proof; # Author : Johan Vromans # Created On : Sat Jun 11 13:44:43 2005 # Last Modified By: Johan Vromans # Last Modified On: Sat Jun 19 00:39:09 2010 # Update Count : 306 # Status : Unknown, Use with caution! ################ Common stuff ################ use strict; use warnings; ################ The Process ################ use EB; use EB::Format; use EB::Report; ################ Subroutines ################ sub new { my ($class, $opts) = @_; $class = ref($class) || $class; $opts = {} unless $opts; bless { %$opts }, $class; } sub proefensaldibalans { my ($self, $opts) = @_; $self->perform($opts); } sub perform { my ($self, $opts) = @_; my $detail = $opts->{detail}; $detail = $opts->{verdicht} ? 2 : -1 unless defined $detail; $opts->{proef} = 1; $opts->{detail} = $detail; my @grand = (0) x 4; # grand total $opts->{STYLE} = "proef"; $opts->{LAYOUT} = [ { name => "acct", title => _T("RekNr"), width => 6, }, { name => "desc", title => $detail >= 0 ? _T("Verdichting/Grootboekrekening") : _T("Grootboekrekening"), width => 40, }, { name => "deb", title => _T("Debet"), width => $amount_width, align => ">", }, { name => "crd", title => _T("Credit"), width => $amount_width, align => ">", }, { name => "sdeb", title => _T("Saldo Db"), width => $amount_width, align => ">" }, { name => "scrd", title => _T("Saldo Cr"), width => $amount_width, align => ">" }, ]; my $rep = EB::Report::GenBase->backend($self, $opts); my $rr; $rep->{periodex} = 1; my ($begin, $end) = @{$rep->{periode}}; $dbh->begin_work; my $table = EB::Report->GetTAccountsAll($begin, $end); $rep->start(_T("Proef- en Saldibalans")); my $sth; my $hvd_hdr; my $vd_hdr; my $journaal = sub { my ($acc_id, $acc_desc, $acc_ibalance) = @_; my @tot = (0) x 4; my $did = 0; if ( $acc_ibalance ) { $did++; if ( $acc_ibalance < 0 ) { $tot[1] = -$acc_ibalance; } else { $tot[0] = $acc_ibalance; } # $rep->addline('D2', '', _T("Beginsaldo"), @tot); } my $sth = $dbh->sql_exec ("SELECT jnl_amount,jnl_desc". " FROM Journal". " WHERE jnl_acc_id = ?". " AND jnl_date >= ? AND jnl_date <= ?". " ORDER BY jnl_bsr_date", $acc_id, $begin, $end, ); while ( my $rr = $sth->fetchrow_arrayref ) { my ($amount, $desc) = @$rr; $did++; my @t = (0) x 4; $t[$amount<0] += abs($amount); # $rep->addline('D2', '', $desc, @t); $tot[$_] += $t[$_] foreach 0..$#tot; } if ( $tot[0] >= $tot[1] ) { $tot[2] = $tot[0] - $tot[1]; $tot[3] = 0; } else { $tot[3] = $tot[1] - $tot[0]; $tot[2] = 0; } $tot[0] ||= "00" if $did; $tot[1] ||= "00" if $did; @tot; }; my $grootboeken = sub { my ($vd, $hvd) = shift; my @tot = (0) x 4; my $sth = $dbh->sql_exec ("SELECT acc_id, acc_desc, acc_balance, acc_ibalance". " FROM ${table}". " WHERE acc_struct = ?". " AND ( acc_ibalance <> 0". " OR acc_id IN ( SELECT DISTINCT jnl_acc_id FROM Journal". " WHERE jnl_date >= ? AND jnl_date <= ? ))". " ORDER BY acc_id", $vd->[0], $begin, $end); while ( my $rr = $sth->fetchrow_arrayref ) { my ($acc_id, $acc_desc, $acc_balance, $acc_ibalance) = @$rr; my @t = $journaal->($acc_id, $acc_desc, $acc_ibalance); next if "@t" eq "0 0 0 0"; $tot[$_] += $t[$_] foreach 0..$#tot; next unless $detail > 1; if ( $hvd_hdr ) { $rep->add({ acct => $hvd_hdr->[0], desc => $hvd_hdr->[1], _style => 'h1', }); undef $hvd_hdr; } if ( $vd_hdr ) { $rep->add({ acct => $vd_hdr->[0], desc => $vd_hdr->[1], _style => 'h2', }); undef $vd_hdr; } $rep->add({ _style => 'd2', acct => $acc_id, desc => $acc_desc, deb => numfmt($t[0]), crd => numfmt($t[1]), $t[2] ? ( sdeb => numfmt($t[2]) ) : (), $t[3] ? ( scrd => numfmt($t[3]) ) : (), }); } if ( $tot[0] >= $tot[1] ) { $tot[2] = $tot[0] - $tot[1]; $tot[3] = 0; } else { $tot[3] = $tot[1] - $tot[0]; $tot[2] = 0; } @tot; }; my $verdichtingen = sub { my ($hvd) = shift; my @tot = (0) x 4; my $did = 0; foreach my $vd ( @{$hvd->[2]} ) { next unless defined $vd; $vd_hdr = [ $vd->[0], $vd->[1] ]; my @t = $grootboeken->($vd, $hvd); next if "@t" eq "0 0 0 0"; $tot[$_] += $t[$_] foreach 0..$#tot; next unless $detail > 0; if ( $hvd_hdr ) { $rep->add({ acct => $hvd_hdr->[0], desc => $hvd_hdr->[1], _style => 'h1', }); undef $hvd_hdr; } $rep->add({ _style => 't2', acct => $vd->[0], desc => __x("Totaal {vrd}", vrd => $vd->[1]), $t[0] ? ( deb => numfmt($t[0]) ) : (), $t[1] ? ( crd => numfmt($t[1]) ) : (), $t[2] ? ( sdeb => numfmt($t[2]) ) : (), $t[3] ? ( scrd => numfmt($t[3]) ) : (), }); } if ( $tot[0] >= $tot[1] ) { $tot[2] = $tot[0] - $tot[1]; $tot[3] = 0; } else { $tot[3] = $tot[1] - $tot[0]; $tot[2] = 0; } @tot; }; my $hoofdverdichtingen = sub { my (@hvd) = @_; my @tot = (0) x 4; foreach my $hvd ( @hvd ) { next unless defined $hvd; $hvd_hdr = [ $hvd->[0], $hvd->[1] ]; my @t = $verdichtingen->($hvd); next if "@t" eq "0 0 0 0"; if ( $detail && $hvd_hdr ) { $rep->add({ acct => $hvd_hdr->[0], desc => $hvd_hdr->[1], _style => 'h1', }); undef $hvd_hdr; } $rep->add({ _style => 't1', acct => $hvd->[0], desc => __x("Totaal {vrd}", vrd => $hvd->[1]), $t[0] ? ( deb => numfmt($t[0]) ) : (), $t[1] ? ( crd => numfmt($t[1]) ) : (), $t[2] ? ( sdeb => numfmt($t[2]) ) : (), $t[3] ? ( scrd => numfmt($t[3]) ) : (), }); $tot[$_] += $t[$_] foreach 0..$#tot; } @tot; }; if ( $detail >= 0 ) { # Verdicht my @vd; my @hvd; $sth = $dbh->sql_exec("SELECT vdi_id, vdi_desc". " FROM Verdichtingen". " WHERE vdi_struct IS NULL". " ORDER BY vdi_id"); while ( $rr = $sth->fetchrow_arrayref ) { $hvd[$rr->[0]] = [ @$rr, []]; } @vd = @hvd; $sth = $dbh->sql_exec("SELECT vdi_id, vdi_desc, vdi_struct". " FROM Verdichtingen". " WHERE vdi_struct IS NOT NULL". " ORDER BY vdi_id"); while ( $rr = $sth->fetchrow_arrayref ) { push(@{$hvd[$rr->[2]]->[2]}, [@$rr]); @vd[$rr->[0]] = [@$rr]; } my @tot = $hoofdverdichtingen->(@hvd); $rep->add({ _style => 't', desc => _T("TOTAAL"), $tot[0] ? ( deb => numfmt($tot[0]) ) : (), $tot[1] ? ( crd => numfmt($tot[1]) ) : (), $tot[2] ? ( sdeb => numfmt($tot[2]) ) : (), $tot[3] ? ( scrd => numfmt($tot[3]) ) : (), }); } else { # Op Grootboek my @tot = (0) x 4; my $sth = $dbh->sql_exec ("SELECT acc_id, acc_desc, acc_balance, acc_ibalance". " FROM ${table}". " WHERE ( acc_ibalance <> 0". " OR acc_id IN ( SELECT DISTINCT jnl_acc_id FROM Journal". " WHERE jnl_date >= ? AND jnl_date <= ? ))". " ORDER BY acc_id", $begin, $end); while ( my $rr = $sth->fetchrow_arrayref ) { my ($acc_id, $acc_desc, $acc_balance, $acc_ibalance) = @$rr; my @t = $journaal->($acc_id, $acc_desc, $acc_ibalance); next if "@t" eq "0 0 0 0"; $tot[$_] += $t[$_] foreach 0..$#tot; $rep->add({ _style => 'd', acct => $acc_id, desc => $acc_desc, deb => numfmt($t[0]), crd => numfmt($t[1]), $t[2] ? ( sdeb => numfmt($t[2]) ) : (), $t[3] ? ( scrd => numfmt($t[3]) ) : (), }); } $rep->add({ _style => 't', desc => _T("TOTAAL"), deb => numfmt($tot[0]), crd => numfmt($tot[1]), $tot[2] ? ( sdeb => numfmt($tot[2]) ) : (), $tot[3] ? ( scrd => numfmt($tot[3]) ) : (), }); } $rep->finish; $dbh->rollback; } package EB::Report::Proof::Text; use EB; use base qw(EB::Report::Reporter::Text); sub new { my ($class, $opts) = @_; my $self = $class->SUPER::new($opts->{STYLE}, $opts->{LAYOUT}); $self->{detail} = $opts->{detail}; $self; } # Style mods. sub style { my ($self, $row, $cell) = @_; my $stylesheet = { d2 => { desc => { indent => 2 }, }, t2 => { _style => { skip_after => $self->{detail} > 1, }, desc => { indent => 1 }, }, h2 => { desc => { indent => 1 }, }, t1 => { _style => { skip_after => $self->{detail} > 0, skip_before => $self->{detail} > 1, }, }, t => { _style => { line_before => 1 } }, }; $cell = "_style" unless defined($cell); return $stylesheet->{$row}->{$cell}; } package EB::Report::Proof::Csv; use EB; use base qw(EB::Report::Reporter::Csv); sub new { my ($class, $opts) = @_; $class->SUPER::new($opts->{STYLE}, $opts->{LAYOUT}); } package EB::Report::Proof::Html; use EB; use base qw(EB::Report::Reporter::Html); use strict; sub new { my ($class, $opts) = @_; $class->SUPER::new($opts->{STYLE}, $opts->{LAYOUT}); } 1; EekBoek-2.030.1/lib/EB/Report/GenBase.pm0000644000400000040000000001633113151741117015136 0ustar jvjv#! perl -- -*- coding: utf-8 -*- use utf8; # Author : Johan Vromans # Created On : Sat Oct 8 16:40:43 2005 # Last Modified By: Johan Vromans # Last Modified On: Thu Aug 31 10:01:19 2017 # Update Count : 179 # Status : Unknown, Use with caution! package main; our $cfg; our $dbh; package EB::Report::GenBase; use strict; use EB; use IO::File; use EB::Format; sub new { my ($class, $opts) = @_; $class = ref($class) || $class; my $self = { %$opts }; bless $self => $class; } # API. sub _oops { warn("?Package ".ref($_[0])." did not implement '$_[1]' method\n") } sub start { shift->_oops('start') } sub outline { shift->_oops('outline') } sub finish { shift->_oops('finish') } # Class methods sub backend { my (undef, $self, $opts) = @_; my %extmap = ( txt => "text", htm => "html" ); my $gen; # Short options, like --html. for ( qw(html csv text) ) { $gen = $_ if $opts->{$_}; } # Override by explicit --gen-XXX option(s). foreach ( keys(%$opts) ) { next unless /^gen-(.*)$/; $gen = $1; } # Override by explicit --generate option(s). $gen = $opts->{generate} if $opts->{generate}; # Infer from filename extension. my $t; if ( !defined($gen) && ($t = $opts->{output}) && $t =~ /\.([^.]+)$/ ) { my $ext = lc($1); $ext = $extmap{$ext} || $ext; $gen = $ext; } # Fallback to text. $gen ||= "text"; # Build class and package name. Last chance to override... my $class = $opts->{backend} || (ref($self)||$self) . "::" . ucfirst($gen); my $pkg = $class; $pkg =~ s;::;/;g;; $pkg .= ".pm"; # Try to load backend. Gives user the opportunity to override. eval { local $SIG{__WARN__}; local $SIG{__DIE__}; require $pkg; } unless $ENV{AUTOMATED_TESTING}; if ( ! _loaded($class) ) { my $err = $@; if ( $err =~ /^can't locate /i ) { $err = _T("De uitvoer-backend kon niet worden gevonden"); } die("?".__x("Uitvoer in de vorm {gen} is niet mogelijk: {reason}", gen => $gen, reason => $err)."\n"); } my $be = $class->new($opts); # Handle output redirection. if ( $opts->{output} && $opts->{output} ne '-' ) { $be->{fh} = IO::File->new($opts->{output}, "w") or die("?".__x("Fout tijdens aanmaken {file}: {err}", file => $opts->{output}, err => $!)."\n"); } elsif ( fileno(STDOUT) > 0 ) { # Normal file. $be->{fh} = IO::File->new_from_fd(fileno(STDOUT), "w"); } else { # In-memory. $be->{fh} = bless \*STDOUT , 'IO::Handle'; } binmode($be->{fh}, ":encoding(utf8)"); # Handle pagesize. $be->{fh}->format_lines_per_page($be->{page} = defined($opts->{page}) ? $opts->{page} : 999999); # Get real (or fake) current date, and adjust periode end if needed. $be->{now} = iso8601date(); if ( my $t = $cfg->val(qw(internal now), 0) ) { $be->{now} = $t if $be->{now} gt $t; } # Date/Per. if ( $opts->{per} ) { die(_T("--per sluit --periode uit")."\n") if $opts->{periode}; die(_T("--per sluit --boekjaar uit")."\n") if defined $opts->{boekjaar}; $be->{periode} = [ $be->{per_begin} = $dbh->adm("begin"), $be->{per_end} = $opts->{per} ]; $be->{periodex} = 1; } elsif ( $opts->{periode} ) { die(_T("--periode sluit --boekjaar uit")."\n") if defined $opts->{boekjaar}; $be->{periode} = $opts->{periode}; $be->{per_begin} = $opts->{periode}->[0]; $be->{per_end} = $opts->{periode}->[1]; $be->{periodex} = 2; } elsif ( defined($opts->{boekjaar}) || defined($opts->{d_boekjaar}) ) { my $bky = $opts->{boekjaar}; $bky = $opts->{d_boekjaar} unless defined $bky; my $rr = $dbh->do("SELECT bky_begin, bky_end". " FROM Boekjaren". " WHERE bky_code = ?", $bky); die("?",__x("Onbekend boekjaar: {bky}", bky => $bky)."\n"), return unless $rr; my ($begin, $end) = @$rr; $be->{periode} = [ $be->{per_begin} = $begin, $be->{per_end} = $end ]; $be->{periodex} = 3; $be->{boekjaar} = $bky; } else { $be->{periode} = [ $be->{per_begin} = $dbh->adm("begin"), $be->{per_end} = $dbh->adm("end") ]; $be->{periodex} = 0; } if ( $be->{per_end} gt $be->{now} ) { warn("!".__x("Datum {per} valt na de huidige datum {now}", per => datefmt_full($be->{per_end}), now => datefmt_full($be->{now}))."\n") if 0; $be->{periode}->[1] = $be->{per_end} = $be->{now} if 0; } # Sanity. my $opendate = $dbh->do("SELECT min(bky_begin) FROM Boekjaren WHERE NOT bky_code = ?", BKY_PREVIOUS)->[0]; if ( $be->{per_begin} gt $be->{now} ) { die("?".__x("Periode begint {from}, dit is na de huidige datum {now}", from => datefmt_full($be->{per_begin}), now => datefmt_full($be->{now}))."\n"); } if ( $be->{per_begin} lt $opendate ) { die("?".__x("Datum {per} valt vóór het begin van de administratie {begin}", per => datefmt_full($be->{per_begin}), begin => datefmt_full($opendate))."\n"); } if ( $be->{per_end} lt $opendate ) { die("?".__x("Datum {per} valt vóór het begin van de administratie {begin}", per => datefmt_full($be->{per_end}), begin => datefmt_full($opendate))."\n"); } $be->{_cssdir} = $cfg->val(qw(html cssdir), undef); $be->{_cssdir} =~ s;/*$;/; if defined $be->{_cssdir}; $be->{_style} = $opts->{style} if $opts->{style}; $be->{_title0} = $opts->{title} if $opts->{title}; # Return instance. $be; } my %bec; sub backend_options { my (undef, $self, $opts) = @_; my $package = ref($self) || $self; my $pkg = $package; $pkg =~ s;::;/;g;; return @{$bec{$pkg}} if $bec{$pkg}; # Some standard backends may be included in the coding ... my %be; foreach my $std ( qw(text html csv) ) { $be{$std} = 1 if _loaded($package . "::" . ucfirst($std)); } #### FIXME: options dest is uncontrollable!!!! #### DO NOT TRANSLATE UNTIL FIXED !!!! my @opts = ( __xt("cmo:report:output")."=s", __xt("cmo:report:page")."=i" ); if ( $App::Packager::PACKAGED ) { $be{wxhtml}++; unless ( $be{wxhtml} ) { # Ignored, but forces the packager to include these modules. require EB::Report::BTWAangifte::Wxhtml; require EB::Report::Balres::Wxhtml; require EB::Report::Debcrd::Wxhtml; require EB::Report::Grootboek::Wxhtml; require EB::Report::Journal::Wxhtml; require EB::Report::Open::Wxhtml; require EB::Report::Proof::Wxhtml; } } else { # Find files. foreach my $lib ( @INC ) { my @files = glob("$lib/$pkg/*.pm"); next unless @files; # warn("=> be_opt: found ", scalar(@files), " files in $lib/$pkg\n"); foreach ( @files ) { next unless m;/([^/]+)\.pm$;; # Actually, we should check whether the class implements the # GenBase API, but we can't do that without preloading all # backends. $be{lc($1)}++; } } } # Short --XXX for known backends. foreach ( qw(html csv text) ) { push(@opts, $_) if $be{$_}; } push(@opts, __xt("cmo:report:style")."=s", __xt("cmo:report:title|titel")."=s") if $be{html}; # Explicit --gen-XXX for all backends. push(@opts, map { +"gen-$_"} keys %be); # Cache. $bec{$pkg} = [@opts]; @opts; # better be list context } # Helper. sub _loaded { my $class = shift; no strict "refs"; %{$class . "::"} ? 1 : 0; } 1; EekBoek-2.030.1/lib/EB/Report/BTWAangifte.pm0000644000400000040000000005431613044346163015735 0ustar jvjv#! perl -- -*- coding: utf-8 -*- use utf8; # Author : Johan Vromans # Created On : Tue Jul 19 19:01:33 2005 # Last Modified By: Johan Vromans # Last Modified On: Thu Jan 26 16:40:41 2017 # Update Count : 653 # Status : Unknown, Use with caution! ################ Common stuff ################ package main; our $cfg; our $dbh; package EB::Report::BTWAangifte; use strict; use warnings; use EB; use EB::Format; use EB::Booking; # for norm_btw() use POSIX qw(floor ceil); my $trace = $cfg->val(__PACKAGE__, "trace", undef); my $noround; my @periodetabel; sub new { my $class = shift; $class = ref($class) || $class; my $self = {}; bless $self, $class; $self->{"adm_$_"} = $dbh->adm($_) for qw(begin btwperiod); $self->{adm_btwperiod} ||= 1; unless ( $self->{adm_begin} ) { die("?"._T("De administratie is nog niet geopend")."\n"); } $self; } sub periodetabel { my ($self) = (@_); unless ( @periodetabel ) { @periodetabel = ( [] ) x 13; my @m; for ( 1 .. 12 ) { push(@m, [ sprintf("%02d-01", $_), sprintf("%02d-%02d", $_, ($_ & 1 xor $_ & 8) ? 31 : 30) ]); } $m[1][1] = substr($self->{adm_begin}, 0, 4) % 4 ? "02-28" : "02-29"; $periodetabel[12] = [ _T("per maand"), @m ]; $periodetabel[1] = [ _T("per jaar"), [$m[0][0], $m[11][1] ]]; $periodetabel[4] = [ _T("per kwartaal"), [$m[0][0], $m[2][1]], [$m[3][0], $m[5][1] ], [$m[6][0], $m[8][1]], [$m[9][0], $m[11][1]]]; } \@periodetabel; } use EB::Report::GenBase; sub perform { my ($self, $opts) = @_; $noround = $opts->{noround} || 0; # Determine the period to be used. # BTW report is slightly awkward. It takes the boekjaar into # account, also an explicitly specified period. But it can also # process a form of symbolic period, like "k1" or "m4". # Order of precedence: # 1. --period, # 2. symbolic period, depending on boekjaar, # 3. (default) next (or first) period in boekjaar. # Note that a possible --period / symbolic period conflict has # already been trapped in the shell. my $year = substr($dbh->adm("begin"), 0, 4); # default for now my $btwperiod = $self->{adm_btwperiod}; # Check symbolic period (excludes --period). if ( $opts->{compat_periode} ) { # Adjust current year, if applicable. if ( defined($opts->{boekjaar}) || defined($opts->{d_boekjaar}) ) { my $bky = $opts->{boekjaar}; $bky = $opts->{d_boekjaar} unless defined $bky; my $rr = $dbh->do("SELECT bky_begin". " FROM Boekjaren". " WHERE bky_code = ?", $bky); die("?",__x("Onbekend boekjaar: {bky}", bky => $bky)."\n"), return unless $rr; $year = substr($rr->[0], 0, 4); } # Parse the symbolic period. $self->parse_periode($opts->{compat_periode}, $year); # Store in --period. $opts->{periode} = [ $self->{p_start}, $self->{p_end} ]; # GenBase backend will disallow --period with boekjaar... delete($opts->{boekjaar}); } # No symbolic. So we have either a --period, or nothing. # The latter includes a possible --boekjaar ;-). elsif ( !defined($opts->{periode}) ) { # We have nothing. Adjust year to --boekjaar if applicable. if ( defined($opts->{boekjaar}) || defined($opts->{d_boekjaar}) ) { my $bky = $opts->{boekjaar}; $bky = $opts->{d_boekjaar} unless defined $bky; my $rr = $dbh->do("SELECT bky_begin". " FROM Boekjaren". " WHERE bky_code = ?", $bky); die("?",__x("Onbekend boekjaar: {bky}", bky => $bky)."\n"), return unless $rr; $year = substr($rr->[0], 0, 4); } my $tbl = $self->periodetabel->[$btwperiod]; if ( $btwperiod == 1 ) { # aangifteperiode => jaar $opts->{periode} = [ $year . "-" . $tbl->[1]->[0], $year . "-" . $tbl->[1]->[1] ]; $self->{compat_periode} = $self->periode(1, $year); } elsif ( 0 ) { # determine period depending on current date. my @tm = localtime(time); $tm[5] += 1900; my $m; if ( $year < 1900+$tm[5] ) { $m = $btwperiod; } else { $m = 1 + int($tm[4] / (12/$btwperiod)); } $opts->{periode} = [ $year . "-" . $tbl->[$m]->[0], $year . "-" . $tbl->[$m]->[1] ]; $self->{compat_periode} = $self->periode($btwperiod, $year, $m); } else { # determine period depending on previous aangifte my $next = $dbh->adm("btwbegin"); my $m; if ( substr($next, 0, 4) gt $year ) { $m = $btwperiod; } elsif ( substr($next, 0, 4) lt $year ) { $m = 1; } else { for ( $m = 1; $m <= 12; $m++ ) { last if substr($next, 5) eq $tbl->[$m]->[0]; } } $opts->{periode} = [ $year . "-" . $tbl->[$m]->[0], $year . "-" . $tbl->[$m]->[1] ]; $self->{compat_periode} = $self->periode($btwperiod, $year, $m); } delete($opts->{boekjaar}); } # else: we have an explicit --period. Nothing here to do. else { $self->{compat_periode} = ""; } $opts->{STYLE} = "btwaangifte"; # my $w = $amount_width + 1; # $self->{fh}->printf("%-5s%-40s%${w}s%${w}s\n", $opts->{LAYOUT} = [ { name => "_colsep", # neat? or trick? #sep => "|", width => 1 }, { name => "num", width => 4 }, { name => "desc", width => 40 }, { name => "col1", width => $amount_width, align => ">" }, { name => "col2", width => $amount_width, align => ">" }, ]; my $rep = EB::Report::GenBase->backend($self, $opts); unless ( $rep->{per_begin} eq $dbh->adm("btwbegin") ) { my $msg = _T("BTW aangifte periode sluit niet aan bij de vorige aangifte"); $opts->{close} ? die("?$msg\n") : warn("!$msg\n"); } unless ( $opts->{noreport} ) { my $data = $self->collect($rep->{per_begin}, $rep->{per_end}); $self->report($rep, $data); } if ( $opts->{close} ) { $dbh->adm("btwbegin", scalar parse_date($rep->{per_end}, undef, 1)); # implied commit } } sub periode { my ($self, $p, $year, $v) = @_; if ( $p == 1 ) { return __x("{year}", year => $year); } elsif ( $p == 4 ) { return __x("{quarter} {year}", quarter => (_T("1e kwartaal"), _T("2e kwartaal"), _T("3e kwartaal"), _T("4e kwartaal"))[$v-1], year => $year); } elsif ( $p == 12 ) { return __x("{month} {year}", month => _T( $EB::Utils::month_names[$v-1] ), year => $year); } else { die("?".__x("Programmafout: Ongeldige BTW periode: {per}", per => $p)."\n"); } } sub parse_periode { my ($self, $v, $year) = @_; my $pp = sub { my ($per, $n) = @_; unless ( $self->{adm_btwperiod} == $per ) { warn($self->{close} ? "?" :"!". __x("Aangifte {per} komt niet overeen met de BTW instelling". " van de administratie ({admper})", per => $self->periodetabel->[$per][0], admper => $self->periodetabel->[$self->{adm_btwperiod}][0], )."\n") } $self->{adm_btwperiod} = $per; my $tbl = $self->periodetabel->[$self->{adm_btwperiod}]; $self->{p_start} = $year . "-" . $tbl->[$n]->[0]; $self->{p_end} = $year . "-" . $tbl->[$n]->[1]; $self->{compat_periode} = $self->periode($per, $year, $n); if ( $per == $n ) { $self->{p_next} = ($year+1) . "-" . $tbl->[1]->[0]; } else { $self->{p_next} = $year . "-" . $tbl->[$n+1]->[0]; } }; my $yrpat = _T("j(aar)?"); if ( $v =~ /^$yrpat$|^j(aar)?$/i ) { $pp->(1, 1); return; } if ( $v =~ /^[kq](\d)$/i && $1 >= 1 && $1 <= 4) { $pp->(4, $1); return; } if ( $v =~ /^(\d+)$/i && $1 >= 1 && $1 <= 12) { $pp->(12, $1); return; } if ( $v =~ /^(\w+)$/i ) { my $i; for ( $i = 0; $i < 12; $i++ ) { last if lc($EB::Utils::month_names[$i]) eq lc($v); last if lc($EB::Utils::months[$i]) eq lc($v); } if ( $i < 12 ) { $pp->(12, $i+1); return; } } die("?".__x("Ongeldige waarde voor BTW periode: \"{per}\"", per => $v) . "\n"); } sub collect { my ($self, $begin, $end) = @_; my $v; my $tot = 0; # 1. Door mij verrichte leveringen/diensten # 1a. Belast met hoog tarief my $deb_h = 0; my $deb_btw_h = 0; # 1b. Belast met laag tarief my $deb_l = 0; my $deb_btw_l = 0; # 1c. Belast met ander, niet-nul tarief my $deb_a = 0; my $deb_btw_a = 0; # 1d. Eigen gebruik. my $deb_p = 0; my $deb_btw_p = 0; # 1e. Belast met 0%/verlegd my $deb_0 = 0; my $verlegd = 0; # 3. Door mij verrichte leveringen # 3a. Buiten de EU my $extra_deb = 0; # 3b. Binnen de EU my $intra_deb = 0; my $intra_deb_btw = 0; # 4. Aan mij verrichte leveringen # 4a. Van buiten de EU my $extra_crd = 0; # 4b. Verwervingen van goederen uit de EU. my $intra_crd = 0; my $intra_crd_btw = 0; # Totaaltellingen. my $crd_btw = 0; # BTW betaald (voorheffingen) my $xx = 0; # ongeclassificeerd (fout, dus) # Target: alle boekstukken van type 0 (inkoop/verkoop). my $sth = $dbh->sql_exec ("SELECT bsr_amount,bsr_acc_id,bsr_btw_id,bsr_btw_acc,bsr_btw_class,rel_debcrd,rel_btw_status". " FROM Boekstukregels, Relaties". " WHERE bsr_rel_code = rel_code AND bsr_dbk_id = rel_ledger". " AND bsr_date >= ? AND bsr_date <= ?". " AND bsr_type = 0". " UNION ALL ". "SELECT bsr_amount,bsr_acc_id,bsr_btw_id,bsr_btw_acc,bsr_btw_class,null as rel_debcrd,0 as rel_btw_status". " FROM Boekstukregels". " WHERE bsr_rel_code IS NULL". " AND bsr_date >= ? AND bsr_date <= ?". " AND bsr_type = 0", $begin, $end, $begin, $end); my $rr; my $tr = $trace ? sub { warn("BTW " . shift() . " " . join(" ", map { defined $_ ? $_ : "-" } @$rr). "\n"); } : sub {}; while ( $rr = $sth->fetchrow_arrayref ) { my ($amt, $acc, $btw_id, $btw_acc, $btwclass, $debcrd, $btw_status) = @$rr; next unless $btwclass & BTWKLASSE_BTW_BIT; my $btg_id = 0; my $btw = 0; $amt = -$amt; if ( $btw_id && $btw_acc ) { # Bepaal tariefgroep en splits bedrag uit. $btg_id = $dbh->lookup($btw_id, qw(BTWTabel btw_id btw_tariefgroep)); my $a = EB::Booking::->norm_btw($amt, $btw_id); $amt = $a->[0] - ($btw = $a->[1]); # ex BTW } unless ( defined $debcrd ) { $debcrd = !($btwclass & BTWKLASSE_KO_BIT); } if ( $btw_status == BTWTYPE_NORMAAL ) { if ( $debcrd ) { if ( $btg_id == BTWTARIEF_HOOG ) { $tr->("Hoog"); $deb_h += $amt; $deb_btw_h += $btw; } elsif ( $btg_id == BTWTARIEF_LAAG ) { $tr->("Laag"); $deb_l += $amt; $deb_btw_l += $btw; } elsif ( $btg_id == BTWTARIEF_NUL ) { $tr->("0%"); $deb_0 += $amt; } elsif ( $btg_id == BTWTARIEF_PRIV ) { $tr->("Privé"); $deb_p += $amt; $deb_btw_p += $btw; } else { confess( "BTWTARIEF NOT ANDERS" ) unless $btg_id == BTWTARIEF_ANDERS; $tr->("Ander"); $deb_a += $amt; $deb_btw_a += $btw; } } else { $tr->("Voorheffing"); $crd_btw -= $btw; } } elsif ( $btw_status == BTWTYPE_VERLEGD ) { if ( $debcrd ) { $tr->("Verlegd"); $verlegd += $amt; } } elsif ( $btw_status == BTWTYPE_INTRA ) { if ( $debcrd ) { $tr->("Intra"); $intra_deb += $amt; $intra_deb_btw += $btw; } else { $intra_crd -= $amt; $intra_crd_btw -= $btw; } } elsif ( $btw_status == BTWTYPE_EXTRA ) { if ( $debcrd ) { $tr->("Extra D"); $extra_deb += $amt; } else { $tr->("Extra C"); $extra_crd -= $amt; } } else { # Foutvanger. $tr->("????"); $xx += $amt; } } my %data; my $delta = 0; my $ad = sub { my ($a, $b) = @_; $b *= AMTSCALE unless $noround; $delta += $a - $b; }; # 1. Door mij verrichte leveringen/diensten # 1a. Belast met hoog tarief $v = rounddown($deb_btw_h); $data{deb_btw_h} = $v; $ad->($deb_btw_h, $v); $data{deb_h} = rounddown($deb_h); $tot += $v; # 1b. Belast met laag tarief $v = rounddown($deb_btw_l); $data{deb_l} = rounddown($deb_l); $data{deb_btw_l} = $v; $ad->($deb_btw_l, $v); $tot += $v; # 1c. Belast met ander, niet-nul tarief $v = rounddown($deb_btw_a); $data{deb_a} = rounddown($deb_a); $data{deb_btw_a} = $v; $ad->($deb_btw_a, $v); $tot += $v; # 1d. Eigen gebruik $v = rounddown($deb_btw_p); $data{deb_p} = rounddown($deb_p); $data{deb_btw_p} = $v; $ad->($deb_btw_p, $v); $tot += $v; # 1e. Belast met 0%/verlegd $data{deb_0} = rounddown($deb_0 + $verlegd); #$data{deb_0} = roundtozero($deb_0 + $verlegd); # Buitenland # 3. Door mij verrichte leveringen # 3a. Buiten de EU $data{extra_deb} = rounddown($extra_deb); # 3b. Binnen de EU $data{intra_deb} = rounddown($intra_deb); $v = rounddown($intra_deb_btw); $data{intra_deb_btw} = $v; # TODO $ad->($intra_deb_btw, $v); # 4. Aan mij verrichte leveringen # 4a. Van buiten de EU $data{extra_crd} = rounddown($extra_crd); # 4b. Verwervingen van goederen uit de EU. $data{intra_crd} = rounddown($intra_crd); $v = roundup($intra_crd_btw); $data{intra_crd_btw} = $v; $ad->($intra_crd_btw, $v); $tot += $v; # 5 Berekening totaal # 5a. Subtotaal $data{sub0} = $tot; # 5b. Voorbelasting my ($vb) = @{$dbh->do("SELECT SUM(jnl_amount)". " FROM Journal". " WHERE ( jnl_acc_id = ? OR jnl_acc_id = ?". " OR jnl_acc_id = ? OR jnl_acc_id = ? )". " AND jnl_bsr_date >= ? AND jnl_bsr_date <= ?", $dbh->std_acc("btw_ih"), $dbh->std_acc("btw_il"), $dbh->std_acc("btw_ia",0), $dbh->std_acc("btw_ip",0), $begin, $end)}; $vb ||= 0; # prevent warnings $vb += $intra_crd_btw; # geheven intra btw terugvorderen my $btw_i_delta = $vb - $crd_btw - $intra_crd_btw; $v = roundup($vb); $data{vb} = $v; $tot -= $v; $ad->(-$vb, -$v); # 5c Subtotaal / 5g Totaal $data{sub1} = $data{tot} = $tot; $data{onbekend} = $xx if $xx; # 5d Kleine Ondernemers if ( $self->{compat_periode} =~ /^\d\d\d\d$/ ) { # aangifte per jaar if ( $data{ko} = kleine_ondernemers($self->{compat_periode}, $data{sub1}) ) { $data{tot} -= $data{ko}; } } # Check op afgedragen BTW. foreach my $acc ( @{$dbh->std_accs} ) { next unless $acc =~ /^btw_v(.)$/; my $t = $1; ($vb) = @{$dbh->do("SELECT SUM(jnl_amount)". " FROM Journal". " WHERE ( jnl_acc_id = ? )". " AND jnl_bsr_date >= ? AND jnl_bsr_date <= ?", $dbh->std_acc($acc), $begin, $end)}; next unless defined($vb); $vb = -$vb; if ( $data{"deb_btw_$t"} != ($v = rounddown($vb)) ) { $data{"btw_v${t}_delta"} = $v - $data{"deb_btw_$t"}; $data{"deb_btw_$t"} = $v; } } $data{btw_i_delta} = $btw_i_delta if $btw_i_delta; $data{delta} = $delta if $delta; return \%data; } sub report { my ($self, $rep, $data) = @_; my $outline = sub { my ($column, $desc, $sub, $amt) = @_; $rep->add({ _style => 'd', num => $column, desc => $desc, defined($sub) ? ( col1 => $noround ? numfmt($sub) : $sub) : (), defined($amt) ? (col2 => $noround ? numfmt($amt) : $amt) : (), }); }; $rep->start(_T("BTW Aangifte"), $self->{compat_periode} ? __x("Periode: {per}", per => $self->{compat_periode}) : __x("Periode: {from} t/m {to}", from => datefmt_full($rep->{per_begin}), to => datefmt_full($rep->{per_end}))); # Binnenland $rep->add({ _style => 'h1', num => "Binnenland" }); # 1. Door mij verrichte leveringen/diensten $rep->add({ _style => 'h2', num => "1. Door mij verrichte leveringen/diensten", }); # 1a. Belast met hoog tarief $outline->("1a", "Belast met hoog tarief", $data->{deb_h}, $data->{deb_btw_h}); # 1b. Belast met laag tarief $outline->("1b", "Belast met laag tarief", $data->{deb_l}, $data->{deb_btw_l}); # 1c. Belast met ander, niet-nul tarief $outline->("1c", "Belast met ander tarief", $data->{deb_a}, $data->{deb_btw_a}) if $data->{deb_a} || $data->{deb_btw_a}; # 1d. Eigen gebruik $outline->("1d", "Eigen gebruik", $data->{deb_p}, $data->{deb_btw_p}) if $data->{deb_p} || $data->{deb_btw_p}; # 1e. Belast met 0%/verlegd $outline->("1e", "Belast met 0% / verlegd", $data->{deb_0}, undef); # Buitenland $rep->add({ _style => 'h1', num => "Buitenland" }); # 3. Door mij verrichte leveringen $rep->add({ _style => 'h2', num => "3. Door mij verrichte leveringen" }); # 3a. Buiten de EU $outline->("3a", "Buiten de EU", $data->{extra_deb}, undef); # 3b. Binnen de EU $outline->("3b", "Binnen de EU", $data->{intra_deb}, undef); # 4. Aan mij verrichte leveringen $rep->add({ _style => 'h2', num => "4. Aan mij verrichte leveringen" }); # 4a. Van buiten de EU $outline->("4a", "Van buiten de EU", $data->{extra_crd}, 0); # 4b. Verwervingen van goederen uit de EU. $outline->("4b", "Verwervingen van goederen uit de EU", $data->{intra_crd}, $data->{intra_crd_btw}); # 5 Berekening totaal $rep->add({ _style => 'h1', num => "Berekening" }); $rep->add({ _style => 'h2', num => "5. Berekening totaal" }); # 5a. Subtotaal $outline->("5a", "Subtotaal", undef, $data->{sub0}); # 5b. Voorbelasting $outline->("5b", "Voorbelasting", undef, $data->{vb}); # 5c Subtotaal $outline->("5c", "Subtotaal", undef, $data->{sub1}); if ( $self->{compat_periode} =~ /^\d\d\d\d$/ ) { # aangifte per jaar if ( defined($data->{ko}) ) { # 5d Subtotaal $outline->("5d", "Vermindering kleineondernemersregeling", undef, $data->{ko}); } else { $outline->("5d", "Geen gegevens voor kleineondernemersregeling", undef, undef); } } # 5g Subtotaal if ( $data->{tot} >= 0 ) { $outline->("5g", "Totaal te betalen", undef, $data->{tot}); if ( $data->{delta} ) { $outline->("", "Totaal te betalen (onafgerond)", numfmt($data->{sub1}*AMTSCALE+$data->{delta})); $outline->("", "Afrondingsverschil", numfmt($data->{delta})); } } else { $outline->("5g", "Totaal terug te vragen", undef, 0-$data->{tot}); if ( $data->{delta} ) { $outline->('', "Totaal terug te vragen (onafgerond)", numfmt(-($data->{sub1}*AMTSCALE+$data->{delta}))); $outline->('', "Afrondingsverschil", numfmt($data->{delta})); } } $outline->("?", "Onbekend", undef, numfmt($data->{onbekend})) if $data->{onbekend}; my @msg; if ( $data->{btw_i_delta} ) { push(@msg, __x("Er is een verschil van {amount}". " tussen de berekende en werkelijk ingehouden BTW.". " Voor de aangifte is de werkelijk ingehouden waarde gebruikt.", amount => numfmt($data->{btw_i_delta}))); } foreach my $type ( @{BTWTARIEVEN()} ) { my $t = lc(substr($type, 0, 1)); if ( $data->{"btw_v".$t."_delta"} ) { push(@msg, __x("Er is een verschil van {amount}". " tussen de berekende en werkelijk afgedragen BTW {type}.". " Voor de aangifte is de werkelijk afgedragen waarde gebruikt.", type => $type, amount => numfmt($data->{"btw_v".$t."_delta"}))); } } $rep->finish(@msg); } ################ Subroutines ################ sub rounddown { my ($vb) = @_; return 0 unless $vb; return $vb if $noround; $vb /= AMTSCALE; if ( $vb >= 0 ) { $vb = floor($vb); } else { $vb = -ceil(abs($vb)); } $vb; } sub roundup { my ($vb) = @_; return 0 unless $vb; return $vb if $noround; $vb /= AMTSCALE; if ( $vb >= 0 ) { $vb = ceil($vb); } else { $vb = -floor(abs($vb)); } $vb; } sub roundtozero { my ($vb) = @_; return 0 unless $vb; return $vb if $noround; $vb /= AMTSCALE; if ( $vb >= 0 ) { $vb = floor($vb); } else { $vb = 0-floor(abs($vb)); } $vb; } sub kleine_ondernemers { my ($year, $amount) = @_; return 0 if $amount < 0; # Formule lijkt linds 1995 ongwijzigd, alleen de bedragen # veranderen. Sinds 2002 zijn de bedragen ongewijzigd. Alle # officiële documentatie spreeekt over "Als de afdracht van # omzetbelasting beneden de 1.345 per jaar blijft, ...". # Code change: beschouw de huidige bedragen als vaststaand. return if $year < 2002; # my %mmtab = ( 2002 => [ 1345, 1883 ], # 2003 => [ 1345, 1883 ], # 2004 => [ 1345, 1883 ], # 2005 => [ 1345, 1883 ], # 2006 => [ 1345, 1883 ], # 2007 => [ 1345, 1883 ], # ); # # $mmtab{$year} ||= [ 1345, 1883 ] if $year >= 2002; # # return unless exists $mmtab{$year}; # # my ($min, $max) = @{$mmtab{$year}}; my ($min, $max) = ( 1345, 1883 ); if ( $noround ) { $min *= AMTSCALE; $max *= AMTSCALE; } return $amount if $amount <= $min; return 0 if $amount > $max; my $kko = ($min / ($max - $min)) * ($max - $amount); return $noround ? $kko : roundup($kko*AMTSCALE); } sub warnings { my $self = shift; return unless @_; my (@msgs) = @_; foreach ( @msgs ) { warn("!".$_."\n"); } } package EB::Report::BTWAangifte::Text; use strict; use warnings; use base qw(EB::Report::Reporter::Text); # Style mods. sub style { my ($self, $row, $cell) = @_; my $stylesheet = { h1 => { _style => { skip_before => 1, skip_after => 1 }, num => { colspan => 2 }, }, h2 => { _style => { skip_before => 1, skip_after => 1 }, num => { colspan => 2 }, }, d => { }, }; $cell = "_style" unless defined($cell); return $stylesheet->{$row}->{$cell}; } sub finish { shift->SUPER::finish; EB::Report::BTWAangifte::warnings(undef, @_); } package EB::Report::BTWAangifte::Html; use strict; use warnings; use base qw(EB::Report::Reporter::Html); # Style mods. sub style { my ($self, $row, $cell) = @_; my $stylesheet = { h1 => { num => { class => "heading", colspan => 2 }, }, h2 => { num => { class => "subheading", colspan => 2 }, }, }; $cell = "_style" unless defined($cell); return $stylesheet->{$row}->{$cell}; } sub finish { my $self = shift; if ( @_ ) { print { $self->{fh} } ("
\n"); print { $self->{fh} } ("

\n"); print { $self->{fh} } (join("
\n", map { $self->html($_) } @_) ); print { $self->{fh} } ("

\n"); print { $self->{fh} } ("\n"); } $self->SUPER::finish; } package EB::Report::BTWAangifte::Csv; use strict; use warnings; use base qw(EB::Report::Reporter::Csv); sub finish { shift->SUPER::finish; EB::Report::BTWAangifte::warnings(undef, @_); } 1; EekBoek-2.030.1/lib/EB/Report/Reporter.pm0000644000400000040000000001032012725476602015436 0ustar jvjv#! perl # Reporter.pm -- # Author : Johan Vromans # Created On : Wed Dec 28 13:18:40 2005 # Last Modified By: Johan Vromans # Last Modified On: Sat Jun 19 00:40:09 2010 # Update Count : 152 # Status : Unknown, Use with caution! package main; our $cfg; our $dbh; package EB::Report::Reporter; use strict; use warnings; use EB; use EB::Format; sub new { my ($class, $style, $config) = @_; if ( @_ == 2 ) { $config = $style->{LAYOUT}; $style = $style->{STYLE}; } $class = ref($class) || $class; my $self = bless { _fields => [], _fdata => {}, _style => $style, }, $class; foreach my $col ( @$config ) { if ( $col->{name} ) { if ( $col->{name} eq "_colsep" ) { $self->{_colsep} = $col->{sep} || (" " x $col->{width}); next; } my $a = { name => $col->{name} }; $a->{title} = $col->{title} || ""; $a->{width} = $col->{width} || length($a->{title}); $a->{align} = $col->{align} || "<"; $a->{style} = $col->{style} || $col->{name}; $self->{_fdata}->{$a->{name}} = $a; push(@{$self->{_fields}}, $a); if ( my $t = $cfg->val("layout $style", $col->{name}."_width", undef) ) { $self->widths({$col->{name} => $t}); } } else { die("?"._T("Ontbrekend \"name\" of \"style\"")); } } if ( my $t = $cfg->val("layout $style", "fields", undef) ) { $self->fields(split(' ', $t)); } # Return object. $self; } sub fields { my ($self, @f) = @_; my @nf; # new order of fields foreach my $fld ( @f ) { my $a = $self->{_fdata}->{$fld}; die("?".__x("Onbekend veld: {fld}", fld => $fld)."\n") unless defined($a); push(@nf, $a); } $self->{_fields} = \@nf; # PBP: Return nothing sensible. return; } sub widths { my ($self, $w) = @_; while ( my($fld,$width) = each(%$w) ) { die("?".__x("Onbekend veld: {fld}", fld => $fld)."\n") unless defined($self->{_fdata}->{$fld}); my $ow = $self->{_fdata}->{$fld}->{width}; if ( $width =~ /^\+(\d+)$/ ) { $ow += $1; } elsif ( $width =~ /^-(\d+)$/ ) { $ow -= $1; } elsif ( $width =~ /^(\d+)\%$/ ) { $ow *= $1; $ow = int($ow/100); } elsif ( $width =~ /^\d+$/ ) { $ow = $width; } else { die("?".__x("Ongeldige breedte {w} voor veld {fld}", fld => $fld, w => $width)."\n"); } $self->{_fdata}->{$fld}->{width} = $ow; } # PBP: Return nothing sensible. return; } sub start { my $self = shift; my ($t1, $t2, $t3l, $t3r) = @_; # Top title. if ( !$t1 ) { # This one really should be filled in with something distinguishing. $t1 = _T("Rapportage"); } # Report date / period. if ( !$t2 ) { $t2 = "Periode: ****"; if ( exists($self->{periodex}) ) { if ( $self->{periodex} == 1 ) { $t2 = __x("Periode: t/m {to}", to => datefmt_full($self->{periode}->[1])); } else { $t2 = __x("Periode: {from} t/m {to}", from => datefmt_full($self->{periode}->[0]), to => datefmt_full($self->{periode}->[1])); } } } # Administration name. if ( !$t3l ) { $t3l = $::dbh->adm("name"); } # Creation date + program version if ( !$t3r ) { if ( my $t = $cfg->val(qw(internal now), 0) ) { # Fixed date. Strip program version. Makes it easier to compare reports. $t3r = (split(' ', $EB::ident))[0] . ", " . $t; } else { # Use current date. $t3r = $EB::ident . ", " . datefmt_full(iso8601date()); } } # Move to self. $self->{_title1} = $t1; $self->{_title2} = $t2; $self->{_title3l} = $t3l; $self->{_title3r} = $t3r; $self->{_needhdr} = 1; $self->{_needskip} = 0; $self->{fh} ||= *STDOUT; } sub finish { my ($self) = @_; } sub add { my ($self, $data) = @_; while ( my($k,$v) = each(%$data) ) { die("?",__x("Ongeldig veld: {fld}", fld => $k)) unless defined $self->{_fdata}->{$k}; } } sub style { return } sub _getstyle { my ($self, $row, $cell) = @_; return $self->style($row) unless $cell; my $a = $self->style("_any", $cell) || {}; my $b = $self->style($row, $cell) || {}; return { %$a, %$b }; } sub _checkhdr { my ($self) = @_; return unless $self->{_needhdr}; $self->{_needhdr} = 0; $self->header; } 1; EekBoek-2.030.1/lib/EB/Report/Open.pm0000644000400000040000000001233612725476602014546 0ustar jvjv#! perl package main; our $config; our $dbh; package EB::Report::Open; # Author : Johan Vromans # Created On : Fri Sep 30 17:48:16 2005 # Last Modified By: Johan Vromans # Last Modified On: Sun Jun 24 22:29:59 2012 # Update Count : 206 # Status : Unknown, Use with caution! ################ Common stuff ################ use strict; use warnings; ################ The Process ################ use EB; use EB::Format; use EB::Report::GenBase; ################ Subroutines ################ sub new { return bless {}; } sub perform { my ($self, $opts, $args) = @_; $opts->{STYLE} = "openstaand"; $opts->{LAYOUT} = [ { name => "rel", title => _T("Relatie"), width => 10, }, { name => "date", title => _T("Datum"), width => $date_width, }, { name => "desc", title => _T("Omschrijving"), width => 30, }, { name => "amt", title => _T("Bedrag"), width => $amount_width, align => ">", }, { name => "bsk", title => _T("Boekstuk"), width => 16, }, ]; my $rep = EB::Report::GenBase->backend($self, $opts); my $per = $rep->{per} = $rep->{periode}->[1]; $rep->{periodex} = 1; # force 'per'. my $sel; if ( $opts->{deb} && !$opts->{crd} ) { $sel = " AND dbk_type = @{[DBKTYPE_VERKOOP]}"; } elsif ( !$opts->{deb} && $opts->{crd} ) { $sel = " AND dbk_type = @{[DBKTYPE_INKOOP]}"; } else { $sel = " AND dbk_type in (@{[DBKTYPE_INKOOP]},@{[DBKTYPE_VERKOOP]})"; } if ( $args && @$args == 1 ) { $sel .= " AND bsr_rel_code = ?"; } my $eb = $opts->{eb_handle}; my $gtot = 0; # grand total deb/crd my $rtot = 0; # relation total my $sth = $dbh->sql_exec("SELECT bsk_id, dbk_id, dbk_desc, bsk_nr, bsk_desc, bsk_date,". " bsk_open, dbk_type, dbk_acc_id, bsr_rel_code, bsk_bky". " FROM Boekstukken, Dagboeken, Boekstukregels". " WHERE bsk_dbk_id = dbk_id". " AND bsr_bsk_id = bsk_id AND bsr_nr = 1". " AND bsk_date <= ?". $sel. " ORDER BY dbk_acc_id, bsr_rel_code, bsk_date", $per, @$args); $rep->start(_T("Openstaande posten")); my $cur_rel; my $cur_cat; my $did; while ( my $rr = $sth->fetchrow_arrayref ) { my ($bsk_id, $dbk_id, $dbk_desc, $bsk_nr, $bsk_desc, $bsk_date, $bsk_amount, $dbk_type, $dbk_acc_id, $bsr_rel, $bsk_bky) = @$rr; # Correct for future payments. my $rop = $dbh->do("SELECT sum(bsr_amount)". " FROM Boekstukregels". " WHERE bsr_type IN (@{[DBKTYPE_INKOOP]},@{[DBKTYPE_VERKOOP]})". " AND bsr_date > ?". " AND bsr_paid = ?", $per, $bsk_id); if ( $rop && $rop->[0] ) { $bsk_amount -= $rop->[0]; } next unless $bsk_amount; if ( defined($cur_rel) && $bsr_rel ne $cur_rel ) { $rep->add({ _style => "trelatie", desc => __x("Totaal {rel}", rel => $cur_rel), amt => numfmt($rtot), }); $rtot = 0; } if ( defined($cur_cat) && $dbk_acc_id ne $cur_cat ) { $rep->add({ _style => "tdebcrd", desc => __x("Totaal {debcrd}", debcrd => $dbh->lookup($cur_cat, qw(Accounts acc_id acc_desc))), amt => numfmt($gtot), }); $gtot = 0; $rtot = 0; } $bsk_amount = 0-$bsk_amount if $dbk_type == DBKTYPE_INKOOP; if ( $eb ) { my $t = lc($dbk_desc); $t =~ s/\s+/_/g; print {$eb} ("adm_relatie ", join(":", $t, $bsk_bky, $bsk_nr), " ", $bsk_date, " \"", $bsr_rel, "\" \"", $bsk_desc, "\" ", numfmt_plain($bsk_amount), "\n"); } my $bsk; my $style = $dbk_type == DBKTYPE_INKOOP ? "cdata" : $dbk_type == DBKTYPE_VERKOOP ? "ddata" : "data"; if ( $bsk_date lt $rep->{per_begin} ) { $bsk = join(":", $dbk_desc, $bsk_bky, $bsk_nr); $style = "prevdata"; } else { $bsk = join(":", $dbk_desc, $bsk_nr); } $rep->add({ _style => $style, date => datefmt($bsk_date), bsk => $bsk, desc => $bsk_desc, rel => $bsr_rel, amt => numfmt($bsk_amount), }); $gtot += $bsk_amount; $rtot += $bsk_amount; $cur_rel = $bsr_rel; $cur_cat = $dbk_acc_id; $did++; } if ( defined($cur_rel) ) { $rep->add({ _style => "trelatie", desc => __x("Totaal {rel}", rel => $cur_rel), amt => numfmt($rtot), }); $rtot = 0; } if ( defined($cur_cat) ) { $rep->add({ _style => "tdebcrd", desc => __x("Totaal {debcrd}", debcrd => $dbh->lookup($cur_cat, qw(Accounts acc_id acc_desc))), amt => numfmt($gtot), }); } if ( $did ) { $rep->add({ _style => "last" }); $rep->finish; } else { return "!"._T("Geen openstaande posten gevonden"); } return; } package EB::Report::Open::Text; use strict; use warnings; use base qw(EB::Report::Reporter::Text); # Style mods. sub style { my ($self, $row, $cell) = @_; my $stylesheet = { trelatie => { _style => { skip_after => 1 }, }, tdebcrd => { _style => { cancel_skip => 1, skip_after => 1 }, amt => { line_before => 1 }, }, last => { _style => { line_before => 1 }, }, }; $cell = "_style" unless defined($cell); return $stylesheet->{$row}->{$cell}; } package EB::Report::Open::Html; use strict; use warnings; use base qw(EB::Report::Reporter::Html); package EB::Report::Open::Csv; use strict; use warnings; use base qw(EB::Report::Reporter::Csv); 1; EekBoek-2.030.1/lib/EB/Report/Proof/0000755000400000040000000000000013151742350014355 5ustar jvjvEekBoek-2.030.1/lib/EB/Report/Proof/Wxhtml.pm0000644000400000040000000000220212725476601016203 0ustar jvjv#! perl # Wxhtml.pm -- WxHtml backend for Proof/Saldi report. # Author : Johan Vromans # Created On : *** # Last Modified By: Johan Vromans # Last Modified On: Sat Jun 19 00:38:57 2010 # Update Count : 4 # Status : Unknown, Use with caution! package EB::Report::Proof::Wxhtml; use strict; use warnings; use base qw(EB::Report::Reporter::WxHtml); sub style { my ($self, $row, $cell) = @_; my $stylesheet = { d => { acct => { link => "gbk://" }, }, d2 => { acct => { link => "gbk://" }, desc => { indent => 2 }, }, h1 => { _style => { colour => 'red', size => '+2', } }, h2 => { _style => { colour => 'red' }, desc => { indent => 1,}, }, t1 => { _style => { colour => 'blue', size => '+1', } }, t2 => { _style => { colour => 'blue' }, desc => { indent => 1 }, }, v => { _style => { colour => 'red', size => '+2', } }, grand => { _style => { colour => 'blue' } }, }; $cell = "_style" unless defined($cell); return $stylesheet->{$row}->{$cell}; } 1; EekBoek-2.030.1/lib/EB/Report/Debcrd/0000755000400000040000000000000013151742350014453 5ustar jvjvEekBoek-2.030.1/lib/EB/Report/Debcrd/Wxhtml.pm0000644000400000040000000000140712725476602016310 0ustar jvjv#! perl # Wxhtml.pm -- # Author : Johan Vromans # Created On : Thu Feb 7 13:21:53 2008 # Last Modified By: Johan Vromans # Last Modified On: Sat Jun 19 00:35:31 2010 # Update Count : 23 # Status : Unknown, Use with caution! #! perl package EB::Report::Debcrd::Wxhtml; use strict; use warnings; use base qw(EB::Report::Reporter::WxHtml); sub style { my ($self, $row, $cell) = @_; my $stylesheet = { bsk => { bsknr => { link => "jnl://" }, }, paid => { bsknr => { link => "jnl://" }, }, h1 => { _style => { colour => 'red', size => '+2', } }, grand => { _style => { colour => 'blue' } }, }; $cell = "_style" unless defined($cell); return $stylesheet->{$row}->{$cell}; } 1; EekBoek-2.030.1/lib/EB/Report/Grootboek.pm0000644000400000040000000001463712725476602015606 0ustar jvjv#! perl package main; our $cfg; our $dbh; package EB::Report::Grootboek; # Author : Johan Vromans # Created On : Wed Jul 27 11:58:52 2005 # Last Modified By: Johan Vromans # Last Modified On: Thu Jun 7 13:59:31 2012 # Update Count : 287 # Status : Unknown, Use with caution! ################ Common stuff ################ use strict; use warnings; ################ The Process ################ use EB; use EB::Booking; # for dcfromtd() use EB::Format; use EB::Report::GenBase; use EB::Report; ################ Subroutines ################ sub new { return bless {}; } sub perform { my ($self, $opts) = @_; my $detail = $opts->{detail}; my $sel = $opts->{select}; $opts->{STYLE} = "grootboek"; $opts->{LAYOUT} = [ { name => "acct", title => _T("GrBk"), width => 5, align => ">" }, { name => "desc", title => _T("Grootboek/Boekstuk"), width => 30, }, { name => "date", title => _T("Datum"), width => $date_width }, { name => "deb", title => _T("Debet"), width => $amount_width, align => ">" }, { name => "crd", title => _T("Credit"), width => $amount_width, align => ">" }, { name => "bsk", title => _T("BoekstukNr"), width => 14, }, { name => "rel", title => _T("Relatie"), width => 10, }, ]; my $rep = EB::Report::GenBase->backend($self, $opts); my $per = $rep->{periode}; my ($begin, $end) = @$per; if ( my $t = $cfg->val(qw(internal now), 0) ) { $end = $t if $t lt $end; } $rep->start(_T("Grootboek")); $dbh->begin_work; my $table = EB::Report->GetTAccountsAll($begin, $end); my $ah = $dbh->sql_exec("SELECT acc_id,acc_desc,acc_ibalance,acc_balres". " FROM ${table}". ($sel ? (" WHERE acc_id IN ($sel)") : (" WHERE acc_ibalance <> 0". " OR acc_id in". " ( SELECT DISTINCT jnl_acc_id FROM Journal )")). " ORDER BY acc_id"); my $dgrand = 0; my $cgrand = 0; my $mdgrand = 0; my $mcgrand = 0; my $n0 = numfmt(0); my $t; my $did = 0; while ( my $ar = $ah->fetchrow_arrayref ) { my ($acc_id, $acc_desc, $acc_ibalance, $acc_balres) = @$ar; my $sth = $dbh->sql_exec("SELECT jnl_amount,jnl_damount,jnl_bsk_id,bsk_desc,". "bsk_nr,dbk_desc,dbk_dcsplit,jnl_bsr_date,jnl_desc,jnl_rel". " FROM Journal, Boekstukken, Dagboeken". " WHERE jnl_dbk_id = dbk_id". " AND jnl_bsk_id = bsk_id". " AND jnl_acc_id = ?". " AND jnl_date >= ? AND jnl_date <= ?". " ORDER BY jnl_bsr_date, jnl_bsk_id, jnl_seq", $acc_id, $begin, $end); my $rr = $sth->fetchrow_arrayref; if ( !$acc_ibalance && !$rr ) { $sth->finish; next; } $rep->add({ _style => 'h1', acct => $acc_id, desc => $acc_desc, }) if $detail; my $a = { _style => 'h2', desc => _T("Beginsaldo") }; if ( $acc_ibalance ) { if ( $acc_ibalance < 0 ) { $a->{crd} = numfmt(-$acc_ibalance); $a->{deb} = $n0; } else { $a->{crd} = $n0; $a->{deb} = numfmt($acc_ibalance); } } else { $a->{deb} = $a->{crd} = $n0; } $rep->add($a) if $detail > 0; my $dtot = 0; my $ctot = 0; my $dcsplit; # any acct was DC split while ( $rr ) { my ($amount, $damount, $bsk_id, $bsk_desc, $bsk_nr, $dbk_desc, $dbk_dcsplit, $date, $desc, $rel) = @$rr; warn("?Internal error: delta amount while no DC split, acct = $acc_id ($acc_desc)\n") if defined($damount) && !$dbk_dcsplit; $dcsplit ||= $dbk_dcsplit; my ($deb, $crd) = EB::Booking::dcfromtd($amount, $damount); $ctot += $crd if $crd; $dtot += $deb if $deb; $rep->add({ _style => 'd', desc => $desc, date => datefmt($date), deb => numfmt($deb), crd => numfmt($crd), bsk => join(":", $dbk_desc, $bsk_nr), $rel ? ( rel => $rel) : (), }) if $detail > 1; $rr = $sth->fetchrow_arrayref; } $a = { _style => 't2', desc => _T("Totaal mutaties") }; if ( $dcsplit ) { $a->{crd} = numfmt($ctot); $a->{deb} = numfmt($dtot); $mdgrand += $dtot if $dtot; $mcgrand += $ctot if $ctot; } elsif ( $ctot > $dtot ) { $a->{crd} = numfmt($ctot-$dtot); $mcgrand += $ctot - $dtot; } else { $a->{deb} = numfmt($dtot-$ctot); $mdgrand += $dtot - $ctot; } $rep->add($a) if $detail && ($dtot || $ctot || $acc_ibalance); $rep->add({ _style => 't1', acct => $acc_id, desc => __x("Totaal {adesc}", adesc => $acc_desc), $ctot > $dtot + $acc_ibalance ? ( crd => numfmt($ctot-$dtot-$acc_ibalance) ) : ( deb => numfmt($dtot+$acc_ibalance-$ctot) ), }); if ( $ctot > $dtot + $acc_ibalance ) { $cgrand += $ctot - $dtot-$acc_ibalance; } else { $dgrand += $dtot+$acc_ibalance - $ctot; } $did++; } if ( $did ) { $rep->add({ _style => 'tm', desc => _T("Totaal mutaties"), deb => numfmt($mdgrand), crd => numfmt($mcgrand), }); $rep->add({ _style => 'tg', desc => _T("Totaal"), $cgrand || 1 ? ( crd => numfmt($cgrand) ) : (), $dgrand || !$cgrand ? ( deb => numfmt($dgrand) ) : (), }); } else { print("?"._T("Geen informatie gevonden")."\n"); } $rep->finish; # Rollback temp table. $dbh->rollback; } package EB::Report::Grootboek::Text; use EB; use base qw(EB::Report::Reporter::Text); sub new { my ($class, $opts) = @_; my $self = $class->SUPER::new($opts->{STYLE}, $opts->{LAYOUT}); $self->{detail} = $opts->{detail}; return $self; } # Style mods. sub style { my ($self, $row, $cell) = @_; my $stylesheet = { _any => { # desc => { truncate => 1 }, }, h2 => { desc => { indent => 1 }, }, d => { desc => { indent => 2 }, }, t1 => { _style => { skip_after => ($self->{detail} > 0) }, }, t2 => { desc => { indent => 1 }, }, tm => { _style => { skip_before => 1 }, }, tg => { _style => { line_before => 1 } }, }; $cell = "_style" unless defined($cell); return $stylesheet->{$row}->{$cell}; } package EB::Report::Grootboek::Html; use EB; use base qw(EB::Report::Reporter::Html); sub new { my ($class, $opts) = @_; $class->SUPER::new($opts->{STYLE}, $opts->{LAYOUT}); } package EB::Report::Grootboek::Csv; use EB; use base qw(EB::Report::Reporter::Csv); use strict; sub new { my ($class, $opts) = @_; $class->SUPER::new($opts->{STYLE}, $opts->{LAYOUT}); } 1; EekBoek-2.030.1/lib/EB/Report/Reporter/0000755000400000040000000000000013151742350015072 5ustar jvjvEekBoek-2.030.1/lib/EB/Report/Reporter/Text.pm0000644000400000040000000001417012725476601016370 0ustar jvjv#! perl # Text.pm -- Reporter backend for text reports. # Author : Johan Vromans # Created On : Wed Dec 28 13:21:11 2005 # Last Modified By: Johan Vromans # Last Modified On: Sat Jun 19 00:39:44 2010 # Update Count : 119 # Status : Unknown, Use with caution! package main; our $cfg; our $dbh; package EB::Report::Reporter::Text; use strict; use warnings; use EB; use base qw(EB::Report::Reporter); ################ API ################ sub start { my ($self, @args) = @_; $self->SUPER::start(@args); $self->_make_format; $self->{_lines} = 0; $self->{_page} = 0; $self->{_colsep} = " " unless defined $self->{_colsep}; } sub finish { my ($self) = @_; $self->_checkskip(1); # cancel skips. $self->SUPER::finish(); close($self->{fh}); } sub add { my ($self, $data) = @_; my $style = delete($data->{_style}); $self->SUPER::add($data); $self->_checkhdr; my $skip_after = 0; my $line_after = 0; my $cancel_skip = 0; if ( $style and my $t = $self->_getstyle($style) ) { $self->_skip if $t->{skip_before}; $skip_after = $t->{skip_after}; $self->_line if $t->{line_before}; $line_after = $t->{line_after}; $cancel_skip = $t->{cancel_skip}; } $self->_checkskip($cancel_skip); my @values; my @widths; my @indents; my $linebefore; my $lineafter; my $colspan = 0; my $lw; #push(@values, $style||"") if $cfg->val(__PACKAGE__, "layout", 0); foreach my $col ( @{$self->{_fields}} ) { if ( $colspan > 1 ) { $colspan--; $$lw += $col->{width} + length($self->{_colsep}); push(@values, ""); push(@widths, 0); push(@indents, 0); next; } my $fname = $col->{name}; push(@values, defined($data->{$fname}) ? $data->{$fname} : ""); push(@widths, $col->{width}); # Examine style mods. my $indent = 0; my $excess = 0; if ( $style ) { if ( my $t = $self->_getstyle($style, $fname) ) { $indent = $t->{indent} || 0; if ( $t->{line_before} ) { $linebefore->{$fname} = ($t->{line_before} eq "1" ? "-" : $t->{line_before}) x $col->{width}; } if ( $t->{line_after} ) { $lineafter->{$fname} = ($t->{line_after} eq "1" ? "-" : $t->{line_after}) x $col->{width}; } if ( $t->{excess} ) { #### TODO $widths[-1] += $t->{excess}; } if ( $t->{truncate} ) { $values[-1] = substr($values[-1], 0, $widths[-1] - $indent); } if ( $t->{colspan} ) { $colspan = $t->{colspan}; $lw = \$widths[-1]; } } } push(@indents, $indent); } # use Data::Dumper; # warn(Dumper \@values); # warn(Dumper \@widths); if ( $linebefore ) { $self->add($linebefore); } my @lines; while ( 1 ) { my $more = 0; my @v; foreach my $i ( 0..$#widths ) { my $ind = $indents[$i]; my $maxw = $widths[$i] - $ind; $ind = " " x $ind; if ( length($values[$i]) <= $maxw ) { push(@v, $ind.$values[$i]); $values[$i] = ""; } else { my $t = substr($values[$i], 0, $maxw); if ( substr($values[$i], $maxw, 1) eq " " ) { push(@v, $ind.$t); substr($values[$i], 0, length($t) + 1, ""); } elsif ( $t =~ /^(.*)([ ]+)/ ) { my $pre = $1; push(@v, $ind.$pre); substr($values[$i], 0, length($pre) + length($2), ""); } else { push(@v, $ind.$t); substr($values[$i], 0, $maxw, ""); } $more++; } } my $t = $self->_format_line(\@v, \@widths); $t =~ s/ +$//; push(@lines, $t) if $t =~ /\S/; last unless $more; } if ( $self->{_lines} < @lines ) { $self->{_needhdr} = 1; $self->_checkhdr; } print {$self->{fh}} @lines; $self->{_lines} -= @lines; # Post: Lines for cells. if ( $lineafter ) { $self->add($lineafter); } # Post: Line for row. if ( $line_after ) { $self->_line; } # Post: Skip after this row. elsif ( $skip_after ) { $self->_skip; } } ################ Pseudo-Internal (used by Base class) ################ sub header { my ($self) = @_; my $t = sprintf("%s\n" . "%-" . ($self->{_width}-10) . "s%10s\n" . "%-" . ($self->{_width}-31) . "s%31s\n" . "\n", $self->_center($self->{_title1}, $self->{_width}), $self->{_title2}, 1 ? "" : ("Blad: " . (++$self->{_page})), $self->{_title3l}, $self->{_title3r}); if ( grep { $_->{title} =~ /\S/ } @{$self->{_fields}} ) { $t .= $self->_format_line([map { $_->{title} } @{$self->{_fields}}], [map { $_->{width} } @{$self->{_fields}}]), } $t =~ s/ +$//gm; print {$self->{fh}} ($t); $self->_line; $self->_checkskip(1); # cancel skips. $self->{_lines} = $self->{page} - 6; } ################ Internal methods ################ sub _make_format { my ($self) = @_; my $width = 0; # new width my $cs = $self->{_colsep} || " "; my $cw = length($cs); foreach my $a ( @{$self->{_fields}} ) { $width += $a->{width} + $cw; } $self->{_width} = $width - $cw; # PBP: Return nothing sensible. return; } sub _format_line { my ($self, $values, $widths) = @_; my $t = ""; my $i = 0; for ( my $i = 0; $i <= $#{$self->{_fields}}; $i++ ) { $t .= $self->{_colsep} if $t ne '' && $widths->[$i]; my $a = $self->{_fields}->[$i]; my $v = shift(@$values); if ( $a->{align} eq '<' ) { $t .= $v; $t .= ' ' x ($widths->[$i] - length($v)); } #elsif ( $a->{align} eq '<' ) { else { $t .= ' ' x ($widths->[$i] - length($v)); $t .= $v; } $i += $a->{colspan} if $a->{colspan}; } $t . "\n"; } sub _checkskip { my ($self, $cancel) = @_; return if !$self->{_needskip} || $self->{_lines} <= 0; $self->{_lines}--, print {$self->{fh}} ("\n") unless $cancel; $self->{_needskip} = 0; } sub _line { my ($self) = @_; $self->_checkhdr; $self->_checkskip(1); # cancel skips. print {$self->{fh}} ("-" x ($self->{_width}), "\n"); $self->{_lines}--; } sub _skip { my ($self) = @_; $self->_checkhdr; $self->{_needskip} = 1; } sub _center { my ($self, $text, $width) = @_; (" " x (($width - length($text))/2)) . $text; } sub _expand { my ($self, $text) = @_; $text =~ s/(.)/$1 /g; $text =~ s/ +$//; $text; } 1; EekBoek-2.030.1/lib/EB/Report/Reporter/Csv.pm0000644000400000040000000000325712725476602016204 0ustar jvjv#! perl # Csv.pm -- Reporter backend for CSV reports. # Author : Johan Vromans # Created On : Thu Jan 5 18:47:37 2006 # Last Modified By: Johan Vromans # Last Modified On: Sat Jun 19 00:39:24 2010 # Update Count : 16 # Status : Unknown, Use with caution! package main; our $cfg; our $dbh; package EB::Report::Reporter::Csv; use strict; use warnings; use EB; use base qw(EB::Report::Reporter); ################ API ################ sub start { my ($self, @args) = @_; $self->SUPER::start(@args); } sub finish { my ($self) = @_; $self->SUPER::finish(); close($self->{fh}); } my $sep; sub add { my ($self, $data) = @_; my $style = delete($data->{_style}); $self->SUPER::add($data); return unless %$data; $sep = $self->{_sep} ||= $cfg->val(qw(csv separator), ","); $self->_checkhdr; my $line; foreach my $col ( @{$self->{_fields}} ) { my $fname = $col->{name}; my $value = defined($data->{$fname}) ? _csv($data->{$fname}) : ""; $line .= $sep if defined($line); $line .= $value; } print {$self->{fh}} ($line, "\n"); } ################ Pseudo-Internal (used by Base class) ################ sub header { my ($self) = @_; if ( grep { $_->{title} =~ /\S/ } @{$self->{_fields}} ) { print {$self->{fh}} (join($sep, map { _csv($_->{title}||"") } @{$self->{_fields}}), "\n"); } } ################ Internal methods ################ sub _csv { my ($value) = @_; # Quotes must be doubled. $value =~ s/"/""/g; # Quote if anything non-simple. $value = '"' . $value . '"' if $value =~ /\s|\Q$sep\E|"/ || $value !~ /^[+-]?\d+([.,]\d+)?/; return $value; } 1; EekBoek-2.030.1/lib/EB/Report/Reporter/WxHtml.pm0000644000400000040000000001262413044346163016663 0ustar jvjv#! perl # WxHtml.pm -- Reporter backend for WxHtml # Author : Johan Vromans # Created On : Fri Mar 2 21:01:17 2007 # Last Modified By: Johan Vromans # Last Modified On: Fri Oct 9 20:38:04 2015 # Update Count : 77 # Status : Unknown, Use with caution! # WxHtmlWindow supports HTML, but to a limited extent. In particular, # no CSS. # For WxHtml we generate a simplified HTML, where the ornaments and # decorations are handled in the HTML subset supported. package main; our $cfg; our $dbh; package EB::Report::Reporter::WxHtml; use strict; use warnings; use EB; use base qw(EB::Report::Reporter); ################ API ################ sub new { my ($class, $opts) = @_; # This backend can collect the output in a scalar. my $o; $o = delete($opts->{output}) if $opts->{output} && UNIVERSAL::isa($opts->{output}, 'SCALAR'); my $self = $class->SUPER::new($opts); $self->{overall_font_size} = $cfg->val(qw(wxhtml fontsize), "0");; $self->{_OUT} = $o if $o; return $self; } my $html; sub start { my ($self, @args) = @_; eval { require HTML::Entities; }; $html = $@ ? \&__html : \&_html; $self->SUPER::start(@args); } sub finish { my ($self) = @_; $self->SUPER::finish(); $self->_print("
\n"); $self->_print("\n") if $self->{overall_font_size}; $self->_print("\n", "\n"); $self->_close; } sub add { my ($self, $data) = @_; my $style = delete($data->{_style}); $self->SUPER::add($data); return unless %$data; $self->_checkhdr; $self->_print("\n"); my %style; if ( $style && (my $t = $self->_getstyle($style)) ) { %style = %$t; } my $colspan = 0; foreach my $col ( @{$self->{_fields}} ) { if ( $colspan > 1 ) { $colspan--; next; } my $fname = $col->{name}; my $value = defined($data->{$fname}) ? $data->{$fname} : ""; my $align = $col->{align} eq "<" ? "left" : $col->{align} eq ">" ? "right" : "center"; $align = " align=\"$align\"" if $align; my $val = $value eq "" ? " " : $html->($value); # Examine style mods. my ($font, $weight, $italic, $indent); if ( $style ) { if ( my $t = $self->_getstyle($style, $fname) ) { $t = { %style, %$t }; my $colour = $t->{colour} || $t->{color} || ""; $colour = " color=\"$colour\"" if $colour; my $size = defined($t->{size}) ? " size=\"$t->{size}\"" : ""; $weight = [ "", "" ] if defined($t->{weight}) && $t->{weight} eq "bold"; $italic = [ "", "" ] if $t->{italic}; $font = [ "", "" ] if $colour || $size; $align = " align=\"$t->{align}\"" if $t->{align}; $indent = " " x (2 * $t->{indent}) if $t->{indent}; if ( $t->{colspan} && $t->{colspan} > 1 ) { $colspan = $t->{colspan}; $align .= " colspan=\"" . $colspan . "\""; } if ( $t->{link} && $value ne "" ) { my $v = "{link}.$value."?"; if ( $self->{periodex} ) { $v .= "periode=" . $self->{per_begin} . "-" . $self->{per_end} . "&"; } chop($v); $val = $v."\">$val"; } if ( $t->{att} && $value ne "" ) { my $v = $val . "  {att}.$value."?"; if ( $self->{periodex} ) { $v .= "periode=" . $self->{per_begin} . "-" . $self->{per_end} . "&"; } chop($v); $val = $v."\">\x{1f4c4}"; } } } $self->_print("", $font ? $font->[0] : (), $weight ? $weight->[0] : (), $italic ? $italic->[0] : (), $indent ? $indent : (), $val, $italic ? $italic->[1] : (), $weight ? $weight->[1] : (), $font ? $font->[1] : (), "\n"); } $self->_print("\n"); } ################ Pseudo-Internal (used by Base class) ################ sub header { my ($self) = @_; my $ofs = $self->{overall_font_size}; $self->_print ("\n", "\n", "", $html->($self->{_title1}), "\n", "\n", "\n", $ofs ? "\n" : (), "

", $html->($self->{_title1}), "
\n", $html->($self->{_title2}), "
\n", $html->($self->{_title3l}), "
\n", " 

\n", $ofs ? "
\n" : (), $ofs ? "\n" : (), "\n"); if ( grep { $_->{title} =~ /\S/ } @{$self->{_fields}} ) { $self->_print("\n"); foreach ( @{$self->{_fields}} ) { $self->_print("\n"); } $self->_print("\n"); } } ################ Internal methods ################ sub _print { my $self = shift; if ( exists($self->{_OUT}) ) { ${$self->{_OUT}} .= $_ foreach @_; return; } $self->{fh}->print(@_); } sub _close { my $self = shift; if ( exists($self->{_OUT}) ) { return; } $self->{fh}->close; } sub html { my $self = shift; _html(@_); } sub _html { HTML::Entities::encode(shift); } sub __html { my ($t) = @_; $t =~ s/&/&/g; $t =~ s//>/g; $t =~ s/\240/ /g; $t =~ s/\x{eb}/ë/g; # for IVP. $t; } 1; EekBoek-2.030.1/lib/EB/Report/Reporter/Html.pm0000644000400000040000000001071212725476601016346 0ustar jvjv#! perl # Html.pm -- HTML backend for Reporters. # Author : Johan Vromans # Created On : Thu Dec 29 15:46:47 2005 # Last Modified By: Johan Vromans # Last Modified On: Sat Jun 19 00:39:34 2010 # Update Count : 70 # Status : Unknown, Use with caution! package main; our $dbh; our $cfg; package EB::Report::Reporter::Html; use strict; use warnings; use EB; use EB::Format qw(datefmt_full); use base qw(EB::Report::Reporter); ################ API ################ my $html; sub start { my ($self, @args) = @_; eval { require HTML::Entities; }; $html = $@ ? \&__html : \&_html; $self->SUPER::start(@args); } sub finish { my ($self) = @_; $self->SUPER::finish(); print {$self->{fh}} ("
{align} eq "<" ? "left" : $_->{align} eq ">" ? "right" : "center", "\">", "", $html->($_->{title}), "
\n"); my $now = $cfg->val(qw(internal now), iso8601date()); # Treat empty value as no value. $now ||= iso8601date(); my $ident = $EB::ident; $ident = (split(' ', $ident))[0] if $cfg->val(qw(internal now), 0); $self->{fh}->print("

", __x("Overzicht aangemaakt op {date} door {ident}", ident => $ident, date => datefmt_full($now), url => $EB::url), "

\n"); $self->{fh}->print("\n", "\n"); close($self->{fh}); } sub add { my ($self, $data) = @_; my $style = delete($data->{_style}); $self->SUPER::add($data); return unless %$data; $self->_checkhdr; print {$self->{fh}} ("\n"); my $colspan = 0; foreach my $col ( @{$self->{_fields}} ) { if ( $colspan > 1 ) { $colspan--; next; } my $fname = $col->{name}; my $value = defined($data->{$fname}) ? $data->{$fname} : ""; my $class = "c_$fname"; # Examine style mods. if ( $style ) { if ( my $t = $self->_getstyle($style, $fname) ) { if ( $t->{class} ) { $class = $t->{class}; } if ( $t->{colspan} ) { $colspan = $t->{colspan}; } } } print {$self->{fh}} (" 1 ? " colspan=\"$colspan\"" : "", ">", $value eq "" ? " " : $html->($value), "\n"); } print {$self->{fh}} ("\n"); } ################ Pseudo-Internal (used by Base class) ################ sub header { my ($self) = @_; print {$self->{fh}} ("\n", "\n", "", $html->($self->{_title0} || $self->{_title1}), "\n"); if ( my $style = $self->{_style} ) { if ( $style =~ /\W/ ) { print {$self->{fh}} ('', "\n"); } elsif ( defined $self->{_cssdir} ) { print {$self->{fh}} ('', "\n"); } elsif ( my $css = findlib("css/".$style.".css") ) { print {$self->{fh}} ('', "\n"); } else { print {$self->{fh}} ("\n"); } } print {$self->{fh}} ("\n", "\n", "

", $html->($self->{_title1}), "

\n", "

", $html->($self->{_title2}), "
\n", $html->($self->{_title3l}), "

\n", "\n"); if ( grep { $_->{title} =~ /\S/ } @{$self->{_fields}} ) { print {$self->{fh}} ("\n"); foreach ( @{$self->{_fields}} ) { print {$self->{fh}} ("\n"); } print {$self->{fh}} ("\n"); } } ################ Internal methods ################ sub html { my $self = shift; _html(@_); } sub _html { HTML::Entities::encode(shift); } sub __html { my ($t) = @_; $t =~ s/&/&/g; $t =~ s//>/g; $t =~ s/\240/ /g; $t =~ s/\x{eb}/ë/g; # for IVP. $t; } sub copy_style { my ($out, $css) = @_; my $in; unless ( open($in, "<:encoding(utf-8)", $css) ) { print {$out} ("/**** stylesheet $css: $! ****/\n"); return; } print {$out} ("/** begin stylesheet $css */\n"); while ( <$in> ) { if ( /^\s*\@import\s*(["']?)(.*?)\1\s*;/ ) { use File::Basename; my $newcss = join("/", dirname($css), $2); copy_style($out, $newcss); } else { print {$out} $_; } } close($in); print {$out} ("/** end stylesheet $css */\n"); } 1; EekBoek-2.030.1/lib/EB/Report/Journal.pm0000644000400000040000000002134013044346163015243 0ustar jvjv#! perl # Author : Johan Vromans # Created On : Sat Jun 11 13:44:43 2005 # Last Modified By: Johan Vromans # Last Modified On: Thu Oct 8 22:21:28 2015 # Update Count : 344 # Status : Unknown, Use with caution! ################ Common stuff ################ package main; our $cfg; our $dbh; package EB::Report::Journal; use strict; use warnings; use EB; use EB::Format; use EB::Booking; # for dcfromtd() use EB::Report::GenBase; sub new { bless {}, shift; } sub journal { my ($self, $opts) = @_; my $nr = $opts->{select}; my $pfx = $opts->{postfix} || ""; my $detail = $opts->{detail}; my $extra_btw_info = $cfg->val(qw(journal btwxinfo), $dbh->does_btw ? 1 : 0); $opts->{STYLE} = "journaal"; $opts->{LAYOUT} = [ { name => "date", title => _T("Datum"), width => $date_width, }, { name => "desc", title => _T("Boekstuk/Grootboek"), width => 30, }, { name => "acct", title => _T("Rek"), width => 5, align => ">", }, { name => "deb", title => _T("Debet"), width => $amount_width, align => ">", }, { name => "crd", title => _T("Credit"), width => $amount_width, align => ">", }, $extra_btw_info ? ({ name => "btw", title => _T("BTW \%"), width => $amount_width, align => ">", }, { name => "btg", title => _T("Tarief"), width => 10, }) : (), { name => "bsk", title => _T("Boekstuk/regel"), width => 30, }, { name => "rel", title => _T("Relatie"), width => 10, }, ]; my $rep = EB::Report::GenBase->backend($self, $opts); my $per = $rep->{periode}; if ( my $t = $cfg->val(qw(internal now), 0) ) { $per->[1] = $t if $t lt $per->[1]; } # Sort order (boekstukken). my $so = join(", ", $opts->{bkstsort} ? ( "jnl_dbk_id", # dagboek "bsk_nr", # boekstuk "jnl_date", # date ) : ( "jnl_date", # date "jnl_dbk_id", # dagboek "bsk_nr", # boekstuk ), "CASE WHEN jnl_seq = 0 THEN 0 ELSE 1 END",# bsr 0 eerst "sign(jnl_amount) DESC", # debet eerst "jnl_acc_id", # rekeningnummer "jnl_amount DESC", # grootste bedragen vooraan "jnl_type", "jnl_seq"); # if all else fails $rep->start(_T("Journaal")); my $sth; if ( $nr ) { if ( $nr =~ /^([[:alpha:]].*):(\d+)$/ ) { my $rr = $dbh->do("SELECT dbk_desc, dbk_id". " FROM Dagboeken". " WHERE dbk_desc ILIKE ?", $1); unless ( $rr ) { warn("?".__x("Onbekend dagboek: {dbk}", dbk => $1)."\n"); return; } $sth = $dbh->sql_exec("SELECT jnl_date, jnl_bsr_date, jnl_dbk_id, jnl_bsk_id, bsk_nr, jnl_bsr_seq, jnl_seq, ". "jnl_type, jnl_acc_id, jnl_amount, jnl_damount, jnl_desc, jnl_rel, jnl_bsk_ref". " FROM Journal, Boekstukken, Dagboeken". " WHERE bsk_nr = ?". " AND dbk_id = ?". " AND jnl_bsk_id = bsk_id". " AND jnl_dbk_id = dbk_id". ($per ? " AND jnl_date >= ? AND jnl_date <= ?" : ""). " ORDER BY ".$so, $2, $rr->[1], $per ? @$per : ()); $pfx ||= __x("Boekstuk {nr}", nr => "$rr->[0]:$2"); } elsif ( $nr =~ /^([[:alpha:]].*)$/ ) { my $rr = $dbh->do("SELECT dbk_desc, dbk_id". " FROM Dagboeken". " WHERE dbk_desc ILIKE ?", $1); unless ( $rr ) { warn("?".__x("Onbekend dagboek: {dbk}", dbk => $1)."\n"); return; } $sth = $dbh->sql_exec("SELECT jnl_date, jnl_bsr_date, jnl_dbk_id, jnl_bsk_id, bsk_nr, jnl_bsr_seq, jnl_seq, ". "jnl_type, jnl_acc_id, jnl_amount, jnl_damount, jnl_desc, jnl_rel, jnl_bsk_ref". " FROM Journal, Boekstukken, Dagboeken". " WHERE dbk_id = ?". " AND jnl_bsk_id = bsk_id". " AND jnl_dbk_id = dbk_id". ($per ? " AND jnl_date >= ? AND jnl_date <= ?" : ""). " ORDER BY ".$so, $rr->[1], $per ? @$per : ()); $pfx ||= __x("Dagboek {nr}", nr => $rr->[0]); } else { $sth = $dbh->sql_exec("SELECT jnl_date, jnl_bsr_date, jnl_dbk_id, jnl_bsk_id, bsk_nr, jnl_bsr_seq, jnl_seq, ". "jnl_type, jnl_acc_id, jnl_amount, jnl_damount, jnl_desc, jnl_rel". " FROM Journal, Boekstukken". " WHERE jnl_bsk_id = ?". " AND jnl_bsk_id = bsk_id". ($per ? " AND jnl_date >= ? AND jnl_date <= ?" : ""). " ORDER BY ".$so,, $nr, $per ? @$per : ()); $pfx ||= __x("Boekstuk {nr}", nr => $nr); } } else { $sth = $dbh->sql_exec("SELECT jnl_date, jnl_bsr_date, jnl_dbk_id, jnl_bsk_id, bsk_nr, jnl_bsr_seq, jnl_seq, ". "jnl_type, jnl_acc_id, jnl_amount, jnl_damount, jnl_desc, jnl_rel, jnl_bsk_ref". " FROM Journal, Boekstukken". " WHERE jnl_bsk_id = bsk_id". ($per ? " AND jnl_date >= ? AND jnl_date <= ?" : ""). " ORDER BY ".$so, $per ? @$per : ()); } my $rr; my $nl = 0; my $totd = my $totc = 0; while ( $rr = $sth->fetchrow_arrayref ) { my ($jnl_date, $jnl_bsr_date, $jnl_dbk_id, $jnl_bsk_id, $bsk_nr, $jnl_bsr_seq, $jnl_seq, $jnl_type, $jnl_acc_id, $jnl_amount, $jnl_damount, $jnl_desc, $jnl_rel, $jnl_bsk_ref) = @$rr; my $iv = _dbk_type($jnl_dbk_id) == DBKTYPE_INKOOP ? 'c' : _dbk_type($jnl_dbk_id) == DBKTYPE_VERKOOP ? 'd' : ''; if ( $jnl_seq == 0 ) { $nl++, next unless $detail; my $t = $jnl_rel; if ( $t && $jnl_bsk_ref ) { $t .= ":" . $jnl_bsk_ref; } if ( $iv && $cfg->val(qw(internal noxrel), 0) ) { undef $t; } my $st = $iv.'head'; if ( EB::Booking->find_attachment($jnl_bsk_id) ) { $st .= 'a'; } $rep->add({ _style => $st, date => datefmt($jnl_bsr_date), desc => join(":", _dbk_desc($jnl_dbk_id), $bsk_nr), bsk => $jnl_desc, rel => $t, }); next; } my ($deb, $crd) = EB::Booking::dcfromtd($jnl_amount, $jnl_damount); $totd += $deb; $totc += $crd; next unless $detail; my $t = $jnl_rel; if ( $t && $jnl_bsk_ref ) { $t .= ":" . $jnl_bsk_ref; } if ( $t ) { $iv = _acc_type($jnl_acc_id) ? 'd' : 'c'; } else { $iv = ''; } my $btw_perc = ""; my $btw_tg = ""; if ( $extra_btw_info > 1 || ( $extra_btw_info && defined($jnl_type) && $jnl_type == 0 ) ) { my $res = $dbh->do( "SELECT bsr_btw_id, bsr_btw_class FROM Boekstukregels". " WHERE bsr_bsk_id = ? AND bsr_nr = ?", $jnl_bsk_id, $jnl_bsr_seq ); if ( defined($res) && defined($res->[0]) && defined($res->[1]) && $res->[1] & BTWKLASSE_BTW_BIT ) { my $btw_id = $res->[0]; $res = $dbh->do( "SELECT btw_perc, btw_tariefgroep". " FROM BTWTabel". " WHERE btw_id = ?", $btw_id ); $btw_perc = btwfmt( $res->[0] ); $btw_tg = BTWTARIEVEN->[$res->[1]]; } } $rep->add({ _style => $iv.'data', date => datefmt($jnl_bsr_date), desc => _acc_desc($jnl_acc_id), acct => $jnl_acc_id, ($deb || defined $jnl_damount) ? (deb => numfmt($deb)) : (), ($crd || defined $jnl_damount) ? (crd => numfmt($crd)) : (), bsk => $jnl_desc, $jnl_rel ? ( rel => $t ) : (), $extra_btw_info ? ( btw => $btw_perc, btg => $btw_tg ) : (), }); } $rep->add({ _style => 'total', desc => __x("Totaal {pfx}", pfx => $pfx), deb => numfmt($totd), crd => numfmt($totc), }); $rep->finish; } my %dbk_desc; sub _dbk_desc { $dbk_desc{$_[0]} ||= $dbh->lookup($_[0], qw(Dagboeken dbk_id dbk_desc =)); } my %dbk_type; sub _dbk_type { $dbk_type{$_[0]} ||= $dbh->lookup($_[0], qw(Dagboeken dbk_id dbk_type =)); } my %acc_desc; sub _acc_desc { return '' unless $_[0]; $acc_desc{$_[0]} ||= $dbh->lookup($_[0], qw(Accounts acc_id acc_desc =)); } my %acc_type; sub _acc_type { return '' unless $_[0]; $acc_type{$_[0]} ||= $dbh->lookup($_[0], qw(Accounts acc_id acc_debcrd =)); } package EB::Report::Journal::Text; use EB; use base qw(EB::Report::Reporter::Text); use strict; sub new { my ($class, $opts) = @_; $class->SUPER::new($opts->{STYLE}, $opts->{LAYOUT}); } # Style mods. sub style { my ($self, $row, $cell) = @_; my $style_data = { _style => { skip_after => 1, cancel_skip => 1, }, desc => { indent => 2 }, bsk => { indent => 2 }, }; my $stylesheet = { data => $style_data, cdata => $style_data, ddata => $style_data, total => { _style => { line_before => 1 }, # desc => { excess => 2 }, }, }; $cell = "_style" unless defined($cell); return $stylesheet->{$row}->{$cell}; } package EB::Report::Journal::Html; use EB; use base qw(EB::Report::Reporter::Html); use strict; sub new { my ($class, $opts) = @_; $class->SUPER::new($opts->{STYLE}, $opts->{LAYOUT}); } package EB::Report::Journal::Csv; use EB; use base qw(EB::Report::Reporter::Csv); sub new { my ($class, $opts) = @_; $class->SUPER::new($opts->{STYLE}, $opts->{LAYOUT}); } 1; EekBoek-2.030.1/lib/EB/Report/Debcrd.pm0000644000400000040000000002116412725476601015026 0ustar jvjv#! perl package main; our $cfg; our $dbh; package EB::Report::Debcrd; # Author : Johan Vromans # Created On : Wed Dec 28 16:08:10 2005 # Last Modified By: Johan Vromans # Last Modified On: Sun Jun 24 22:23:55 2012 # Update Count : 188 # Status : Unknown, Use with caution! ################ Common stuff ################ use strict; use warnings; ################ The Process ################ use EB; use EB::Format; use EB::Report::GenBase; ################ Subroutines ################ sub new { return bless {}; } sub debiteuren { my ($self, $args, $opts) = @_; $self->_perform($args, $opts, 1); } sub crediteuren { my ($self, $args, $opts) = @_; $self->_perform($args, $opts, 0); } sub _perform { my ($self, $args, $opts, $debcrd) = @_; if ( $args ) { $args = join("|", map { quotemeta($_) } @$args); } $opts->{STYLE} = "debrept"; $opts->{LAYOUT} = [ { name => "debcrd", title => $debcrd ? _T("Debiteur") : _T("Crediteur"), width => 10 }, { name => "date", title => _T("Datum"), width => $date_width }, { name => "desc", title => _T("Omschrijving"), width => 25 }, { name => "amount", title => _T("Bedrag"), width => $amount_width, align => ">" }, { name => "open", title => _T("Open"), width => $amount_width, align => ">" }, { name => "paid", title => _T("Betaald"), width => $amount_width, align => ">" }, { name => "bsknr", title => _T("Boekstuk"), width => 18 }, ]; my $rep = EB::Report::GenBase->backend($self, { %$opts, debcrd => $debcrd }); my %rels; my $sth; $sth = $dbh->sql_exec("SELECT DISTINCT bsr_rel_code". " FROM Boekstukregels, Boekstukken, Dagboeken". " WHERE bsr_date >= ? AND bsr_date <= ?". " AND bsr_bsk_id = bsk_id". " AND bsk_dbk_id = dbk_id". " AND dbk_type = ?", @{$rep->{periode}}, $debcrd ? DBKTYPE_VERKOOP : DBKTYPE_INKOOP); while ( my $rr = $sth->fetchrow_arrayref ) { next if $args && $rr->[0] !~ /^$args$/i; $rels{$rr->[0]} = undef; } $sth->finish; $sth = $dbh->sql_exec("SELECT bsr_rel_code, bsr_paid". " FROM Boekstukregels, Boekstukken". " WHERE bsr_paid = bsk_id". " AND bsr_date >= ? AND bsr_date <= ?". " AND bsk_date < ?". " AND bsr_type = ?", @{$rep->{periode}}, $rep->{per_begin}, $debcrd ? DBKTYPE_INKOOP : DBKTYPE_VERKOOP); while ( my $rr = $sth->fetchrow_arrayref ) { next if $args && $rr->[0] !~ /^$args$/i; $rels{$rr->[0]}->{$rr->[1]} = 1; } $sth->finish; return "!"._T("Geen boekingen gevonden") unless %rels; $rep->start($debcrd ? _T("Debiteurenadministratie") : _T("Crediteurenadministratie")); my $a_grand = 0; my $o_grand = 0; foreach my $rel ( sort(keys(%rels)) ) { my $a_tot = 0; my $o_tot = 0; my @rp = (); push(@rp, { debcrd => $rel, _style=> "h1" }); my $sth; # Process betalingen zonder boekstuk. if ( $rels{$rel} ) { foreach my $bsk_id ( keys %{$rels{$rel}} ) { my $sth; $sth = $dbh->sql_exec("SELECT bsk_id, bsk_desc, bsk_date,". " bsk_amount, bsk_open, dbk_desc, bsk_nr, bsk_bky". " FROM Boekstukken, Boekstukregels, Dagboeken". " WHERE bsk_id = ?". " AND bsk_dbk_id = dbk_id". " AND bsr_bsk_id = bsk_id", $bsk_id); my $rr = $sth->fetchrow_arrayref; $sth->finish; my ($bsk_id, $bsk_desc, $bsk_date, $bsr_amount, $bsr_open, $dbk_desc, $bsk_nr, $bsk_bky) = @$rr; # Correct for future payments. my $rop = $dbh->do("SELECT sum(bsr_amount)". " FROM Boekstukregels". " WHERE bsr_type = ?". " AND bsr_date > ?". " AND bsr_paid = ?", $debcrd ? 1 : 2, $rep->{per_end}, $bsk_id); if ( $rop && $rop->[0] ) { $bsr_open -= $rop->[0]; } $bsr_amount = 0-$bsr_amount unless $debcrd; $bsr_open = 0-$bsr_open unless $debcrd; $a_tot += $bsr_amount; $o_tot += $bsr_open; push(@rp, { desc => $bsk_desc, date => datefmt($bsk_date), amount => numfmt($bsr_amount), open => numfmt($bsr_open), bsknr => join(":", $dbk_desc, $bsk_bky, $bsk_nr), _style => "bskprv", }); $sth = $dbh->sql_exec("SELECT bsr_date, bsr_desc, bsr_amount,". " dbk_desc, bsk_nr". " FROM Boekstukregels, Boekstukken, Dagboeken". " WHERE bsr_type = ?". " AND bsr_date >= ? AND bsr_date <= ?". " AND bsr_paid = ?". " AND bsr_bsk_id = bsk_id AND bsk_dbk_id = dbk_id". " ORDER BY bsr_date, bsk_nr", $debcrd ? 1 : 2, @{$rep->{periode}}, $bsk_id); while ( my $rr = $sth->fetchrow_arrayref ) { my ($x_bsr_date, $x_bsr_desc, $x_bsr_amount, $x_dbk_desc, $x_bsk_nr, $x_bsk_bky) = @$rr; $x_bsr_amount = 0-$x_bsr_amount unless $debcrd; push(@rp, { desc => $x_bsr_desc, date => datefmt($x_bsr_date), paid => numfmt(0-$x_bsr_amount), bsknr => join(":", $x_dbk_desc, $x_bsk_nr), _style => "paid", }); } } } # Process boekstukken met evt. betalingen. $sth = $dbh->sql_exec("SELECT bsk_id, bsk_desc, bsk_date,". " bsk_amount, bsk_open, dbk_desc, bsk_nr". " FROM Boekstukken, Boekstukregels, Dagboeken". " WHERE bsr_date >= ? AND bsr_date <= ?". " AND bsr_bsk_id = bsk_id". " AND bsk_dbk_id = dbk_id". " AND bsr_type = 0". " AND bsr_nr = 1". " AND bsr_rel_code = ?". " AND dbk_type = ?". " ORDER BY bsk_date, bsk_nr", @{$rep->{periode}}, $rel, $debcrd ? DBKTYPE_VERKOOP : DBKTYPE_INKOOP); while ( my $rr = $sth->fetchrow_arrayref ) { my ($bsk_id, $bsk_desc, $bsk_date, $bsr_amount, $bsr_open, $dbk_desc, $bsk_nr) = @$rr; # Correct for future payments. my $rop = $dbh->do("SELECT sum(bsr_amount)". " FROM Boekstukregels". " WHERE bsr_type = ?". " AND bsr_date > ?". " AND bsr_paid = ?", $debcrd ? 1 : 2, $rep->{per_end}, $bsk_id); if ( $rop && $rop->[0] ) { $bsr_open -= $rop->[0]; } next if $opts->{openstaand} && $bsr_open == 0; $bsr_amount = 0-$bsr_amount unless $debcrd; $bsr_open = 0-$bsr_open unless $debcrd; $a_tot += $bsr_amount; $o_tot += $bsr_open; push(@rp, { desc => $bsk_desc, date => datefmt($bsk_date), amount => numfmt($bsr_amount), open => numfmt($bsr_open), bsknr => join(":", $dbk_desc, $bsk_nr), _style => "bsk", }); my $sth = $dbh->sql_exec("SELECT bsr_date, bsr_desc, bsr_amount,". " dbk_desc, bsk_nr". " FROM Boekstukregels, Boekstukken, Dagboeken". " WHERE bsr_type = ?". " AND bsr_date >= ? AND bsr_date <= ?". " AND bsr_paid = ?". " AND bsr_bsk_id = bsk_id AND bsk_dbk_id = dbk_id". " ORDER BY bsr_date, bsk_nr", $debcrd ? 1 : 2, @{$rep->{periode}}, $bsk_id); while ( my $rr = $sth->fetchrow_arrayref ) { my ($x_bsr_date, $x_bsr_desc, $x_bsr_amount, $x_dbk_desc, $x_bsk_nr) = @$rr; $x_bsr_amount = 0-$x_bsr_amount unless $debcrd; push(@rp, { desc => $x_bsr_desc, date => datefmt($x_bsr_date), paid => numfmt(0-$x_bsr_amount), bsknr => join(":", $x_dbk_desc, $x_bsk_nr), _style => "paid", }); } } push(@rp, { debcrd => $rel, desc => _T("Totaal"), amount => numfmt($a_tot), open => numfmt($o_tot), _style => "total", }); $a_grand += $a_tot; $o_grand += $o_tot; next if $opts->{openstaand} && $o_tot == 0; $rep->add($_) foreach @rp; } $rep->add({ debcrd => _T("Totaal"), amount => numfmt($a_grand), open => numfmt($o_grand), _style => "grand", }); $rep->finish; return; } package EB::Report::Debcrd::Text; use EB; use base qw(EB::Report::Reporter::Text); sub new { my ($class, $opts) = @_; $class->SUPER::new($opts->{STYLE}, $opts->{LAYOUT}); } # Style mods. sub style { my ($self, $row, $cell) = @_; my $stylesheet = { paid => { desc => { indent => 2 }, }, total => { _style => { skip_after => 1 }, amount => { line_before => 1 }, open => { line_before => 1 }, }, grand => { _style => { line_before => 1 } }, }; $cell = "_style" unless defined($cell); return $stylesheet->{$row}->{$cell}; } package EB::Report::Debcrd::Html; use EB; use base qw(EB::Report::Reporter::Html); sub new { my ($class, $opts) = @_; $class->SUPER::new($opts->{STYLE}, $opts->{LAYOUT}); } package EB::Report::Debcrd::Csv; use EB; use base qw(EB::Report::Reporter::Csv); sub new { my ($class, $opts) = @_; $class->SUPER::new($opts->{STYLE}, $opts->{LAYOUT}); } 1; EekBoek-2.030.1/lib/EB/Booking/0000755000400000040000000000000013151742350013405 5ustar jvjvEekBoek-2.030.1/lib/EB/Booking/Delete.pm0000644000400000040000000001016313044346163015151 0ustar jvjv#! perl package main; our $dbh; our $spp; our $config; package EB::Booking::Delete; # Author : Johan Vromans # Created On : Mon Sep 19 22:19:05 2005 # Last Modified By: Johan Vromans # Last Modified On: Thu Sep 24 22:01:25 2015 # Update Count : 90 # Status : Unknown, Use with caution! ################ Common stuff ################ use strict; use warnings; use EB; use base qw(EB::Booking); sub new { return bless {}, shift; } sub perform { my ($self, $id, $opts) = @_; my $sth; my $rr; my $orig = $id; my $bky = $self->{bky} ||= $opts->{boekjaar} || $dbh->adm("bky"); my ($bsk, $dbsk, $err) = $dbh->bskid($id, $bky); die("?$err\n") unless defined $bsk; my $does_btw = $dbh->does_btw; my ($dd) = @{$dbh->do("SELECT bsk_date". " FROM Boekstukken". " WHERE bsk_id = ?", $bsk)}; my ($begin, $end); return unless ($begin, $end) = $self->begindate; return unless $self->in_bky($dd, $begin, $end); if ( $does_btw && $dbh->adm("btwbegin") && $dd lt $dbh->adm("btwbegin") ) { my $r = $dbh->do("SELECT COUNT(*)". " from Boekstukregels, Boekstukken". " WHERE bsr_bsk_id = bsk_id". " AND bsr_bsk_id = ?". " AND ( bsr_btw_class != 0 OR bsr_btw_id != 0 )". " LIMIT 1", $bsk); if ( $r && $r->[0] ) { warn("?"._T("Deze boeking valt in de periode waarover al BTW aangifte is gedaan en kan niet meer worden verwijderd")."\n"); return; } } my ($amt, $open, $dbk, $att) = @{$dbh->do("SELECT bsk_amount,bsk_open,bsk_dbk_id,bsk_att". " FROM Boekstukken". " WHERE bsk_id = ?", $bsk)}; # Check if this boekstuk is used by others. This can only be the # case if has been paid. if ( defined($open) && $amt != $open ) { # It has been paid. Show the user the list of bookstukken. $sth = $dbh->sql_exec("SELECT dbk_desc, bsk_nr". " FROM Boekstukken,Boekstukregels,Dagboeken". " WHERE bsk_id = bsr_bsk_id". " AND bsk_dbk_id = dbk_id". " AND bsr_paid = ?", $bsk); $rr = $sth->fetchall_arrayref; if ( $rr ) { my $t = ""; foreach ( @$rr ) { $t .= join(":", @$_) . " "; } chomp($t); return "?".__x("Boekstuk {bsk} is in gebruik door {lst}", bsk => $dbsk, lst => $t)."\n"; } } # Collect list of affected boekstukken. $sth = $dbh->sql_exec("SELECT bsr_paid,bsr_amount". " FROM Boekstukregels". " WHERE bsr_paid IS NOT NULL AND bsr_bsk_id = ?", $bsk); $rr = $sth->fetchall_arrayref; my @bsk; my @amt; if ( $rr ) { foreach ( @$rr ) { push(@bsk, $_->[0]); push(@amt, $_->[1]); } } eval { $dbh->begin_work; # Adjust saldi grootboekrekeningen. # Hoewel in veel gevallen niet nodig, is het toch noodzakelijk i.v.m. # de saldi van bankrekeningen. $sth = $dbh->sql_exec("SELECT jnl_acc_id, jnl_amount". " FROM Journal". " WHERE jnl_bsk_id = ? AND jnl_seq > 0", $bsk); while ( my $rr = $sth->fetchrow_arrayref ) { $dbh->upd_account($rr->[0], -$rr->[1]); } # Delete journal entries. $dbh->sql_exec("DELETE FROM Journal". " WHERE jnl_bsk_id = ?", $bsk)->finish; # Clear 'paid' info. $dbh->sql_exec("UPDATE Boekstukken". " SET bsk_open = bsk_open - ?". " WHERE bsk_id = ?", shift(@amt), $_)->finish foreach @bsk; # Delete boekstukregels. $dbh->sql_exec("DELETE FROM Boekstukregels". " WHERE bsr_bsk_id = ?", $bsk)->finish; # Delete boekstuk. $dbh->sql_exec("DELETE FROM Boekstukken". " WHERE bsk_id = ?", $bsk)->finish; # Delete attachments. $dbh->drop_attachment($att) if defined $att; # # Adjust saldi van boekingen na deze. # $dbh->sql_exec("UPDATE Boekstukken". # " SET bsk_saldo = bsk_saldo - ?". # " WHERE bsk_saldo IS NOT NULL AND". # " bsk_dbk_id = ? AND bsk_id > ?", # $amt, $dbk, $bsk)->finish; # If we get here, all went okay. $dbh->commit; }; if ( $@ ) { # It didn't work. Shouldn't happen. warn("?".$@); $dbh->rollback; return "?".__x("Boekstuk {bsk} niet verwijderd", bsk => $dbsk)."\n"; } return __x("Boekstuk {bsk} verwijderd", bsk => $dbsk)."\n"; } 1; EekBoek-2.030.1/lib/EB/Booking/Decode.pm0000644000400000040000000002343013044346163015133 0ustar jvjv#! perl package main; our $dbh; our $config; package EB::Booking::Decode; # Author : Johan Vromans # Created On : Tue Sep 20 15:16:31 2005 # Last Modified By: Johan Vromans # Last Modified On: Tue Oct 13 16:58:45 2015 # Update Count : 194 # Status : Unknown, Use with caution! ################ Common stuff ################ use strict; use warnings; use EB; use EB::Format; use EB::Booking; # for norm_btw() sub new { return bless {}, shift; } my @bsr_types = ([], [ "Standaard", ("") x 8, "Open post vorige periode" ], [ "Standaard", ("") x 8, "Open post vorige periode" ], [ "Standaard", "Betaling van debiteur", "Betaling aan crediteur" ], [ "Standaard", "Betaling van debiteur", "Betaling aan crediteur" ], [ "Standaard", "Betaling van debiteur", "Betaling aan crediteur" ], [], ); sub decode { my ($self, $bsk, $opts) = @_; my $trail = $opts->{trail}; my $single = $opts->{single}; my $ex_btw = $opts->{btw}; my $ex_bsknr = $opts->{bsknr}; my $ex_bky = $opts->{bky}; my $ex_debcrd = $opts->{debcrd}; my $ex_tot = $opts->{totaal} || $opts->{total}; my $no_ivbskdesc = $opts->{noivbskdesc}; my $dbver = sprintf("%03d%03d%03d", $dbh->adm("scm_majversion"), $dbh->adm("scm_minversion")||0, $dbh->adm("scm_revision")); $bsk = $dbh->bskid($bsk); my $rr = $dbh->do("SELECT bsk_id, bsk_nr, bsk_ref, bsk_desc, ". "bsk_dbk_id, bsk_date, bsk_amount, bsk_saldo, bsk_isaldo, bsk_bky ". ($dbver lt "001000002" ? ", bsk_paid" : ", bsk_open"). ",bsk_att". " FROM Boekstukken". " WHERE bsk_id = ?", $bsk); unless ( $rr ) { warn("?".__x("Onbekend boekstuk: {bsk}", bsk => $bsk)."\n"); return; } my ($bsk_id, $bsk_nr, $bsk_ref, $bsk_desc, $bsk_dbk_id, $bsk_date, $bsk_amount, $bsk_saldo, $bsk_isaldo, $bsk_bky, $bsk_open, $bsk_att) = @$rr; my $tot = 0; my ($dbktype, $acct, $dbk_desc) = @{$dbh->do("SELECT dbk_type, dbk_acc_id, dbk_desc". " FROM Dagboeken". " WHERE dbk_id = ?", $bsk_dbk_id)}; my $cmd = ""; my $setup = sub { my ($rel_code) = @_; if ( $trail ) { $cmd = lc($dbk_desc); $cmd =~ s/[^[:alnum:]]/_/g; $cmd .= ":$bsk_bky" if $ex_bky; $cmd .= ":$bsk_nr" if $ex_bsknr; $cmd .= " --".__xt("cmo:boeking:ref")."=" . _quote($bsk_ref) if defined $bsk_ref; $cmd .= " ".datefmt_full($bsk_date)." "; if ( $dbktype == DBKTYPE_INKOOP || $dbktype == DBKTYPE_VERKOOP ) { $cmd .= $no_ivbskdesc ? _quote($rel_code) : _quote($bsk_desc, $rel_code); } if ($dbktype == DBKTYPE_BANK || $dbktype == DBKTYPE_KAS || $dbktype == DBKTYPE_MEMORIAAL) { $cmd .= _quote($bsk_desc); } else { $cmd .= " --".__xt("cmo:boeking:totaal")."=" . numfmt_plain($dbktype == DBKTYPE_INKOOP ? 0-$bsk_amount : $bsk_amount) if $ex_tot && $acct; } $cmd .= " --".__xt("cmo:boeking:beginsaldo")."=" . numfmt_plain($bsk_isaldo) if $ex_tot && defined $bsk_isaldo; $cmd .= " --".__xt("cmo:boeking:saldo")."=" . numfmt_plain($bsk_saldo) if $ex_tot && defined $bsk_saldo; if ( $bsk_att ) { my ( $name, $enc, $contents ) = @{ $dbh->do("SELECT att_name, att_encoding". " FROM Attachments". " WHERE att_id = ?", $bsk_att) }; $name = sprintf("int://%08d/%s", $bsk_att, $name) unless $enc == ATTENCODING_URI; $cmd .= " --bijlage=" . _quote($name); } } else { $cmd = "Boekstuk $bsk_id, nr $bsk_nr, dagboek " . $dbh->lookup($bsk_dbk_id, qw(Dagboeken dbk_id dbk_desc =)). "($bsk_dbk_id)". ", datum ".datefmt_full($bsk_date). ", "; if ( $dbktype == DBKTYPE_INKOOP || $dbktype == DBKTYPE_VERKOOP ) { my ($rd, $rt) = @{$dbh->do("SELECT rel_desc,rel_debcrd". " FROM Relaties". " WHERE rel_code = ?", $rel_code)}; $cmd .= $rt ? "deb " : "crd "; $cmd .= "$rel_code ($rd), "; } $cmd .= _quote($bsk_desc); if ( $dbver lt "001000002" ) { $cmd .= $bsk_open ? ", *$bsk_open" : ", open" } elsif ( defined $bsk_open ) { $cmd .= $bsk_open ? ", @{[numfmt_plain(abs($bsk_open))]} open" : ", voldaan" } $cmd .= "\n"; } }; my $sth = $dbh->sql_exec("SELECT bsr_nr, bsr_date, ". "bsr_desc, bsr_amount, bsr_btw_id, bsr_btw_class, ". "bsr_type, bsr_acc_id, bsr_rel_code, bsr_paid, bsr_ref ". " FROM Boekstukregels". " WHERE bsr_bsk_id = ?". " ORDER BY bsr_nr", $bsk); $rr = $sth->fetchrow_arrayref; unless ( $rr ) { # Special case for boekstuk zonder boekstukregels. $setup->(undef); return $cmd; } while ( $rr ) { my ($bsr_nr, $bsr_date, $bsr_desc, $bsr_amount, $bsr_btw_id, $bsr_btw_class, $bsr_type, $bsr_acc_id, $bsr_rel_code, $bsr_paid, $bsr_ref) = @$rr; if ( $bsr_nr == 1) { $setup->($bsr_rel_code); } my ($rd, $rt, $acc_balres, $acc_kstomz) = $bsr_acc_id ? @{$dbh->do("SELECT acc_desc,acc_debcrd,acc_balres,acc_kstomz". " FROM Accounts". " WHERE acc_id = ?", $bsr_acc_id)} : ("[Open posten vorige periode]", 1); my $dc = $bsr_amount >= 0 ? "debet" : "credit"; $dc = uc($dc) unless (($bsr_amount < 0) xor $rt); $cmd .= join("", " Boekstukregel, nr $bsr_nr, datum $bsr_date, ", _quote($bsr_desc), ", type $bsr_type (", $bsr_types[$dbktype][$bsr_type], ")\n", " ", "bedrag ", numfmt_plain(abs($bsr_amount)), " ", $dc, defined($bsr_btw_id) ? (", BTW code $bsr_btw_id (", $dbh->lookup($bsr_btw_id, qw(BTWTabel btw_id btw_desc)), ")") : (), defined($bsr_acc_id) ? (", rek $bsr_acc_id (", $rt ? "D/" : "C/", $rd, ")",) : (), "\n") unless $trail; croak("INTERNAL ERROR: BTW/N id = $bsr_btw_id") if !($bsr_btw_class & BTWKLASSE_BTW_BIT) && $bsr_btw_id; my $a = EB::Booking::->norm_btw($bsr_amount, $bsr_btw_id); $tot += $a->[0]; next unless $trail; $bsr_acc_id ||= ""; my $btw = ""; # Refactor later. if ( $bsr_btw_class & BTWKLASSE_BTW_BIT ) { my $alias = $bsr_btw_id; if ( $bsr_btw_id > BTW_CODE_AUTO ) { if ( $bsr_btw_id & 1 ) { $alias = $dbh->lookup($bsr_btw_id, qw(BTWTabel btw_id btw_desc)); } else { $alias = $dbh->lookup($bsr_btw_id, qw(BTWTabel btw_id btw_alias)); $alias .= qw( - + )[$dbh->lookup($bsr_btw_id, qw(BTWTabel btw_id btw_incl))]; } } my $ko = $bsr_btw_class & BTWKLASSE_KO_BIT ? 1 : 0; if ( $ex_btw ) { $btw = $alias . qw(O K)[$ko]; } else { $btw .= $alias if btw_code($bsr_acc_id) != $bsr_btw_id || ($bsr_type == 0 && $dbktype == DBKTYPE_MEMORIAAL); $btw .= qw(O K)[$ko] if (!defined($acc_kstomz) || ($acc_kstomz xor $ko)); } } elsif ( $dbh->does_btw ) { if ( $ex_btw ) { $btw = 'N'; } else { $btw = 'N' if defined($acc_kstomz); } } $btw = '@' . $btw unless $btw eq ""; if ( $dbktype == DBKTYPE_INKOOP || $dbktype == DBKTYPE_VERKOOP ) { $bsr_amount = -$bsr_amount if $dbktype == DBKTYPE_VERKOOP; $cmd .= $single ? " " : " \\\n\t"; $cmd .= _quote($bsr_desc) . " " . numfmt_plain($bsr_amount) . $btw . " " . $bsr_acc_id; } elsif ( $dbktype == DBKTYPE_BANK || $dbktype == DBKTYPE_KAS || $dbktype == DBKTYPE_MEMORIAAL ) { $bsr_amount = -$bsr_amount; my $dd = ""; # Explicitly add the date if it is different, or when the # description could be parsed as a date (bug #40). $dd = " ".datefmt_full($bsr_date) if $bsr_date ne $bsk_date || $bsr_desc =~ /^[[:digit:]]+-/; if ( $bsr_type == 0 ) { $cmd .= $single ? " " : " \\\n\t"; $cmd .= "std$dd " . _quote($bsr_desc) . " " . numfmt_plain($bsr_amount) . $btw . " " . $bsr_acc_id; } elsif ( $bsr_ref && ( $bsr_type == 1 || $bsr_type == 2 ) ) { my $type = $bsr_type == 1 ? "deb" : "crd"; $cmd .= $single ? " " : " \\\n\t"; $cmd .= "$type$dd " . _quote($bsr_ref) . " " . numfmt_plain($bsr_amount); } elsif ( $bsr_type == 1 || $bsr_type == 2 ) { my $type = $bsr_type == 1 ? "deb" : "crd"; $cmd .= $single ? " " : " \\\n\t"; # Check for a full payment. my $sth = $dbh->sql_exec("SELECT bsk_amount, dbk_desc, bsk_nr, bsk_ref, bsr_rel_code, bsk_bky". " FROM Boekstukken, Boekstukregels, Dagboeken". " WHERE bsk_dbk_id = dbk_id". " AND bsr_bsk_id = bsk_id". " AND bsk_id = ?", $bsr_paid); my ($paid, $dbk, $nr, $ref, $rel, $bky) = @{$sth->fetchrow_arrayref}; $sth->finish; if ( $paid == $bsr_amount ) { # Matches -> Full payment $cmd .= "$type$dd " . _quote($bsr_rel_code) . " " . numfmt_plain($bsr_amount); } else { # Partial payment. Use boekstuknummer. $dbk = lc($dbk); $dbk =~ s/[^[:alnum:]]/_/g; my $t; if ( defined $ref ) { $t = $rel; $t .= ":$bky" if ($opts->{boekjaar}||$opts->{d_boekjaar}) ne $bky; $t .= ":$ref"; } else { $t = $dbk; $t .= ":$bky" if ($opts->{boekjaar}||$opts->{d_boekjaar}) ne $bky; $t .= ":$nr"; } $cmd .= join(" ", $type.$dd, _quote($t), numfmt_plain($bsr_amount)); } } } $rr = $sth->fetchrow_arrayref; } return ($cmd, $tot, $bsk_amount, $acct) if wantarray; $cmd; } ################ Subroutines ################ # Escape " quotes and \ so lines can be read in by parsewords. Note # that multiple arguments will be concatenated quoted, not quoted # concatenated. sub _quote { my @res; foreach my $t ( @_ ) { $t =~ s/(["\\])/\\$1/g; push(@res, "\"$t\""); } "@res"; } my %btw_code; sub btw_code { my($acct) = @_; return $btw_code{$acct} if defined $btw_code{$acct}; _lku($acct); $btw_code{$acct}; } sub _lku { my ($acct) = @_; Carp::confess("acct is null") unless $acct; my $rr = $dbh->do("SELECT acc_btw". " FROM Accounts". " WHERE acc_id = ?", $acct); die("?".__x("Onbekend rekeningnummer: {acct}", acct => $acct)."\n") unless $rr; $btw_code{$acct} = $rr->[0]; } 1; EekBoek-2.030.1/lib/EB/Booking/IV.pm0000644000400000040000000003024113044346163014264 0ustar jvjv#! perl -- -*- coding: utf-8 -*- use utf8; package main; our $cfg; our $dbh; package EB::Booking::IV; # Author : Johan Vromans # Created On : Thu Jul 7 14:50:41 2005 # Last Modified By: Johan Vromans # Last Modified On: Wed Oct 7 17:11:15 2015 # Update Count : 364 # Status : Unknown, Use with caution! ################ Common stuff ################ use strict; use warnings; # Dagboek type 1: Inkoop # Dagboek type 2: Verkoop use EB; use EB::Format; use EB::Report::Journal; use base qw(EB::Booking); my $trace_updates = $cfg->val(__PACKAGE__, "trace_updates", 0); # for debugging sub perform { my ($self, $args, $opts) = @_; return unless $self->adm_open; my $dagboek = $opts->{dagboek}; my $dagboek_type = $opts->{dagboek_type}; my $bsk_ref = $opts->{ref}; my $bsk_att = $opts->{bijlage}; if ( defined $bsk_ref && $bsk_ref =~ /^\d+$/ ) { warn("?".__x("Boekingsreferentie moet tenminste één niet-numeriek teken bevatten: {ref}", ref => $bsk_ref)."\n"); return; } if ( defined $bsk_att ) { return unless $self->check_attachment($bsk_att); } unless ( $dagboek_type == DBKTYPE_INKOOP || $dagboek_type == DBKTYPE_VERKOOP) { warn("?".__x("Ongeldige operatie (IV) voor dagboek type {type}", type => $dagboek_type)."\n"); return; } my $iv = $dagboek_type == DBKTYPE_INKOOP; my $totaal = $opts->{totaal}; my $does_btw = $dbh->does_btw; my $bky = $self->{bky} ||= $opts->{boekjaar} || $dbh->adm("bky"); if ( defined($totaal) ) { my $t = amount($totaal); return "?".__x("Ongeldig totaal: {total}", total => $totaal) unless defined $t; $totaal = $t; } my ($begin, $end); return unless ($begin, $end) = $self->begindate; my $date; if ( $date = parse_date($args->[0], substr($begin, 0, 4)) ) { shift(@$args); } else { return "?".__x("Onherkenbare datum: {date}", date => $args->[0])."\n" if ($args->[0]||"") =~ /^[[:digit:]]+-/; $date = iso8601date(); } return "?"._T("Deze opdracht is onvolledig. Gebruik de \"help\" opdracht voor meer aanwijzingen.")."\n" unless @$args >= 3; return unless $self->in_bky($date, $begin, $end); if ( $does_btw && $dbh->adm("btwbegin") && $date lt $dbh->adm("btwbegin") ) { warn("?"._T("De boekingsdatum valt in de periode waarover al BTW aangifte is gedaan")."\n"); return; } my $gdesc = ""; my $debcode; my $rr; if ( $cfg->val(qw(general ivdesc), undef) ) { $gdesc = shift(@$args); $debcode = shift(@$args); $rr = $dbh->do("SELECT rel_code, rel_acc_id, rel_btw_status FROM Relaties" . " WHERE UPPER(rel_code) = ?" . " AND " . ($iv ? "NOT " : "") . "rel_debcrd" . " AND rel_ledger = ?", uc($debcode), $dagboek); unless ( defined($rr) ) { unshift(@$args, $debcode); $debcode = $gdesc; $gdesc = ""; $rr = $dbh->do("SELECT rel_code, rel_acc_id, rel_btw_status FROM Relaties" . " WHERE UPPER(rel_code) = ?" . " AND " . ($iv ? "NOT " : "") . "rel_debcrd" . " AND rel_ledger = ?", uc($debcode), $dagboek); unless ( defined($rr) ) { warn("?".__x("Onbekende {what}: {who}", what => lc($iv ? _T("Crediteur") : _T("Debiteur")), who => $debcode)."\n"); return; } } } else { $debcode = shift(@$args); $rr = $dbh->do("SELECT rel_code, rel_acc_id, rel_btw_status FROM Relaties" . " WHERE UPPER(rel_code) = ?" . " AND " . ($iv ? "NOT " : "") . "rel_debcrd" . " AND rel_ledger = ?", uc($debcode), $dagboek); unless ( defined($rr) ) { $gdesc = $debcode; $debcode = shift(@$args); $rr = $dbh->do("SELECT rel_code, rel_acc_id, rel_btw_status FROM Relaties" . " WHERE UPPER(rel_code) = ?" . " AND " . ($iv ? "NOT " : "") . "rel_debcrd" . " AND rel_ledger = ?", uc($debcode), $dagboek); unless ( defined($rr) ) { warn("?".__x("Onbekende {what}: {who}", what => lc($iv ? _T("Crediteur") : _T("Debiteur")), who => $debcode)."\n"); return; } } } my ($rel_acc_id, $rel_btw); ($debcode, $rel_acc_id, $rel_btw) = @$rr; my $btw_adapt = $cfg->val(qw(strategy btw_adapt), 0); my $nr = 1; my $bsk_id; my $bsk_nr; my $did = 0; while ( @$args ) { return "?"._T("Deze opdracht is onvolledig. Gebruik de \"help\" opdracht voor meer aanwijzingen.")."\n" unless @$args >= 2; my ($desc, $amt, $acct) = splice(@$args, 0, 3); my $bsr_ref; $desc = $gdesc if $desc !~ /\S/; $gdesc = $desc if $gdesc !~ /\S/; $acct ||= $rel_acc_id; if ( $opts->{verbose} ) { my $t = $desc; $t = '"' . $desc . '"' if $t =~ /\s/; warn(" "._T("boekstuk").": $t $amt $acct\n"); } unless ( $desc =~ /\S/ ) { warn("?"._T("De omschrijving van de boekstukregel ontbreekt")."\n"); return; } if ( $acct !~ /^\d+$/ ) { if ( $acct =~ /^(\d*)([cd])/i ) { warn("?"._T("De \"D\" of \"C\" toevoeging aan het rekeningnummer is hier niet toegestaan")."\n"); return; } warn("?".__x("Ongeldig grootboekrekeningnummer: {acct}", acct => $acct )."\n"); return; } my $rr = $dbh->do("SELECT acc_desc,acc_balres,acc_kstomz,acc_debcrd,acc_btw". " FROM Accounts". " WHERE acc_id = ?", $acct); unless ( $rr ) { warn("?".__x("Onbekende grootboekrekening: {acct}", acct => $acct)."\n"); $dbh->rollback if $dbh->in_transaction; return; } my ($adesc, $balres, $kstomz, $debcrd, $btw_id) = @$rr; if ( $balres ) { warn("!".__x("Grootboekrekening {acct} ({desc}) is een balansrekening", acct => $acct, desc => $adesc)."\n") if 0; #$dbh->rollback; #return; } if ( $btw_id && !$does_btw ) { croak("INTERNAL ERROR: ". __x("Grootboekrekening {acct} heeft BTW in een BTW-vrije administratie", acct => $acct)); } if ( $nr == 1 ) { $bsk_nr = $self->bsk_nr($opts); return unless defined($bsk_nr); $bsk_id = $dbh->get_sequence("boekstukken_bsk_id_seq"); if ( $bsk_ref and $dbh->do("SELECT count(*)". " FROM Boekstukken, Boekstukregels". " WHERE bsk_id = bsr_bsk_id". " AND upper(bsk_ref) = ?". " AND upper(bsr_rel_code) = ?". " AND bsk_bky = ?", uc($bsk_ref), uc($debcode), $bky)->[0] ) { warn("?".__x("Referentie {ref} bestaat al voor relatie {rel}", rel => $debcode, ref => $bsk_ref)."\n"); return; } $dbh->begin_work; $dbh->sql_insert("Boekstukken", [qw(bsk_id bsk_nr bsk_ref bsk_desc bsk_dbk_id bsk_date bsk_bky)], $bsk_id, $bsk_nr, $bsk_ref, $gdesc, $dagboek, $date, $bky); } # Amount can override BTW id with @X postfix. my ($namt, $btw_spec, $btw_explicit) = $does_btw ? $self->amount_with_btw($amt, $btw_id) : amount($amt); unless ( defined($namt) ) { warn("?".__x("Ongeldig bedrag: {amt}", amt => $amt)."\n"); return; } $amt = $iv ? $namt : -$namt; if ( $does_btw ) { ($btw_id, $kstomz) = $self->parse_btw_spec($btw_spec, $btw_id, $kstomz); unless ( defined($btw_id) ) { warn("?".__x("Ongeldige BTW-specificatie: {spec}", spec => $btw_spec)."\n"); return; } } # Bepalen van de BTW. # Voor neutrale boekingen (@N, of op een neutrale rekening) wordt geen BTW # toegepast. Op _alle_ andere wel. De BTW kan echter nul zijn, of void. # Het eerste wordt bewerkstelligd door $btw_id op 0 te zetten, het tweede # door $btw_acc geen waarde te geven. my $btwclass = 0; my $btw_acc; if ( defined($kstomz) ) { # BTW toepassen. if ( $kstomz ? !$iv : $iv ) { #warn("?".__x("U kunt geen {ko} boeken in een {iv} dagboek", warn("!".__x("Pas op! U boekt {ko} in een {iv} dagboek", ko => $kstomz ? _T("kosten") : _T("omzet"), iv => $iv ? _T("inkoop") : _T("verkoop"), )."\n"); #return; } # Void BTW voor non-EU en verlegd. if ( $btw_id && ($rel_btw == BTWTYPE_NORMAAL || $rel_btw == BTWTYPE_INTRA) ) { my $res = $dbh->do( "SELECT btw_tariefgroep, btw_start, btw_end, btw_alias, btw_desc, btw_incl". " FROM BTWTabel". " WHERE btw_id = ?", $btw_id ); my $incl = $res->[5]; if ( $incl && $rel_btw == BTWTYPE_INTRA ) { if ( $btw_explicit ) { # user specified -> warning warn("!".__x("BTW code {code} is inclusief BTW maar relatie {rel} is intra-communautair", code => $btw_id, rel => $debcode)."\n" ); } warn("!".__x("Er wordt geen BTW berekend voor intra-relatie {rel}", rel => $debcode)."\n" ); } my $tg; unless ( defined($res) && defined( $tg = $res->[0] ) ) { warn("?".__x("Onbekende BTW-code: {code}", code => $btw_id)."\n"); return; } if ( defined( $res->[1] ) && $res->[1] gt $date ) { my $ok = 0; if ( $btw_adapt && !$btw_explicit ) { my $rr = $dbh->do( "SELECT btw_id, btw_desc". " FROM BTWTabel". " WHERE btw_tariefgroep = ?". " AND btw_end >= ?". " AND " . ( $incl ? "" : "NOT " ) . "btw_incl". " ORDER BY btw_id", $tg, $date ); if ( $rr && $rr->[0] ) { warn("%".__x("BTW-code: {code} aangepast naar {new} i.v.m. de boekingsdatum", code => $res->[3]||$res->[4]||$btw_id, new => $rr->[1]||$rr->[0], )."\n"); $btw_id = $rr->[0]; $ok++; } } unless ( $ok ) { warn("!".__x("BTW-code: {code} is nog niet geldig op de boekingsdatum", code => $res->[3]||$res->[4]||$btw_id)."\n"); } } if ( defined( $res->[2] ) && $res->[2] lt $date ) { my $ok = 0; if ( $btw_adapt && !$btw_explicit ) { my $rr = $dbh->do( "SELECT btw_id, btw_desc". " FROM BTWTabel". " WHERE btw_tariefgroep = ?". " AND btw_start <= ?". " AND " . ( $incl ? "" : "NOT " ) . "btw_incl". " ORDER BY btw_id", $tg, $date ); if ( $rr && $rr->[0] ) { warn("%".__x("BTW-code: {code} aangepast naar {new} i.v.m. de boekingsdatum", code => $res->[3]||$res->[4]||$btw_id, new => $rr->[1]||$rr->[0], )."\n"); $btw_id = $rr->[0]; $ok++; } } unless ( $ok ) { warn("!".__x("BTW-code: {code} is niet meer geldig op de boekingsdatum", code => $res->[3]||$res->[4]||$btw_id)."\n"); } } my $tp = BTWTARIEVEN->[$tg]; my $t = qw(v i)[$iv] . lc(substr($tp, 0, 1)); $btw_acc = $dbh->std_acc("btw_$t"); } } elsif ( $btw_id ) { warn("?"._T("BTW toepassen is niet mogelijk op een neutrale rekening")."\n"); return; } # ASSERT: $btw_id != 0 implies defined($kstomz). $dbh->sql_insert("Boekstukregels", [qw(bsr_nr bsr_date bsr_bsk_id bsr_desc bsr_amount bsr_btw_id bsr_btw_acc bsr_btw_class bsr_type bsr_acc_id bsr_rel_code bsr_dbk_id bsr_ref)], $nr++, $date, $bsk_id, $desc, $amt, $btw_id, $btw_acc, BTWKLASSE($does_btw ? defined($kstomz) : 0, $rel_btw, defined($kstomz) ? $kstomz : $iv), 0, $acct, $debcode, $dagboek, $bsr_ref); } my $ret = $self->journalise($bsk_id, $iv, $totaal); # $rr = [ @$ret ]; # shift(@$rr); # $rr = [ sort { $a->[5] <=> $b->[5] } @$rr ]; # foreach my $r ( @$rr ) { # my (undef, undef, undef, undef, $nr, $ac, $amt) = @$r; # next unless $nr; # warn("update $ac with ".numfmt($amt)."\n") if $trace_updates; # $dbh->upd_account($ac, $amt); # } my $tot = $ret->[$#{$ret}]->[8]; # ERROR PRONE $dbh->sql_exec("UPDATE Boekstukken SET bsk_amount = ?, bsk_open = ? WHERE bsk_id = ?", $tot, $tot, $bsk_id)->finish; $dbh->store_journal($ret); $tot = -$tot if $iv; my $fail = defined($totaal) && $tot != $totaal; if ( $opts->{journal} ) { warn("?"._T("Dit overzicht is ter referentie, de boeking is niet uitgevoerd!")."\n") if $fail; EB::Report::Journal->new->journal ({select => $bsk_id, d_boekjaar => $bky, detail => 1}); } if ( $fail ) { $dbh->rollback; return "?".__x("Boeking {bk} is niet uitgevoerd!", bk => join(":", $dbh->lookup($dagboek, qw(Dagboeken dbk_id dbk_desc)), $bsk_nr))." ". __x(" Boekstuk totaal is {act} in plaats van {exp}", act => numfmt($tot), exp => numfmt($totaal)) . "."; } $self->add_attachment( $bsk_att, $bsk_id ) if $bsk_att; $dbh->commit; # TODO -- need this to get a current booking. $opts->{verbose} || 1 ? join(":", $dbh->lookup($dagboek, qw(Dagboeken dbk_id dbk_desc)), $bsk_nr) : ""; } 1; EekBoek-2.030.1/lib/EB/Booking/BKM.pm0000644000400000040000000005143613044346163014370 0ustar jvjv#! perl package main; our $cfg; our $dbh; package EB::Booking::BKM; # Author : Johan Vromans # Created On : Thu Jul 7 14:50:41 2005 # Last Modified By: Johan Vromans # Last Modified On: Wed Oct 7 17:11:39 2015 # Update Count : 555 # Status : Unknown, Use with caution! ################ Common stuff ################ use strict; use warnings; # Dagboek type 3: Bank # Dagboek type 4: Kas # Dagboek type 5: Memoriaal use EB; use EB::Format; use EB::Report::Journal; use base qw(EB::Booking); my $trace_updates = $cfg->val(__PACKAGE__, "trace_updates", 0); # for debugging sub perform { my ($self, $args, $opts) = @_; return unless $self->adm_open; my $dagboek = $opts->{dagboek}; my $dagboek_type = $opts->{dagboek_type}; my $totaal = $opts->{totaal}; my $saldo = $opts->{saldo}; my $beginsaldo = $opts->{beginsaldo}; my $does_btw = $dbh->does_btw; my $verbose = $opts->{verbose}; my $bsk_att = $opts->{bijlage}; if ( defined($totaal) ) { my $t = amount($totaal); return "?".__x("Ongeldig totaal: {total}", total => $totaal) unless defined $t; $totaal = $t; } if ( defined($saldo) ) { my $t = amount($saldo); return "?".__x("Ongeldig saldo: {saldo}", saldo => $saldo) unless defined $t; $saldo = $t; } if ( defined($beginsaldo) ) { my $t = amount($beginsaldo); return "?".__x("Ongeldig beginsaldo: {saldo}", saldo => $beginsaldo) unless defined $t; $beginsaldo = $t; } if ( defined $bsk_att ) { return unless $self->check_attachment($bsk_att); } my $bky = $self->{bky} ||= $opts->{boekjaar} || $dbh->adm("bky"); my ($begin, $end); return unless ($begin, $end) = $self->begindate; my $date; if ( $date = parse_date($args->[0], substr($begin, 0, 4)) ) { shift(@$args); } else { return "?".__x("Onherkenbare datum: {date}", date => $args->[0])."\n" if ($args->[0]||"") =~ /^[[:digit:]]+-/; $date = iso8601date(); } return "?"._T("Deze opdracht is onvolledig. Gebruik de \"help\" opdracht voor meer aanwijzingen.")."\n" unless @$args; return unless $self->in_bky($date, $begin, $end); my $gdesc = shift(@$args); my $bsk_nr = $self->bsk_nr($opts); return unless defined($bsk_nr); my $nr = 1; my $bsk_id; my $gacct = $dbh->lookup($dagboek, qw(Dagboeken dbk_id dbk_acc_id)); # Be slightly paranoid... if ( defined($gacct) && $gacct != $dbh->lookup( $gacct, qw(Accounts acc_id acc_id) ) ) { croak("INTERNAL ERROR: ". __x("Grootboekrekening {acct} voor dagboek {dbk} is niet gedefinieerd", acct => $gacct, dbk => $dbh->lookup( $dagboek, qw( Dagboeken dbk_id dbk_desc ) ) ) ); } my $btw_adapt = $cfg->val(qw(strategy btw_adapt), 0); if ( $gacct ) { my $vsaldo = saldo_for($dagboek, $bsk_nr-1, $bky); if ( defined $beginsaldo ) { return "?".__x("Beginsaldo komt niet overeen met het eindsaldo van de voorgaande boeking", s1 => numfmt($beginsaldo), s2 => numfmt($vsaldo))."\n" if defined($vsaldo) && $vsaldo != $beginsaldo; print(__x("Beginsaldo: {bal}", bal => numfmt($beginsaldo)), "\n") if $verbose; } elsif ( defined $vsaldo ) { $beginsaldo = $vsaldo; print(__x("Saldo voorgaande boeking: {bal}", bal => numfmt($beginsaldo)), "\n") if $verbose; } else { $beginsaldo = $dbh->lookup($gacct, qw(Accounts acc_id acc_balance)); print(__x("Huidig saldo: {bal}", bal => numfmt($beginsaldo)), "\n") if $verbose; } } $bsk_id = $dbh->get_sequence("boekstukken_bsk_id_seq"); $dbh->begin_work; $dbh->sql_insert("Boekstukken", [qw(bsk_id bsk_nr bsk_desc bsk_dbk_id bsk_date bsk_bky)], $bsk_id, $bsk_nr, $gdesc, $dagboek, $date, $bky); my $tot = 0; my $did = 0; my $fail = 0; ENTRY: while ( @$args ) { my $type = shift(@$args); my $bsr_ref; if ( $type eq "std" ) { return "?"._T("Deze opdracht is onvolledig. Gebruik de \"help\" opdracht voor meer aanwijzingen.")."\n" unless @$args >= 3; my $dd = parse_date($args->[0], substr($begin, 0, 4)); if ( $dd ) { shift(@$args); return unless $self->in_bky($dd, $begin, $end); if ( $does_btw && $dbh->adm("btwbegin") && $dd lt $dbh->adm("btwbegin") ) { warn("?"._T("De boekingsdatum valt in de periode waarover al BTW aangifte is gedaan")."\n"); return; } } else { return "?".__x("Onherkenbare datum: {date}", date => $args->[0])."\n" if ($args->[0]||"") =~ /^[[:digit:]]+-/; $dd = $date; } return "?"._T("Deze opdracht is onvolledig. Gebruik de \"help\" opdracht voor meer aanwijzingen.")."\n" unless @$args >= 3; my ($desc, $amt, $acct) = splice(@$args, 0, 3); if ( $opts->{verbose} ) { my $t = $desc; $t = '"' . $desc . '"' if $t =~ /\s/; warn(" "._T("boekstuk").": std $t $amt $acct\n"); } if ( $acct !~ /^\d+$/ ) { if ( $acct =~ /^(\d+)([cd])/i ) { warn("?"._T("De \"D\" of \"C\" toevoeging aan het rekeningnummer is hier niet toegestaan")."\n"); } else { warn("?".__x("Ongeldig grootboekrekeningnummer: {acct}", acct => $acct )."\n"); } $fail++; next; } my $rr = $dbh->do("SELECT acc_desc,acc_balres,acc_kstomz,acc_btw". " FROM Accounts". " WHERE acc_id = ?", $acct); unless ( $rr ) { warn("?".__x("Onbekende grootboekrekening: {acct}", acct => $acct)."\n"); $fail++; next; } my ($adesc, $balres, $kstomz, $btw_id) = @$rr; if ( $balres && $dagboek_type != DBKTYPE_MEMORIAAL ) { warn("!".__x("Grootboekrekening {acct} ({desc}) is een balansrekening", acct => $acct, desc => $adesc)."\n") if 0; } if ( $btw_id && !$does_btw ) { croak("INTERNAL ERROR: ". __x("Grootboekrekening {acct} heeft BTW in een BTW-vrije administratie", acct => $acct)); } my $bid; my $oamt = $amt; my $btw_explicit; ($amt, $bid, $btw_explicit) = $does_btw ? $self->amount_with_btw($amt, undef) : amount($amt); unless ( defined($amt) ) { warn("?".__x("Ongeldig bedrag: {amt}", amt => $oamt)."\n"); $fail++; next; } $btw_id = 0, undef($bid) if defined($bid) && !$bid; # override: @0 # For memorials, if there's BTW associated, it must be explicitly confirmed. if ( $btw_id && !defined($bid) && $dagboek_type == DBKTYPE_MEMORIAAL ) { warn("?"._T("Boekingen met BTW zijn niet mogelijk in een memoriaal.". " De BTW is op nul gesteld.")."\n"); $btw_id = 0; } my $btw_acc; if ( defined($bid) ) { ($btw_id, $kstomz) = $self->parse_btw_spec($bid, $btw_id, $kstomz); unless ( defined($btw_id) ) { warn("?".__x("Ongeldige BTW-specificatie: {spec}", spec => $bid)."\n"); $fail++; next; } if ( !defined($kstomz) && $btw_id ) { warn("?"._T("BTW toepassen is niet mogelijk op een neutrale rekening")."\n"); $fail++; next; } } if ( $btw_id ) { my $res = $dbh->do( "SELECT btw_tariefgroep, btw_start, btw_end, btw_alias, btw_desc, btw_incl". " FROM BTWTabel". " WHERE btw_id = ?", $btw_id ); my $incl = $res->[5]; my $tg; unless ( defined($res) && defined( $tg = $res->[0] ) ) { warn("?".__x("Onbekende BTW-code: {code}", code => $btw_id)."\n"); return; } croak("INTERNAL ERROR: btw code $btw_id heeft tariefgroep $tg") unless $tg; if ( defined( $res->[1] ) && $res->[1] gt $dd ) { my $ok = 0; if ( $btw_adapt && !$btw_explicit ) { my $rr = $dbh->do( "SELECT btw_id, btw_desc". " FROM BTWTabel". " WHERE btw_tariefgroep = ?". " AND btw_end >= ?". " AND " . ( $incl ? "" : "NOT " ) . "btw_incl". " ORDER BY btw_id", $tg, $dd ); if ( $rr && $rr->[0] ) { warn("%".__x("BTW-code: {code} aangepast naar {new} i.v.m. de boekingsdatum", code => $res->[3]||$res->[4]||$btw_id, new => $rr->[1]||$rr->[0], )."\n"); $btw_id = $rr->[0]; $ok++; } } unless ( $ok ) { warn("!".__x("BTW-code: {code} is nog niet geldig op de boekingsdatum", code => $res->[3]||$res->[4]||$btw_id)."\n"); } } if ( defined( $res->[2] ) && $res->[2] lt $dd ) { my $ok = 0; if ( $btw_adapt && !$btw_explicit ) { my $rr = $dbh->do( "SELECT btw_id, btw_desc". " FROM BTWTabel". " WHERE btw_tariefgroep = ?". " AND btw_start <= ?". " AND " . ( $incl ? "" : "NOT " ) . "btw_incl". " ORDER BY btw_id", $tg, $dd ); if ( $rr && $rr->[0] ) { warn("%".__x("BTW-code: {code} aangepast naar {new} i.v.m. de boekingsdatum", code => $res->[3]||$res->[4]||$btw_id, new => $rr->[1]||$rr->[0], )."\n"); $btw_id = $rr->[0]; $ok++; } } unless ( $ok ) { warn("!".__x("BTW-code: {code} is niet meer geldig op de boekingsdatum", code => $res->[3]||$res->[4]||$btw_id)."\n"); } } my $tp = BTWTARIEVEN->[$tg]; my $t = qw(v i)[$kstomz] . lc(substr($tp, 0, 1)); $btw_acc = $dbh->std_acc("btw_$t"); } my $btw = 0; my $bsr_amount = $amt; my $orig_amount = $amt; my ($btw_ink, $btw_verk); if ( $btw_id ) { ( $bsr_amount, $btw, $btw_ink, $btw_verk ) = @{$self->norm_btw($bsr_amount, $btw_id)}; $amt = $bsr_amount - $btw; } $orig_amount = -$orig_amount; $dbh->sql_insert("Boekstukregels", [qw(bsr_nr bsr_date bsr_bsk_id bsr_desc bsr_amount bsr_btw_id bsr_btw_acc bsr_btw_class bsr_type bsr_acc_id bsr_rel_code bsr_dbk_id bsr_ref)], $nr++, $dd, $bsk_id, $desc, $orig_amount, $btw_id, $btw_acc, BTWKLASSE($does_btw ? defined($kstomz) : 0, BTWTYPE_NORMAAL, $kstomz||0), 0, $acct, undef, undef, $bsr_ref); # warn("update $acct with ".numfmt(-$amt)."\n") if $trace_updates; # $dbh->upd_account($acct, -$amt); $tot += $amt; if ( $btw ) { # my $btw_acct = # $dbh->lookup($acct, qw(Accounts acc_id acc_debcrd)) ? $btw_ink : $btw_verk; # warn("update $btw_acct with ".numfmt(-$btw)."\n") if $trace_updates; # $dbh->upd_account($btw_acct, -$btw); $tot += $btw; } } elsif ( $type eq "deb" || $type eq "crd" ) { my $debcrd = $type eq "deb" ? 1 : 0; return "?"._T("Deze opdracht is onvolledig. Gebruik de \"help\" opdracht voor meer aanwijzingen.")."\n" unless @$args >= 2; my $dd = parse_date($args->[0], substr($begin, 0, 4)); if ( $dd ) { shift(@$args); return unless $self->in_bky($dd, $begin, $end); if ( $does_btw && $dbh->adm("btwbegin") && $dd lt $dbh->adm("btwbegin") ) { warn("?"._T("De boekingsdatum valt in de periode waarover al BTW aangifte is gedaan")."\n"); return; } } else { return "?".__x("Onherkenbare datum: {date}", date => $args->[0])."\n" if ($args->[0]||"") =~ /^[[:digit:]]+-/; $dd = $date; } return "?"._T("Deze opdracht is onvolledig. Gebruik de \"help\" opdracht voor meer aanwijzingen.")."\n" unless @$args >= 2; my ($rel, $amt) = splice(@$args, 0, 2); warn(" "._T("boekstuk").": $type $rel $amt\n") if $verbose; my $oamt = $amt; $amt = amount($amt); unless ( defined($amt) ) { warn("?".__x("Ongeldig bedrag: {amt}", amt => $oamt)."\n"); $fail++; next; } my ($rr, $sql, @sql_args); if ( $rel =~ /:/ ) { $bsr_ref = $rel; # store in db my ($id, $bsk, $err) = $dbh->bskid($rel, $bky); unless ( defined($id) ) { warn("?$err\n"); $fail++; next; } $sql = "SELECT bsk_nr, bsk_id, dbk_id, dbk_acc_id, bsk_desc, bsk_amount, bsr_rel_code". " FROM Boekstukken, Boekstukregels, Dagboeken" . " WHERE bsk_id = ?". " AND bsk_dbk_id = dbk_id". " AND bsr_bsk_id = bsk_id". " AND bsr_nr = 1". " AND dbk_type = ?"; @sql_args = ( $id, $debcrd ? DBKTYPE_VERKOOP : DBKTYPE_INKOOP); $rr = $dbh->do($sql, @sql_args); unless ( defined($rr) ) { # Can this happen??? warn("?".__x("Geen post gevonden voor boekstuk {bsk}", bsk => $rel)."\n"); $fail++; next; } } elsif ( 1 ) { # Lookup rel code. $rr = $dbh->do("SELECT rel_code FROM Relaties" . " WHERE upper(rel_code) = ?" . " AND " . ($debcrd ? "" : "NOT ") . "rel_debcrd", uc($rel)); unless ( defined($rr) ) { warn("?".__x("Onbekende {what}: {who}", what => lc($type eq "deb" ? _T("Debiteur") : _T("Crediteur")), who => $rel)."\n"); $fail++; next; } # Get actual code. $rel = $rr->[0]; # Zoek open posten. my $ddd; my $delta = $cfg->val(qw(strategy bkm_multi_delta), 0); $delta = undef; # disable for now. $ddd = parse_date($dd, substr($begin, 0, 4), $delta) if $delta; $sql = "SELECT bsk_open, bsk_nr, bsk_id, dbk_id, dbk_acc_id, bsk_desc, bsk_amount ". " FROM Boekstukken, Boekstukregels, Dagboeken" . " WHERE bsk_open != 0". " AND dbk_type = ?". " AND bsk_dbk_id = dbk_id". " AND bsr_bsk_id = bsk_id". " AND bsr_rel_code = ?". " AND bsr_nr = 1". ( $delta ? " AND bsr_date <= ?" : "" ). " ORDER BY bsr_date"; @sql_args = ( $debcrd ? DBKTYPE_VERKOOP : DBKTYPE_INKOOP, $rel, $delta ? $ddd : () ); # Resultset of candidates. my $res = []; my $sth = $dbh->sql_exec($sql, @sql_args); while ( $rr = $sth->fetchrow_arrayref ) { if ( $rr->[0] == $amt ) { # exact match $res = [[@$rr]]; last; } else { # Add. push(@$res, [@$rr]); } } $sth->finish; my $wmsg; if ( @$res == 0 ) { # Nothing. undef $rr; } elsif ( @$res == 1 && $res->[0]->[0] == $amt ) { # Exact match. Use it. $rr = $res->[0]; } # Knapsack slows down terribly with large search sets. Limit it. elsif ( @$res <= $cfg->val(qw(strategy bkm_multi_max), 15) ) { # Use exact knapsack matching to find possible components. my @amts = map { $_->[0] } @$res; if ( my @k = partition($amt, \@amts) ) { # We found something. Check strategy. if ( $cfg->val(qw(strategy bkm_multi), 0) ) { # We may split. my @t; # for reporting foreach ( @{$k[0]} ) { push(@t, numfmt($amts[$_])); # Push back the data in the input queue. unshift(@$args, $type, $dd, $rel, numfmt_plain($amts[$_])); } # Inform the user. my $t = shift(@t); warn("!".__x("Betaling {rel} {amt} voldoet de open posten {amtss} en {amts}", rel => $rel, amt => numfmt($amt), amtss => join(", ", @t), amts => $t)."\n"); next ENTRY; } else { undef $rr; foreach my $k ( @k ) { my @t; # for reporting foreach ( @{$k} ) { push(@t, numfmt($amts[$_])); } my $t = shift(@t); $wmsg .= "\n%" if $wmsg; # $wmsg .= __x("Wellicht de betaling van de open posten {amtss} en {amts}?", # amtss => join(", ", @t), # amts => $t); $wmsg .= _T("Wellicht de betaling van de volgende open posten:"); foreach ( @{$k} ) { my ($open, $bsknr, $bskid, $dbk_id, $bsk_desc, $bsk_amount) = @{$res->[$_]}; $wmsg .= sprintf("\n%% %s %s %s", join(":", $dbh->lookup($dbk_id, qw(Dagboeken dbk_id dbk_desc)), $bsknr), numfmt($open), $bsk_desc); } } } } # Punt it. else { undef $rr; } } else { $wmsg = __x("Geen alternatieven beschikbaar (teveel open posten)"); undef $rr; } unless ( defined($rr) ) { warn("?".__x("Geen open post van {amt} gevonden voor relatie {rel}", amt => numfmt($amt), rel => $rel)."\n"); if ( $wmsg) { warn("%".$wmsg."\n"); } elsif ( @$res ) { warn("%".__x("Open posten voor relatie {rel}:", rel => $rel)."\n"); foreach ( @$res ) { my ($open, $bsknr, $bskid, $dbk_id, $dbk_acc_id, $bsk_desc, $bsk_amount) = @$_; warn(sprintf("%% %s %s %s\n", join(":", $dbh->lookup($dbk_id, qw(Dagboeken dbk_id dbk_desc)), $bsknr), numfmt($open), $bsk_desc)); } } $fail++; next; } $rr = [@$rr, $rel]; shift(@$rr); } else { # Lookup rel code. $rr = $dbh->do("SELECT rel_code FROM Relaties" . " WHERE upper(rel_code) = ?" . " AND " . ($debcrd ? "" : "NOT ") . "rel_debcrd", uc($rel)); unless ( defined($rr) ) { warn("?".__x("Onbekende {what}: {who}", what => lc($type eq "deb" ? _T("Debiteur") : _T("Crediteur")), who => $rel)."\n"); $fail++; next; } # Get actual code. $rel = $rr->[0]; # Find associated booking. $sql = "SELECT bsk_id, dbk_id, dbk_acc_id, bsk_desc, bsk_amount ". " FROM Boekstukken, Boekstukregels, Dagboeken" . " WHERE bsk_open != 0". ($amt ? " AND bsk_open = ?" : ""). " AND dbk_type = ?". " AND bsk_dbk_id = dbk_id". " AND bsr_bsk_id = bsk_id". " AND bsr_rel_code = ?". " ORDER BY bsr_date"; @sql_args = ( $amt ? $amt : (), $debcrd ? DBKTYPE_VERKOOP : DBKTYPE_INKOOP, $rel); $rr = $dbh->do($sql, @sql_args); unless ( defined($rr) ) { warn("?".__x("Geen open post van {amt} gevonden voor relatie {rel}", amt => numfmt($amt), rel => $rel)."\n"); $fail++; next; } $rr = [@$rr, $rel]; } my ($bsknr, $bskid, $dbk_id, $dbk_acc_id, $bsk_desc, $bsk_amount, $bsr_rel) = @$rr; #my $acct = $dbh->std_acc($debcrd ? "deb" : "crd"); my $acct = $dbk_acc_id; $dbh->sql_insert("Boekstukregels", [qw(bsr_nr bsr_date bsr_bsk_id bsr_desc bsr_amount bsr_btw_id bsr_type bsr_acc_id bsr_btw_class bsr_rel_code bsr_dbk_id bsr_paid bsr_ref)], $nr++, $dd, $bsk_id, "*".$bsk_desc, -$amt, 0, $type eq "deb" ? 1 : 2, $acct, 0, $bsr_rel, $dbk_id, $bskid, $bsr_ref); $dbh->sql_exec("UPDATE Boekstukken". " SET bsk_open = bsk_open - ?". " WHERE bsk_id = ?", $amt, $bskid); # warn("update $acct with ".numfmt(-$amt)."\n") if $trace_updates; # $dbh->upd_account($acct, -$amt); $tot += $amt; } else { warn("?".__x("Onbekend transactietype: {type}", type => $type)."\n"); $fail++; next; } } if ( $gacct ) { warn("update $gacct with ".numfmt($tot)."\n") if $trace_updates; $dbh->upd_account($gacct, $tot); # my $new = $dbh->lookup($gacct, qw(Accounts acc_id acc_balance)); my $new = $beginsaldo + $tot; print(__x("Nieuw saldo: {bal}", bal => numfmt($new)), "\n") if $verbose; $dbh->sql_exec("UPDATE Boekstukken". " SET bsk_saldo = ?, bsk_isaldo = ?". " WHERE bsk_id = ?", $new, $beginsaldo, $bsk_id)->finish; if ( defined $saldo ) { unless ( $saldo == $new ) { warn("?".__x("Saldo {new} klopt niet met de vereiste waarde {act}", new => numfmt($new), act => numfmt($saldo))."\n"); $fail++; } } if ( defined($totaal) and $tot != $totaal ) { $fail++; warn("?".__x(" Boekstuk totaal is {act} in plaats van {exp}", act => numfmt($tot), exp => numfmt($totaal)) . "\n"); } my $isaldo = saldo_for($dagboek, $bsk_nr+1, $bky, "isaldo"); if ( defined($isaldo) and $isaldo != $new ) { $fail++; warn("?".__x("Saldo {new} klopt niet met beginsaldo eropvolgende boekstuk {isaldo}", new => numfmt($new), isaldo => numfmt($isaldo)) . "\n"); } } elsif ( $tot ) { warn("?".__x("Boekstuk is niet in balans (verschil is {diff})", diff => numfmt($tot))."\n"); $fail++; } $dbh->sql_exec("UPDATE Boekstukken SET bsk_amount = ? WHERE bsk_id = ?", $tot, $bsk_id)->finish; $dbh->store_journal($self->journalise($bsk_id)); if ( $opts->{journal} ) { warn("?"._T("Dit overzicht is ter referentie, de boeking is niet uitgevoerd!")."\n") if $fail; EB::Report::Journal->new->journal ({select => $bsk_id, d_boekjaar => $bky, detail => 1}); } if ( $fail ) { warn("?"._T("Boeking ". join(":", ($dbh->lookup($dagboek, qw(Dagboeken dbk_id dbk_desc)), $bsk_nr)). " is niet uitgevoerd!")."\n"); $dbh->rollback; return undef; } $self->add_attachment( $bsk_att, $bsk_id ) if $bsk_att; $dbh->commit; # TODO -- need this to get a current booking. $verbose || 1 ? join(":", $dbh->lookup($dagboek, qw(Dagboeken dbk_id dbk_desc)), $bsk_nr) : ""; } sub saldo_for { my ($dbk, $nr, $bky, $ww) = (@_, "saldo"); my $sth = $dbh->sql_exec("SELECT bsk_$ww FROM Boekstukken". " WHERE bsk_dbk_id = ? AND bsk_nr = ?". " AND bsk_bky = ?", $dbk, $nr, $bky); my $rr = $sth->fetchrow_arrayref; $sth->finish; if ( $rr && defined($rr->[0]) ) { return $rr->[0]; } return; } # Adapted from 'Higher Order Perl' (Mark Jason Dominus), # sec 5.1.1 "Finding All Possible Partitions". sub partition { my ($target, $values, $ix) = @_; return [] if $target == 0; $ix = [ 0 .. $#{$values} ] unless defined $ix; return () if @$ix == 0; my ($first, @rest) = @$ix; my @solutions = partition($target - $values->[$first], $values, \@rest); return ( (map { [ $first, @$_ ] } @solutions), partition($target, $values, \@rest)); } 1; EekBoek-2.030.1/lib/EB/Shell.pm0000644000400000040000000012372613045161622013434 0ustar jvjv#! perl # Author : Johan Vromans # Created On : Thu Jul 14 12:54:08 2005 # Last Modified By: Johan Vromans # Last Modified On: Fri Feb 3 21:09:54 2017 # Update Count : 269 # Status : Unknown, Use with caution! use utf8; package main; our $cfg; our $dbh; our $app; package EB::Shell; use strict; use warnings; use EB; my $bky; # current boekjaar (if set) use base qw(EB::Shell::DeLuxe); use EB::Tools::Attachments; sub new { my $class = shift; $class = ref($class) || $class; my $opts = UNIVERSAL::isa($_[0], 'HASH') ? shift : { @_ }; if ( $opts->{command} && $ARGV[0] eq "import" ) { $dbh->connectdb(1); } else { _plug_cmds(); } # User defined stuff. my $pkg = $cfg->val(qw(shell userdefs), undef); if ( $pkg ) { $pkg =~ s/::/\//g; $pkg .= ".pm"; eval { require $pkg }; die($@) if $@; } else { eval { local $SIG{__WARN__}; local $SIG{__DIE__}; require EB::Shell::Userdefs; }; die($@) if $@ && $@ !~ /can't locate eb.shell.userdefs\.pm in \@inc/i; } my $self = $class->SUPER::new($opts); if ( $self->{interactive} ) { $self->term->Attribs->{completion_function} = sub { $self->eb_complete(@_) }; } if ( defined $self->{boekjaar} ) { $self->do_boekjaar($self->{boekjaar}); } $self; } sub prompt { my $t = $cfg->val(qw(database name)); $t =~ s/^eekboek_//; $t = shift->{prompt} . " [$t"; $t .= ":$bky" if defined $bky; $t . "] "; } sub default { undef; } sub intro { my $self = $_[0]; if ( $self->{interactive} ) { do_database(); bky_msg(); } undef; } sub outro { undef } sub postcmd { shift; if ( $dbh->in_transaction ) { warn("%"._T("Openstaande transactie is teruggedraaid")."\n"); $dbh->rollback; } shift } sub bky_msg { my $sth = $dbh->sql_exec("SELECT bky_code". " FROM Boekjaren". " WHERE bky_end < ?". " AND NOT bky_opened IS NULL". " AND bky_closed IS NULL". " ORDER BY bky_begin", defined $bky ? $dbh->lookup($bky, qw(Boekjaren bky_code bky_begin)) : $dbh->adm("begin")); while ( my $rr = $sth->fetchrow_arrayref ) { warn("!".__x("Pas op! Boekjaar {bky} is nog niet afgesloten.", bky => $rr->[0])."\n"); } } my $dbk_pat; my $dbk_i_pat; my $dbk_v_pat; my $dbk_bkm_pat; sub eb_complete { my ($self, $word, $line, $pos) = @_; my $i = index($line, ' '); #warn "\nCompleting '$word' in '$line' (pos $pos, space $i)\n"; my $pre = substr($line, 0, $pos); #warn "\n[$pre][", substr($line, $pos), "]\n"; select(STDERR); $| = 1; select(STDOUT); # Some ReadLiners put the terminal in raw mode... my $nl = "\r\n"; if ( $i < 0 || $i > $pos-1 || $pre =~ /^help\s+$/ ) { my @words = $self->completions; if ( $pre =~ /^help\s+$/ ) { push( @words, $self->{cm}->{rapporten}, $self->{cm}->{periodes}); } my @a = grep { /^$word/ } @words; if ( @a ) { return $a[0] if @a == 1; print STDERR ( $nl, join(" ", @a), $nl, # Re-prompt. We'll lose the ornaments, # but it's better than nothing (I hope). $self->prompt, "$line" ); } return; } if ( $word =~ /^\d+$/ ) { my $sth = $dbh->sql_exec("SELECT acc_id,acc_desc from Accounts". " WHERE CAST(acc_id AS text) LIKE ?". " ORDER BY acc_id", "$word%"); my $rr = $sth->fetchrow_arrayref; return () unless $rr; my ($w, $d) = @$rr; $rr = $sth->fetchrow_arrayref; return ($w) unless $rr; printf STDERR ($nl."%9d %s".$nl, $w, $d); while ( $rr ) { printf STDERR ("%9d %s".$nl, @$rr); $rr = $sth->fetchrow_arrayref; } print STDERR ("$line"); return (); } my $t; if ( ($word =~ /^[[:alpha:]]/ || $word eq "?") && (($pre =~ /^\s*(?:$dbk_bkm_pat).*\s(crd|deb)\s+$/ and $t = $1) || ($pre =~ /^\s*(?:$dbk_i_pat)(?::\S+)?(?:\s+[0-9---]+)?\s*$/ and $t = "deb") || ($pre =~ /^\s*(?:$dbk_v_pat)(?::\S+)?(?:\s+[0-9---]+)?\s*$/ and $t = "crd"))) { $word = "" if $word eq "?"; my $sth = $dbh->sql_exec("SELECT rel_code,rel_desc from Relaties". " WHERE rel_code LIKE ?". " AND " . ($t eq "deb" ? "" : "NOT ") . "rel_debcrd". " ORDER BY rel_code", "$word%"); my $rr = $sth->fetchrow_arrayref; return () unless $rr; my ($w, $d) = @$rr; $rr = $sth->fetchrow_arrayref; if ( !$rr && $word ne "" ) { return ($w); } printf STDERR ($nl." %s %s".$nl, $w, $d); while ( $rr ) { printf STDERR (" %s %s".$nl, @$rr); $rr = $sth->fetchrow_arrayref; } print STDERR ("$line"); return (); } #warn "\n[$pre][", substr($line, $pos), "]\n"; return (); } sub parseline { my ($self, $line) = @_; $line =~ s/\\\s*$//; $line =~ s/;\s*$//; my ($cmd, @args) = $self->SUPER::parseline($line); if ( $cmd =~ /^(.+):(\S+)$/ ) { $cmd = $1; unshift(@args, "--nr=$2"); } ($cmd, @args); } ################ Subroutines ################ use EB; # Plug in some commands dynamically. sub _plug_cmds { foreach my $dbk_type ( 1 .. scalar(@{DBKTYPES()})-1 ) { my $dbk = lc(_T(DBKTYPES->[$dbk_type])); no strict 'refs'; undef &{"help_$dbk"}; *{"help_$dbk"} = sub { my $self = shift; $self->_help($dbk_type); }; } my $sth = $dbh->sql_exec("SELECT dbk_id,dbk_desc,dbk_type FROM Dagboeken"); my $rr; while ( $rr = $sth->fetchrow_arrayref ) { my ($dbk_id, $dbk_desc, $dbk_type) = @$rr; no strict 'refs'; my $dbk = lc(_T($dbk_desc)); #### TODO: _T ??? $dbk =~ s/\s+/_/g; undef &{"do_$dbk"} if defined &{"do_$dbk"}; *{"do_$dbk"} = sub { my $self = shift; $self->_add($dbk_id, @_); }; undef &{"help_$dbk"}; *{"help_$dbk"} = sub { my $self = shift; $self->_help($dbk_type); }; if ( $dbk_type == DBKTYPE_INKOOP ) { $dbk_v_pat .= lc($dbk_desc)."|"; $dbk_pat .= lc($dbk_desc)."|"; } elsif ( $dbk_type == DBKTYPE_VERKOOP ) { $dbk_i_pat .= lc($dbk_desc)."|"; $dbk_pat .= lc($dbk_desc)."|"; } else { $dbk_bkm_pat .= lc($dbk_desc)."|"; $dbk_pat .= lc($dbk_desc)."|"; } } # Opening (adm_...) commands. require EB::Tools::Opening; foreach my $adm ( @{EB::Tools::Opening->commands} ) { my $cmd = $adm; $cmd =~ s/^set_//; no strict 'refs'; undef &{"do_adm_$cmd"} if defined &{"do_adm_$cmd"}; *{"do_adm_$cmd"} = sub { (shift->{o} ||= EB::Tools::Opening->new)->$adm(@_); }; my $help = "help_$cmd"; undef &{"help_adm_$cmd"}; *{"help_adm_$cmd"} = sub { my $self = shift; ($self->{o} ||= EB::Tools::Opening->new)->can($help) ? $self->{o}->$help() : $self->{o}->shellhelp($cmd); }; } foreach ($dbk_pat, $dbk_i_pat, $dbk_v_pat, $dbk_bkm_pat) { chop if $_; } } sub _forget_cmds { # Delete daybook-associated shell functions. my $t = "|".join( "|", @{ $dbh->tablesdb } )."|"; if ( $t =~ /\|dagboeken\|/i ) { my $sth = $dbh->sql_exec("SELECT dbk_desc FROM Dagboeken"); my $rr; while ( $rr = $sth->fetchrow_arrayref ) { my ($dbk_desc) = @$rr; no strict 'refs'; my $dbk = lc(_T($dbk_desc)); #### TODO: _T ??? $dbk =~ s/\s+/_/g; undef &{"do_$dbk"} if defined &{"do_$dbk"}; } } } sub _help { my ($self, $dbk_type) = @_; my $text = __x("Toevoegen boekstuk in een dagboek van type {type}", type => DBKTYPES->[$dbk_type]) . ".\n\n"; if ( $dbk_type == DBKTYPE_INKOOP ) { $text .= _T( <[:] [ ] gevolgd door een of meer: Controle van het totale boekstukbedrag kan met de optie --totaal=. De laatste mag worden weggelaten. EOS } elsif ( $dbk_type == DBKTYPE_VERKOOP ) { $text .= _T( <[:] [ ] gevolgd door een of meer Controle van het totale boekstukbedrag kan met de optie --totaal=. De laatste mag worden weggelaten. EOS } elsif ( $dbk_type == DBKTYPE_BANK || $dbk_type == DBKTYPE_KAS || $dbk_type == DBKTYPE_MEMORIAAL ) { $text .= _T( <[:] [ ] gevolgd door een of meer: crd [ ] (betaling van crediteur) deb [ ] (betaling van debiteur) std [ ] (vrije boeking) Controle van het eindsaldo kan met de optie --saldo=. Controle van het totale boekstukbedrag kan met de optie --totaal=. Voor deelbetalingen of betalingen met afwijkend bedrag kan in plaats van de het boekstuknummer worden opgegeven. EOS } $text; } sub clionly { my ( $self, $cmd ) = @_; warn("?".__x("Opdracht \"{cmd}\" is niet beschikbaar.", cmd => $cmd)."\n"); undef; } ################ Service ################ sub argcnt($$;$) { my ($cnt, $min, $max) = @_; $max = $min unless defined $max; return 1 if $cnt >= $min && $cnt <= $max; warn("?"._T("Te weinig argumenten voor deze opdracht")."\n") if $cnt < $min; warn("?"._T("Te veel argumenten voor deze opdracht")."\n") if $cnt > $max; undef; } ################ Global toggles ################ sub _state { my ($cur, $state) = @_; return !$cur unless defined($state); my $on = _T("aan"); my $off = _T("uit"); return 1 if $state =~ /^$on|1$/i; return 0 if $state =~ /^$off|0$/i; return !$cur; } sub do_trace { my ($self, @args) = @_; my $opts = { quiet => 0 }; return unless parse_args(\@args, [ 'quiet!' ], $opts); return unless argcnt(@args, 0, 1); my $state = shift(@args); $self->{trace} = _state($self->{trace}, $state); if ( $dbh ) { $dbh->trace($self->{trace}); } return "" if $opts->{quiet}; __x("SQL Trace: {state}", state => uc($self->{trace} ? _T("aan") : _T("uit"))); } sub do_journal { my ($self, @args) = @_; my $opts = { quiet => 0 }; return unless parse_args(\@args, [ 'quiet!' ], $opts); return unless argcnt(@args, 0, 1); my $state = shift(@args); $self->{journal} = _state($self->{journal}, $state); return "" if $opts->{quiet}; __x("Journal: {state}", state => uc($self->{journal} ? _T("aan") : _T("uit"))); } sub do_confirm { my ($self, @args) = @_; my $opts = { quiet => 0 }; return unless parse_args(\@args, [ 'quiet!' ], $opts); return unless argcnt(@args, 0, 1); my $state = shift(@args); $self->{confirm} = _state($self->{confirm}, $state); return "" if $opts->{quiet}; __x("Bevestiging: {state}", state => uc($self->{confirm} ? _T("aan") : _T("uit"))); } sub do_database { my ($self, @args) = @_; return unless argcnt(scalar(@args), 0); __x("Database: {db}", db => $cfg->val(qw(database name))); } sub help_database { _T(<lookup($dagboek, qw(Dagboeken dbk_id dbk_type =)); my $action; if ( $dagboek_type == DBKTYPE_INKOOP || $dagboek_type == DBKTYPE_VERKOOP ) { require EB::Booking::IV; $action = EB::Booking::IV->new; } elsif ( $dagboek_type == DBKTYPE_BANK || $dagboek_type == DBKTYPE_KAS || $dagboek_type == DBKTYPE_MEMORIAAL) { require EB::Booking::BKM; $action = EB::Booking::BKM->new; } else { die("?".__x("Onbekend of verkeerd dagboek: {dbk} [{type}]", dbk => $dagboek, type => $dagboek_type)."\n"); } my $opts = { dagboek => $dagboek, dagboek_type => $dagboek_type, d_boekjaar => $bky || $dbh->adm("bky"), journal => $self->{journal}, totaal => undef, ref => undef, verbose => $self->{verbose}, confirm => $self->{confirm}, }; my $args = \@args; return unless parse_args($args, [ __xt('cmo:boeking:boekstuk|nr').'=s' => \$opts->{boekstuk}, __xt('cmo:boeking:boekjaar').'=s' => \$opts->{boekjaar}, __xt('cmo:boeking:journal|journaal').'!' => \$opts->{journal}, __xt('cmo:boeking:totaal').'=s' => \$opts->{totaal}, __xt('cmo:boeking:ref').'=s' => \$opts->{ref}, __xt('cmo:boeking:confirm').'!' => \$opts->{confirm}, ( $dagboek_type == DBKTYPE_BANK || $dagboek_type == DBKTYPE_KAS ) ? ( __xt('cmo:boeking:saldo').'=s' => \$opts->{saldo}, __xt('cmo:boeking:beginsaldo').'=s' => \$opts->{beginsaldo} ) : (), 'bijlage=s' => \$opts->{bijlage}, ], $opts); $opts->{boekjaar} = $opts->{d_boekjaar} unless defined $opts->{boekjaar}; $bsk = $action->perform($args, $opts); $bsk ? $bsk =~ /^\w+:\d+/ ? __x("Geboekt: {bsk}", bsk => $bsk) : $bsk : ""; } ################ Reports ################ sub do_journaal { my ($self, @args) = @_; my $b = $bsk; my $opts = { _cmd => "journaal", detail => 1, d_boekjaar => $bky || $dbh->adm("bky"), }; require EB::Report::Journal; require EB::Report::GenBase; return unless parse_args(\@args, [ __xt('cmo:journaal:detail|details').'!' => \$opts->{journal}, __xt('cmo:journaal:totaal') => sub { $opts->{detail} = 0 }, __xt('cmo:journaal:bkstsort') => \$opts->{bkstsort}, __xt('cmo:journaal:boekjaar').'=s' => \$opts->{boekjaar}, __xt('cmo:journaal:periode').'=s' => sub { periode_arg($opts, "periode", $_[1]) }, EB::Report::GenBase->backend_options(EB::Report::Journal::, $opts), ], $opts); # print STDERR Dumper($opts), "\n"; $b = shift(@args) if @args; undef $b if $b && lc($b) eq "all"; $opts->{select} = $b; EB::Report::Journal->new->journal($opts); undef; } sub help_journaal { _T( < Alleen boekstuknummer met dit id journaal Alle journaalposten van dit dagboek journaal : Boekstuk van dit dagboek journaal Journaalposten van de laatste boeking Opties --[no]detail Mate van detail, standaard is met details --totaal Alleen het totaal (detail = 0) --bkstsort Sorteer op boekstuk, standaard is sorteren op datum --periode=XXX Alleen over deze periode Zie verder "help rapporten" voor algemene informatie over aan te maken rapporten. EOS } sub do_balans { my ($self, @args) = @_; my $opts = { d_boekjaar => $bky || $dbh->adm("bky"), }; require EB::Report::Balres; require EB::Report::GenBase; return unless parse_args(\@args, [ 'detail=i', 'verdicht', 'opening', 'boekjaar=s', 'per=s' => sub { date_arg($opts, @_) }, EB::Report::GenBase->backend_options(EB::Report::Balres::, $opts), ], $opts); return unless argcnt(@args, 0); if ( $opts->{opening} && $opts->{per} ) { warn("?"._T("Openingsbalans kent geen einddatum")."\n"); return; } EB::Report::Balres->new->balans($opts); undef; } sub help_balans { _T( < Balans op grootboekrekening --verdicht Verdicht, gedetailleerd --detail= Verdicht, mate van detail = 0, 1 of 2 --per= Selecteer einddatum --boekjaar= Selecteer boekjaar --opening Toon openingsbalans Zie verder "help rapporten" voor algemene informatie over aan te maken rapporten. EOS } sub do_result { my ($self, @args) = @_; my $opts = { d_boekjaar => $bky || $dbh->adm("bky"), }; require EB::Report::Balres; require EB::Report::GenBase; return unless parse_args(\@args, [ 'detail=i', 'verdicht', 'boekjaar=s', 'periode=s' => sub { periode_arg($opts, @_) }, EB::Report::GenBase->backend_options(EB::Report::Balres::, $opts), ], $opts); return unless argcnt(@args, 0); EB::Report::Balres->new->result($opts); undef; } sub help_result { _T( < Overzicht op grootboekrekening --verdicht Verdicht, gedetailleerd --detail= Verdicht, mate van detail = 0,1,2 --periode= Selecteer periode --boekjaar= Selecteer boekjaar Zie verder "help rapporten" voor algemene informatie over aan te maken rapporten. EOS } sub do_proefensaldibalans { my ($self, @args) = @_; my $opts = { d_boekjaar => $bky || $dbh->adm("bky"), }; require EB::Report::Proof; require EB::Report::GenBase; return unless parse_args(\@args, [ 'detail=i', 'verdicht', 'boekjaar=s', 'per=s' => sub { date_arg($opts, @_) }, EB::Report::GenBase->backend_options(EB::Report::Proof::, $opts), ], $opts); warn("?"._T("Te veel argumenten voor deze opdracht")."\n"), return if @args; EB::Report::Proof->new->proefensaldibalans($opts); undef; } sub help_proefensaldibalans { _T( < Proef- en Saldibalans op grootboekrekening --verdicht Verdicht, gedetailleerd (hetzelfde als --detail=2) --detail= Verdicht, mate van detail = 0,1,2 --per= Selecteer einddatum --boekjaar= Selecteer boekjaar Zie verder "help rapporten" voor algemene informatie over aan te maken rapporten. EOS } sub do_grootboek { my ($self, @args) = @_; my $opts = { detail => 2, d_boekjaar => $bky || $dbh->adm("bky"), }; require EB::Report::Grootboek; require EB::Report::GenBase; return unless parse_args(\@args, [ 'detail=i', 'periode=s' => sub { periode_arg($opts, @_) }, 'boekjaar=s', EB::Report::GenBase->backend_options(EB::Report::Grootboek::, $opts), ], $opts); my $fail; my ($max_hvd, $max_vrd); my @accts; while ( @args ) { $_ = shift(@args); if ( /^\d+$/ ) { # Check for (Hoofd)Verdichtingen. $max_hvd ||= $dbh->do ( "SELECT MAX(vdi_id) FROM Verdichtingen ". "WHERE vdi_struct IS NULL")->[0]; $max_vrd ||= $dbh->do ( "SELECT MAX(vdi_id) FROM Verdichtingen ". "WHERE NOT vdi_struct IS NULL")->[0]; if ( $_ < $max_hvd ) { my $sth = $dbh->sql_exec ( "SELECT acc_id FROM Accounts ". "WHERE acc_struct IN ". " ( SELECT vdi_id FROM Verdichtingen ". " WHERE vdi_struct = ? ) ". "ORDER BY acc_id DESC", $_ ); while ( my $rr = $sth->fetch ) { unshift( @accts, $rr->[0] ); } } elsif ( $_ < $max_vrd ) { my $sth = $dbh->sql_exec ( "SELECT acc_id from Accounts ". "WHERE acc_struct = ? ". "ORDER BY acc_id DESC", $_ ); while ( my $rr = $sth->fetch ) { unshift( @accts, $rr->[0] ); } } # Assume ordinary account number. elsif ( $dbh->lookup( $_, qw(Accounts acc_id acc_id) ) ) { push( @accts, $_ ); } else { warn("?".__x("Onbekend rekeningnummer: {acct}", acct => $_)."\n"); $fail++; } next; } else { # Search on Account name. my $sth = $dbh->sql_exec ( "SELECT acc_id from Accounts ". "WHERE acc_desc ILIKE ? ". "ORDER BY acc_id DESC", '%' . $_ . '%' ); while ( my $rr = $sth->fetch ) { unshift( @accts, $rr->[0] ); } if ( @accts == 0 ) { warn("?".__x("Onbekende rekeningnaam: {acct}", acct => $_)."\n"); $fail++; } next; } } return if $fail; $opts->{select} = join( ",", @accts ) if @accts; EB::Report::Grootboek->new->perform($opts); undef; } sub help_grootboek { _T( < | ] ... Opties: --detail= Mate van detail, =0,1,2 (standaard is 2) --periode= Alleen over deze periode Naast rekeningnummers kunnen ook nummers van verdichtingen en hoofdverdichtingen worden opgegeven, en gehele of gedeeltelijke namen van de rekeningen. Zie verder "help rapporten" voor algemene informatie over aan te maken rapporten. EOS } sub do_dagboeken { my ($self, @args) = @_; my $rr; my $sth = $dbh->sql_exec("SELECT dbk_id, dbk_desc, dbk_type, dbk_acc_id". " FROM Dagboeken". " ORDER BY dbk_id"); my $fmt = "%2s %-16s %-12s %5s\n"; my $text = sprintf($fmt, _T("Nr"), _T("Naam"), _T("Type"), _T("Rekening")); while ( $rr = $sth->fetchrow_arrayref ) { my ($dbk_id, $dbk_desc, $dbk_type, $dbk_acct) = @$rr; $dbk_acct ||= _T("n.v.t."); $text .= sprintf($fmt, $dbk_id, $dbk_desc, DBKTYPES->[$dbk_type], $dbk_acct); } $text; } sub help_dagboeken { _T( < $bky || $dbh->adm("bky"), close => 0, }; require EB::Report::BTWAangifte; require EB::Report::GenBase; return unless parse_args(\@args, [ "boekjaar=s", 'periode=s' => sub { periode_arg($opts, @_) }, "definitief" => sub { $opts->{close} = 1 }, EB::Report::GenBase->backend_options(EB::Report::BTWAangifte::, $opts), "noreport", "noround", ], $opts) or goto &help_btwaangifte; if ( @args && lc($args[-1]) eq "definitief" ) { $opts->{close} = 1; pop(@args); } warn("?"._T("Te veel argumenten voor deze opdracht")."\n"), return if @args > ($opts->{periode} ? 0 : 1); $opts->{compat_periode} = $args[0] if @args; warn("?"._T("Deze administratie voert geen BTW")."\n"), return unless $dbh->does_btw; EB::Report::BTWAangifte->new($opts)->perform($opts); undef; } sub help_btwaangifte { _T( < ] [ ] Aangifteperiode kan zijn: j jaar Het gehele jaar k1 k2 k3 k4 1e/2e/3e/4e kwartaal (ook: q1, ...) 1 2 3 ... Maand (op nummer) jan feb ... Maand (korte naam) januari ... Maand (lange naam) Standaard is de eerstvolgende periode waarover nog geen aangifte is gedaan. Opties: --definitief De BTW periode wordt afgesloten. Er zijn geen boekingen in deze periode meer mogelijk. --periode= Selecteer aangifteperiode. Dit kan niet samen met --boekjaar, en evenmin met de bovenvermelde methode van periode-specificatie. --boekjaar= Selecteer boekjaar --noreport Geen rapportage. Dit is enkel zinvol samen met --definitief om de afgesloten BTW periode aan te passen. --noround Alle bedragen zonder af te ronden. Zie verder "help rapporten" voor algemene informatie over aan te maken rapporten. EOS } sub do_debiteuren { my ($self, @args) = @_; my $opts = { d_boekjaar => $bky || $dbh->adm("bky"), }; require EB::Report::Debcrd; require EB::Report::GenBase; return unless parse_args(\@args, [ "boekjaar=s", EB::Report::GenBase->backend_options(EB::Report::Debcrd::, $opts), 'periode=s' => sub { periode_arg($opts, @_) }, 'openstaand', ], $opts); EB::Report::Debcrd->new->debiteuren(\@args, $opts); } sub help_debiteuren { _T( < ] [ ... ] Opties: --periode Periode --boekjaar= Selecteer boekjaar --openstaand Alleen met openstaande posten Zie verder "help rapporten" voor algemene informatie over aan te maken rapporten. EOS } sub do_crediteuren { my ($self, @args) = @_; my $opts = { d_boekjaar => $bky || $dbh->adm("bky"), }; require EB::Report::Debcrd; require EB::Report::GenBase; return unless parse_args(\@args, [ "boekjaar=s", EB::Report::GenBase->backend_options(EB::Report::Debcrd::, $opts), 'periode=s' => sub { periode_arg($opts, @_) }, 'openstaand', ], $opts); EB::Report::Debcrd->new->crediteuren(\@args, $opts); } sub help_crediteuren { _T( < ] [ ... ] Opties: --periode= Periode --boekjaar= Selecteer boekjaar --openstaand Alleen met openstaande posten Zie verder "help rapporten" voor algemene informatie over aan te maken rapporten. EOS } sub do_openstaand { my ($self, @args) = @_; my $opts = { d_boekjaar => $bky || $dbh->adm("bky"), }; require EB::Report::Open; require EB::Report::GenBase; return unless parse_args(\@args, [ "boekjaar=s", EB::Report::GenBase->backend_options(EB::Report::Open::, $opts), 'per=s' => sub { date_arg($opts, @_) }, 'deb|debiteuren', 'crd|crediteuren', ], $opts); return unless argcnt(@args, 0, 1); EB::Report::Open->new->perform($opts, \@args); } sub help_openstaand { _T( < ] [ ] Opties: --per= Einddatum --boekjaar= Selecteer boekjaar --deb --debiteuren Alleen debiteuren --crd --crediteuren Alleen crediteuren Zie verder "help rapporten" voor algemene informatie over aan te maken rapporten. EOS } sub help_rapporten { _T( < De einddatum voor de rapportage. (Niet voor elke opdracht relevant.) Zie "help periodes" voor details. --periode= De periode waarover de rapportage moet plaatsvinden. (Niet voor elke opdracht relevant.) Zie "help periodes" voor details. --output= Produceer het rapport in dit bestand Uitvoertype is afhankelijk van bestandsextensie, bv. xx.html levert HTML, xx.txt een tekstbestand, xx.csv een CSV, etc. --gen- Forceer uitvoertype (html, csv, text, ...) Afhankelijk van de beschikbare uitvoertypes zijn ook de kortere opties --html, --csv en --text mogelijk. (Let op: --gen-XXX, niet --gen=XXX) --page= Paginagrootte voor tekstrapporten. EOS } sub help_periodes { _T( <= 2; my $cmd = shift(@args); require EB::Tools::Schema; if ( $cmd eq 'gbk' ) { goto &help_schema unless @args % 4 == 0 || @args % 4 == 1; # weird, but okay my $fail; for ( my $i = 0; $i < @args; $i += 4 ) { unless ( $args[$i] =~ /^[[:digit:]]+$/i ) { warn("?".__x("Ongeldig of ontbrekend rekeningnummer: {x}", x => $args[$i])."\n"); $fail++; } next if $i+1 >= @args; unless ( $args[$i+1] =~ /^[dc]!?|[kon]$/i ) { warn("?".__x("Ongeldige of ontbrekende type specificatie: {x}", x => $args[$i+1])."\n"); $fail++; } unless ( $args[$i+3] =~ /^[[:digit:]]+$/i ) { warn("?".__x("Ongeldige of ontbrekende verdichting: {x}", x => $args[$i])."\n"); $fail++; } } goto &help_schema if $fail; EB::Tools::Schema->new->add_gbk( @args, $opts ); } else { goto &help_schema; } } sub help_schema { _T( < [ ] Aanmaken grootboekrekening schema gbk [ ] Opties: de gewenste grootboekrekening D/C voor Debet / Credit K/O/N voor Kosten / Omzet / Neutraal Eventueel gevolgd door ! als deze balansrekening vast staat aan één kant De omschrijving van deze grootboekrekening De verdichting waaronder deze rekening valt Wanneer enkel een nummer wordt opgegeven dan worden de gegevens van de betreffende grootboekrekening getoond. EOS } ################ Relations ################ sub do_relatie { my ($self, @args) = @_; my $opts = { }; return unless parse_args(\@args, [ __xt("cmo:relatie:dagboek").'=s' => \$opts->{dagboek}, $dbh->does_btw ? ( __xt("cmo:relatie:btw").'=s' => \$opts->{btw} ) : (), ], $opts) or goto &help_relatie; warn("?"._T("Ongeldig aantal argumenten voor deze opdracht")."\n"), return if @args % 3; require EB::Relation; while ( @args ) { my @a = splice(@args, 0, 3); my $res = EB::Relation->new->add(@a, $opts); warn("$res\n") if $res; } } sub help_relatie { my $ret = _T( < ] { } ... Opties: --dagboek= Selecteer dagboek voor deze relatie EOS $ret .= _T( <does_btw; --btw= BTW type: normaal, verlegd, intra, extra *** BTW type 'verlegd' wordt nog niet ondersteund *** EOS $ret; } ################ Im/export ################ sub do_export { my ($self, @args) = @_; my $opts = { single => 0, explicit => 0, totals => 1, }; return unless parse_args(\@args, [ 'dir=s', 'file|output=s', 'boekjaar=s', 'titel=s', 'xaf=s', 'single', 'explicit', 'totals!', ], $opts) or goto &help_export; my $t = 0; $t++ if defined($opts->{dir}); $t++ if defined($opts->{file}); $t++ if defined($opts->{xaf}); if ( $t > 1 ) { warn("?"._T("Opties --dir, --file en --xaf sluiten elkaar uit")."\n"); return; } if ( $t != 1 ) { warn("?"._T("Specificeer --dir, --file of --xaf")."\n"); return; } return unless argcnt(@args, 0); check_open(1); if ( $opts->{xaf} ) { require EB::Export::XAF; # XAF bevat altijd maar één boekjaar. $opts->{boekjaar} ||= $bky; EB::Export::XAF->export($opts); } else { if ( $opts->{boekjaar} ) { warn("?"._T("Optie --boekjaar wordt niet ondersteund door deze export")."\n"); return; } $opts->{desc} = delete $opts->{titel}; require EB::Export; EB::Export->export($opts); } return; } sub help_export { _T( < ] Opties: --file= Selecteer uitvoerbestand --dir= Selecteer uitvoerdirectory --xaf= Export XML Auditfile Financieel --boekjaar= Selecteer boekjaar (alleen met --xaf) Er moet een --file, --dir of een --xaf optie worden opgegeven. De XAF export exporteert altijd één enkel boekjaar. Voor de andere exports wordt altijd de gehele administratie geëxporteerd. Eventueel bestaande files worden overschreven. EOS } sub do_import { my ($self, @args) = @_; return $self->clionly("import") if $app; my $opts = { clean => 1, }; return unless parse_args(\@args, [ 'dir=s', 'file=s', 'clean!', ], $opts); if ( defined($opts->{dir}) && defined($opts->{file}) ) { warn("?"._T("Opties --dir en --file sluiten elkaar uit")."\n"); return; } if ( !defined($opts->{dir}) && !defined($opts->{file}) ) { warn("?"._T("Specificeer --dir of --file")."\n"); return; } return unless argcnt(scalar(@args), 0); if ( $opts->{clean} && !$dbh->feature("import") ) { warn("?".__x("Database type {drv} ondersteunt niet het import commando. Gebruik de --import command line optie.", drv => $dbh->driverdb)."\n"); return; } require EB::Import; EB::Import->do_import($self, $opts); return; } sub help_import { _T( < ] Opties: --file= Selecteer exportbestand --dir= Selecteer exportdirectory Er moet of een --file of een --dir optie worden opgegeven. LET OP: IMPORT VERVANGT DE COMPLETE ADMINISTRATIE! Deze opdracht wordt niet door alle database systemen ondersteund. Deze opdracht is alleen in de command line versie beschikbaar. EOS } sub do_include { my ($self, @args) = @_; my $opts = { optional => 0, }; return unless parse_args(\@args, [ 'optional|optioneel', ], $opts); return unless argcnt(scalar(@args), 1); my $file = shift(@args); # Note: no :encoding, this is handled by the input loop. if ( open(my $fd, '<', $file) ) { $self->attach_file($fd); } elsif ( !$opts->{optional} ) { die("$file: $!\n"); } "" } sub help_include { _T( < ] Opties: --optioneel Het bestand mag ontbreken. De opdracht wordt dan verder genegeerd. EOS } ################ Miscellaneous ################ sub do_boekjaar { my ($self, @args) = @_; return unless argcnt(@args, 1); my $b = $dbh->lookup($args[0], qw(Boekjaren bky_code bky_name)); warn("?".__x("Onbekend boekjaar: {code}", code => $args[0])."\n"), return unless defined $b; $bky = $args[0]; bky_msg(); __x("Boekjaar voor deze sessie: {bky} ({desc})", bky => $bky, desc => $b); } sub help_boekjaar { _T( < EOS } sub do_dump_schema { my ($self, @args) = @_; _T( < $bky || $dbh->adm("bky"), }; return unless parse_args(\@args, [ 'boekjaar=s', ], $opts); $opts->{boekjaar} = $opts->{d_boekjaar} unless defined $opts->{boekjaar}; require EB::Booking::Delete; require EB::Booking::Decode; @args = ($bsk) if $bsk && !@args; return _T("Gaarne een boekstuk") unless @args == 1; my $cmd; my $id = shift(@args); if ( $self->{interactive} ) { (my $xid, my $id, my $err) = $dbh->bskid($id, $opts->{boekjaar}); unless ( defined($id) ) { warn("?".$err."\n"); return; } $cmd = EB::Booking::Decode->decode($id, { boekjaar => $opts->{boekjaar}, trail => 1, bsknr => 1, single => 1 }); } my $res = EB::Booking::Delete->new->perform($id, $opts); if ( $res && $self->{interactive} && $res !~ /^[?!]/ ) { # no error $self->term->addhistory($cmd); } $res; } sub help_verwijder { _T( < ] Opties: --boekjaar= Selekteer boekjaar Het verwijderde boekstuk wordt in de commando-historie geplaatst. Met een pijltje-omhoog kan dit worden teruggehaald en na eventuele wijziging opnieuw ingevoerd. EOS } sub do_toon { my ($self, @args) = @_; my $b = $bsk; my $opts = { verbose => 0, bsknr => 1, d_boekjaar => $bky || $dbh->adm("bky"), }; return unless parse_args(\@args, [ 'btw!', 'bsknr!', 'bky!', 'totaal!', 'boekjaar=s', 'verbose!', 'trace!', ], $opts); $opts->{trail} = !$opts->{verbose}; $opts->{boekjaar} = $opts->{d_boekjaar} unless defined $opts->{boekjaar}; require EB::Booking::Decode; @args = ($bsk) if $bsk && !@args; return _T("Gaarne een boekstuk") unless @args == 1; my ($id, $dbs, $err) = $dbh->bskid(shift(@args), $opts->{boekjaar}); unless ( defined($id) ) { warn("?".$err."\n"); return; } my $res = EB::Booking::Decode->decode($id, $opts); if ( $self->{interactive} && $res !~ /^[?!]/ && $opts->{trail} ) { # no error my $t = $res; $t =~ s/\s+\\\s+/ /g; $self->term->addhistory($t); } $res; } sub help_toon { _T( < ] Opties: --boekjaar= Selekteer boekjaar --verbose Toon in uitgebreide (tekst) vorm --btw Vermeld altijd BTW codes --bsknr Vermeld altijd het boekstuknummer (default) Het getoonde boekstuk wordt in de commando-historie geplaatst. Met een pijltje-omhoog kan dit worden teruggehaald en na eventuele wijziging opnieuw ingevoerd. EOS } sub do_bijlage { my ($self, @args) = @_; my $b = $bsk; my $opts = { verbose => 0, d_boekjaar => $bky || $dbh->adm("bky"), }; return unless parse_args(\@args, [ 'boekjaar=s', 'export=s', 'output=s', 'verbose!', 'trace!', ], $opts); $opts->{boekjaar} = $opts->{d_boekjaar} unless defined $opts->{boekjaar}; @args = ($bsk) if $bsk && !@args; return _T("Gaarne een boekstuk") unless @args == 1; my ($bsk_id, $dbs, $err) = $dbh->bskid($args[0], $opts->{boekjaar}); unless ( defined($bsk_id) ) { warn("?".$err."\n"); return; } require EB::Booking; my ( $att_id ) = EB::Booking->find_attachment($bsk_id); unless ( defined($att_id) ) { warn("?".__x("Geen bijlage gevonden voor boekstuk {bsk}", bsk => $args[0])."\n"); return; } if ( $opts->{export} ) { EB::Tools::Attachments->new->save_to_file( $opts->{export}, $att_id ); return $opts->{verbose} ? __x("Bijlage opgeslagen in {file}", file => $opts->{export}) : ""; } EB::Tools::Attachments->new( id => $att_id )->open( undef, $opts->{output} ); ""; } sub help_bijlage { _T( < ] Opties: --boekjaar= Selekteer boekjaar --output= Schrijf de bijlage naar dit bestand i.p.v. deze te tonen EOS } sub do_jaareinde { my ($self, @args) = @_; my $opts = { d_boekjaar => $bky, }; return unless parse_args(\@args, [ 'boekjaar=s', 'definitief', 'verwijder', 'eb=s', ], $opts); return _T("Opties \"definitief\" en \"verwijder\" sluiten elkaar uit") if $opts->{definitief} && $opts->{verwijder}; return unless argcnt(@args, 0); require EB::Tools::Einde; EB::Tools::Einde->new->perform(\@args, $opts); } sub help_jaareinde { _T( < ] Opties: --boekjaar= Sluit het opgegeven boekjaar af. --definitief Sluit het boekjaar definitief af. Er zijn dan geen boekingen meer mogelijk. --verwijder Verwijder een niet-definitieve jaarafsluiting. --eb= Schrijf openingsopdrachten in dit bestand. EOS } sub do_sql { my ($self, @args) = @_; return $self->clionly("sql") if $app; $dbh->isql(@args); undef; } sub help_sql { _T( < ] Deze opdracht is alleen in de command line versie beschikbaar. EOS } ################ Argument parsing ################ use Getopt::Long; sub parse_args { my ($args, $ctl, $opts) = @_; local(*ARGV) = $args; Getopt::Long::Configure("prefix_pattern=--"); my $ret = GetOptions($opts, @$ctl); $ret; } =begin maybelater sub parse_args2 { my ( $argv, $c, $opts ) = @_; my @resarg; my $ok = -1; my $pfx = "cmo:" . $opts->{_cmd} . ":"; my @ctl = @$c; my %ctl; while ( my $ctl = shift(@ctl) ) { my $dest; my $needvalue = 0; my $negate = 0; if ( $ctl =~ /^(.*)=[is]$/ ) { $ctl = $1; $needvalue = 1; } elsif ( $ctl =~ /^(.*)!$/ ) { $ctl = $1; $negate = 1; } foreach ( split( /\|/, $ctl ) ) { $dest ||= @ctl && ref($ctl[0]) ? shift(@ctl) : \($opts->{$_}); die("?".__x("Ongeldige optiespecificatie \"{opt}\"", opt => $ctl), "\n"), return -1 unless /^[-\w]+$/; $ctl{__xt($pfx.$_)} = [ $dest, $needvalue ]; $ctl{__xt($pfx."no".$_)} = [ $dest, -1 ] if $negate; } } # print STDERR Dumper(\%ctl), "\n"; my $i = 0; while ( $i < @$argv ) { my $opt = $argv->[$i++]; unless ( $opt =~ /^--(.+)/ ) { push( @resarg, $opt ); next; } $opt = $1; my $has_value; if ( $opt =~ /^(.*?)=(.*)/ ) { $opt = $1; $has_value = $2; } my $ctl; unless ( $ctl = $ctl{$opt} ) { die("?".__x("Onbekende optie: \"{opt}\"", opt => $opt)."\n"); $ok = 0; next; } my $value = 1; if ( $ctl->[1] < 0 ) { # negate $value = 0; } elsif ( $ctl->[1] > 0 ) { # need value if ( defined $has_value ) { $value = $has_value; } elsif ( $i < @$argv && $argv->[$i] !~ /^--/ ) { $value = $argv->[$i++]; } else { die("?".__x("Optie \"{opt}\" moet een waarde krijgen.", opt => $opt), "\n"); $ok = 0; next; } } elsif ( defined $has_value ) { die("?".__x("Optie \"{opt}\" neemt geen waarde.", opt => $opt), "\n"); $ok = 0; next; } my $dest = $ctl->[0]; if ( ref($dest) eq 'SCALAR' ) { $$dest = $value; } elsif ( ref($dest) eq 'CODE' ) { $dest->( $opt, $value ); } else { die("?".__x("Optie \"{opt}\" oeps {ref}.", opt => $opt, ref => $dest), "\n"); $ok = 0; } } # Copy remaining arguments. @$argv = @resarg; # Weed out undefined entries in $opts. while ( my($k,$v) = each(%$opts) ) { delete $opts->{$k} unless defined $v; } return $ok; } =cut sub periode_arg { my ($opts, $name, $value) = @_; if ( my $p = parse_date_range($value, substr($dbh->adm("begin"),0,4)) ) { $opts->{$name} = $p; } else { die("?".__x("Ongeldige periode-aanduiding: {per}", per => $value)."\n"); } } sub date_arg { my ($opts, $name, $value) = @_; if ( my $p = parse_date($value, substr($dbh->adm("begin"),0,4)) ) { $opts->{$name} = $p; } else { die("?".__x("Ongeldige datum: {per}", per => $value)."\n"); } } sub check_open { my ($self, $open) = @_; $open = 1 unless defined($open); if ( $open && !$dbh->adm_open ) { die("?"._T("De administratie is nog niet geopend")."\n"); } elsif ( !$open && $dbh->adm_open ) { die("?"._T("De administratie is reeds geopend")."\n"); } 1; } sub check_busy { my ($self, $busy) = @_; $busy = 1 unless defined($busy); if ( $busy && !$dbh->adm_busy ) { die("?"._T("De administratie is nog niet in gebruik")."\n"); } elsif ( !$busy && $dbh->adm_busy ) { die("?"._T("De administratie is reeds in gebruik")."\n"); } 1; } 1; EekBoek-2.030.1/lib/EB/examples/0000755000400000040000000000000013151742350013633 5ustar jvjvEekBoek-2.030.1/lib/EB/examples/Userdefs.pm0000644000400000040000000000344512725476601015770 0ustar jvjv#! perl # Userdefs.pm -- User definable stuff # Author : Johan Vromans # Created On : Thu Feb 7 14:28:50 2008 # Last Modified By: Johan Vromans # Last Modified On: Sat Jun 19 00:49:01 2010 # Update Count : 5 # Status : Unknown, Use with caution! package EB::Shell::Userdefs; use strict; use warnings; use EB; # Dit is een voorbeeld van een command-wrapper. # Wanneer de opdracht "kasverkoop" wordt ingegeven, wordt de method # pp_kasverkoop aangeroepen met de commandonaam en alle meegegeven # argumenten. Deze method is dan verantwoordelijk voor het afleveren # van een (mogelijke andere) opdrachtnaam en argumenten. sub EB::Shell::pp_kasverkoop { my ($self, $cmd, @args) = @_; # Controleer argumenten. "--nr=.." is een intern doorgegeven # argument wanneer de vorm "kasverkoop:boekstuknummer" wordt # gebruikt. die("Foute opdracht: tenminste twee argumenten nodig: datum en bedrag\n") if ( @args < 2 || (@args < 3 && $args[0] =~ /^--?nr=(.+)/)); # Nieuwe opdracht. $cmd = "kas"; # Opbouwen nieuwe lijst argumenten. my @a; if ( $args[0] =~ /^--?nr=(.+)/ ) { push(@a, shift(@args)); # boekstuknummer } if ( $args[0] =~/^\d+-\d+(-\d+)?$/ ) { push(@a, shift(@args)); # datum } my $amt = shift(@args); my $desc = @args ? "@args" : "Diversen"; push(@a, "Verkoop", "std", $desc, $amt.'@1', "8600"); # Toon... warn("+ $cmd @a\n"); # En afleveren. ($cmd, @a); } # En uiteraard, de hulpboodschap. sub EB::Shell::help_kasverkoop { return < [ ... ] Bijvoorbeeld: kasverkoop 28-01 25,00 Dit wordt omgezet in de opdracht: kas 28-01 Verkopen std Diversen 20,00\@1 8600 EOD } # Package ends here. 1; EekBoek-2.030.1/lib/EB/examples/nl/0000755000400000040000000000000013151742350014244 5ustar jvjvEekBoek-2.030.1/lib/EB/examples/nl/eenmanszaak.dat0000644000400000040000000004203313044346163017240 0ustar jvjv# eenmanszaak.dat -- EekBoek voorbeeld rekeningschema voor Eenmanszaak # Author : Johan Vromans # Created On : Wed Dec 14 16:22:15 2005 # Last Modified By: Johan Vromans # Last Modified On: Wed Feb 19 14:52:45 2014 # Update Count : 16 # # Content-Type: text/plain; charset = UTF-8 # # DIT SCHEMA IS INDICATIEF EN DIENT VOOR EIGEN GEBRUIK TE WORDEN # AANGEPAST # # Dit bestand definiëert alle vaste gegevens van een administratie of # groep administraties: het rekeningschema (balansrekeningen en # resultaatrekeningen), de dagboeken en de BTW tarieven. # # Algemene syntaxregels: # # * Lege regels en regels die beginnen met een hekje # worden niet # geïnterpreteerd. # * Een niet-ingesprongen tekst introduceert een nieuw onderdeel. # * Alle ingesprongen regels zijn gegevens voor dat onderdeel. # REKENINGSCHEMA # # Het rekeningschema is hiërarchisch opgezet volgende de beproefde # methode Bakker. De hoofdverdichtingen lopen van 1 t/m 9, de # verdichtingen t/m 99. De grootboekrekeningen zijn verdeeld in # balansrekeningen en resultaatrekeningen. # # De omschrijving van de grootboekrekeningen wordt voorafgegaan door # een vlaggetje, een letter die resp. Debet/Credit (voor # balansrekeningen) en Kosten/Omzet/Neutraal (voor resultaatrekeningen) # aangeeft. De omschrijving wordt indien nodig gevolgd door extra # informatie. Voor grootboekrekeningen kan op deze wijze de BTW # tariefstelling worden aangegeven die op deze rekening van toepassing # is: # # :btw=nul # :btw=hoog # :btw=laag # :btw=privé # :btw=anders # # Ook is het mogelijk aan te geven dat een rekening een koppeling # (speciale betekenis) heeft met :koppeling=xxx. De volgende koppelingen # zijn mogelijk: # # crd de standaard tegenrekening (Crediteuren) voor inkoopboekingen # deb de standaard tegenrekening (Debiteuren) voor verkoopboekingen # btw_ih de rekening voor BTW boekingen voor inkopen, hoog tarief # btw_il idem, laag tarief # btw_vh idem, verkopen, hoog tarief # btw_vl idem, laag tarief # btw_ph idem, privé, hoog tarief # btw_pl idem, laag tarief # btw_ah idem, anders, hoog tarief # btw_al idem, laag tarief # btw_ok rekening voor de betaalde BTW # winst rekening waarop de winst wordt geboekt # # De koppeling winst is verplicht en moet altijd in een administratie # voorkomen in verband met de jaarafsluiting. # De koppelingen voor BTW moeten worden opgegeven indien BTW # van toepassing is op de administratie. # De koppelingen voor Crediteuren en Debiteuren moeten worden # opgegeven indien er inkoop dan wel verkoopdagboeken zijn die gebruik # maken van de standaardwaarden (dus zelf geen tegenrekening hebben # opgegeven). # Normaal lopen hoofdverdichtingen van 1 t/m 9, en verdichtingen # van 10 t/m 99. Indien daarvan wordt afgeweken kan dit worden opgegeven # met de opdracht "Verdichting". De twee getallen geven het hoogste # nummer voor hoofdverdichtingen resp. verdichtingen. Verdichting 9 99 # De nummers van de grootboekrekeningen worden geacht groter te zijn # dan de maximale verdichting. Daarvan kan worden afgeweken door # middels voorloopnullen de _lengte_ van het nummer groter te maken # dan de lengte van de maximale verdichting. Als bijvoorbeeld 99 de # maximale verdichting is, dan geeft 001 een grootboekrekening met # nummer 1 aan. Balansrekeningen 1 Vaste Activa 11 Immateriële vaste activa 100 D Goodwill 101 C Afschrijving goodwill 110 D Aanloopkosten 111 C Afschrijving aanloopkosten 12 Materiële vaste activa 200 D Gebouwen en terreinen 201 C Afschrijving gebouwen 210 D Verbouwing 211 C Afschrijving verbouwingen 220 D Machines en installaties 221 C Afschrijving mach. & installaties 230 D Inventaris en inrichting :btw=hoog,kosten 231 C Afschrijving inventaris & inrichting 240 D Computers :btw=hoog,kosten 241 C Afschrijving computers 250 D Auto's 251 C Afschrijving Auto's 13 Financiële vaste activa 300 D Deelneming B.V. A 310 C Lening B.V. A 320 D Lening u/g de heer A 2 Vlottende activa 21 Handelsvoorraden 3000 D Voorraad 3900 C Voorziening incourante voorraad 22 Vorderingen 1200 D Debiteuren :koppeling=deb 1210 C Factoring debiteuren 1220 D Debiteuren vorig boekjaar 1250 D Dubieuze debiteuren 1290 D Voorziening debiteuren 1300 D Waarborgsommen 1350 D Te factureren omzet 1360 D Te ontvangen rente 1370 D Te ontvangen ziekengeld 1380 D Te ontvangen provisie 1400 D Vooruitbet. huisvestingskosten 1410 D Vooruitbet. reclamekosten 1420 D Vooruitbet. verzekering 1430 D Vooruitbet. autokosten 1440 C Vooruitbet. kantoorartikelen 23 Effecten 900 D Aandelen 910 D Obligaties 24 Liquide middelen 1000 D Kas 1100 D ABN-AMRO Bank 1101 D ABN AMRO Bank G-rekening 1110 D ING Bank 1120 D Postbank 1150 D Deposito 1190 D Kruisposten 1191 D Kruisposten Kas 1192 D Kruisposten overboekingen 25 Tussenrekeningen 2000 C Vraagposten 2200 D Kostenspreiding vorderingen 2210 C Kostenspreiding schulden 2400 C Onbekende betalingen 2900 D Correctierekening 3 Eigen vermogen 31 Kapitaal 500 C Kapitaal :koppeling=winst 510 C Privé stortingen 520 D Privé opnamen 530 C Privé rente 540 C Privé ziektekosten 550 C Privé belastingen 560 C Privé schenkingen 570 C Privé verzekeringen 580 C Privé buitengewone lasten 590 C Privé uitgaven overige 4 Vreemd vermogen 41 Kredietinstellingen lang 800 C Hypotheek bedrijfspand 810 C Lening Bank 811 C Middellang krediet Bank 820 C Financiallease auto 821 C Financiallease computer 44 Overige schulden lang 880 C Lening opgenomen 890 C Overige leningen 45 Banken kort 1130 C Rabobank 1140 C VSB Bank 46 Leveranciers kredieten 1600 C Crediteuren :koppeling=crd 1620 C Crediteuren vorig boekjaar 1650 C Nog te ontvangen fakturen 48 Belastingen & soc. lasten 1500 C BTW Verkoop Hoog :koppeling=btw_vh 1510 C BTW Verkoop Laag :koppeling=btw_vl 1520 D BTW Inkoop Hoog :koppeling=btw_ih 1530 D BTW Inkoop Laag :koppeling=btw_il 1540 C BTW autokostenvergoeding 1550 C BTW Import 1560 C Omzetbelasting betaald :koppeling=btw_ok 1570 D BTW kleine ondernemersregeling 1710 C Loonheffing betaald 1711 C Ingehouden loonheffing 1720 C Bedrijfsvereniging bet. 1721 C Berekende premie BVG 1730 C Pensioenpremie betaald 1731 C Berekende pesioenpremie 1740 C VUT premie betaald 1741 C Berekende VUT premie 1750 C Sociaal fonds betaald 1751 C Berekende premie S. Fonds 49 Overige schulden kort 1900 C Aflossingsverplichtingen 1910 C Reservering vakantiegeld 1911 C Reservering vakantiedagen 1920 C Te betalen accountantskosten 1921 C Te betalen advieskosten 1922 C Te betalen autokosten 1923 C Te betalen algemene kosten 1924 C Te betalen personeelskosten 1925 C Te betalen rente 1926 C Te betalen huisvestingskosten 1929 C Te betalen overige kosten 1950 C Netto lonen en salarissen 1960 C Pensioen verzekeringsmij. 1990 C Diverse schulden kort Resultaatrekeningen 5 Bedrijfsopbrengsten 51 Netto omzet 8600 O Omzet diversen BTW hoog :btw=hoog 8610 O Omzet diversen BTW laag :btw=laag 8620 O Omzet diversen BTW vrij 8900 K Betalingskorting verkoop 8910 K Korting verkoop 8920 K Prijsverschillen verkoop 52 Kostprijs van de omzet 7000 K Inkoop materiaal :btw=hoog 7800 K Mutatie eindvoorraad 7900 K Betalingskorting inkoop 7920 K Prijsverschillen inkoop 53 Overige bedrijfsopbrengst 8680 O Omzet naar kosten BTW hoog :btw=hoog 8690 K Doorbelaste omzet naar kosten 8700 K Kleine ondernemersregeling 8800 K Huuropbrengst 6 Personeelslasten 60 Lonen en salarissen 4000 K Bruto lonen 4001 K Tantième 4002 K Gratificaties 4010 K Overhevelingstoeslag 4020 K Premiespaarregeling 4021 K Loonheffing spaarregeling 4070 K Mutatie vakantiegeld 4071 K Mutatie vakantiedagen 4080 K Ontvangen ziekengeld 4090 K Doorberekende salarissen 61 Sociale lasten 4100 K Bedrijfsvereniging premies 4101 K Ingehouden pr. bedr. vereniging 4110 K VUT premie 4111 K Ingehouden VUT premie 4120 K Sociaal fonds 4121 K Ingehouden sociaal fonds 4130 K Pensioenpremie 4131 K Ingehouden pensioenpremies 4140 K Ziekteverzuimverzekering 4150 K Ziektekostenverzekering 4151 K Bijdrage ziektekostenverzekering 4170 K Soc. lasten vakantiegeld 4171 K Soc. lasten vakantiedagen 4180 K Soc. lasten ontv. ziekengeld 4190 K Doorberekende soc. lasten 62 Overige personeelskosten 4200 K Reiskostenvergoedingen 4205 K Consultancy ingekocht 4210 K Vaste reiskostenverg. 4220 K Vrijgestelde vergoedingen 4230 K Studiekosten 4240 K Kostenvergoeding 4250 K Representatie vergoeding 4260 K Uitzendburo :btw=hoog 4270 K Kantine en consumptie 4280 K Bedrijfskleding personeel :btw=hoog 4290 K Overige personeelskosten 63 Afschrijving materiële vaste activa 4300 K Afschr. kosten gebouwen 4310 K Afschr. kosten verbouwing 4320 K Afschr. kosten mach & inst. 4330 K Afschr. kosten inv. & inr. 4340 K Afschr. kosten computers 4350 K Afschr. kosten auto's 4360 K Res. verkoop mat. vaste activa 65 Huisvestingskosten 4500 K Huur bedrijfspand :btw=hoog 4510 K Servicekosten :btw=hoog 4520 K Gas water & electra 4530 K Vaste lasten 4540 K Onderhoud bedrijfspand :btw=hoog 4550 K Schoonmaakkosten :btw=hoog 4560 K Verzekering bedrijfspand 4590 K Overige huisvestingskosten :btw=hoog 66 Autokosten 4600 K Leasekosten auto :btw=hoog 4610 K Brandstof auto :btw=hoog 4620 K Onderhoud auto :btw=hoog 4630 K Verzekering auto 4640 K Kilometervergoedingen 4650 K Huur auto :btw=hoog 4670 K Boetes 4671 K Boetes 0% aftrekbaar 4680 K BTW privégebruik auto 4690 K Overige autokosten :btw=hoog 67 Verkoopkosten 4700 K Reclamekosten :btw=hoog 4710 K Advertentiekosten :btw=hoog 4711 K Sponsoring 4720 K Beurskosten :btw=hoog 4730 K Relatiegeschenken 4740 K Reis- en verblijfkosten :btw=hoog 4741 K Reis- en verblijfk. 90% :btw=hoog 4742 K Voedsel en drank 90% 4750 K Representatiekosten :btw=hoog 4751 K Representatiekosten 90% 4760 K Credit-cardkosten 4770 K Factoringkosten 4790 K Overige verkoopkosten :btw=hoog 68 Distributiekosten 4810 K Vervoerskosten :btw=hoog 4890 K Overige distributiekosten :btw=hoog 69 Algemene kosten 4780 K Kasverschillen 4800 K Verzending portikosten 4900 K Telefoon- en faxkosten :btw=hoog 4905 K Internetkosten :btw=hoog 4910 K Contributies & abonnementen :btw=hoog 4911 K Contr. & abonn. BTW 0% 4920 K Verzekering algemeen 4930 K Kantoorartikelen :btw=hoog 4931 K Kleine aanschaf kantoor :btw=hoog 4932 K Vakliteratuur 4940 K Accountantskosten :btw=hoog 4941 K Administratiekosten :btw=hoog 4942 K Loonadministratiekosten :btw=hoog 4943 K Notaris & advocaatkosten :btw=hoog 4950 K Drukwerk & papier :btw=hoog 4960 K Branche-organisatiekosten 4970 K Postzegels 4980 K Bankkosten 4990 K Overige algemene kosten :btw=hoog 4991 K Bijzondere baten & lasten 4992 K Reiskosten 7 Afschrijvingen 64 Afschrijving immateriële vaste activa 4380 K Afschr. kosten goodwill 4390 K Afschr. kosten aanloopkosten 9 Financiële baten & lasten 71 Rente baten 9000 K Rente bate deposito 9040 K Rente bate lening u/g 9052 K Rente bate Postbank 9080 K Rente bate belastingen 9090 K Rente bate overige 72 Rente- en overige financiële lasten 9100 K Rente last hypotheek pand 9110 K Rente last lening bank 9111 K Rente last m.lang krediet 9120 K Rente last fin. lease auto 9140 K Rente last lening o/g 9152 K Rente last Postbank 9180 K Rente last belastingen 9190 K Rente last overige 73 Opbrengst overige activa 9200 K Opbrengst effecten 9210 K Mutatie effecten # DAGBOEKEN # # EekBoek ondersteunt vijf soorten dagboeken: Kas, Bank, Inkoop, # Verkoop en Memoriaal. Er kunnen een in principe onbeperkt aantal # dagboeken worden aangemaakt. # In de eerste kolom wordt de korte naam (code) voor het dagboek # opgegeven. Verder moet voor elk dagboek worden opgegeven van welk # type het is. Voor dagboeken van het type Kas en Bank moet een # tegenrekening worden opgegeven, voor de overige dagboeken mag een # tegenrekening worden opgegeven. # De optie :dc kan worden gebruikt om aan te geven dat het journaal # voor dit dagboek de boekstuktotalen in gescheiden debet en credit # moet tonen. Dagboeken I Inkoop :type=inkoop K Kas :type=kas :rekening=1000 M Memoriaal :type=memoriaal P Postbank :type=bank :rekening=1120 V Verkoop :type=verkoop # BTW TARIEVEN # # Er zijn vijf tariefgroepen: "hoog", "laag", "nul", "privé" en # "anders". De tariefgroep bepaalt het rekeningnummer waarop de # betreffende boeking plaatsvindt. # Binnen elke tariefgroep zijn meerdere tarieven mogelijk, hoewel dit # in de praktijk niet snel zal voorkomen. # In de eerste kolom wordt de code voor dit tarief opgegeven. Deze kan # o.m. worden gebruikt om expliciet een BTW tarief op te geven bij het # boeken. Voor elk gebruikt tarief (behalve die van groep "nul") moet # het percentage worden opgegeven. Met de aanduiding :exclusief kan # worden opgegeven dat boekingen op rekeningen met deze tariefgroep # standaard het bedrag exclusief BTW aangeven. # # BELANGRIJK: Mutaties die middels de command line shell of de API # worden uitgevoerd maken gebruik van het geassocieerde BTW tarief van # de grootboekrekeningen. Wijzigingen hierin kunnen dus consequenties # hebben voor de reeds in scripts vastgelegde boekingen. BTW Tarieven H21 BTW 21% :tariefgroep=hoog :perc=21,00 L06 BTW 6,0% :tariefgroep=laag :perc=06,00 P12 BTW Privé 12% :tariefgroep=privé :perc=12,00 # Einde EekBoek schema EekBoek-2.030.1/lib/EB/examples/nl/opening.eb0000644000400000040000000000216113044346163016216 0ustar jvjv# Administratiegegevens. # Naam van de administratie. adm_naam "EekBoek Demo Administratie" # Periode waarover BTW aangifte moet worden gedaan. adm_btwperiode jaar # Begindatum van deze administratie. adm_begindatum 2013 # Standaard wordt voor als boekjaarcode het jaartal gebruikt. U kunt # ook iets anders opgeven. adm_boekjaarcode "2013" # Data voor openingsbalans: # Het balanstotaal is het totaal van alle debet posten, dat uiteraard # overeenkomt met het totaal van alle credit posten. adm_balanstotaal 15854,77 # De openingsposten. adm_balans 1100 1344,37 # Inventaris en inrichting adm_balans 1101 1304,81 # Afschr. Inv. en inr. adm_balans 1110 13378,48 # Computers adm_balans 1111 12106,78 # Afscr. computers adm_balans 2320 1131,92 # Saldo Postbank adm_balans 3100 2443,18 # Kapitaal # Openstaande posten uit voorgaande boekjaren als volgt: # Eerst, indien nodig, de betreffende relatie toevoegen: #relatie KESTER "Repro van Kesteren" 6950 # Dan het openstaande boekstuk: #adm_relatie inkoop:2012:67 2006-12-11 "KESTER" "Printwerk" 48,79 # Open de administratie. adm_open EekBoek-2.030.1/lib/EB/examples/nl/schema.dat0000644000400000040000000002444613044346163016213 0ustar jvjv# EekBoek Rekeningschema voor eekboek_sample # Dit bestand definiëert alle vaste gegevens van een administratie of # groep administraties: het rekeningschema (balansrekeningen en # resultaatrekeningen), de dagboeken en de BTW tarieven. # # Algemene syntaxregels: # # * Lege regels en regels die beginnen met een hekje # worden niet # geïnterpreteerd. # * Een niet-ingesprongen tekst introduceert een nieuw onderdeel. # * Alle ingesprongen regels zijn gegevens voor dat onderdeel. # REKENINGSCHEMA # # Het rekeningschema is hiërarchisch opgezet volgende de beproefde # methode Bakker. De hoofdverdichtingen lopen van 1 t/m 9, de # verdichtingen t/m 99. De grootboekrekeningen zijn verdeeld in # balansrekeningen en resultaatrekeningen. # # De omschrijving van de grootboekrekeningen wordt voorafgegaan door # een vlaggetje, een letter die resp. Debet/Credit (voor # balansrekeningen) en Kosten/Omzet/Neutraal (voor resultaatrekeningen) # aangeeft. De omschrijving wordt indien nodig gevolgd door extra # informatie. Voor grootboekrekeningen kan op deze wijze de BTW # tariefstelling worden aangegeven die op deze rekening van toepassing # is: # # :btw=nul # :btw=hoog # :btw=laag # :btw=privé # :btw=anders # # Ook is het mogelijk aan te geven dat een rekening een koppeling # (speciale betekenis) heeft met :koppeling=xxx. De volgende koppelingen # zijn mogelijk: # # crd de standaard tegenrekening (Crediteuren) voor inkoopboekingen # deb de standaard tegenrekening (Debiteuren) voor verkoopboekingen # btw_ih de rekening voor BTW boekingen voor inkopen, hoog tarief # btw_il idem, laag tarief # btw_vh idem, verkopen, hoog tarief # btw_vl idem, laag tarief # btw_ph idem, privé, hoog tarief # btw_pl idem, laag tarief # btw_ah idem, anders, hoog tarief # btw_al idem, laag tarief # btw_ok rekening voor de betaalde BTW # winst rekening waarop de winst wordt geboekt # # De koppeling winst is verplicht en moet altijd in een administratie # voorkomen in verband met de jaarafsluiting. # De koppelingen voor BTW moeten worden opgegeven indien BTW # van toepassing is op de administratie. # De koppelingen voor Crediteuren en Debiteuren moeten worden # opgegeven indien er inkoop dan wel verkoopdagboeken zijn die gebruik # maken van de standaardwaarden (dus zelf geen tegenrekening hebben # opgegeven). # Normaal lopen hoofdverdichtingen van 1 t/m 9, en verdichtingen # van 10 t/m 99. Indien daarvan wordt afgeweken kan dit worden opgegeven # met de opdracht "Verdichting". De twee getallen geven het hoogste # nummer voor hoofdverdichtingen resp. verdichtingen. Verdichting 9 99 # De nummers van de grootboekrekeningen worden geacht groter te zijn # dan de maximale verdichting. Daarvan kan worden afgeweken door # middels voorloopnullen de _lengte_ van het nummer groter te maken # dan de lengte van de maximale verdichting. Als bijvoorbeeld 99 de # maximale verdichting is, dan geeft 001 een grootboekrekening met # nummer 1 aan. Balansrekeningen 1 Vaste Activa 11 Materiële vaste activa 1100 D Inventaris en inrichting :btw=hoog,kosten 1101 C Afschrijving inv. & inr. 1110 D Computers :btw=hoog,kosten 1111 C Afschrijving computers 1120 D Wagenpark :btw=hoog,kosten 1121 C Afschrijving Wagenpark 2 Vlottende activa 21 Handelsvoorraden 2100 C Voorraad 22 Vorderingen 2200 D Debiteuren :koppeling=deb 23 Liquide middelen 2300 D Kas 2320 D Postbank 2330 D Postbank Inbedrijf 2390 D Kruisposten 3 Eigen vermogen 31 Kapitaal 3100 C Kapitaal de heer/mevrouw :koppeling=winst 3110 C Privé stortingen 3120 D Privé opnamen 4 Vreemd vermogen 41 Leveranciers kredieten 4100 C Crediteuren :koppeling=crd 4150 C Nog te ontvangen fakturen 42 Belastingen & soc. lasten 4200 C BTW Verkoop Hoog :koppeling=btw_vh 4210 C BTW Verkoop Laag :koppeling=btw_vl 4212 C BTW Verkoop Privé :koppeling=btw_vp 4220 D BTW Inkoop Hoog :koppeling=btw_ih 4230 D BTW Inkoop Laag :koppeling=btw_il 4232 D BTW Inkoop Privé :koppeling=btw_ip 4240 C BTW Autokostenvergoeding 4290 C Omzetbelasting betaald :koppeling=btw_ok Resultaatrekeningen 6 Kosten 61 Verkoopkosten 6100 K Reis- en verblijfkosten :btw=hoog 6110 K Sponsoring 62 Huisvestingskosten 6200 K Verzekeringen 63 Bedrijfsvoering 6310 K Kamer van Koophandel 6320 K Vakbond 6330 K Branche-organisatiekosten 66 Autokosten 6600 K Leasekosten auto :btw=hoog 6610 K Brandstof auto :btw=hoog 6620 K Onderhoud auto :btw=hoog 6630 K Verzekering auto 6640 K Kilometervergoedingen 6650 K Huur auto :btw=hoog 6660 K Motorrijtuigenbelasting 6670 K Boetes 6671 K Boetes 0% aftrekbaar 6680 K BTW privégebruik auto 6690 K Overige autokosten :btw=hoog 67 Contributies & abonnementen 6700 K Contributies & abonnementen :btw=hoog 6710 K Contr. & abonn. BTW 0% 68 Afschrijvingen 6800 K Afschr. kosten inv. & inr. 6810 K Afschr. kosten computers 6820 K Afschr. kosten wagenpark 69 Algemene kosten 6900 K Telefoon- en faxkosten :btw=hoog 6905 K Internetkosten :btw=hoog 6920 K Kantoorartikelen :btw=hoog 6921 K Computerbenodigdheden :btw=hoog 6930 K Vakliteratuur :btw=laag 6940 K Administratiekosten :btw=hoog 6950 K Drukwerk & papier :btw=hoog 6970 K Postzegels 6971 K Verzending portikosten 6980 K Bankkosten 6981 K Kasverschillen 6982 K Afrondingen 6990 K Overige algemene kosten :btw=hoog 8 Bedrijfsopbrengsten 81 Omzet Consultancy 8100 O Omzet advisering :btw=hoog 8110 O Omzet advisering BTW vrij 82 Omzet Royalties 8200 O Omzet royalties BTW vrij 83 Omzet Editing 8300 O Omzet editing :btw=hoog 84 Omzet Cursussen 8400 O Omzet cursussen :btw=hoog 8410 O Omzet cursuslicenties :btw=hoog 85 Omzet Projekten 8500 O Omzet projekten :btw=hoog 89 Omzet Diversen 8900 O Omzet diversen BTW hoog :btw=hoog 8910 O Omzet diversen BTW laag :btw=laag 8920 O Omzet diversen BTW vrij 9 Financiële baten & lasten 91 Rente baten 9120 O Rente bate Postbank 9130 O Rente bate Postbank Inbedrijf 9190 O Rente bate overige 92 Rente- en overige financiële lasten 9220 K Rente last Postbank 9230 K Rente last Postbank Inbedrijf 9290 K Rente last overige 93 Overige baten 9380 O Bijtelling privégebruik auto :btw=privé 9390 O Kleine ondernemersregeling # DAGBOEKEN # # EekBoek ondersteunt vijf soorten dagboeken: Kas, Bank, Inkoop, # Verkoop en Memoriaal. Er kunnen een in principe onbeperkt aantal # dagboeken worden aangemaakt. # In de eerste kolom wordt de korte naam (code) voor het dagboek # opgegeven. Verder moet voor elk dagboek worden opgegeven van welk # type het is. Voor dagboeken van het type Kas en Bank moet een # tegenrekening worden opgegeven, voor de overige dagboeken mag een # tegenrekening worden opgegeven. # De optie :dc kan worden gebruikt om aan te geven dat het journaal # en het grootboek voor dit dagboek de boekstuktotalen in gescheiden # debet en credit moet tonen. Dagboeken I Inkoop :type=inkoop K Kas :type=kas :rekening=2300 M Memoriaal :type=memoriaal P Postbank :type=bank :rekening=2320 R Inbedrijf :type=bank :rekening=2330 V Verkoop :type=verkoop # BTW TARIEVEN # # Er zijn vijf tariefgroepen: "hoog", "laag", "nul", "privé" en # "anders". De tariefgroep bepaalt het rekeningnummer waarop de # betreffende boeking plaatsvindt. # Binnen elke tariefgroep zijn meerdere tarieven mogelijk, hoewel dit # in de praktijk niet snel zal voorkomen. # In de eerste kolom wordt de code voor dit tarief opgegeven. Deze kan # o.m. worden gebruikt om expliciet een BTW tarief op te geven bij het # boeken. Voor elk gebruikt tarief (behalve die van groep "nul") moet # het percentage worden opgegeven. Met de aanduiding :exclusief kan # worden opgegeven dat boekingen op rekeningen met deze tariefgroep # standaard het bedrag exclusief BTW aangeven. # # Indien een BTW-tarief niet geldig is op de boekingsdatum wordt # gekeken naar de configuratiesetting [strategy] btw_adapt. Indien # deze is gezet op een niet-nul waarde dan wordt gezocht naar een # alternatief BTW-tarief en deze gebruikt. In alle gevallen wordt een # adequate medlding gegeven. # Dit kan per boeking(sregel) worden onderdrukt door de tariefcode # expliciet mee te geven. # # BELANGRIJK: Mutaties die middels de command line shell of de API # worden uitgevoerd maken gebruik van het geassocieerde BTW tarief van # de grootboekrekeningen. Wijzigingen hierin kunnen dus consequenties # hebben voor de reeds in scripts vastgelegde boekingen. BTW Tarieven H21 BTW 21% :tariefgroep=hoog :perc=21,00 L06 BTW 6,0% :tariefgroep=laag :perc=06,00 P12 BTW Privé 12% :tariefgroep=privé :perc=12,00 # Einde EekBoek schema EekBoek-2.030.1/lib/EB/examples/nl/relaties.eb0000644000400000040000000000217513044346163016374 0ustar jvjv# Aanmaken relaties. # # Syntax: # # Relatie "" standaardrekening # # Als dagboek wordt het laagstgenummerde inkoop/verkoop dagboek # genomen. Het is altijd beter het dagboek expliciet op te geven. # # Opties: # # --dagboek=XXXX selecteer dagboek # --btw=XXX btw type, zie verderop # # Een relatie is crediteur indien het dagboek een inkoopdagboek is. relatie --dagboek=inkoop \ XS4ALL "XS4All Internet B.V." 6905 #relatie --dagboek=inkoop \ # KPN "KPN" 6900 # Met impiciete dagboekdetectie: relatie KPN "KPN" 6900 # Meerdere relaties kunnen ook in een keer: # # relatie --dagboek=inkoop \ # XS4ALL "XS4All Internet B.V." 6905 \ # KPN "KPN" 6900 # Een relatie is debiteur indien het dagboek een verkoopdagboek is. # Relatie "" standaardrekening relatie --dagboek=verkoop \ ACME "Acme Corp." 8100 # Relatie van buiten Europa. BTW code is 'extra'. # Andere mogelijkheden voor BTW zijn 'normaal', # 'verlegd' en 'intra' (intra-communautair, binnen Europa). relatie --dagboek=verkoop --btw=extra \ ORA "O'Reilly & Associates" 8200 EekBoek-2.030.1/lib/EB/examples/nl/bvnv.dat0000644000400000040000000004707613044346163015732 0ustar jvjv# bvnv.dat -- EekBoek voorbeeld rekeningschema voor een BV/NV # Author : Johan Vromans # Created On : Wed Dec 14 16:22:15 2005 # Last Modified By: Johan Vromans # Last Modified On: Mon Nov 19 13:37:53 2012 # Update Count : 14 # # Content-Type: text/plain; charset = UTF-8 # # DIT SCHEMA IS INDICATIEF EN DIENT VOOR EIGEN GEBRUIK TE WORDEN # AANGEPAST # # Aangemaakt door EB::Tools::Schema op 12-12-2005 17:22:47 # Dit bestand definiëert alle vaste gegevens van een administratie of # groep administraties: het rekeningschema (balansrekeningen en # resultaatrekeningen), de dagboeken en de BTW tarieven. # # Algemene syntaxregels: # # * Lege regels en regels die beginnen met een hekje # worden niet # geïnterpreteerd. # * Een niet-ingesprongen tekst introduceert een nieuw onderdeel. # * Alle ingesprongen regels zijn gegevens voor dat onderdeel. # REKENINGSCHEMA # # Het rekeningschema is hiërarchisch opgezet volgende de beproefde # methode Bakker. De hoofdverdichtingen lopen van 1 t/m 9, de # verdichtingen t/m 99. De grootboekrekeningen zijn verdeeld in # balansrekeningen en resultaatrekeningen. # # De omschrijving van de grootboekrekeningen wordt voorafgegaan door # een vlaggetje, een letter die resp. Debet/Credit (voor # balansrekeningen) en Kosten/Omzet/Neutraal (voor resultaatrekeningen) # aangeeft. De omschrijving wordt indien nodig gevolgd door extra # informatie. Voor grootboekrekeningen kan op deze wijze de BTW # tariefstelling worden aangegeven die op deze rekening van toepassing # is: # # :btw=nul # :btw=hoog # :btw=laag # :btw=privé # :btw=anders # # Ook is het mogelijk aan te geven dat een rekening een koppeling # (speciale betekenis) heeft met :koppeling=xxx. De volgende koppelingen # zijn mogelijk: # # crd de standaard tegenrekening (Crediteuren) voor inkoopboekingen # deb de standaard tegenrekening (Debiteuren) voor verkoopboekingen # btw_ih de rekening voor BTW boekingen voor inkopen, hoog tarief # btw_il idem, laag tarief # btw_vh idem, verkopen, hoog tarief # btw_vl idem, laag tarief # btw_ph idem, privé, hoog tarief # btw_pl idem, laag tarief # btw_ah idem, anders, hoog tarief # btw_al idem, laag tarief # btw_ok rekening voor de betaalde BTW # winst rekening waarop de winst wordt geboekt # # De koppeling winst is verplicht en moet altijd in een administratie # voorkomen in verband met de jaarafsluiting. # De koppelingen voor BTW moeten worden opgegeven indien BTW # van toepassing is op de administratie. # De koppelingen voor Crediteuren en Debiteuren moeten worden # opgegeven indien er inkoop dan wel verkoopdagboeken zijn die gebruik # maken van de standaardwaarden (dus zelf geen tegenrekening hebben # opgegeven). # Normaal lopen hoofdverdichtingen van 1 t/m 9, en verdichtingen # van 10 t/m 99. Indien daarvan wordt afgeweken kan dit worden opgegeven # met de opdracht "Verdichting". De twee getallen geven het hoogste # nummer voor hoofdverdichtingen resp. verdichtingen. Verdichting 12 99 # De nummers van de grootboekrekeningen worden geacht groter te zijn # dan de maximale verdichting. Daarvan kan worden afgeweken door # middels voorloopnullen de _lengte_ van het nummer groter te maken # dan de lengte van de maximale verdichting. Als bijvoorbeeld 99 de # maximale verdichting is, dan geeft 001 een grootboekrekening met # nummer 1 aan. Balansrekeningen 1 Vaste Activa 15 Immateriële vaste activa 100 D Goodwill 101 C Afschrijving goodwill 110 D Aanloopkosten 111 C Afschrijving aanloopkosten 16 Materiële vaste activa 200 D Gebouwen en terreinen 201 C Afschrijving gebouwen 210 D Verbouwingen 211 C Afschrijving verbouwingen 220 D Machines en installaties 221 C Afschrijving mach. & inst. 230 D Inventaris en inrichting 231 C Afschrijving inv. & inr. 240 D Computers 241 C Afschrijving computers 250 D Auto's 251 C Afschrijving Auto's 17 Financiële vaste activa 300 D Deelneming B.V. A 301 D Deelneming B.V. B 302 D Deelneming B.V. C 303 D Deelneming B.V. D 320 D Lening u/g de heer A # u/g = uitgezet (uitgeleend) geld 321 D Lening u/g de heer B 330 D Lening B.V. A 331 D Lening B.V. B 370 D Overige leningen u/g 390 D Overige effecten 2 Vlottende activa 21 Handelsvoorraden 3000 D Voorraad 3900 C Voorziening incourante voorraad 22 Vorderingen 1200 D Debiteuren :koppeling=deb 1210 C Factoring debiteuren 1220 D Debiteuren vorig boekjaar 1250 D Dubieuze debiteuren 1290 D Voorziening debiteuren 1300 D Waarborgsommen 1320 D Rekening-courant B.V. A 1321 D Rekening-courant B.V. B 1350 D Te factureren omzet 1360 D Te ontvangen rente 1370 D Te ontvangen ziekengeld 1380 D Te ontvangen provisie 1400 D Vooruitbet. huisvestingsk 1410 D Vooruitbet. reclamekosten 1420 D Vooruitbet. verzekering 1430 D Vooruitbet. autokosten 1440 C Vooruitbet. kantoorartikelen 23 Effecten 900 D Aandelen 910 D Obligaties 24 Liquide middelen 1000 D Kas 1100 D ABN AMRO Bank 1101 D ABN AMRO Bank G-rekening 1110 D ING Bank 1120 D Postbank 1130 C Rabobank 1140 C VSB Bank 1150 D Deposito 1190 D Kruisposten 1191 D Kruisposten Kas 1192 D Kruisposten overboekingen 25 Tussenrekeningen 2000 C Vraagposten 2200 D Kostenspreiding vordering 2210 C Kostenspreiding schulden 2400 C Onbekende betalingen 2900 D Correctierekening 3 Eigen vermogen 31 Aandelenkapitaal 500 C Geplaatst kapitaal :koppeling=winst 32 Reserves 510 C Wettelijke reserve 520 C Algemene reserve 530 C Winst lopend boekjaar 540 C Ingehouden Winst 550 C Onverdeelde Winst 34 Voorzieningen 700 C Pensioenvoorziening 710 C Stamrechtverplichting 720 C Voorz. latente belasting 740 C Voorziening onderhoud 4 Vreemd vermogen 41 Kredietinstellingen lang 800 C Hypotheek bedrijfspand 810 C Lening Bank 811 C Middellang krediet Bank 820 C Financiallease auto 42 Groepsmaatschappijen lang 830 C Lening B.V. C 831 C Lening B.V. D 43 Aandeelhouders lang 860 C Lening o/g de heer A # o/g = geleend geld 861 C Lening o/g de heer B 44 Overige schulden lang 870 C Overige leningen o/g 890 C Overige schulden lang 46 Leveranciers kredieten 1600 C Crediteuren :koppeling=crd 1620 C Crediteuren vorig boekjaar 1650 C Nog te ontvangen fakturen 47 Groepsmaatschappijen kort 1940 C Rekening-courant B.V. C 1941 C Rekening-courant B.V. D 48 Belastingen & soc. lasten 1500 C BTW Verkoop Hoog :koppeling=btw_vh 1510 C BTW Verkoop Laag :koppeling=btw_vl 1520 D BTW Inkoop Hoog :koppeling=btw_ih 1530 D BTW Inkoop Laag :koppeling=btw_il 1540 C BTW autokostenverg. 1541 C BTW privégebr. auto 1560 C Omzetbelasting betaald :koppeling=btw_ok 1570 D BTW kleine ondernemersregeling 1700 C Vennootschapsbelasting 1710 C Loonheffing betaald 1711 C Ingehouden loonheffing 1720 C Bedrijfsvereniging betaald 1721 C Berekende premie BVG 1730 C Pensioenpremie betaald 1731 C Berekende pensioenpremie 1740 C VUT premie betaald 1741 C Berekende VUT premie 1750 C Sociaal fonds betaald 1751 C Berekende premie S. Fonds 49 Overige schulden kort 1900 C Aflossingsverplichtingen 1910 C Reservering vakantiegeld 1911 C Reservering vakantiedagen 1920 C Te betalen accountantskosten 1921 C Te betalen advieskosten 1922 C Te betalen autokosten 1923 C Te betalen algem. kosten 1924 C Te betalen personeelskostenn 1925 C Te betalen rente 1926 C Te betalen huisvestingskosten 1927 C Te betalen dividend 1929 C Te betalen overige kosten 1950 C Netto lonen en salarissen 1960 C Pensioen verzekeringsmij. 1990 C Diverse schulden kort 11 Belastingen 91 Belastingen 1550 C BTW Import 9800 D Vennootschapsbelastingen 9810 D Belasting voorgaande jaren Resultaatrekeningen 5 Bedrijfsopbrengsten 51 Netto omzet 8000 O Omzet BTW Hoog :btw=hoog 8100 O Omzet BTW Laag :btw=laag 8200 O Omzet BTW Geen 8600 O Omzet diversen BTW Hoog :btw=hoog 8610 O Omzet diversen BTW Laag :btw=laag 8620 O Omzet diversen BTW Geen 8900 K Betalingskorting verkoop 8910 K Korting verkoop 8920 K Prijsverschillen verkoop 52 Kostprijs van de omzet 7000 K Inkopen BTW Hoog :btw=hoog 7100 K Inkopen BTW Laag :btw=laag 7200 K Inkopen BTW Geen 7600 K Inkopen diversen :btw=hoog 7700 K Mutatie eindvoorraad 7900 K Betalingskorting inkoop 7920 K Prijsverschillen inkoop 53 Overige bedrijfsopbrengst 8680 O Omzet naar kosten BTW Hoog :btw=hoog 8690 K Doorbelaste omzet naar kosten 8700 K Kleine ondernemersregeling 8800 K Huuropbrengst 6 Personeelskosten 60 Lonen en salarissen 4000 K Bruto lonen 4001 K Tantieme 4002 K Gratificaties 4010 K Overhevelingstoeslag 4020 K Premiespaarregeling 4021 K Loonheffing spaarregeling 4070 K Mutatie vakantiegeld 4071 K Mutatie vakantiedagen 4080 K Ontvangen ziekengeld 4090 K Doorberekende salarissen 61 Sociale lasten 4100 K Bedrijfsvereniging 4101 K Ingehouden bedrijfsvereneniging 4110 K VUT premie 4111 K Ingehouden VUT premie 4120 K Sociaal fonds 4121 K Ingehouden sociaal fonds 4130 K Pensioenpremie 4131 K Ingehouden pensioenpremie 4140 K Ziekteverzuimverzekering 4150 K Ziektekostenverzekering 4151 K Bijdrage ziektekostenverzekering 4170 K Soc. lasten vakantiegeld 4171 K Soc. lasten vakantiedagen 4180 K Soc. lasten ontv. ziekengeld 4190 K Doorberekende soc. lasten 62 Overige personeelskosten 4200 K Reiskostenvergoedingen 4210 K Vaste reiskostenvergoedingen 4220 K Vrijgestelde vergoedingen 4230 K Studiekosten 4240 K Kostenvergoeding 4250 K Representatie vergoeding 4260 K Uitzendburo :btw=hoog 4270 K Kantine en consumptie 4290 K Diverse personeelskosten 7 Afschrijvingen 64 Afschrijving immateriele vaste activa 4380 K Afschr. kosten goodwill 4390 K Afschr. kosten aanloopkosten 8 Overige bedrijfslasten 63 Afschrijving materiële vaste activa 4300 K Afschr. kosten gebouwen 4310 K Afschr. kosten verbouwing 4320 K Afschr. kosten mach. & install. 4330 K Afschr. kosten inv. & inr. 4340 K Afschr. kosten computers 4350 K Afschr. kosten auto's 4360 K Res. verkoop mat. vaste activa 65 Huisvestingskosten 4500 K Huur bedrijfspand :btw=hoog 4510 K Servicekosten :btw=hoog 4520 K Gas, water & electra 4530 K Vaste lasten 4540 K Onderhoud bedrijfspand :btw=hoog 4550 K Schoonmaakkosten :btw=hoog 4560 K Verzekering bedrijfspand 4590 K Overige huisvestingskosten :btw=hoog 66 Autokosten 4600 K Leasekosten auto :btw=hoog 4610 K Brandstof auto :btw=hoog 4620 K Onderhoud auto :btw=hoog 4630 K Verzekering auto 4640 K Kilometervergoedingen 4650 K Huur auto :btw=hoog 4660 K BTW privégebruik auto 4670 K Boetes 4671 K Boetes 0% aftrekbaar 4690 K Overige autokosten :btw=hoog 67 Verkoopkosten 4700 K Reclamekosten :btw=hoog 4710 K Advertentiekosten :btw=hoog 4711 K Sponsoring 4720 K Beurskosten :btw=hoog 4730 K Relatiegeschenken 4740 K Reis- en verblijfkosten :btw=hoog 4741 K Reis- en verblijfk. 90% 4742 K Voedsel en drank 90% 4750 K Representatiekosten :btw=hoog 4751 K Representatiekosten 90% 4760 K Credit-cardkosten 4770 K Factoringkosten :btw=hoog 4780 K Kasverschillen 4790 K Overige verkoopkosten :btw=hoog 68 Distributiekosten 4800 K Verzending portikosten 4810 K Vervoerskosten :btw=hoog 4890 K Overige distributiekosten :btw=hoog 69 Algemene kosten 4900 K Telefoon- en faxkosten :btw-hoog 4905 K Internetkosten :btw=hoog 4910 K Contributies & abonnement :btw=hoog 4920 K Verzekering algemeen 4930 K Kantoorartikelen :btw=hoog 4931 K Kleine aanschaf kantoor :btw=hoog 4932 K Vakliteratuur 4940 K Accountantskosten :btw=hoog 4941 K Administratiekosten :btw=hoog 4942 K Loonadministratiekosten :btw=hoog 4943 K Notaris & advocaatkosten :btw=hoog 4950 K Drukwerk & papier :btw=hoog 4960 K Branche-organisatiekosten 4970 K Postzegels 4980 K Bankkosten 4990 K Overige algemene kosten :btw=hoog 4991 K Bijzondere baten & lasten 9 Financiële baten & lasten 71 Rente baten 9000 K Rente bate deposito 9030 K Rente bate lening B.V. 9040 K Rente bate lening u/g 9050 K Rente bate ABN AMRO Bank 9051 K Rente bate ING Bank 9052 K Rente bate Postbank 9053 K Rente bate Rabobank 9054 K Rente bate VSB Bank 9070 K Rente bate aandeelhouder 9080 K Rente bate belastingen 9090 K Rente bate overige 72 Rente- en overige financiële lasten 9100 K Rente last hypotheek pand 9110 K Rente last lening bank 9111 K Rente last m.l. krediet 9120 K Rente last fin. lease auto 9130 K Rente last lening B.V. 9140 K Rente last lening o/g 9150 K Rente last ABN AMRO bank 9151 K Rente last ING Bank 9152 K Rente last Postbank 9153 K Rente last Rabobank 9154 K Rente last VSB Bank 9160 K Rente last factormaatschappij 9170 K Rente last aandeelhouder 9180 K Rente last belastingen 9190 K Rente last overige 73 Opbrengst overige activa 9200 K Opbrengst effecten 9210 K Mutatie effecten 10 Resultaat deelnemingen 81 Consolidatie deelnemingen 9500 K Resultaat boekjaar B.V. A 9501 K Resultaat boekjaar B.V. B 82 Overige deelnemingen 9510 K Resultaat boekjaar B.V. C 9511 K Resultaat boekjaar B.V. D 12 Buitengewone baten & lasten 95 Buitengewone baten 9900 K Buitengewone baten 9901 K Belasting buiteng. baten 97 Buitengewone lasten 9910 K Buitengewone lasten 9911 K Belasting buiteng. lasten # DAGBOEKEN # # EekBoek ondersteunt vijf soorten dagboeken: Kas, Bank, Inkoop, # Verkoop en Memoriaal. Er kunnen een in principe onbeperkt aantal # dagboeken worden aangemaakt. # In de eerste kolom wordt de korte naam (code) voor het dagboek # opgegeven. Verder moet voor elk dagboek worden opgegeven van welk # type het is. Voor dagboeken van het type Kas en Bank moet een # tegenrekening worden opgegeven, voor de overige dagboeken mag een # tegenrekening worden opgegeven. # De optie :dc kan worden gebruikt om aan te geven dat het journaal # voor dit dagboek de boekstuktotalen in gescheiden debet en credit # moet tonen. Dagboeken A Voorraad :type=memoriaal B ING-Bank :type=bank :rekening=1110 I Inkopen :type=inkoop K Kas :type=kas :rekening=1000 M Memoriaal :type=memoriaal P Postbank :type=bank :rekening=1120 R Rabobank :type=bank :rekening=1130 S Spreiding :type=memoriaal V Verkopen :type=verkoop # BTW TARIEVEN # # Er zijn vijf tariefgroepen: "hoog", "laag", "nul", "privé" en # "anders". De tariefgroep bepaalt het rekeningnummer waarop de # betreffende boeking plaatsvindt. # Binnen elke tariefgroep zijn meerdere tarieven mogelijk, hoewel dit # in de praktijk niet snel zal voorkomen. # In de eerste kolom wordt de code voor dit tarief opgegeven. Deze kan # o.m. worden gebruikt om expliciet een BTW tarief op te geven bij het # boeken. Voor elk gebruikt tarief (behalve die van groep "nul") moet # het percentage worden opgegeven. Met de aanduiding :exclusief kan # worden opgegeven dat boekingen op rekeningen met deze tariefgroep # standaard het bedrag exclusief BTW aangeven. # # BELANGRIJK: Mutaties die middels de command line shell of de API # worden uitgevoerd maken gebruik van het geassocieerde BTW tarief van # de grootboekrekeningen. Wijzigingen hierin kunnen dus consequenties # hebben voor de reeds in scripts vastgelegde boekingen. BTW Tarieven H19 BTW 19% :tariefgroep=hoog :perc=19,00 H21 BTW 19% :tariefgroep=hoog :perc=21,00 L06 BTW 6% :tariefgroep=laag :perc=6,00 P12 BTW 12% autokostenvergoeding :tariefgroep=hoog :perc=12,00 X01 BTW privégebruik auto 12% :tariefgroep=nul X02 BTW kleine ondernemersregeling :tariefgroep=nul EekBoek-2.030.1/lib/EB/examples/nl/mutaties.eb0000644000400000040000000002015613044346163016416 0ustar jvjv# Inkopen (Dagboek: Inkoop) # Algemene vorm van de opdrachten: # # dagboek [ datum ] argumenten # # Argumenten inkoop: "Omschrijving" crediteurcode boekstukregel # Boekstukregel: "Omschrijving" bedrag [ grootboekrekening ] # # Standaard wordt de met deze crediteur geassocieerde # grootboekrekening gebruikt (zie relaties.eb). # # Standaard wordt het met de grootboekrekening geassocieerde BTW # tarief gebruikt. Dit kan worden gewijzigd door een toevoeging aan # het bedrag: # @0 geen BTW # @H21 pas het hoge 21% tarief toe # @L06 pas het lage 6% tarief toe # # Een credit-boeking kan worden gespecificeerd door een negatief # bedrag. # Enkelvoudig, met één enkele boekstukregel. inkoop 05-01 "Internet" XS4ALL "ADSL" 22,80 # Meerdere boekstukregels; de grootboekrekening is dan verplicht. # De totaaltelling is optioneel, maar sterk aangeraden om fouten # te voorkomen. inkoop 15-01 "ADSL + Telefoon" KPN --totaal=104,65 \ "ADSL" 24,20 6905 \ "Telefoonkosten" 80,45 6900 inkoop 09-02 "Internet" XS4ALL "ADSL" 22,80 inkoop 08-03 "Internet" XS4ALL "ADSL" 22,80 inkoop 18-03 "Telefoonkosten" KPN "ADSL + Telefoon" 101,52 inkoop 05-04 "Internet" XS4ALL "ADSL" 22,80 inkoop 10-05 "Internet" XS4ALL "ADSL" 22,80 inkoop 20-05 "Telefoonkosten" KPN "ADSL + Telefoon" 102,22 inkoop 07-06 "Internet" XS4ALL "ADSL" 22,80 inkoop 05-07 "Internet" XS4ALL "ADSL" 22,80 inkoop 15-07 "Telefoonkosten" KPN "ADSL + Telefoon" 104,66 inkoop 09-08 "Internet" XS4ALL "ADSL" 22,80 inkoop 06-09 "Internet" XS4ALL "ADSL" 22,80 inkoop 16-09 "Telefoonkosten" KPN "ADSL + Telefoon" 108,72 inkoop 11-10 "Internet" XS4ALL "ADSL" 22,80 inkoop 07-11 "Internet" XS4ALL "ADSL" 2*11+0,80 inkoop 17-11 "Telefoonkosten" KPN "ADSL + Telefoon" 109,67 inkoop 06-12 "Internet" XS4ALL "ÁDSL" 22,80 # Expliciet boekstuknummer: inkoop:20 07-12 "Internet" XS4ALL "ADSL" 22,80 # Verwijderen: inkoop:23 07-12 "Internet" XS4ALL "ÄDSL" 22,80 verwijder inkoop:23 # Verkopen (Dagboek: Verkoop) # # Argumenten verkoop: "Omschrijving" debiteurcode boekstukregel # Boekstukregel: "Omschrijving" bedrag [ grootboekrekening ] # # Standaard wordt de met deze debiteur geassocieerde # grootboekrekening gebruikt (zie file relaties.eb). # # Zie de beschrijving bij Inkopen voor de mogelijkheden het # toegepaste BTW tarief te specificeren. # # Meerdere boekstukregels zijn mogelijk; de grootboekrekening is dan # verplicht. Zie bij Inkopen voor een voorbeeld. # # Een debet-boeking kan worden gespecificeerd door een negatief # bedrag. verkoop 18-02 "Perl Cursus" ACME "Perl Cursus 1e bet." 3.570 8400 verkoop 18-03 "Perl Cursus" ACME "Perl Cursus 2e bet." 3,570 8400 verkoop 18-04 "Perl Cursus" ACME "Perl Cursus rest" 600 8400 verkoop 12-05 "Perl Cursus" ACME "Perl Cursus rest" -5 8400 verkoop 14-05 "Ondersteuning" ACME "Consultancy" 714 verkoop 16-07 "Ondersteuning" ACME "Consultancy" 714 verkoop 19-08 "Pocket Reference" ORA "Produktie boek" 1.000 8300 # Bank (Dagboek: Postbank) # # Argumenten bankboeking: "Omschrijving" boekstukregel # Boekstukregel: # std "Omschrijving" bedrag grootboekrekening # crd "Omschrijving" crediteurcode bedrag (negatief!) # deb "Omschrijving" debiteurcode bedrag # # Standaard wordt het eerste met deze crediteur/debiteur geassocieerde # open inkoop/verkoop-boekstuk afgeboekt. # # Voor deze boekingen geldt dat een negatief getal het banksaldo # vermindert, en een positief getal het saldo vermeerdert. # # 'std' boekingen met BTW zijn ongebruikelijk. # Daarom moet in dat geval de toepassing van BTW expliciet worden # opgegeven met de "@" toevoeging: # @0 geen BTW (onderdrukt de waarschuwing) # @H21 pas het hoge 21% tarief toe # @L06 pas het lage 6% tarief toe # BTW wordt geboekt op de BTW-Omzetrekening voor positieve bedragen, # en op de BTW-Kostenrekening voor negatieve bedragen. Dit kan worden # gewijzigd door aan de codering een "O" (Omzet) of "K" (Kosten) toe # te voegen. # # Door het eindsaldo op te geven wordt dit geverifieerd. postbank 31-01 "Afschrift 1" --saldo=1001,77 \ std 06-01 "Girotel" -2,70 6980 \ crd 19-01 XS4ALL -22,80 \ crd 31-01 KPN -104,65 postbank 28-02 "Afschrift 2" --saldo=976,27 \ std 10-02 "Girotel" -2,70 6980 \ crd 23-02 XS4ALL -22,80 postbank 31-03 "Afschrift 3" --saldo=4419,25 \ std 09-03 "Girotel" -2,70 6980 \ deb 18-03 ACME 3570,00 \ crd 31-03 XS4ALL -22,80 \ crd 31-03 KPN -101,52 postbank 30-04 "Afschrift 4" --saldo=7963,75 \ std 06-04 "Girotel" -2,70 6980 \ crd 06-04 XS4ALL -22,80 \ deb 12-04 ACME 3570,00 postbank 31-05 "Afschrift 5" --saldo=8436,03 \ std 11-05 "Girotel" -2,70 6980 \ crd 31-05 XS4ALL -22,80 \ deb 31-05 ACME 600,00 \ crd 31-05 KPN -102,22 postbank 30-06 "Afschrift 6" --saldo=9119,53 \ std 08-06 "Girotel" -2,70 6980 \ deb 08-06 ACME 714,00 \ deb 12-06 ACME -5,00 \ crd 21-06 XS4ALL -22,80 postbank 31-07 "Afschrift 7" --saldo=8989,37 \ std 06-07 "Girotel" -2,70 6980 \ crd 30-07 XS4ALL -22,80 \ crd 31-07 KPN -104,66 postbank 31-08 "Afschrift 8" --saldo=10.677,87 \ std 10-08 "Girotel" -2,70 6980 \ deb 10-08 ACME 714,00 \ crd 10-08 XS4ALL -22,80 \ deb 19-08 ORA 1000,00 postbank 30-09 "Afschrift 9" --saldo=10.543,65 \ std 17-09 "Girotel" -2,70 6980 \ crd 30-09 XS4ALL -22,80 \ crd 30-09 KPN -108,72 postbank 31-10 "Afschrift 10" --saldo=10518,15 \ std 12-10 "Girotel" -2,70 6980 \ crd 13-10 XS4ALL -22,80 postbank 30-11 "Afschrift 11" --saldo=10.382,98 \ std 08-11 "Girotel" -2,70 6980 \ crd 30-11 XS4ALL -22,80 \ crd 30-11 KPN -109,67 # Er kan een expliciet volgnummer worden opgegeven. postbank:12 07-12 "Afschrift 12" --saldo 10357.48 \ std 06-12 "Girotel" -2,70 6980 \ crd 07-12 XS4ALL -22,80 # Partiele betalingen door het boekstuk op te geven i.p.v. de # debiteur/crediteur. postbank 09-12 "Eerste deel ADSL" --saldo=10,347.48 \ crd 09-12 Inkoop:20 -10,00 # De rest van de betaling kan met opgave van boekstuk, maar natuurlijk # ook op de 'handige' manier waarbij EekBoek het zelf uitzoekt. postbank 10-12 "Tweede deel ADSL" --saldo=10334,68 \ crd 10-12 XS4ALL -12,80 # Afschrijvingen # # Memoriaal is als een bankboeking, maar er is geen impliciete # grootboekrekening waarop het totaal wordt geboekt. Het boekstuk moet # dus precies in balans zijn. # Ook hier geldt dat een positief bedrag de betreffende rekening # crediteert (vermeerdert) en een negatief bedrag vermindert. # Eveneens van toepassing is de opmerking bij Bankboekingen over 'std' # boekingen met BTW. memoriaal 31-12 "Afschrijving inventaris" \ std "Afschrijving" -411,26 6800 \ std "Afschrijving" 411,26 1101 memoriaal 31-12 "Afschrijving computers" \ std "Afschrijving" -396,82 6810 \ std "Afschrijving" 396,82 1111 # Rapportages voor de accountant. # balans --output=out/balans.html # balans --detail=2 --output=out/balans2.html # result --output=out/result.html # result --detail=2 --output=out/result2.html # journaal --output=out/journaal.html # grootboek --output=out/grootboek.html # btwaangifte --output=out/btwaangifte.html # openstaand --output=out/openstaand.html EekBoek-2.030.1/lib/EB/examples/nl/vereniging.dat0000644000400000040000000002673512725476601017121 0ustar jvjv# Voorbeeld EekBoek Rekeningschema -*- coding: utf-8 -*- # Content-Type: text/plain; charset = UTF-8 # Dit bestand definiëert alle vaste gegevens van een administratie of # groep administraties: het rekeningschema (balansrekeningen en # resultaatrekeningen), de dagboeken en de BTW tarieven. # # Algemene syntaxregels: # # * Lege regels en regels die beginnen met een hekje # worden niet # geïnterpreteerd. # * Een niet-ingesprongen tekst introduceert een nieuw onderdeel. # * Alle ingesprongen regels zijn gegevens voor dat onderdeel. # REKENINGSCHEMA # # Het rekeningschema is hiërarchisch opgezet volgende de beproefde # methode Bakker. De hoofdverdichtingen lopen van 1 t/m 9, de # verdichtingen t/m 99. De grootboekrekeningen zijn verdeeld in # balansrekeningen en resultaatrekeningen. # # De omschrijving van de grootboekrekeningen wordt voorafgegaan door # een vlaggetje, een letter die resp. Debet/Credit (voor # balansrekeningen) en Kosten/Omzet/Neutraal (voor resultaatrekeningen) # aangeeft. De omschrijving wordt indien nodig gevolgd door extra # informatie. Voor grootboekrekeningen kan op deze wijze de BTW # tariefstelling worden aangegeven die op deze rekening van toepassing # is: # # :btw=nul # :btw=hoog # :btw=laag # :btw=privé # :btw=anders # # Ook is het mogelijk aan te geven dat een rekening een koppeling # (speciale betekenis) heeft met :koppeling=xxx. De volgende koppelingen # zijn mogelijk: # # crd de standaard tegenrekening (Crediteuren) voor inkoopboekingen # deb de standaard tegenrekening (Debiteuren) voor verkoopboekingen # btw_ih de rekening voor BTW boekingen voor inkopen, hoog tarief # btw_il idem, laag tarief # btw_vh idem, verkopen, hoog tarief # btw_vl idem, laag tarief # btw_ph idem, privé, hoog tarief # btw_pl idem, laag tarief # btw_ah idem, anders, hoog tarief # btw_al idem, laag tarief # btw_ok rekening voor de betaalde BTW # winst rekening waarop de winst wordt geboekt # # De koppeling winst is verplicht en moet altijd in een administratie # voorkomen in verband met de jaarafsluiting. # De koppelingen voor BTW moeten worden opgegeven indien BTW # van toepassing is op de administratie. # De koppelingen voor Crediteuren en Debiteuren moeten worden # opgegeven indien er inkoop dan wel verkoopdagboeken zijn die gebruik # maken van de standaardwaarden (dus zelf geen tegenrekening hebben # opgegeven). # Normaal lopen hoofdverdichtingen van 1 t/m 9, en verdichtingen # van 10 t/m 99. Indien daarvan wordt afgeweken kan dit worden opgegeven # met de opdracht "Verdichting". De twee getallen geven het hoogste # nummer voor hoofdverdichtingen resp. verdichtingen. Verdichting 9 99 # De nummers van de grootboekrekeningen worden geacht groter te zijn # dan de maximale verdichting. Daarvan kan worden afgeweken door # middels voorloopnullen de _lengte_ van het nummer groter te maken # dan de lengte van de maximale verdichting. Als bijvoorbeeld 99 de # maximale verdichting is, dan geeft 001 een grootboekrekening met # nummer 1 aan. Balansrekeningen 1 Vaste Activa 12 Materiele vaste activa 1210 D Schouw 1211 C Afschrijving Schouw 1220 D Buitenboordmotor 10pk 1221 C Afschrijving Buitenboordmotor 10pk 2 Vlottende activa 21 Vooraden 2110 D Voorraad Educatief Materiaal 22 Vorderingen 2200 D Debiteuren :koppeling=deb 2210 D Debiteuren Scholenwerkgroep 2220 D Vooruitbetaalde bedragen 24 Liquide middelen 2400 D Kas 2410 D Postbank Bestuur 2420 D Postbank Scholenwerkgroep 2450 D Postbank Plus rekening 2460 D Postbank Loyaal rekening 2490 D Kruisposten 3 Eigen vermogen 31 Kapitaal 3100 C Eigen Vermogen :koppeling=winst 32 Reserveringen 3210 C Reservering Gidsencurus 3220 C Reservering Huisvesting 3230 C Reservering Inventaris en Inrichting 3240 C Reservering Materieel 3250 C Reservering Vaartuigen 3260 C Reservering Baggerfonds 3270 C Reservering Jubileum 4 Vreemd vermogen 46 Leveranciers kredieten 4600 C Crediteuren :koppeling=crd Resultaatrekeningen 5 Opbrengsten 50 Tussenrekeningen opbrengsten 5010 O Bijdragen van leden 5011 O Contributie Leden 5012 O Contributie Huisgenootleden 5013 O Contributie donateurs 5014 O Giften bij contributies 5015 O Overige giften 5030 O Bijdragen Rijk/Provincie 5050 O Subsidie Gouda 5060 O Subsidie Reeuwijk 5080 O Rente baten 5090 O Overige baten 51 Baten Bestuur en algemeen 5110 O Bijdragen van leden Bestuur 5120 O Inkomsten uit verkopen Bestuur 5130 O Bijdragen Rijk/Provincie Bestuur 5150 O Subsidie Gouda Bestuur 5160 O Subsidie Reeuwijk Bestuur 5190 O Overige baten Bestuur 52 Baten VLB 5210 O Bijdragen van leden VLB 5220 O Inkomsten uit verkopen VLB 5230 O Bijdragen Rijk/Provincie VLB 5250 O Subsidie Gouda VLB 5260 O Subsidie Reeuwijk VLB 5270 O SOL Subsidies en Bijdragen 5280 O Subsidies Veen 5290 O Overige baten VLB 53 Baten Cursussen 5310 O Bijdragen van leden Cursussen 5320 O Inkomsten uit verkopen Cursussen 5330 O Bijdragen Rijk/Provincie Cursussen 5350 O Subsidie Gouda Cursussen 5360 O Subsidie Reeuwijk Cursussen 5390 O Overige baten Cursussen 54 Baten Excursies 5410 O Bijdragen van leden Excursies 5420 O Inkomsten uit verkopen Excursies 5430 O Bijdragen Rijk/Provincie Excursies 5450 O Subsidie Gouda Excursies 5460 O Subsidie Reeuwijk Excursies 5490 O Overige baten Excursies 55 O Baten Scholen 5510 O Bijdragen van leden Scholen 5520 O Inkomsten uit verkopen Scholen 5530 O Bijdragen Rijk/Provincie Scholen 5550 O Subsidie Gouda Scholen 5560 O Subsidie Reeuwijk Scholen 5590 O Overige baten Scholen 56 Baten Inktzwam 5610 O Bijdragen van leden Inktzwam 5620 O Inkomsten uit verkopen Inktzwam 5630 O Bijdragen Rijk/Provincie Inktzwam 5650 O Subsidie Gouda Inktzwam 5660 O Subsidie Reeuwijk Inktzwam 5690 O Overige baten Inktzwam 57 Baten Evenementen 5710 O Bijdragen van leden Evenementen 5720 O Inkomsten uit verkopen Evenementen 5730 O Bijdragen Rijk/Provincie Evenementen 5750 O Subsidie Gouda Evenementen 5760 O Subsidie Reeuwijk Evenementen 5770 O Subsidie NatuurNetwerk 5780 O Subsidie Zuidhollandse Milieufederatie 5790 O Overige baten Evenementen 58 Baten Educatief Materiaal 5810 O Bijdragen van leden Educatief Materiaal 5820 O Inkomsten uit verkopen Educatief Materiaal 5830 O Bijdragen Rijk/Provincie Educatief Materiaal 5850 O Subsidie Gouda Educatief Materiaal 5860 O Subsidie Reeuwijk Educatief Materiaal 5890 O Overige baten Educatief Materiaal 59 Baten Overig (incidenteel) 5900 O Incidentele baten 6 Kosten werkgroepen 60 Tussenrekeningen kosten # Deze kosten zijn nog te verdelen over de werkgroepen 6010 K Personeelskosten 6020 K Huisvestingskosten 6030 K Organisatiekosten 6040 K Uitvoeringskosten 6090 K Overige kosten 61 Kosten Bestuur en algemeen 6110 K Personeelskosten Bestuur 6120 K Huisvestingskosten Bestuur 6130 K Organisatiekosten Bestuur 6140 K Uitvoeringskosten Bestuur 6150 K Kosten Ledenvergadering 6160 K Afdracht district ZH 6170 K Afdracht landelijk IVN 6180 K Bankkosten 6190 K Overige kosten Bestuur 62 Kosten Werkgroep VLB 6210 K Personeelskosten VLB 6220 K Huisvestingskosten VLB 6230 K Organisatiekosten VLB 6240 K Uitvoeringskosten VLB 6250 K Afschrijvingskosten VLB 6290 K Overige kosten VLB 63 Kosten Werkgroep Cursussen 6310 K Personeelskosten Cursussen 6320 K Huisvestingskosten Cursussen 6330 K Organisatiekosten Cursussen 6340 K Uitvoeringskosten Cursussen 6390 K Overige kosten Cursussen 64 Kosten Werkgroep Excursies en Lezingen 6410 K Personeelskosten Excursies en Lezingen 6420 K Huisvestingskosten Excursies en Lezingen 6430 K Organisatiekosten Excursies en Lezingen 6440 K Uitvoeringskosten Excursies 6450 K Uitvoeringskosten Lezingen 6490 K Overige kosten Excursies 65 Kosten Werkgroep Scholen 6510 K Personeelskosten Scholen 6520 K Huisvestingskosten Scholen 6530 K Organisatiekosten Scholen 6540 K Uitvoeringskosten Scholen 6590 K Overige kosten Scholen 66 Kosten Werkgroep Inktzwam en PR 6610 K Personeelskosten Inktzwam 6620 K Huisvestingskosten Inktzwam 6630 K Organisatiekosten Inktzwam 6640 K Uitvoeringskosten Inktzwam 6650 K Kosten Website 6660 K Kosten PR 6670 K Drukkosten Inktzwam 6680 K Portokosten Inktzwam 6690 K Overige kosten Inktzwam 67 Kosten Werkgroep Evenementen 6710 K Personeelskosten Evenementen 6720 K Huisvestingskosten Evenementen 6730 K Organisatiekosten Evenementen 6740 K Uitvoeringskosten Evenementen 6750 K Uitvoeringskosten Seizoensopening 6760 K Uitvoeringskosten Symposium 6790 K Overige kosten Evenementen 68 Kosten Werkgroep Educatied Materiaal 6810 K Personeelskosten Educatief Materiaal 6820 K Huisvestingskosten Educatief Materiaal 6830 K Organisatiekosten Educatief Materiaal 6840 K Uitvoeringskosten Educatief Materiaal 6890 K Overige kosten Educatief Materiaal 69 Overige kosten (incidenteel) 6900 K Incidentele kosten # DAGBOEKEN # # EekBoek ondersteunt vijf soorten dagboeken: Kas, Bank, Inkoop, # Verkoop en Memoriaal. Er kunnen een in principe onbeperkt aantal # dagboeken worden aangemaakt. # In de eerste kolom wordt de korte naam (code) voor het dagboek # opgegeven. Verder moet voor elk dagboek worden opgegeven van welk # type het is. Voor dagboeken van het type Kas en Bank moet een # tegenrekening worden opgegeven, voor de overige dagboeken mag een # tegenrekening worden opgegeven. # De optie :dc kan worden gebruikt om aan te geven dat het journaal # voor dit dagboek de boekstuktotalen in gescheiden debet en credit # moet tonen. Dagboeken Ink Inkoop :type=inkoop Kas Kas :type=kas :rekening=2400 :dc Mem Memoriaal :type=memoriaal P_B Postbank_bestuur :type=bank :rekening=2410 :dc P_S Postbank_scholen :type=bank :rekening=2420 :dc P_P Postbank_plus :type=bank :rekening=2450 :dc P_L Postbank_Loyaal :type=bank :rekening=2460 :dc Ver Verkoop :type=verkoop # Einde EekBoek schema EekBoek-2.030.1/lib/EB/examples/nl/ondernemer.dat0000644000400000040000000005131513044346163017104 0ustar jvjv# EekBoek Rekeningschema, gebaseerd op een voorbeeld van Johan Vromans. -*- coding: utf-8 -*- # Aangemaakt op 2008-12-18 # First published: 2009-05-03 (version: 1.0). # Versie 1.1, laatst gewijzigd op 2009-05-06 # Dit schema sluit aan bij de Aangifte inkomstenbelasting 2008 voor ondernemers. # Laatste versie: http://yellowmatter.dyndns.org/accounting/eekboek/schema/ondernemers/ # Author: Jaap van Wingerde, # e-mail: <1234567890@vanwingerde.net>. # EekBoek is een electronisch boekhoudprogramma door Johan Vromans # bedoeld voor het midden- en # kleinbedrijf , # . # # Content-Type: text/plain; charset = UTF-8 # Dit bestand definiëert alle vaste gegevens van een administratie of # groep administraties: het rekeningschema (balansrekeningen en # resultaatrekeningen), de dagboeken en de BTW tarieven. # # Algemene syntaxregels: # # * Lege regels en regels die beginnen met een hekje # worden niet # geïnterpreteerd. # * Een niet-ingesprongen tekst introduceert een nieuw onderdeel. # * Alle ingesprongen regels zijn gegevens voor dat onderdeel. # REKENINGSCHEMA # # Het rekeningschema is hiërarchisch opgezet volgende de beproefde # methode Bakker. De hoofdverdichtingen lopen van 1 t/m 9, de # verdichtingen t/m 99. De grootboekrekeningen zijn verdeeld in # balansrekeningen en resultaatrekeningen. # # De omschrijving van de grootboekrekeningen wordt voorafgegaan door # een vlaggetje, een letter die resp. Debet/Credit (voor # balansrekeningen) en Kosten/Omzet/Neutraal (voor resultaatrekeningen) # aangeeft. De omschrijving wordt indien nodig gevolgd door extra # informatie. Voor grootboekrekeningen kan op deze wijze de BTW # tariefstelling worden aangegeven die op deze rekening van toepassing # is: # # :btw=nul # :btw=hoog # :btw=laag # :btw=privé # :btw=anders # # Ook is het mogelijk aan te geven dat een rekening een koppeling # (speciale betekenis) heeft met :koppeling=xxx. De volgende koppelingen # zijn mogelijk: # # crd de standaard tegenrekening (Crediteuren) voor inkoopboekingen # deb de standaard tegenrekening (Debiteuren) voor verkoopboekingen # btw_ih de rekening voor BTW boekingen voor inkopen, hoog tarief # btw_il idem, laag tarief # btw_vh idem, verkopen, hoog tarief # btw_vl idem, laag tarief # btw_ph idem, privé, hoog tarief # btw_pl idem, laag tarief # btw_ah idem, anders, hoog tarief # btw_al idem, laag tarief # btw_ok rekening voor de betaalde BTW # winst rekening waarop de winst wordt geboekt # # De koppeling winst is verplicht en moet altijd in een administratie # voorkomen in verband met de jaarafsluiting. # De koppelingen voor BTW moeten worden opgegeven indien BTW # van toepassing is op de administratie. # De koppelingen voor Crediteuren en Debiteuren moeten worden # opgegeven indien er inkoop dan wel verkoopdagboeken zijn die gebruik # maken van de standaardwaarden (dus zelf geen tegenrekening hebben # opgegeven). # Normaal lopen hoofdverdichtingen van 1 t/m 9, en verdichtingen # van 10 t/m 99. Indien daarvan wordt afgeweken kan dit worden opgegeven # met de opdracht "Verdichting". De twee getallen geven het hoogste # nummer voor hoofdverdichtingen resp. verdichtingen. # De nummers van de grootboekrekeningen worden geacht groter te zijn # dan de maximale verdichting. Daarvan kan worden afgeweken door # middels voorloopnullen de _lengte_ van het nummer groter te maken # dan de lengte van de maximale verdichting. Als bijvoorbeeld 99 de # maximale verdichting is, dan geeft 001 een grootboekrekening met # nummer 1 aan. Verdichting 99 9999 Balansrekeningen ### Overzicht activa 01 Immateriële vaste activa 0101 Goodwill 010199 D Goodwill 0102 Vergunningen, concessies en intellectule eigendommen 010299 D Vergunningen, concessies en intellectule eigendommen 0103 Kosten van onderzoek en ontwikkeling 010399 D Kosten van onderzoek en ontwikkeling 0104 Vooruitbetaald op immateriële vaste activa 010499 D Vooruitbetaald op immateriële vaste activa 0105 Overige immateriële vaste activa 010599 D Overige immateriële vaste activa 02 Materiële vaste activa 0201 (Bedrijfs)gebouwen inclusief ondergrond 020199 D (Bedrijfs)gebouwen inclusief ondergrond 0202 (Bedrijfs)terreinen 020299 D (Bedrijfs)terreinen 0203 Machines en installaties 020399 D Machines en installaties 0204 Inventaris 020400 D Inrichting :kosten 020401 C Afschrijving inrichting # zie 280501 020402 D Gereedschappen 020403 C Afschrijving gereedschappen # zie 280503 020498 D Overige inventaris 020499 C Afschrijving overige inventaris # zie 280599 0205 Auto's en overige transportmiddelen 020598 D Auto's en overige transportmiddelen 020599 C Afschrijving auto's en overige transportmiddelen 0206 Vaste bedrijfsmiddelen in uitvoering en vooruitbetaald op materiële vaste activa 020698 D Vaste bedrijfsmiddelen in uitvoering en vooruitbetaald op materiële vaste activa 020699 C Afschrijving vaste bedrijfsmiddelen in uitvoering en vooruitbetaald op materiële vaste activa 0207 Overige materiële vaste activa 020798 D Overige materiële vaste activa :kosten 020799 C Afschrijving overige materiële vaste activa 03 Voorraden 0301 Grond- en hulpstoffen 030199 D Grond en hulpstoffen 0302 Onderhanden werk 030299 D Onderhanden werk 0303 Gereed product en handelsgoederen 030301 D Voorraad <1> 030302 D Voorraad <2> 030303 D Voorraad <3> 030304 D Voorraad <4> 030399 D Voorraad <5> 0304 Vooruitbetaald op voorraden 030499 D Vooruitbetaald op voorraden :kosten 04 Vorderingen op overlopende activa 0401 Vordering omzetbelasting 040108 D 2008 040109 D 2009 040110 D 2010 040199 D Overige vordering omzetbelasting 0402 Kortlopende vorderingen op gelieerde maatschappijen 040299 D Kortlopende vorderingen op gelieerde maatschappijen 0403 Kortlopende vorderingen op participanten 040399 D Kortlopende vorderingen op participanten 0404 Vorderingen op handelsdebiteuren 040401 D Vordering 040499 D Vorderingen op handelsdebiteuren :koppeling=deb 0405 Overlopende activa 040599 D Overlopende activa 0406 Overige overlopende vorderingen 040699 D Overige overlopende vorderingen 05 Effecten 0501 Effecten 050199 D Effecten 06 Liquide middelen 0601 Banktegoeden 060100 D 060199 D Overige banktegoeden 0602 Overige liquide middelen 060200 D Kas 060201 D Borg 060290 D Kruisposten 060299 D Overige liquide middelen ### Overzicht passiva 07 Ondernemingsvermogen en privé stortingen en ontrekkingen 0701 Eigen vermogen 070100 C Eigen vermogen :koppeling=winst 0702 Egalisatiereserve 070299 C Egalisatiereserve 0703 Reserve assurantie eigen risico 070399 C Reserve assurantie eigen risico 0704 Exportreserve 070499 C Exportreserve 0705 Herinvesteringsreserve 070599 C Herinvesteringsreserve 0706 Oudedagsreserve 070699 C Oudedagsreserve 08 Privé onttrekkingen en stortingen 0801 Privé onttrekkingen 080100 D in contanten 080101 D in natura en goederen 080102 D privé gebruik woning 080103 D privé gebruik auto van onderneming 080199 D overige privé onttrekkingen 0802 Privé stortingen 080200 C betalingen uit privé 080201 C gebruik privé auto 080299 C overige privé stortingen 0803 Kosten privé auto inclusief 19% OB 080301 D onderhoud en reparatie 080302 D onderdelen 080303 D brandstof 080399 D overige gebruikskosten 09 Terugkeerreserve 0901 Terugkeerreserve 090100 C Vorming positieve terugkeerreserve 090101 D Vorming negatieve terugkeerreserve 10 Voorzieningen 1001 Garantievoorziening 100199 C Garantievoorziening 1002 Lijfrentevoorziening 100299 C Lijfrentevoorziening 1003 Pensioenvoorziening 100399 C Pensioenvoorziening 1004 VUT-voorziening 100499 C VUT-voorziening 1005 Milieuvoorziening 100599 C Milieuvoorziening 1009 Overige voorzieningen 100999 C Overige voorzieningen 11 Schulden en overlopende passiva 1101 Onderhandse leningen 110100 C Lening <1> 110101 C Lening <2> 110102 C Lening <3> 110103 C Lening <4> 110104 C Lening <5> 110105 C Lening <6> 110106 C Lening <7> 110199 C Overige onderhandse leningen 1102 Obligaties 110299 C Obligaties 1103 Schulden aan kredietinstellingen 110399 C Schulden aan kredietinstellingen 1104 Schulden aan leveranciers en handelskredieten 110401 C Openstaande creditfactuur 110402 C Openstaande factuur 110499 C Schulden aan leveranciers en handelskredieten :koppeling=crd 1105 Schulden aan gelieerde maatschappijen 110599 C Schulden aan gelieerde maatschappijen 1106 Schulden aan participanten 110699 C Schulden aan participanten 1107 Loonbelasting en premie volksverzekeringen 110799 C Loonbelasting en premie volksverzekeringen 1108 Premies werknemersverzekeringen 110899 C Premies werknemersverzekeringen 1109 Omzetbelasting lopend jaar 110900 C OB Verkoop Hoog :koppeling=btw_vh 110901 C OB Verkoop Laag :koppeling=btw_vl 110902 C OB Verkoop overige tarieven, behalve 0% 110903 C OB verlegd 110910 C OB Leveringen uit landen buiten de EU (invoer) 110911 C OB Verwervingen van goederen uit landen binnen EU 110920 D OB Inkoop Hoog :koppeling=btw_ih 110921 D OB Inkoop Laag :koppeling=btw_il 110980 C Kleine ondernemersregeling omzetbelasting 110990 C Afrondingsverschillen Omzetbelasting 110999 C Betaalde omzetbelasting 1110 Omzetbelasting andere jaren 111006 C Omzetbelasting 2006 111007 C Omzetbelasting 2007 111008 C Omzetbelasting 2008 111009 C Omzetbelasting 2009 :koppeling=btw_ok 111010 C Omzetbelasting 2010 111011 C Omzetbelasting 2011 111012 C Omzetbelasting 2012 111013 C Omzetbelasting 2013 111014 C Omzetbelasting 2014 1111 Overlopende passiva 111199 C Overlopende passiva 1112 Overige schulden 111299 C Overige schulden Resultaatrekeningen ## Opbrengsten 12 Netto-omzet 1200 Netto omzet 120000 O Omzet <1> 120001 O Omzet <2> 120002 O Omzet <3> 120003 O Omzet <4> 120004 O Omzet <5> 120005 O Omzet <6> 120006 O Omzet <7> 120007 O Omzet <8> 120091 O Kleine ondernemersregeling omzetbelasting 120092 O Afrondingsverschillen omzetbelasting 120099 O Omzet overig 13 Wijzigingen in voorraden gereed product en onderhanden werk 1300 Wijzigingen in onderhanden werk 130000 O 130099 O Overige Wijziging in onderhanden werk 1301 Wijziging in voorraden gereed product 130199 O Overige Wijziging in voorraden gereed product 1400 Geactiveerde productie voor het eigen bedrijf 140099 O Geactiveerde productie voor het eigen bedrijf 15 Opbrengsten van vorderingen op gelieerde maatschappijen 1500 Opbrengsten van vorderingen op gelieerde maatschappijen 150099 O Opbrengsten van vorderingen op gelieerde maatschappijen 16 Boekwinst op activa 1600 Boekwinst op activa 160099 O Boekwinst op activa 17 Opbrengst van vorderingen op participanten 1700 Opbrengst van vorderingen op participanten 18 Opbrengst van banktegoeden 1800 Opbrengst van banktegoeden 180099 O rente 19 Opbrengsten van overige vorderingen 1900 Opbrengsten van overige vorderingen 190099 O Opbrengsten van overige vorderingen 20 Ontvangen divident 2000 Ontvangen divident 200099 O Ontvangen divident 21 Waarderingsvermeerdering van vorderingen 2100 Waarderingsvermeerdering van vorderingen 210099 O Waarderingsvermeerdering van vorderingen 22 Waarderingsvermeerdering van immateriële en materiële vaste activa 2200 Waarderingsvermeerdering van immateriële en materiële vaste activa 220099 O Waarderingsvermeerdering van immateriële en materiële vaste activa 23 Bijzondere waarderingsvermeerdering van vlottende activa 2300 Bijzondere waarderingsvermeerdering van vlottende activa 230099 O Bijzondere waarderingsvermeerdering van vlottende activa 24 Waarderingsvermeerdering van effecten 2400 Waarderingsvermeerdering van effecten 240099 O Waarderingsvermeerdering van effecten 25 Overige opbrengsten 2500 Overige opbrengsten 250000 O Subsidies 250050 O Afrondingsverschillen 250099 O Overige opbrengsten ## Kosten 26 Inkoopkosten, uitbesteed werk en dergelijke 2600 Kosten van grond- en hulpstoffen en inkoopprijs van de verkopen 260001 K Inkoop <1> 260002 K Inkoop <2> 260099 K Inkoop overige materialen 2601 Kosten van uitbesteed werk en andere externe kosten 260101 K <1> 260102 K <2> 260103 K <3> 260104 K <4> 260105 K <5> 260106 K <6> 260199 K Overige kosten van uitbesteed werk en andere externe kosten 27 Personeelskosten 2700 Personeelskosten 270001 K Lonen en salarissen 270002 K Arbeidsbeloning aan fiscale partner 270003 K Sociale lasten 270004 K Pensioenlasten 270005 K Overige personeelskosten 270006 O Ontvangen uitkeringen en subsidies 28 Afschrijvingen 2801 Goodwill, vergunningen, concessies en intellectuele eigendommen 280199 K Goodwill, vergunningen, concessies en intellectuele eigendommen 2802 (Bedrijfs)gebouwen 280299 K (Bedrijfs)gebouwen 2803 (Bedrijfs)terreinen 280399 K (Bedrijfs)terreinen 2804 Machines en installaties 280499 K Machines en installaties 2805 Inventaris 280501 K Inrichting 280503 K Gereedschappen 280599 K Overige inventaris 2806 Auto's en overige transportmiddelen 280699 K Auto's en overige transportmiddelen 2899 Overige afschrijvingen 289999 K Overige afschrijvingen 29 Overige bedrijfskosten 2901 Auto- en transportkosten 290100 K Gebruik privé auto 290101 K Huren auto 290102 K Overige kosten huurauto 290109 K Overige autokosten 290111 K Trein 290112 K Bus 290113 K Taxi 290114 K Vliegtuig 290119 K Overig openbaar vervoer 290121 K Bode 290199 K Overige auto- en transportkosten 39 Huisvestingskosten 3901 Huisvestingskosten 390100 K Huur 390101 K Parkeervergunning 390199 K Overige huisvestingskosten 40 Onderhoudskosten van overige materiële vaste activa 4001 Onderhoudskosten van overige materiële vaste activa 400100 K Onderhoudskosten van overige materiële vaste activa 41 Verkoopkosten 4101 Verkoopkosten 410100 K Bemiddelingskosten 410101 K Reclame 410102 K 410103 K Fotografie 410104 K Drukken en printen 410105 K 410106 K Internet 410107 K Porto 410108 K Gemengde kosten 410109 K Hotels 410110 K Google Adwords 410199 K Overige verkoopkosten 42 Kosten van schulden aan gelieerde maatschappijen 4201 Kosten van schulden aan gelieerde maatschappijen 420100 K Kosten van schulden aan gelieerde maatschappijen 43 Kosten van schulden aan particpanten 4301 Kosten van schulden aan particpanten 430100 K Kosten van schulden aan particpanten 44 Kosten van schulden, andere rentelasten en soortgelijke kosten 4401 Kosten van schulden, andere rentelasten en soortgelijke kosten 440100 K Rente bank 440199 K Overige kosten van schulden, andere rentelasten en soortgelijke kosten 45 Waarderingsvermindering van vorderingen 4501 Waarderingsvermindering van vorderingen 450100 K Waarderingsvermindering van vorderingen 46 Waarderingsvermindering van immateriële en materiële vaste activa 4601 Waarderingsvermindering van immateriële en materiële vaste activa 460100 K Waarderingsvermindering van immateriële en materiële vaste activa 47 Bijzondere waarderingsvermindering van vlottende activa 4701 Bijzondere waarderingsvermindering van vlottende activa 470100 K Bijzondere waarderingsvermindering van vlottende activa 48 Waarderingsvermindering van effecten 4801 Waarderingsvermindering van effecten 480100 K Waarderingsvermindering van effecten 49 Andere kosten 4901 Andere kosten 490100 K Telefoon 490101 K Internet 490102 K Contributies 490103 K Verzekeringen 490104 K Vakliteratuur 490105 K Toegangsbewijzen 490106 K Vakbond 490107 K Bank 490108 K Opleidingen 490199 K Overige andere kosten 50 Buitengewone lasten 5001 Afboeking herinvesteringsreserve op gekochte activa 500199 K Afboeking herinvesteringsreserve op gekochte activa 5002 Opheffing negatieve terugkeerreserve 50029 K Opheffing negatieve terugkeerreserve 5003 Overige buitengewone lasten 500000 K 500399 K Overige buitengewone lasten 51 Buitengewone baten 5101 Overige buitengewone baten 510199 O Overige buitengewone baten # DAGBOEKEN # # EekBoek ondersteunt vijf soorten dagboeken: Kas, Bank, Inkoop, # Verkoop en Memoriaal. Er kunnen een in principe onbeperkt aantal # dagboeken worden aangemaakt. # In de eerste kolom wordt de korte naam (code) voor het dagboek # opgegeven. Verder moet voor elk dagboek worden opgegeven van welk # type het is. Voor dagboeken van het type Kas en Bank moet een # tegenrekening worden opgegeven, voor de overige dagboeken mag een # tegenrekening worden opgegeven. # De optie :dc kan worden gebruikt om aan te geven dat het journaal # voor dit dagboek de boekstuktotalen in gescheiden debet en credit # moet tonen. Dagboeken I Inkoop :type=inkoop K Kas :type=kas :rekening=060200 M Memoriaal :type=memoriaal B :type=bank :rekening=060100 V Verkoop :type=verkoop # BTW TARIEVEN # # Er zijn vijf tariefgroepen: "hoog", "laag", "nul", "privé" en # "anders". De tariefgroep bepaalt het rekeningnummer waarop de # betreffende boeking plaatsvindt. # Binnen elke tariefgroep zijn meerdere tarieven mogelijk, hoewel dit # in de praktijk niet snel zal voorkomen. # In de eerste kolom wordt de code voor dit tarief opgegeven. Deze kan # o.m. worden gebruikt om expliciet een BTW tarief op te geven bij het # boeken. Voor elk gebruikt tarief (behalve die van groep "nul") moet # het percentage worden opgegeven. Met de aanduiding :exclusief kan # worden opgegeven dat boekingen op rekeningen met deze tariefgroep # standaard het bedrag exclusief BTW aangeven. # # BELANGRIJK: Mutaties die middels de command line shell of de API # worden uitgevoerd maken gebruik van het geassocieerde BTW tarief van # de grootboekrekeningen. Wijzigingen hierin kunnen dus consequenties # hebben voor de reeds in scripts vastgelegde boekingen. BTW Tarieven H21 BTW 21% :tariefgroep=hoog :perc=21,00 L06 BTW 6,0% :tariefgroep=laag :perc=06,00 P12 BTW Privé 12% :tariefgroep=privé :perc=12,00 # Einde EekBoek schema EekBoek-2.030.1/lib/EB/examples/README0000644000400000040000000000046512725476602014532 0ustar jvjvDeze directory bevat voorbeelden van EekBoek schema's en andere data bestanden. Alle bestanden zijn bedoeld als voorbeeld, en niet om een werkende administratie uit aan te maken. Gebruik daarvoor het bestand sampledb.ebz in de schema directory, of draai ebshell met de command line optie --createsampledb . EekBoek-2.030.1/lib/EB/examples/Kasverkoop.pm0000644000400000040000000000464112725476602016334 0ustar jvjv#! perl # Author : Johan Vromans # Created On : Tue Dec 30 11:56:22 2008 # Last Modified By: Johan Vromans # Last Modified On: Sat Jun 19 00:48:45 2010 # Update Count : 24 # Status : Unknown, Use with caution! # Om deze module te gebruiken dient deze te worden geplaatst in de # werk-directory. Vervolgens moet aan .eekboek.conf de volgende sectie # worden toegevoegd: # # [shell] # userdefs = Kasverkoop # # De naam achter userdefs moet uiteraard dezelfde zijn als die # waaronder de module is opgeslagen, zonder de ".pm" extensie. package EB::Shell::Kasverkoop; use strict; use warnings; use EB; # Implementatie opdracht "kasverkoop". # # kasverkoop datum debiteur omschrijving bedrag # # Dit wordt omgezet in twee opdrachten: # # verkoop datum Kasboeking debiteur omschrijving bedrag # kas datum omschrijving deb debiteur bedrag sub EB::Shell::do_kasverkoop { my ($self, @args) = @_; # Controleer argumenten. "--nr=.." is een intern doorgegeven # argument wanneer de vorm "kasverkoop:boekstuknummer" wordt # gebruikt. my $bsknr; if ( @args && $args[0] =~ /^--?nr=(.+)/ ) { $bsknr = $1; shift(@args); } my $datum; if ( @args && $args[0] =~/^\d+-\d+(-\d+)?$/ ) { $datum = shift(@args); } else { $datum = iso8601date(); } # Nu moeten nog drie argumenten overblijven. die("Onvoldoende argumenten. Nodig: [ datum ] debiteur omschrijving bedrag\n") unless @args == 3; # Opmaken verkoopboeking. my @cmd1 = qw(verkoop); push(@cmd1, $datum, $args[1], $args[0], $args[1], $args[2]); # Opmaken kasboeking. my @cmd2 = qw(kas); push(@cmd2, "--nr=$bsknr") if $bsknr; push(@cmd2, $datum, $args[1], "deb", $args[0], $args[2]); for my $command ( \@cmd1, \@cmd2 ) { warn("+ @$command\n") if $self->{echo}; my $cmd = shift(@$command); my $m = $self->can("do_$cmd"); die("Onbekende opdracht: $cmd (eigen schuld)") unless $m; my $output = $self->$m(@$command); $self->print("$output\n") if $output; } return; } # En uiteraard, de hulpboodschap. sub EB::Shell::help_kasverkoop { return < Bijvoorbeeld: kasverkoop 28-01 PIETJE "Dansles" 25,00 Dit wordt omgezet in de opdrachten: verkoop 28-01 "Kasverkoop" PIETJE "Dansles" 25,00 kas 28-01 "Kasverkoop" deb PIETJE 25,00 EOD } # Package ends here. 1; EekBoek-2.030.1/lib/EB/examples/eekboek.conf0000644000400000040000000000412313044346163016112 0ustar jvjv; Example EekBoek config file. ; ; This file will be placed in your current directory when you execute ; the command: ; ; $ ebshell --createsampleconfig ; ; Change as needed. See http://www.eekboek.nl/docs/config.html ; for details. ; ; NOTE THAT FOR MOST PURPOSES, ONLY THE DATABASE NAME AND DRIVER NEED ; TO BE SPECIFIED. ALL OTHER SETTINGS MAY REMAIN AS THEY ARE. ; THESE ARE EXAMPLES. See http://www.eekboek.nl/docs/config.html ; for details. [general] ; Location where administrations are placed. ;admdir = $HOME/.eekboek/admdir ; Force wizard even if there's a config file in place. ;wizard = 0 [preferences] ; Show journal after each booking. ;journal = 1 [database] ; Name of the database to use. This is the name EekBoek uses to ; identify the database. Note that the actual name as used by the ; database system may be different. ;name = sample ; The database driver (postgres or sqlite). ;driver = sqlite ; Name of the system that runs the database, if not local. ;host = dbhost.example.com ; Access port for the database, if not local. ;port = 5432 ; User to access the database, if not current. ;user = eekboek ; Password for database access, if needed. ;password = secret [strategy] ; Method for rounding numbers (ieee, posix, bankers). ;round = ieee ; Combine bookings to match a payment. ;bkm_multi = 1 ; Do not try an alternative calculation if BTW does not match. ;iv_vc = 0 [shell] ; Private module with EekBoek extensions. ;userdefs = Userdefs ; Abort run when errors are encountered. ;errexit = 0 [format] ; Date format (YYYY-MM-DD, DD-MM-YYY, DD-MM). ;date = DD-MM-YYYY ; Formatted numbers. Only used to specify the decimal point and ; thousands separator. If longer than 9 characters, numwidth (see ; below) is adjusted as well. ;amount = 1234,56 ;amount = 1.234,56 ;amount = 1234.56 ;amount = 1,234.56 [text] ; Column width for amounts in textual reports. ;numwidth = 9 [html] ; Where to find stylesheets. If omitted, default styles will be included. ; See the docs. ;cssdir = css [csv] ; Field separator for generated CSV files. ;separator = , [security] ; None, currently. EekBoek-2.030.1/lib/EB/Config.pm0000644000400000040000000001445713151741100013563 0ustar jvjv#! perl -- -*- coding: utf-8 -*- use utf8; # Config.pm -- Configuration files. # Author : Johan Vromans # Created On : Fri Jan 20 17:57:13 2006 # Last Modified By: Johan Vromans # Last Modified On: Thu Aug 31 10:01:04 2017 # Update Count : 263 # Status : Unknown, Use with caution! package main; our $cfg; our $dbh; package EB::Config; use strict; use warnings; use Carp; use File::Spec; sub init_config { my ($pkg, $opts) = @_; my $app; Carp::croak("Internal error -- missing package arg for __PACKAGE__\n") unless $app = delete $opts->{app}; $app = lc($app); return if $::cfg && $app && $::cfg->{app} eq lc($app); # Pre-parse @ARGV for "-f configfile". my $extraconf = $opts->{config}; my $skipconfig = $opts->{nostdconf}; # Resolve extraconf to a file name. It must exist. if ( $extraconf ) { if ( -d $extraconf ) { my $f = File::Spec->catfile( $extraconf, EB::Config::Handler::std_config($app) ); if ( -e $f ) { $extraconf = $f; } else { $extraconf = File::Spec->catfile($extraconf, EB::Config::Handler::std_config_alt($app)); } } die("$extraconf: $!\n") unless -f $extraconf; } # Build the list of config files. my @cfgs; if ( !$skipconfig ) { @cfgs = ( File::Spec->catfile( "etc", $app, EB::Config::Handler::std_config($app) ), EB::Config::Handler::user_dir ( $app, EB::Config::Handler::std_config($app) ), ); unless ( $extraconf ) { push(@cfgs, EB::Config::Handler::std_config($app)); $cfgs[-1] = EB::Config::Handler::std_config_alt($app) unless -e $cfgs[-1]; } } push(@cfgs, $extraconf) if $extraconf; # Load configs. my $cfg = EB::Config::Handler->new($app); for my $file ( @cfgs ) { next unless -s $file; $cfg->load($file); } if ( $opts->{define} ) { while ( my ($k, $v) = each( %{ $opts->{define} } ) ) { if ( $k =~ /^(\w+(?:::\w+)*)::?(\w+)/ ) { $cfg->newval($1, $2, $v); } else { warn("define error: \"$k\" = \"$v\"\n"); } } } $cfg->_plug(qw(database name EB_DB_NAME)); if ( my $db = $cfg->val(qw(database name), undef) ) { $db =~ s/^eekboek_//; # legacy $cfg->newval(qw(database name), $db); $ENV{EB_DB_NAME} = $db; } $cfg->_plug(qw(database host EB_DB_HOST)); $cfg->_plug(qw(database port EB_DB_PORT)); $cfg->_plug(qw(database user EB_DB_USER)); $cfg->_plug(qw(database password EB_DB_PASSWORD)); $cfg->_plug(qw(csv separator EB_CSV_SEPARATOR)); $cfg->_plug(qw(internal now EB_SQL_NOW)); $cfg->_plug("internal sql", qw(trace EB_SQL_TRACE)); $cfg->_plug("internal sql", qw(prepstats EB_SQL_PREP_STATS)); $cfg->_plug("internal sql", qw(replayout EB_SQL_REP_LAYOUT)); if ( $cfg->val(__PACKAGE__, "showfiles", 0) ) { warn("Config files:\n ", join( "\n ", $cfg->files ), "\n"); } if ( $cfg->val(__PACKAGE__, "dumpcfg", 0) ) { use Data::Dumper; warn(Dumper($cfg)); } $::cfg = $cfg; } sub import { my ($self, $app) = @_; return unless defined $app; die("PROGRAM ERROR: EB::Config cannot import anything"); } package EB::Config::Handler; # Very simple inifile handler (read-only). sub _key { my ($section, $parameter) = @_; $section.'::'.$parameter; } sub val { my ($self, $section, $parameter, $default) = @_; my $res; $res = $self->{data}->{ _key($section, $parameter) }; $res = $default unless defined $res; Carp::cluck("=> missing config: \"" . _key($section, $parameter) . "\"\n") unless defined $res || @_ > 3; $res; } sub newval { my ($self, $section, $parameter, $value) = @_; $self->{data}->{ _key($section, $parameter) } = $value; } sub setval { my ($self, $section, $parameter, $value) = @_; my $key = _key( $section, $parameter ); Carp::cluck("=> missing config: \"$key\"\n") unless exists $self->{data}->{ $key }; $self->{data}->{ $key } = $value; } sub _plug { my ($self, $section, $parameter, $env) = @_; $self->newval($section, $parameter, $ENV{$env}) if $ENV{$env} && !$self->val($section, $parameter, undef); } sub files { my ($self) = @_; return $self->{files}->[-1] unless wantarray; return @{ $self->{files} }; } sub file { goto &files; # for convenience } sub set_file { my ( $self, $file ) = @_; if ( $self->{files}->[0] eq '' ) { $self->{files} = []; } push( @{ $self->{files} }, $file ); } sub app { my ($self) = @_; $self->{app}; } sub new { my ($package, $app, $file) = @_; my $self = bless {}, $package; $self->{files} = [ '' ]; $self->{data} = {}; $self->{app} = $app; $self->load($file) if defined $file; return $self; } sub load { my ($self, $file) = @_; open( my $fd, "<:encoding(utf-8)", $file ) or Carp::croak("Error opening config $file: $!\n"); $self->set_file($file); my $section = "global"; my $fail; while ( <$fd> ) { chomp; next unless /\S/; next if /^[#;]/; if ( /^\s*\[\s*(.*?)\s*\]\s*$/ ) { $section = lc $1; next; } if ( /^\s*(.*?)\s*=\s*(.*?)\s*$/ ) { $self->{data}->{ _key($section, lc($1)) } = $2; next; } Carp::cluck("Error in config $file, line $.:\n$_\n"); $fail++; } Carp::croak("Error processing config $file, aborted\n") if $fail; $self; } sub printconf { my ( $self, $list ) = @_; return unless @$list > 0; foreach my $conf ( @$list ) { unless ( $conf =~ /^(.+?):([^:]+)/ ) { print STDOUT ("\n"); next; } my ($sec, $conf) = ($1, $2); $sec =~ s/:+$//; my $val = $self->val($sec, $conf, undef); print STDOUT ($val) if defined $val; print STDOUT ("\n"); } } sub user_dir { my ( $app, $item ) = @_; { local $SIG{__WARN__}; local $SIG{__DIE__}; eval { $app = $app->app }; } if ( $^O =~ /^mswin/i ) { my $f = File::Spec->catpath( $ENV{HOMEDRIVE}, $ENV{HOMEPATH}, File::Spec->catfile( $app, $item )); return $f; } File::Spec->catfile( glob("~"), "." . lc( $app), defined($item) ? $item : (), ); } sub std_config { my ( $app ) = @_; { local $SIG{__WARN__}; local $SIG{__DIE__}; eval { $app = $app->app }; } lc($app) . ".conf"; } sub std_config_alt { "." . &std_config; } 1; EekBoek-2.030.1/lib/EB/Export/0000755000400000040000000000000013151742350013276 5ustar jvjvEekBoek-2.030.1/lib/EB/Export/XAF.pm0000644000400000040000000002302613044346163014260 0ustar jvjv# perl # Export::XAF -- Export XML Audit File # Author : Johan Vromans # Created On : Sun Apr 13 17:25:07 2008 # Last Modified By: Johan Vromans # Last Modified On: Fri Dec 11 21:51:17 2015 # Update Count : 244 # Status : Unknown, Use with caution! ################ Common stuff ################ package main; our $dbh; our $cfg; package EB::Export::XAF; use strict; use warnings; use EB; use EB::Format; ################ The Process ################ sub export { my ($self, $opts) = @_; $self = bless {}, $self unless ref $self; my $xaf; open($xaf, '>:encoding(utf-8)', $opts->{xaf}) or die("?". __x("Fout tijdens het aanmaken van exportbestand {name}: {err}", name => $opts->{xaf}, msg => $!)."\n"); $self->{fh} = $xaf; # Default to current boekjaar. $self->{bky} = $opts->{boekjaar} || $dbh->adm("bky"); $self->{indent} = 0; $self->{openingdata} = []; $self->{elts} = []; # Generate XML Audit File. $self->generate_XAF(); } ################ XML Routines ################ { sub indent { " " x $_[0]->{indent} } sub indent_incr { $_[0]->{indent}++ } sub indent_decr { $_[0]->{indent}-- } sub indent_init { $_[0]->{indent} = 0 } } sub generate_XAF { my ($self) = @_; $self->auditfile_begin(); $self->generalLedger(); $self->customersSuppliers(); $self->transactions(); $self->auditfile_end(); } sub auditfile_begin { my ($self) = @_; my $r = $dbh->do("SELECT bky_begin, bky_end". " FROM Boekjaren". " WHERE bky_code = ?", $self->{bky}); $r or die(__x("Onbekend boekjaar: {bky}", bky => $self->{bky})."\n"); @{$self}{qw(begin end)} = @$r; $self->print ('', "\n"); $self->xml_elt_open("auditfile"); $self->xml_elt_open("header"); $self->xml_elt("auditfileVersion", "CLAIR2.00.00"); $self->xml_elt("companyID", $cfg->val(qw(company id), "x")); $self->xml_elt("taxRegistrationNr", $cfg->val(qw(company taxreg), "1")); $self->xml_elt("companyName", $cfg->val(qw(company name), "Squirrel")); $self->xml_elt("companyAddress", $cfg->val(qw(company address), "Here")); $self->xml_elt("companyCity", $cfg->val(qw(company city), "There")); $self->xml_elt("companyPostalCode", $cfg->val(qw(company postalcode), "1234AA")); $self->xml_elt("fiscalYear", $self->{bky}); $self->xml_elt("startDate", $self->{begin}); $self->xml_elt("endDate", $self->{end}); $self->xml_elt("currencyCode", "EUR"); $self->xml_elt("dateCreated", $cfg->val(qw(internal now), iso8601date())); $self->xml_elt("productID", "EekBoek"); $self->xml_elt("productVersion", $EekBoek::VERSION); $self->xml_elt_close("header"); } sub auditfile_end { my ($self) = @_; $self->xml_elt_close("auditfile"); indent_decr; } sub generalLedger { my ($self) = @_; # Parse SQL and execute. my $sth = $dbh->sql_exec ("SELECT acc_id, acc_desc, acc_debcrd, acc_balres, acc_ibalance". " FROM Accounts". " ORDER BY acc_id"); # Bind result columns. $sth->bind_columns(\my($acc_id, $acc_desc, $acc_dc, $acc_br, $acc_ibal)); $self->xml_elt_open("generalLedger"); $self->xml_elt("taxonomy", "geen"); # Fetch entries, one by one. while ( $sth->fetch ) { $self->xml_elt_open("ledgerAccount"); $self->xml_elt("accountID", $acc_id); $self->xml_elt("accountDesc", $acc_desc); # B = Balance, P = Profit/Loss. $self->xml_elt("accountType", $acc_br ? "B" : "P"); $self->xml_elt("leadCode", $acc_id); $self->xml_elt_close("ledgerAccount"); # Save opening transactions. push(@{$self->{openingdata}}, [ $acc_id, $acc_ibal ]) if $acc_ibal; } $self->xml_elt_close("generalLedger"); } sub customersSuppliers { my ($self) = @_; # Parse SQL and execute. my $sth = $dbh->sql_exec ("SELECT DISTINCT rel_code, rel_desc". " FROM Relaties". " ORDER BY rel_code"); # Bind result columns. $sth->bind_columns(\my($rel_code, $rel_desc)); $self->xml_elt_open("customersSuppliers"); # Fetch entries, one by one. while ( $sth->fetch ) { $self->xml_elt_open("customerSupplier"); $self->xml_elt("custSupID", $rel_code); $self->xml_elt("companyName", $rel_desc); $self->xml_elt_open("streetAddress"); $self->xml_elt("address", "onbekend"); $self->xml_elt("city", "ONBEKEND"); $self->xml_elt("postalCode", "0000 XX"); $self->xml_elt("country", "Nederland"); $self->xml_elt_close("streetAddress"); $self->xml_elt_close("customerSupplier"); } $self->xml_elt_close("customersSuppliers"); } sub transactions { my ($self) = @_; $self->xml_elt_open("transactions"); # Retrieve credit and debit totals separately. my ($dcnt, $damt) = @{$dbh->do("SELECT count (*), sum(jnl_amount)". " FROM Journal". " WHERE jnl_amount > 0". " AND jnl_date >= ?". " AND jnl_date <= ?". " AND jnl_seq != 0", $self->{begin}, $self->{end})}; my ($ccnt, $camt) = @{$dbh->do("SELECT count (*), sum(jnl_amount)". " FROM Journal". " WHERE jnl_amount < 0". " AND jnl_date >= ?". " AND jnl_date <= ?". " AND jnl_seq != 0", $self->{begin}, $self->{end})}; my $entries = $dcnt + $ccnt; if ( @{$self->{openingdata}} ) { $entries += @{$self->{openingdata}}; foreach ( @{$self->{openingdata}} ) { if ( $_->[1] < 0 ) { $camt += $_->[1]; } else { $damt += $_->[1]; } } } $self->xml_elt("numberEntries", $entries); $self->xml_elt("totalDebit", _numfmt($damt)); $self->xml_elt("totalCredit", _numfmt(-$camt)); # Get the list of daybooks (dagboeken). my $sth = $dbh->sql_exec ("SELECT dbk_id, dbk_desc, dbk_type". " FROM Dagboeken". " ORDER BY dbk_id"); my @dbk; while ( my $rr = $sth->fetch ) { push(@dbk, [@$rr]); } # Process the daybooks (dagboeken). foreach my $dbk ( @dbk ) { $self->xml_elt_open("journal"); $self->xml_elt("journalID", $dbk->[0]); $self->xml_elt("description", $dbk->[1]); $self->xml_elt("type", $dbk->[2]); # Insert openings transactions in (first) memorial. if ( $dbk->[2] == DBKTYPE_MEMORIAAL && @{$self->{openingdata}} ) { $self->xml_elt_open("transaction"); $self->xml_elt("transactionID", 0); $self->xml_elt("period", 0); $self->xml_elt("transactionDate", $self->{begin}); my $nr = 0; foreach my $op ( @{$self->{openingdata}} ) { $self->xml_elt_open("line"); $self->xml_elt("recordID", ++$nr); $self->xml_elt("accountID", $op->[0]); $self->xml_elt("documentID", 0); $self->xml_elt("description", "opening"); $self->xml_amt($op->[1]); $self->xml_elt_close("line"); } $self->{openingdata} = []; # clear $self->xml_elt_close("transaction"); } # Fetch transactions from journal. $sth = $dbh->sql_exec ("SELECT jnl_date, bsk_nr, jnl_seq,". " jnl_acc_id, jnl_rel, jnl_desc, ". " jnl_amount, jnl_damount". " FROM Journal, Boekstukken". " WHERE jnl_dbk_id = ?". " AND jnl_bsk_id = bsk_id". " AND jnl_date >= ?". " AND jnl_date <= ?". " ORDER BY bsk_nr, jnl_date, jnl_bsk_id, jnl_seq", $dbk->[0], $self->{begin}, $self->{end}); $sth->bind_columns (\my ($jnl_date, $bsk_nr, $jnl_seq, $jnl_acc_id, $jnl_rel, $jnl_desc, $jnl_amount, $jnl_damount)); FETCH: while ( $sth->fetch ) { $self->xml_elt_open("transaction"); $self->xml_elt("transactionID", $bsk_nr); $self->xml_elt("period", substr($jnl_date, 5, 2)); $self->xml_elt("transactionDate", $jnl_date); my $rel = $jnl_rel; # save relation while ( $sth->fetch ) { if ( $jnl_seq == 0 ) { # Close current transaction, proceed with next. $self->xml_elt_close("transaction"); redo FETCH; } $self->xml_elt_open("line"); $self->xml_elt("recordID", $jnl_seq); $self->xml_elt("accountID", $jnl_acc_id); $self->xml_elt("custSupID", $rel); $self->xml_elt("documentID", $bsk_nr); $self->xml_elt("description", $jnl_desc); $self->xml_amt($jnl_amount); $self->xml_elt_close("line"); } $self->xml_elt_close("transaction"); last; } $self->xml_elt_close("journal"); } $self->xml_elt_close("transactions"); } sub print { my ($self, @args) = @_; print { $self->{fh} } @args; } sub printi { my ($self, @args) = @_; print { $self->{fh} } $self->indent, @args; } sub _numfmt { my ($v) = @_; my $t = numfmt_plain($v); $t =~ s/,/./; $t; } ################ XML Support Routines ################ { # Open/close element. sub xml_elt_open { my ($self, $tag) = @_; $self->printi("<$tag>\n"); $self->indent_incr; unshift(@{$self->{elts}}, $tag); } sub xml_elt_close { my ($self, $tag) = @_; if ( $tag eq $self->{elts}->[0] ) { shift(@{$self->{elts}}); } else { warn("XML ERROR: closing element $tag while in ", $self->{elts}->[0], "\n"); } $self->indent_decr; $self->printi("\n"); } } # Output an XML element. sub xml_elt { my ($self, $tag, $val) = @_; $self->printi("<$tag>@{[xml_text($val)]}\n"); } # Output an XML amount. sub xml_amt { my ($self, $amount) = @_; if ( $amount >= 0 ) { $self->xml_elt("debitAmount", _numfmt($amount)); } else { $self->xml_elt("creditAmount", _numfmt(-$amount)); } } # XMLise text. sub xml_text { return "" unless defined $_[0]; for ( $_[0] ) { s/&/&/g; s/'/'/g; s//>/g; return $_; } } 1; EekBoek-2.030.1/lib/EB/Main.pm0000644000400000040000000001514213151230373013237 0ustar jvjv#! perl -- -*- coding: utf-8 -*- use utf8; # Author : Johan Vromans # Created On : Thu Jul 7 15:53:48 2005 # Last Modified By: Johan Vromans # Last Modified On: Tue Aug 29 11:16:43 2017 # Update Count : 1019 # Status : Unknown, Use with caution! ################ Common stuff ################ package main; our $cfg; our $dbh; package EB::Main; use strict; use warnings; use EekBoek; use EB; use EB::DB; use Getopt::Long 2.13; ################ The Process ################ sub run { my ( $pkg, $opts ) = @_; $opts = {} unless defined $opts; binmode(STDOUT, ":encoding(utf8)"); binmode(STDERR, ":encoding(utf8)"); # Preliminary initialize config. EB->app_init( { app => $EekBoek::PACKAGE } ); # Command line options. $opts = { interactive => -t, # runs interactively #command, # command to process #echo, # echo input confirm => 0, # NYI #journal, # show journal #inexport, # in/export #file, # file voor in/export #dir, # directory voor in/export #title, # title for export #errexit # disallow errors in batch verbose => 0, # verbose processing #boekjaar, # boekjaar # Development options (not shown with -help). debug => 0, # debugging trace => 0, # trace (show process) test => 0, # test mode. # Let supplied options override. %$opts, }; # Process command line options. app_options($opts); # Post-processing. $opts->{trace} |= ($opts->{debug} || $opts->{test}); # Initialize config. EB->app_init( { app => $EekBoek::PACKAGE, %$opts } ); if ( $opts->{printconfig} ) { $cfg->printconf( \@ARGV ); exit; } my $userdir = $cfg->user_dir; mkdir($userdir) unless -d $userdir; unless ( defined($opts->{wizard}) && !$opts->{wizard} ) { if ( $opts->{wizard} or !$opts->{config} && ( ( -e $cfg->std_config || -e $cfg->std_config_alt ) ? $cfg->val( qw(general wizard), 0 ) : 1 ) ) { if ( $opts->{inexport} ) { die("?"._T("Opties --init, --command en --import zijn niet toegestaan bij gebruik van de wizard.")."\n") if $opts->{inexport} || $opts->{command}; } require EB::IniWiz; EB::IniWiz->run($opts); # sets $opts->{runeb} die("?"._T("Geen administratie geselecteerd")."\n") unless $opts->{runeb}; EB->app_init( { app => $EekBoek::PACKAGE, %$opts } ); } } $opts->{echo} = "eb> " if $opts->{echo}; my $dataset = $cfg->val(qw(database name), undef); unless ( $dataset ) { die("?"._T("Geen EekBoek database opgegeven.". " Specificeer een database in de configuratiefile,". " of selecteer een andere configuratiefile". " op de command line met \"--config=...\"."). "\n"); } $cfg->newval(qw(database name), $dataset); $cfg->newval(qw(preferences journal), $opts->{journal}) if defined $opts->{journal}; $dbh = EB::DB->new(trace => $opts->{trace}); my $createdb; if ( defined $opts->{inexport} ) { if ( $opts->{inexport} ) { $opts->{command} = 1; $createdb = 1; @ARGV = qw(import --noclean); push(@ARGV, "--file", $opts->{file}) if defined $opts->{file}; push(@ARGV, "--dir", $opts->{dir}) if defined $opts->{dir}; } else { $opts->{command} = 1; @ARGV = qw(export); push(@ARGV, "--file", $opts->{file}) if defined $opts->{file}; push(@ARGV, "--dir", $opts->{dir}) if defined $opts->{dir}; push(@ARGV, "--titel", $opts->{title}) if defined $opts->{title}; } } if ( $createdb ) { $dbh->createdb($dataset); warn("%".__x("Lege database {db} is aangemaakt", db => $dataset)."\n"); } return 0 if $opts->{command} && !@ARGV; require EB::Shell; my $shell = EB::Shell->new ({ HISTFILE => $userdir."/history", command => $opts->{command}, interactive => $opts->{interactive}, errexit => defined($opts->{errexit})?$opts->{errexit}:$cfg->val(qw(shell errexit),0), verbose => $opts->{verbose}, trace => $opts->{trace}, journal => $cfg->val(qw(preferences journal), 0), echo => $opts->{echo}, prompt => lc($cfg->app), boekjaar => $opts->{boekjaar}, }); $| = 1; $shell->run; } ################ Subroutines ################ ################ Subroutines ################ sub app_options { my ( $opts ) = @_; # Process options, if any. # Make sure defaults are set before returning! return unless @ARGV > 0; Getopt::Long::Configure(qw(no_ignore_case)); if ( !GetOptions( $opts, 'command|c' => sub { $opts->{command} = 1; die("!FINISH\n"); }, 'import' => sub { $opts->{inexport} = 1; }, 'export' => sub { $opts->{inexport} = 0; }, 'init' => sub { $opts->{inexport} = 1; $opts->{dir} = "."; }, 'define|D=s%', 'printconfig|P', 'nostdconf|X', 'config|f=s', 'title|titel=s', 'echo|e!', 'ident', 'journaal', 'boekjaar=s', 'verbose|v', 'dir=s', 'file=s', 'interactive!', 'wizard!', 'errexit!', 'version', 'trace', 'help|?', 'debug', ) or $opts->{help} ) { app_usage(2); } app_usage(2) if @ARGV && !($opts->{command} || $opts->{printconfig}); app_ident() if $opts->{ident} || $opts->{version}; } sub app_ident { return; print STDERR (__x("Dit is {pkg} [{name} {version}]", pkg => $EekBoek::PACKAGE, name => "Shell", version => $EekBoek::VERSION) . "\n"); } sub app_usage { my ($exit) = @_; app_ident(); print STDERR __x(< $0); Gebruik: {prog} [options] [file ...] --command -c voer de rest van de opdrachtregel uit als command --echo -e toon ingelezen opdrachten --boekjaar=XXX specificeer boekjaar --import importeer een nieuwe administratie --export exporteer een administratie --dir=XXX directory voor im/export --file=XXX bestand voor im/export --titel=XXX omschrijving voor export --init (re)creëer administratie --help deze hulpboodschap --ident toon identificatie --verbose geef meer uitgebreide information Voor experts: --config=XXX -f specificeer configuratiebestand --nostdconf -X gebruik uitsluitend dit configuratiebestand --define=XXX -D definieer configuratiesetting --printconfig -P print config waarden --[no]interactive forceer [non]interactieve modus --[no]errexit stop direct na een fout in de invoer EndOfUsage CORE::exit $exit if defined $exit && $exit != 0; } 1; EekBoek-2.030.1/lib/EB/Version.pm0000644000400000040000000000016713151742200013776 0ustar jvjv# This file is generated. Do not edit! package EB::Version; our $VERSION = "2.030.1"; print "$VERSION " unless caller; EekBoek-2.030.1/lib/EB/Report.pm0000644000400000040000000001231012725476602013635 0ustar jvjv#! perl package main; our $dbh; # Report.pm -- Report tools # Author : Johan Vromans # Created On : Mon Nov 14 21:46:04 2005 # Last Modified By: Johan Vromans # Last Modified On: Tue Nov 1 10:53:12 2011 # Update Count : 45 # Status : Unknown, Use with caution! package EB::Report; use strict; use warnings; use EB; use EB::Format qw(numfmt); use EB::Report::GenBase; my $trace = 0; sub GetTAccountsBal { shift; my ($end, $inc) = @_; # balans(r, t) = balans(r, t0) + sum(journaal, r, t0..t) + sum(boekjaarbalans, r, t' < t) # balans(r, t0) $dbh->sql_exec("DELETE FROM TAccounts"); $dbh->sql_exec("INSERT INTO TAccounts". " (acc_id,acc_desc,acc_balres,acc_debcrd,acc_dcfixed,". "acc_ibalance,acc_balance,acc_struct)". " SELECT acc_id,acc_desc,acc_balres,acc_debcrd,acc_dcfixed,". "acc_ibalance,acc_ibalance AS acc_balance,acc_struct". " FROM Accounts")->finish; return "TAccounts" unless defined $end; # sum(journaal, r, t0..t) my $sth = $dbh->sql_exec("SELECT jnl_acc_id,acc_balance,SUM(jnl_amount)". " FROM Journal,TAccounts". " WHERE acc_id = jnl_acc_id". " AND jnl_date ".($inc ? "<" : "<=")." ?". " GROUP BY jnl_acc_id,acc_balance,acc_ibalance", $end); while ( my $rr = $sth->fetchrow_arrayref ) { my ($acc_id, $acc_balance, $sum) = @$rr; next unless $sum; $sum += $acc_balance; warn("!".__x("Balansrekening {acct}, saldo aangepast naar {exp}", acct => $acc_id, exp => numfmt($sum)) . "\n") if $trace; $dbh->sql_exec("UPDATE TAccounts". " SET acc_balance = ?". " WHERE acc_id = ?", $sum, $acc_id)->finish; } # sum(boekjaarbalans, r, t' < t) $sth = $dbh->sql_exec("SELECT bkb_acc_id, bkb_balance". " FROM Boekjaarbalans". " WHERE bkb_end ".($inc ? "<=" : "<")." ?", $end); while ( my $rr = $sth->fetchrow_arrayref ) { my ($acc_id, $acc_balance) = @$rr; warn("!".__x("Balansrekening {acct}, saldo aangepast met {exp}", acct => $acc_id, exp => numfmt(-$acc_balance)) . "\n") if $trace; $dbh->sql_exec("UPDATE TAccounts". " SET acc_balance = acc_balance - ?". " WHERE acc_id = ?", $acc_balance, $acc_id)->finish; } # Return temp table. "TAccounts"; } sub GetTAccountsAll { push(@_, 1); goto &GetTAccountsRes; } sub GetTAccountsRes { shift; my ($begin, $end, $all) = @_; # beginsaldo(r, t1, t2) = sum(journaal, r, t0..t1) + sum(boekjaarbalans, r, t' < t1) # eindsaldo(r, t1, t2) = beginsaldo(r, t1, t2) + sum(journaal, r, t1..t2) # init $dbh->sql_exec("DELETE FROM TAccounts"); if ( $all ) { $dbh->sql_exec("INSERT INTO TAccounts SELECT * FROM Accounts")->finish; } else { $dbh->sql_exec("INSERT INTO TAccounts". " (acc_id,acc_desc,acc_balres,acc_debcrd,". "acc_ibalance,acc_balance,acc_struct)". " SELECT acc_id,acc_desc,acc_balres,acc_debcrd,0,0,acc_struct". " FROM Accounts". " WHERE NOT acc_balres")->finish; } # beginsaldo(r, t1, t2) = sum(journaal, r, t0..t1) ... my $sth = $dbh->sql_exec("SELECT jnl_acc_id,SUM(jnl_amount)". " FROM Journal,TAccounts". " WHERE acc_id = jnl_acc_id". " AND jnl_date < ?". " GROUP BY jnl_acc_id", $begin); while ( my $rr = $sth->fetchrow_arrayref ) { my ($acc_id, $sum) = @$rr; next unless $sum; warn("!".__x("Resultaatrekening {acct}, beginsaldo is {exp}", acct => $acc_id, exp => numfmt($sum)) . "\n") if $trace; $dbh->sql_exec("UPDATE TAccounts". " SET acc_ibalance = acc_ibalance + ?". " WHERE acc_id = ?", $sum, $acc_id)->finish; } # ... + sum(boekjaarbalans, r, t' < t1) $sth = $dbh->sql_exec("SELECT bkb_acc_id, bkb_balance". " FROM Boekjaarbalans". " WHERE bkb_end < ?", $begin); while ( my $rr = $sth->fetchrow_arrayref ) { my ($acc_id, $acc_balance) = @$rr; warn("!".__x("Resultaatrekening {acct}, saldo aangepast met {exp}", acct => $acc_id, exp => numfmt(-$acc_balance)) . "\n") if $trace; $dbh->sql_exec("UPDATE TAccounts". " SET acc_ibalance = acc_ibalance - ?". " WHERE acc_id = ?", $acc_balance, $acc_id)->finish; } # zet eindsaldo op beginsaldo $dbh->sql_exec("UPDATE TAccounts". " SET acc_balance = acc_ibalance")->finish; # eindsaldo(r, t2) = beginsaldo(r, t1) + sum(journaal, r, t1..t2) $sth = $dbh->sql_exec("SELECT jnl_acc_id,SUM(jnl_amount)". " FROM Journal,TAccounts". " WHERE acc_id = jnl_acc_id". " AND jnl_date >= ?". " AND jnl_date <= ?". " GROUP BY jnl_acc_id", $begin, $end); while ( my $rr = $sth->fetchrow_arrayref ) { my ($acc_id, $sum) = @$rr; next unless $sum; warn("!".__x("Resultaatrekening {acct}, mutaties is {exp}", acct => $acc_id, exp => numfmt($sum)) . "\n") if $trace; $dbh->sql_exec("UPDATE TAccounts". " SET acc_balance = acc_ibalance + ?". " WHERE acc_id = ?", $sum, $acc_id)->finish; } "TAccounts"; } sub GetTAccountsCopy { shift; $dbh->sql_exec("DELETE FROM TAccounts"); $dbh->sql_exec("INSERT INTO TAccounts SELECT * FROM Accounts")->finish; "TAccounts"; } 1; EekBoek-2.030.1/lib/EB/Utils.pm0000644000400000040000000002000112725476602013456 0ustar jvjv#! perl # Utils.pm -- # Author : Johan Vromans # Created On : Wed Sep 21 13:09:01 2005 # Last Modified By: Johan Vromans # Last Modified On: Tue May 14 20:21:30 2013 # Update Count : 127 # Status : Unknown, Use with caution! package EB::Utils; use strict; use base qw(Exporter); our @EXPORT; our @EXPORT_OK; use Time::Local; # We're imported by EB that exports _T. Kinda catch-22. *_T = *EB::_T; # These are only used by the BTW Aangifte modules. # Note these are translated using _T where appropriate. our @months = split(" ", "Jan Feb Mrt Apr Mei Jun Jul Aug Sep Okt Nov Dec"); our @month_names = split(" ", "Januari Februari Maart April Mei Juni Juli Augustus September Oktober November December"); our @days = split(" ", "Zon Maa Din Woe Don Vri Zat"); our @day_names = split(" ", "Zondag Maandag Dinsdag Woensdag Donderdag Vrijdag Zaterdag"); my $_i; my %rev_months; $_i = 1; foreach ( @months ) { $rev_months{ lc $_ } = $_i; $rev_months{ "m$_i" } = $_i; $rev_months{ sprintf("m%02d", $_i) } = $_i; $_i++; } my %rev_month_names; $_i = 1; foreach ( @month_names ) { $rev_month_names{ lc $_ } = $_i++; } sub parse_date { my ($date, $default_year, $delta_d, $delta_m, $delta_y) = @_; # Parse a date and return it in ISO format (scalar) or # (YYYY,MM,DD) list context. my ($d, $m, $y); if ( $date =~ /^(\d\d\d\d)-(\d\d)-(\d\d)$/ ) { ($y, $m, $d) = ($1, $2, $3); } elsif ( $date =~ /^(\d\d?)-(\d\d?)-(\d\d\d\d)$/ ) { ($d, $m, $y) = ($1, $2, $3); } elsif ( $date =~ /^(\d\d?)-(\d\d?)$/ ) { return unless $default_year; ($d, $m, $y) = ($1, $2, $default_year); } elsif ( $date =~ /^(\d\d?) (\w+)$/ ) { return unless $default_year; return unless $m = $rev_month_names{$2} || $rev_months{$2}; ($d, $y) = ($1, $default_year); } else { return; # invalid format } # The date, as delivered, must be valid. my $time = eval { timelocal(0, 0, 12, $d, $m-1, $y) }; return unless $time; # invalid date # Handle deltas. $y += $delta_y if $delta_y; $m += $delta_m if $delta_m; while ( $m > 12 ) { $m -= 12, $y++ } while ( $m < 1 ) { $m += 12; $y-- } $delta_d += $d - 1; # New date, as of 1st of the month. $time = eval { timelocal(0, 0, 12, 1, $m-1, $y) }; return unless $time; # invalid date # Apply delta. $time += $delta_d * 24*60*60 if $delta_d; # Convert and return. my @tm = localtime($time); @tm = (1900 + $tm[5], 1 + $tm[4], $tm[3]); wantarray ? @tm : sprintf("%04d-%02d-%02d", @tm); } push( @EXPORT, qw(parse_date) ); sub parse_date_range { my ($range, $default_year) = @_; # Parse a date and return it as an array ref of two ISO formatted # dates. my ($d1, $m1, $y1, $d2, $m2, $y2); my $datefix; $range = lc($range); # 2004-03-04 - 2004-05-06 -> [ "2004-03-04", "2004-05-06" ] if ( $range =~ /^(\d\d\d\d)-(\d\d)-(\d\d)\s*[-\/]\s*(\d\d\d\d)-(\d\d)-(\d\d)$/ ) { ($y1, $m1, $d1, $y2, $m2, $d2) = ($1, $2, $3, $4, $5, $6); } # 2004-03-04/05-06 -> [ "2004-03-04", "2004-05-06" ] elsif ( $range =~ /^(\d\d\d\d)-(\d\d)-(\d\d)\s*\/\s*(\d\d)-(\d\d)$/ ) { ($y1, $m1, $d1, $y2, $m2, $d2) = ($1, $2, $3, $1, $4, $5); } # 2004-03-04/06 -> [ "2004-03-04", "2004-03-06" ] elsif ( $range =~ /^(\d\d\d\d)-(\d\d)-(\d\d)\s*\/\s*(\d\d)$/ ) { ($y1, $m1, $d1, $y2, $m2, $d2) = ($1, $2, $3, $1, $2, $4); } # 03-04-2004 - 05-06-2004 -> [ "2004-04-03", "2004-06-05" ] elsif ( $range =~ /^(\d\d)-(\d\d)-(\d\d\d\d)\s*-\s*(\d\d)-(\d\d)-(\d\d\d\d)$/ ) { ($d1, $m1, $y1, $d2, $m2, $y2) = ($1, $2, $3, $4, $5, $6); } # 03-04 - 05-06 -> [ "2004-04-03", "2004-06-25" ] elsif ( $range =~ /^(\d\d)-(\d\d)\s*-\s*(\d\d)-(\d\d)$/ ) { return unless $default_year; ($d1, $m1, $y1, $d2, $m2, $y2) = ($1, $2, $default_year, $3, $4, $default_year); } # 3 april - 5 juni -> [ "2004-04-03", "2004-06-25" ] # 3 april - 5 juni 2004 -> [ "2004-04-03", "2004-06-25" ] elsif ( $range =~ /^(\d+)\s+(\w+)\s*-\s*(\d+)\s+(\w+)(?:\s+(\d{4}))?$/ ) { return unless $default_year; return unless $m1 = $rev_month_names{$2} || $rev_months{$2}; return unless $m2 = $rev_month_names{$4} || $rev_months{$4}; $d1 = $1; $d2 = $3; $y1 = $y2 = $5 || $default_year; } # 3 april 2004 - 5 juni 2004 -> [ "2004-04-03", "2004-06-25" ] elsif ( $range =~ /^(\d+)\s+(\w+)\s+(\d{4})\s*-\s*(\d+)\s+(\w+)\s+(\d{4})$/ ) { return unless $m1 = $rev_month_names{$2} || $rev_months{$2}; return unless $m2 = $rev_month_names{$5} || $rev_months{$5}; $d1 = $1; $d2 = $4; $y1 = $3; $y2 = $6; } # april - juni -> [ "2004-04-01", "2004-06-30" ] # april - juni 2004 -> [ "2004-04-01", "2004-06-30" ] elsif ( $range =~ /^(\w+)\s*-\s*(\w+)(?:\s+(\d{4}))?$/ ) { return unless $default_year; return unless $m1 = $rev_month_names{$1} || $rev_months{$1}; return unless $m2 = $rev_month_names{$2} || $rev_months{$2}; $d1 = 1; $d2 = -1; $y1 = $y2 = $3 || $default_year; } # 2004 -> [ "2004-01-01", "2004-12-31" ] elsif ( $range =~ /^(\d{4})$/ ) { $d1 = 1; $d2 = -1; $m1 = 1; $m2 = 12; $y1 = $y2 = $1; } # k2 -> [ "2004-04-01", "2004-06-30" ] # k2 2004 -> [ "2004-04-01", "2004-06-30" ] elsif ( $range =~ /^[kq](\d+)(?:\s+(\d{4}))?$/ ) { return unless $2||$default_year; return unless $1 >= 1 && $1 <= 4; $m1 = 3 * $1 - 2; $m2 = $m1 + 2; $d1 = 1; $d2 = -1; $y1 = $y2 = $2 || $default_year; } # jaar -> [ "2004-01-01", "2004-12-31" ] elsif ( $range eq lc(EB::_T("jaar")) || $range eq "jaar" ) { return unless $default_year; $d1 = 1; $d2 = -1; $m1 = 1; $m2 = 12; $y1 = $y2 = $default_year; } # apr | april -> [ "2004-04-01", "2004-04-30" ] # apr 2004 -> [ "2004-04-01", "2004-04-30" ] elsif ( $range =~ /^(\w+)(?:\s+(\d{4}))?$/ ) { return unless $2||$default_year; return unless $m1 = $m2 = $rev_month_names{$1} || $rev_months{$1}; $d1 = 1; $d2 = -1; $y1 = $y2 = $2 || $default_year; } else { return; # unrecognizable format } if ( $d2 < 0 ) { $datefix = 24 * 60 * 60; $d2 = 1; $m2 = 1, $y2++ if ++$m2 > 12; } my $time1 = eval { timelocal(0, 0, 12, $d1, $m1-1, $y1) }; return unless $time1; # invalid date my $time2 = eval { timelocal(0, 0, 12, $d2, $m2-1, $y2) }; return unless $time2; # invalid date $time2 -= $datefix if $datefix; my @tm = localtime($time1); my @tm1 = (1900 + $tm[5], 1 + $tm[4], $tm[3]); @tm = localtime($time2); my @tm2 = (1900 + $tm[5], 1 + $tm[4], $tm[3]); [ sprintf("%04d-%02d-%02d", @tm1), sprintf("%04d-%02d-%02d", @tm2) ] } push( @EXPORT, qw(parse_date_range) ); sub iso8601date { my ($time) = shift || time; my @tm = localtime($time); sprintf("%04d-%02d-%02d", 1900+$tm[5], 1+$tm[4], $tm[3]); } push( @EXPORT, qw(iso8601date) ); sub min { $_[0] < $_[1] ? $_[0] : $_[1] } sub max { $_[0] > $_[1] ? $_[0] : $_[1] } push( @EXPORT, qw(min max) ); # Locale / Gettext. # Variable expansion. See GNU gettext for details. sub __expand($%) { my ($t, %args) = @_; my $re = join('|', map { quotemeta($_) } keys(%args)); $t =~ s/\{($re)\}/defined($args{$1}) ? $args{$1} : "{$1}"/ge; $t; } # Translation w/ variables. sub __x($@) { my ($t, %vars) = @_; __expand(_T($t), %vars); } # Translation w/ singular/plural handling. sub __n($$$) { my ($sing, $plur, $n) = @_; _T($n == 1 ? $sing : $plur); } # Translation w/ singular/plural handling and variables. sub __nx($$$@) { my ($sing, $plur, $n, %vars) = @_; __expand(__n($sing, $plur, $n), %vars); } # Make __xn a synonym for __nx. *__xn = \&__nx; # And the dummy... sub N__($) { $_[0] }; # This is for context sensitive translations, where e.g., cmd:btw # translates to cmd:vat and we deliver need the part after the colon. sub __xt { my $t = _T($_[0]); $t =~ s/^.*://; $t; } # Same, without translating. # Basically, __xt is __XN(_T($_[0])). sub __XN { my $t = $_[0]; $t =~ s/^.*://; $t; } push( @EXPORT, qw( __x __n __nx __xn N__ __xt __XN ) ); # ... more to come ... @EXPORT_OK = @EXPORT; 1; EekBoek-2.030.1/lib/EB/Format.pm0000644000400000040000000002201713044346163013610 0ustar jvjv#! perl # Format.pm -- # Author : Johan Vromans # Created On : Thu Jul 14 12:54:08 2005 # Last Modified By: Johan Vromans # Last Modified On: Thu Jan 26 16:38:42 2017 # Update Count : 105 # Status : Unknown, Use with caution! package main; our $cfg; our $dbh; package EB::Format; use strict; use EB; use base qw(Exporter); my $stdfmt0; my $stdfmtw; my $btwfmt0; my $btwfmtw; my $numpat; my $btwpat; my $decimalpt; my $thousandsep; our @EXPORT; our $amount_width; our $date_width; sub numround_ieee { # This somethimes does odd things. # E.g. 892,5 -> 892 and 891,5 -> 892. 0 + sprintf("%.0f", $_[0]); } use POSIX qw(floor ceil); sub numround_posix { my ($val) = @_; if ( $val < 0 ) { ceil($val - 0.5); } else { floor($val + 0.5); } } use POSIX qw(floor); my $_half; sub numround_bankers { # Based on Math::Round::round_even. my $x = shift; return 0 unless $x; my $sign = ($x >= 0) ? 1 : -1; $x = abs($x); my $in = int($x); # Round to next even if exactly 0.5. if ( ($x - $in) == 0.5 ) { return $sign * (($in % 2 == 0) ? $in : $in + 1); } unless ( defined($_half) ) { # Determine what value to use for "one-half". Because of the # perversities of floating-point hardware, we must use a value # slightly larger than 1/2. We accomplish this by determining # the bit value of 0.5 and increasing it by a small amount in # a lower-order byte. Since the lowest-order bits are still # zero, the number is mathematically exact. my $halfhex = unpack('H*', pack('d', 0.5)); if ( substr($halfhex,0,2) ne '00' && substr($halfhex, -2) eq '00' ) { # Big-endian. substr($halfhex, -4) = '1000'; } else { # Little-endian. substr($halfhex, 0, 4) = '0010'; } $_half = unpack('d', pack('H*', $halfhex)); } $sign * POSIX::floor($x + $_half); } sub init_formats { confess( "NUMGROUPS != AMTPRECISION" ) unless NUMGROUPS != AMTPRECISION; ################ BTW display format ################ $btwfmt0 = '%.' . (BTWPRECISION-2) . 'f'; $btwfmtw = '%' . BTWWIDTH . "." . (BTWPRECISION-2) . 'f'; $btwpat = qr/^([-+])?(\d+)?(?:[.,])?(\d{1,@{[BTWPRECISION-2]}})?$/; ################ Amount display format ################ $amount_width = $cfg->val(qw(text numwidth), AMTWIDTH); if ( $amount_width =~ /^\+(\d+)$/ ) { $amount_width = AMTWIDTH + $1; } elsif ( $amount_width =~ /^\-(\d+)$/ ) { $amount_width = AMTWIDTH - $1; } elsif ( $amount_width =~ /^(\d+)%$/ ) { $amount_width = int((AMTWIDTH * $1) / 100); } elsif ( $amount_width !~ /^\d+$/ ) { warn("?"._T("Configuratiefout: [format]numwidth moet een getal zijn")."\n"); $amount_width = AMTWIDTH; } $decimalpt = $cfg->val(qw(locale decimalpt), undef); $thousandsep = $cfg->val(qw(locale thousandsep), undef); my $fmt = $cfg->val(qw(format amount), undef); if ( $fmt || !defined($decimalpt) ) { $fmt = _T("1.234,56") unless defined $fmt; Carp::croak(__x("Configuratiefout: ongeldige waarde voor {item}", item => "format".':'."amount")."\n") unless $fmt =~ /^\d+([.,])\d\d$/ || $fmt =~ /^\d+(\.\d\d\d)*(\,)\d\d$/ || $fmt =~ /^\d+(\,\d\d\d)*(\.)\d\d$/; if ( defined $2 ) { $decimalpt = $2; $thousandsep = substr($1, 0, 1); } else { $decimalpt = $1; $thousandsep = ""; } $amount_width = length($fmt) if length($fmt) > $amount_width; } else { $amount_width += int(($amount_width - AMTPRECISION - 2) / 3) if $thousandsep; } $stdfmt0 = '%.' . AMTPRECISION . 'f'; $stdfmtw = '%' . $amount_width . "." . AMTPRECISION . 'f'; my $sub = ""; $sub .= <= 0 ) { \$v = ("0" x (@{[AMTPRECISION + 1]} - length(\$v))) . \$v if length(\$v) <= @{[AMTPRECISION]}; substr(\$v, length(\$v) - @{[AMTPRECISION]}, 0) = q\000$decimalpt\000; } else { \$v = sprintf("$stdfmt0", \$v/@{[AMTSCALE]}); EOD $sub .= <val(qw(strategy round), "ieee")); unless ( defined &{"numround_$numround"} ) { die("?".__x("Onbekende afrondingsmethode: {meth}", meth => $numround)."\n"); } *numround = \&{"numround_$numround"}; ################ Date display format ################ $fmt = $cfg->val(qw(format date), "YYYY-MM-DD"); $sub = "sub datefmt { \$_[0] }"; my $sub_full = "sub datefmt_full { \$_[0] }"; my $sub_plain = "sub datefmt_plain { \$_[0] }"; if ( lc($fmt) eq "dd-mm-yyyy" ) { $sub = q; $sub_full = q; } elsif ( lc($fmt) eq "dd-mm" ) { $sub = q; $sub_full = q; } elsif ( lc($fmt) ne "yyyy-mm-dd" ) { die("?".__x("Ongeldige datumformaatspecificatie: {fmt}", fmt => $fmt)."\n"); } for ( $sub, $sub_full, $sub_plain ) { eval($_); die($_."\n".$@) if $@; } $date_width = length(datefmt("2006-01-01")); } sub numxform_strict { $_ = shift; my $err = __x("Ongeldig bedrag: {num}", num => $_); my $sign = ""; $sign = $1 if s/^([-+])// && $1 eq '-'; # NNNN -> NNNN.00 if ( /^\d+$/ ) { s/^0+(\d)$/$1/; return $sign . $_ . "." . ("0" x AMTPRECISION); } # N,NNN -> NNNN.00 if ( /^(\d{1,@{[NUMGROUPS]}})(\,\d{@{[NUMGROUPS]}})*$/ && $1 ) { s/\,//g; s/^0+(\d)$/$1/; return $sign . $_ . "." . ("0" x AMTPRECISION); } # N.NNN -> NNNN.00 if ( /^(\d{1,@{[NUMGROUPS]}})(\.\d{@{[NUMGROUPS]}})*$/ && $1 ) { s/\.//g; s/^0+(\d)$/$1/; return $sign . $_ . "." . ("0" x AMTPRECISION); } # N.NNN,NN or N,NNN.NN return $err unless /^([\d.]+)(\,)(\d{@{[AMTPRECISION]}})$/ || /^([\d,]+)(\.)(\d{@{[AMTPRECISION]}})$/; my ($mant, $sep, $frac) = ( $1, $2, $3 ); # N.NNN , NN -> NNNN NN if ( $sep eq "," ) { $mant =~ s/\.//g if $mant =~ /^\d{1,@{[NUMGROUPS]}}(\.\d{@{[NUMGROUPS]}})*$/; } # N,NNN . NN -> NNNN NN else { $mant =~ s/\,//g if $mant =~ /^\d{1,@{[NUMGROUPS]}}(\,\d{@{[NUMGROUPS]}})*$/; } # NNNN NN -> NNNN.NN $mant =~ s/^0+(\d)$/$1/; return $sign . $mant . "." . $frac if $mant =~ /^\d+$/; die("?$err\n"); # not well-formed } sub numxform_loose { $_ = shift; my $err = __x("Ongeldig getal: {num}", num => $_); # If there's a single comma, make decimal point. s/,/./ if /^.*,.*$/; return $_ if /^[-+]*\d+(\.\d+)?$/; die("?$err\n"); # not well-formed } sub numxform { my ($n) = @_; my $res = numxform_strict($n); return $res if defined $res; # return $n if $n =~ /^[-a+]?\d+[.,]\d+$/; # a ? return $n if $n =~ /^[-+]?\d+[.,]\d+$/; return undef; } sub amount($) { my $val = shift; my $debug = $cfg->val(__PACKAGE__, "debugexpr", 0); if ( $val =~ /.[-+*\/\(\)]/ ) { print STDERR ("val \"$val\" -> ") if $debug; $val =~ s/([.,\d]+)/numxform_loose($1)/ge; print STDERR ("\"$val\" -> ") if $debug; my $res = eval($val); warn("$val: $@"), return undef if $debug && $@; return undef if $@; $val = sprintf($stdfmt0, $res); print STDERR ("$val\n") if $debug; } else { return undef unless $val = numxform_strict($val); # fortunately, 0.00 is true } return undef unless $val =~ $numpat; my ($s, $w, $f) = ($1 || "", $2 || 0, $3 || 0); $f .= "0" x (AMTPRECISION - length($f)); return 0 + ($s.$w.$f); } sub numfmtw { my $v = shift; if ( $v == int($v) && $v >= 0 ) { $v = ("0" x (AMTPRECISION - length($v) + 1)) . $v if length($v) <= AMTPRECISION; $v = (" " x (AMTWIDTH - length($v))) . $v if length($v) < AMTWIDTH; substr($v, length($v) - AMTPRECISION, 0) = $decimalpt; } else { $v = sprintf($stdfmtw, $v/AMTSCALE); $v =~ s/\./$decimalpt/; } $v; } #### UNUSED sub numfmtv { my $v = shift; if ( $v == int($v) && $v >= 0 ) { $v = ("0" x (AMTPRECISION - length($v) + 1)) . $v if length($v) <= AMTPRECISION; $v = (" " x ($_[0] - length($v))) . $v if length($v) < $_[0]; substr($v, length($v) - AMTPRECISION, 0) = $decimalpt; } else { $v = sprintf('%'.$_[0].'.'.AMTPRECISION.'f', $v/AMTSCALE); $v =~ s/\./$decimalpt/; } $v; } sub btwfmt { my $v = sprintf($btwfmt0, 100*$_[0]/BTWSCALE); $v =~ s/\./$decimalpt/; $v; } sub btwpat { $btwpat } ################ Code ################ push( @EXPORT, qw(amount numround btwfmt), qw($amount_width numfmt numfmt_plain), qw($date_width datefmt datefmt_full datefmt_plain), ); 1; EekBoek-2.030.1/lib/EB/Relation.pm0000644000400000040000000001116613044346163014140 0ustar jvjv#! perl # Relation.pm -- # Author : Johan Vromans # Created On : Thu Jul 14 12:54:08 2005 # Last Modified By: Johan Vromans # Last Modified On: Sat Mar 1 22:19:37 2014 # Update Count : 122 # Status : Unknown, Use with caution! package main; our $dbh; package EB::Relation; use strict; use warnings; use EB; sub new { my $class = shift; $class = ref($class) || $class; my $self = {}; bless $self => $class; $self->add(@_) if @_; $self; } sub add { my ($self, $code, $desc, $acct, $opts) = @_; my $bstate = $opts->{btw}; my $dbk = $opts->{dagboek}; if ( defined($bstate) ) { $bstate = lc($bstate); if ( $bstate =~ /^\d+$/ && $bstate >= 0 && $bstate < @{&BTWTYPES} ) { # Ok. } elsif ( $bstate eq lc(BTWTYPES->[BTWTYPE_NORMAAL]) ) { $bstate = BTWTYPE_NORMAAL } elsif ( $bstate eq lc(BTWTYPES->[BTWTYPE_VERLEGD]) ) { $bstate = BTWTYPE_VERLEGD } elsif ( $bstate eq lc(BTWTYPES->[BTWTYPE_INTRA] ) ) { $bstate = BTWTYPE_INTRA } elsif ( $bstate eq lc(BTWTYPES->[BTWTYPE_EXTRA] ) ) { $bstate = BTWTYPE_EXTRA } else { warn("?".__x("Ongeldige waarde voor BTW status: {btw}", btw => $bstate)."\n"); return; } if ( $bstate == BTWTYPE_VERLEGD ) { #### TODO warn("?"._T("Relaties met verlegde BTW worden nog niet ondersteund")."\n"); return; } } my $debiteur; my $ddesc; if ( $dbk ) { my $rr = $dbh->do("SELECT dbk_id, dbk_type, dbk_desc". " FROM Dagboeken". " WHERE dbk_desc ILIKE ?", $dbk); unless ( $rr ) { warn("?".__x("Onbekend dagboek: {dbk}", dbk => $dbk)."\n"); return; } my ($id, $type, $desc) = @$rr; if ( $type == DBKTYPE_INKOOP ) { $debiteur = 0; } elsif ( $type == DBKTYPE_VERKOOP ) { $debiteur = 1; } else { warn("?".__x("Ongeldig dagboek voor relatie: {dbk}", dbk => $dbk)."\n"); return; } $dbk = $id; $ddesc = $desc; } # There are virtually no restrictions on what can go in a relation # code. Relation codes that start with digits and a dash may lead # to parse errors. # Except for the schema SQL this is the only place where the length # constraint is explicit. if ( $code =~ /^\d+-/ || length($code) > 10 ) { warn("?".__x("Ongeldige relatiecode: {rel}", rel => $code)."\n"); return; } # Invoeren nieuwe relatie. # Koppeling debiteur/crediteur op basis van debcrd van de # bijbehorende grootboekrekening. # Koppeling met dagboek op basis van het laagstgenummerde # inkoop/verkoop dagboek (tenzij meegegeven). my $dbcd = "acc_debcrd"; if ( $acct =~ /^(\d+)([DC]$)/i) { warn("!"._T("Waarschuwing: De toevoeging 'D' of 'C' aan het grootboeknummer wordt afgeraden! Gebruik de --dagboek optie indien nodig.")."\n"); $acct = $1; $dbcd = uc($2) eq 'D' ? 0 : 1; # Note: D -> Crediteur if ( defined($debiteur) && $dbcd == $debiteur ) { warn("?".__x("Dagboek {dbk} implicieert {typ1} maar {acct} impliceert {typ2}", dbk => $ddesc, typ1 => lc($debiteur ? _T("Debiteur") : _T("Crediteur")), acct => $acct.$2, typ2 => lc($dbcd ? _T("Crediteur") : _T("Debiteur")))."\n"); return; } } my $rr = $dbh->do("SELECT acc_desc,acc_balres,$dbcd". " FROM Accounts". " WHERE acc_id = ?", $acct); unless ( $rr ) { warn("?".__x("Onbekende grootboekrekening: {acct}", acct => $acct). "\n"); return; } my ($adesc, $balres, $debcrd) = @$rr; if ( $balres ) { warn("!".__x("Grootboekrekening {acct} ({desc}) is een balansrekening", acct => $acct, desc => $adesc)."\n"); return; } $debcrd = defined($debiteur) ? $debiteur : 0+!!$debcrd; unless ( $dbk ) { my $sth = $dbh->sql_exec("SELECT dbk_id, dbk_desc". " FROM Dagboeken". " WHERE dbk_type = ?". " ORDER BY dbk_id", $debcrd ? DBKTYPE_VERKOOP : DBKTYPE_INKOOP); $rr = $sth->fetchrow_arrayref; $sth->finish; ($dbk, $ddesc) = @$rr; } $rr = $dbh->do("SELECT COUNT(*)". " FROM Relaties". " WHERE upper(rel_code) = ? AND rel_ledger = ?", uc($code), $dbk); if ( $rr->[0]) { warn("?".__x("Relatiecode {code} is niet uniek in dagboek {dbk}", code => uc($code), dbk => $ddesc)."\n"); return; } $dbh->begin_work; $dbh->sql_insert("Relaties", [qw(rel_code rel_desc rel_debcrd rel_btw_status rel_ledger rel_acc_id)], $code, $desc, $debcrd, $bstate || 0, $dbk, $acct); $dbh->commit; $debcrd ? __x("Debiteur {code} -> {acct} ({desc}), dagboek {dbk}", code => $code, acct => $acct, desc => $adesc, dbk => $ddesc) : __x("Crediteur {code} -> {acct} ({desc}), dagboek {dbk}", code => $code, acct => $acct, desc => $adesc, dbk => $ddesc); } 1; EekBoek-2.030.1/lib/EB/Wx/0000755000400000040000000000000013151742350012413 5ustar jvjvEekBoek-2.030.1/lib/EB/Wx/FakeApp.pm0000644000400000040000000000021612725476602014271 0ustar jvjv#! perl package main; our $app; # Note: a non-null $app is a signal for EB to load the GUI version of # the Locale module. $app = {}; 1; EekBoek-2.030.1/lib/EB/Wx/IniWiz/0000755000400000040000000000000013151742350013624 5ustar jvjvEekBoek-2.030.1/lib/EB/Wx/IniWiz/OpenDialog.pm0000644000400000040000000001243312725476602016220 0ustar jvjv#! perl package main; use strict; use utf8; package EB::Wx::IniWiz::OpenDialog; use base qw(Wx::Dialog); use strict; use EB qw(_T); use Wx qw[wxID_OK wxID_CANCEL wxID_NEW wxID_REMOVE wxID_ANY wxBITMAP_TYPE_ANY wxDefaultPosition wxDefaultSize wxDEFAULT_DIALOG_STYLE wxHORIZONTAL wxVERTICAL wxALIGN_CENTER_VERTICAL wxLEFT wxRIGHT wxALL wxTOP wxBOTTOM wxEXPAND wxLB_SINGLE ]; # Dummy as of Wx 2.8, but still generated by wxGlade. { no warnings 'redefine'; sub wxADJUST_MINSIZE() { 0 } } sub new { my( $self, $parent, $id, $title, $pos, $size, $style, $name ) = @_; $parent = undef unless defined $parent; $id = -1 unless defined $id; $title = "" unless defined $title; $pos = wxDefaultPosition unless defined $pos; $size = wxDefaultSize unless defined $size; $name = "" unless defined $name; # begin wxGlade: EB::Wx::IniWiz::OpenDialog::new $style = wxDEFAULT_DIALOG_STYLE unless defined $style; $self = $self->SUPER::new( $parent, $id, $title, $pos, $size, $style, $name ); $self->{sizer_6_staticbox} = Wx::StaticBox->new($self, wxID_ANY, _T("Beschikbare administraties") ); $self->{bm_logo} = Wx::StaticBitmap->new($self, wxID_ANY, Wx::Bitmap->new("ebwiz.jpg", wxBITMAP_TYPE_ANY), wxDefaultPosition, wxDefaultSize, ); $self->{lb_adm} = Wx::ListBox->new($self, wxID_ANY, wxDefaultPosition, wxDefaultSize, [], wxLB_SINGLE); $self->{static_line_1} = Wx::StaticLine->new($self, wxID_ANY, wxDefaultPosition, wxDefaultSize, ); $self->{b_new} = Wx::Button->new($self, wxID_NEW, ""); $self->{b_remove} = Wx::Button->new($self, wxID_REMOVE, ""); $self->{b_cancel} = Wx::Button->new($self, wxID_CANCEL, ""); $self->{b_accept} = Wx::Button->new($self, wxID_OK, ""); $self->__set_properties(); $self->__do_layout(); Wx::Event::EVT_LISTBOX_DCLICK($self, $self->{lb_adm}->GetId, \&OnSelectAndGo); Wx::Event::EVT_BUTTON($self, $self->{b_new}->GetId, \&OnNew); Wx::Event::EVT_BUTTON($self, $self->{b_remove}->GetId, \&OnRemove); Wx::Event::EVT_BUTTON($self, $self->{b_cancel}->GetId, \&OnCancel); Wx::Event::EVT_BUTTON($self, $self->{b_accept}->GetId, \&OnOpen); # end wxGlade $self->SetSize(0, 0, $self->GetSizeWH); $self->Center; return $self; } sub init { my ( $self, $dirs ) = @_; $self->{lb_adm}->Append($dirs); $self->{lb_adm}->SetSelection(0); $self->{lb_adm}->SetFocus; $self->{b_accept}->SetFocus if @$dirs == 1; $self->{b_new}->SetFocus if @$dirs == 0; } sub GetSelection { my ( $self ) = @_; $self->{lb_adm}->GetSelection; } sub __set_properties { my $self = shift; # begin wxGlade: EB::Wx::IniWiz::OpenDialog::__set_properties $self->SetTitle(_T("Administratiekeuze")); $self->SetSize(Wx::Size->new(776, 376)); $self->{lb_adm}->SetSelection(0); # end wxGlade } sub __do_layout { my $self = shift; # begin wxGlade: EB::Wx::IniWiz::OpenDialog::__do_layout $self->{sizer_1} = Wx::BoxSizer->new(wxHORIZONTAL); $self->{sizer_1a} = Wx::BoxSizer->new(wxVERTICAL); $self->{sizer_2} = Wx::BoxSizer->new(wxVERTICAL); $self->{sizer_3} = Wx::BoxSizer->new(wxHORIZONTAL); $self->{sizer_5} = Wx::BoxSizer->new(wxHORIZONTAL); $self->{sizer_6}= Wx::StaticBoxSizer->new($self->{sizer_6_staticbox}, wxVERTICAL); $self->{sizer_7} = Wx::BoxSizer->new(wxVERTICAL); $self->{sizer_7}->Add($self->{bm_logo}, 0, wxEXPAND|wxALIGN_CENTER_VERTICAL|wxADJUST_MINSIZE, 0); $self->{sizer_5}->Add($self->{sizer_7}, 0, wxRIGHT|wxEXPAND, 15); $self->{sizer_6}->Add($self->{lb_adm}, 1, wxALL|wxEXPAND|wxADJUST_MINSIZE, 2); $self->{sizer_5}->Add($self->{sizer_6}, 1, wxEXPAND, 0); $self->{sizer_2}->Add($self->{sizer_5}, 1, wxEXPAND, 0); $self->{sizer_2}->Add($self->{static_line_1}, 0, wxTOP|wxBOTTOM|wxEXPAND, 10); $self->{sizer_3}->Add(5, 5, 1, wxEXPAND|wxADJUST_MINSIZE, 0); $self->{sizer_3}->Add($self->{b_new}, 0, wxADJUST_MINSIZE, 0); $self->{sizer_3}->Add($self->{b_remove}, 0, wxLEFT|wxADJUST_MINSIZE, 5); $self->{sizer_3}->Add($self->{b_cancel}, 0, wxLEFT|wxRIGHT|wxADJUST_MINSIZE, 5); $self->{sizer_3}->Add($self->{b_accept}, 0, wxADJUST_MINSIZE, 0); $self->{sizer_2}->Add($self->{sizer_3}, 0, wxEXPAND, 0); $self->{sizer_1a}->Add($self->{sizer_2}, 1, wxEXPAND, 5); $self->{sizer_1}->Add($self->{sizer_1a}, 1, wxALL|wxEXPAND, 10); $self->SetSizer($self->{sizer_1}); $self->Layout(); # end wxGlade } sub OnNew { my ($self, $event) = @_; # wxGlade: EB::Wx::IniWiz::OpenDialog::OnNew $self->EndModal( wxID_NEW ); # end wxGlade } sub OnRemove { my ($self, $event) = @_; # wxGlade: EB::Wx::IniWiz::OpenDialog::OnRemove $self->EndModal( wxID_REMOVE ); # end wxGlade } sub OnCancel { my ($self, $event) = @_; # wxGlade: EB::Wx::IniWiz::OpenDialog::OnCancel $self->EndModal( wxID_CANCEL ); # end wxGlade } sub OnOpen { my ($self, $event) = @_; # wxGlade: EB::Wx::IniWiz::OpenDialog::OnOpen $self->EndModal( wxID_OK ); # end wxGlade } sub OnSelectAndGo { my ($self, $event) = @_; # wxGlade: EB::Wx::IniWiz::OpenDialog::OnSelectAndGo $self->EndModal( wxID_OK ); # end wxGlade } # end of class EB::Wx::IniWiz::OpenDialog 1; EekBoek-2.030.1/lib/EB/Wx/IniWiz.pm0000644000400000040000000011554713151741124014175 0ustar jvjv#! perl -- -*- coding: utf-8 -*- use utf8; package main; use strict; use warnings; use EekBoek; use EB; use EB::Tools::MiniAdm; use Archive::Zip qw( :ERROR_CODES :CONSTANTS ); our $app; our $cfg; our $bin; our @ebz; # ( [ "filename.ebz", "flags" ], [...], ... ) my @configs = ( qw( schema.dat mutaties.eb relaties.eb opening.eb ) ); package EB::Wx::IniWiz; use base qw(Wx::Frame); use EB; use File::Spec; use File::Basename; my @db_drivers; my @adm_dirs; my @adm_names; my $runeb; my $default = _T("--standaard--"); use Wx qw[ wxADJUST_MINSIZE wxALIGN_CENTER_VERTICAL wxALL wxBITMAP_TYPE_ANY wxBOTTOM wxCANCEL wxCONFIG_USE_LOCAL_FILE wxDEFAULT_FRAME_STYLE wxDefaultPosition wxDefaultSize wxEXPAND wxHORIZONTAL wxICON_ERROR wxICON_INFORMATION wxID_CANCEL wxID_NEW wxID_OK wxID_OPEN wxID_REMOVE wxLEFT wxNORMAL wxOK wxRA_SPECIFY_ROWS wxRIGHT wxSP_ARROW_KEYS wxTELETYPE wxTE_AUTO_URL wxTE_MULTILINE wxTE_PASSWORD wxTE_READONLY wxTOP wxVERTICAL ]; # Dummy as of Wx 2.8, but still generated by wxGlade. { no warnings 'redefine'; sub wxADJUST_MINSIZE() { 0 } } # The wizard panels. my $wp; for ( qw( select admname btw batch db confirm ) ) { $wp->{$_} = sprintf("wiz_p%02d", 0+keys(%$wp)); } sub new { my( $self, $parent, $id, $title, $pos, $size, $style, $name ) = @_; $parent = undef unless defined $parent; $id = -1 unless defined $id; $title = "" unless defined $title; $pos = wxDefaultPosition unless defined $pos; $size = wxDefaultSize unless defined $size; $name = "" unless defined $name; # begin wxGlade: EB::Wx::IniWiz::new $style = wxDEFAULT_FRAME_STYLE unless defined $style; $self = $self->SUPER::new( $parent, $id, $title, $pos, $size, $style, $name ); $self->{p_dummy} = Wx::Panel->new($self, -1, wxDefaultPosition, wxDefaultSize, ); $self->{wiz_p05} = Wx::WizardPanel->new($self->{p_dummy}, -1, wxDefaultPosition, wxDefaultSize, ); $self->{wiz_p04} = Wx::WizardPanel->new($self->{p_dummy}, -1, wxDefaultPosition, wxDefaultSize, ); $self->{wiz_p03} = Wx::WizardPanel->new($self->{p_dummy}, -1, wxDefaultPosition, wxDefaultSize, ); $self->{wiz_p02} = Wx::WizardPanel->new($self->{p_dummy}, -1, wxDefaultPosition, wxDefaultSize, ); $self->{wiz_p01} = Wx::WizardPanel->new($self->{p_dummy}, -1, wxDefaultPosition, wxDefaultSize, ); $self->{sizer_5_staticbox} = Wx::StaticBox->new($self->{wiz_p01}, -1, _T("Administratie") ); $self->{sizer_8_staticbox} = Wx::StaticBox->new($self->{wiz_p02}, -1, _T("BTW") ); $self->{sizer_6_staticbox} = Wx::StaticBox->new($self->{wiz_p03}, -1, _T("Dagboeken") ); $self->{sizer_4_staticbox} = Wx::StaticBox->new($self->{wiz_p04}, -1, _T("Database") ); $self->{sizer_2_staticbox} = Wx::StaticBox->new($self->{wiz_p05}, -1, _T("Bevestiging") ); $self->{wiz_p00} = Wx::WizardPanel->new($self->{p_dummy}, -1, wxDefaultPosition, wxDefaultSize, ); $self->{t_main} = Wx::TextCtrl->new($self->{p_dummy}, -1, "", wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE|wxTE_READONLY); $self->{ch_runeb} = Wx::CheckBox->new($self->{p_dummy}, -1, _T("EekBoek opstarten"), wxDefaultPosition, wxDefaultSize, ); $self->{b_details} = Wx::Button->new($self->{p_dummy}, -1, _T("Details...")); $self->{b_ok} = Wx::Button->new($self->{p_dummy}, wxID_OK, ""); $self->{label_2} = Wx::StaticText->new($self->{wiz_p00}, -1, _T("Welkom bij de EekBoek administratie-wizard."), wxDefaultPosition, wxDefaultSize, ); $self->{rb_select} = Wx::RadioBox->new($self->{wiz_p00}, -1, _T("Maak uw keuze"), wxDefaultPosition, wxDefaultSize, [_T("Een nieuwe administratie aanmaken"), _T("Verbinden met een bestaande administratie")], 0, wxRA_SPECIFY_ROWS); $self->{label_3} = Wx::StaticText->new($self->{wiz_p01}, -1, _T("Naam"), wxDefaultPosition, wxDefaultSize, ); $self->{t_adm_name} = Wx::TextCtrl->new($self->{wiz_p01}, -1, _T("Mijn eerste EekBoek"), wxDefaultPosition, wxDefaultSize, ); $self->{label_10} = Wx::StaticText->new($self->{wiz_p01}, -1, _T("Code"), wxDefaultPosition, wxDefaultSize, ); $self->{t_adm_code} = Wx::TextCtrl->new($self->{wiz_p01}, -1, "", wxDefaultPosition, wxDefaultSize, ); $self->{l_begin_date_1} = Wx::StaticText->new($self->{wiz_p01}, -1, _T("Begindatum"), wxDefaultPosition, wxDefaultSize, ); $self->{l_begin_date_2} = Wx::StaticText->new($self->{wiz_p01}, -1, _T("01-01-"), wxDefaultPosition, wxDefaultSize, ); $self->{sp_adm_begin} = Wx::SpinCtrl->new($self->{wiz_p01}, -1, "", wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS|wxTE_AUTO_URL, 0, 100, ); $self->{l_template} = Wx::StaticText->new($self->{wiz_p01}, -1, _T("Sjabloon"), wxDefaultPosition, wxDefaultSize, ); $self->{ch_template} = Wx::Choice->new($self->{wiz_p01}, -1, wxDefaultPosition, wxDefaultSize, [_T("Lege administratie")], ); $self->{cb_btw} = Wx::CheckBox->new($self->{wiz_p02}, -1, _T("BTW toepassen op deze administratie"), wxDefaultPosition, wxDefaultSize, ); $self->{l_btw_period} = Wx::StaticText->new($self->{wiz_p02}, -1, _T("Aangifteperiode"), wxDefaultPosition, wxDefaultSize, ); $self->{ch_btw_period} = Wx::Choice->new($self->{wiz_p02}, -1, wxDefaultPosition, wxDefaultSize, [_T("Maand"), _T("Kwartaal"), _T("Jaar")], ); $self->{cb_debiteuren} = Wx::CheckBox->new($self->{wiz_p03}, -1, _T("Verkoop"), wxDefaultPosition, wxDefaultSize, ); $self->{cb_crediteuren} = Wx::CheckBox->new($self->{wiz_p03}, -1, _T("Inkoop"), wxDefaultPosition, wxDefaultSize, ); $self->{cb_kas} = Wx::CheckBox->new($self->{wiz_p03}, -1, _T("Kas"), wxDefaultPosition, wxDefaultSize, ); $self->{cb_bank} = Wx::CheckBox->new($self->{wiz_p03}, -1, _T("Bank"), wxDefaultPosition, wxDefaultSize, ); $self->{label_1} = Wx::StaticText->new($self->{wiz_p04}, -1, _T("Database naam"), wxDefaultPosition, wxDefaultSize, ); $self->{t_db_name} = Wx::TextCtrl->new($self->{wiz_p04}, -1, "", wxDefaultPosition, wxDefaultSize, ); $self->{label_db_type} = Wx::StaticText->new($self->{wiz_p04}, -1, _T("Database type"), wxDefaultPosition, wxDefaultSize, ); $self->{ch_db_driver} = Wx::Choice->new($self->{wiz_p04}, -1, wxDefaultPosition, wxDefaultSize, [_T("PostgreSQL"), _T("SQLite")], ); $self->{label_db_host} = Wx::StaticText->new($self->{wiz_p04}, -1, _T("Server host"), wxDefaultPosition, wxDefaultSize, ); $self->{t_db_host} = Wx::TextCtrl->new($self->{wiz_p04}, -1, "", wxDefaultPosition, wxDefaultSize, ); $self->{label_db_port} = Wx::StaticText->new($self->{wiz_p04}, -1, _T("Server port"), wxDefaultPosition, wxDefaultSize, ); $self->{t_db_port} = Wx::TextCtrl->new($self->{wiz_p04}, -1, "", wxDefaultPosition, wxDefaultSize, ); $self->{label_db_user} = Wx::StaticText->new($self->{wiz_p04}, -1, _T("Database user"), wxDefaultPosition, wxDefaultSize, ); $self->{t_db_user} = Wx::TextCtrl->new($self->{wiz_p04}, -1, "", wxDefaultPosition, wxDefaultSize, ); $self->{label_db_password} = Wx::StaticText->new($self->{wiz_p04}, -1, _T("Password"), wxDefaultPosition, wxDefaultSize, ); $self->{t_db_password} = Wx::TextCtrl->new($self->{wiz_p04}, -1, "", wxDefaultPosition, wxDefaultSize, wxTE_PASSWORD); $self->{b_db_test} = Wx::Button->new($self->{wiz_p04}, -1, _T("Test database")); $self->{label_5} = Wx::StaticText->new($self->{wiz_p05}, -1, _T("Druk op 'Voltooien' om de volgende bestanden aan te maken:"), wxDefaultPosition, wxDefaultSize, ); $self->{cb_cr_config} = Wx::CheckBox->new($self->{wiz_p05}, -1, _T("Configuratiebestand"), wxDefaultPosition, wxDefaultSize, ); $self->{cb_cr_schema} = Wx::CheckBox->new($self->{wiz_p05}, -1, _T("Rekeningschema"), wxDefaultPosition, wxDefaultSize, ); $self->{cb_cr_relaties} = Wx::CheckBox->new($self->{wiz_p05}, -1, _T("Relaties (debiteuren en crediteuren)"), wxDefaultPosition, wxDefaultSize, ); $self->{cb_cr_opening} = Wx::CheckBox->new($self->{wiz_p05}, -1, _T("Openingsgegevens"), wxDefaultPosition, wxDefaultSize, ); $self->{cb_cr_mutaties} = Wx::CheckBox->new($self->{wiz_p05}, -1, _T("Mutaties (boekingen)"), wxDefaultPosition, wxDefaultSize, ); $self->{cb_cr_database} = Wx::CheckBox->new($self->{wiz_p05}, -1, _T("Database"), wxDefaultPosition, wxDefaultSize, ); $self->{label_8} = Wx::StaticText->new($self->{wiz_p05}, -1, _T("Let op! Eventuele bestaande bestanden worden overschreven!"), wxDefaultPosition, wxDefaultSize, ); $self->__set_properties(); $self->__do_layout(); Wx::Event::EVT_BUTTON($self, $self->{b_details}->GetId, \&OnDetails); Wx::Event::EVT_BUTTON($self, $self->{b_ok}->GetId, \&OnOk); # end wxGlade # Set defaults for code and db name. OnSelectAdmName( $self->{wiz} ); my $prev; for ( my $i = 0; ; $i++ ) { my $page = sprintf("wiz_p%02d", $i); last unless exists $self->{$page}; $self->{sz_main}->Detach($self->{$page}); Wx::WizardPageSimple::Chain( $self->{$prev}, $self->{$page} ) if $prev; $prev = $page; } my $dir = dirname( findlib( "templates.txt", "templates" ) ); @ebz = map { [ $_, "" ] } glob( "$dir/*.ebz" ); my $i = 0; my $dp = quotemeta( _T("Omschrijving").": " ); foreach my $ebz ( @ebz ) { require Archive::Zip; my $zip = Archive::Zip->new(); next unless $zip->read($ebz->[0]) == ::AZ_OK; my $desc = $zip->zipfileComment; if ( $desc =~ /flags:\s*(.*)/i ) { $ebz->[1] = $1; } if ( $desc =~ /^$dp\s*(.*)$/m ) { $desc = $1; } elsif ( $desc =~ /export van (.*) aangemaakt door eekboek/i ) { $desc = $1; } else { $desc = $1 if $ebz->[0] =~ m/([^\\\/]+)\.ebz$/i; } $desc =~ s/[\n\r]+$//; # can't happen? think again... $self->{ch_template}->Append($desc); $i++; if ( $ebz->[0] =~ /\/sample(db)?\.ebz$/ ) { $self->{ch_template}->SetSelection($i); OnSelectTemplate( $self->{wiz} ); } } unshift (@ebz, undef ); # skeleton # Enumerate DB drivers. my $drivers = find_db_drivers(); $self->{ch_db_driver}->Delete(0) while $self->{ch_db_driver}->GetCount; foreach ( sort keys %$drivers ) { push( @db_drivers, $_ ); $self->{ch_db_driver}->Append( $drivers->{$_} ); $self->{ch_db_driver}->SetSelection(@db_drivers-1) if $_ eq "sqlite"; } #### WARNING: Hard-wired reference to wiz_p04. # $self->{dc_dbpath} = Wx::DirPickerCtrl->new($self->{wiz_p04}, -1, "", _T("Kies een folder"), wxDefaultPosition, wxDefaultSize, 2 ); # $self->{grid_db}->Replace( $self->{l_placeholder_dbpath}, $self->{dc_dbpath}, 1 ); # $self->{l_placeholder_dbpath}->Destroy; # $self->{dc_dbpath}->SetToolTipString(_T("Folder waar databases worden opgeslagen (niet voor alle database typen)")); # $self->{dc_dbpath}->SetPath(_T("-- Huidige directory --")); Wx::Event::EVT_WIZARD_PAGE_CHANGING($self, $self->{wiz}->GetId, \&OnPageChanging); Wx::Event::EVT_WIZARD_FINISHED($self, $self->{wiz}->GetId, \&OnWizardFinished ); Wx::Event::EVT_WIZARD_CANCEL($self, $self->{wiz}->GetId, \&OnWizardCancel ); Wx::Event::EVT_RADIOBOX($self->{wiz}, $self->{rb_select}->GetId, \&OnSelectFunction ); Wx::Event::EVT_CHECKBOX($self->{wiz}, $self->{cb_btw}->GetId, \&OnToggleBTW ); Wx::Event::EVT_CHECKBOX($self->{wiz}, $self->{cb_cr_schema}->GetId, \&OnToggleCreate ); Wx::Event::EVT_CHECKBOX($self->{wiz}, $self->{cb_cr_opening}->GetId, \&OnToggleCreate ); Wx::Event::EVT_CHECKBOX($self->{wiz}, $self->{cb_cr_relaties}->GetId, \&OnToggleCreate ); Wx::Event::EVT_CHECKBOX($self->{wiz}, $self->{cb_cr_mutaties}->GetId, \&OnToggleCreate ); Wx::Event::EVT_CHOICE($self->{wiz}, $self->{ch_template}->GetId, \&OnSelectTemplate ); Wx::Event::EVT_TEXT($self->{wiz}, $self->{t_adm_name}->GetId, \&OnSelectAdmName ); Wx::Event::EVT_TEXT($self->{wiz}, $self->{t_adm_code}->GetId, \&OnSelectAdmCode ); Wx::Event::EVT_SPINCTRL($self->{wiz}, $self->{sp_adm_begin}->GetId, \&OnSelectAdmName ); Wx::Event::EVT_CHOICE($self->{wiz}, $self->{ch_db_driver}->GetId, \&OnSelectDbDriver ); Wx::Event::EVT_BUTTON($self->{wiz}, $self->{b_db_test}->GetId, \&OnDbTest); $self->{wiz}->SetPageSize([600,-1]); my $icon = Wx::Icon->new(); $icon->CopyFromBitmap(Wx::Bitmap->new("eb.jpg", wxBITMAP_TYPE_ANY)); $self->SetIcon($icon); $self->{wiz}->SetIcon($icon); $self->SetSize([450,300]); $self->Center; return $self; } sub runwiz { my ( $self, $opts ) = @_; $self->{wiz}->RunWizard( $self->{$wp->{select}} ); $self->{wiz}->Destroy; } sub getadm { # STATIC my ( $pkg, $opts ) = @_; chdir($opts->{admdir}); my %h; $h{$_} = 1 foreach glob( "*/" . $cfg->std_config ); $h{$_} = 1 foreach glob( "*/" . $cfg->std_config_alt ); my @files = keys(%h); @adm_names = (); @adm_dirs = (); foreach ( sort @files ) { push( @adm_dirs, dirname($_) ); my $desc = $adm_dirs[-1]; if ( open( my $fd, '<:utf8', $adm_dirs[-1]."/opening.eb" ) ) { while ( <$fd> ) { next unless /adm_naam\s+"(.+)"/; $desc = $1; last; } close($fd); } push( @adm_names, $desc); } my $ret = wxID_NEW; if ( @adm_dirs ) { require EB::Wx::IniWiz::OpenDialog; my $d = EB::Wx::IniWiz::OpenDialog->new( undef, -1, _T("Kies"), wxDefaultPosition, wxDefaultSize, ); $d->init( \@adm_names ); $ret = $d->ShowModal; if ( $ret == wxID_OK ) { chdir( $adm_dirs[ $d->GetSelection ] ) || die("chdir"); } elsif ( $ret == wxID_REMOVE ) { my $sel = $d->GetSelection; $d->Destroy; $d = Wx::MessageDialog->new( undef, $adm_names[$sel] . "\n\n" . _T("Administratie verwijderen?"), _T("Verwijderen administratie"), wxOK|wxCANCEL, wxDefaultPosition ); my $ret = $d->ShowModal; $d->Destroy; if ( $ret == wxID_OK ) { use File::Path qw(remove_tree); remove_tree( $adm_dirs[$sel], { verbose => 1 } ); } # Try again. return getadm( $pkg, $opts ); } $d->Destroy; } return $ret; } sub __set_properties { my $self = shift; my $year = 1900 + (localtime(time))[5]; $self->{sp_adm_begin}->SetRange( $year-100, $year+100 ); $self->{sp_adm_begin}->SetValue( $year ); # begin wxGlade: EB::Wx::IniWiz::__set_properties $self->SetTitle(_T("EekBoek MiniAdm Setup")); $self->{t_main}->SetFont(Wx::Font->new(10, wxTELETYPE, wxNORMAL, wxNORMAL, 0, "")); $self->{ch_runeb}->SetValue(1); $self->{b_details}->Show(0); $self->{b_ok}->Enable(0); $self->{rb_select}->SetSelection(0); $self->{wiz_p00}->Show(0); $self->{t_adm_name}->SetToolTipString(_T("Een omschrijving van deze administratie, bijvoorbeeld \"Boekhouding 2009\".")); $self->{t_adm_code}->SetToolTipString(_T("Een korte, unieke aanduiding van deze administratie, bijvoorbeeld \"admin2009\".")); $self->{sp_adm_begin}->SetToolTipString(_T("De begindatum. Het boekjaar begint op 1 januari van dit jaar.")); $self->{ch_template}->SetSelection(0); $self->{wiz_p01}->Show(0); $self->{cb_btw}->SetToolTipString(_T("BTW toepassen")); $self->{cb_btw}->SetValue(1); $self->{ch_btw_period}->SetToolTipString(_T("De aangifteperiode voor de omzetbelasting")); $self->{ch_btw_period}->SetSelection(1); $self->{wiz_p02}->Show(0); $self->{cb_debiteuren}->SetToolTipString(_T("Verkoop- en Debiteurenadministratie")); $self->{cb_debiteuren}->SetValue(1); $self->{cb_crediteuren}->SetToolTipString(_T("Inkoop- en Crediteurenadministratie")); $self->{cb_crediteuren}->SetValue(1); $self->{cb_kas}->SetToolTipString(_T("Kas (contant geld)")); $self->{cb_kas}->SetValue(1); $self->{cb_bank}->SetToolTipString(_T("Er wordt gebruik gemaakt van een bankrekening")); $self->{cb_bank}->SetValue(1); $self->{wiz_p03}->Show(0); $self->{t_db_name}->SetToolTipString(_T("De naam van de aan te maken database, b.v. \"admin2009\".")); $self->{ch_db_driver}->SetToolTipString(_T("Het databasesysteem waar de database wordt opgeslagen")); $self->{ch_db_driver}->SetSelection(1); $self->{label_db_host}->Enable(0); $self->{t_db_host}->SetToolTipString(_T("Het systeem waarop de database server draait, indien niet lokaal.")); $self->{t_db_host}->Enable(0); $self->{label_db_port}->Enable(0); $self->{t_db_port}->SetToolTipString(_T("De netwerkpoort waarop de database server luistert, indien niet lokaal.")); $self->{t_db_port}->Enable(0); $self->{label_db_user}->Enable(0); $self->{t_db_user}->SetToolTipString(_T("De user naam voor de database server.")); $self->{t_db_user}->Enable(0); $self->{label_db_password}->Enable(0); $self->{t_db_password}->SetToolTipString(_T("Het password van deze user.")); $self->{t_db_password}->Enable(0); $self->{wiz_p04}->Show(0); $self->{cb_cr_config}->SetValue(1); $self->{cb_cr_schema}->SetToolTipString(_T("Rekeningschema, dagboeken, BTW instellingen")); $self->{cb_cr_schema}->SetValue(1); $self->{cb_cr_relaties}->SetToolTipString(_T("Debiteuren en Crediteuren")); $self->{cb_cr_relaties}->SetValue(1); $self->{cb_cr_opening}->SetToolTipString(_T("Administratieve gegevens")); $self->{cb_cr_opening}->SetValue(1); $self->{cb_cr_mutaties}->SetToolTipString(_T("Mutaties (boekingen)")); $self->{cb_cr_mutaties}->SetValue(1); $self->{cb_cr_database}->SetToolTipString(_T("De database wordt aangemaakt en gevuld")); $self->{cb_cr_database}->SetValue(1); $self->{wiz_p05}->Show(0); # end wxGlade $self->{cb_cr_schema }->SetValue( ! -f "schema.dat" ); $self->{cb_cr_opening }->SetValue( ! -f "opening.eb" ); $self->{cb_cr_mutaties}->SetValue( ! -f "mutaties.eb" ); $self->{cb_cr_relaties}->SetValue( ! -f "relaties.eb" ); $self->{cb_cr_config }->SetValue( ! ( -f $cfg->std_config || -f $cfg->std_config_alt ) ); $self->{t_db_name}->SetValue(sprintf("adm%04d", 1900+(localtime(time))[5])); $self->{t_db_host}->SetValue( $ENV{EB_DB_HOST} || $default ); $self->{t_db_port}->SetValue( $ENV{EB_DB_PORT} || $default ); $self->{t_db_user}->SetValue( $ENV{EB_DB_USER} || $default ); $self->{t_db_password}->SetValue( $ENV{EB_DB_PASSWORD} || "" ); } sub __do_layout { my $self = shift; # begin wxGlade: EB::Wx::IniWiz::__do_layout $self->{sz_dummy} = Wx::BoxSizer->new(wxHORIZONTAL); $self->{sz_main} = Wx::BoxSizer->new(wxVERTICAL); $self->{sizer_1} = Wx::BoxSizer->new(wxHORIZONTAL); $self->{sizer_2}= Wx::StaticBoxSizer->new($self->{sizer_2_staticbox}, wxVERTICAL); $self->{grid_sizer_5} = Wx::FlexGridSizer->new(6, 1, 5, 5); $self->{sizer_16} = Wx::BoxSizer->new(wxHORIZONTAL); $self->{sizer_4}= Wx::StaticBoxSizer->new($self->{sizer_4_staticbox}, wxVERTICAL); $self->{grid_db} = Wx::FlexGridSizer->new(7, 2, 5, 5); $self->{sizer_15} = Wx::BoxSizer->new(wxHORIZONTAL); $self->{sizer_6}= Wx::StaticBoxSizer->new($self->{sizer_6_staticbox}, wxHORIZONTAL); $self->{grid_sizer_3} = Wx::FlexGridSizer->new(4, 1, 5, 5); $self->{sizer_14} = Wx::BoxSizer->new(wxHORIZONTAL); $self->{sizer_8}= Wx::StaticBoxSizer->new($self->{sizer_8_staticbox}, wxHORIZONTAL); $self->{grid_sizer_4} = Wx::FlexGridSizer->new(2, 1, 5, 5); $self->{sizer_7} = Wx::BoxSizer->new(wxHORIZONTAL); $self->{sizer_13} = Wx::BoxSizer->new(wxHORIZONTAL); $self->{sizer_5}= Wx::StaticBoxSizer->new($self->{sizer_5_staticbox}, wxHORIZONTAL); $self->{grid_sizer_2} = Wx::FlexGridSizer->new(4, 2, 5, 5); $self->{sizer_3} = Wx::BoxSizer->new(wxHORIZONTAL); $self->{sizer_11} = Wx::BoxSizer->new(wxHORIZONTAL); $self->{sizer_17} = Wx::BoxSizer->new(wxVERTICAL); $self->{sizer_9} = Wx::BoxSizer->new(wxVERTICAL); $self->{sz_buttons} = Wx::BoxSizer->new(wxHORIZONTAL); $self->{sizer_9}->Add($self->{t_main}, 1, wxBOTTOM|wxEXPAND|wxADJUST_MINSIZE, 10); $self->{sizer_9}->Add($self->{ch_runeb}, 0, wxBOTTOM|wxADJUST_MINSIZE, 10); $self->{sz_buttons}->Add(1, 1, 1, wxEXPAND|wxADJUST_MINSIZE, 0); $self->{sz_buttons}->Add($self->{b_details}, 0, wxLEFT|wxRIGHT|wxADJUST_MINSIZE, 5); $self->{sz_buttons}->Add($self->{b_ok}, 0, wxADJUST_MINSIZE, 0); $self->{sizer_9}->Add($self->{sz_buttons}, 0, wxEXPAND, 0); $self->{sz_main}->Add($self->{sizer_9}, 1, wxALL|wxEXPAND, 10); $self->{sizer_17}->Add($self->{label_2}, 1, wxEXPAND|wxADJUST_MINSIZE, 0); $self->{sizer_17}->Add($self->{rb_select}, 1, wxEXPAND|wxADJUST_MINSIZE, 10); $self->{sizer_11}->Add($self->{sizer_17}, 1, wxEXPAND, 0); $self->{wiz_p00}->SetSizer($self->{sizer_11}); $self->{sz_main}->Add($self->{wiz_p00}, 0, wxEXPAND, 0); $self->{grid_sizer_2}->Add($self->{label_3}, 0, wxALIGN_CENTER_VERTICAL|wxADJUST_MINSIZE, 0); $self->{grid_sizer_2}->Add($self->{t_adm_name}, 0, wxEXPAND|wxADJUST_MINSIZE, 0); $self->{grid_sizer_2}->Add($self->{label_10}, 0, wxALIGN_CENTER_VERTICAL|wxADJUST_MINSIZE, 0); $self->{grid_sizer_2}->Add($self->{t_adm_code}, 0, wxEXPAND|wxADJUST_MINSIZE, 0); $self->{grid_sizer_2}->Add($self->{l_begin_date_1}, 0, wxALIGN_CENTER_VERTICAL|wxADJUST_MINSIZE, 0); $self->{sizer_3}->Add($self->{l_begin_date_2}, 0, wxALIGN_CENTER_VERTICAL|wxADJUST_MINSIZE, 0); $self->{sizer_3}->Add($self->{sp_adm_begin}, 0, wxADJUST_MINSIZE, 0); $self->{grid_sizer_2}->Add($self->{sizer_3}, 1, wxEXPAND, 0); $self->{grid_sizer_2}->Add($self->{l_template}, 0, wxALIGN_CENTER_VERTICAL|wxADJUST_MINSIZE, 0); $self->{grid_sizer_2}->Add($self->{ch_template}, 0, wxEXPAND|wxADJUST_MINSIZE, 0); $self->{grid_sizer_2}->AddGrowableCol(1); $self->{sizer_5}->Add($self->{grid_sizer_2}, 1, wxALL|wxEXPAND, 5); $self->{sizer_13}->Add($self->{sizer_5}, 1, wxEXPAND, 0); $self->{wiz_p01}->SetSizer($self->{sizer_13}); $self->{sz_main}->Add($self->{wiz_p01}, 0, wxEXPAND, 0); $self->{grid_sizer_4}->Add($self->{cb_btw}, 0, wxADJUST_MINSIZE, 0); $self->{sizer_7}->Add($self->{l_btw_period}, 0, wxALIGN_CENTER_VERTICAL|wxADJUST_MINSIZE, 0); $self->{sizer_7}->Add($self->{ch_btw_period}, 0, wxLEFT|wxEXPAND|wxADJUST_MINSIZE, 5); $self->{grid_sizer_4}->Add($self->{sizer_7}, 1, wxEXPAND, 0); $self->{grid_sizer_4}->AddGrowableCol(0); $self->{sizer_8}->Add($self->{grid_sizer_4}, 1, wxALL|wxEXPAND, 5); $self->{sizer_14}->Add($self->{sizer_8}, 1, wxEXPAND, 0); $self->{wiz_p02}->SetSizer($self->{sizer_14}); $self->{sz_main}->Add($self->{wiz_p02}, 0, wxEXPAND, 0); $self->{grid_sizer_3}->Add($self->{cb_debiteuren}, 0, wxALIGN_CENTER_VERTICAL|wxADJUST_MINSIZE, 0); $self->{grid_sizer_3}->Add($self->{cb_crediteuren}, 0, wxALIGN_CENTER_VERTICAL|wxADJUST_MINSIZE, 0); $self->{grid_sizer_3}->Add($self->{cb_kas}, 0, wxADJUST_MINSIZE, 0); $self->{grid_sizer_3}->Add($self->{cb_bank}, 0, wxADJUST_MINSIZE, 0); $self->{sizer_6}->Add($self->{grid_sizer_3}, 1, wxALL|wxEXPAND, 5); $self->{sizer_15}->Add($self->{sizer_6}, 1, wxEXPAND, 0); $self->{wiz_p03}->SetSizer($self->{sizer_15}); $self->{sz_main}->Add($self->{wiz_p03}, 0, wxEXPAND, 0); $self->{grid_db}->Add($self->{label_1}, 0, wxALIGN_CENTER_VERTICAL|wxADJUST_MINSIZE, 0); $self->{grid_db}->Add($self->{t_db_name}, 0, wxEXPAND|wxADJUST_MINSIZE, 0); $self->{grid_db}->Add($self->{label_db_type}, 0, wxALIGN_CENTER_VERTICAL|wxADJUST_MINSIZE, 0); $self->{grid_db}->Add($self->{ch_db_driver}, 0, wxEXPAND|wxADJUST_MINSIZE, 0); $self->{grid_db}->Add($self->{label_db_host}, 0, wxALIGN_CENTER_VERTICAL|wxADJUST_MINSIZE, 0); $self->{grid_db}->Add($self->{t_db_host}, 0, wxEXPAND|wxADJUST_MINSIZE, 0); $self->{grid_db}->Add($self->{label_db_port}, 0, wxALIGN_CENTER_VERTICAL|wxADJUST_MINSIZE, 0); $self->{grid_db}->Add($self->{t_db_port}, 0, wxEXPAND|wxADJUST_MINSIZE, 0); $self->{grid_db}->Add($self->{label_db_user}, 0, wxALIGN_CENTER_VERTICAL|wxADJUST_MINSIZE, 0); $self->{grid_db}->Add($self->{t_db_user}, 0, wxEXPAND|wxADJUST_MINSIZE, 0); $self->{grid_db}->Add($self->{label_db_password}, 0, wxALIGN_CENTER_VERTICAL|wxADJUST_MINSIZE, 0); $self->{grid_db}->Add($self->{t_db_password}, 0, wxEXPAND|wxADJUST_MINSIZE, 0); $self->{grid_db}->Add(0, 0, 0, wxEXPAND|wxADJUST_MINSIZE, 0); $self->{grid_db}->Add($self->{b_db_test}, 0, wxADJUST_MINSIZE, 0); $self->{grid_db}->AddGrowableCol(1); $self->{sizer_4}->Add($self->{grid_db}, 1, wxALL|wxEXPAND, 5); $self->{sizer_16}->Add($self->{sizer_4}, 1, wxEXPAND, 0); $self->{wiz_p04}->SetSizer($self->{sizer_16}); $self->{sz_main}->Add($self->{wiz_p04}, 0, wxEXPAND, 0); $self->{sizer_2}->Add($self->{label_5}, 0, wxLEFT|wxRIGHT|wxTOP|wxADJUST_MINSIZE, 5); $self->{grid_sizer_5}->Add($self->{cb_cr_config}, 0, wxADJUST_MINSIZE, 0); $self->{grid_sizer_5}->Add($self->{cb_cr_schema}, 0, wxADJUST_MINSIZE, 0); $self->{grid_sizer_5}->Add($self->{cb_cr_relaties}, 0, wxADJUST_MINSIZE, 0); $self->{grid_sizer_5}->Add($self->{cb_cr_opening}, 0, wxADJUST_MINSIZE, 0); $self->{grid_sizer_5}->Add($self->{cb_cr_mutaties}, 0, wxADJUST_MINSIZE, 0); $self->{grid_sizer_5}->Add($self->{cb_cr_database}, 0, wxADJUST_MINSIZE, 0); $self->{sizer_2}->Add($self->{grid_sizer_5}, 1, wxALL|wxEXPAND, 5); $self->{sizer_2}->Add($self->{label_8}, 0, wxALL|wxADJUST_MINSIZE, 5); $self->{sizer_1}->Add($self->{sizer_2}, 1, wxEXPAND, 5); $self->{wiz_p05}->SetSizer($self->{sizer_1}); $self->{sz_main}->Add($self->{wiz_p05}, 0, wxEXPAND, 0); $self->{p_dummy}->SetSizer($self->{sz_main}); $self->{sz_dummy}->Add($self->{p_dummy}, 1, wxEXPAND, 0); $self->SetSizer($self->{sz_dummy}); $self->{sz_dummy}->Fit($self); $self->Layout(); # end wxGlade } sub OnSelectFunction { my ( $self, $event ) = @_; $self = $self->GetParent; my @hideshow = qw( l_begin_date_1 l_begin_date_2 sp_adm_begin l_template ch_template ); my @hideshow0 = qw( schema relaties mutaties database ); my @hideshow1 = qw( config opening ); if ( $self->{rb_select}->GetSelection == 0 ) { Wx::WizardPageSimple::Chain( $self->{$wp->{select}}, $self->{$wp->{admname}} ); Wx::WizardPageSimple::Chain( $self->{$wp->{admname}}, $self->{$wp->{btw}} ); Wx::WizardPageSimple::Chain( $self->{$wp->{btw}}, $self->{$wp->{batch}} ); Wx::WizardPageSimple::Chain( $self->{$wp->{batch}}, $self->{$wp->{db}} ); Wx::WizardPageSimple::Chain( $self->{$wp->{db}}, $self->{$wp->{confirm}} ); foreach ( @hideshow0, @hideshow1 ) { $self->{"cb_cr_$_"}->SetValue(1); $self->{"cb_cr_$_"}->Enable(1); $self->{"cb_cr_$_"}->Show(1); } foreach ( @hideshow ) { $self->{$_}->Show(1); } $self->Layout; OnSelectTemplate( $self->{wiz} ); } else { Wx::WizardPageSimple::Chain( $self->{$wp->{select}}, $self->{$wp->{admname}} ); Wx::WizardPageSimple::Chain( $self->{$wp->{admname}}, $self->{$wp->{db}} ); Wx::WizardPageSimple::Chain( $self->{$wp->{db}}, $self->{$wp->{confirm}} ); for ( my $i = 0; $i < @db_drivers; $i++ ) { next unless $db_drivers[$i] eq "postgres"; $self->{ch_db_driver}->SetSelection($i); OnSelectDbDriver( $self->{wiz} ); last; } foreach ( @hideshow1 ) { $self->{"cb_cr_$_"}->SetValue(1); $self->{"cb_cr_$_"}->Enable(0); } foreach ( @hideshow0 ) { $self->{"cb_cr_$_"}->SetValue(0); $self->{"cb_cr_$_"}->Show(0); } foreach ( @hideshow ) { $self->{$_}->Show(0); } $self->Layout; } } sub OnPageChanging { my ($self, $event) = @_; return unless $event->GetDirection; my $page = $event->GetPage; if ( $page->GetId == $self->{$wp->{admname}}->GetId ) { my $nu = sub { my $m = Wx::MessageDialog->new($self->{wiz}, shift, _T("Niet uniek"), wxICON_ERROR|wxOK ); my $ret = $m->ShowModal; $m->Destroy; return $ret; }; my $c = $self->{t_adm_name}->GetValue; foreach ( @adm_names ) { next unless lc($_) eq lc($c); $nu->( _T("Er bestaat al een administratie met deze naam.") ); $event->Veto; # The code will probable also be duplicate. # Prevent double warning. return; } $c = $self->{t_adm_code}->GetValue; foreach ( @adm_dirs ) { next unless lc($_) eq lc($c); $nu->( _T("Er bestaat al een administratie met deze code.") ); $event->Veto; last; } } if ( $page->GetId == $self->{$wp->{db}}->GetId ) { return unless $self->{rb_select}->GetSelection; my $res = $self->_dbtest; if ( $res ) { my $m = Wx::MessageDialog->new($self->{wiz}, $res, _T("Database Test Resultaat"), wxICON_INFORMATION | wxOK ); $m->ShowModal; $m->Destroy; $event->Veto; } } } sub OnToggleBTW { my ($self, $event) = @_; # wxGlade: EB::Wx::IniWiz::OnToggleBTW $self = $self->GetParent; my $x = $self->{cb_btw}->IsChecked ? 1 : 0; $self->{ch_btw_period}->Enable($x); $self->{l_btw_period}->Enable($x); # end wxGlade } sub OnSelectTemplate { my ($self, $event) = @_; # wxGlade: EB::Wx::IniWiz::OnSelectTemplate $self = $self->GetParent; my $x = $self->{ch_template}->GetSelection; if ( $x ) { if ( $ebz[$x]->[1] =~ /\B-btw\b/i ) { $self->{cb_btw}->SetValue(0); $self->{cb_btw}->Enable(0); $self->{ch_btw_period}->Enable(0); $self->{l_btw_period}->Enable(0); Wx::WizardPageSimple::Chain( $self->{$wp->{admname}}, $self->{$wp->{db}} ); } else { $self->{cb_btw}->SetValue(1); $self->{cb_btw}->Enable(0); $self->{ch_btw_period}->Enable(1); $self->{l_btw_period}->Enable(1); Wx::WizardPageSimple::Chain( $self->{$wp->{admname}}, $self->{$wp->{btw}} ); Wx::WizardPageSimple::Chain( $self->{$wp->{btw}}, $self->{$wp->{db}} ); } } else { $self->{cb_btw}->Enable(1); Wx::WizardPageSimple::Chain( $self->{$wp->{admname}}, $self->{$wp->{btw}} ); Wx::WizardPageSimple::Chain( $self->{$wp->{btw}}, $self->{$wp->{batch}} ); } # end wxGlade } sub OnSelectAdmName { my ($self, $event) = @_; # wxGlade: EB::Wx::IniWiz::OnSelectAdmName $self = $self->GetParent; my $x = lc $self->{t_adm_name}->GetValue; $x =~ s/\s+/_/g; $x =~ s/\W//g; $x .= "_" . $self->{sp_adm_begin}->GetValue; $self->{t_adm_code}->SetValue($x); $self->{t_db_name}->SetValue($x); # end wxGlade } sub OnSelectAdmCode { my ($self, $event) = @_; # wxGlade: EB::Wx::IniWiz::OnSelectAdmCode $self = $self->GetParent; my $x = lc $self->{t_adm_code}->GetValue; $x =~ s/\s+/_/g; $x =~ s/\W//g; # $x .= "_" . $self->{sp_adm_begin}->GetValue; $self->{t_db_name}->SetValue($x); # end wxGlade } sub OnToggleCreate { my ($self, $event) = @_; # wxGlade: EB::Wx::IniWiz::OnToggleBTW $self = $self->GetParent; my $x = $event->GetEventObject->IsChecked ? 1 : 0; $self->{ "cb_cr_$_" }->SetValue($x) foreach qw(schema relaties opening mutaties); # end wxGlade } sub OnWizardFinished { my ($self, $event) = @_; # wxGlade: EB::Wx::IniWiz::OnWizardFinished my %opts; $opts{adm_naam} = $self->{t_adm_name}->GetValue; $opts{adm_code} = $self->{t_adm_code}->GetValue; $opts{adm_begindatum} = $self->{sp_adm_begin}->GetValue; $opts{db_naam} = $self->{t_db_name}->GetValue; $opts{db_driver} = $db_drivers[$self->{ch_db_driver}->GetSelection]; $opts{db_host} = $self->{t_db_host}->GetValue if $self->{t_db_host}->IsEnabled && $self->{t_db_host}->GetValue && $self->{t_db_host}->GetValue ne $default; $opts{db_port} = $self->{t_db_port}->GetValue if $self->{t_db_port}->IsEnabled && $self->{t_db_port}->GetValue && $self->{t_db_port}->GetValue ne $default; $opts{db_user} = $self->{t_db_user}->GetValue if $self->{t_db_user}->IsEnabled && $self->{t_db_user}->GetValue && $self->{t_db_user}->GetValue ne $default; $opts{db_password} = $self->{t_db_password}->GetValue if $self->{t_db_password}->IsEnabled && $self->{t_db_password}->GetValue && $self->{t_db_password}->GetValue ne ""; #$opts{db_path} = $self->{dc_dbpath}->GetPath # if $self->{dc_dbpath}->IsEnabled # && $self->{dc_dbpath}->GetPath !~ /^--/; $opts{"has_$_"} = $self->{"cb_$_"}->IsChecked foreach qw(debiteuren crediteuren kas bank btw); $opts{"create_$_"} = $self->{"cb_cr_$_"}->IsChecked foreach qw(config schema relaties opening mutaties database); $opts{adm_btwperiode} = qw(maand kwartaal jaar)[$self->{ch_btw_period}->GetSelection] if $opts{has_btw}; $opts{template} = $ebz[ $self->{ch_template}->GetSelection ]->[0]; if ( $opts{adm_code} ) { mkdir($opts{adm_code}) unless -d $opts{adm_code}; chdir($opts{adm_code}) or die("chdir($opts{adm_code}): $!\n");; } $self->{b_ok}->Enable(0); my $log = $self->{t_main}; eval { EB::Tools::MiniAdm->sanitize(\%opts); foreach my $c ( qw(config schema relaties opening mutaties database) ) { my $msg = __x("Aanmaken {cfg}: ", cfg => $c); $log->AppendText($msg); if ( $opts{"create_$c"} ) { if ( $c eq "database" ) { my $t = $log->GetInsertionPoint; $log->AppendText(_T("Even geduld...")); $self->Refresh; $self->Update; my $ret; EB->app_init( { app => $EekBoek::PACKAGE, %opts } ); require EB::Main; local $::app; # defeat Shell blocking of import command local @ARGV = qw( --init ); my @msg; my $out; # Intercept warn and die. local $SIG{__WARN__} = sub { push( @msg, join("\n", @_) ); }; local $SIG{__DIE__} = sub { push( @msg, "?".join("\n", @_) ); }; # Intercept STDOUT. open( my $oldout, ">&STDOUT" ); close( STDOUT ); open( STDOUT, '>', \$out ) or die("STDOUT capture fail"); $ret = EB::Main->run; # Restore STDOUT. close(STDOUT); open ( STDOUT, ">&", $oldout ); if ( $ret ) { $log->Replace($t, $log->GetInsertionPoint, _T("Mislukt")."\n"); } else { $log->Replace($t, $log->GetInsertionPoint, _T("Gereed")."\n"); } if ( $out || @msg ) { $self->{b_details}->Show(1); $self->{sz_buttons}->Layout; $self->{_details} = ""; if ( @msg ) { $self->{_details} .= _T("==== Meldingen ====")."\n"; $self->{_details} .= $_ . "\n" for @msg; } if ( $out ) { $self->{_details} .= _T("==== Uitvoer ====")."\n"; $self->{_details} .= $out . "\n"; } } $self->Update; } else { $self->Refresh; my $m = "generate_". $c; EB::Tools::MiniAdm->$m(\%opts); $log->AppendText(_T("Gereed")."\n"); $self->Update; } } else { $log->AppendText(_T("Overgeslagen")."\n"); } } }; $log->AppendText($@) if $@; $self->{b_ok}->Enable(1); $self->{b_ok}->SetFocus; unless ( -e $cfg->std_config || -e $cfg->std_config_alt ) { $self->{ch_runeb}->SetValue(0); } elsif ( $self->{rb_select}->GetSelection != 0 ) { foreach ( qw( opening.eb ) ) { $self->{ch_runeb}->SetValue(0) unless -s $_; } } else { foreach ( @configs ) { $self->{ch_runeb}->SetValue(0) unless -s $_; } } # end wxGlade } sub OnWizardCancel { my ($self, $event) = @_; # wxGlade: EB::Wx::IniWiz::OnWizardCancel $self->Show(1); $self->{t_main}->SetValue(_T("Afgebroken!")."\n"); $self->{b_ok}->Enable(1); $self->{ch_runeb}->SetValue(0); # end wxGlade } sub OnOk { my ($self, $event) = @_; # wxGlade: EB::Wx::IniWiz::OnOk $runeb = $self->{ch_runeb}->IsChecked; $self->Destroy; # end wxGlade } sub find_db_drivers { my %drivers; if ( $App::Packager::PACKAGED ) { # Trust packager. unless ( $App::Packager::PACKAGED ) { # Ignored, but force packaging. require EB::DB::Postgres; require EB::DB::Sqlite; } return { sqlite => "SQLite", postgres => "PostgreSQL", }; } foreach my $lib ( @INC ) { next unless -d "$lib/EB/DB"; foreach my $drv ( glob("$lib/EB/DB/*.pm") ) { open( my $fd, "<", $drv ) or next; while ( <$fd> ) { if ( /sub\s+type\s*{\s*"([^"]+)"\s*;?\s*}/ ) { my $s = $1; my $t = substr($drv,length("$lib/EB/DB/")); $t =~ s/\.pm$//; $drivers{lc($t)} ||= $s; last; } } close($fd); } } \%drivers; } sub OnSelectDbDriver { my ($self, $event) = @_; # wxGlade: EB::Wx::IniWiz::OnSelectDbDriver $self = $self->GetParent; my $sel = $self->{ch_db_driver}->GetSelection; my $is_default = $db_drivers[$sel] eq 'sqlite'; for ( qw( label_db_host t_db_host label_db_port t_db_port label_db_user t_db_user label_db_password t_db_password ) ) { $self->{$_}->Enable( !$is_default ); $_[0]->Layout; $self->Layout; } # end wxGlade } sub _dbtest { my $self = shift; my $drv = $db_drivers[$self->{ch_db_driver}->GetSelection]; $drv = "EB::DB::" . ucfirst($drv); my $res; my $opts; $opts->{host} = $self->{t_db_host}->GetValue if $self->{t_db_host}->IsEnabled && $self->{t_db_host}->GetValue && $self->{t_db_host}->GetValue ne $default; $opts->{port} = $self->{t_db_port}->GetValue if $self->{t_db_port}->IsEnabled && $self->{t_db_port}->GetValue && $self->{t_db_port}->GetValue ne $default; $opts->{user} = $self->{t_db_user}->GetValue if $self->{t_db_user}->IsEnabled && $self->{t_db_user}->GetValue && $self->{t_db_user}->GetValue ne $default; $opts->{password} = $self->{t_db_password}->GetValue if $self->{t_db_password}->IsEnabled && $self->{t_db_password}->GetValue && $self->{t_db_password}->GetValue ne ""; my $db; if ( $self->{rb_select}->GetSelection == 1 ) { $db = $self->{t_db_name}->GetValue; } eval { eval "use $drv"; die($@) if $@; $res = $drv->feature("test") ? $drv->test( $db, $opts ) : ''; }; $res = $@ if $@; delete( $INC{"EB.pm"} ); # remove fake environment return $res; } sub OnDbTest { my ($self, $event) = @_; # wxGlade: EB::Wx::IniWiz::OnDbTest $self = $self->GetParent; my $res = $self->_dbtest; my $icon = ( $res ? wxICON_ERROR : wxICON_INFORMATION ); $icon |= wxOK; my $m = Wx::MessageDialog->new($self->{wiz}, $res || _T("Succes!"), _T("Database Test Resultaat"), $icon ); $m->ShowModal; $m->Destroy; # end wxGlade } sub OnDetails { my ($self, $event) = @_; # wxGlade: EB::Wx::IniWiz::OnDetails return unless $self->{_details}; $self->{t_main}->SetValue( $self->{_details} ); $self->{_details} = ""; $self->{b_details}->Enable(0); # end wxGlade } # end of class EB::Wx::IniWiz 1; package Wx::WizardPanel; use Wx qw[wxBITMAP_TYPE_ANY]; use EB; #use Wx::Locale gettext => '_T'; sub new { my ( $class, $self ) = @_; $self = $self->GetParent; $self->{wiz} ||= Wx::Wizard->new( $self, -1, _T("The Wiz"), Wx::Bitmap->new("ebwiz.jpg", wxBITMAP_TYPE_ANY )); Wx::WizardPageSimple->new( $self->{wiz} ); } package EB::Wx::IniWiz; sub run { my ( $self, $opts ) = @_; my $admdir = $opts->{admdir} || $cfg->val(qw(general admdir), $cfg->user_dir("admdir")); $runeb = 1; $admdir =~ s/\$([A-Z_]+)/$ENV{$1}/ge; if ( $admdir ) { mkdir($admdir) unless -d $admdir; die("No admdir $admdir: $!") unless -d $admdir; } $opts->{admdir} = $admdir; $runeb = 0; no warnings 'redefine'; local *Wx::App::OnInit = sub{1}; $app = Wx::App->new(); $app->SetAppName($EekBoek::PACKAGE); $app->SetVendorName("Squirrel Consultancy"); if ( $^O =~ /^mswin/i ) { Wx::ConfigBase::Get->SetPath("/ebwxiniwiz"); } else { Wx::ConfigBase::Set (Wx::FileConfig->new ( $app->GetAppName() , $app->GetVendorName() , $cfg->user_dir("ebwxiniwiz"), '', wxCONFIG_USE_LOCAL_FILE, )); } Wx::ConfigBase::Get->Write('general/appversion', $EekBoek::VERSION); my $ret = wxID_NEW; $ret = EB::Wx::IniWiz->getadm($opts) if $admdir; if ( $ret == wxID_CANCEL ) { $runeb = 0; } elsif ( $ret == wxID_NEW || $ret == wxID_OPEN || ! ( -s $cfg->std_config || -s $cfg->std_config_alt ) ) { # getadm will chdir my $top = EB::Wx::IniWiz->new(); $app->SetTopWindow($top); $top->Center; $top->Show(1); $top->runwiz; $app->MainLoop; } else { $runeb = 1; } $opts->{runeb} = $runeb; } 1; EekBoek-2.030.1/lib/EB/Wx/Help.pm0000644000400000040000000000263113044363102013636 0ustar jvjv#! perl package main; our $cfg; package EB::Wx::Help; use strict; use EB; use Wx qw(wxHF_FLATTOOLBAR wxHF_TOOLBAR wxHF_CONTENTS wxHF_SEARCH wxHF_BOOKMARKS wxHF_INDEX wxHF_PRINT wxHF_DEFAULTSTYLE wxHF_DIALOG wxHF_MODAL ); use Wx qw(wxACCEL_CTRL wxACCEL_NORMAL wxID_CLOSE); use Wx::Event; use Wx::Html; use Wx::Help; use Wx::FS; # very important for HTB to work Wx::FileSystem::AddHandler( new Wx::ZipFSHandler ); sub new { my $class = shift; my $modal = shift || 0; my $self = Wx::HtmlHelpController->new ( wxHF_FLATTOOLBAR | wxHF_TOOLBAR # | wxHF_CONTENTS # | wxHF_INDEX | wxHF_CONTENTS # | wxHF_BOOKMARKS | wxHF_SEARCH | wxHF_PRINT | ( $modal ? wxHF_DIALOG|wxHF_MODAL : 0 ) ); return bless { widget => $self, modal => $modal }, $class; } sub show_html_help { my ($self) = @_; if ( my $htb_file = $ENV{EB_HTB} && -s $ENV{EB_HTB} ? $ENV{EB_HTB} : findlib( "docs.htb", "help" ) ) { $self->{widget}->AddBook( $htb_file, 1 ); $self->{widget}->DisplayContents; return if $self->{modal}; if( my $hframe = Wx::Window::FindWindowByName('wxHtmlHelp')) { $hframe->SetAcceleratorTable (Wx::AcceleratorTable->new ( [wxACCEL_CTRL, ord 'w', wxID_CLOSE], [wxACCEL_NORMAL, 27, wxID_CLOSE], )); } } else { ::info( _T("No help available for this language"), _T("Sorry") ); } } package Wx::HtmlHelpFrame; our @ISA = qw( Wx::Frame ); 1; EekBoek-2.030.1/lib/EB/Wx/Shell/0000755000400000040000000000000013151742350013462 5ustar jvjvEekBoek-2.030.1/lib/EB/Wx/Shell/Window.pm0000644000400000040000000000352712725476602015310 0ustar jvjv#! perl package main; our $cfg; our $state; our $app; our $dbh; package EB::Wx::Shell::Window; use strict; use warnings; use Wx qw[ wxACCEL_CTRL wxACCEL_NORMAL wxID_CLOSE wxTHICK_FRAME ]; sub sizepos_save { my ($self, $posonly) = @_; my $config = Wx::ConfigBase::Get; my ( $x, $y ) = $self->GetPositionXY; $config->WriteInt( "windows/".$self->{mew}."/xpos", $x ); $config->WriteInt( "windows/".$self->{mew}."/ypos", $y ); unless ( $posonly ) { ($x, $y) = ( Wx::wxMAC ) ? $self->GetClientSizeWH : $self->GetSizeWH ; $config->WriteInt( "windows/".$self->{mew}."/xwidth", $x ); $config->WriteInt( "windows/".$self->{mew}."/ywidth", $y ); } } sub sizepos_restore { my ($self, $mew, $posonly) = @_; $self->{mew} = $mew if defined $mew; my $config = Wx::ConfigBase::Get; my $x = $config->ReadInt( "windows/".$self->{mew}."/xpos", -1 ); my $y = $config->ReadInt( "windows/".$self->{mew}."/ypos", -1 ); $self->Move( $x, $y ) if $x >= 0 && $y >= 0; unless ( $posonly ) { $x = $config->ReadInt( "windows/".$self->{mew}."/xwidth", -1 ); $y = $config->ReadInt( "windows/".$self->{mew}."/ywidth", -1 ); if ( $x >= 0 && $y >= 0 ) { $self->SetSize( $x, $y ); $self->SetClientSize([$x, $y]) if Wx::wxMAC(); } else { $self->SetSize(0, 0, $self->GetSizeWH); $self->Center; } } # For convenience: CLOSE on Ctrl-W and Esc. # (Doesn't work on GTK, yet). $self->SetAcceleratorTable (Wx::AcceleratorTable->new ( [wxACCEL_CTRL, ord 'w', wxID_CLOSE], [wxACCEL_NORMAL, 27, wxID_CLOSE], )); } #### Override sub init { shift->refresh(@_); } #### Override sub refresh { } # wxGlade insists on generating these. sub Wx::wxTHICK_FRAME() { 0 } # removed 2.x sub Wx::wxADJUST_MINSIZE() { 0 } # bogus 2.8, removed in 2.9 1; EekBoek-2.030.1/lib/EB/Wx/Shell/HtmlViewer.pm0000644000400000040000000001125612725476601016124 0ustar jvjv#! perl package main; package EB::Wx::Shell::HtmlViewer; use base qw(Wx::Dialog); use base qw(EB::Wx::Shell::Window); use strict; # begin wxGlade: ::dependencies use Wx::Locale gettext => '_T'; # end wxGlade use Wx::Html; use Wx qw[ wxADJUST_MINSIZE wxALL wxDEFAULT_DIALOG_STYLE wxDefaultPosition wxDefaultSize wxEXPAND wxHORIZONTAL wxID_CLOSE wxID_OK wxID_PRINT wxID_SAVE wxLEFT wxMAXIMIZE_BOX wxMINIMIZE_BOX wxFD_OVERWRITE_PROMPT wxRESIZE_BORDER wxFD_SAVE wxTHICK_FRAME wxVERTICAL ]; sub new { my( $self, $parent, $id, $title, $pos, $size, $style, $name ) = @_; $parent = undef unless defined $parent; $id = -1 unless defined $id; $title = "" unless defined $title; $pos = wxDefaultPosition unless defined $pos; $size = wxDefaultSize unless defined $size; $name = "" unless defined $name; # begin wxGlade: EB::Wx::Shell::HtmlViewer::new $style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER|wxMAXIMIZE_BOX|wxMINIMIZE_BOX|wxTHICK_FRAME unless defined $style; $self = $self->SUPER::new( $parent, $id, $title, $pos, $size, $style, $name ); $self->{b_print} = Wx::Button->new($self, wxID_PRINT, ""); $self->{b_save} = Wx::Button->new($self, wxID_SAVE, ""); $self->{p_close} = Wx::Button->new($self, wxID_CLOSE, ""); $self->{p_htmlview} = Wx::HtmlWindow->new($self, -1, wxDefaultPosition, wxDefaultSize, ); $self->__set_properties(); $self->__do_layout(); Wx::Event::EVT_BUTTON($self, $self->{b_print}->GetId, \&OnPrint); Wx::Event::EVT_BUTTON($self, $self->{b_save}->GetId, \&OnSave); Wx::Event::EVT_BUTTON($self, $self->{p_close}->GetId, \&OnClose); # end wxGlade Wx::Event::EVT_HTML_LINK_CLICKED($self->{p_htmlview}, $self->{p_htmlview}->GetId, \&OnLinkClicked); $self->{_PRINTER} = Wx::HtmlEasyPrinting->new('Print'); $self->sizepos_restore(lc($title)); return $self; } sub info_only { my ( $self ) = @_; $self->{b_print}->Hide; $self->{b_save}->Hide; } sub html { $_[0]->{p_htmlview} } sub htmltext :lvalue { $_[0]->{_HTMLTEXT} } sub printer { $_[0]->{_PRINTER} } sub __set_properties { my $self = shift; # begin wxGlade: EB::Wx::Shell::HtmlViewer::__set_properties $self->SetTitle(_T("HTML Uitvoer")); $self->SetSize(Wx::Size->new(618, 522)); $self->{p_close}->SetFocus(); $self->{p_close}->SetDefault(); # end wxGlade } sub __do_layout { my $self = shift; # begin wxGlade: EB::Wx::Shell::HtmlViewer::__do_layout $self->{sz_htmlview} = Wx::BoxSizer->new(wxVERTICAL); $self->{sz_htmlviewbuttons} = Wx::BoxSizer->new(wxHORIZONTAL); $self->{sz_htmlviewbuttons}->Add($self->{b_print}, 0, wxADJUST_MINSIZE, 0); $self->{sz_htmlviewbuttons}->Add($self->{b_save}, 0, wxLEFT|wxADJUST_MINSIZE, 5); $self->{sz_htmlviewbuttons}->Add(5, 1, 1, wxADJUST_MINSIZE, 0); $self->{sz_htmlviewbuttons}->Add($self->{p_close}, 0, wxADJUST_MINSIZE, 0); $self->{sz_htmlview}->Add($self->{sz_htmlviewbuttons}, 0, wxALL|wxEXPAND, 5); $self->{sz_htmlview}->Add($self->{p_htmlview}, 1, wxEXPAND, 0); $self->SetSizer($self->{sz_htmlview}); $self->Layout(); # end wxGlade } sub OnPrint { my ($self, $event) = @_; # wxGlade: EB::Wx::Shell::HtmlViewer::OnPrint $self->printer->SetFooter(' - @PAGENUM@ - '); $self->printer->PrintText($self->htmltext); # end wxGlade } sub OnSave { my ($self, $event) = @_; # wxGlade: EB::Wx::Shell::HtmlViewer::OnSave my $d = Wx::FileDialog->new($self, _T("Opslaan als..."), "", _T("raport.html"), _T("HTML bestanden (*.html)|*.html"), wxFD_SAVE | wxFD_OVERWRITE_PROMPT); my $result = $d->ShowModal; if ( $result == wxID_OK ) { my $file = $d->GetPath; open(my $fd, ">", $file); print { $fd } $self->htmltext; close($fd); } # end wxGlade } sub OnClose { my ($self, $event) = @_; # wxGlade: EB::Wx::Shell::HtmlViewer::OnClose $self->sizepos_save; $self->Show(0); # end wxGlade } sub OnLinkClicked { my ($self, $event) = @_; my $link = $event->GetLinkInfo->GetHref; if ( $link =~ m;^([^:]+)://(.+)$; && (my $rep = EB::Wx::Shell::MainFrame->can("ShowR" . ucfirst(lc($1)))) ) { my @a = split(/[?&]/, $2); my $args = { select => shift(@a) }; foreach ( @a ) { if ( /^([^=]+)=(.*)/ ) { $args->{$1} = $2; } else { $args->{$_} = 1; } } $rep->($self->GetParent->GetParent, $args); } elsif ( $link =~ m;^(https?|mailto):; ) { Wx::LaunchDefaultBrowser($link); } else { Wx::LogMessage('Link: "%s"', $1); } } # end of class EB::Wx::Shell::HtmlViewer 1; EekBoek-2.030.1/lib/EB/Wx/Shell/MainFrame.pm0000644000400000040000000006402613044346163015672 0ustar jvjv#! perl package main; use strict; our $cfg; our $dbh; package EB::Wx::Shell::MainFrame; use EekBoek; use base qw(Wx::Frame); use base qw(EB::Wx::Shell::Window); use strict; use utf8; use Encode; use File::Spec; use File::Basename; # begin wxGlade: ::dependencies use Wx::Locale gettext => '_T'; # end wxGlade use EB; use EB::Wx::Shell::HtmlViewer; use EB::Wx::Shell::EditDialog; use EB::Wx::Shell::PreferencesDialog; use Wx qw[ wxADJUST_MINSIZE wxALL wxBITMAP_TYPE_ANY wxBLUE wxDEFAULT_FRAME_STYLE wxDefaultPosition wxDefaultSize wxEXPAND wxFD_FILE_MUST_EXIST wxGREEN wxHORIZONTAL wxHOURGLASS_CURSOR wxHSCROLL wxICON_ERROR wxICON_INFORMATION wxICON_WARNING wxID_ABOUT wxID_APPLY wxID_CLEAR wxID_EXIT wxID_HELP wxID_OK wxID_OPEN wxID_PREFERENCES wxLEFT wxMODERN wxNORMAL wxNullCursor wxOK wxRED wxRIGHT wxST_SIZEGRIP wxSYS_DEFAULT_GUI_FONT wxTE_MULTILINE wxTE_PROCESS_ENTER wxTE_PROCESS_TAB wxTE_READONLY wxVERTICAL ]; my $prefctl; ################ Locale ################ # Variable expansion. See GNU gettext for details. sub __expand($%) { my ($t, %args) = @_; my $re = join('|', map { quotemeta($_) } keys(%args)); #### WHOAH!!!!! # $1 seems to be stuck to the EekBoek initial message. #### WHOAH!!!!! $t =~ s/(\{)($re)\}/defined($args{$2}) ? $args{$2} : "{$2}"/ge; $t; } # Translation w/ variables. sub __x($@) { my ($t, %vars) = @_; __expand(_T($t), %vars); } # Translation w/ singular/plural handling. sub __n($$$) { my ($sing, $plur, $n) = @_; _T($n == 1 ? $sing : $plur); } # Translation w/ singular/plural handling and variables. sub __nx($$$@) { my ($sing, $plur, $n, %vars) = @_; __expand(__n($sing, $plur, $n), %vars); } # Make __xn a synonym for __nx. *__xn = \&__nx; ################ Locale ################ sub new { my( $self, $parent, $id, $title, $pos, $size, $style, $name ) = @_; $parent = undef unless defined $parent; $id = -1 unless defined $id; $title = "" unless defined $title; $pos = wxDefaultPosition unless defined $pos; $size = wxDefaultSize unless defined $size; $name = "" unless defined $name; use constant MENU_INPUTEDIT => Wx::NewId(); use constant MENU_INPUTEXEC => Wx::NewId(); use constant MENU_REP_TRIAL => Wx::NewId(); use constant MENU_REP_BAL_ACT => Wx::NewId(); use constant MENU_REP_BAL_MGP => Wx::NewId(); use constant MENU_REP_BAL_GRP => Wx::NewId(); use constant MENU_REP_BAL_GAC => Wx::NewId(); use constant MENU_REP_RES_ACT => Wx::NewId(); use constant MENU_REP_RES_MGP => Wx::NewId(); use constant MENU_REP_RES_GRP => Wx::NewId(); use constant MENU_REP_RES_GAC => Wx::NewId(); use constant MENU_REP_JNL => Wx::NewId(); use constant MENU_REP_UN => Wx::NewId(); use constant MENU_REP_AP => Wx::NewId(); use constant MENU_REP_AR => Wx::NewId(); use constant MENU_REP_VAT => Wx::NewId(); use constant MENU_HELP_SUPPORT => Wx::NewId(); # ###WARNING: Re-generating will loose # $self->__set_menubar(); # insert before $self->{s_input_staticbox} = ... # begin wxGlade: EB::Wx::Shell::MainFrame::new $style = wxDEFAULT_FRAME_STYLE unless defined $style; $self = $self->SUPER::new( $parent, $id, $title, $pos, $size, $style, $name ); $self->{p_dummy} = Wx::Panel->new($self, -1, wxDefaultPosition, wxDefaultSize, ); $self->__set_menubar(); $self->{s_input_staticbox} = Wx::StaticBox->new($self->{p_dummy}, -1, _T("Invoer") ); $self->{statusbar} = $self->CreateStatusBar(1, wxST_SIZEGRIP); $self->{t_output} = Wx::TextCtrl->new($self->{p_dummy}, -1, "", wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE|wxTE_READONLY|wxHSCROLL); $self->{b_edit} = Wx::BitmapButton->new($self->{p_dummy}, -1, (Wx::Bitmap->new("edit.png", wxBITMAP_TYPE_ANY))); $self->{t_input} = Wx::TextCtrl->new($self->{p_dummy}, -1, "", wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER|wxTE_PROCESS_TAB); $self->{b_send} = Wx::BitmapButton->new($self->{p_dummy}, -1, (Wx::Bitmap->new("button_ok.png", wxBITMAP_TYPE_ANY))); $self->__set_properties(); $self->__do_layout(); Wx::Event::EVT_BUTTON($self, $self->{b_edit}->GetId, \&OnEdit); Wx::Event::EVT_TEXT_ENTER($self, $self->{t_input}->GetId, \&OnTextEnter); Wx::Event::EVT_BUTTON($self, $self->{b_send}->GetId, \&OnSend); # end wxGlade Wx::Event::EVT_MENU($self, wxID_OPEN, \&OnOpen); Wx::Event::EVT_MENU($self, wxID_PREFERENCES, \&OnPrefs); Wx::Event::EVT_MENU($self, wxID_EXIT, \&OnQuit); Wx::Event::EVT_MENU($self, wxID_CLEAR, \&OnClear); Wx::Event::EVT_MENU($self, MENU_INPUTEDIT, \&OnEdit); Wx::Event::EVT_MENU($self, MENU_INPUTEXEC, \&OnSend); Wx::Event::EVT_MENU($self, MENU_REP_TRIAL, \&OnTrial); my $i = -1; for ( MENU_REP_BAL_ACT, MENU_REP_BAL_MGP, MENU_REP_BAL_GRP, MENU_REP_BAL_GAC,) { my $sub = $i++; Wx::Event::EVT_MENU($self, $_, sub { push(@_, $sub); &OnMenuBal }); } $i = -1; for ( MENU_REP_RES_ACT, MENU_REP_RES_MGP, MENU_REP_RES_GRP, MENU_REP_RES_GAC,) { my $sub = $i++; Wx::Event::EVT_MENU($self, $_, sub { push(@_, $sub); &OnMenuRes }); } Wx::Event::EVT_MENU($self, MENU_REP_JNL, \&OnJournal); Wx::Event::EVT_MENU($self, MENU_REP_UN, \&OnMenuUns); Wx::Event::EVT_MENU($self, MENU_REP_AP, \&OnMenuAP); Wx::Event::EVT_MENU($self, MENU_REP_AR, \&OnMenuAR); Wx::Event::EVT_MENU($self, MENU_REP_VAT, \&OnMenuVAT); Wx::Event::EVT_MENU($self, wxID_HELP, \&OnHelp); Wx::Event::EVT_MENU($self, MENU_HELP_SUPPORT, \&OnSupport); Wx::Event::EVT_MENU($self, wxID_ABOUT, \&OnAbout); #### End of MenuBar Wx::Event::EVT_CLOSE($self, \&OnQuit); Wx::Event::EVT_CHAR($self->{t_input}, sub { $self->OnChar(@_) }); # Wx::Event::EVT_IDLE($self, \&OnIdle); $prefctl ||= { repwin => 0, errorpopup => 1, warnpopup => 1, infopopup => 0, histlines => 200, }; $self->SetSize(801, 551); $self->sizepos_restore("main"); return $self; } sub __set_menubar { my $self = shift; # Unfortunately, due to an error in wxGlade sub-menu # generation we need to do it ourselves. All... $self->{menubar} = Wx::MenuBar->new(); my $wxglade_tmp_menu; $wxglade_tmp_menu = Wx::Menu->new(); $wxglade_tmp_menu->Append(wxID_OPEN, _T("&Open\tCtrl-O"), ""); $wxglade_tmp_menu->AppendSeparator(); $wxglade_tmp_menu->Append(wxID_PREFERENCES, _T("Voorkeuren..."), ""); $wxglade_tmp_menu->AppendSeparator(); $wxglade_tmp_menu->Append(wxID_EXIT, _T("Afsluiten\tCtrl-Q"), ""); $self->{menubar}->Append($wxglade_tmp_menu, _T("&Bestand")); $wxglade_tmp_menu = Wx::Menu->new(); $wxglade_tmp_menu->Append(MENU_INPUTEDIT, _T("&Edit invoerregel\tCtrl+Enter"), ""); $wxglade_tmp_menu->Append(MENU_INPUTEXEC, _T("&Uitvoeren invoerregel\tEnter"), ""); $wxglade_tmp_menu->AppendSeparator(); $wxglade_tmp_menu->Append(wxID_CLEAR, _T("Uitvoer schoonmaken"), ""); $self->{menubar}->Append($wxglade_tmp_menu, _T("B&ewerken")); $self->{Reports} = Wx::Menu->new(); $self->{Reports}->Append(MENU_REP_TRIAL, _T("Proef- en Saldibalans"), ""); $self->{Reports_bal} = Wx::Menu->new(); $self->{Reports_bal}->Append(MENU_REP_BAL_ACT, _T("Op grootboekrekening"), ""); $self->{Reports_bal}->AppendSeparator(); $self->{Reports_bal}->Append(MENU_REP_BAL_MGP, _T("Op hoofdverdichting"), ""); $self->{Reports_bal}->Append(MENU_REP_BAL_GRP, _T("Op verdichting"), ""); $self->{Reports_bal}->Append(MENU_REP_BAL_GAC, _T("Gedetailleerd"), ""); $self->{Reports}->Append(Wx::NewId(), _T("Balans"), $self->{Reports_bal}, ""); $self->{Reports_res} = Wx::Menu->new(); $self->{Reports_res}->Append(MENU_REP_RES_ACT, _T("Op grootboekrekening"), ""); $self->{Reports_res}->AppendSeparator(); $self->{Reports_res}->Append(MENU_REP_RES_MGP, _T("Op hoofdverdichting"), ""); $self->{Reports_res}->Append(MENU_REP_RES_GRP, _T("Op verdichting"), ""); $self->{Reports_res}->Append(MENU_REP_RES_GAC, _T("Gedetailleerd"), ""); $self->{Reports}->Append(Wx::NewId(), _T("Verlies/Winst"), $self->{Reports_res}, ""); $self->{Reports}->AppendSeparator(); $self->{Reports}->Append(MENU_REP_JNL, _T("Journaal"), ""); $self->{Reports}->AppendSeparator(); $self->{Reports}->Append(MENU_REP_UN, _T("Openstaande posten"), ""); $self->{Reports}->AppendSeparator(); $self->{Reports}->Append(MENU_REP_AP, _T("Crediteuren"), ""); $self->{Reports}->Append(MENU_REP_AR, _T("Debiteuren"), ""); $self->{Reports}->AppendSeparator(); $self->{Reports}->Append(MENU_REP_VAT, _T("BTW Aangifte"), ""); $self->{menubar}->Append($self->{Reports}, _T("&Rapporten")); $wxglade_tmp_menu = Wx::Menu->new(); $wxglade_tmp_menu->Append(wxID_HELP, _T("&Hulp..."), ""); $wxglade_tmp_menu->AppendSeparator(); $wxglade_tmp_menu->Append(MENU_HELP_SUPPORT, _T("Ondersteuning..."), ""); $wxglade_tmp_menu->AppendSeparator(); $wxglade_tmp_menu->Append(wxID_ABOUT, _T("Over..."), ""); $self->{menubar}->Append($wxglade_tmp_menu, _T("&Hulp")); $self->SetMenuBar($self->{menubar}); } sub __set_properties { my $self = shift; # begin wxGlade: EB::Wx::Shell::MainFrame::__set_properties $self->SetTitle(_T("EekBoek")); $self->SetSize(Wx::Size->new(800, 550)); $self->{statusbar}->SetStatusWidths(-1); my( @statusbar_fields ) = ( "" ); if( @statusbar_fields ) { $self->{statusbar}->SetStatusText($statusbar_fields[$_], $_) for 0 .. $#statusbar_fields ; } $self->{b_edit}->SetSize($self->{b_edit}->GetBestSize()); $self->{t_input}->SetFocus(); $self->{b_send}->SetSize($self->{b_send}->GetBestSize()); # end wxGlade my $f = Wx::SystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); $self->{t_output}->SetFont(Wx::Font->new($f->GetPointSize, wxMODERN, wxNORMAL, wxNORMAL, 0, "")); } sub __do_layout { my $self = shift; # begin wxGlade: EB::Wx::Shell::MainFrame::__do_layout $self->{sz_dummy} = Wx::BoxSizer->new(wxHORIZONTAL); $self->{s_main} = Wx::BoxSizer->new(wxVERTICAL); $self->{s_layout} = Wx::BoxSizer->new(wxVERTICAL); $self->{s_input}= Wx::StaticBoxSizer->new($self->{s_input_staticbox}, wxHORIZONTAL); $self->{s_output} = Wx::BoxSizer->new(wxHORIZONTAL); $self->{s_output}->Add($self->{t_output}, 1, wxEXPAND|wxADJUST_MINSIZE, 0); $self->{s_layout}->Add($self->{s_output}, 1, wxEXPAND, 0); $self->{s_input}->Add($self->{b_edit}, 0, wxRIGHT|wxADJUST_MINSIZE, 5); $self->{s_input}->Add($self->{t_input}, 1, wxEXPAND|wxADJUST_MINSIZE, 0); $self->{s_input}->Add($self->{b_send}, 0, wxLEFT|wxADJUST_MINSIZE, 5); $self->{s_layout}->Add($self->{s_input}, 0, wxEXPAND, 0); $self->{s_main}->Add($self->{s_layout}, 1, wxALL|wxEXPAND, 5); $self->{p_dummy}->SetSizer($self->{s_main}); $self->{sz_dummy}->Add($self->{p_dummy}, 1, wxEXPAND, 0); $self->SetSizer($self->{sz_dummy}); $self->Layout(); $self->SetSize(Wx::Size->new(800, 550)); # end wxGlade } sub RunCommand { my ($self, $cmd) = @_; unless ( defined $self->{_shell} ) { unless ( $self->{_ebcfg} && -s $self->{_ebcfg} ) { my $md = Wx::MessageDialog->new ($self, _T("Selecteer eerst een geldige eekboek.conf"), _T("Geen configuratie"), wxOK|wxICON_INFORMATION, wxDefaultPosition); $md->ShowModal; $md->Destroy; $self->OnOpen; return; } my $cfg = EB->app_init( { app => $EekBoek::PACKAGE, config => $self->{_ebcfg} } ); $self->{statusbar}->SetStatusText($EB::imsg, 0); $cfg->connect_db; require EB::Shell; $self->{_shell} = EB::Shell->new; } $cmd = "database" unless defined $cmd; $self->{t_output}->AppendText("eb> "); $self->ShowText($cmd, wxBLUE); $self->_cmd($cmd); } use Text::ParseWords qw(shellwords); sub _cmd { my ( $self, $cmd ) = @_; my ( @cmd ) = shellwords($cmd); # If there's a quoting mistake, parseline returns nothing. if ( $cmd =~ /\S/ && $cmd[0] !~ /\S/ ) { $self->process_stderr("?"._T("Fout in de invoerregel. Controleer de \" en ' tekens.")."\n"); return -1; } my ( $cmd, @args ) = @cmd; if (! length($cmd)) { return -1; } if ( $cmd =~ /^(balans|result|proefensaldibalans|journaal|openstaand|(?:deb|cred)iteuren|grootboek|btwaangifte)(?:\s|$)/ ) { unshift( @args, "--gen-wxhtml" ); } if ( $cmd =~ /^\s*(help|\?)/i ) { $self->OnHelp; return 1; } if ( $cmd =~ /^\s*(exit|quit|logout)/i ) { $self->OnQuit; return 1; } my $meth = "do_".lc($cmd); unless ( $self->{_shell}->can($meth) ) { $self->process_stderr("?"._T("Onbekende opdracht. \"help\" geeft een lijst van mogelijke opdrachten.")."\n"); return -1; } my ( $out, $t, @msg ); eval { # Intercept warn and die. local $SIG{__WARN__} = sub { push( @msg, join("\n", @_) ); }; local $SIG{__DIE__} = sub { push( @msg, "?".join("\n", @_) ); }; # Intercept STDOUT. open( my $oldout, ">&STDOUT" ); close( STDOUT ); open( STDOUT, '>', \$out ) or die("STDOUT capture fail"); # Call API command. $t = $self->{_shell}->$meth(@args); # Restore STDOUT. close(STDOUT); open ( STDOUT, ">&", $oldout ); }; if ($@) { my $err = $@; chomp $err; $self->process_stderr("?$err\n"); } else { # Process output. $out .= "\n" unless !$out || $out =~ /\n$/; if ( $t =~ /^[%!?]/ ) { $self->process_stderr($t); } else { $out .= $t; } $self->process_stderr($_) for @msg; $self->process_stdout($_) for split(/\n/, $out); } return 1; } sub ShowText { my ($self, $text, $colour) = @_; if ( $colour ) { my $t = Wx::TextAttr->new; $t->SetTextColour($colour); my $x0 = $self->{t_output}->GetLastPosition; $self->{t_output}->AppendText($text."\n"); $self->{t_output}->SetStyle($x0, $self->{t_output}->GetLastPosition, $t); } else { $self->{t_output}->AppendText($text."\n"); } } my $capturing; sub process_stdout { my ($self, $text) = @_; my $out = decode("utf-8", $text); # warn("app: $out\n"); if ( $capturing || $out eq "" ) { $capturing .= $out . "\n"; if ( $out eq "" ) { $self->SetCursor(wxHOURGLASS_CURSOR); } elsif ( $out eq "" ) { $self->SetCursor(wxNullCursor); my ($title) = ($capturing =~ m{(.+?)}); #warn("captured $title: ", length($capturing), " characters\n"); my $panel = $self->{prefs_repwin} ? "d_htmlpanel" : "d_htmlpanel_$title"; $self->{$panel} ||= EB::Wx::Shell::HtmlViewer->new ($self, -1, $title); $self->{$panel}->Show(0); $self->{$panel}->html->SetPage($capturing); $self->{$panel}->htmltext = $capturing; $self->{$panel}->SetTitle($title); $self->{$panel}->Show(1); $capturing = ""; } } else { $self->{t_output}->AppendText($out."\n"); } } sub process_stderr { my ($self, $text) = @_; my $out = decode("utf-8", $text); # warn("err: $out\n"); $self->ProcessMessages($out); } sub ProcessMessages { my ($self, $err) = @_; return unless $err; my @err = split(/\n+/, $err); while ( @err ) { $err = shift(@err); my @i; if ( $err =~ /^\?+(.*)/ ) { $self->ShowText($err, wxRED); next unless $self->{prefs_errorpopup}; @i = ($1, _T("Fout"), wxOK|wxICON_ERROR); } elsif ( $err =~ /^\!+(.*)/ ) { $self->ShowText($err, Wx::Colour->new("magenta")); next unless $self->{prefs_warnpopup}; @i = ($1, _T("Waarschuwing"), wxOK|wxICON_WARNING); } else { $self->ShowText($err, wxGREEN); next unless $self->{prefs_infopopup}; @i = ($err, _T("Mededeling"), wxOK|wxICON_INFORMATION); } my $md = Wx::MessageDialog->new($self, @i, wxDefaultPosition); $md->ShowModal; $md->Destroy; } } sub OnTextEnter { my ($self, $event) = @_; # wxGlade: EB::Wx::Shell::MainFrame::OnTextEnter my $cmd = $self->{t_input}->GetValue; return unless $cmd; push(@{$self->{_cmd}}, $cmd) unless $cmd eq $self->{_cmd}->[-1]; $self->{_cmdptr} = $#{$self->{_cmd}} + 1; $self->{t_input}->SetValue(""); $cmd =~ s/ *\t */ /g; $self->RunCommand($cmd); $self->{t_input}->SetFocus(); # end wxGlade } sub OnSend { my ($self, $event) = @_; # wxGlade: EB::Wx::Shell::MainFrame::OnSend &OnTextEnter; # end wxGlade } sub OnEdit { my ($self, $event) = @_; # wxGlade: EB::Wx::Shell::MainFrame::OnEdit my $d = $self->{d_editdialog} ||= EB::Wx::Shell::EditDialog->new; my $t = $self->{t_input}->GetValue; $t =~ s/\t/\n/g; $d->{t_input}->SetValue($t); $d->{t_input}->SetInsertionPoint( $self->{t_input}->GetInsertionPoint ); $d->{t_input}->SetFocus; my $ret = $d->ShowModal; $d->Show(0); return unless $ret == wxID_APPLY; $t = $d->{t_input}->GetValue; $t =~ s/\n/\t/g; $self->{t_input}->SetValue($t); &OnTextEnter; # end wxGlade } sub OnOpen { my ($self, $event) = @_; # wxGlade: EB::Wx::Shell::MainFrame::OnOpen my $fd = Wx::FileDialog->new ($self, _T("Kies"), "", "", ".eekboek.conf;eekboek.conf", 0|wxFD_FILE_MUST_EXIST, wxDefaultPosition); my $ret = $fd->ShowModal; if ( $ret == wxID_OK ) { if ( $self->{_shell} ) { EB::DB->disconnect; undef $self->{_shell}; } $self->{_ebcfg} = $fd->GetPath; chdir(dirname($fd->GetPath)); $self->RunCommand(undef); } $fd->Destroy; # end wxGlade } sub OnQuit { my ($self, $event) = @_; # wxGlade: EB::Wx::Shell::MainFrame::OnQuit $self->SaveHistory; $self->sizepos_save; $self->SavePreferences; foreach ( grep( /^d_htmlpanel/, keys(%$self) ) ) { $self->{$_}->OnClose; } foreach ( grep( /^d_.*dialog/, keys(%$self) ) ) { $self->{$_}->Destroy; } $self->Destroy; # end wxGlade } sub PutOnHistory { my ($self, $cmd) = @_; return if $cmd eq ""; $cmd =~ s/\s+--gen-wxhtml//; return if @{$self->{_cmd}} && $cmd eq $self->{_cmd}->[-1]; return if exists $self->{_cmd}->[$self->{_cmdptr}] && $cmd eq $self->{_cmd}->[$self->{_cmdptr}]; push(@{$self->{_cmd}}, $cmd); } use Wx qw(:keycode); sub OnChar { my ($self, $ctl, $event) = @_; # Get key code and char, if ordinary. my $k = $event->GetKeyCode; my $c = ($k < WXK_START) ? pack("C", $k) : ""; if ( $k == WXK_UP && $self->{_cmdptr} > 0 ) { $self->PutOnHistory($ctl->GetValue); $ctl->SetValue($self->{_cmd}->[--$self->{_cmdptr}]); $ctl->SetInsertionPointEnd; } elsif ( $k == WXK_DOWN && $self->{_cmdptr} < $#{$self->{_cmd}} ) { $self->PutOnHistory($ctl->GetValue); $ctl->SetValue($self->{_cmd}->[++$self->{_cmdptr}]); $ctl->SetInsertionPointEnd; } elsif ( $k == WXK_RETURN && $event->ControlDown ) { $self->OnEdit($event); } elsif ( $k == WXK_TAB || $k == WXK_RETURN || $k >= WXK_START || $event->HasModifiers ) { # Common controls. $event->Skip; return; } else { $event->Skip; } } sub OnHelp { my ($self, $event) = @_; # wxGlade: EB::Wx::Shell::MainFrame::OnHelp require EB::Wx::Help; my $h = EB::Wx::Help->new; $h->show_html_help; # end wxGlade } sub OnAbout { my ($self, $event) = @_; # wxGlade: EB::Wx::Shell::MainFrame::OnAbout my $year = 1900 + (localtime(time))[5]; # Sometimes version numbers are localized... my $dd = sub { my $v = $_[0]; $v =~ s/,/./g; $v }; my $md = Wx::MessageDialog->new ($self, __x("{pkg} {app} versie {ver}", pkg => $EekBoek::PACKAGE, app => "WxShell", ver => $dd->($EekBoek::VERSION))."\n". "Copyright 2007-$year Squirrel Consultancy\n\n". __x("Geschreven door {author}", author => "Johan Vromans")."\n". "\n". "http://www.squirrel.nl\n". __x("Voor ondersteuning: {url}", url => "http://www.eekboek.nl/support.html")."\n". "\n". __x("GUI ontwerp met {wxglade}", wxglade => "wxGlade, http://wxglade.sourceforge.net")."\n\n". __x("{pkg} versie {ver}", pkg => "Perl", ver => $dd->(sprintf("%vd",$^V)))."\n". __x("{pkg} versie {ver}", pkg => "WxPerl", ver => $dd->($Wx::VERSION))."\n". __x("{pkg} versie {ver}", pkg => "wxWidgets", ver => $dd->(Wx::wxVERSION))."\n". ( $App::Packager::PACKAGED ? __x("{pkg} versie {ver}", pkg => App::Packager::Packager(), ver => $dd->(App::Packager::Version()))."\n" : () ), __x("Over {pkg} {app}", pkg => $EekBoek::PACKAGE, app => "WxShell"), wxOK|wxICON_INFORMATION, wxDefaultPosition); $md->ShowModal; $md->Destroy; # end wxGlade } sub OnSupport { my ($self, $event) = @_; # wxGlade: EB::Wx::Shell::MainFrame::OnSupport my $title = _T("Ondersteuning"); my $md = EB::Wx::Shell::HtmlViewer->new($self, -1, $title); $md->info_only; $md->html->SetPage(_T(<Voor het uitwisselen van ervaringen, vragen om ondersteuning e.d. kunt u zich abonneren op de mailing list voor gebruikers op SourceForge.

De EekBoek gebruikers houden zelf een wiki bij met tips en andere wetenswaardigheden.

EekBoek kan gratis worden gedownload en gebruikt. Mocht u echter aanvullende wensen hebben op het gebied van ondersteuning dan kan dat ook. Squirrel Consultancy is gaarne bereid u betaalde ondersteuning te bieden, bijvoorbeeld bij het installeren van EekBoek, het opzetten van administraties, en het overzetten van uw bestaande administraties naar EekBoek. Ook kunnen specifieke uitbreidingen of aanpassingen naar uw wens worden gerealiseerd.

Voor meer informatie: info\@squirrel.nl.

EOD $md->SetTitle($title); $md->ShowModal; $md->Destroy; # end wxGlade } sub OnClear { my ($self, $event) = @_; # wxGlade: EB::Wx::Shell::MainFrame::OnClear $self->{t_output}->SetValue(""); # end wxGlade } sub OnPrefs { my ($self, $event) = @_; # wxGlade: EB::Wx::Shell::MainFrame::OnPrefs $self->{d_prefs} ||= EB::Wx::Shell::PreferencesDialog->new($self, -1, "Preferences"); for ( keys( %$prefctl ) ) { if ( exists $self->{d_prefs}->{"cx_$_"} ) { $self->{d_prefs}->{"cx_$_"}->SetValue( $self->{"prefs_$_"} ); } elsif ( exists $self->{d_prefs}->{"spin_$_"} ) { $self->{d_prefs}->{"spin_$_"}->SetValue( $self->{"prefs_$_"} ); } } my $ret = $self->{d_prefs}->ShowModal; if ( $ret == wxID_OK ) { for ( keys( %$prefctl ) ) { if ( exists $self->{d_prefs}->{"cx_$_"} ) { $self->{"prefs_$_"} = $self->{d_prefs}->{"cx_$_"}->GetValue; } elsif ( exists $self->{d_prefs}->{"spin_$_"} ) { $self->{"prefs_$_"} = $self->{d_prefs}->{"spin_$_"}->GetValue; } } } # end wxGlade } sub FillHistory { my ($self, $histfile) = @_; $self->{_histfile} = $histfile; $self->{_cmd} = []; $self->{_cmdptr} = 0; if ( -s $histfile ) { my $fh; return unless open($fh, "<:encoding(utf-8)", $histfile); my $prev = ''; while ( <$fh> ) { chomp; next if $_ eq $prev; $self->PutOnHistory($_); $prev = $_; } close($fh); } $self->{_cmdinit} = $self->{_cmdptr} = $#{$self->{_cmd}} + 1; } sub GetPreferences { my ( $self ) = @_; my $conf = Wx::ConfigBase::Get; for ( keys( %$prefctl ) ) { $self->{"prefs_$_"} = $conf->ReadInt( "preferences/$_", $prefctl->{$_} ); } } sub SaveHistory { my $self = shift; my $fh; my $histfile = $self->{_histfile}; $self->{_cmdinit} = $self->{_cmdptr} - $self->{prefs_histlines}; $self->{_cmdinit} = 0 if $self->{_cmdinit} < 0; return unless open($fh, ">:encoding(utf-8)", $histfile); while ( $self->{_cmdinit} < $self->{_cmdptr} ) { print { $fh } ($self->{_cmd}->[$self->{_cmdinit}], "\n"); $self->{_cmdinit}++; } close($fh); } sub SavePreferences { my ( $self ) = @_; my $conf = Wx::ConfigBase::Get; for ( keys( %$prefctl ) ) { $conf->WriteInt( "preferences/$_", $self->{"prefs_$_"} ); } } sub OnMenuBal { my ($self, $event, $sub) = @_; # wxGlade: EB::Wx::Shell::MainFrame::OnMenuBal if ( defined $sub && $sub >= 0 ) { $self->_cmd("balans --verdicht --detail=$sub --gen-wxhtml\n"); } else { $self->_cmd("balans --gen-wxhtml\n"); } # end wxGlade } sub OnMenuRes { my ($self, $event, $sub) = @_; # wxGlade: EB::Wx::Shell::MainFrame::OnMenuRes if ( defined $sub && $sub >= 0 ) { $self->_cmd("result --verdicht --detail=$sub --gen-wxhtml\n"); } else { $self->_cmd("result --gen-wxhtml\n"); } # end wxGlade } sub OnMenuAP { my ($self, $event) = @_; # wxGlade: EB::Wx::Shell::MainFrame::OnMenuAP $self->_cmd("crediteuren --gen-wxhtml\n"); # end wxGlade } sub OnMenuAR { my ($self, $event) = @_; # wxGlade: EB::Wx::Shell::MainFrame::OnMenuAR $self->_cmd("debiteuren --gen-wxhtml\n"); # end wxGlade } sub OnMenuVAT { my ($self, $event) = @_; # wxGlade: EB::Wx::Shell::MainFrame::OnMenuAR $self->_cmd("btwaangifte --gen-wxhtml\n"); # end wxGlade } sub OnMenuUns { my ($self, $event) = @_; # wxGlade: EB::Wx::Shell::MainFrame::OnMenuUns $self->_cmd("openstaand --gen-wxhtml\n"); # end wxGlade } sub OnTrial { my ($self, $event) = @_; # wxGlade: EB::Wx::Shell::MainFrame::OnTrial $self->_cmd("proefensaldibalans --gen-wxhtml\n"); # end wxGlade } sub OnJournal { my ($self, $event) = @_; # wxGlade: EB::Wx::Shell::MainFrame::OnJournal $self->_cmd("journaal --gen-wxhtml\n"); # end wxGlade } #### Callbacks from HTML links sub _HTMLCallBack { my ($self, $command, $args) = @_; my $cmd = $command; $cmd .= " " . delete($args->{select}); while ( my($k,$v) = each( %$args ) ) { $cmd .= " --$k=$v"; } $cmd .= " --gen-wxhtml"; $self->_cmd($cmd."\n"); } sub ShowRJnl { shift->_HTMLCallBack( "journaal", @_ ) } sub ShowRGbk { shift->_HTMLCallBack( "grootboek", @_ ) } sub ShowRCrd { shift->_HTMLCallBack( "crediteuren", @_ ) } sub ShowRDeb { shift->_HTMLCallBack( "debiteuren", @_ ) } sub ShowRAtt { my ( $self, $args ) = @_; $self->_cmd("bijlage " . $args->{select}); } # end of class EB::Wx::Shell::MainFrame 1; EekBoek-2.030.1/lib/EB/Wx/Shell/Main.pm0000644000400000040000000001377113044363347014723 0ustar jvjv#! perl -- -*- coding: utf-8 -*- use utf8; # Author : Johan Vromans # Created On : Sun Jul 31 23:35:10 2005 # Last Modified By: Johan Vromans # Last Modified On: Wed Feb 1 14:47:19 2017 # Update Count : 446 # Status : Unknown, Use with caution! ################ Common stuff ################ package main; our $cfg; our $app; use EB::Wx::FakeApp; package EB::Wx::Shell::Main; use strict; use warnings; use EekBoek; use EB; use Getopt::Long 2.13; ################ The Process ################ my $app_dir; use base qw(Wx::App); use Wx qw[ wxBITMAP_TYPE_ANY wxCONFIG_USE_LOCAL_FILE wxDefaultPosition wxDefaultSize wxICON_ERROR wxOK ]; sub OnInit { my( $self ) = shift; return 1; } ################ Run ################ sub run { my ( $pkg, $opts ) = @_; $opts = {} unless defined $opts; binmode(STDOUT, ":encoding(utf8)"); binmode(STDERR, ":encoding(utf8)"); # Preliminary initialize config. EB->app_init( { app => $EekBoek::PACKAGE } ); # Command line options. $opts = { #config, # config file #nostdconf, # skip standard configs #define, # config overrides verbose => 0, # verbose processing # Development options (not shown with -help). debug => 0, # debugging trace => 0, # trace (show process) test => 0, # test mode. # Let supplied options override. %$opts, }; # Process command line options. app_options($opts); # Post-processing. $opts->{trace} |= ($opts->{debug} || $opts->{test}); # Initialize config. EB->app_init( { app => $EekBoek::PACKAGE, %$opts } ); if ( $opts->{printconfig} ) { $cfg->printconf( \@ARGV ); exit; } $app_dir = $cfg->user_dir; mkdir($app_dir) unless -d $app_dir; Wx::InitAllImageHandlers(); if ( $opts->{showhelp} ) { # Standalone help browser. require EB::Wx::Help; my $h = EB::Wx::Help->new(1); $h->show_html_help; exit; } #### WHAT THE ***** IS GOING ON HERE???? #*Fcntl::O_NOINHERIT = sub() { 0 }; #*Fcntl::O_EXLOCK = sub() { 0 }; #*Fcntl::O_TEMPORARY = sub() { 0 }; if ( ( defined($opts->{wizard}) ? $opts->{wizard} : 1 ) && !$opts->{config} ) { require EB::Wx::IniWiz; EB::Wx::IniWiz->run($opts); # sets $opts->{runeb} return unless $opts->{runeb}; EB->app_init( { app => $EekBoek::PACKAGE, %$opts } ); } my $app = EB::Wx::Shell::Main->new(); $app->SetAppName($EekBoek::PACKAGE); $app->SetVendorName("Squirrel Consultancy"); if ( $^O =~ /^mswin/i ) { Wx::ConfigBase::Get->SetPath("/ebwxshell"); } else { Wx::ConfigBase::Set (Wx::FileConfig->new ( $app->GetAppName() , $app->GetVendorName() , $cfg->user_dir("ebwxshell"), '', wxCONFIG_USE_LOCAL_FILE, )); } my $histfile = $cfg->user_dir("history"); require EB::Wx::Shell::MainFrame; my $frame = EB::Wx::Shell::MainFrame->new (undef, undef, $EekBoek::PACKAGE, wxDefaultPosition, wxDefaultSize, undef, $EekBoek::PACKAGE); my $config = $opts->{config}; unless ( $config ) { $config = $cfg->std_config; $config = $cfg->std_config_alt unless -f $config; } $frame->{_ebcfg} = $config if -e $config; $frame->FillHistory($histfile); $frame->GetPreferences; Wx::ConfigBase::Get->Write('general/appversion', $EekBoek::VERSION); my $icon = Wx::Icon->new(); $icon->CopyFromBitmap(Wx::Bitmap->new("eb.jpg", wxBITMAP_TYPE_ANY)); $frame->SetIcon($icon); $app->SetTopWindow($frame); $frame->Show(1); $frame->RunCommand(undef); $app->MainLoop(); } # Since Wx::Bitmap cannot be convinced to use a search path, we # need a stronger method... my $wxbitmapnew = \&Wx::Bitmap::new; no warnings 'redefine'; *Wx::Bitmap::new = sub { # Only handle Wx::Bitmap->new(file, type) case. goto &$wxbitmapnew if @_ != 3 || -f $_[1]; my ($self, @rest) = @_; $rest[0] = EB::findlib("Wx/icons/".File::Basename::basename($rest[0])); $wxbitmapnew->($self, @rest); }; use warnings 'redefine'; ################ Subroutines ################ sub app_options { my ( $opts ) = @_; # Filter psn arguments (Mac OSX). @ARGV = grep { ! /psn_\d_\d+/ } @ARGV; # Process options, if any. # Make sure defaults are set before returning! return unless @ARGV > 0; # Store valid & trap invalid option warnings my @optionerrors; local $SIG{__WARN__} = sub { my $warning = shift; push(@optionerrors, $warning); }; Getopt::Long::Configure(qw(no_ignore_case)); if ( !GetOptions( $opts, 'define|D=s%', 'nostdconf|X', 'config|f=s', 'admdir=s', 'open=s', 'wizard!', 'printconfig|P', 'showhelp', 'ident', 'verbose', 'trace!', 'help|?', 'debug', ) or $opts->{help} ) { app_usage(); } app_usage() if @ARGV && !$opts->{printconfig}; app_ident() if $opts->{ident}; return unless @optionerrors; my $d = Wx::MessageDialog->new ( undef, join("\n", @optionerrors), "Opstartregelfouten", wxICON_ERROR|wxOK, wxDefaultPosition ); $d->ShowModal; $d->Destroy; CORE::exit(2); } sub app_ident { return; warn(__x("Dit is {pkg} [{name} {version}]", pkg => $EekBoek::PACKAGE, name => "WxShell", version => $EekBoek::VERSION) . "\n"); } sub app_usage { my ($exit) = @_; app_ident(); warn _T(< '_T'; # end wxGlade use Wx qw[ wxADJUST_MINSIZE wxALIGN_CENTER_VERTICAL wxALL wxDEFAULT_DIALOG_STYLE wxDefaultPosition wxDefaultSize wxEXPAND wxHORIZONTAL wxID_CANCEL wxID_OK wxLEFT wxRIGHT wxSP_ARROW_KEYS wxTOP wxVERTICAL ]; sub new { my( $self, $parent, $id, $title, $pos, $size, $style, $name ) = @_; $parent = undef unless defined $parent; $id = -1 unless defined $id; $title = "" unless defined $title; $pos = wxDefaultPosition unless defined $pos; $size = wxDefaultSize unless defined $size; $name = "" unless defined $name; # begin wxGlade: EB::Wx::Shell::PreferencesDialog::new $style = wxDEFAULT_DIALOG_STYLE unless defined $style; $self = $self->SUPER::new( $parent, $id, $title, $pos, $size, $style, $name ); $self->{sz_prefs_inner_staticbox} = Wx::StaticBox->new($self, -1, _T("Voorkeuren") ); $self->{cx_repwin} = Wx::CheckBox->new($self, -1, _T("Rapporten in hetzelfde venster"), wxDefaultPosition, wxDefaultSize, ); $self->{cx_errorpopup} = Wx::CheckBox->new($self, -1, _T("Popup window voor foutboodschappen"), wxDefaultPosition, wxDefaultSize, ); $self->{cx_warnpopup} = Wx::CheckBox->new($self, -1, _T("Popup window voor waarschuwingen"), wxDefaultPosition, wxDefaultSize, ); $self->{cx_infopopup} = Wx::CheckBox->new($self, -1, _T("Popup window voor mededelingen"), wxDefaultPosition, wxDefaultSize, ); $self->{l_histlines} = Wx::StaticText->new($self, -1, _T("Aantal te bewaren regels invoer historie:"), wxDefaultPosition, wxDefaultSize, ); $self->{spin_histlines} = Wx::SpinCtrl->new($self, -1, "200", wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 99999, 200); $self->{b_prefs_cancel} = Wx::Button->new($self, wxID_CANCEL, ""); $self->{b_prefs_ok} = Wx::Button->new($self, wxID_OK, ""); $self->__set_properties(); $self->__do_layout(); Wx::Event::EVT_BUTTON($self, $self->{b_prefs_cancel}->GetId, \&OnCancel); Wx::Event::EVT_BUTTON($self, $self->{b_prefs_ok}->GetId, \&OnAccept); # end wxGlade return $self; } sub __set_properties { my $self = shift; # begin wxGlade: EB::Wx::Shell::PreferencesDialog::__set_properties $self->SetTitle(_T("Voorkeursinstellingen")); $self->{cx_errorpopup}->SetValue(1); $self->{cx_warnpopup}->SetValue(1); $self->{cx_infopopup}->SetValue(1); $self->{b_prefs_ok}->SetDefault(); # end wxGlade } sub __do_layout { my $self = shift; # begin wxGlade: EB::Wx::Shell::PreferencesDialog::__do_layout $self->{sz_prefs_outer} = Wx::BoxSizer->new(wxVERTICAL); $self->{sz_prefs_buttons} = Wx::BoxSizer->new(wxHORIZONTAL); $self->{sz_prefs_inner}= Wx::StaticBoxSizer->new($self->{sz_prefs_inner_staticbox}, wxVERTICAL); $self->{sz_prefs} = Wx::BoxSizer->new(wxVERTICAL); $self->{sz_histlines} = Wx::BoxSizer->new(wxHORIZONTAL); $self->{sz_prefs}->Add($self->{cx_repwin}, 0, wxADJUST_MINSIZE, 0); $self->{sz_prefs}->Add($self->{cx_errorpopup}, 0, wxADJUST_MINSIZE, 0); $self->{sz_prefs}->Add($self->{cx_warnpopup}, 0, wxADJUST_MINSIZE, 0); $self->{sz_prefs}->Add($self->{cx_infopopup}, 0, wxADJUST_MINSIZE, 0); $self->{sz_histlines}->Add($self->{l_histlines}, 0, wxRIGHT|wxALIGN_CENTER_VERTICAL|wxADJUST_MINSIZE, 5); $self->{sz_histlines}->Add($self->{spin_histlines}, 0, wxALIGN_CENTER_VERTICAL|wxADJUST_MINSIZE, 0); $self->{sz_histlines}->Add(0, 0, 1, wxEXPAND|wxADJUST_MINSIZE, 0); $self->{sz_prefs}->Add($self->{sz_histlines}, 1, wxEXPAND, 0); $self->{sz_prefs}->Add(1, 5, 0, wxADJUST_MINSIZE, 0); $self->{sz_prefs_inner}->Add($self->{sz_prefs}, 1, wxLEFT|wxRIGHT|wxTOP|wxEXPAND, 5); $self->{sz_prefs_outer}->Add($self->{sz_prefs_inner}, 1, wxLEFT|wxRIGHT|wxTOP|wxEXPAND, 5); $self->{sz_prefs_buttons}->Add(5, 1, 1, wxEXPAND|wxADJUST_MINSIZE, 0); $self->{sz_prefs_buttons}->Add($self->{b_prefs_cancel}, 0, wxADJUST_MINSIZE, 0); $self->{sz_prefs_buttons}->Add($self->{b_prefs_ok}, 0, wxLEFT|wxADJUST_MINSIZE, 5); $self->{sz_prefs_outer}->Add($self->{sz_prefs_buttons}, 0, wxALL|wxEXPAND, 5); $self->SetSizer($self->{sz_prefs_outer}); $self->{sz_prefs_outer}->Fit($self); $self->Layout(); # end wxGlade } sub OnCancel { my ($self, $event) = @_; # wxGlade: EB::Wx::Shell::PreferencesDialog::OnCancel $event->Skip; # end wxGlade } sub OnAccept { my ($self, $event) = @_; # wxGlade: EB::Wx::Shell::PreferencesDialog::OnAccept $event->Skip; # end wxGlade } # end of class EB::Wx::Shell::PreferencesDialog 1; EekBoek-2.030.1/lib/EB/Wx/Shell/EditDialog.pm0000644000400000040000000000542712725476601016046 0ustar jvjv#! perl package main; use strict; package EB::Wx::Shell::EditDialog; use base qw(Wx::Dialog); use base qw(EB::Wx::Shell::Window); use strict; use Wx qw[ wxADJUST_MINSIZE wxALL wxBOTTOM wxDEFAULT_DIALOG_STYLE wxDefaultPosition wxDefaultSize wxEXPAND wxHORIZONTAL wxID_APPLY wxID_CANCEL wxRESIZE_BORDER wxRIGHT wxTE_MULTILINE wxTHICK_FRAME wxVERTICAL ]; use Wx::Locale gettext => '_T'; sub new { my( $self, $parent, $id, $title, $pos, $size, $style, $name ) = @_; $parent = undef unless defined $parent; $id = -1 unless defined $id; $title = "" unless defined $title; $pos = wxDefaultPosition unless defined $pos; $size = wxDefaultSize unless defined $size; $name = "" unless defined $name; # begin wxGlade: EB::Wx::Shell::EditDialog::new $style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER|wxTHICK_FRAME unless defined $style; $self = $self->SUPER::new( $parent, $id, $title, $pos, $size, $style, $name ); $self->{t_input} = Wx::TextCtrl->new($self, -1, "", wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE); $self->{b_cancel} = Wx::Button->new($self, wxID_CANCEL, ""); $self->{b_apply} = Wx::Button->new($self, wxID_APPLY, ""); $self->__set_properties(); $self->__do_layout(); Wx::Event::EVT_BUTTON($self, $self->{b_cancel}->GetId, \&OnCancel); Wx::Event::EVT_BUTTON($self, $self->{b_apply}->GetId, \&OnApply); # end wxGlade $self->sizepos_restore(lc($title)); return $self; } sub __set_properties { my $self = shift; # begin wxGlade: EB::Wx::Shell::EditDialog::__set_properties $self->SetTitle(_T("Wijzigen invoerregel")); $self->SetSize(Wx::Size->new(582, 318)); $self->{t_input}->SetFocus(); # end wxGlade } sub __do_layout { my $self = shift; # begin wxGlade: EB::Wx::Shell::EditDialog::__do_layout $self->{sz_main} = Wx::BoxSizer->new(wxVERTICAL); $self->{sz_buttons} = Wx::BoxSizer->new(wxHORIZONTAL); $self->{sz_main}->Add($self->{t_input}, 1, wxALL|wxEXPAND|wxADJUST_MINSIZE, 5); $self->{sz_buttons}->Add(5, 0, 1, wxEXPAND|wxADJUST_MINSIZE, 0); $self->{sz_buttons}->Add($self->{b_cancel}, 0, wxRIGHT|wxBOTTOM|wxADJUST_MINSIZE, 5); $self->{sz_buttons}->Add($self->{b_apply}, 0, wxRIGHT|wxBOTTOM|wxADJUST_MINSIZE, 5); $self->{sz_main}->Add($self->{sz_buttons}, 0, wxEXPAND, 0); $self->SetSizer($self->{sz_main}); $self->Layout(); # end wxGlade } sub OnCancel { my ($self, $event) = @_; # wxGlade: EB::Wx::Shell::EditDialog::OnCancel $self->sizepos_save; $event->Skip; # end wxGlade } sub OnApply { my ($self, $event) = @_; # wxGlade: EB::Wx::Shell::EditDialog::OnApply $self->sizepos_save; $self->EndModal( wxID_APPLY ); # end wxGlade } # end of class EB::Wx::Shell::EditDialog 1; EekBoek-2.030.1/lib/EB/Tools/0000755000400000040000000000000013151742350013115 5ustar jvjvEekBoek-2.030.1/lib/EB/Tools/MiniAdm.pm0000644000400000040000000003474413044346163015010 0ustar jvjv#! perl -- -*- coding: utf-8 -*- use utf8; # MiniAdm.pm -- # Author : Johan Vromans # Created On : Sun Oct 4 15:11:05 2009 # Last Modified By: Johan Vromans # Last Modified On: Wed Feb 19 14:50:46 2014 # Update Count : 113 # Status : Unknown, Use with caution! package main; use strict; use warnings; use Encode; our$cfg; package EB::Tools::MiniAdm; #use EB::Config; use EB; sub donotclobber { my ( $self, $opts ) = @_; my @files = qw( schema.dat opening.eb mutaties.eb relaties.eb ); push( @files, $cfg->std_config ); my $tally = 0; foreach ( @files ) { $tally++ if -f $_; } if ( $tally == @files ) { warn("?"._T("GESTOPT: Er is al een administratie aangemaakt")."\n"); return; } if ( $tally ) { warn("?"._T("GESTOPT: Er is al een administratie gedeeltelijk aangemaakt")."\n"); return; } return 1; } sub build { my ( $self, $opts ) = @_; return unless $self->donotclobber; return unless $self->sanitize($opts); # Generate. $self->generate_config($opts); $self->generate_schema($opts); $self->generate_relaties($opts); $self->generate_opening($opts); $self->generate_mutaties($opts); 1; } sub sanitize { my ( $self, $opts ) = @_; $opts->{adm_naam} ||= _T("Demo administratie"); $opts->{adm_btwperiode} ||= "jaar" if $opts->{has_btw}; $opts->{adm_begindatum} ||= 1900 + (localtime(time))[5]; $opts->{adm_boekjaarcode} ||= 1900 + (localtime(time))[5]; for ( qw(naam boekjaarcode) ) { $opts->{ "adm_$_" } =~ s/"/_/g; } $opts->{db_naam} ||= "demoadm"; $opts->{db_driver} ||= "sqlite"; 1; } use Archive::Zip qw( :ERROR_CODES :CONSTANTS ); use Encode; sub generate_file { my ( $self, $file, $type, $opts, $writer ) = @_; if ( ! $opts->{_zip} && $opts->{template} ) { $opts->{_zip} = Archive::Zip->new(); die( "?".__x("Probleem met het benaderen van {file}: {err}", file => $opts->{template}, err => "$!")."\n" ) unless $opts->{_zip}->read( $opts->{template} ) == AZ_OK; } my $m; if ( $opts->{_zip} ) { $m = $opts->{_zip}->memberNamed($file); } my $fd; if ( $opts->{_zip} && $m ) { my $data = $opts->{_zip}->contents($m); die( "?".__x("Probleem met het aanmaken van {file}: Zip error", file => $file)."\n" ) unless $data; #### TODO: Make more generic. if ( $file eq "opening.eb" ) { for ( $data ) { s/^(\s*adm_naam\s+).*$ /$1"$opts->{adm_naam}" /mgx; s/^(\s*adm_btwperiode\s+).*$ /$1"$opts->{adm_btwperiode}" /mgx; s/^(\s*adm_begindatum\s+).*$ /$1"$opts->{adm_begindatum}" /mgx; s/^(\s*adm_boekjaarcode\s+).*$/$1"$opts->{adm_boekjaarcode}"/mgx; } } $data =~ s/\r//g; $data = decode_utf8($data); $data = [ split(/\n/, $data) ]; $writer = sub { print { $fd } $_, "\n" foreach @$data }; $type = undef; } open( $fd, '>:encoding(utf-8)', $file ) or die( "?".__x("Probleem met het aanmaken van {file}: {err}", file => $file, err => "$!")."\n" ); if ( $type ) { print { $fd } ("# EekBoek $type\n", "# Content-Type: text/plain; charset = UTF-8\n\n"); } if ( $writer ) { $writer->( $self, $fd ); } close( $fd ) or die( "?".__x("Probleem met het afsluiten van {file}: {err}", file => $file, err => "$!")."\n" ); } sub generate_config { my ( $self, $opts ) = @_; return if exists $opts->{create_config} && !$opts->{create_config}; my $fmt = "%-10.10s = %s\n"; $self->generate_file ( $cfg->std_config, undef, $opts, sub { my ( $self, $fd ) = @_; if ( $opts->{lang} ) { print { $fd } ("[locale]\n"); printf { $fd } ( $fmt, "lang", $opts->{lang} ); print { $fd } ("\n"); } print { $fd } ("[database]\n"); printf { $fd } ( $fmt, "name", $opts->{db_naam} ); foreach ( qw( driver host port user password path ) ) { next unless defined $opts->{"db_$_"}; printf { $fd } ( $fmt, $_, $opts->{"db_$_"} ) } } ); } sub generate_schema { my ( $self, $opts ) = @_; return if exists $opts->{create_schema} && !$opts->{create_schema}; # has_btw # has_crediteuren # has_crediteuren # has_kas # has_bank $self->generate_file ( "schema.dat", _T("Rekeningschema"), $opts, sub { my ( $self, $fd ) = @_; print { $fd } ( <<'EOD' ); # Dit bestand definiëert alle vaste gegevens van een administratie of # groep administraties: het rekeningschema (balansrekeningen en # resultaatrekeningen), de dagboeken en de BTW tarieven. # # Algemene syntaxregels: # # * Lege regels en regels die beginnen met een hekje # worden niet # geïnterpreteerd. # * Een niet-ingesprongen tekst introduceert een nieuw onderdeel. # * Alle ingesprongen regels zijn gegevens voor dat onderdeel. # REKENINGSCHEMA # # Het rekeningschema is hiërarchisch opgezet volgende de beproefde # methode Bakker. De hoofdverdichtingen lopen van 1 t/m 9, de # verdichtingen t/m 99. De grootboekrekeningen zijn verdeeld in # balansrekeningen en resultaatrekeningen. # # De omschrijving van de grootboekrekeningen wordt voorafgegaan door # een vlaggetje, een letter die resp. Debet/Credit (voor # balansrekeningen) en Kosten/Omzet/Neutraal (voor resultaatrekeningen) # aangeeft. De omschrijving wordt indien nodig gevolgd door extra EOD if ( $opts->{has_btw} ) { print { $fd } ( <<'EOD' ); # informatie. Voor grootboekrekeningen kan op deze wijze de BTW # tariefstelling worden aangegeven die op deze rekening van toepassing # is: # # :btw=nul # :btw=hoog # :btw=laag # :btw=privé # :btw=anders EOD } else { print { $fd } ( <<'EOD' ); # informatie. EOD } print { $fd } ( <<'EOD' ); # # Ook is het mogelijk aan te geven dat een rekening een koppeling # (speciale betekenis) heeft met :koppeling=xxx. De volgende koppelingen # zijn mogelijk: # EOD if ( $opts->{has_crediteuren} ) { print { $fd } ( <<'EOD' ); # crd de standaard tegenrekening (Crediteuren) voor inkoopboekingen EOD } if ( $opts->{has_debiteuren} ) { print { $fd } ( <<'EOD' ); # deb de standaard tegenrekening (Debiteuren) voor verkoopboekingen EOD } if ( $opts->{has_btw} ) { print { $fd } ( <<'EOD' ); # btw_ih de rekening voor BTW boekingen voor inkopen, hoog tarief # btw_il idem, laag tarief # btw_vh idem, verkopen, hoog tarief # btw_vl idem, laag tarief # btw_ph idem, privé, hoog tarief # btw_pl idem, laag tarief # btw_ah idem, anders, hoog tarief # btw_al idem, laag tarief # btw_ok rekening voor de betaalde BTW EOD } print { $fd } ( <<'EOD' ); # winst rekening waarop de winst wordt geboekt # # De koppeling winst is verplicht en moet altijd in een administratie # voorkomen in verband met de jaarafsluiting. EOD if ( $opts->{has_btw} ) { print { $fd } ( <<'EOD' ); # De koppelingen voor BTW moeten worden opgegeven indien BTW # van toepassing is op de administratie. EOD } print { $fd } ( <<'EOD' ); # De koppelingen voor Crediteuren en Debiteuren moeten worden # opgegeven indien er inkoop dan wel verkoopdagboeken zijn die gebruik # maken van de standaardwaarden (dus zelf geen tegenrekening hebben # opgegeven). # Normaal lopen hoofdverdichtingen van 1 t/m 9, en verdichtingen # van 10 t/m 99. Indien daarvan wordt afgeweken kan dit worden opgegeven # met de opdracht "Verdichting". De twee getallen geven het hoogste # nummer voor hoofdverdichtingen resp. verdichtingen. Verdichting 9 99 # De nummers van de grootboekrekeningen worden geacht groter te zijn # dan de maximale verdichting. Daarvan kan worden afgeweken door # middels voorloopnullen de _lengte_ van het nummer groter te maken # dan de lengte van de maximale verdichting. Als bijvoorbeeld 99 de # maximale verdichting is, dan geeft 001 een grootboekrekening met # nummer 1 aan. Balansrekeningen 1 Vaste Activa 11 Materiële vaste activa 2 Vlottende activa 21 Handelsvoorraden 22 Vorderingen EOD if ( $opts->{has_debiteuren} ) { print { $fd } ( <<'EOD' ); 2200 D Debiteuren :koppeling=deb EOD } print { $fd } ( <<'EOD' ); 23 Liquide middelen EOD if ( $opts->{has_kas} ) { print { $fd } ( <<"EOD" ); 2300 D Kas EOD } if ( $opts->{has_bank} ) { print { $fd } ( <<"EOD" ); 2320 D Bank EOD } print { $fd } ( <<"EOD" ); 2390 D Kruisposten 3 Eigen vermogen 31 Kapitaal 3100 C Kapitaal de heer/mevrouw :koppeling=winst 3110 C Privé stortingen 3120 D Privé opnamen 4 Vreemd vermogen 41 Leveranciers kredieten EOD if ( $opts->{has_crediteuren} ) { print { $fd } ( <<'EOD' ); 4100 C Crediteuren :koppeling=crd EOD } print { $fd } ( <<'EOD' ); 42 Belastingen & soc. lasten EOD if ( $opts->{has_btw} ) { print { $fd } ( <<"EOD" ); 4200 C BTW Verkoop Hoog :koppeling=btw_vh 4210 C BTW Verkoop Laag :koppeling=btw_vl 4212 C BTW Verkoop Privé :koppeling=btw_vp 4214 C BTW Verkoop Anders :koppeling=btw_va 4220 D BTW Inkoop Hoog :koppeling=btw_ih 4230 D BTW Inkoop Laag :koppeling=btw_il 4232 D BTW Inkoop Privé :koppeling=btw_ip 4234 D BTW Inkoop Anders :koppeling=btw_ia 4290 C Omzetbelasting betaald :koppeling=btw_ok EOD } my $btw_hoog = ""; my $btw_laag = ""; if ( $opts->{has_btw} ) { $btw_hoog = ":btw=hoog"; $btw_laag = ":btw=laag"; } print { $fd } ( <<"EOD" ); Resultaatrekeningen 6 Kosten 61 Verkoopkosten 62 Huisvestingskosten 63 Bedrijfsvoering 67 Contributies & abonnementen 69 Algemene kosten EOD if ( $opts->{has_bank} ) { print { $fd } ( <<"EOD" ); 6980 K Bankkosten EOD } if ( $opts->{has_kas} ) { print { $fd } ( <<"EOD" ); 6981 K Kasverschillen EOD } print { $fd } ( <<"EOD" ); 8 Bedrijfsopbrengsten 89 Omzet Diversen EOD if ( $opts->{has_btw} ) { print { $fd } ( <<'EOD' ); 8900 O Omzet diversen BTW hoog :btw=hoog 8910 O Omzet diversen BTW laag :btw=laag 8920 O Omzet diversen BTW vrij EOD } print { $fd } ( <<"EOD" ); 9 Financiële baten & lasten 91 Rente baten EOD if ( $opts->{has_bank} ) { print { $fd } ( <<"EOD" ); 9120 O Rente bate Bank EOD } print { $fd } ( <<"EOD" ); 92 Rente- en overige financiële lasten EOD if ( $opts->{has_bank} ) { print { $fd } ( <<"EOD" ); 9220 K Rente last Bank EOD } print { $fd } ( <<"EOD" ); 93 Overige baten EOD if ( $opts->{has_btw} ) { print { $fd } ( <<"EOD" ); 9390 O Kleine ondernemersregeling EOD } print { $fd } ( <<"EOD" ); # DAGBOEKEN # # EekBoek ondersteunt vijf soorten dagboeken: Kas, Bank, Inkoop, # Verkoop en Memoriaal. Er kunnen een in principe onbeperkt aantal # dagboeken worden aangemaakt. # In de eerste kolom wordt de korte naam (code) voor het dagboek # opgegeven. Verder moet voor elk dagboek worden opgegeven van welk # type het is. Voor dagboeken van het type Kas en Bank moet een # tegenrekening worden opgegeven, voor de overige dagboeken mag een # tegenrekening worden opgegeven. # De optie :dc kan worden gebruikt om aan te geven dat het journaal # voor dit dagboek de boekstuktotalen in gescheiden debet en credit # moet tonen. Dagboeken EOD if ( $opts->{has_crediteuren} ) { print { $fd } ( <<"EOD" ); I Inkoop :type=inkoop EOD } if ( $opts->{has_debiteuren} ) { print { $fd } ( <<"EOD" ); V Verkoop :type=verkoop EOD } if ( $opts->{has_kas} ) { print { $fd } ( <<"EOD" ); K Kas :type=kas :rekening=2300 EOD } if ( $opts->{has_bank} ) { print { $fd } ( <<"EOD" ); B Bank :type=bank :rekening=2320 EOD } print { $fd } ( <<"EOD" ); M Memoriaal :type=memoriaal EOD if ( $opts->{has_btw} ) { print { $fd } ( <<"EOD" ); # BTW TARIEVEN # # Er zijn vijf tariefgroepen: "hoog", "laag", "nul", "privé" en # "anders". De tariefgroep bepaalt het rekeningnummer waarop de # betreffende boeking plaatsvindt. # Binnen elke tariefgroep zijn meerdere tarieven mogelijk, hoewel dit # in de praktijk niet snel zal voorkomen. # In de eerste kolom wordt de code voor dit tarief opgegeven. Deze kan # o.m. worden gebruikt om expliciet een BTW tarief op te geven bij het # boeken. Voor elk gebruikt tarief (behalve die van groep "nul") moet # het percentage worden opgegeven. Met de aanduiding :exclusief kan # worden opgegeven dat boekingen op rekeningen met deze tariefgroep # standaard het bedrag exclusief BTW aangeven. # # BELANGRIJK: Mutaties die middels de command line shell of de API # worden uitgevoerd maken gebruik van het geassocieerde BTW tarief van # de grootboekrekeningen. Wijzigingen hierin kunnen dus consequenties # hebben voor de reeds in scripts vastgelegde boekingen. BTW Tarieven H21 BTW 21% :tariefgroep=hoog :perc=21,00 L06 BTW 6,0% :tariefgroep=laag :perc=06,00 P12 BTW Privé 12% :tariefgroep=privé :perc=12,00 EOD } print { $fd } ( <<"EOD" ); # Einde EekBoek schema EOD } ); } sub generate_relaties { my ( $self, $opts ) = @_; return if exists $opts->{create_relaties} && !$opts->{create_relaties}; $self->generate_file( "relaties.eb", _T("Relaties"), $opts ); } sub generate_opening { my ( $self, $opts ) = @_; return if exists $opts->{create_opening} && !$opts->{create_opening}; $self->generate_file ( "opening.eb", _T("Opening"), $opts, sub { my ( $self, $fd ) = @_; print { $fd } ( "adm_naam \"", $opts->{adm_naam}, "\"\n" ); print { $fd } ( "adm_btwperiode ", $opts->{adm_btwperiode}, "\n" ) if $opts->{has_btw}; print { $fd } ( "adm_begindatum \"", $opts->{adm_begindatum}, "\"\n" ); print { $fd } ( "adm_boekjaarcode \"", $opts->{adm_boekjaarcode}, "\"\n" ); print { $fd } ( "adm_open\n"); } ); } sub generate_mutaties { my ( $self, $opts ) = @_; return if exists $opts->{create_mutaties} && !$opts->{create_mutaties}; $self->generate_file( "mutaties.eb", _T("Mutaties"), $opts ); } 1; EekBoek-2.030.1/lib/EB/Tools/Einde.pm0000644000400000040000000002126012725476602014512 0ustar jvjv#! perl -- -*- coding: utf-8 -*- use utf8; # Einde.pm -- Eindejaarsverwerking # Author : Johan Vromans # Created On : Sun Oct 16 21:27:40 2005 # Last Modified By: Johan Vromans # Last Modified On: Sat Jun 19 00:42:33 2010 # Update Count : 247 # Status : Unknown, Use with caution! package main; our $cfg; our $dbh; package EB::Tools::Einde; use strict; use warnings; use EB; use EB::Format; use EB::Report; use EB::Report::GenBase; use EB::Report::Journal; use EB::Report::Open; sub new { my ($class) = @_; $class = ref($class) || $class; return bless {} => $class; } sub perform { my ($self, $args, $opts) = @_; # Akties: # Afboeken resultaatrekeningen -> Winstrekening # Afboeken BTW I/V H/L -> BTW Betaald my $tot = 0; my $date = $cfg->val(qw(internal now), iso8601date()); $date = $dbh->adm("end") unless $date lt $dbh->adm("end"); my $sth; my $rr; my $bky = $opts->{boekjaar}; my $def = $opts->{definitief}; my $eb; if ( $opts->{eb} ) { unless ( open($eb, '>:encoding(utf-8)', $opts->{eb}) ) { warn("?", __x("Fout tijdens het aanmaken van bestand {file}: {err}", file => $opts->{eb}, err => $!."")."\n"); return; } $opts->{eb_handle} = $eb; } my ($acc_id, $acc_desc, $acc_balance); warn("?",_T("Geen boekjaar opgegeven")."\n"), return unless $bky; $rr = $dbh->do("SELECT bky_begin, bky_end, bky_closed". " FROM Boekjaren". " WHERE bky_code = ?", $bky); warn("?",__x("Onbekend boekjaar: {bky}", bky => $bky)."\n"), return unless $rr; my ($begin, $end, $closed) = @$rr; if ( $closed ) { if ( $opts->{verwijder} ) { warn("?",__x("Boekjaar {bky} is definitief afgesloten", bky => $bky)."\n"); } else { warn("?",__x("Boekjaar {bky} is reeds definitief afgesloten", bky => $bky)."\n"); } return; } $dbh->begin_work; $dbh->sql_exec("DELETE FROM Boekjaarbalans where bkb_bky = ?", $bky)->finish; $dbh->commit, return if $opts->{verwijder}; $opts->{STYLE} = "journaal"; $opts->{LAYOUT} = [ { name => "date", title => _T("Datum"), width => $date_width, }, { name => "desc", title => _T("Boekstuk/Grootboek"), width => 30, }, { name => "acct", title => _T("Rek"), width => 5, align => ">", }, { name => "deb", title => _T("Debet"), width => $amount_width, align => ">", }, { name => "crd", title => _T("Credit"), width => $amount_width, align => ">", }, { name => "bsk", title => _T("Boekstuk/regel"), width => 30, }, { name => "rel", title => _T("Relatie"), width => 10, }, ]; my $rep; $rep = EB::Report::GenBase->backend(EB::Report::Journal::, $opts); my $tbl = EB::Report::->GetTAccountsBal($end); $sth = $dbh->sql_exec("SELECT acc_id, acc_desc, acc_balance". " FROM ${tbl}". " WHERE NOT acc_balres". " AND acc_balance <> 0". " ORDER BY acc_id"); my $edt = parse_date($end, undef, 1); my $dtot = 0; my $ctot = 0; my $did; my $desc; while ( $rr = $sth->fetchrow_arrayref ) { ($acc_id, $acc_desc, $acc_balance) = @$rr; $tot += $acc_balance; $dbh->sql_insert("Boekjaarbalans", [qw(bkb_bky bkb_acc_id bkb_balance bkb_end)], $bky, $acc_id, $acc_balance, $end); unless ( $did++ ) { $rep->start(_T("Journaal"), __x("Afsluiting boekjaar {bky}", bky => $bky)); } unless ( $desc ) { $rep->add({ _style => 'head', date => datefmt_full($end), desc => join(":", "<<"._T("Systeemdagboek").">>", $bky, 1), }); $desc = "Afboeken Resultaatrekeningen"; } $acc_balance = -$acc_balance; $rep->add({ _style => 'data', date => datefmt_full($end), desc => $dbh->lookup($acc_id, qw(Accounts acc_id acc_desc)), acct => $acc_id, $acc_balance >= 0 ? ( deb => numfmt($acc_balance) ) : ( crd => numfmt(-$acc_balance) ), bsk => $desc, }); $dtot += $acc_balance if $acc_balance > 0; $ctot -= $acc_balance if $acc_balance < 0; } if ( $did ) { my $d = '<< ' . ($tot <= 0 ? __x("Winst boekjaar {bky}", bky => $bky) : __x("Verlies boekjaar {bky}", bky => $bky)) . ' >>'; $dbh->sql_insert("Boekjaarbalans", [qw(bkb_bky bkb_acc_id bkb_balance bkb_end)], $bky, $dbh->std_acc("winst"), -$tot, $end); $tot = -$tot; $rep->add({ _style => 'data', date => datefmt_full($end), desc => $d, acct => $dbh->std_acc("winst"), $tot >= 0 ? ( crd => numfmt($tot) ) : ( deb => numfmt(-$tot) ), bsk => $desc, }); $ctot += $tot if $tot > 0; $dtot -= $tot if $tot < 0; } $tot = 0; $desc = ""; if ( $dbh->does_btw ) { ## Afboeken BTW foreach ( @{ $dbh->std_accs } ) { my $stdacc = $_; # copy for mod next unless $stdacc =~ /^btw_[iv].$/; next unless defined( $stdacc = $dbh->std_acc($stdacc, undef) ); ($acc_id, $acc_desc, $acc_balance) = @{$dbh->do("SELECT acc_id,acc_desc,acc_balance". " FROM ${tbl}". " WHERE acc_id = ?", $stdacc)}; next unless $acc_balance; $tot += $acc_balance; $dbh->sql_insert("Boekjaarbalans", [qw(bkb_bky bkb_acc_id bkb_balance bkb_end)], $bky, $acc_id, $acc_balance, $end); unless ( $did++ ) { $rep->start(_T("Journaal"), __x("Afsluiting boekjaar {bky}", bky => $bky)); } elsif ( !$desc ) { # $rep->outline(' '); } unless ( $desc ) { $rep->add({ _style => 'head', date => datefmt_full($end), desc => join(":", "<<"._T("Systeemdagboek").">>", $bky, 2), }); $desc = "Afboeken BTW rekeningen"; } $acc_balance = -$acc_balance; $rep->add({ _style => 'data', date => datefmt_full($end), desc => $dbh->lookup($acc_id, qw(Accounts acc_id acc_desc)), acct => $acc_id, $acc_balance >= 0 ? ( deb => numfmt($acc_balance) ) : ( crd => numfmt(-$acc_balance) ), bsk => $desc, }); $dtot += $acc_balance if $acc_balance > 0; $ctot -= $acc_balance if $acc_balance < 0; } if ( $did && $dbh->does_btw ) { ($acc_id, $acc_desc, $acc_balance) = @{$dbh->do("SELECT acc_id,acc_desc,acc_balance". " FROM ${tbl}". " WHERE acc_id = ?", $dbh->std_acc("btw_ok"))}; $dbh->sql_insert("Boekjaarbalans", [qw(bkb_bky bkb_acc_id bkb_balance bkb_end)], $bky, $acc_id, -$tot, $end); $tot = -$tot; $rep->add({ _style => 'data', date => datefmt_full($end), desc => $acc_desc, acct => $acc_id, $tot >= 0 ? ( crd => numfmt($tot) ) : ( deb => numfmt(-$tot) ), bsk => $desc, }); $ctot += $tot if $tot > 0; $dtot -= $tot if $tot < 0; } } ## End afboeken BTW if ( $did ) { $rep->add({ _style => 'total', desc => __x("Totaal {pfx}", pfx => __x("Afsluiting boekjaar {bky}", bky => $bky)), deb => numfmt($dtot), crd => numfmt($ctot), }); $rep->finish; } if ( $eb ) { print {$eb} ("\n# ", __x("Eindbalans bij afsluiting boekjaar {bky}", bky => $bky), "\n"); $sth = $dbh->sql_exec("SELECT acc_id, acc_desc, acc_balance, acc_ibalance, acc_debcrd". " FROM ${tbl}". " WHERE acc_balres". " ORDER BY acc_debcrd DESC, acc_id"); my ($dt, $ct); my $debcrd; while ( $rr = $sth->fetchrow_arrayref ) { my ($acc_id, $acc_desc, $acc_balance, $acc_ibalance, $acc_debcrd) = @$rr; # warn("=> acc $acc_id bal = $acc_balance ibal = $acc_ibalance\n"); if ( my $t = $dbh->do("SELECT bkb_balance". " FROM Boekjaarbalans". " WHERE bkb_bky = ?". " AND bkb_acc_id = ?", $bky, $acc_id) ) { $acc_balance -= $t->[0]; } next unless $acc_balance; if ( $acc_balance >= 0 ) { $dt += $acc_balance; } else { $ct -= $acc_balance; } $acc_balance = 0 - $acc_balance unless $acc_debcrd; if ( !defined($debcrd) || $acc_debcrd != $debcrd ) { print {$eb} ("\n# ", $acc_debcrd ? _T("Debet") : _T("Credit"), "\n"); } printf {$eb} ("adm_balans %-5s %10s # %s\n", $acc_id, numfmt_plain($acc_balance), $acc_desc); $debcrd = $acc_debcrd; } die("?".__x("Internal error -- unbalance {arg1} <> {arg2}", arg1 => numfmt($dt), arg2 => numfmt($ct))."\n") unless $dt == $ct; print {$eb} ("\n# ", _T("Totaal"), "\n", "adm_balanstotaal ", numfmt_plain($dt), "\n"); print {$eb} ("\n# ", __x("Openstaande posten bij afsluiting boekjaar {bky}", bky => $bky), "\n\n"); my $t = EB::Report::Open->new->perform($opts); if ( $t ) { $t =~ s/^./# /; print {$eb} ($t, "\n"); } } else { EB::Report::Open->new->perform($opts); } if ( $def ) { $dbh->sql_exec("UPDATE Boekjaren". " SET bky_closed = now()". " WHERE bky_code = ?", $bky)->finish; } $dbh->commit; close($eb) if $eb; undef; } 1; EekBoek-2.030.1/lib/EB/Tools/SQLEngine.pm0000644000400000040000000000740712725476602015262 0ustar jvjv#! perl # SQLEngine.pm -- Execute SQL commands # Author : Johan Vromans # Created On : Wed Sep 28 20:45:55 2005 # Last Modified By: Johan Vromans # Last Modified On: Sat Jun 19 00:47:09 2010 # Update Count : 72 # Status : Unknown, Use with caution! package EB::Tools::SQLEngine; use strict; use warnings; use EB; sub new { my ($class, @args) = @_; $class = ref($class) || $class; bless { _cb => {}, @args } => $class; } sub callback($%) { my ($self, %vec) = @_; return unless %vec; while ( my($k,$v) = each(%vec) ) { $self->{_cb}->{$k} = $v; } } # Basic SQL processor. Not very advanced, but does the job. # Note that COPY status will not work across different \i providers. # COPY status need to be terminated on the same level it was started. sub process { my ($self, $cmd, $copy) = (@_, 0); my $sql = ""; my $dbh = $self->{dbh} || $::dbh; # If we have PostgreSQL and it is of a suitable version, we can use # fast loading. my $pgcopy = $dbh->feature("pgcopy"); # Filter SQL, if needed. my $filter = $dbh->feature("filter"); # Remember type my $type = $dbh->driverdb; # Use raw handle from here. $dbh = $dbh->dbh; my $skipthis; foreach my $line ( split(/\n/, $cmd) ) { # Detect \i provider (include). if ( $line =~ /^\\i\s+(.*).sql/ ) { my $call = $self->{_cb}->{$1}; die("?".__x("SQLEngine: No callback for {cb}", cb => $1)."\n") unless $call; $self->process($call->(), $copy); next; } # Handle COPY status. if ( $copy ) { if ( $line eq "\\." ) { # End COPY. $dbh->pg_endcopy if $pgcopy; $copy = 0; } elsif ( $pgcopy ) { # Use PostgreSQL fast load. $dbh->pg_putline($line."\n"); } else { # Use portable INSERT. my @args = map { $_ eq 't' ? 1 : $_ eq 'f' ? 0 : $_ eq '\\N' ? undef : $_ } split(/\t/, $line); my $s = $copy; my @a = map { !defined($_) ? "NULL" : /^[0-9]+$/ ? $_ : $dbh->quote($_) } @args; $s =~ s/\?/shift(@a)/eg; $copy = $filter->($copy) if $filter; my $sth = $dbh->prepare($copy); $sth->execute(@args); $sth->finish; } next; } if ( $line =~ /^-- SKIP:\s*(\S+)/ ) { $skipthis = lc($1) eq lc($type); } elsif ( $line =~ /^-- ONLY:\s*(\S+)/ ) { $skipthis = lc($1) ne lc($type); } # Ordinary lines. # Strip comments. $line =~ s/--.*$//m; # Ignore empty lines. next unless $line =~ /\S/; # Trim whitespace. $line =~ s/\s+/ /g; $line =~ s/^\s+//; $line =~ s/\s+$//; # Append to command string. $sql .= $line . " "; # Execute if trailing ; if ( $line =~ /.+;$/ ) { if ( $skipthis ) { warn("++ SKIPPED:: $sql\n") if $self->{trace}; $skipthis = 0; $sql = ""; next; } # Check for COPY/ if ( $sql =~ /^copy\s(\S+)\s+(\([^\051]+\))/i ) { if ( $pgcopy ) { # Use PostgreSQL fast load. $copy = 1; } else { # Prepare SQL statement. $copy = "INSERT INTO $1 $2 VALUES (" . join(",", map { "?" } split(/,/, $2)) . ")"; $sql = ""; next; } } # Postprocessing. $sql = $filter->($sql) if $filter; next unless $sql; # Intercept transaction commands. Must be handled by DBI calls. if ( $sql =~ /^begin\b/i ) { warn("++ INTERCEPTED:: $sql\n") if $self->{trace}; $dbh->begin_work if $dbh->{AutoCommit}; } elsif ( $sql =~ /^commit\b/i ) { warn("++ INTERCEPTED: $sql\n") if $self->{trace}; $dbh->commit; } elsif ( $sql =~ /^rollback\b/i ) { warn("++ INTERCEPTED: $sql\n") if $self->{trace}; $dbh->rollback; } else { # Execute. warn("++ $sql\n") if $self->{trace}; $dbh->do($sql); } $sql = ""; } } die("?".__x("Incomplete SQL opdracht: {sql}", sql => $sql)."\n") if $sql; } 1; EekBoek-2.030.1/lib/EB/Tools/Opening.pm0000644000400000040000000005474213044346163015071 0ustar jvjv#! perl -- -*- coding: utf-8 -*- use utf8; # Author : Johan Vromans # Created On : Tue Aug 30 09:49:11 2005 # Last Modified By: Johan Vromans # Last Modified On: Thu Mar 13 17:55:41 2014 # Update Count : 313 # Status : Unknown, Use with caution! package main; our $dbh; our $config; package EB::Tools::Opening; use strict; use warnings; use EB; use EB::Format; # List of API methods (for the shell). sub commands { [qw(open set_naam set_btwperiode set_begindatum set_balanstotaal set_boekjaarcode set_balans set_relatie)]; } sub new { my $class = shift; $class = ref($class) || $class; bless {}, $class; } # Shell methods. # NOTE: A true result means ERROR! sub set_naam { return shellhelp() unless @_ == 2; my ($self, $naam) = @_; $self->check_open(0); $self->{o}->{naam} = $naam; ""; } sub set_btwperiode { return shellhelp() unless @_ == 2; my ($self, $per) = @_; my $pat = join("|", _T("jaar"), _T("maand"), _T("kwartaal")); return __x("Ongeldige BTW periode: {per}", per => $per)."\n" unless $per =~ /^$pat|jaar|maand}kwartaal$/i; #$self->check_open(0); $self->{o}->{btwperiode} = 1 if lc($per) eq _T("jaar") || lc($per) eq "jaar"; $self->{o}->{btwperiode} = 4 if lc($per) eq _T("kwartaal") || lc($per) eq "kwartaal"; $self->{o}->{btwperiode} = 12 if lc($per) eq _T("maand") || lc($per) eq "maand"; "" } sub set_begindatum { return shellhelp() unless @_ == 2; my ($self, $date) = @_; if ( $date =~ /^\d{4}$/ ) { $date .= "-01-01"; } my $d = parse_date($date); my ($jaar) = $d =~ /^(\d{4})/; return __x("Ongeldige openingsdatum: {date}", date => $date)."\n" unless $jaar =~ /^\d+$/ && $jaar >= 1990 && $jaar < 2099; # TODO $self->check_open(0); $self->{o}->{begindatum} = $d; $d =~ s/^(\d{4})/$1+1/e; $self->{o}->{einddatum} = parse_date($d, undef, -1); ""; } sub set_boekjaarcode { return shellhelp() unless @_ == 2; my ($self, $code) = @_; my $t; return __x("Ongeldige boekjaar-code: {year}", year => $code)."\n" unless $code =~ /^\w{1,4}$/; return __x("Boekjaar-code {year} bestaat al ({desc}", year => $code, desc => $t)."\n" if $t = $dbh->lookup($code, qw(Boekjaren bky_code bky_name)); #$self->check_open(0); $self->{o}->{boekjaarcode} = $code; ""; } sub set_balanstotaal { return shellhelp() unless @_ == 2; my ($self, $amt) = @_; my $anew; return __x("Ongeldig bedrag: {amount}", amount => $amt)."\n" unless defined($anew = amount($amt)); $self->check_open(0); $self->{o}->{balanstotaal} = $anew; ""; } sub set_balans { return shellhelp() unless @_ == 3; my ($self, $acct, $amt) = @_; my $rr = $dbh->do("SELECT acc_balres, acc_debcrd". " FROM Accounts". " WHERE acc_id = ?", $acct); return __x("Onbekende grootboekrekening: {acct}", acct => $acct)."\n" unless defined($rr); my $balres = $rr->[0]; return __x("Grootboekrekening {acct} is geen balansrekening", acct => $acct)."\n" unless $balres; my $debcrd; if ( $amt =~ /^(.*)([DC])/ ) { $amt = $1; $debcrd = $2 eq "D"; } else { $debcrd = $rr->[1]; } my $anew; return __x("Ongeldig bedrag: {amount}", amount => $amt)."\n" unless defined($anew = amount($amt)); $self->check_open(0); $anew = -$anew unless $debcrd; if ( exists($self->{o}->{balans}->{$acct}) ) { my $e = $self->{o}->{balans}->{$acct}; $anew = -$anew if ($e->[0] xor $debcrd); $self->{o}->{balans}->{$acct}->[1] += $anew; } else { $self->{o}->{balans}->{$acct} = [ $debcrd, $anew ]; } ""; } sub set_relatie { # adm_relatie verkoop:2000:31 2000-12-30 ACME Cursus 1000 # adm_relatie 2000-12-31 Cons deb ACME 1000 return shellhelp() unless @_ == 6; my $self = shift; my ($date, $desc, $type, $code, $amt); my ($dbk, $bky, $nr); if ( $_[0] =~ /^(\w+):(\w+):(\d+)$/ ) { # adm_relatie verkoop:2000:31 2000-12-30 ACME Cursus 1000 ($dbk, $bky, $nr) = ($1, $2, $3); shift; ($date, $code, $desc, $amt) = @_; my $t = $dbh->lookup($dbk, qw(Dagboeken dbk_desc dbk_type ILIKE)); return __x("Onbekend dagboek: {dbk}", dbk => $dbk)."\n" unless defined($t); $type = $t == DBKTYPE_VERKOOP; } else { # adm_relatie 2000-12-31 Cons deb ACME 1000 ($date, $desc, $type, $code, $amt) = @_; return _T("Relatietype moet \"deb\" of \"crd\" zijn")."\n" unless $type =~ /^crd|deb$/; $type = $type eq "deb"; } my $t = parse_date($date); return __x("Ongeldige datum: {date}", date => $date)."\n" unless $t; $date = $t; return __x("Datum {date} valt niet vóór het boekjaar", date => datefmt_full($date))."\n" if $self->{o}->{begindatum} && $self->{o}->{begindatum} le $t; $bky = substr($date, 0, 4) unless defined $bky; my $acct; my $sth; unless ( defined($dbk) ) { $sth = $dbh->sql_exec("SELECT rel_code, rel_ledger". " FROM Relaties". " WHERE UPPER(rel_code) = ?". " AND ".($type ? "" : "NOT ")." rel_debcrd", uc($code)); my $rr = $sth->fetch; return __x("Onbekende relatie: {rel}", rel => $code)."\n" unless defined $rr; ($code, $dbk) = @$rr; $sth->finish; $sth = $dbh->sql_exec("SELECT dbk_id, dbk_acc_id". " FROM Dagboeken". " WHERE dbk_id = ?", $dbk); } else { $sth = $dbh->sql_exec("SELECT dbk_id, dbk_acc_id". " FROM Dagboeken". " WHERE UPPER(dbk_desc) = ?", uc($dbk)); } ($dbk, $acct) = @{$sth->fetch}; my $rr = $dbh->do("SELECT rel_code FROM Relaties" . " WHERE UPPER(rel_code) = ?" . " AND " . ($type ? "" : "NOT ") . "rel_debcrd" . " AND rel_ledger = ?", uc($code), $dbk); return __x("Onbekende relatie: {rel}", rel => $code)."\n" unless defined $rr; my $anew; return __x("Ongeldig bedrag: {amount}", amount => $amt)."\n" unless defined($anew = amount($amt)); $self->check_open(0); push(@{$self->{o}->{relatie}}, [$bky, $nr, $date, $desc, $type, $code, $dbk, $acct, $anew]); ""; } # The actual opening process. sub open { if ( $dbh->adm_open ) { goto &reopen; } return shellhelp() unless @_ == 1; my ($self) = @_; $self->check_open(0); my $o = $self->{o}; my $fail = 0; $fail++, warn(_T("De naam van de administratie is nog niet opgegeven")."\n") unless $o->{naam}; $fail++, warn(_T("De begindatum is nog niet opgegeven")."\n") unless $o->{begindatum}; my $does_btw = $dbh->does_btw; my $gbj; unless ( $gbj = defined($o->{boekjaarcode}) ) { warn(__x("Er is geen boekjaarcode opgegeven, de waarde {val} wordt gebruikt", val => $o->{boekjaarcode} = substr($o->{begindatum}, 0, 4))."\n"); $fail++, warn(__x("Boekjaarcode \"{code}\" is reeds in gebruik", code => $o->{boekjaarcode})."\n") if $dbh->lookup($o->{boekjaarcode}, qw(Boekjaren bky_code bky_name)); } elsif ( $o->{boekjaarcode} !~ /^\w{1,4}$/ ) { warn(__x("Ongeldige boekjaarcode: {code}", code => $o->{boekjaarcode})."\n"); $fail++; } $fail++, warn(_T("De BTW periode is nog niet opgegeven")."\n") if $does_btw && !$o->{btwperiode}; if ( ($o->{balans} || $o->{relatie}) && !defined($o->{balanstotaal}) ) { $fail++; warn(_T("Het totaalbedrag van de openingsbalans is nog niet opgegeven")."\n"); } # Generalise for multiple deb/crd accounts. my %adeb; my %acrd; my $sth = $dbh->sql_exec("SELECT dbk_acc_id FROM Dagboeken". " WHERE dbk_type = ?", DBKTYPE_INKOOP); while ( my $rr = $sth->fetch ) { $acrd{0+$rr->[0]} = 0; } $sth = $dbh->sql_exec("SELECT dbk_acc_id FROM Dagboeken". " WHERE dbk_type = ?", DBKTYPE_VERKOOP); while ( my $rr = $sth->fetch ) { $adeb{0+$rr->[0]} = 0; } $dbh->begin_work; if ( defined($o->{balanstotaal}) ) { my $adeb; my $acrd; my $need_rel = 0; if ( !$o->{balans} && $o->{openingsbalans} ) { $fail++; warn(_T("De openingsbalans is nog niet opgegeven")."\n"); } else { # Boekhoudkundig rekenen. my $bdebet = $o->{balanstotaal}; my $bcredit = -$bdebet; # Rekenkundig rekenen. my $rcredit = $bcredit; my $rdebet = $bdebet; while ( my ($acct, $e) = each(%{$o->{balans}}) ) { my ($dc, $amt) = @$e; # Rekenkundig rekenen. if ( $dc ) { $rdebet -= $amt; } else { $rcredit -= $amt; } # Boekhoudkundig rekenen. if ( $amt >= 0 ) { $bdebet -= $amt; } else { $bcredit -= $amt; } $need_rel++, $adeb{$acct} += $amt if defined($adeb{$acct}); $need_rel++, $acrd{$acct} += $amt if defined($acrd{$acct}); } if ( ($rdebet || $rcredit) && ($bdebet || $bcredit) ) { $fail++; warn(_T("De openingsbalans is niet correct!")."\n"); warn(__x("Opgegeven balanstotaal = {total}", total => numfmt($o->{balanstotaal}))."\n"); warn(__x("Rekenkundig residu debet = {rdeb}, credit = {rcrd}", rdeb => numfmt($rdebet), rcrd => numfmt(-$rcredit)). ($rdebet == -$rcredit ? __x(" (balanstotaal {total})", total => numfmt($o->{balanstotaal} - $rdebet)) : '')."\n"); warn(__x("Boekhoudkundig residu debet = {rdeb}, credit = {rcrd}", rdeb => numfmt($bdebet), rcrd => numfmt(-$bcredit)). ($bdebet == -$bcredit ? __x(" (balanstotaal {total})", total => numfmt($o->{balanstotaal} - $bdebet)) : '')."\n"); } # Helpful hints... $fail++, warn(_T("Er zijn geen openstaande posten opgegeven")."\n") if !$o->{relatie} && $need_rel; $fail++, warn(_T("Er zijn openstaande posten opgegeven, maar geen corresponderende balansposten")."\n") if $o->{relatie} && !$need_rel; # Process relations. foreach my $r ( @{$o->{relatie}} ) { my ($bky, $nr, $date, $desc, $debcrd, $code, $dbk, $acct, $amt) = @$r; if ( $debcrd ) { $adeb = $acct; $adeb ||= $dbh->std_acc("deb", $adeb); unless ( defined $adeb ) { $adeb = (keys(%adeb))[0] if scalar(keys(%adeb)) == 1; } unless ( defined $adeb ) { warn(_T("Deze administratie kent geen koppeling voor verkoopboekingen")."\n"); $fail++; $adeb = 0; next; } next unless $adeb; $adeb{$adeb} -= $amt; } else { $acrd = $acct; $acrd ||= $dbh->std_acc("crd", $acrd); unless ( defined $acrd ) { $acrd = (keys(%acrd))[0] if scalar(keys(%acrd)) == 1; } unless ( defined $acrd ) { warn(_T("Deze administratie kent geen koppeling voor inkoopboekingen")."\n"); $fail++; $acrd = 0; # defined next; } next unless $acrd; $acrd{$acrd} += $amt; } if ( defined($bky) ) { my $sth = $dbh->sql_exec("SELECT bky_begin, bky_end". " FROM Boekjaren". " WHERE bky_code = ?", $bky); my $rr = $sth->fetchrow_arrayref; $sth->finish; if ( defined($rr) ) { my ($begin, $end) = @$rr; if ( $date lt $begin || $date gt $end ) { $fail++; warn(_T("Boekingsdatum valt niet binnen het boekjaar")."\n"); } } else { # Add a (pseudo) boekjaar. my $t = $o->{begindatum}; $t .= "-01-01" if length($t) == 4; (my $begin = $t) =~ s/^(\d{4})/substr($date,0,4)/e; my $end = parse_date($begin, undef, -1, undef, +1); $dbh->sql_insert("Boekjaren", [qw(bky_code bky_name bky_begin bky_end bky_btwperiod bky_opened bky_closed)], $bky, "$begin - $end", $begin, $end, 0, undef, undef); } } else { $bky = BKY_PREVIOUS; } } foreach my $adeb ( keys(%adeb) ) { next unless $adeb{$adeb}; $fail++; if ( $adeb{$adeb} >= 0 ) { warn(__x("Er is {amt} te weinig aan openstaande {dc} (rekening {acct}) opgegeven", amt => numfmt($adeb{$adeb}), acct => $adeb, dc => lc(_T("Debiteuren")))."\n"); } else { warn(__x("Er is {amt} te veel aan openstaande {dc} (rekening {acct}) opgegeven", amt => numfmt(-$adeb{$adeb}), acct => $adeb, dc => lc(_T("Debiteuren")))."\n"); } } foreach my $acrd ( keys(%acrd) ) { next unless $acrd{$acrd}; $fail++; if ( $acrd{$acrd} >= 0 ) { warn(__x("Er is {amt} te veel aan openstaande {dc} (rekening {acct}) opgegeven", amt => numfmt($acrd{$acrd}), acct => $acrd, dc => lc(_T("Crediteuren")))."\n"); } else { warn(__x("Er is {amt} te weinig aan openstaande {dc} (rekening {acct}) opgegeven", amt => numfmt(-$acrd{$acrd}), acct => $acrd, dc => lc(_T("Crediteuren")))."\n"); } } } } if ( $fail ) { $dbh->rollback if $dbh->in_transaction; return _T("DE OPENING IS NIET UITGEVOERD!")."\n"; } my $now = iso8601date(); $dbh->sql_insert("Boekjaren", [qw(bky_code bky_name bky_begin bky_end bky_btwperiod bky_opened)], $o->{boekjaarcode}, $o->{naam}, $o->{begindatum}, $o->{einddatum}, $o->{btwperiode}||0, $now); $dbh->sql_exec("UPDATE Metadata". " SET adm_bky = ?, adm_btwbegin = ?", $o->{boekjaarcode}, $does_btw ? $o->{begindatum} : undef); my $t = parse_date($o->{begindatum}, undef, -1); $dbh->sql_exec("UPDATE Boekjaren". " SET bky_closed = ?, bky_end = ?". " WHERE bky_code = ?", $t, $t, BKY_PREVIOUS); if ( defined $o->{balanstotaal} ) { while ( my ($acct, $e) = each(%{$o->{balans}}) ) { my ($dc, $amt) = @$e; $dbh->sql_exec("UPDATE Accounts". " SET acc_balance = acc_balance + ?,". " acc_ibalance = acc_ibalance + ?". " WHERE acc_id = ?", $amt, $amt, $acct); } my $dbk_inkoop; my $dbk_verkoop; foreach my $r ( @{$o->{relatie}} ) { my ($bky, $nr, $date, $desc, $debcrd, $code, $dagboek, $acct, $amt) = @$r; $nr = $dbh->get_sequence("bsk_nr_0_seq") unless defined $nr; # my ($dagboek) = @{$dbh->do("SELECT dbk_id". # " FROM Dagboeken". # " WHERE dbk_acc_id = ?", # $acct)}; if ( $debcrd ) { # unless ( $dbk_verkoop ) { # ($dbk_verkoop) = @{$dbh->do("SELECT dbk_id FROM Dagboeken". # " WHERE dbk_type = ?", # DBKTYPE_VERKOOP)}; # } # $dagboek = $dbk_verkoop; } else { # unless ( $dbk_inkoop ) { # ($dbk_inkoop) = @{$dbh->do("SELECT dbk_id FROM Dagboeken". # " WHERE dbk_type = ?", # DBKTYPE_INKOOP)}; # } # $dagboek = $dbk_inkoop; $amt = -$amt; } my $bsk_id = $dbh->get_sequence("boekstukken_bsk_id_seq"); $dbh->sql_insert("Boekstukken", [qw(bsk_id bsk_nr bsk_desc bsk_dbk_id bsk_date bsk_bky bsk_open bsk_amount)], $bsk_id, $nr, $desc, $dagboek, $date, $bky, $amt, $amt); $dbh->sql_insert("Boekstukregels", [qw(bsr_nr bsr_date bsr_bsk_id bsr_desc bsr_rel_code bsr_amount bsr_dbk_id bsr_type bsr_btw_class)], 1, $date, $bsk_id, $desc, $code, 0-$amt, $dagboek, 9, 0); } # my $highest = $dbh->get_sequence("bsk_nr_0_seq") + 1; # $dbh->set_sequence("bsk_nr_${dbk_inkoop}_seq", $highest) # if $dbk_inkoop; # $dbh->set_sequence("bsk_nr_${dbk_verkoop}_seq", $highest) # if $dbk_verkoop; } $dbh->commit; delete($self->{o}); $dbh->adm(""); # flush cache require EB::Report::Balres; my $opts = { verbose => $self->{verbose}, per => $dbh->adm("begin"), }; EB::Report::Balres->new->openingsbalans($opts); undef; } # A new bookyear. sub reopen { return shellhelp() unless @_ == 1; my ($self) = @_; $self->check_open(1); my $o = $self->{o}; my $fail = 0; # New begin date is old + one year. my $y = parse_date($dbh->adm("end"), undef, 1); # Avoid opening a new book year too soon. if ( $y gt parse_date(iso8601date(), undef, 0, 6) ) { warn(__x("Begindatum {year} komt in de toekomst te liggen", year => $y)."\n"); $fail++; } $o->{begindatum} = $y; $y =~ s/^(\d{4})/$1+1/e; $o->{einddatum} = parse_date($y, undef, -1); warn(_T("Er is geen nieuwe BTW periode opgegeven, deze blijft ongewijzigd")."\n") if $dbh->does_btw && !$o->{btwperiode}; if ( !defined($o->{boekjaarcode}) ) { warn(__x("Er is geen boekjaarcode opgegeven, de waarde {val} wordt gebruikt", val => $o->{boekjaarcode} = substr($o->{begindatum}, 0, 4))."\n"); } return _T("HET NIEUWE BOEKJAAR IS NIET GEOPEND!")."\n" if $fail; my $now = iso8601date(); $dbh->begin_work; $dbh->sql_insert("Boekjaren", [qw(bky_code bky_name bky_begin bky_end bky_btwperiod bky_opened)], $o->{boekjaarcode}, defined $o->{naam} ? $o->{naam} : $dbh->adm("name"), $o->{begindatum}, $o->{einddatum}, defined $o->{btwperiode} ? $o->{btwperiode} : $dbh->adm("btwperiod"), $now); $dbh->adm("bky", $o->{boekjaarcode}, "use_existing_transaction"); $dbh->adm(""); # flush cache # Reset boekstuknummer sequences. my $sth = $dbh->sql_exec("SELECT dbk_id FROM Dagboeken"); my $max = 1; while ( my $rr = $sth->fetchrow_arrayref ) { my $t = $dbh->get_sequence("bsk_nr_".$rr->[0]."_seq"); $dbh->set_sequence("bsk_nr_".$rr->[0]."_seq", 1); $max = $t if $t > $max; } # Sequence for bookings prev period. $dbh->set_sequence("bsk_nr_0_seq", $max); $dbh->commit; delete($self->{o}); undef; } sub shellhelp { my ($self, $cmd) = @_; _T( < Een code van max 4 letters en/of cijfers waarmee het boekjaar kan worden geïdentificeerd. Standaard wordt het jaartal van het boekjaar genomen. adm_open Alle informatie die met de bovenstaande opdrachten is ingevoerd, wordt verwerkt. Opdrachten voor het openen van een administratie: adm_naam "Naam van de administratie" adm_btwperiode [ jaar | kwartaal | maand ] adm_begindatum Een administratie loopt altijd van 1 januari tot en met 31 december van een kalenderjaar. adm_boekjaarcode Een code van max 4 letters en/of cijfers waarmee het boekjaar kan worden geïdentificeerd. Standaard wordt het jaartal van het boekjaar genomen. De boekjaarcode is alleen relevant indien er meerdere boekjaren in één administratie worden bijgehouden. adm_balanstotaal Als een balanstotaal is opgegeven, moeten er ook openingsbalansboekingen worden uitgevoerd met een of meer adm_balans opdrachten. adm_balans De debet en credit boekingen moeten uiteindelijk allebei gelijk zijn aan het opgegeven balanstotaal. Indien er een bedrag is opgegeven voor de balansrekening Crediteuren of Debiteuren, dan moet er voor dit bedrag ook openstaande posten worden ingevoerd met een of meer adm_relatie opdrachten. adm_relatie Invoeren van een openstaande post uit het voorgaande boekjaar. Het moet volledig zijn, dus ::. adm_open Alle informatie die met de bovenstaande opdrachten is ingevoerd, wordt verwerkt. EOS } sub help_btwperiode { _T( < De boekjaarcode telt maximaal 4 letters en/of cijfers. Standaard wordt het jaartal van het te openen boekjaar genomen. De boekjaarcode is alleen belangrijk indien er meerdere boekjaren in één administratie worden bijgehouden. Deze opdracht kan worden gebruikt bij het openen van een boekjaar. Zie "help adm_open" voor meer informatie. EOS } sub help_naam { _T( < Deze opdracht kan alleen worden gebruikt bij het openen van een nieuwe administratie. Zie "help adm_open" voor meer informatie. EOS } sub help_balanstotaal { _T( < Het balanstotaal is de zowel de som van alle debet-posten als de som van alle credit-posten van de openingsbalans. Als een balanstotaal is opgegeven, moeten er ook openingsbalansboekingen worden uitgevoerd met een of meer adm_balans opdrachten. Zie ook "help adm_balans". Deze opdracht kan alleen worden gebruikt bij het openen van een nieuwe administratie. Zie "help adm_open" voor meer informatie. EOS } sub help_balans { _T( < De debet en credit boekingen moeten uiteindelijk allebei gelijk zijn aan het opgegeven balanstotaal. Indien er een bedrag is opgegeven voor de balansrekening Crediteuren of voor Debiteuren, dan moeten er ook openstaande posten voor in totaal dit bedrag worden ingevoerd met een of meer adm_relatie opdrachten. Zie ook "help adm_relatie". Deze opdracht kan alleen worden gebruikt bij het openen van een nieuwe administratie. Zie "help adm_open" voor meer informatie. EOS } sub help_relatie { _T( < Het moet volledig zijn, dus ::. Indien er voor de openingsbalans een bedrag is opgegeven voor de balansrekening Crediteuren of voor Debiteuren, dan moeten er ook openstaande posten voor in totaal dit bedrag worden ingevoerd. Zie ook "help adm_balans". Deze opdracht kan alleen worden gebruikt bij het openen van een nieuwe administratie. Zie "help adm_open" voor meer informatie. EOS } sub check_open { my ($self, $open) = @_; $open = 1 unless defined($open); if ( $open && !$dbh->adm_open ) { die("?"._T("De administratie is nog niet geopend")."\n"); } elsif ( !$open && $dbh->adm_open ) { die("?"._T("De administratie is reeds in gebruik")."\n"); } 1; } 1; EekBoek-2.030.1/lib/EB/Tools/Schema.pm0000644000400000040000000011515013044346163014661 0ustar jvjv#! perl -- -*- coding: utf-8 -*- use utf8; # Author : Johan Vromans # Created On : Sun Aug 14 18:10:49 2005 # Last Modified By: Johan Vromans # Last Modified On: Tue Feb 18 13:45:04 2014 # Update Count : 952 # Status : Unknown, Use with caution! ################ Common stuff ################ package main; our $cfg; our $dbh; package EB::Tools::Schema; use strict; use warnings; our $sql = 0; # load schema into SQL files my $trace = $cfg->val(__PACKAGE__, "trace", 0); ################ The Process ################ use EB; use EB::Format; use EB::DB; use Encode; ################ Subroutines ################ ################ Schema Loading ################ my $schema; my %km; # keyword map sub create { shift; # singleton class method my ($name) = @_; my $file; if ( $name !~ /^\w+$/) { $file = $name; } else { foreach my $dir ( ".", "schema" ) { foreach my $ext ( ".dat" ) { next unless -s "$dir/$name$ext"; $file = "$dir/$name$ext"; last; } } $file = findlib("schema/$name.dat") unless $file; } die("?".__x("Onbekend schema: {schema}", schema => $name)."\n") unless $file; open(my $fh, "<", $file) or die("?".__x("Toegangsfout schema data: {err}", err => $!)."\n"); $schema = $name; _create1(undef, sub { <$fh> }); seek( $fh, 0, 0 ); _create2(undef, sub { <$fh> }); __x("Schema {schema} geïnitialiseerd", schema => $name); } sub _create1 { # 1st pass shift; # singleton class method my ($rl) = @_; $dbh = EB::DB->new(trace => $trace) unless $sql; load_schema1($rl); } sub _create2 { # 2nd pass shift; # singleton class method my ($rl) = @_; load_schema2($rl); } my @hvdi; # hoofdverdichtingen my @vdi; # verdichtingen my $max_hvd; # hoogste waarde voor hoofdverdichting my $max_vrd; # hoogste waarde voor verdichting my %acc; # grootboekrekeningen my $chvdi; # huidige hoofdverdichting my $cvdi; # huidige verdichting my %std; # standaardrekeningen my %dbk; # dagboeken my @dbk; # dagboeken my @btw; # btw tarieven my %btw; # btw aliases my $btw_auto; # btw auto code my %btwmap; # btw type/incl -> code my $fail; # any errors sub init_vars { @hvdi = (); # hoofdverdichtingen @vdi = (); # verdichtingen undef $max_hvd; # hoogste waarde voor hoofdverdichting undef $max_vrd; # hoogste waarde voor verdichting %acc = (); # grootboekrekeningen undef $chvdi; # huidige hoofdverdichting undef $cvdi; # huidige verdichting %std = (); # standaardrekeningen %dbk = (); # dagboeken @dbk = (); # dagboeken @btw = (); # btw tarieven %btw = (); # btw aliases $btw_auto = BTW_CODE_AUTO; # btw auto code %btwmap = (); # btw type/incl -> code undef $fail; # any errors init_kmap(); } sub init_kmap { %km = (); ####FIXME: Use N__ and __XN and friends. # BTW tariefgroepen. $km{tg_hoog} = __xt("scm:tg:hoog"); $km{tg_laag} = __xt("scm:tg:laag"); $km{tg_nul} = __xt("scm:tg:nul"); $km{tg_geen} = __xt("scm:tg:geen"); $km{tg_privé} = __xt("scm:tg:privé"); $km{tg_prive} = __xt("scm:tg:prive"); $km{tg_anders} = __xt("scm:tg:anders"); # Koppelingen. $km{winst} = __xt("scm:std:winst"); $km{crd} = __xt("scm:std:crd"); $km{deb} = __xt("scm:std:deb"); $km{btw_il} = __xt("scm:std:btw_il"); $km{btw_vl} = __xt("scm:std:btw_vl"); $km{btw_ih} = __xt("scm:std:btw_ih"); $km{btw_vp} = __xt("scm:std:btw_vp"); $km{btw_ip} = __xt("scm:std:btw_ip"); $km{btw_va} = __xt("scm:std:btw_va"); $km{btw_ia} = __xt("scm:std:btw_ia"); $km{btw_ok} = __xt("scm:std:btw_ok"); $km{btw_vh} = __xt("scm:std:btw_vh"); # Section headings. $km{hdr_verdichting} = __xt("scm:hdr:Verdichting"); $km{hdr_balans} = __xt("scm:hdr:Balansrekeningen"); $km{balans} = __xt("scm:balans"); $km{hdr_resultaat} = __xt("scm:hdr:Resultaatrekeningen"); $km{result} = __xt("scm:result"); $km{hdr_dagboeken} = __xt("scm:hdr:Dagboeken"); $km{dagboeken} = __xt("scm:dagboeken"); $km{hdr_btwtarieven} = __xt("scm:hdr:BTW Tarieven"); # Daybook Types. $km{inkoop} = __xt("scm:dbk:inkoop"); $km{verkoop} = __xt("scm:dbk:verkoop"); $km{bank} = __xt("scm:dbk:bank"); $km{kas} = __xt("scm:dbk:kas"); $km{memoriaal} = __xt("scm:dbk:memoriaal"); # Misc. $km{inclusief} = __xt("scm:inclusief"); $km{exclusief} = __xt("scm:exclusief"); $km{incl} = __xt("scm:incl"); $km{excl} = __xt("scm:excl"); $km{btw} = __xt("scm:btw"); $km{vanaf} = __xt("scm:vanaf"); $km{tot} = __xt("scm:tot"); $km{kosten} = __xt("scm:kosten"); $km{kostenrekening} = __xt("scm:kostenrekening"); $km{omzet} = __xt("scm:omzet"); $km{omzetrekening} = __xt("scm:omzetrekening"); $km{koppeling} = __xt("scm:koppeling"); $km{type} = __xt("scm:type"); $km{rek} = __xt("scm:rek"); $km{rekening} = __xt("scm:rekening"); $km{percentage} = __xt("scm:percentage"); $km{perc} = __xt("scm:perc"); $km{tariefgroep} = __xt("scm:tariefgroep"); } sub _xt { # scm:btw -> scm:vat -> vat my $t = _T(shift); $t =~ s/^.*://; $t; } sub _xtr { # scm:vat -> scm:btw -> btw my $t = shift; (my $pfx, $t) = ( $1, $2 ) if $t =~ /^(.*):(.*)/; keys(%km); # reset iteration while ( my ($k, $v) = each %km ) { next unless $t eq $v; return $1 if $k =~ /^tg_(.*)/; return $k; } undef; } sub error { warn('?', @_); $fail++; } my $dbkid; sub scan_dagboeken { return 0 unless /^\s+(\w{1,4})\s+(.*)/ && $1; $dbkid++; my ($id, $desc) = ($1, $2); error(__x("Dubbel: dagboek {dbk}", dbk => $id)."\n") if defined($dbk{$id}); my $type; my $dcsplit, my $rek = 0; my $extra; while ( $desc =~ /^(.+?)\s+:([^\s:]+)\s*$/ ) { $desc = $1; $extra = $2; if ( $extra =~ m/^$km{type}=(\S+)$/i ) { my $t = DBKTYPES; for ( my $i = 0; $i < @$t; $i++ ) { next unless lc($1) eq lc(_xt("scm:dbk:".lc($t->[$i]))); $type = $i; last; } error(__x("Dagboek {id} onbekend type \"{type}\"", id => $id, type => $1)."\n") unless defined($type); } elsif ( $extra =~ m/^(?:$km{rek}|$km{rekening})?=(\d+)$/i ) { $rek = $1; } elsif ( $extra =~ m/^dc$/i ) { $dcsplit = 1; } else { error(__x("Dagboek {id}: onbekende info \"{info}\"", id => $id, info => $extra)."\n"); } } error(__x("Dagboek {id}: het :type ontbreekt", id => $id)."\n") unless defined($type); error(__x("Dagboek {id}: het :rekening nummer ontbreekt", id => $id)."\n") if ( $type == DBKTYPE_KAS || $type == DBKTYPE_BANK ) && !$type; error(__x("Dagboek {id}: :dc is alleen toegestaan voor Kas en Bankboeken", id => $id)."\n") if $dcsplit && !( $type == DBKTYPE_KAS || $type == DBKTYPE_BANK ); my $t = lc(_T($desc)); $t =~ s/\s+/_/g; error(__x("Dagboek naam \"{dbk}\" is niet toegestaan.", dbk => $desc)."\n") if $desc =~ /^adm[ _]/i || defined &{"EB::Shell::do_$t"}; $dbk{$id} = $dbkid; $dbk[$dbkid] = [ $id, $desc, $type, $dcsplit, $rek||undef ]; } sub scan_btw { return 0 unless /^\s+(\w+-?)\s+(.*)/; my ($id, $desc) = ($1, $2); my $id0 = $id; # for messages my $alias; unless ( $id =~ /^\d+$/ ) { error(__x("Ongeldige code voor BTW tarief: {id} (moet minstens twee tekens zijn)", id => $id0)."\n") if length($id) < 3; # prevent clash with HK and such. error(__x("Dubbel: BTW tarief {id}", id => $id0)."\n") if exists($btw{lc $id}); $btw_auto += 2; $btw{lc $id} = $btw_auto; $alias = lc $id; $id = $btw_auto; } else { error(__x("Ongeldige code voor BTW tarief: {id}", id => $id0)."\n") if $id > BTW_CODE_AUTO; } error(__x("Dubbel: BTW tarief {id}", id => $id0)."\n") if defined($btw[$id]); my $perc; my $groep = 0; my $incl = 1; my $sdate; my $edate; my $extra; while ( $desc =~ /^(.+?)\s+:([^\s:]+)\s*$/ ) { $desc = $1; $extra = $2; if ( $extra =~ m/^(?:$km{perc}|$km{percentage})?=(\S+)$/i ) { $perc = amount($1); if ( AMTPRECISION > BTWPRECISION-2 ) { $perc = substr($perc, 0, length($perc) - (AMTPRECISION - BTWPRECISION-2)) } elsif ( AMTPRECISION < BTWPRECISION-2 ) { $perc .= "0" x (BTWPRECISION-2 - AMTPRECISION); } } elsif ( $extra =~ m/^$km{tariefgroep}=$km{tg_hoog}$/i ) { $groep = BTWTARIEF_HOOG; } elsif ( $extra =~ m/^$km{tariefgroep}=$km{tg_laag}$/i ) { $groep = BTWTARIEF_LAAG; } elsif ( $extra =~ m/^$km{tariefgroep}=($km{tg_nul}|$km{tg_geen})$/i ) { $groep = BTWTARIEF_NUL; warn("!"._T("Gelieve BTW tariefgroep \"Geen\" te vervangen door \"Nul\"")."\n") if lc($1) eq $km{tg_geen}; } elsif ( $extra =~ m/^$km{tariefgroep}=(prive|$km{tg_privé}|$km{tg_prive})$/i ) { $groep = BTWTARIEF_PRIV; } elsif ( $extra =~ m/^$km{tariefgroep}=$km{tg_anders}$/i ) { $groep = BTWTARIEF_ANDERS; } elsif ( $extra =~ m/^(?:$km{incl}|$km{inclusief})$/i ) { $incl = 1; } elsif ( $extra =~ m/^(?:$km{excl}|$km{exclusief})$/i ) { $incl = 0; } elsif ( $extra =~ m/^(?:$km{vanaf})=(.+)$/i ) { $sdate = $1; error("Ongeldige datumaanduiding in {key}: {value}", key => $km{vanaf}, value => $sdate) unless $sdate =~ /^(\d{4}-\d\d-\d\d)$/; $sdate = parse_date($1) or error(__x("Ongeldige datumaanduiding in {key}: {value}", key => $km{vanaf}, value => $1)); } elsif ( $extra =~ m/^(?:$km{tot})=(.+)$/i ) { $edate = $1; error("Ongeldige datumaanduiding in {key}: {value}", key => $km{tot}, value => $sdate) unless $edate =~ /^(\d{4}-\d\d-\d\d)$/; $edate = parse_date($1, undef, -1) or error(__x("Ongeldige datumaanduiding in {key}: {value}", key => $km{tot}, value => $1)); } else { error(__x("BTW tarief {id}: onbekende info \"{info}\"", id => $id0, info => $extra)."\n"); } } error(__x("BTW tarief {id}: geen percentage en de tariefgroep is niet \"{none}\"", id => $id0, none => _T("geen"))."\n") unless defined($perc) || $groep == BTWTARIEF_NUL; # Add the definition. Automatically add one for the non-$incl variant if it is named. $btw[$id] = [ $id, $alias, $desc, $groep, $perc, $incl, $sdate, $edate ]; $btw[$id+1] = [ $id+1, undef, $alias.($incl?'-':'+'), $groep, $perc, !$incl, $sdate, $edate ] if $id > BTW_CODE_AUTO; if ( $groep == BTWTARIEF_NUL && !defined($btwmap{n}) ) { $btwmap{n} = $id; } else { my $pfx = $incl ? "" : "-"; if ( $groep == BTWTARIEF_HOOG && !defined($btwmap{"h$pfx"}) ) { $btwmap{"h$pfx"} = $id; } elsif ( $groep == BTWTARIEF_LAAG && !defined($btwmap{"l$pfx"}) ) { $btwmap{"l$pfx"} = $id; } elsif ( $groep == BTWTARIEF_PRIV && !defined($btwmap{"p$pfx"}) ) { $btwmap{"p$pfx"} = $id; } elsif ( $groep == BTWTARIEF_ANDERS && !defined($btwmap{"a$pfx"}) ) { $btwmap{"a$pfx"} = $id; } } $btwmap{$id} = $id; $btwmap{$alias} = $id if defined($alias) && $alias !~ /^\d+$/; 1; } sub scan_balres { my ($balres) = shift; if ( /^\s*(\d+)\s+(.+)/ && length($1) <= length($max_hvd) && $1 <= $max_hvd ) { error(__x("Dubbel: hoofdverdichting {vrd}", vrd => $1)."\n") if exists($hvdi[$1]); $hvdi[$chvdi = $1] = [ $2, $balres ]; } elsif ( /^\s*(\d+)\s+(.+)/ && length($1) <= length($max_vrd) && $1 <= $max_vrd ) { error(__x("Dubbel: verdichting {vrd}", vrd => $1)."\n") if exists($vdi[$1]); error(__x("Verdichting {vrd} heeft geen hoofdverdichting", vrd => $1)."\n") unless defined($chvdi); $vdi[$cvdi = $1] = [ $2, $balres, $chvdi ]; } elsif ( /^\s*(\d+)\s+(\S+)\s+(.+)/ ) { my ($id, $flags, $desc) = ($1, $2, $3); error(__x("Dubbel: rekening {acct}", acct => $1)."\n") if exists($acc{$id}); error(__x("Rekening {id} heeft geen verdichting", id => $id)."\n") unless defined($cvdi); my $debcrd; my $kstomz; my $dcfixed; if ( ($balres ? $flags =~ /^[dc]\!?$/i : $flags =~ /^[kon]$/i) || $flags =~ /^[dc][ko]$/i ) { $debcrd = $flags =~ /d/i; $kstomz = $flags =~ /k/i if $flags =~ /[ko]/i; $dcfixed = $flags =~ /\!/; } else { error(__x("Rekening {id}: onherkenbare vlaggetjes {flags}", id => $id, flags => $flags)."\n"); } my $btw_type = 'n'; my $btw_ko; my $extra; while ( $desc =~ /^(.+?)\s+:([^\s:]+)\s*$/ ) { $desc = $1; $extra = $2; if ( $extra =~ m/^$km{btw}=(.+)$/i ) { my $spec = $1; my @spec = split(/,/, lc($spec)); my $btw_inex = 1; foreach ( @spec ) { if ( $balres && /^($km{kosten}|$km{omzet})$/ ) { $btw_ko = $1 eq $km{kosten}; } # elsif ( defined $btwmap{$_} ) { # $btw_type = $btwmap{$_}; # } elsif ( /^($km{tg_hoog}|$km{tg_laag}|$km{tg_nul}|prive|$km{tg_privé}|$km{tg_prive}|$km{tg_anders})$/ ) { $btw_type = substr(_xtr("scm:tg:$1"), 0, 1); } elsif ( /^\d+$/ ) { $btw_type = $_; warn("!".__x("Rekening {id}: gelieve BTW tariefcode {code} te vervangen door een tariefgroep", id => $id, code => $_)."\n") } elsif ( $_ eq $km{tg_geen} ) { $btw_type = 0; $kstomz = $btw_ko = undef; } elsif ( /^($km{incl}|$km{excl}|$km{inclusief}|$km{exclusief})?$/ ) { $btw_inex = $1 eq $km{incl} || $1 eq $km{inclusief}; } else { error(__x("Foutieve BTW specificatie: {spec}", spec => $spec)."\n"); last; } } $btw_type .= "-" unless $btw_inex; } elsif ( $extra =~ m/$km{koppeling}=(\S+)/i ) { my $t = _xtr("scm:std:$1"); error(__x("Rekening {id}: onbekende koppeling \"{std}\"", id => $id, std => $1)."\n") unless exists($std{$t}); error(__x("Rekening {id}: extra koppeling voor \"{std}\"", id => $id, std => $1)."\n") if $std{$t}; $std{$t} = $id; } } if ( $btw_type ne 'n' ) { error(__x("Rekening {id}: BTW koppeling '{ko}' met een {acc} is niet toegestaan", id => $id, ko => ($km{omzet}, $km{kosten})[$btw_ko], acc => ($km{omzetrekening}, $km{kostenrekening})[$kstomz])."\n") if !$balres && defined($kstomz) && defined($btw_ko) && $btw_ko != $kstomz; error(__x("Rekening {id}: BTW koppeling met neutrale resultaatrekening is niet toegestaan", id => $id)."\n") unless defined($kstomz) || defined($btw_ko); error(__x("Rekening {id}: BTW koppeling met een balansrekening vereist kosten/omzet specificatie", id => $id)."\n") if $balres && !defined($btw_ko); } $desc =~ s/\s+$//; $kstomz = $btw_ko unless defined($kstomz); $acc{$id} = [ $desc, $cvdi, $balres, $debcrd, $kstomz, $btw_type, $dcfixed ]; 1; } else { 0; } } sub scan_balans { unshift(@_, 1); goto &scan_balres; } sub scan_result { unshift(@_, 0); goto &scan_balres; } sub scan_ignore { 1 } sub load_schema1 { my ($rl) = shift; init_vars(); my $scanner; # current scanner %std = map { $_ => 0 } qw(btw_ok btw_vh winst crd deb btw_il btw_vl btw_ih btw_vp btw_ip btw_va btw_ia); while ( $_ = $rl->() ) { if ( /^\# \s* content-type: \s* text (?: \s* \/ \s* plain)? \s* ; \s* charset \s* = \s* (\S+) \s* $/ix ) { my $charset = lc($1); if ( $charset =~ /^(?:utf-?8)$/i ) { next; } error(_T("Invoer moet Unicode (UTF-8) zijn.")."\n"); } my $s = "".$_; eval { $_ = decode('utf8', $s, 1); }; if ( $@ ) { warn("?".__x("Geen geldige UTF-8 tekens in regel {line} van de invoer", line => $.)."\n".$s."\n"); warn($@); $fail++; next; } next if /^\s*#/; next unless /\S/; # Scanner selectie. if ( /^($km{balans}|$km{hdr_balans})/i ) { $scanner = \&scan_ignore; next; } if ( /^($km{result}|$km{hdr_resultaat})/i ) { $scanner = \&scan_ignore; next; } if ( /^($km{dagboeken}|$km{hdr_dagboeken})/i ) { $scanner = \&scan_ignore; next; } if ( /^$km{hdr_btwtarieven}/i ) { $scanner = \&scan_btw; next; } # Overige settings. if ( /^$km{hdr_verdichting}\s+(\d+)\s+(\d+)/i && $1 < $2 ) { next; } # Anders: Scan. if ( $scanner ) { chomp; $scanner->() or error(__x("Ongeldige invoer in schema bestand, regel {lno}:\n{line}", line => $_, lno => $.)."\n"); next; } error(__x("Ongeldige invoer in schema bestand, regel {lno}:\n{line}", line => $_, lno => $.)."\n"); } if ( @btw && !defined $btwmap{n} ) { $btw[0] = [ 0, undef, _T("BTW 0%"), BTWTARIEF_NUL, 0, 1 ]; $btwmap{n} = 0; } } sub load_schema2 { my ($rl) = shift; my $scanner; # current scanner $max_hvd = 9; $max_vrd = 99; while ( $_ = $rl->() ) { if ( /^\# \s* content-type: \s* text (?: \s* \/ \s* plain)? \s* ; \s* charset \s* = \s* (\S+) \s* $/ix ) { my $charset = lc($1); if ( $charset =~ /^(?:utf-?8)$/i ) { next; } error(_T("Invoer moet Unicode (UTF-8) zijn.")."\n"); } my $s = "".$_; eval { $_ = decode('utf8', $s, 1); }; if ( $@ ) { warn("?".__x("Geen geldige UTF-8 tekens in regel {line} van de invoer", line => $.)."\n".$s."\n"); warn($@); $fail++; next; } next if /^\s*#/; next unless /\S/; # Scanner selectie. if ( /^($km{balans}|$km{hdr_balans})/i ) { $scanner = \&scan_balans; next; } if ( /^($km{result}|$km{hdr_resultaat})/i ) { $scanner = \&scan_result; next; } if ( /^($km{dagboeken}|$km{hdr_dagboeken})/i ) { $scanner = \&scan_dagboeken; next; } if ( /^$km{hdr_btwtarieven}/i ) { $scanner = \&scan_ignore; next; } # Overige settings. if ( /^$km{hdr_verdichting}\s+(\d+)\s+(\d+)/i && $1 < $2 ) { $max_hvd = $1; $max_vrd = $2; next; } # Anders: Scan. if ( $scanner ) { chomp; $scanner->() or error(__x("Ongeldige invoer in schema bestand, regel {lno}:\n{line}", line => $_, lno => $.)."\n"); next; } error(__x("Ongeldige invoer in schema bestand, regel {lno}:\n{line}", line => $_, lno => $.)."\n"); # This is here for historical reasons. # If you weren't at the THE in 1977 this will mean nothing to you... # error("?"._T("Men beginne met \"Balansrekeningen\", \"Resultaatrekeningen\",".# # " \"Dagboeken\" of \"BTW Tarieven\"")."\n"); } # Bekijk alle dagboeken om te zien of er inkoop/verkoop dagboeken # zijn die een tegenrekening nodig hebben. In dat geval moet de # betreffende koppeling in het schema gemaakt zijn. my ($need_deb, $need_crd) = (0,0); foreach ( @dbk ) { next unless defined($_); # sparse my ($id, $desc, $type, $dc, $rek) = @$_; if ( defined($rek) ) { # Controleer of de tegenrekening isgedefinieerd. next if defined $acc{$rek}; error(__x("Tegenrekening {acct} van dagboek {id} is niet gedefinieerd", acct => $rek, id => $id)."\n"); $fail++; next; } if ( $type == DBKTYPE_INKOOP ) { $need_crd++; $_->[4] = $std{"crd"}; #### Verify that it's a C acct. } elsif ( $type == DBKTYPE_VERKOOP ) { $need_deb++; $_->[4] = $std{"deb"}; #### Verify that it's a D acct. } elsif ( $type != DBKTYPE_MEMORIAAL ) { error(__x("Dagboek {id} heeft geen tegenrekening", id => $id)."\n"); $fail++; } } # Verwijder onnodige koppelingen. delete($std{crd}) unless $need_crd; delete($std{deb}) unless $need_deb; unless (defined($btwmap{p}) || defined($btwmap{"p-"}) ) { delete($std{"btw_ip"}) unless $std{"btw_ip"}; delete($std{"btw_vp"}) unless $std{"btw_vp"}; } unless (defined($btwmap{a}) || defined($btwmap{"a-"}) ) { delete($std{"btw_ia"}) unless $std{"btw_ia"}; delete($std{"btw_va"}) unless $std{"btw_va"}; } my %mapbtw = ( n => "Nul", h => "Hoog", "l" => "Laag" ); if ( @btw ) { foreach ( keys(%mapbtw) ) { next if defined($btwmap{$_}); error(__x("Geen BTW tarief gevonden met tariefgroep {gr}, inclusief", gr => $mapbtw{$_})."\n"); } } else { for ( qw(ih il ip ia vh vl vp va ok) ) { delete($std{"btw_$_"}) unless $std{"btw_$_"}; } $btwmap{n} = undef; $btw[0] = [ 0, "BTW Nul", BTWTARIEF_NUL, 0, 0 ]; } while ( my($k,$v) = each(%std) ) { next if $v; error(__x("Geen koppeling gevonden voor \"{std}\"", std => $k)."\n"); } die("?"._T("FOUTEN GEVONDEN IN SCHEMA BESTAND, VERWERKING AFGEBROKEN")."\n") if $fail; if ( $sql ) { gen_schema(); } else { create_schema(); } } sub create_schema { use EB::Tools::SQLEngine; my $engine = EB::Tools::SQLEngine->new(trace => $trace); $engine->callback(map { $_, __PACKAGE__->can("sql_$_") } qw(constants vrd acc std btw dbk) ); $dbh->begin_work; $engine->process(sql_eekboek()); $dbh->commit; } sub _trim { my ($t) = @_; for ( $t ) { s/\s+/ /g; s/^\s+//; s/\s+$//; return $_; } } sub _tsv { join("\t", map { _trim($_) } @_) . "\n"; } sub sql_eekboek { my $f = findlib("schema/eekboek.sql"); open (my $fh, '<:encoding(utf-8)', $f) or die("?"._T("Installatiefout -- geen database schema")."\n"); local $/; my $sql = <$fh>; close($fh); $sql; } sub sql_constants { my $out = "COPY Constants (name, value) FROM stdin;\n"; foreach my $key ( sort(@EB::Globals::EXPORT) ) { no strict; next if ref($key->()); $out .= "$key\t" . $key->() . "\n"; } $out . "\\.\n"; } sub sql_vrd { my $out = <[0], _tf($v->[1]), _tfn(undef), "\\N"); } $out .= "\\.\n"; $out .= <[0], _tf($v->[1]), _tfn(undef), $v->[2]); } $out . "\\.\n"; } sub sql_acc { my $out = < $b } keys(%acc) ) { my $g = $acc{$i}; croak(__x("Geen BTW tariefgroep voor code {code}", code => $g->[5])) unless exists $btwmap{$g->[5]} || exists $btwmap{$g->[5]."-"}; $out .= _tsv($i, $g->[0], $g->[1], _tf($g->[2]), _tf($g->[3]), _tfn($g->[2] ? $g->[6] : undef), _tfn($g->[4]), defined($btwmap{$g->[5]}) ? $btwmap{$g->[5]} : "\\N", 0, 0); } $out . "\\.\n"; } sub sql_std { my $out = <[1] = "\\N" unless defined($_->[1]); $_->[6] = "\\N" unless defined($_->[6]); $_->[7] = "\\N" unless defined($_->[7]); if ( $_->[3] == BTWTARIEF_NUL ) { $_->[4] = 0; $_->[5] = "\\N"; } else { $_->[5] = _tf($_->[5]); } $out .= _tsv(@$_); } $out . "\\.\n"; } sub sql_dbk { my $out = <[4] ||= $std{deb} if $_->[2] == DBKTYPE_VERKOOP; $_->[4] ||= $std{crd} if $_->[2] == DBKTYPE_INKOOP; $out .= join("\t", map { defined($_) ? $_ : "\\N" } @$_). "\n"; } $out .= "\\.\n"; $out .= "\n-- Sequences for Boekstuknummers, one for each Dagboek\n"; foreach ( @dbk ) { next unless defined; $out .= "CREATE SEQUENCE bsk_nr_$_->[0]_seq;\n"; } $out; } use Encode; sub gen_schema { foreach ( qw(eekboek vrd acc dbk btw std) ) { warn('%'.__x("Aanmaken {sql}...", sql => "$_.sql")."\n"); # Careful. Data is utf8. open(my $f, ">:encoding(utf-8)", "$_.sql") or die("Cannot create $_.sql: $!\n"); my $cmd = "sql_$_"; no strict 'refs'; print $f decode_utf8($cmd->()); close($f); } } sub _tf { qw(f t)[shift]; } sub _tfn { defined($_[0]) ? qw(f t)[$_[0]] : "\\N"; } ################ Subroutines ################ sub dump_sql { my ($self, $schema) = @_; local($sql) = 1; create(undef, $schema); } my %kopp; my $fh; sub dump_schema { my ($self, $fh) = @_; $fh ||= *STDOUT; # Only generate comments when translated. my $preamble = <new(trace => $trace); $dbh->connectdb; # can't wait... init_kmap(); my @t = localtime(time); print {$fh} ( "# ", __x( "{pkg} Rekeningschema voor {db}", pkg => $EekBoek::PACKAGE, db => $dbh->dbh->{Name} ), "\n", "# ", __x( "Aangemaakt door {pkg} {version} op {ts}", pkg => $EekBoek::PACKAGE, version => $EekBoek::VERSION, ts => sprintf( "%02d-%02d-%04d %02d:%02d:%02d", $t[3], 1+$t[4], 1900+$t[5], @t[2,1,0] ), ), "\n", "# Content-Type: text/plain; charset = UTF-8\n" ); print {$fh} $preamble if $comment; my $sth = $dbh->sql_exec("SELECT * FROM Standaardrekeningen"); my $rr = $sth->fetchrow_hashref; $sth->finish; while ( my($k,$v) = each(%$rr) ) { next unless defined $v; $k =~ s/^std_acc_//; $kopp{$v} = $k; } print {$fh} <do("SELECT MAX(vdi_id) FROM Verdichtingen WHERE vdi_struct IS NULL")->[0]; $max_vrd = $dbh->do("SELECT MAX(vdi_id) FROM Verdichtingen WHERE NOT vdi_struct IS NULL")->[0]; print {$fh} < 9 || $max_vrd > 99 ) ? ( $max_hvd, $max_vrd ) : ( 9, 99 ) ); print {$fh} <does_btw ) { print {$fh} < $EekBoek::PACKAGE ), "\n" ); } sub dump_acc { my ($balres, $fh) = @_; print {$fh} ("\n", $balres ? $km{hdr_balans} : $km{hdr_resultaat}, "\n"); my $sth = $dbh->sql_exec("SELECT vdi_id, vdi_desc". " FROM Verdichtingen". " WHERE ".($balres?"":"NOT ")."vdi_balres". " AND vdi_struct IS NULL". " ORDER BY vdi_id"); while ( my $rr = $sth->fetchrow_arrayref ) { my ($id, $desc) = @$rr; printf {$fh} ("\n %d %s\n", $id, $desc); print {$fh} ("# ".__x("HOOFDVERDICHTING MOET TUSSEN {min} EN {max} (INCL.) LIGGEN", min => 1, max => $max_hvd)."\n") if $id > $max_hvd; my $sth = $dbh->sql_exec("SELECT vdi_id, vdi_desc". " FROM Verdichtingen". " WHERE vdi_struct = ?". " ORDER BY vdi_id", $id); while ( my $rr = $sth->fetchrow_arrayref ) { my ($id, $desc) = @$rr; printf {$fh} (" %-2d %s\n", $id, $desc); print {$fh} ("# ".__x("VERDICHTING MOET TUSSEN {min} EN {max} (INCL.) LIGGEN", min => $max_hvd+1, max => $max_vrd)."\n") if $id <= $max_hvd || $id > $max_vrd; my $sth = $dbh->sql_exec("SELECT acc_id, acc_desc, acc_balres,". " acc_debcrd, acc_dcfixed, acc_kstomz,". " acc_btw, btw_tariefgroep, btw_incl". " FROM Accounts, BTWTabel ". " WHERE acc_struct = ?". " AND (btw_id = acc_btw". " OR btw_id = 0 AND acc_btw IS NULL)". " ORDER BY acc_id", $id); while ( my $rr = $sth->fetchrow_arrayref ) { my ($id, $desc, $acc_balres, $acc_debcrd, $acc_dcfixed, $acc_kstomz, $btw_id, $btw, $btwincl) = @$rr; my $flags = ""; if ( $balres ) { $flags .= $acc_debcrd ? "D" : "C"; $flags .= '!' if $acc_dcfixed; } else { $flags .= defined($acc_kstomz) ? ($acc_kstomz ? "K" : "O") : "N"; } my $extra = ""; if ( $btw == BTWTARIEF_HOOG ) { $extra .= " :$km{btw}=$km{tg_hoog}"; $extra .= ",$km{excl}" unless $btwincl; if ( $balres ) { $extra .= ",$km{kosten}" if $acc_kstomz; $extra .= ",$km{omzet}" if !$acc_kstomz; } } elsif ( $btw == BTWTARIEF_LAAG ) { $extra .= " :$km{btw}=$km{tg_laag}"; $extra .= ",$km{excl}" unless $btwincl; if ( $balres ) { $extra .= ",$km{kosten}" if $acc_kstomz; $extra .= ",$km{omzet}" if !$acc_kstomz; } } elsif ( $btw == BTWTARIEF_PRIV ) { $extra .= " :$km{btw}=$km{tg_privé}"; $extra .= ",$km{excl}" unless $btwincl; if ( $balres ) { $extra .= ",$km{kosten}" if $acc_kstomz; $extra .= ",$km{omzet}" if !$acc_kstomz; } } elsif ( $btw == BTWTARIEF_ANDERS ) { $extra .= " :$km{btw}=$km{tg_anders}"; $extra .= ",$km{excl}" unless $btwincl; if ( $balres ) { $extra .= ",$km{kosten}" if $acc_kstomz; $extra .= ",$km{omzet}" if !$acc_kstomz; } } elsif ( $btw != BTWTARIEF_NUL ) { $extra .= " :$km{btw}=$btw_id"; } else { if ( $balres && defined($acc_kstomz) ) { $extra .= " :$km{btw}=$km{kosten}" if $acc_kstomz; $extra .= " :$km{btw}=$km{omzet}" if !$acc_kstomz; } } $extra .= " :$km{koppeling}=".$km{$kopp{$id}} if exists($kopp{$id}); $desc =~ s/^\s+//; $desc =~ s/\s+$//; my $t = sprintf(" %-4s %-2s %-40.40s %s", $id < $max_vrd ? (("0" x (length($max_vrd)-length($id)+1)) . $id) : $id, $flags, $desc, $extra); $t =~ s/\s+$//; print {$fh} ($t, "\n"); print {$fh} ("# ".__x("{id} ZOU EEN BALANSREKENING MOETEN ZIJN", id => $id)."\n") if $acc_balres && !$balres; print {$fh} ("# ".__x("{id} ZOU EEN RESULTAATREKENING MOETEN ZIJN", id => $id)."\n") if !$acc_balres && $balres; } } } } sub dump_btw { my $fh = shift; print {$fh} ("\n$km{hdr_btwtarieven}\n\n"); my $sth = $dbh->sql_exec("SELECT btw_id, btw_alias, btw_desc, btw_perc, btw_tariefgroep,". "btw_incl, btw_start, btw_end". " FROM BTWTabel". " ORDER BY btw_id"); while ( my $rr = $sth->fetchrow_arrayref ) { my ($id, $alias, $desc, $perc, $btg, $incl, $start, $end) = @$rr; my $extra = ""; $extra .= " :$km{tariefgroep}=" . $km{"tg_".lc(BTWTARIEVEN->[$btg])}; if ( $btg != BTWTARIEF_NUL ) { $extra .= " :$km{perc}=".btwfmt($perc); $extra .= " :$km{exclusief}" unless $incl; } $extra .= " :$km{vanaf}=$start" if $start; $extra .= " :$km{tot}=".parse_date($end, undef, 1) if $end; if ( $id >= BTW_CODE_AUTO ) { next unless $alias; $alias = sprintf("%-10s", $alias); } else { $alias = sprintf("%3d", $id); } my $t = sprintf(" %s %-20s %s", $alias, $desc, $extra); $t =~ s/\s+$//; print {$fh} ($t, "\n"); } } sub dump_dbk { my $fh = shift; print {$fh} ("\n$km{hdr_dagboeken}\n\n"); my $sth = $dbh->sql_exec("SELECT dbk_id, dbk_desc, dbk_type, dbk_dcsplit, dbk_acc_id". " FROM Dagboeken". " ORDER BY dbk_id"); while ( my $rr = $sth->fetchrow_arrayref ) { my ($id, $desc, $type, $dc, $acc_id) = @$rr; $acc_id = 0 if $type == DBKTYPE_INKOOP && $dbh->std_acc("crd", 0) == $acc_id; $acc_id = 0 if $type == DBKTYPE_VERKOOP && $dbh->std_acc("deb", 0) == $acc_id; my $t = sprintf(" %-4s %-20s :type=%-10s %s", $id, $desc, _xt("scm:dbk:".lc(DBKTYPES->[$type])), ($acc_id ? ":$km{rekening}=$acc_id" : ""). ($dc ? " :dc" : ""), ); $t =~ s/\s+$//; print {$fh} ($t, "\n"); } } ################ API functions ################ sub new { bless \my $x, shift; } sub add_gbk { my ($self, @args) = @_; my $opts = pop(@args); # currently unused my $in_transaction; my $anyfail; my $ret = ""; while ( @args ) { my ($gbk, $flags, $desc, $vrd) = splice( @args, 0, 4 ); if ( defined($flags) and defined($desc) and defined($vrd) ) { my ( $balres, $debcrd, $kstomz, $fixed ); ( $flags, $fixed ) = ( $1, !!$2 ) if $flags =~ /^(.)(!)$/; $flags = lc($flags); my $t = $dbh->lookup($gbk, qw(Accounts acc_id acc_desc)); if ( $t ) { warn "?". __x("Grootboekrekening {gbk} ({desc}) bestaat reeds", gbk => $gbk, desc => $t)."\n"; $anyfail++; next; } $balres = $dbh->lookup($vrd, qw(Verdichtingen vdi_id vdi_balres)); unless ( defined $balres ) { warn "?".__x("Onbekende verdichting: {vrd}", vrd => $vrd)."\n"; $anyfail++; next; } if ( $balres ) { if ( $flags =~ /^[dc]$/ ) { $debcrd = $flags eq 'd'; } else { warn "?"._T("Ongeldig type voor balansrekening (alleen D / C toegestaan)")."\n"; $anyfail++; next; } } else { if ( $flags =~ /^[kon]$/ ) { $kstomz = $flags eq 'k' ? 1 : $flags eq 'o' ? 0 : undef; } else { warn "?"._T("Ongeldig type voor resultaatrekening (alleen K / O / N toegestaan)")."\n"; $anyfail++; next; } } $dbh->begin_work unless $in_transaction++; $t = $dbh->sql_insert("Accounts", [qw(acc_id acc_desc acc_struct acc_balres acc_debcrd acc_dcfixed acc_kstomz acc_btw acc_ibalance acc_balance)], $gbk, $desc, $vrd, $balres, $debcrd, $fixed, $kstomz, undef, 0, 0); unless ( $t ) { warn "?".__x("Fout tijdens het opslaan van grootboekrekening {gbk}", gbk => $gbk)."\n"; $anyfail++; next; } } unless ( $anyfail ) { my $rr = $dbh->do("SELECT acc_desc, acc_balres, acc_debcrd,". " acc_kstomz, acc_dcfixed, vdi_id, vdi_desc, vdi_struct". " FROM Accounts, Verdichtingen". " WHERE acc_id = ?". " AND acc_struct = vdi_id", $gbk); unless ( $rr ) { warn "!".__x("Onbekende grootboekrekening: {gbk}", gbk => $gbk)."\n"; #$anyfail++; next; } my $t = $dbh->lookup($rr->[7], qw(Verdichtingen vdi_id vdi_desc)); $ret .= __x("{balres} {gbk} {debcrd}{fixed}{kstomz} ({desc});". " Verdichting {vrd} ({vdesc});". " Hoofdverdichting {hvrd} ({hdesc})", balres => ($rr->[1] ? "Balansrekening" : "Resultaatrekening"), gbk => $gbk, desc => $rr->[0], debcrd => ($rr->[1] ? ($rr->[2] ? "Debet" : "Credit") : ""), kstomz => ($rr->[1] ? "" : defined($rr->[3]) ? $rr->[3] ? " Kosten" : " Omzet" : " Neutraal"), fixed => $rr->[4] ? "!" : "", vrd => $rr->[5], vdesc => $rr->[6], hvrd => $rr->[7], hdesc => $t, )."\n"; } } if ( $in_transaction ) { $anyfail ? $dbh->rollback : $dbh->commit; } return $ret; } 1; EekBoek-2.030.1/lib/EB/Tools/Attachments.pm0000644000400000040000000001142513045163576015742 0ustar jvjv#! perl use utf8; # Author : Johan Vromans # Created On : Tue Oct 6 13:55:54 2015 # Last Modified By: Johan Vromans # Last Modified On: Fri Feb 3 21:26:38 2017 # Update Count : 92 # Status : Unknown, Use with caution! package main; our $dbh; our $config; package EB::Tools::Attachments; use strict; use warnings; use Fcntl qw(O_RDONLY O_WRONLY O_CREAT); use File::Temp; use EB; sub new { my ( $pkg, %init ) = @_; bless { id => 0, name => undef, path => undef, encoding => 0, checksum => undef, content => undef, %init }, $pkg; } sub store { my ( $self, $id ) = @_; $self->{id} ||= $id || $dbh->get_sequence("attachments_id_seq"); $self->{encoding} ||= ATTENCODING_BASE64; $self->{size} ||= $self->{encoding} == ATTENCODING_URI ? length( $self->{name} ) : length( ${ $self->{content} } ); my $att_id = $dbh->store_attachment($self); $self->set_sequence( "attachments_id_seq", $self->{id} ) if $id; return $self->{id}; } sub store_from_uri { my ( $self, $uri, $id ) = @_; $id ||= $self->{id}; $self->{encoding} = ATTENCODING_URI; $self->{name} = $uri; $self->store; } sub store_from_file { my ( $self, $filename, $id ) = @_; $id ||= $self->{id}; my $file = $filename; sysopen( my $fd, $file, O_RDONLY ) or die(__x("Bijlage {file} kan niet worden opgeslagen: {err}", file => $filename, err => "".$!)."\n"); my $cnt; my $buf = ""; my $offset = 0; # my $ctx = Digest::MD5->new; while ( ( $cnt = sysread( $fd, $buf, 20480, $offset ) ) > 0 ) { =begin later unless ( defined $type ) { if ( $buf =~ /^\%PDF-/ ) { $type = ATTTYPE_PDF; } elsif ( $buf =~ /^\x89PNG\x0d\x0a\x1a\x0a/ ) { $type = ATTTYPE_PNG; } elsif ( $buf =~ /^\xff\xd8/ ) { $type = ATTTYPE_JPG; } elsif ( $buf =~ /^[[:print:]\s]*$/ ) { $type = ATTTYPE_TEXT; } else { die(__x("Bijlage {file} is van een niet-ondersteund type", file => $filename)."\n"); } } =cut $offset += $cnt; } die(__x("Bijlage {file} kon niet worden gelezen: {err}", file => $filename, err => $!)."\n") unless $cnt == 0; close($fd); # $ctx->add($buf); # $self->{checksum} = $ctx->hexdigest; $self->{content} = \$buf; $self->{name} ||= File::Basename::fileparse($file); $self->{size} = $offset; $self->store; } sub drop { my ( $self, $id ) = @_; $dbh->drop_attachment( $id || $self->{id} ); } sub get { my ( $self, $id ) = @_; my $href = $dbh->get_attachment( $id || $self->{id} ); # { name => $name, encoding => $enc, content => \$data } return $href; } sub save_to_file { my ( $self, $filename, $id ) = @_; my $atts = $self->get( $id || $self->{id} ); # HashRef! for ( qw( name content ) ) { $self->{$_} = $atts->{$_}; } if ( $atts->{encoding} == ATTENCODING_URI ) { my $content = $self->{name} . "\n"; $self->{content} = \$content; } my $fd; if ( $filename ) { sysopen( $fd, $filename, O_WRONLY|O_CREAT, 0666 ) or die("?".__x("Fout bij aanmaken bestand {file}: {err}", file => $filename, err => $!)."\n"); } else { $fd = File::Temp->new( UNLINK => 0, SUFFIX => "__" . $self->{name} ); $filename = $fd->filename; } syswrite( $fd, ${ $self->{content} }, length( ${ $self->{content} } ) ) == length( ${ $self->{content} } ) or die("?".__x("Fout bij schrijven bestand {file}: {err}", file => $filename, err => $!)."\n"); $fd->close or die("?".__x("Fout bij afsluiten bestand {file}: {err}", file => $filename, err => $!)."\n"); return $filename; } sub save_to_zip { my ( $self, $zip, $membername, $id ) = @_; my $atts = $self->get( $id || $self->{id} ); # HashRef! my $m = $zip->addString( $atts->{content}, $membername ); # Error check not needed? $m->desiredCompressionMethod(8); } sub open { my ( $self, $id, $output ) = @_; $id ||= $self->{id}; my $href = EB::Tools::Attachments->new->get($id); my $file = $self->save_to_file( $output, $id ); return if defined $output; if ( $^O eq "MSWin32" ) { if ( $Wx::VERSION ) { Wx::LaunchDefaultBrowser("$file"); } else { system("start", $file); # ???? } unlink($file); } elsif ( $^O eq "OSX" ) { # Do we need to sleep here? system("sh -c 'open \"$file\"; rm -f \"$file\"'&"); } else { # xdg-open spawns the right tool and exits immediately. system("sh -c 'xdg-open \"$file\"; sleep 5; rm -f \"$file\"'&"); } } sub attachments { my ( $self ) = @_; my $ret = []; my $sth = $dbh->sql_exec("SELECT att_id,att_name,att_encoding FROM Attachments ORDER BY att_id"); while ( my $rr = $sth->fetchrow_arrayref ) { push( @$ret, { id => $rr->[0], name => $rr->[1], encoding => $rr->[2] } ); } $ret; } 1; EekBoek-2.030.1/lib/EB/Booking.pm0000644000400000040000000003062113044346163013750 0ustar jvjv#! perl -- -*- coding: utf-8 -*- use utf8; # Booking.pm -- Base class for Bookings. # Author : Johan Vromans # Created On : Sat Oct 15 23:36:51 2005 # Last Modified By: Johan Vromans # Last Modified On: Thu Jan 26 16:39:38 2017 # Update Count : 226 # Status : Unknown, Use with caution! package main; our $cfg; our $dbh; package EB::Booking; use strict; use warnings; use EB; use EB::Format; use EB::Tools::Attachments; sub new { my ($class) = @_; $class = ref($class) || $class; return bless {} => $class; } sub adm_open { my ($self) = @_; unless ( $dbh->adm_open ) { warn("?"._T("De administratie is nog niet geopend")."\n"); return; } 1; } sub check_bsk_nr { my ($self, $opts) = @_; my $bsk_nr = $opts->{boekstuk}; my $bky = $opts->{boekjaar}; $bky = $dbh->adm("bky") unless defined($bky); my $dbk = $opts->{dagboek}; my $rr = $dbh->do("SELECT count(*) FROM Boekstukken". " WHERE bsk_nr = ? AND bsk_dbk_id = ? AND bsk_bky = ?", $bsk_nr, $dbk, $bky); return 1 if defined($rr) && $rr->[0] == 0; warn("?".__x("Boekstuk {bsk} is reeds in gebruik", bsk => join(":", $dbh->lookup($dbk, qw(Dagboeken dbk_id dbk_desc)), $bsk_nr))."\n"); return; } sub bsk_nr { my ($self, $opts) = @_; my $bsk_nr; my $prev = defined($opts->{boekjaar}) && $opts->{boekjaar} ne $dbh->adm("bky"); $bsk_nr = $opts->{boekstuk}; if ( defined $bsk_nr ) { unless ( $bsk_nr =~ /^[0-9]+$/ ) { warn("?"._T("Het boekstuknummer moet een geheel getal (volgnummer) zijn")."\n"); return; } return unless $self->check_bsk_nr($opts); my $t = $prev ? "0" : $opts->{dagboek}; $dbh->set_sequence("bsk_nr_${t}_seq", $bsk_nr+1) # if $dbh->get_sequence("bsk_nr_${t}_seq", "noincr") < $bsk_nr; } elsif ( $prev ) { warn("?"._T("Boekstukken in voorafgaande boekjaren moeten verplicht worden voorzien van een boekstuknummer")."\n"); return; #$bsk_nr = $dbh->get_sequence("bsk_nr_0_seq"); } else { $bsk_nr = $dbh->get_sequence("bsk_nr_".$opts->{dagboek}."_seq"); $opts->{boekstuk} = $bsk_nr; return unless $self->check_bsk_nr($opts); } $bsk_nr; } sub begindate { my ($self) = @_; my $begin; my $end; if ( $self->{bky} ne $dbh->adm("bky") ) { my ($b, $e, $c) = @{$dbh->do("SELECT bky_begin, bky_end, bky_closed". " FROM Boekjaren". " WHERE bky_code = ?", $self->{bky})}; if ( $c ) { warn("?".__x("Boekjaar {code} is gesloten, er kan niet meer in worden gewijzigd", code => $self->{bky})."\n"); return; } $begin = $b; $end = $e; } elsif ( $dbh->adm("closed") ) { warn("?"._T("De administratie is gesloten en kan niet meer worden gewijzigd")."\n"); return; } $begin ||= $dbh->adm("begin"); return $begin unless wantarray; $end ||= $dbh->adm("end"); ($begin, $end); } sub in_bky { my ($self, $date, $begin, $end) = @_; if ( $date lt $begin ) { warn("?".__x("De boekingsdatum {date} valt vóór aanvang van dit boekjaar", date => datefmt_full($date))."\n"); return; } if ( $date gt $end ) { warn("?".__x("De boekingsdatum {date} valt na het einde van dit boekjaar", date => datefmt_full($date))."\n"); return; } 1; } sub amount_with_btw { my ($self, $amt, $btw_spec) = @_; my $explicit; if ( $amt =~ /^(.+)\@(.+)$/ ) { $amt = $1; $btw_spec = $2; $explicit = $btw_spec !~ /^[hlgn]?[-+]?[ko]?$/i; } return (amount($amt), $btw_spec, $explicit); } sub parse_btw_spec { my ($self, $spec, $btw_id, $kstomz) = @_; return (0, undef) unless defined($spec); $spec = lc($spec); # Quickie for G/N. if ( $spec =~ /^([gn])$/ ) { return (0, undef); } # Quickie for K/O. elsif ( $spec =~ /^([ko])$/ ) { return ($btw_id, $1 eq 'k'); } # Strip off trailing K|O. elsif ( $spec =~ /^([hl]|\d+)([-+]?)([ko])$/ || $spec =~ /^(\w+)([-+])([ko])$/ ) { $kstomz = $3 eq 'k'; $spec = $1.$2; } =begin deprecated # Deprecated since several years... elseif ( $spec =~ /^(.*)([iv])(.*)$/ ) { $kstomz = $2 eq 'i'; $spec = $1.$3; warn("!".__x("BTW specificatie {spec}: Gebruik K of O in plaats van I of V", spec => $_[0])."\n"); } =cut # Examine rest. Numeric -> BTW id. if ( $spec =~ /^(\d+)([-+])?$/ ) { $btw_id = $1; if ( defined $2 ) { my $excl = $2 eq '-'; my $res = $dbh->do("SELECT btw_perc, btw_tariefgroep FROM BTWTabel". " WHERE btw_id = ?", $btw_id); return unless $res; $res = $dbh->do("SELECT btw_id FROM BTWTabel". " WHERE btw_perc = ? AND btw_tariefgroep = ?". " AND ".($excl?"NOT ":"")."btw_incl", $res->[0], $res->[1]); return unless $res; $btw_id = $res->[0]; } } # H L H- L- H+ L+ elsif ( $spec =~ /^([hl])([-+])?$/ ) { $btw_id = $1; my $excl; $excl = $2 eq '-' if defined $2; my $res = $dbh->da("SELECT btw_id, btw_alias, btw_desc FROM BTWTabel". " WHERE btw_tariefgroep = ?". " AND ".($excl?"NOT ":"")."btw_incl". " ORDER BY btw_id ASC", $btw_id eq "h" ? BTWTARIEF_HOOG : BTWTARIEF_LAAG); warn("!".__x("BTW aanduiding \"{spec}\" kent meerdere tariefcodes: {list} (code {code} \"{desc}\" is gebruikt)", spec => $spec, list => join(" ", map { defined($_->[1]) ? $_->[1] : $_->[0] } @$res), code => $res->[0]->[0], desc => $res->[0]->[2], )."\n") if @$res != 1; $btw_id = $res->[0]->[0]; } # alias elsif ( $spec =~ /^(\w\w+)([-+])?$/ ) { # warn("SPEC: $spec\n"); $dbh->trace(1); my $res = $dbh->do("SELECT btw_id, btw_perc, btw_tariefgroep FROM BTWTabel". " WHERE btw_alias = ?", lc $1); # $dbh->trace(0); return unless $res; $btw_id = $res->[0]; if ( defined $2 ) { my $excl = $2 eq '-'; # $dbh->trace(1); $res = $dbh->do("SELECT btw_id FROM BTWTabel". " WHERE btw_perc = ? AND btw_tariefgroep = ?". " AND ".($excl?"NOT ":"")."btw_incl", $res->[1], $res->[2]); # $dbh->trace(0); return unless $res; $btw_id = $res->[0]; } # warn("SPEC: $spec => $btw_id\n"); } # + - elsif ( $spec =~ /^([-+])$/ && $btw_id ) { my $res = $dbh->da("SELECT btw_id, btw_desc FROM BTWTabel". " WHERE btw_tariefgroep =". " ( SELECT btw_tariefgroep FROM BTWTabel". " WHERE btw_id = ? )". " AND ".($1 eq '-'?"NOT ":"")."btw_incl", $btw_id); warn("!".__x("BTW aanduiding \"{spec}\" kent meerdere tariefcodes: {list} (code {code} \"{desc}\" is gebruikt)", spec => $spec, list => join(" ", map { $_->[0] } @$res), code => $res->[0]->[0], desc => $res->[0]->[1], )."\n") if @$res != 1; $btw_id = $res->[0]->[0]; } elsif ( $spec ne '' ) { return; } ($btw_id, $kstomz); } #### Class method sub norm_btw { my ($self, $bsr_amt, $bsr_btw_id) = @_; my ($btw_perc, $btw_incl); if ( $bsr_btw_id ) { my $rr = $dbh->do("SELECT btw_perc, btw_incl, btw_tariefgroep". " FROM BTWTabel". " WHERE btw_id = ?", $bsr_btw_id); confess( "Unknown BTW: $bsr_btw_id" ) unless $rr; ($btw_perc, $btw_incl) = @$rr; } return [ $bsr_amt, 0 ] unless $btw_perc; my $bruto = $bsr_amt; my $netto = $bsr_amt; if ( $btw_incl ) { $netto = numround($bruto * (1 / (1 + $btw_perc/BTWSCALE))); } else { $bruto = numround($netto * (1 + $btw_perc/BTWSCALE)); } [ $bruto, $bruto - $netto, $btw_perc ]; } #### Class method sub dcfromtd { # Calculate a (debet,credit) pair from a (total,debet) pair. my ($total, $debet) = @_; return ($debet, $debet-$total) if defined($debet); return ($total, 0) if $total >= 0; (0, -$total); } #### Class method sub journalise { my ($self, $bsk_id, $iv, $total) = @_; $total = -$total if defined($total) && !$iv; # date bsk_id bsr_seq(0) dbk_id (acc_id) amount debcrd desc(bsk) (rel) # date (bsk_id) bsr_seq(>0) (dbk_id) acc_id amount debcrd desc(bsr) rel(acc=1200/1600) my ($jnl_date, $jnl_bsk_id, $jnl_dbk_id, $jnl_acc_id, $jnl_amount, $jnl_desc, $jnl_rel); my $rr = $::dbh->do("SELECT bsk_nr, bsk_desc, bsk_dbk_id, bsk_date, bsk_ref". " FROM Boekstukken". " WHERE bsk_id = ?", $bsk_id); my ($bsk_nr, $bsk_desc, $bsk_dbk_id, $bsk_date, $bsk_ref) = @$rr; my ($dbktype, $dbkdcsplit, $dbk_acc_id) = @{$::dbh->do("SELECT dbk_type, dbk_dcsplit, dbk_acc_id". " FROM Dagboeken". " WHERE dbk_id = ?", $bsk_dbk_id)}; my $sth = $::dbh->sql_exec("SELECT bsr_nr, bsr_date, ". "bsr_desc, bsr_amount, bsr_btw_class, bsr_btw_id, ". "bsr_btw_acc, bsr_type, bsr_acc_id, bsr_rel_code, bsr_dbk_id". " FROM Boekstukregels". " WHERE bsr_bsk_id = ?", $bsk_id); my $ret = []; my $tot = 0; my ($dtot, $ctot) = (0, 0); my ($vhtot, $vltot) = (0, 0); my $nr = 1; my $vat; # for automatic rounding VAT calc my $g_bsr_rel_code; while ( $rr = $sth->fetchrow_arrayref ) { my ($bsr_nr, $bsr_date, $bsr_desc, $bsr_amount, $bsr_btw_class, $bsr_btw_id, $bsr_btw_acc, $bsr_type, $bsr_acc_id, $bsr_rel_code, $bsr_rel_dbk) = @$rr; my $bsr_bsk_id = $bsk_id; my $btw = 0; my $amt = $bsr_amount; my $btw_intra = ($bsr_btw_class & BTWKLASSE_TYPE_BITS) == BTWTYPE_INTRA; $g_bsr_rel_code = $bsr_rel_code if defined $iv && $bsr_rel_code; if ( ($bsr_btw_class & BTWKLASSE_BTW_BIT) && $bsr_btw_id && $bsr_btw_acc && !$btw_intra ) { ( $bsr_amount, $btw, my $perc ) = @{$self->norm_btw($bsr_amount, $bsr_btw_id)}; $amt = $bsr_amount - $btw; $vat->{$bsr_btw_acc}->{amt} += $amt; $vat->{$bsr_btw_acc}->{btw} += $btw; $vat->{$bsr_btw_acc}->{prc} = $perc; } $tot += $bsr_amount; $dtot += $bsr_amount if $bsr_amount < 0; $ctot += $bsr_amount if $bsr_amount > 0; my $btwtag = _T("BTW "); push(@$ret, [$bsk_date, $bsk_dbk_id, $bsk_id, $bsr_date, $bsr_nr, $nr++, 0, $bsr_acc_id, $bsr_amount - $btw, undef, $bsr_desc, $bsr_type ? ($bsr_rel_code, $bsr_rel_dbk) : (undef, undef), undef]); push(@$ret, [$bsk_date, $bsk_dbk_id, $bsk_id, $bsr_date, $bsr_nr, $nr++, 1, $bsr_btw_acc, $btw, undef, $btwtag.$bsr_desc, undef, undef, undef]) if $btw; } if ( defined($total) && $tot != $total && $cfg->val(qw(strategy iv_vc), 1) ) { # mismatch! #warn("=> $tot <-> $total\n"); # Vaak het gevolg van verschil in BTW berekening per # boekingsregel versus per boekstuktotaal. while ( my($k,$v) = each(%$vat) ) { # Bereken BTW over totaal van deze tariefgroep. my $t = numround($v->{amt} * ($v->{prc}/BTWSCALE)); if ( $t != $v->{btw} ) { # Aha! #warn("=> [$k] $v->{btw} <-> $t\n"); # Corrigeer het totaal, en maak een correctieboekstukregel. $tot -= $v->{btw} - $t; push(@$ret, [$bsk_date, $bsk_dbk_id, $bsk_id, $bsk_date, undef, $nr++, 1, $k, $t - $v->{btw}, undef, _T("BTW Afr. ").$bsk_desc, undef, undef, undef]); warn("!".__x("BTW rek. nr. {acct}, correctie van {amt} uitgevoerd", acct => $k, amt => numfmt($t-$v->{btw}))."\n"); } } } if ( $dbk_acc_id ) { if ( $dbkdcsplit ) { push(@$ret, [$bsk_date, $bsk_dbk_id, $bsk_id, $bsk_date, undef, $nr++, 0, $dbk_acc_id, -$tot, -$dtot, $bsk_desc, undef, undef, undef]); } else { push(@$ret, [$bsk_date, $bsk_dbk_id, $bsk_id, $bsk_date, undef, $nr++, 0, $dbk_acc_id, -$tot, undef, $bsk_desc, undef, undef, undef]); } } unshift(@$ret, [$bsk_date, $bsk_dbk_id, $bsk_id, $bsk_date, undef, 0, 0, undef, undef, undef, $bsk_desc, $g_bsr_rel_code, undef, $bsk_ref]); $ret; } sub check_attachment { my ( $self, $att ) = @_; return 1 unless defined $att; return 1 if $att =~ m;^(\w+)://(.+);; # URI if ( ! ( -f $att && -r _ ) ) { warn("?".__x("Boekingsbijlage kan niet worden gevonden: {att}", att => $att)."\n"); return; } return 1; } sub add_attachment { my ( $self, $att, $bsk_id ) = @_; return unless defined $att; my $att_id; if ( $att =~ m;^(\w+)://(.+); ) { # URI if ( $1 eq "int" && $2 =~ m;^(\d+)/.+; ) { $att_id = $1; } else { $att_id = EB::Tools::Attachments->new->store_from_uri($att); } } else { # We may at some point in time decide to turn $file into # file://$url and treat as such. $att_id = EB::Tools::Attachments->new->store_from_file($att); } $dbh->sql_exec("UPDATE Boekstukken SET bsk_att = ? WHERE bsk_id = ?", $att_id, $bsk_id); } sub find_attachment { my ( $self, $bsk_id ) = @_; $dbh->lookup( $bsk_id, qw(Boekstukken bsk_id bsk_att =) ); } 1; EekBoek-2.030.1/lib/EB/res/0000755000400000040000000000000013151742350012606 5ustar jvjvEekBoek-2.030.1/lib/EB/res/help/0000755000400000040000000000000013151742350013536 5ustar jvjvEekBoek-2.030.1/lib/EB/res/help/nl/0000755000400000040000000000000013151742350014147 5ustar jvjvEekBoek-2.030.1/lib/EB/res/help/nl/docs.htb0000644000400000040000000354552213151307566015624 0ustar jvjvPK yK bookings/UT uYvYux PKyK띃j{bookings/receivable.htmlUT uYuYux XmoF_eqv H*E&^$GF$].%[.)v^ )<3WؐiI,t*V{1=_D/n~[ݻ/߾4I>N?TYB,1lU."1_slIy?]NdZ7KJAyxBl((մBՂ˂FbE֙%Y>/awj8*:2<2Me4h33qCbMݎI9ZJVl8AQ",<% *ǵةl4қ -H@PFf+˧}W( g G%ڤDe>^{M~ռUDZ)z¼%TI%<_ om 8O/{H2/ܫ%l6ɾ RgkcIdl۫yH"h{yz&NO'ӳĵۮīwds$[2u"cU]bQY62m@R(V7nGŜi7O9/m"}DT9(O\)Cڮ⻋8GcU:5^+ѹDB:l98X6ASٶ_ B]}n!t'boc * 27F3Ce?վ;sv6wTю?]U{a\YPR ݇iP*cq\X :|<^a@a]TuWƂUP"s7`pؘBW; <'3\1P?g<ށu߶]"Rpv' Ee(c^-y>}E,'.|QMzŤcPdYz?z͋{t/򄻆ѥ cRH#Q(TZ* 8̥R#˸2D.O ~bG:lI̯y AzӲBTprF>aSV~f/|  `3$.At)S=0CԌP,`c!]i_ƽYvP=fkϲS1ff̎CR>W82.&`QW/M l1kX>^҃G;9W/׆Vso܊_ {Y,l\qўΌ9SHvVW7~-oY[u"[n;63P&]H r5A:T*S|g—mc4g."@ƽ-ӱ1VI͔ .p`R' F7UTiP2)U]v)n 9QВ݅S`pG$I'EwPKyKi^@bookings/index.htmlUT uYuYux Wr6}WL.3i;M82O&n:} $b}w^Dۙ/ՋD8.VKփ6B5$:4ESCaիW'MpW/X?_\ͥSt|n4o8=Dr7K6IiEb:4V)lJ uEqfL^!!-C ,u}T,-2%^?>!>d2:vxA$ĻvD`8De %Iof_<_#saxt>n=yܺccx6 P+-8B|8gw'1 i;b)\@ԣ7"JYڨ  Tۢٳ;V`lγ,n޻]C)(8 BV6 #E4`3EVZWNG,[R4A,Ӑ Ka]b@/]!jBS5/IHnH-`~ CL'-=کN7Vj:.*eP9,w:vB8r!؍j1":~'8)`3:LbH,S9~RPnjU ;6JZ]yNT]sĄґ(Z;92>jKU5$"GbJ05nb+2tu;G P@Mъ5R",]̿Js~7憮GKgOņ.Mqʞ, {fJN-"/~-(R[t D\%PWEa+M ?EPIgrlN TxqvD[rŔNT麡3ڳz3tV~{'x"h*7%<7SB{7P_>`{_Gi (^21F±wԟewُ.\cyiEӖ|VWiKh2%Q2UgvOuClfLt>u:+@"xAbZ9bf{:6RAj΢]''Oi[<< ](7UF{KNax3yUZV 5jZGO*R%k)+)Kz@J5fL1H# JF " *\d" P;蝪 Jx]˙֤fX eǕXjUWi5a+dէ37j3"<@lo|.*qp]يŬF@!SG6~6>AJl/^ؚP`s6J"jxib .wWru@Xºz l@عlB\{8Kan,E~,`'fA g)q(c?QHm{:!?[ _f})B`Ƕ֮D_Í8G@C\S!n›KTwa#t;F7}> 8]%Dt ``]Mu/ yMC 1jqh[[gyܧcdk(w MC=zli)MrW,N.4 "4*zM!?A45RT"wWwD2(qq,%zS7ob%mMա2B0&\Y^e\)+Ve4D W5r:51 &.vZPb^ػU>$ƎlYA7;"hPQ- d.?Wuw_XSb?uF2{IsG׬ ɖn9e/9$Ҍ)XZsTJg+o5GY. CS:IM~d5qN9? %~ͱ% pjk2!!\&M7G?a:يک@>NN B/3r# [hMZGtv3vE\xN[o+`uEl CN(Y\ /X8Mo/8vCqyA;3q9\n*R0TY@|ݫF!yJfg +RwI|IWu{ܮ"Ų=(. l.W"r#Mg'3; : Akfh b=+,)tMӾ5/Bc>9cqQFD a|4Sj'X?UM+oS H<3g)`:Nq?EZ5lJZh0iOzUFR#NN;8~ xx"u/ʛ}1Ο[;hD6_)/*wy=e uv떧'cSذǧd,E),q^ar‘qbx9S{zP b-CbmT`T0dg#BŠ0YY3x;|hnUrͷ-]%;5R3J2$APbiɗ8>?em7|O% cd|WUNވb&IJ˵82޽WB:N->wfTI],V늮nr< $ӊr݃T9Ujc+WMD"2/rPKyK4ABRbookings/memorial.htmlUT uYuYux mT]8}ϯd%ԙVشHH&n;k;L=:n) Ccs]}5lye<9lL3ϕ?_.򷋬|r[[~xz (.8ƫ@RǜEe( e1Vzѷ!z QT^r? ]L#j'=E4{x4 ZU Y*_X$0|C-&=1UБSMC<)3HI \>qtON7qbʂC}S1Lx6')I~4hE[MːPKyKBE{bookings/oneline.ttUT uYuYux eRMo0 WSc% `M2@aQX[,&h1^%$z { xWI>ڸ&tz}3Y_o~`vu71\fqj|!FUVOʠPiP!U!O>Uq[hKh1v$ x_NnԠxW>W#T:&`COxQU\|!M"ήf=]If}fC^Y,U-Zk Vל 5ZXM=BsQiOʗ?rw2ځPs1GC`7v H^@zKB'wOjp@&yѵE cD :)TQcaxi?eg5Ys/ř)V%Ot3oI3CQ#}*thCrtYEˁ'*HPKyK= Qbookings/payable.htmlUT uYuYux Yis_1 W|TH2-ɑʊ(q/ !J~}^DM*)sp]TGx0 sErӏ'Wtί|>ʼn 睓>ꪊ:5X5ʆó!/Mj(Ʒdt<oJUQ$2ZV8 ἮX#TKIG;B^zh_3Qd3]O'I;Ox[wty[Ed|Xi].YWT ,[]JhieTZ(e%|nB-ɈSg?NR=+;i%J/ (TLjE{pQDQZT@}+&QD0"X8PBYzRu1K[ͭ̃3h4rlLBaՌ(zQ5F`&p1>j"DxQq`4^69 E6cz8<*KmKav}2=_CjEu} )<Nvx?:OF}T,U&]w'g~u"lwn3$@cT}n,hP)(R`|& Kw)Z95j:nǜ#}bT ));;x[@ZtOŋk1\e1áz6\F=:K dtV7:Kr-%HodqRf=[F=e Iog#ecJGR\)BMx2aF7 @Q@IcEweSy.9؛4T:m7:gwQI&X,. ki0Bό{믙s$`ᨉ i622) k2tGK&#SL]fim~[ WWh9!IjAzgd$&W'TH-(VF{<)*'=`o"kȏ#CKߠI0-#JÞ n4q( g=0dew u[CRu~'Ln(̏ܢK.=-c-%QgV'¨c 7Ұ:z{_4O霗cjmAߎp>*F ' FrVXͩEKa3qF(vW ފ+&Z=$~VXc۳%EVͨ"\NŞ\~UkY_ hHW#9PL6`ںl:*sMMuYJӵE.:T\k,@Zќu{Bs|I%z>V -Yp4?h6#79f?^]G H.s&mYC.ś.L;,28/@$;͠:15nrq@l$V|a)t/ү1pb``}6~zUg:\ jR F)%xUY;URpVBR5Dm Rǭ[SeaJlZwWmUJGř}י6T83Rx놷D2AlOig*!| Xlφ]&FJP6Tvg"Sxw`x1)Mb[_F1ԋH5&{`F'Y-Jdz2Q=/d^d:OcD/s6ï/}qmE j:/3k>YP-/5^cket75>h7ynɨpW"+יEiDEcvѾ\i`mW)5 }yeCqHl !t|BڄEd-2^9^r()8{Icl:(}$~+р= N[>YlhlER"$#}$$Bмl1NjZr͢&0~e9_Y&[7#ŰD~$!~Q J^q0T,qog,8zԣѓ{'*v[GFjqo2/ثIOBh`sf 9| $!mQޔ˅ **̽κFJ.*!K\Ix+ȻR;>v6|__ PKyK>Ybookings/cash.htmlUT uYuYux URMo0 Wp])V lXaú zclVHM~(Z^G|b&֮Ѷ-n2_]Of7~Ϸ &JPZUG9ʣ :2*w뻸3eyG yP~(Il{K?Dzh$"]T'<m} b] 鿟>>8],2cM|"#YǯĔ"Fn`^N 8F:ąaq2#J A4B@GTIM+eB׶"GؽUW: ;m;`ڶ1Mb6(%cʈ用]ʱ&;U튆Lvz[$ p-oW. ^KY[ ԯ`xno罿jd{4Ef@B`ɺ>Ix^z:>x$GH<=y)KeL\k0vd3wg4;$@t^LBͅmR&ޝ'>::N@S`Qyg,P]Ma5!KW /ݑL`mU֡f}x#b.:T_uUfWjEG_ .P]L֘ ADLj3m V ;ӻAӝqq5zMNVw. UmeװN>WAl˶@.;˿ upDdFYkZPfUHՄX8bOj-60=ZŦCkT: =Ѓ4%r& RG|~Mġij ?= Iٚt"NMAwM/k]M^J2eQPee mMC[9B/)0=3]MI_7:)` 9xBPM E] I{l'v Ţn鋋x B7Q04+K@H蠶7km^6vX<-eD6NTg AStU"O?7X Xw|#cU&5o2#n[q*ee3gG4$CL&j0"nƁU$ޣQg7K  }Tۗ&@ KC%`25l|Bbuꣴ EVBJQ9NSqEllGݒH`8{+p%6kք} OaNȩCܥ-^72s?ӭ^D#d(l\ËC 8DHzę;#?୉'d #Bjut"i?!˳[8өx;ވx2dro<}&>W2LN? -8\(oqhJ˥T~4\ P,*5?z U RGC ^# &&: a`) .e!^[SuTj5UeJ@9 r:>Qb=!ֲjڨ2UjaU ]f}q6JkїTaRJU([ }Hx.gzHH&ql<@pb_KPVXYPmnL&ӕ.a;x] )+~2[خV[q{'㊎{ 3t|u$SZdtZiBMҀԬȀ55@nRUZ+ȟxUE!!82.pʪ$ P:筦|2Mqd<ǡÉ|οxds> `]9(tL#4j*h$bKVfS*Jl@K2=P`IDP"AKPeelyP=Afl)N=[4R.m \+۬&CQ1ؠ4|ڣC=?#\&bʟ{cʭpF*OK2\fζ`Sz"^G!:l ؃rY v,8lXeaKHիJ.9@E\FUt9 ;E'Ѓ+ԉ@@=?P2R@ mV6֮&ѕ^JLLMjrVB1FbsQ \'&:}&btμxCMڒ_P+'<=UYsP | o->R U`iڬ@VYܲet{FPȯ9EyҪYZo$dIYWĕ~@ԠdaVt0@}d^za\[ j* /dErY0q#٘3@KI [ȕ!<~jr8MމRO@x  8Vݐ"5<=?3[An2Bbǿ )v)Rc~JɅ]Bp%T HG~cAd,U>g&MҳgmR:+T,לh@f=<'ʜb8j$H5tVהK@T"cc Ξ< <R'Iǜ3H@))ү:>+ |%S 2\gp5-d ^ ўM۷:02 S'Deۃ턶ulz?f`߲G#umVv ,=W,jxtőReIaooT~l)@Ja=㴴*Xmѫx9>m\ז3m{un_)zpZ!=1ǜCJ],W5b}U4k3U?rc4pKJب+4i&o ,lKI a<< XIZz;y޻RWiHGQ]b6o~M& ڪxۓoedO-ND\X`9S!Me3^F3tHm9㏚+n\LqيSd]&Q0ƻO=T*sy%^ȏ8vERSm̟.{TRrmXA,rD葱ns@Me!G2+P|K@ݫ;ԀcYK4 &1]DT3l7>7z3LSv#!\җR7՗D)p<* 5Tu` e&'x$.yvG^wd _xT0";;==AH\4N #c7%(GGR֔d[L$K5w%5yf*m >([_oEO""R*OP;Z eqQ@8cDG0f#j,ËqlPI> .$A.{B4؀USMiD v؆ X߀  fs A B(Iܽ»[r6zh `ގq\R!{CuZUxTx*oƯk wz5X@aҹD䗲,!EcQE'PJebMr_dٲ+~. ++Bs6_zcB3!S܌&II;D}nNl7K44[X̣qʈ8M ap^_߱5M}g#@L@fE[E1Bf&Jw&{u!SKa·= /Bc11HXw/{DalS7Q^'gÀ͵ՙ7:l/ Z7$ޘV/A^qN13UEєF s`7`-r܄af*%sWz֩;<ڬH?lVq86 'ΫKTitzT@/$35TF8['(hc_fY)ZJ̱OҨ{H`Yw&ձw4'F7`}p@ &\"Nٴ)9S#qRw  4#?AD`2`h{tm8RM< >pP@cHu!Ob' (<5$N[# ފFMEB_ |JBB!17 i?qd& d9do;h Rt}M. f;4L1!&T|;G* ܼekVOP!#gtҠq,-K4 }S\nZ\]tGEpm!Tpmѻ$VÞ&mrm.7<}}p@ }p{wD:9 *Ćdb./2܃Bj(F:R?RMLd=a8aε7UaBޡh5NCø "Hs=o,CAHWݹל8ewov7EzLMxS ܶ?W8·}nꇮU1j㓓ǣrZ^˳QJ-; |>~7#>:w`6"q| ;k -Nqv YW=q,R8AD{BAlN%|0MDr,wE&4HѹK*: j E , V:\BSjCSFETΪ]Y:px c 9b`qрm9cr iƿ. .u,Ika<+;CR"w nO?> ^(3l}?FH;85t `OAq7N;FJTJ+> &w=]g[-.>Í/fu5{+ M;OHTmɭُ;W)se .@c8+;FN]%[J7R1T"$9n鍣?U79۶n[q\:o|W4?r>Gb /@溉<[Ӈu_^lM{:w}1:{hIm."\p-<,բ =ݎ&랣:] a%wmS?՘?|p^_` u354)!ѥQWߋ:ɣF$#HY$vl{uoSD7d:EI|./3jY:$5v`Ěj$OZvxYG(UgR\KH~t9")/x , NpF֐_mZ@\b/j}t\{{u`>7%9GA\`8$c>44֡ ?kϏPK yKcss/UT uYvYux PKyKV, css/cheat.cssUT uYuYux 1 w~ť[kh~ђ 4@4Ŵz}}L=ÝA9|n (jX>Zt5]([U> }jEk7|={m(-ԕ0f28ͺ%$iT%C`qիZ߭:X=PKyK%խY css/site.cssUT uYuYux Քn0 ~ .E:di(lw-:&*$톼,8V4'")hE9GAl%.UM1贲j)3/h(TtJl証O`o}%dK\塬\E׋,Һ >(v79vKkrkp1s띏H%5`䒐&^C/k,)!X8Zڮ"mTSMh] eo {O@ αG̫O9xԢB܈#xB5|'] -i077m_NdCpqcÂI/(ɮ?. gVeRUA_Qf0|͠f!1<&7PKyK:j date.htmlUT uYuYux Tmo0_q}Yvh4[($ nrM8vnk"8=kz|HXB1Cr]Uzpxh0bY\~]9\}?9$קI2M7p3ÕPL+,B^ Nb&/R 1VbrkĘ>KqL_s]¼̵f^~#F:NQZ=|~'UO:&uȹhHl 5ԝRt'= +)PE-}Xְk僈Ӥ rM@IJhB7a *t. Gт8wRN;rɭYɾI5勋]i2 RlAQn=".(3EsĶR(CN E' Q[ΥgO))I]Pn6|G\p_ 9|G,x }&=u:^CP}&:+yVM4Gi ?6<|0(oU<<^^ɖ\u܈4=ٷ˶A[]~ȩ pQ5BecJ 妇I;>}o3;j4Y&V҈Y"Tϯ*h%&a'PKyKZHR/docs.hhcUT uYuYux ͚R0y kM;SZIOtz퍣D\INO_) R-jy/\>\c wcnfɤmb ?,J d)TOV(j4&g: 49+,NqsqSJn.6P\GJ-yZNЯ&&זB.6WٗE_,|cG6 j)ހa fص?R@ %K&yFn&V˥/z[TIf?(?G2)z'{;ڨ`XxZ^+rKe6 Ѻ[BuJ#5${BPly8O@m`3v,6?HUvŐmF$J&vPI|ES$M v8 -ABZ1)Ce T?Oh\>.|Utvp3Ң2IFHW|{ȶtgFkWLkFǨn'U~—{ VOs\tv:5CFMhHykYZ n.|h7B>ߥ]({kDGS{e4;QA?g9+ A-u2[uRzEvqI;j.4D8?<)׈|Q%2d8 XKh( (lQvo;#V?"54!d$IÁK(a#2G<3&&wnk(8=-oLU'5vQHdA,T# dۤa#F:1&#ryH-#MxzG(a 78?.d~R0iECpB"xUCzAy:?Ӛy~VWTĺFʉzp]VĬ!gPKyKCKfdocs.hhkUT uYuYux )ͱRPQ `\PRYjTZQ_YXWRX T$sJϼ }s*3RR+2Jrs!Vq胜PKyKeQ_docs.hhpUT uYuYux s+I+)VHIMO.HKI@ ,r]SS\Ks:K2S\RKsJJ 2m3A2JrsPK yKebshell/UT uYvYux PKyK Mbuebshell/index.htmlUT uYuYux Xr}W ܪ %_Rve`4O>쇻T[jlnx2:ՉIzu OO0?̣.rq/WO˷ן/T<~r1_^FGuVu9_؟GjNW\J/?)P gu%ٌ*khyF1r:9~鱷Ib4gwgo#nm?V:_N>.8;_⣡B}ͨ,1|mQ3@KsZXNTnQ yY֘&&uDh6Ő*tFMNuN LϊMnĴN\NAdᒆq.?pA?ŞO.$\T78"N7"Yіģ6 V+\mt<6$2 ,Ji#ڳ_j*_bZ׭nx XpZh}pyYZ1!~Hu )8`\i>Էz-{ (c;q@$ os?YO(ό)/Bmyr+qA%vxUX?x:)۔^ #LS%PUB';p%HGgS!*)M NFE 8F3[~J;snSO]fȦYׅwn0y5bҧ+^P-1b T^vc[躘Nxxt2<>WeΚ@7P[T kI;VǓN)-OW`2ysF"Th]JKˎ3PR3%7{ C`TfK2cV8}KIQChbHOTΚ%_YI8I2~a7TlXP '4RsQKrVtXbdjHA$i…smg<ԺLɁe\#J`.VIue' SmJ ( C[8_R~n?FOrTID['e4; ś_k]^5R~yڴE_c=n"_O <`LAk#~r9aTl(_a68[]ޡ7< zE\Lo##a>^+sE18u@X^D[8rR;Ug3#2+N:3j f.¬͢[1< Oyօã2TݫӀc){Ι_pv4f!H8͈m 4jfݒ+]e B:Miw`g`zNMN}+d_ۤ>5-Uc ǚ(jV|D/c||D!euYDy|oΡ$ϘpGT/,;Rn9+F{.yɅ7oK7o)qa}={dDW(8{}1g^G5=v]?/72Y̎'to麅o S )SbPW#5 Q@"TּDPX˃N*۝zgk'N@;v1=}DJ$.+J4 B{!]e DۏXDem|p b[p(d| =;3k$afUqK'&Y|}^k4咩<5ixxM/PKyKaXJhebshell/clo.htmlUT uYuYux Wmo6_1X} ) $NeĘ" ݑRlvVh4E{){(ւu1?KN9]Rj̥37W3nr}3[on7i:}{B;ѪPiz oe5YW0M3J9gfc$i\V!gycNhG)Y^F;ÇCp4|8c[i&7gW+x\OnL]`f%8tȼЋ3V5NO`ZXY-l[N\۸BӴ'lw~/r~nN<Ѭ$ K+[@|\5ŐJ Vp"z=؅ 3D^Lዚ5,xHh*51_.`c̃+*pWN)q KQk `O c= $BX ,ֽ˜۰gA!^rgebSX O qlBcAJFiaKz.s%,- '_{l#AT͍,y71^xPpZx:pp[Iw-: ÔTn+dKcKGnv,0- 7 "dJ{𽖄p&WR2?KUS(LKK  li-5^aTH\p `/軋pV['vҋ\|PKyK]#Gebshell/commands.htmlUT uYuYux Xmo6 _y9iV.W,/[[Ke+/|f|:ȕ$~$[I HDI#"yT-dyCR&LBQ˽ϟ;_-7'\ח߱ߎ߽9a^}<r;P\8I '2H,˜QhN7\-쭡?-nךc *)Xة[T\^,{B %f 4ᨭ!_~dϸYo'}S0鄧t~w"rДHXz @\, {s™ZhoFwY;h"592k:t_5;#ʎ)h%Q3gMRӑN4!;dh- .0W{זkH% !D^Aj#+9|at)isaCs;^? N9;t"kn^b0vF˼P'DNh߉7KAI{UуdMk%̥tE\}GnX~"Le*^4+j 0/":yX%kmQ;\IGOD=Sp.hb2׾]D~Wra??l@F1yŖ 31{`Dv/jߓvtMh<̿aU ݛvTd>h;X{fj%Fq 7fWu\ 6zSo{Qh `w/5%}W Xg^A'#ſ”D3xǀNtgci) ߋ5ײ.5$xEv]n*yAl#2S$7S7M( bbiZ ( \N'zM1w!l:%!aj mڪk'< k3uݗ"fل-HiVoE;nwh`\WчS/1c`|=~ПZ8i[i`d]k/tO#{/׌ϟyn9=wX:?uH>p`._~g,ĘAD3[WYRzy t6z?=PQ:Zd(ėȇR64dغ \_,ϻa6}&dv6Z9A%#% ;]VS/J˺^f'ϲTV4"7(jTD5V$S|d<ѣ4 O*"k՝ܼ^oBxPu|^ZG~K&|_%.H-#ULihۼ(Xrκ@n{Q {p*Sx+љ5lwrU[6/Ŋ1@CoLFūrOԎ5%G3ۛ*M<)=_F9L纎);HFab]͵=V"E7sQؐxhHf@X<`^R_?a=s )LEp3牲r.|glv #<^sm56pGc (HE "۰?P847Mt~α<sX9NW//𽈏M0A‚b }H2b]3$|(z|0m)Rj4 ˩f2ڐ7GZ~Uί>eT:Fų9"yO/WuA+OS=eopt[qJ}b뫓9[NaE|I2^1m|桘((Io)ӁȽ<_IXLn8N[*̠{XX8[Q95MW -}%` ,8S 3ͲkԯZAdkBqQy@MK&_9.jUGyf˖t.z.܍n]\WZΰ&;1>?[{1[|=q-AVCƸIdi Y|7eO愥mL[uUZ>-qL%z+IQbĪ^#`Uc Oű4\){m!/\j1xX9: ]7Om޵4ҙ ̨_W>O X颞RS$."V]TgPIT \V?c3r~j7g1]b+)|my"]lcfu1~\8e#Gt wV ]M *kOWL !>!_E G 3qJu[rǥ#&̖ U Oe*{NW" q@dG9|f ]v 8橐NКܞ?ɎQ-.5:L]?3DxLYo OMVyIN,\$?XlFw[I N5d/ϋ}agGh 5G+\ȼg4T(-*?|W| ~@*mϋ"$X* ~iƦqʧg-G{{L_&] v>RR>4}Q}:T} FϔrH+psi1"dIK ~-@u&Y:!WF0 -;ےӇ?2YYoB Ѹ̻7qPkOV11_ B/,PKڠ4UsOQHCcb60}ˎJlJ6GjQWOu-jv|jn%{ECv*ã(v8[qnjywY&vNV0/rdn٦_2҃+wpu$5)' zE/;&~=<37>s3j»Ĕմ:$ g&6ى$b7K<Եl+)TݴbLngBK[ +aXg#dsҺy&DQ (:0H2?V%o;`dHqشs:͓%0]فM,۲݀7)ouXSܸdPOA z/Wh"FLWYYhL[[F>ߤ=-)kn=܋>4 0 <G&!4, im= s!x%z5|9k$=#JVVrosd op+A>Nt#e(_V[EDD*J:'4Z0_ 6/Ź '7~))dWȧ߱d]=h,>'4TF,>FvGrLuXBsWn:%jFڢ9]bզqqgOQzvH%[d>+9r2udܾf-,߬t]5o E-_ 5Y~uz̙<^gXL4nC,ar&,\4GP 99'wv)CgG :| ~Eꒊ'M<5.s͒t{w5UφZHtTTfׯ U懚wЬ3OOgTsݜ ^xz=M#.§+=+QB; kDDݜp۶j@ae2  | Dk̝q̢"<ru?4۽a%51u75`b0*q+e-PDV)0we>砋?1k$9Wܺe=IyXv:U]<ka3. yy@KfTLl@!賧 5 Vx/>}PohS'd]3>5GTh zkEW&5]6 J t$ OZ]qD%u}Y;X2ɓy lFI`f$QE]oXSJ>M Ή:-w}:͞`;;Oc#Zz:>gK[vWOmZ2E7G` $g, ?]*}ΤhuƟ䀗^r_LtXn=zK дʱg K:/|{3aBi52XwkeU?=A=6YR(WI!ښwxb >\Ddd))]lyx5e!OO~$ :WG_KEtJ#LKE*W`tz$τ[Yמ;_NrW~׫7s5 <# Kf?s;Fl1'*g7*"|LT}km@Mvbr8 P/͟} mk?Hre{ҏלOX?IwwJLbh6tg2?@T"i7()`([0gF'.w} N[SSS8_'Vͻ̻ܼ q%|34+Bd> +ebÍۣ|Qg(# ^C~?14\}Ϭ҉#zކS?,3]_%%'Tux3"`IGBBbzdћOj^w[Ys_jCHV~] Ŵ1R. 61RĊnL'Wh(>=YK7Dnӆ%T.~?J&t{rF-T2D%a̯"E|i|pЖmDtf8> XjY>߿Q!{y=1-K:D{u"9501sd HތkSO2YOT~>UgF){ ֨;P*~L=ek #oo֬C# 4aJHck\87xwاH ۍ!O޽ 2Z5=_EC,'&zM_/nh7:[$lőh:_bffږ5ao*9> 7U4XƔYF̸<<_l`I4+|v}%zG46'n109lzR 5||ߩ>Y2ס B5ӽ yvIRGS̚V-R~k4& a22tn$/kԷ!{pM+WRh#ˆ E7mfvܝ7?࿧{t]@S.hi͖;VrS3%nUw)'ewEϚ^b[dl'{(h/qXCCnRpXdOoǟ~=B]˫MDQגb0r=QBBjA.B9!- D^μ INoE{*vB5o򤵸ez$\]ֻ#O8W6.VQ:ՙup -.ט1H?|"%I&6U?<€uyAʆs/Y[& ԪgyU1}*Q3]aqqrI_T-E7I].K1rl;m&80жIX:Xzтw#凇ORQX\Tw7ѰH `65OqV\QV[vb&SZpii3pX-k3lcEK3Qa.ȴ a9`\@?9gt\D(x%5|۳}"482Ag4iҌ#Q ç~!)J"4eՑZYI qm² Vroo>lJ(1>$Veav{'b(9ǽrA|R θrl6}DNecb᤿[E y/3i>73{?}ɇ_nk~h}2KulG'mckÌ]ӍS3߿o+L>O)U4}"`Z~ԄԮbZK-jk ýkޔU%}h$9!ckVXWP*qw/+U+Iu?5Mc^YғƁ'X wϊjV]XLBY:9dhə(nNՏ1cj}s t̸G''-eH1&Pu3AM' rZfӊ7hnnnaIFVU :_nIB,kgH3uYf}v$.Aę Ud@R9 Um]P>!3\' yp5]7*u('(>I Z Ck߮p2 r敢sy/ ro,-3+; #xɓ!{;띁"7qї 9E+`̎<5TOZ Soepga[H@l_f3†{_ez,;${&5>9>/ϲy @-{ժ;*/I<W1d7e{{rE֛U)dp$P&h[sPϭܜX_mܝM8~4"'@_xt ,&WFrڠ?(d2-/J\$tqn$ݗnuͿ=tZVHHOrߟY{yGśșJpb Z|`R;N-OZkݑ 5 ]ѐay%^tWf6iV5hܬ 3]rA<*F bt8p܌LQ;@I?""!#׾&9mS\n [wE\ Rw(jV?4XgVL1)rfT6m5(:f/䫅{aEEŴ K+h$Կ/=~'$",ݢR3#Oz%KS>ͺsUv66ASժ tw -zd:^WΣ#8p8f?QEE{ϟ?rI3U>09VQQ*aav2Kh`*Y`5pawnGvvӄMBcr*Y3L 'g]ʙ 4-@[#RL/ l 2or: ~{ 7t,4ps{QQAbU͙g1{C}8SZِL;&mE޾J&7{w{( vՏ, T&DtLLYD yDd.aI,Z;>-)˅gg:݈ՏuNa3r7@b F *j-1A屢 CP{22t|`>p "׀ӂQYxX>}pQRϟ+*p޼IO@,w:a3cř8\K5>n󀽗~D!dA²ٝd2ݻw8S7N s5DB+y߾krE} u,iᠰ0<..E$0wnvʄq;>v f~rJ$oQ n8>б߿]lFv<:2"0&0vdN&y<~?bBij$W\Acp7AɶZcUU |:::*-5~ AP_nM %ѽpכS+2Åjyvs𝵍_` y, b KK˫\@nlL$RiPx^9P" -{wS/V77^Z2^$yGZ|J $*/&4@oH?GF~ +u1qA~\ K |d"6W@2SPPd @۷W$$$ !9pjVꄐrfu̹-bςv7 Aw;|P< зu2 ;_V9+~RVVo{iB@7jb׬`46=tr>Y.֟JV-?dadԌ|R+maõ ;_ު.Gm*H)+wHQhpTx/俛[LiSXlRXm4Y|aN}AuX+IᒝL~(;| fx|)Q,F&&/rǒI~'@I*oҌ ^ \8ˣO_MIx.Zع?^Q[qaj䷣zEÙ|1vFV! dX{(RkVOHCEA5M2f?{*gh4I@޺%8V/G*7J~64 [঒s%<@Umx`nAGq&[[e}1oC} n}3A=k..-D@`7aȫM\z f:q,|wa>rlgr>7UK>LqI[3M-cb}m\|hRR pGFDχyޜâ} L ؜I'h7;@OhA> &׌ɫ%M`>:ٽqÍ"dĞ(q{wwz嬪1ulswNGIґwawZ_nmףһ_$;̿c}hPP ccwswpB9ǍDfL.P;gfէâo&5Yh$[/fj"H~fzXK|xx @.hn mle%mOf \#-# 0E[+ 8Z.uWEDV"N/{97=#YXǔlYȳ`iLyIii};1۪{% eoE@浂 q9hR oG@| |OA[i܇k󹚜>s~@>} ϕ~Ǧn6FJr̢) f%9t3za rXg76_œ6d9995$G^,^\-ܟDެ u Ȧ8r,.]åf~ӻ< 6olwd8kfL($dI*|3gMy n[X}5|=IY5^mۃPS: "H-b]{v9 *X Ι.Kl"ur@3&^ͦ_O_<..{p#E{0NеTt1=eKX, kkĎhl\m;9lWhh3^l{O>4yi~E]NήCAl \aM6[I=bh6/'tv %"\_#|1Ci>J 0B_OouTxq#(z5<ɼj 66e̭v n]}V~t]Y.Zn_6HINJozEAahhvV?2?cé0ˡ0P1 p%WoZcdS.Tuh ȕxY}w>3).(Fc qY/$&9,ֶtZ^AK,'66qLAc L<ݖQ  ɸmN(D~}g\{į.hxUVOTt97l2c Gpԩ_թ`O)%CL;\0+2lȬ^*5w?FZBu`Cli[69'OW\un/K'_VC\M݀|鑖~hdV_j<)ޅ#Q{pxSHNlZr(p":gڢW9ݬtt4Ӳ"'ŽNjgmwAq7틼ͬ\Eahf>vcF۷r3Pl}>! >H*,co90Ɂ\v 2mՏ>|cحރaӗ̗pw`e1=`+EE@$~>ɢe}p{x7xs|yM _JJJY jjpNƬ}SlX<:MUZƿ2x7=60&xkVlMI"T*{,ѣG$˃jVڃ J P%j[,rp+W|*:g N$Ιqr}".e9 !:>(ͦ#`օHN2<_:<2""!?-6٧޹S5NQ5w|P^>Hb*c2;le_~?1d rϞ-B5_su}.v NIp-Hq%yc$^S˹UN8hK;e ki11_zZޕ}\%jɫh TO_Ѓ˺PavV@9VEx,*.Kc*~vtt"hٳ s֬ DUTtھ,]BPС$<>4', [JYZ?7..]N 6Ϝ^VUH;O3e6z}ęXtw%f0z3k< 9$tYK=dh*Vp?Ce QL>TESPU i_~ѸAüϟ:W{N> Aؿ=5SI:|X3Ҷ>C˒Rz@C5F0 ejU`h𤥤skzrX4\yc}fdfIrmۓMg=fDZZp[,JvSݕv x ,5hbG2c||^XIBFsd*gTGW/@) T9󳣟{2C Lk 4 60׎)S&Mr9]N]Nʆa$uᴣ}-Á7C@0W ǵ@">uL42 fgHH̦VP/+'medcEX8dzUHd#2&=ì"*+YD RiB :/:ͨ]doAM ,y-u'B:K ^ {KCU*BGolET4Fp9nXGRlzAHp! ` O8qM0xl ]𐑒J= p+r0wG], \x)j2ҩ^dX.=yD:xoOOly{yt{xDD+TNq5>dYtDzr+.m!?XF?‘ǵDBv=Cdʹ&/?~e;=yI,cųAf)+ #XG6Pbyk4vg%U ; ;;S"LED .!ЫXB'_,O7]ΈVo6.gt gU*3d$h0%8[xV2L5.dFN+3h5?~OLtJzb1T|JJz8Pl҃~ U7,VޱEKAp{51;xBU +;N*b:*|BVNȴtuGS/5!;tC -2ώu1跺*gkkkvQ6 }Ё1a$Շh;[@>oXxm H\גΚABĈ k\y"䟲-P갯%%*'=1o)#RޭpJfc14 PQ1 vedf:nf-|CWyu3vY[ĝcc С"|?jʹn=Q4FGQ.[<^\ooi|}Ղ.``) 5f*99Ytg4qW\rCVC_^=PImXާmX'xQ< Ćn[[[G/ )Cxɷ { 't'~xHKx%`K󡨶.TNT8 ÈAW[--{Ll/a^'t]| 7 ql..͖8%rv' hl4IL˛WDP(Ak[3$mÉ_X/ԩw]ƽ+f={(C8edd qwǓ>6gxE2*/9jL&P~2W0,Jtzgcpo"4M#M+W}?z3^4X2//oEZ]VVtrXR~ߖ ?Q8VHN```RV 01:!ē \I$]>i!o(/6ᑐ[::/B=9iBA˗G+lm⹣N''X4 9:r$riȁ+XPtk'ߐ۫V4vvvƣvd2yyLd,֡б<0_̷ )Zy X3__V__BK|vsxs/s |g8`SC9 yCs/0.#?q)yzڐkدF?8;ŋWOX~կܟVb#cȋhc*f)@C?[2xW_~@߳J̙|f{ /?!1oY+`fM42X$lnJd_60"i`^/XtOC |oNVfft18!cYY;s*wX6&槗46>(rrp,X-Э_\ҍIHH0lm-w#NL*hVS3KHLZFꀢ\c7 q_2̏7fVh1_'bٳg 8U@JY5 $ȴPu86=LC SOf AF#jөx6I/ODOB~j6d-u.4;w{~}<MR3{>HU~Ce܁&)t0Nw=";!K Hl`|?ĆɡUd2ө0؂1 <zwܬə 2 5YQ}Јc5뉦C|Д!!+Mxz{/ooge%r9.`Tb0@8vc09]DD+*JJ,4V$[ZllZڼv4v|XgI$jP^(-)fϟo^Ź)* $?KKuQ?/̀ 277'j66WxHb|8(|+^R uQ괏 aLWW9CX䤢|Fa%}9o^ml .h]Ah]kݭ2ÆTDDt Y_ߠp jHGAC--  xDR)@m䖗/{DZ{z%ee)#(Lˉ8"WRİY kMAM:a";GFuDDFB]2bbEqu3Yf3u& 6O%Փhz>bѪ~QU .̛qdJLდ .'/^30]lB0v޺ygȄˌZkmƢ12bMxm~~dXT)]i}Շ  9%) GwB C|j=a$̦E?[_ ooo7&%!Iay7*:QË Cu͠we8fhr$nIXXX\n@#eH80 M)>Ur)aLWWe@|9+٭D9s`d!!N} 8T. g%K1uFѨx`[ڝ* a2N =w+&1\|MA[+.4=U͑spJ#yOL ՘/ӊ-r9쯂˼ ~5Qh{\3'LVVVʹga0:Y# [{|#OxIᝄ"r Ř a_>4AFI2v";lA+\POQ ʼ_.VMYl' ZICsٖ&u`cRbft< b))1t:YDfl:C|YKq!/ {AnGFD|͡~I"DmH}CǛ?'zPYNڅ(ӬⰥ`k1gbl<|dS݀ N}෦3ɱM3ƻ8}''@U/,,#_0!!LJ000 p  мV  灿gSX|(PQl;;TS3!3-lt6g҆ -mm?aihh]oN'g͙.o6qvKsƪhO,T &F+LaTZ@}%Wm)(hRR &òʪ}Z8WNOm/fQ>zz f;yz0M%/dw,IiD+Pzz$ -f[Ͻ^|Rq c?e9-7)ߴ+iZl0v{oW`` !or)~F}Y#ؿ*QCL_/>X[+D:a0eo::9x&)p؆Z`weOJJSzǶPd6 ܙS`xj:< 䒢H_ ֹO6R0 Y^]:hv1Izʦ6Kf))-}~ GDXXޅ݆l%R{[` p k`5p`;S5 aֿW9 ^{. YceiKa,eӚ\tB0,3t]W>|pu^m{`P*`u>Ob7]?wdS$ne<5/l@">%H^3Np_ab 3tߟ -s'_fZvNo`h\-=Sl|SSWkG$vh?47~u _TVf.LtR6jGKKFs(3;PLt_ՉT bM`%Yl4B-f陙;~AAV y\ECW]YP%E:(gyYOD;,LXD]"\1wUV׷.ZoZS 'e Uz˩wYۏ jh-;'K :s?W9rjqiA̘ZtOV lqWz\yT I2R/d2s_BRvuv:泃EtR93D/4Ձit yu}XwԘEBBB,U\{7Zíj:3-X MK cR+jCܟlmo6+O̳Q=Ec2rXXq92&5tdj< g{ߏڰ\ 7n3KJ6s$me%X9?5CݮI2J@Ъ#*-\\o9,j`nΪmqsW>omVJhkfZn$&r*PXX"ӄCƿplBh)nP5 Hֱ0Kaa7{~ ARl_ucaw)*EW䖕*!)&83>7":Dߖ`kk 4%Z.JQ1F)65N/_6wtl]G0Ҷ'\b ?y38U<&J 6c THQ$Y==z.+}(iCH>3OKJ t{&D+jKxJ,Rq-6^mVfƀRgil~gp'^O%{u~϶7DDtb- :.VOr 'J6I]%z=SA<ʕ42#]sW-dXtx3 tOþ*+SA&BZ7_:Ąu7r_?OG`:YA55H\ˈy?s}?GQFDR#P-!cQ/hm}/p͞Ϡ3/̇*DlLLV:$hb -OnɢĿ$Pq]n=U,s&#=f9NN%cm*EGcjd޲ Gya8cE'K+`l \M:sꪬλ[2bM*Z[WcB&n.A4*H`w44|w.FvUGܲ;j~g{TfMN*B[JJJK]a$ F2W Fg4 +<6kjkdRoį%}&gFGp:Uj J$Sy'c%gX]5Ɔ͸mӈChF*+;. cjehki~Rre---MNMhyY0ǃzQnZ*ݻrwϗT=]1鴇 @OE;=r{,Tzxr:"nNrt[_y↕z:n*opll|>=ghBjd`vVdeMm̷!LCu^\1/"e]͞(2;EQA?_/*%)WO+[[~ii."nj }faMánfݥB@ ж΄@PN}jeoyg-6~0W닄Iޛ- W8kf vI0` ̒ɝ{.!CC%w` XsKx!:w@unYbʶYPu zjW߯d'Eq4䰯j7ݖ j:Q'<6K}&C,+`{3l\о2MEc5䑓w :4LL\❂|Mp*wtrRTY؄;;{<@7wZif:5mr&^l3=`|: K{ZtA,K\oe")ýebQ4Ucj<cIG{Q.0Vf񣼕哏9YchS)-"%g-@ ,ؿ(/9.+L h[yW0gxqPH+CKB\ )rtre@U'@3wnsl4$nMg uJ"*w[\+V/..8] t+^Ъg WvUE_[7nIG4܇0 Dy.0)AZ* |tq>; VvZúp?6Ve= ~ اxn7PMZݑT?n}Ғ(qj $a:*ع=xri{1݊HeF΄JL$5߮7r9⾘a),fm4 [?sqttlFQܝNAe-R9ZZ n넬Sְ,s{A)?ny:EEWltvv^pqQံEN,׍ٺJʯzwgxGJj՜Dܠ@B Gggk %S5kaAxc!3iO1*z9@NZ$cV\|^DAAcG8]^?%:㨂՟'O "%yrt-[}3?qv3=]BѷZeld,Saȍ]Pj3>Iqjtm;DIETaDB8ykj(zWe~P߾0$8URŻòvj0`jg@z##h'?Hꫦ< )~[>~4i_^?~FձpM Fө⥒ohe b[oJKQJz:}A]tyf錘,Q5 ʈOsδSqrG}I[Oeog]j-~ H Qa!zKI(rwN3x-hvNŻގ6h7s ͣv"k["F00m18))munVFCDiY2G'gmw\ <{"{,,9&&9K$1&)O+CCl וOmuw?qtם{Qp 8EaWo88*K}yM@@!ݽ9V^⭹Mobtcc.pΜՈ^z`ًs'@N˅JZ wǢFFF9~Ҙ*H+&F }UymD)D.*N* ' #""؄FUT~73SHfܹq#% V%- j_[+$gL4 jl۽h,f*̠=wNtU˩Q _Yp7Ohp /0( 7o`o޼駡_kKP Q2n2Ly J!~`>[A%z{0vji7KKKUK͍gtK3OC̍bO˗? 0_b  Jff3=5̸A8..lp3:0;B!f E@,&EѨ<+Y0ZhDHo =lmma|p{w露Zuw8/z#&n 7'#ovGJqXh,GKt*35^T>4يv~%3*Rz]Q;ſ92S|? ~;:n CD% 68˿+jawO8X,Ὶ}2x6Y@eJ&BBOO@uu U!h/9~ Bt9PYC 2U` wv> Htvug6fD^EODJJ S>za'zw 8c.`6T$Zf~dW~M'UY9r JD xo0i?Wϱ[.B4 BГAg y YT///ym9 ȒL慶%JtXR @K"AA*P4T c3-i fcn%Xt}MHs+{}Nhb;pWV<KCgsƌϧ TI(89LiN7t <vSk4$zN\tkF37IN ock|ɥNHL<:=e>"ݥ6R(7m6ڴ^e9^?u+}XԳĒS==!m\~pgoBJ}fU k")Sά7`? +>4{5:OVAlA.2Fa9 {+ Cd-gw  !DަS9ΝޞHj+F4RW./*|hUBx䷴N>_yzP;ZZJJ*+b׬pX{J;ӣR ;k" h B-z.yL NHU ߏ{81kTv T=0yIi Q]S8|1ǼqgC 攙z{y=K1a' TU0嶀rJLSc7h`P ĝ0`kw|fwqae|oL``bC%.20!(ݩgyiǃZf_.S  1(M,cA}*}" ;jmi)%Hzl 5?R(ODxxx}Zjԃm. iis?-n@ <Z78R#XWKrnBQ9:0o>5aYj~y= 0 ~toYY13)L#fQI= 'Arq[wY+ߣ,ʕxm>MȞwvۣ~\9M(MJEJyvv$tۙuQiTZ  SQ\AO_$%ӆ77BϾͰ*-vTx)R.Aӏqmyi(+IAǰYAiGǩ@'C a$PtEWmzeO\҄C0ՃϮ[ڞ`aE.\ǢN䅨 pXg  qv%>}❟|vws%n)_n/Pdl (6>sR2[ڑtԴuS %%9g4pb}bf*u@a?}{\"l :Պ4IUWw|7w'O6ϰ{Oq=%%RӒr.Taƍzeb" ykO(+o Q"^Wi}͐V?F*Bsmuħ͍w\5f56H* m!8Do#;uݎ<Ny~ew'ŝI8#Jݙ_3 *fΙ<{^#HHgl#K}|8-mE.tvα+j=45xbY_ab)IȘRmqKd3f~<ָᔾUH(sEOK&k Ȁ:CTpWGzguyH)### l@ۿ+TXͦ?VFlAVڃNf3{||߿k@zml CRRa :]ZJ "h2A~HCfllvT;?K;UTZVGeP̸[(xyyYxe2^t`uxgM+B^v`YgkZd%9=Qӑ:dXtF23Ey5k_VAx&:@2o9繺MZ *%:8-lx&Do9u'֫HH>*k=S6Y]%O(vv~ΆVNɝN7?!HXg.=d ^ VXp)Ⱦ5w 0 1{kʏ36SP_` ^1AÇ3&S,)Ȼ`WK77n- fnh2%k=:'p>d/&JyHz%.`ә1 !7y2pEPΉa6z'`?w{[4 | ʼn#I\]  rz6AoÇǑ_d"I@.ϟ~nͷ\f=#x=PȈ]A=ᒼFǕgOF{cĒy[|PCHӢwF߶$N{ x]9yV0H g’0 o=z j tozxZ8*Όgǽi(䔍jןkk*𬕦#FA)!Z]x*swr<%weyo $j<,7>:b4] .D##I ܝ/CR5Ͻ~8Q~`m-(~Dր4P;"0Wa" ȕقѺj?###Mp7)+ʙ4&ΣcYLN$@QQ7Gz$?QPn} a÷x\]wse6xrst/&s:ʞ!&j!_ Z>>>;û-tșJ{j_v}xJڲX1Ҍ|N=55uyyCjIi/Z_#_Hd)yP'3B Y `|ꓣ#/5qfЙ5qw[wbf =@7 ;d (Tf @GeH3>QaI nx16l?U<Lo۔sD3)]1aao nWz 7\jz!cAw q9OR,~쇧tԞ <%Y!4h4t@UV+OြjN؅Guu0 #Ms8\V)(>&VdN<;AR_m D5m՚9 |c{4G%\A,D`Rj}g1E}À-444C-5 fW H t@F~.KP&"Nknl}=5!!<9zUuutx>Nqq1TP^kXG,5f 5Z>u%w8BW_! 89YYY7|eF2>Ųl?mv]T泎T51(,κZ.Ҳ @WooO֋\-sJa/:j1Sd_I(29UssHtpd'&0>(O;Y[[CGYC;.6 9x<̀ai3޻`fMT=>#F~{Tb3.g8ʈѰ Ci¥3?S4ɼj},Əew)aJΏN?~"v:KRwI~ cE]WگX-wy x!4 `M x?[?`p rjϘl ;VMD| 1KVCEUK\S !]uhQ%wc#T_(_(z8goooIoGX}qϐdg,;8%yk 60XՕ㥎f̸ t_Y/:}97e3 @n7c/aT$)))UJnn8k7sx_sfpiA[/:m?x`wu\%xxBaglQ8?ivQl&>Ւ6vzqyO`6(ݓ3ݱ=D1#X+o7]I\+? g 8ko9q~W$l޽ɉ51` +ü]wBXo!͛WX 4?rU I'{lM`I<B2cѮ]ˇ/6:r_]+CQ&ÿ-Ȏ([&&ˬI:8YTD{hE!; ÂELѺTs-$N?+i@ RSS-M FʢpZk컷tHPͲމr\TI =B; $!9)>{,l2A۷.*m(mEUӇͶs`̰0L {{_q屖+tNl`J;ɝ==ˀ~ wfR(6Žʹۋ6\ܥ=sB f# 0iW@bz 3t V=z6;WXXXNe5S#z\/OZbNFf~(ՙ:Ǭ?(U}cwue5*|c< 3hw-QIx4/X)s$DŪ9>| GVv ˤ=C涜xaekeaH2 9PXdwN \kPgfnx9X3- NZ^N7d6)/!4s8_sdU'Q6^6n۷HC۷oϫ7`ѰL-&);O)آԺ(,@Uf  |_w܈,g%&PE8?Q}f,@S[W186SөqCAEEzJ.1.œ]Z= [hZ. w+Zxޤ'>yԗ&{%D@-k# `Go]t ox6(g`(q.̷7?o0@U~H4T9`?5V˿P>X5۲bNZ#A B<ξ IzԦ!.̋w9/nQVGJ_Iή[`Yяqo|6w`؟.AߛQmFoJގvvO<}X_9x3Q4@_w`9Y4 @_ jx=lz>vq`!16<4PlR-@~5\_EokN39tpe8ظ759;M{ {:>X`'Z;U-YA}+++8?i9%OTx9Mae 0q@": ߿5Կ `W3| vMz9`geee}5{a7`˦h5q~#0 + ]_uKMa_8lM<400rV 9;;)ls֬g ݹ{&tڃ[[>uOEo!~{^h5x:*W'݉<XBCQ=JV)9)d|SOrbU torbr̽P4#6Ӣ=⸴  /Bbo!pEe4)P)EqX_--]斑oyء L!&X,áCҲ@K='Nª@?-(]kvb63`;K l,6`c9ZFF#q)3T` q%f^IIzTT_tiF02 [b25Еr|d>Ӱ`Br˩,ؓ`@h 756&~ .| A _Ea?'; ;cؽ쪇!Qqqm[НXНȭ /KA;B 8<%, U\0=X-`w}? ct~| C̿t-V[͂a5dv"g*/ V G ǫ9:SwQe6/|>iz]n$) lpfOΥ7C w{ fCT/27fx"m9T e%= H.lANA#9:cYL}+kj 8RѨ!0覿ُևK>I=X5]s` ccj(H,Kk;5 :amR;`m]]F?޿l"KÍ ˙z9kWG:ʬ#nY`~/y?\Y $TꣻUȒ& 4͓/zo/̮f+S q[T%TAX2-.(mΔ Cѣ \bD|<ݒ 0q07~ҭ/G LjfF'?`ia @^Mw}|~Sw"K!,y)$,*7թn=5Fs?-jgM"! Wk+of%>7܉Xdsh4f3+Jq*~%3 `ffR |=/3Ȋr- qvqZ2(ذu(}ǒ*x,c[[HZl^Ll <@frY]Գd*M϶36M3۔ &LFWN}7}0)x}ad # ``fjb;9nLOM霿8#ܩsA<7Ƀк4?iئ⼖jcpmWyL< .Q1?VbGQZ㜜I+Ao쀯:չLtil #SB\]ݻwQe_Krg/@/,-,eӟډt|\!ExD(]JU 8.ԩ'Y=V 48`]}%%%Xj'oX@^S/p}JG4>: !$nBNDoKkjdbXD>= %>N Y3s ~F:t~#i'9(L%wkXbqܪ\C9T:w4*i{R"Tӄ)4긮L#z?_}$_M4U-mZKTG;@((Z=QMSSaay)Z u^G%m %=UXCa*s&7'bf遠:+XHhƸx*fJ1efگl9tWB.!zЉya:LLeڕ?z\N*"(~TnQM Jt<ɾV. K]7GFBG&{$G< oȌs.oENNH_ĄCb$=Ŋ|Ci2*sc9[n@!6t V# t;5Moo:Zdduj/^_HK>}5Q_րyixY՘bLvag~~wCgug'J|;E+Xkc%4_= ;m,ƾEE}o8Ԩ+*&rY.!ɼp4V9S >~9;)mKyQ`D:c%ȱo^veyEGؗLSg[uO2>Md$ZZL 9Nr-8T~V佞TAw+jگb;ǷjР6J ,%u'%%E{JTTTcg/WygaVյH&pEԈq;fZXz%GĀ/T_RkN:^GGǷˣ (\"xǁox4 W@>v>*=zCC/;VKMkylYdbCVﱥnNOX[T,J;99yp哖?~LA T4pqkM~+`jIK˶zNɌVLWϒ,N?SkivSlNthF55êJ3j6EƆM3mf~yZ(%iov--mXt78!|ƶ_q#TQU{$X޳W:gPÃxTmL"ٔPϭsdhrLqPP|GSN5!s$co hi(_qE`t{gg͂#\KxRT-Wd74u dK\'Y Cˉ%9-5M[rjT%)|BzƗ/)$Ck i|}%&vjRK%K-qR7pK#y*ԭq@1~,-@GGH`kTZT'&&&6_[^(yKF+gr=)bB祵5Z}q~ybpa֘&[_{:7h6VF+h>@BkA^rƈLDK Q/4jFoxl)2dba񰇽3l33TPZ_ C5F¨S5^fƴ׵L(e\\8D,-2P4W.ira9fQ]2W MtJ{DBnhf0=Ӑ 䩱K$TXzR$".f>z@.}FFJM)kjJIXE8nEtț/u /3pa;qOGw\]&wmd<+MUoyq1mp-oy[MU?V2n`E;^2op< < &тR+ҏ,..z+@u>P}I@I `4- { >@%n֠{_S×bV̜@U7 #Gڬt4+T<~Fyt@6њ:ȏq*Wů 7G 6KzwW}mXEE_J?a%Z;q;7M`K| (|;7`G$ >އ-]; M>YUm]:nke 0`vձK :l]Ew(fT_gQGƷ].͑y9~k7RVr1Ge\/*`ŐJW?[Eo;dQSLF^nձ㗀1dy,lsۛ"vLyiu= PV3)`!'F/n݈7f%2+?/z+%9QS?{4;6Ce&wZفGo8cDaKGj7x&fAV[_pT 4 S~uU;u=] q(vFj)tvaR)9 ʭ--] s!H"GadZtwt,o$F`lLfS+T A!s kؠn, ğX$/J"@1f5It_>55{F02g9 a'~ `Bǟؿ#kqYŶjZd BCM`n9>6L. `]JJjn)V/fmӢ!ܷk]@Uʜ\;Yyig{-V8u~78cj4y6Ccoo,8 tr@:wY$Y[[BHFvp9y[W}mWцr[JzP>%V[{z~/I>7 tJƍ6 0 ß%ld)NkӧOp tb[~ftVO +$2x|):9 [JEK`R!K~ w_o18z:1i痛tU;lI F2TÌQ͟cgS;*cǥ7\+'P 4 0t S7iaKP: 0'^ָDg\0HgLpnhYa@׶1^!F F0]|[GlSSBv0 tb9־MLR-\g$DDX:?ӗlYF0{y\\g *$5 K@$izo`1ijw90VS/R=u_)FBȈEn=[*hJEE7XiepeҤ5, `5fU]R;JVehūXY.;J[3+/eo}\*cabW0!|v]s`7CP1b>hgVe^eI79Ae0@)QSůE:JJ e+l 5[ox8u\66 gttۡJ[8ʱ.w15tbt.ݟ$aC D3I{{[ w޿q=ISLbR/ 'r^CDPޔ 呜)ony@↟=lsm9"+;e%+Žk(yƍ;Mh(ɭcМ G &޹ZxFTšۇ( (׻-L=p |6ނFk^ +7Ӑ8էe 510m⡸& C'H7n?*1bR?8(b߼u ì6@ayRKKK`Refxܿ(BN@Sk \ m6 Doe@˛c}o Qg3AiScGLܺu ^;"ܵ,,U! x> 9|eVTR[0i'ENfm-Qjj^#= K,z X'0EkMp@{a3 w \' ~\i_?3Oȃ%{5cϺeO#Zƪdͧ#Fu$.Z/[OԵ=~So#۸NhP{Fuޣ+^XkOӧQbn'$.AubHOWWb'K Ny}h&l_Ry2MeLy ̐pn^D1_ qwMo!"` 5tH%6( ؊b~g}qzɐ K'ζ.X~GJH`odRK6qmĽ|P/3{TXWA[KsZ=\Dҵ.< #C`k5 Y)%z>.nie21!ZnY>ܓ_NVz=L/neXN 5y`: )ݛ8n8dIK&=Ao4\go|ZM})K t|xuEіiO&&Bᴭve{XY<*ּ/Ɯ7jᨲ1R,zUU;tE6nvGx6669ѰD%3QQWޟ:6.eYW\4 zcb`7i Xv mJ<`n$)ǹքضuű<cb" fm]Xߝ;w6`!Pwk#!,ψ2/Cr卬 ]\rN$M\8? d0W6,Tc7E{SNx*BKLL.0Js/\v] i3C4C/W\a,@EVW',:\]tF)PGZ?{Ly*=w<|ЮoGVcoDUڡ$I[|sUǜmlZU;*^bbat\kLr_Y/8(u[` ,஖7M!j@&;'M>鯕 lۄ9qHI6Pby ~Iq y5+`}-rҌdy&",:֏랞d>$ZFƛZQlI菟>rN-IG~V~ԑFڅdVu&230LJC`Ӎ?}#.,/lJ,h T\ڴ7괭N룔K)(cf% &?I#ܗ/k\q_,t<nrzw.6^2__5^wnz=.wXדVk3~/&d~qܽ k v'Sb##6663PDn?I|Nu~.g^G yĠ ꌦRZ>%/Gr\VAޘԋ=5Nt߾}ԑNG'xEcOj~j! c(Ob,=C}4q+ofKL0 -jTͫ[W]帇#[;w#z$||]wXwp^Q]:@}c6,Dd'M#l>B 9K.;BS wã}!]Si=atL..Y\A;wS3"ZD#UN_[48>>롞볗/UO2c{.h`acS] l~.+ u>YY7c0N|#;z^aI]_5ߙi-ЩiBb5T U^^>IC3;RaUܡittw-}bcq˼jzqRa~caajOb"oywUWd}IuERR&1q0؝>b F>Rp`w UOz>{,l+mg )&iDDD"O_K(iad(A☒kza;`h aڻu ؿRؗ -[B=?C0,-!!&X~T%L)TlM بΰyD|Q=*Y194STT֋OH(JT&vq7Y ݜOIx[ȥ[Xb;WXI5ǔ7q2^f%FVv6&&&Q1?}I-eʮiG%63`8 :̧dz#cڧ-kpqgҺ=USl>QNo%ַ=ںpPTRrVׯw}Ar\λx4y_~az;SO Ha2D*؆πi \=]UDU_40q|$D+;h$+3ņ(y7c<?\seai(6_  XXmL?h#av0 "F+PB0`h]2mn-; j ƈX2Hk C~V3$d*=AAhۓkMt~Z)`=ztz8(?rz Ű+8YD0a`*_Sz;Q.&mI۩“\h E!־tQiD &o^4ˬLJ!`!_L8v0e^u GB&o7AI/-- $|v91DQY8ɡZNvl5Wb^VaC\a-K&QWwD`&ȒvZǒ!X(Ci5;?td0yyx4ecy\_\Wev09ZJsRPWksrvXU޻8 fV˹,Ç HD{ot5 vwa?;j/;?&VN׈#2gG)=~tt0Uvc>|t,xtd0GxBɶ,*r^?p#a5Sxv3d"w0 )JvXÕd@P|]Y;%DG(Nb<@6WZ >y):g 8RJ'O0vk`aa6Yu-HOOB;9f>2Xhh\hHv/ݻ:y)X`қ"=3QaZ[/ALⲲhkDb;}ssaѨ8L)=!q" %-7Τ$"DGɫ#/^xIO!ldd4 ܏tQgr\&ິ>u'3E^,ZX2`\WԷIQ%p~e\r6Pnsm}$ˏ^-]RG?F݂aH˟Px[㏀%EH@!T}-ZhV 6v!XYYI+7f[aEB1dee嬜C(zyÇ[ um9޽"蓾bY:>F&&,\\`Vk讇GEx`C$*ٗ/_ށ/?4ǹ쒡g)|pxg|i& mwihhLLffX20=[J2))) QAZ,o%JޅoDb&%=~oXpU|jLKy9|MVy~)+p+d1n 9ŵK&ff_# і8־8I"3M`1@斖|=_gLp<.oqpC;lGWٲDu}@5'F~RrsLc ( ?hdĉ _[[0kw;F+1~*=3֪5y?x(1eJnN&% MI.Ѻ/BE݉c T,l5Iȋ$t'9+P' װ+sqMj8_?2u&S"Xq,Ox F2HO<` LǪ*OG7Җppp`\w/o\ϡ#&>[O6(TהV0Hl9Q r˽FXw}a J!;dF;evQk\G*`:'ǰqO3?306\]S3*ٝ;wRE4}( uŁ>`P ]]yۻ(Y#$`?l .Ti~KiOj6OhTӔiuؒ! Fb]KK+&`a޺~^nL!r7CuY]9(f Ց`j` 1Eq7J#`4 b hUE uSZBCS?i|&\9cA{W"7՗T2,R+*}qp=Ӕ#$rFFF9U+tyP=S^#{h{*F6]0!79=ݳ3 ~ BQ#y}"цr,PO=/>"$ghh(&!1{PɴOzr~cJ`ccc?&'GP8u9֝ K¬ X6v1>^(*"qssR!uQ3a5dw$DI4J|fZQ?DFR>g)pݭ#d1A#@2|j >ヮS}D_vg$r{w߿WVU^|)LM/%?_\J۷o]hvEhsPО3{Y |o<***k{_` EZ~=xT:( 쒟.{uuu-jʥ-A spڐ ~m{tJY'X3 >[e?3cD<==W5d(NJZk!nlhSarλ{Sϳh7:J Dw`X Y###; -ֵ>DpwR `0NycZ&c[ &ܫsķj'D›FwT M5I`έn0&9p7Ds~@ SH&[$],`(k$:S`IaNz=7oF}&qqLTLL{|ݣ#q7Rxel[q%)``{yYeEIgӯ a^FO$ R xc}}$pS*u,$ݽ}gO$7* tT=1؈L!=.!!@U.ș75]9Z`=έn[7,sܷnU~F%˄_l9ԓgu(67 mb>k /&<ah"YXyIK_9a6DZ{>ׯFOZ ''',"n@UE ^꙽=c~($Z枅s^@`~5;vqf%zn\gag-fXrrp݊@-̻>M 戡XXXλHdLL*딹|9RI$Oc۪1hxT鸕9Sƭ[Htp\lV6 Uu|ņ`KF.6\5  xWCDuCrNcFxY0LXhlh Un5)XGՉŽ ɝZqoqJϤƪ=~j}s٫N^o\ "L۱`f0*,Dq137(5yu>v{̖S[*Ϯ)MLZ?zzб ~39x5Z._ Z;`BIGg􈁏Xpx2: V}ccq<|K3e1ˤ-EEE׵7pb{~>3Gn!Xn= *|jC֖i{$MLm ⵴E'9l/ #r)S>7ѕ[  ,>̔-.<;0[ ;Ņ0Ts\|uc>E޹_3dwpYt@OOOw]Ě\Hx7=er%D>w' [M ~1x SR|0όAbƱ1|<0iFGzԑ}4v(8XLH>ycs GX? M91qprZfd ؾռڪ1ҼYOqEU'n>Bk,ݓ3? `{<,S紓3-Fꦁ{ C$?pK~,JeަR@ࢆQzI)ߟɉì\IO&G;;:B%lmGB% lh #BMDPX{Ij?6lQ pV,&T2?}HڑBaQ |=ѲJ7MI4`A}&E`p 36,Wؽ9Q?M7>Ņ'QsF"I@1:Swp79" az-vtR_5*cT&=K_0Ϲ#["hj^xo필bZ9l\p4£\`WRzw;ݑ2kn!Ց)o8x<`$//dO`_W`CzjIm-%΀J֤؎-o!˴J 0ɞ)]yBb"t$4\N7{k1Q yZ8Cjjz`}`c`w]=}9pl>J9ڬ㲀)~!?FVM;?O75#9t, L  Gx8'՗^"?Ă??DDRgWW1iq17?H &7gRSH\\\`5+#˷~Q̌RXY.@}`xlo*b Iy78Z('#vlPv<[ } `RS$̅w ~޷FNQT~ ,#v|lYJlRzQ>.tƲ,/u"tfWV#hk{ϬN(4R'D*D󙨨J 9RߓQXENAQl }bjgqq=XTP `'<xujֈ\2Q';&?:e.[fU?ooYPmmmpɩ7Ɲ>tͷ=ѡˏ[A<;?ڠ? `'0x!/xY y2h_:/>mEs o8G:Xai!N%3Iìc`6%vfEoۍjG #ۭOw?FX{?[GoioZnp–`µ|?mm":Ȯ"87N ֹ9TNNNWjttPh& K̟ s2&/)ǻaB`ᩭWOqkKv~ KEo9^4,<>d~D&}G|}xh]\3T~,͋k7x#&'%xb;:fdd4+!`hw  S?`Rȷ1Tz뫏?H@hɏwES#Zs%d@@TvO‚ b%i$$A~MVP,+TZZTG[t={8G'ƣo_Ro8׾LI ޽AF&& |nnj3?#€tƨ]st.,0OLzX;ZW{A C3h7'1n'Lқݻ[o rna<=PU2_ ,ȻYR֎%;li-|ldxmAS_V)2#C렶~u`jzx6m7wo@WxMƱZxJ/ XFQg{kKHܾAM qVi~h@A~ƈYsrBc{;l?#j4 ۓnǛMlfCλilXJ tj2 uvVRR KN/{vkjbʂED2 ׾uX~|IQF7ò4 3Qo+! ?hIVׯhգ%Wj^ >7JƞgS%;)7(44* r)Li3tҬw\+u\%959+$ۚv8\ndn LaɝKanp2;:ףg p bQH@K# 1@=madU ękB F5qwu%FR=MkcdܿiX뫝Uk9CM(U*ÇcsA`+#f9/`o nX[iRݑЏQq 1ZCaP'""rա Ɓ̻²h)Rۋ>`iZNPH84xG*ڟ)@?$$dud3R;̡Fc$orkBA᚝ueҙG>,,(XCL-긩#t̄}wnvVxƐ5ivb݃O7ѡ3H`gɷ HBXWIQwc)))E)./Of`w`AʔL/__>F~?[R[0unǔ b1QWY{m0s.r?֝˺_ܭ{LOO(p(^kPR!jtVNN$XB#mmma`\{g'ŭ[`HS|II{%xN9 > yjyr%N;0^ HK~57 8 0Dfafbļc`Du5/Mi^PGGBAA!JDc>kjk ĵNsx-{)`_Z3;{0jXZ 2 XYYbrK000l7F ɣjm vY"lod;sgU̟BCi?K3Yb{qEٗwP6ʫ;qdzP|s 55l53rlE#KKKFzx|03 "10$~*#BakyxX\;G']QX{5l| 4\.,2W=eԬ ajnL S{I,bF>.?%%%q}NC(T$ꚘV6:1>,懫ŬґkkWzG ta$//ؕT ا9#Ns8Z_~adGފ_!x;.35 l| )'@X1X [hFB|~'CzKs~K> n'$%plihiQ`#x* P:ւAWLJS,h%,b\_j.}>j=A ՓK ^`k);' RW1ofc:$oṽ٥%q+seY11UU[6)N;Svo?2%C/^riY A" O,y5z_i:sl wFR'zl"}62X0a3BaɎ_uAkXōWʉegg6(8eb>Zj51Y(V2_aR{!n }wC}9#$xw^ )ܣ[[;}8a o[c?eeQS0Z1c $ `[ ח,'02qtwll /h1R[>>˗>}} 5"DkיA\IN`JT)++GgpL[$.>Ƥ;d 9[{ :;:pT< =أixxq_*a~B?GUV38vr;bm׹>Z*^I1#z/y(:-ԭu1tI?S"LIƑ lNTƄr,w7E3AvRǴK>/K/ Y"0j3JvVJxxj>72Zh2[\5Ϝzu$ {dn߇|$Ȩ kMؘvh5D:PXX$z&;L9 63.+.S#g{ªfGsp`(f4cPI58M9n S0PL[̶SMԮwLJ0ha0A`gĕs>]j6u,(wWVz+ʟr1Xy@ ˩UVg0O"wh(`6W.#}j==ߎe:Vo2n~HȑOms#Tedd"vuBq*)rqM+*J>ë4m63<9;p=y&*Ϥ+=Yxv֢˗0G Ț3ww~c{ !i@n맞ץێ>͝ڃ-ڀF0lix`5ͰsTIЈԑ0aDRG:65Y99O/񨫈\^ ` * l᝛q LO_fKXa _N*wHoS˔@[/Ǩ<, PWQ)] +1@*.;&PB1`\# PE);z"Py/Q\QI ܪX=(#)/z݄ww03^q^BB@_5|i[ 5I#8u3ULlgbwm6(0U& j~͓49Yo렀-@M@zySnJt=ztw8HHHhvmfJޣÑǫ[mBy?޽\ʈ/{'0,n$ac!M":+m(\7}G6URÍ{|ZHĂ"\2ONѰDslah_dr..*óyٱ/;cܿZ_ҿ#G"ɩ|VЯ#wYU2hܸ}%wiwQm{V 3AR`b]᱂6ۭUuRBEN6%b*7o-9П!4xFvN]ku W7N0kditR2}o í w^j ΞA0Z8qՋg.b9yy^-sU+'9PQf׷2IAn-_m9unV=B qwRܕ+ 3AFC:%3Ge_q~OsM/hk9z͜")^{Wn [Ae[ixij A뱚]گufvܹ#pH/FN鐞\.HBQ'(yN,oeKS|$@ G ,wVwlAݲ}" ]Rq SZTo\\(k# 42Hz~x1At2 +/rY /?fʛz7)3.dckvmOm9OMMiːMdwx{! !IC+1 3U"{S'wo_ZUO>~YWk%8;XY82..F/#;{Þq纂ZfLMMwmN7XuN"GyME"_IJ w:sXNJZܯ[Uz;_Ҟ=tI-V M }z"K&Sz辽dȞEH8'[F ):^J6&.q-heГdsͬ)=K};cp"q5HcQ_N r%Q{dF {=}k[d&;ju,]~X7e$C"'%<3PTHw]),kK|rVSp̥goiBSg`ٻ?{Lye 'Vk֥. m8p"OX1]xٟ3Gyڠc^r}w{qYGjegyGiY3"x,j^([yneM̛"Θbj(|~#ѵ{4$Cۏ_.7kݴ֬q߯vFfiHz3o`n:iC4RaşgwWQ7u6F vB`4ϮN&۪=&;t#ܓ;W}9lP+9T~b0ܲWuςJ<,M ʶҎXtc5ѩUKQj_oڜ#`/05 Fnj{S69,FΚvw\;}R[C׎:^sQMY =BMq՝W̌籲kcڧm͸ D]dQc'%C-dOly1GPέ_չLilH6΍ G5JM )=*]D]l*M`pYdgU[Y:]Q~:4!5:pw;A~p M)&C(Yuju~X2r&򒧉4 b{[gNy'览CMhajMd1tr(AW'0ؗ> 4[tTӏmHM>O$II"b"E/FL4վtʚ :z{T˲_kfU.rs/?"b=7OA{w"*mW(C9m[k9hFxmYp@'{2=BIwL71ng4pͦ))5/(WesPLN 4H}AIuUHVrKG6GVNnw&ϩj-gQo8:3>䉜#6M{?Ov)lnh~w]))[7 t]C_Sm4laV:d<շI:5 6e2϶5QY}~Z&dfV{~yE5],`p1'\gSK ׬_2x{``W  ^նJGP*^OCcJ*k=tuܻwn(XSSV4)~J,i,VZv=-).4i'u\?愯 "6Qg[^ub"Ŧk!E;;o\8\Ȓ3cwm( %Lt'btW $O[3$>"cO㹅δH&kܓrc{K.6OK31CC۳{K:it%/MtiS'e]ʯar R%|N`i:$}KldbRu ]ϰ.ͭW&ZV o`O߿3Q ^*^x-u'~aL52Z`h < 1"2ݻ\odi(j}((odLeZ˾k%5G߽C|%ᱍT$JVซ粃vK, ^*82x });PĬT OXDߞ.^lpP)gdŠ4==}_0G>fqh֩_vv w/͙i=/Ա+?{[ȗ?F )qߘJ*،59 k]aVR, p38iH\{u^j  V/xz ZBb(]=KH'p ~JbV$D. Ų\Ύۓ?QCVr ;?;UzEeb5 h}y6 ̓U1#UQqEiiC:vڎ /Eqz}$0'79eF\au( nw {cwy›cT~oiV#r$$$[먨(zcǏߝmXfa9j9 ~뛈fٰKeUTqo U{"iW: ,NIX?TVU:v9x{ߝä;(/K}O4IԺw]~rl&T,t.mc. XIKl QtLfCZa5?,F tuw)n[aYNNN::k3 BV7b-ɮnu4 .000LVRq"p=ZbǛt^Hƫ^ Dq+&-n\>|H=.%aĠm $xU/蹸)jLOgN9U=ddd k<0Y$-~ɲ?'?z -Xx_=k2E#]<s ,:6j &h/> vOjop+ `9XTSlᠼ֦4//׎F ^ݿ)d"jjқ^jͤ')\ M6]_d=='Wf[߈.`T?x{m0'&=~$X-$EGGW-DbvRTTTӨw}#aѕ ޾z +}8><2+sw@{ s `)؟` %)=n}>\|E [:8/bk 0:GРW7%=DJsHa!]3fmV$ֳf__G\tk8;gR$ZN* WX/]z^m;lzӃvY^\6,ώ%ggYdf | 5m.` -嵵vnKa[\\IP ݑS99F;}ņгYF]d` o}4(tb4ZĤ7"11R1B̷5,ϟ"W rtKgG͠-f l.&`+Sٿ`nP/j_};_FL=x7Lds9 GJw[6Y;^-‘XfDE=i'%517)eav hP`0ħP]@@ A Hik2jxo±д~ar|txPEIHP`]ڼ e6T@\,1 x:OVA!à!ŋ(]㓼L}*cK0(+uFj3?.L@9:ޯ9.>{c*ע#HjsE?%"^Fkavv\h7Y+Uz };sYe)MFگh`1[[ʭ~sΟ9Gq   r_BK-OW]_[][K`S^SQ5h#c~"Omhhظ;Rj[2(#}N #q5P삜 V8[*21av?pel.nCxh8""ѯErx?;s~d}. ]Yѩr{ e2Hd)a#ViiLcv|ǣ/sOY !A|1:8:Z=G,P%]fEBl֧zs㬫h1?.wY?3A6%x1~C,-ma;trW.a~{~s7G+YBH/6T(m{n7oFwY}_l)gc7KY_Ҿ6\hRXkQy1ͣbwrn,}3$%QHUi._zŪcg M'STs:;eL5wZQ֖B_j|_7:|G0c`?ol'M Âܛj7Q3ͧMh^,C5yZojrOR>=h@>A蜱10J.O"GxfC0i|LJ~gɖMxsj!Lp;];g2gb}|N2`]\PcccĂA}f"0Ө @y^QaBϭj쑏t2Ted\Ypp%CMʢwp ӻ/Ϯ~ql]XsFtͽD#Ri_+Sqk`8Ce[?y|N D0"6V*r6= T,L-4D@BBD:C)L1& HB9z?/״'y (߱zeO˕ uuY@[c;KӺ4Tr0~ySͮmLb{?\:JsбBý?SSdD@  O3M >[ t~U}[]]S+X~ă7]`#cvQ;J_5-(Nllr{y\ 6M@u*h Y]1Rʥ6'"E % Cꀀ#Z"Tbc s~A*̎d _\౱'|"ұ3NNQx?L~] 6`,kDQvpꒄUn"3Oot!#/F֩?N<[9Z9/kt;ޠ=>㵿ȏH <)RA*VQ}pI))4˨-޴W@9LJ4". NRR=^`!Ɣ}cbps(s;,RW뺻:DiQo9?렠>8)WB\TnI)1nÒP~B򲲡>Ny\Zmt[MҠh9?99a"D mL骩I:9\ZZ,iji~O`Td˴4 @_f7^{Gu%'c:Z5+k| n}/^ՙtF5!ppV=*v^nѽBLpW}]ɨ9JX"3U~^wgv{^ܩj't8v|/[QGw'Bwji >|b : ѱ e Ի>^6x'Z-Piks0uxʷt \|^A|mm,V 35 TI߽z)I S>-,B.ؘ@@JiNbW[;. Ci‡ONI Py( we"t[޶xV^އ7{snܲ.*Lh7]Αƾam֜.Nɻr @~]9P3R8q %D>$gߔLe!G ɽٛ5kSK[<!:4^"i!c:<2&(dEa`k/YЃ`8>NHQcGZk璗S?~x(ע1zg#$%pwbJLR{?D^Ev -?koJq+ ]&w7xQkb{ B| NlN?h $ڙSqed_oZ}`e۷[x<&vT*wdfaQy(Y?_uL ѼIPD!^E#&"#ٌ/NqqƛګQ}]~;?(*PIgX]xz@X=FA*s>n/)is=$9jjѫ\r34!֏{!vr XZ0yx0fY^Ke?}zf::ʖN#7AP3Ly ŽD ѱ)/wzrR 83}۳nUfjn!Yj*!s7Nu?Pf;kb |bf1^оIt)EP|/?gO Z;:ޓkxe7YGiLڎZF>%$ ңPz@z3DĨ @rʊKypgJz:5}%rvOʞ(jA&+&]͍K\hT FA<%h9L4~4Eᦾ G73+U<0>OkەjAj]2⅘+(AMϟK{L6yykdKZ껻s=9>b9UL7B?t_aP 9~+:dV}VA PpVh{@˦ܮ U87=,湶*ȑn%a[bز9.0]B9Uqʊ jvgu|ukK:C?eggPCzvymr CXbk4t=#y<=/O@{4)bF4̕ᖋ>?"'(G:nGqa޾UN͎Y*G?GWtx{0= R}ۯ+gy_h?FsKE1MU56>o/EMW T^5j¤#$0&*]\$9oKI;*_k*vA(AV!Tw5Yg]ɭ9z[s|z/ bˁr F˗/azv~0 }LPRd':ÆN0ED硃XQND[ aaŏOrr(**".|ƎxWtXBq3gZ53 3EW.&\Zcu';+Pd;^@1ϼR@x[[vsY^qNnfi-ڐ/2xEf"5z:q3TZ樧uN*c"50vف%ֺWd.sq}20+MW`VlU7|l<2].LHXQ{{^ҩy gύ3wSW{+%aD?>ٯ?&m${Uڍ&\Ymh;G>9mdZUZjFy(SDDG 6Ѿ&ڗОAa A+]lwG<\+`˨"}'e&fVC z\D.AE=;2ŠfWI^{־14G`03%çNR:-{  OH N")112q x/'`']m>QoV\wBcmm3f(7J:;9R100K^@ـaeÂ˾դxFuD~>ȒpZ]YQ4}C#BM4J @~'aBgC毀 ʚL֐_3Ǻ~|99jCW}K0s>,v)%%1o/_y3  C0v̊Lt͊fkbA555=݊fǛគ2߳Օ9g* iB\VJL@'!*!lmm-['MLM!Eɩ *s;B:cdd 賄/]@]BBV'=ʺw\b,w&&/2h 4ZTڤLLLd;KGrAVO/yv;- rA:\CmR!~e=M-I~zz?;R:p0]JM潡dYjT 3Pij쀡 K.7O phhh)d7E Ld]z57`&ͿKfUش'+L6Hu{31az{1@fvۧ~@Ha2_sD9{aqWmrDʇ|%? WI>[ R72wu LZG5WgqT.uՕ;XG+++_L* v#U#"! @3TfR?T`)Z{#%5i^Ն2K3!vgqs>B;Rd__tZ[{ _zXXY2!!uj?~ǚ bn.7Cjpbbzr^,W^*٧d m=jyT:/њ ZiX}@F}3J*@] (pf=s66u0 LyuT;Z7+ tR59k@_644DcuA+++  [gkӦǨ#EK ŵ]"?N+M˹B8ۓ26Gpnocń_+,0uǡUxofuL P4xh-V+'[{wZוQhQ[l@}`ԞO0v2 p<έ@YV[_Qe!*Cbrü]t(ibQ]ss=™55DgNڱARE)7+b_ˠ7뫰 ʐ hIE6\t0^(k2hTK,J666.T7 DڍOO7||X3]_YէݙJ`s5.clf@YWvz;6Gq'҂D($nJQF"OvUsW4~ VҋNLEwW5v G#x6Acx[Pg!0wCKZIU{X 4W7m_yAMM_GFFaLh^ Q !G>R$( y] VLo1eF6'>>>\DH!8:}rm늡 RK23Ug§9[k5T[sCT-L`ejH`~U nE_ȹN%1kjVgyxyg{Zטp,YܝtejFg}A86;+w? Ti3}e5E+*\5!:]pssxrMEf۲bplCm%[s"ۢjUp.n䫷BG3MpsQGU59t.~Cj;T-/I'הN 3i[pOr*y4Vd丐3凙7\|vc ?H"wUk{(@̳gXY9?;G\`;?ܿ R1Q_Mr#i_V"Q5|3,ɮLG8淵h5l|@DE;ń`F1@M'P\1yїȬIsL>>zàREցrxe"eAHJIowMFxhkZL,A}02ҹ($oA!;jjjg;::cu@[G8-jT"\B ` xytIG?xrWxf.&1QvxO[p/ZEecce$$Nof'ʣ4.!6j?nK{Sy42b*w,p!rDg~|Hk űma—\Xaz^sݙWwÉɕjn) %2|vxC3HChIFa죨ZVJ-MXK&qYjB!\{xvQ^NM:o޾}KFE?$'Tl,:JJK 2zuӢ 7wCzr21F|aGͯ{n?MeM}$ÝkTxyW4:<Ԕѯ^gsWUHweVVҡS\] rWIQPeQۇF溳O0Mvi\BGn6?BM[V韋VNO<γupv/2+ ܜhЮ9:/$,*ҴtiQ34%xp]Pu+xjq`(Xf3FnUrB>gd_/o<3N1\"ֳ_wkJ&n`h|qQr]QqbHh;x&z޶=ϼ 5j7f$jDЄ@8SDu3i!l/{n.BaSR.n$sEuu-+VQU뵥ͽ?3?~KӧO%0̚91Rgf܄Pi U\$A29_ ,嗚9fURݾ}g%=i333-dʺassf"hU44^ee?0;cqtzլhZ7,DHc~AΣY#DW\))ƤBAV1^@ P{{,Z3/Z!tuswofat*ч49f6\tSWO k5+MƱ>N2>FDBwn2<;,&^@׵TsK1( Ldsckkd 3Z9w<VжD%|:ϴբƍ;g}3}/s-7lܜjKԸڊ}h꺳~pѥ437W/͛SX6|O:s/̄S5 ٥{u"7QxNN,,O}U)(|cykzdQ} Xo`PGjb³ \ 9*NhНI֖nX  )0&I[4Hֽ"M+.Dp]]v@e]m͈֩l}J74qo]r\aq|cJ :kjzsu񰐤GeURSёyC8[ZZXÛeC;Ke1"<(M%Cš_W2Y5}.a!TqP'NN7^Em&7N\l,n+I<ȴpeqd[." qlJikp[{82?M}.g:bNݚ608U)6G)rrϬ;Ķ}WӇqpT|ۃ7Ce JvjfXʎj h̍xz[OOxa%2AL-Gey]KЁIQS?=b7x{̖*ͮ{l|J.<,\ e^K>"/K."n'>dS<CJpo{Vr_V";ELLZРnD1AUh,=>պy{T 7OiOtS}5^9M)Mi _}PK xVrmmҖeȁaN\˺5&B:ܦ`'SU"BG_( r45| ;/L⾽4ʉu",}q(c|n2W Qm(O,0}HR)0E} ՠ=f~^LIMVkȣXԙTl"GGGK˗w<>!B ffAT^E XvccCV;vvGEf!XIG{LWߚqA 缬PSSvIJV!5 ' R>>a:.VwsdUŧΕޤkl,$;*uZUrVEK+,^̓7o357 ܁ 22?$C=loz8l>*swk$yyj)`;v*!#㜚qsCP*~4E'ip^IJny- ڃ)8 0*8tDH_ftP[^^Q1>il_ ?͛cÙe>Xp]@Pͳ޹R|KIFF +mz.._|LO 5y@=`*1;ע=kMԴoGr F4-hmEDF~4Cgc W:4&]9]j?ظ_gQΟ'<)o uu傥V===ɥa>DQǤFc; y;XzE4߷ Co0"0<Ɩ͋_2RnPKyKP|@ebwxhelp/index.htmlUT uYuYux uRM0 W3']Höe{(ptmbDvGNSYt,KOzϊoZM46Be"b1OM:_.?װ~ow R~r]D)lj/+ߘtqb43DnkhѠC"HIFňa"<|xZ˨8BVd&,qt2|+i4 |_.סj++1whyOwcXO2A;2[hC,X+Z'[p.u%ZŽݝj{=TV=hW1 3qzzMwe7eM l.2p0k uDP''s3E*0CAQɁ^8s 9H)Ep{{}A`J@ /ȈHi.8;˩!oagBg)-gU;Sg7#G \0BSsq䦥jvtjgdKrq0|2 R}yip\/֤S_1ݖ=;DiG2[d䛽7L, wxmt;қTp4R!N !Lխa\ Z$>r]+$تrZ*|,d}$#0ՅbC̑C%pf\C̴V>7ޠN}r\ycmm9x6.'QY ܋_-KYAf0s M(C.|Lݻ= F R%EM] \1*MIU׉&1ԯS$q~ϕCKwuIy!٦+ՉWsFJz 7«]_ Z5 utM0.3JZOjLdR|pSmm+ JL?3 ^v`, Ct׌A?靹o gb r&ۅKXvOʠD?Džw6[v ,N@r&\4B*\[2&d-s6Ւs"~-[bWqnGI(Jȿ/yqk(k(GcӼy~ [&&QW?#u-L&nm] 5c̪@u"WܸǭZr>0ȩ|HP~\YV 0 :k>~6> #G}ڗfF9}B\+{\jL9gH AVu EN4CǡZ1>@>NB9?Xlo?eˆL/s<1y%m`]@?7͐K*9=as_ ^cVn݃~y$^Dy&oE$om)`d\7y:瑫VKmds5{^>J5i7 -;eQR׿ό*i5A:A'Sk"7YU0@ښ!h@ɬFqOp`lg2ϧa☠!`6mN_w'Vv^;(  8c~<6rI O(@+Tٚpf%>T2eᥦF'=歍}ːf.J=a6Ga>k_2q| %-LbƗ9;IkeF_$Ń^⓯*rLpovTX۪ow;B'7C2^7&plpA! waR$nܭ^ARro`i{cdž .\3?(yvwFm'^gk~]) ՟ (3Ce'Uc->/o@ha:>H!M_4Wq쒶׮ARONht/Ndt>6Mp[WH<JɊE45_2x,-)ZDH?rN)kA!B"q a' Jҹ=, H=]g܆d!'Nt_5ʚ#XFS<+pE29hF~O<.2:\{q D -WWVKez GC_6σJ =|lJ?W9#m^t4?v 1OZ S)5Yo>w@6DE_P3@1q&vy@h`9W 0K>{ay&G ~{fȤQ̑=ߎ͂KQPWWWJ!$Y}dP𤹓Y[Y{@ʁ̭"2\\-MCf U5ջ熿έvz=TIVmcPTT>Kcc8Bq_`#Y&oⷮ.ܻq7pKi~k1I].w;?u >)o4ꏣQd_ݟi"R#HÃϯYF3k˛\H>@í#߽]HpMw}*JA3קKt11L~5]/IH(b~16'qq{z} q I%Ϧl`ԉh=W+55u3>!!& K`'Xrr~/870w?ep[awWC-􌊌MMWTT&&fmTJ###z ,?* k0+i{V[r`.~ \;u][[ewVS ϤIE£K.%%EIGTQ9ƍC89Ϗ^xA-==jvV5X^*H5Lrkkk%50 Y쟟Y6z߷=ߋAfD=C؇ER>y{yT:C~KSSiHy__AHCCC^^uvӨ*~En()8,t1COOnEL@m?˞-Gm8jfz t $#{7*vFSF#\S54MPS2A|AAԧĴwpDJ-EFVJJ'Zzl՝PS"te_6#һ>%9D!=zxx0l`A܎I ? |QK"|& Ah0NU-5_qЀ$G@lm `(no64P"H/+)YKGgc\K94!&0v5njׯ_FFfi !Khh(33 vD7 ikk&etyyyF2ük;;Hm(`y?79`:xc@SBN"dttIc}*JJR+V>oM1CWW %X9Ʀo2쀝_o^V4I'4ՑPG!汎l)B?pL?>4.x*sO%UO4#5uwD*FPKLH _j u(6(4MV l Mk|ww3hA5ߴA ZIBuiWd EtK.$$\/).nb=/?? 6-.jjq1CZ1- ԼN.nnm`=[sOoc SA׈APWP>C cWc'TZ;ȿA, {.y[ZDiwe6PVI{ތ(38Urpzɍ>b ʾzAg/EY_bgԜVXŐ=|ĠV_@<ǶDm5 uw ͑ .9§Vc>N%RX Mr+f&_$'NQ2? 3}m֮^c'((C *W`׶ ' ݯSFĜ^Q 3>DܸΔM=X.bhpզ -,^wORl㥦P`[I!ɟnN]`n+{H˽ ^KHv"^-}g0 J&, &&&qoF~677"#% J\T7"HܚA@שMmly[hDE>S  @pu[}yv wCZ.ul qϠy oC%^3BoPB@ QD!/ٯ}ݼ/e )f⏀~Bg*,D=<`)BycSSuuuo4h 7tvtgaof0׆_5--|PZDo?YT`cX -~l:u-u j{(jD $+s`1_B(` __66s T9̞4_PzR6CRpǯnA`ddYȕV&絷u5HcM0088$`-W"xV0DXx4Pg{0ڠ D[P.Ջ71 (//bJ|UoX4Tilc1A~1WW֧;jLI+yǫSϣ. `}fegÁCKFL(02x$E0N>wP!?P8r\1'yں/B #%7!.$t Í)#1 D671C3lE^YRjjB߹s~L'h4w l]-tAͼC?-K8"$ (7{Ta7Au;#'J| ã, lq,@l\~';scU0c3 YN1~!F"T_^(qSpm QqKeӋ CgwnщIہ89zA3'HG%fJ -?&6*HTTT^^Bw> A 3طB"Er,a) ^Ete]/n"ĤM H5;"b[~ ՚eN Q^jjx~~~f ,PN4Ì/Tp}IHwZGvN5OY~ӽȅJS$e1U+mm Ma O?}>T:MJkW4//,y^ewwwP`4J(h{7:j}|<porhvZQq$eSoGjxWEoʹ^*kVJں$ <`i~O0@͠ g#_SK6x\,OmibdaI*RMy: N& _;p?sv\\\sUfd:ڄ-q#MeI3ޝ끮25& F 3 $&wږ?$) ƒGWkО8K),0"<.Jp~~^AF&ӳbg@5|0s 建kLqf)NbVB0+nlhQmw=(+l|Q n] ^:iƃMtOֻ?UPP }xWL J)PFbnPmD*Ϙڨ-q&ƏFde&M"׏F?f?"b&owoҊÎkO'gfkPJ}_M\GRu暑)62#.Gmϖt1«Xp*}x"SQmZnQA0t]5"Ȃ9&]KbTwD7_%/C6,VSpU%cN?"9GxRN2N uCo ۲9urv|ٳ0^R؏bP %14!Ӳ kDPRhh@SX --—FcZ?_djXD6и= "$v)<#y#]~bm'z ^kj4߾3"L$d88LV4IфEka}J9)q9++ɮ?h" i%zq=''uObo]´^UVr/2]NֿQ3癸$q\Y8xʟ{ FX} G} 0oKO,p|8y' Q02v ^jr|TO^1! rvhsjQ@Wj3}#1Jo/"I#)UB\8 {l[{*菈/P`ˀ bxf{?+5hFJcumںׯ5ڤ* NV_!c ֽOۅA^)ro+R7Q֗.g!59h&HΨ4){rdcaV33]i0/D/B4]-/ 5f>F㰙dt=a;] AW4ss +nͿ*:ttH[o9EWzr_GE9ϲuVkq2]E޻DDY{o귐G=b|WZ!2 #mm" ,MCp^K~E˧nT iim_y<n{B>>Z:%gl +jL%F"~)(zW1=qv?xP"`ABk; viԗ<hEKR?#g/tЅl`GZgdDSz)``C_8]ۚ#YHKP\ʝQ /7}A݉G-zJ#AUVZMd|yyFNN'wHlg:,fs`k0t kWi2=ζ[^0 `5A֛68x*(#Q.!ggiq/,E1H-}&gg= ؅ϫ߆1YD c iv00cQ{PmV&LLIS-YVG$c @Df]]0k}sywdz BB-ri7"+Xi┒T8}i'FEQ^DT[5$8oS U5::ep׬XFϰɋKwdms#mԱA7LJri [ꑒ`Gs:8U>nO݅q|ɡk彻Ny 1mBTBqb?)1 d/gܖgޅF%,(|D,+ N b8MI+眑2 ?PRh^xk;VyEQb)챑/Ȉg ucFp"Cؘ̯A-,؆|1۫.PQ7yXM \0ޥؤA8H¤4FGGCSSS999 uAL[ƢQ(O糏!-R5+FSi^^?|ܐǁDvy68%[_^a\&QrL1`mT5P7!LYXRQnop  W˽QSYCC7iߪEHܾ{7,gxE,,qJmIvlz:n޼)M˶$kq ߬tT1Gs5q@CW_ +| BZZ}u?Bbbև:6r;3YYk#邳[u걯( Rgv;5%K{8*e-O(5=aӯ'-[h#[Ъd(OP7v)GG?CI/eu>7G|xkGz6U/[#)e'Zs|upe?bMkRKپ 1;SP03X2?c l1q8"ot^ɠILgrr/>F!3w~=.>kZ@$ qvvm~Muu:uދvfG$pftANSKp~&TuuPFP A50oY(.(ª2ޖ[ r|6:`Q.dJ3;T@(j7`s{Sz=[< ֛s ~kJ +UeO[X8 jxF͒/ŌM!6v7jux_JxcBhEqJ+,k/H /y[C౗HڝS`SʆU<tc`:A|?#~rYuhmB<\:x`5ztҖsv;nF>m{uwT%,BNxFj̛ηa>Xb娛զ3-FUڻjGP3n+SQQ7Yh.Ά% ۦ$Dd--deM'=%yP#8UjtNhOߩ"u+kv^ueX6zBIxB+x6ļ:~G ,?Db4'8ݰM}x% Wb~`OlIɦ9PX=FOO$t_NGsPrș ۳W-Mav, "NFԦ0^n,HVO.ؘ0?]󠫇"k3`;GBrb[9.% $ Sc~Bx~s3f]q}lڰ? /B`: h{z{)s`B|r@^BDBZ;mbS.h%!15(6FjHМ+dym! Z]RŽb3I-Ht۽]_BG\IDwxWz>ڊ=bg2~ J,(BUWE(%Pu>2Kς4\F1Rz~^rVNԋ~{k= JJ{u+$J vJKW]).zxzz]j9 Raͯ^wvze}b}90XdOm߾y y(`eq]8D hJĄ <, N+IbX:Gu܂4M)Ѧ7BWd3>egG^3kv.3T}׆\|OmH N/n#f(R0지MW#T;^|W#z IV*|I},7PKyK*Yebwxshell/index.htmlUT vYvYux UQ6 ~NfN m^blŎdHr|_?R%+f ,㮁=ZǓdHyލ&E\>y?_>|x__ߦa9IxB;)ht)&EYB?d^Y:Nt ySB1T78I¹bBS烘CClZF>A^1vkxb#ʩq3#ƻhcE*@m_{pZ>vd!'HCKiJ"L;9y._hSi;$SݽW퐞YrZ˺KJ+&@`JI}Xc8(#wZ'\ex./~s\M]3U6T&KTYHVSHt;!YI6PcQKY^aq3NG@Ǒ7XMe#IdR6Br 9{߄_ F!*9GKKxI>P}Mi ړB畳wڲW%;{wVEZ ןiri~% j]8+qiWC7]eœQjS3+2.$ZzQ<{=kr}{مJ6²J?ՍM4 ^,vWR--H!`<@" ɡLMyhkl<%!oFZzI*[%ow &flcPr$7[K21(ʇ2B?㣎q: T}#1kk%4cl&$ۚ32ϸf5oP XHc47&GQWű([XNReivC+oҺh"H)0Zk*Y6'Q(H:G%-'" $IRn;4XxUn=q+jQ㝧 T"˨_CPj2a)׼w{n RcCfu8b.o`n{6+9KY6MAd'¢zej"K9Um]#qx13*Wia>AV7$2(Lf=O/ ^gmQc?ajÕ`?[.)Oh Hi,^OplV Uf '[4:V( 6S]r_ؽt"BG}>CpgVr}WjQ"[-QCUlK.sQqU\E;޲(47g,; .)y)Xb&\!f^Pk3jV=j2 OoOǾ(Qa ݸ~@e<@*d BwܝT T(,|<ҽi=tʱ$%IɄXE1uzZ{xw\G1"FmdrN8;ބ9#|!2o9C3]?Zf5]|XSW6|Tǔ%nӟ!+*;#[f;Q˄`rJZq뜂ǿBwx&$h-L7UwPl&Z(\ކ\oҒj;qFoa+0; S՘Zɬ<\.yy9x -5UJߧV%V5x!Up&ɹe"VoHE\yat{M>HԚIj$'9Yar\i ;$j{.|}h_sz,tS&j7}'}D''` E;;W<6g/[k0ÑQ]%Sz88^%~)<&SDVrtW:SG&얺覫Kb *kXi*9c} 0͙C0go~C,{7}x' ~UC3L Ír<2 8Eti%<"Hфx>%6DvBv݂B4>eX䴴e˫cn8,pAnZ=vnC@Gat1#oAJ5}{%q!q'̮ۙ;z gDC_=""l%ʗG0oTb+ 9V/%`\+gڛ26?qWaĐ=~8O6N;i~= *73z=֋!zmFY>>{</e1;•vm{yYPR|V907Q5 ߐi$٩]fٗ sYܻwϧV@٘=%Dݗ=6UZ:\դn9dRl* U 4]f/.-媣KbاF<&O*=.Dw]ǫNPvIHL:M[i2ZtYO]hfG-_`"M !tSKv~rQC}}P])]hӥa;9]Σ+&J.HA$CYFձxIGt .fTTO())P䌌+‚ 9D[MMpxruύxDbNPYssss-a˽)d44슶yN3m~9@*p<oUP9IRh"Z1~?76CtCz9aݖBN9"$OxxJT<0}ٗ3WO- ǒkLg$:f)Ű[, C.16Q?~V;N=*q]NܗVwA߸k9s E}n4]rщ+8җdʇ+h-VѠ̦jᶨtϕyyywJ?7x-J Dء7FgrIX(JyNٵTաyimg]Ybf5ȐEK6zn& O&˅D?XmRmT~Oec].F΍7VSf&$zZcGVrIi9oqG{6&`9$~[#g]pU\w U'Ld.qLtMcGN6;}v=HOC1O@":ۙCQyT|s4$>WC=|D ec $^Bӹ}U*W˲㙖=. n#HEdza`{ߒx;$$-3^fQp m8/bqrrRtPMPxHkq/\rm(7^W'9\źp&>#&ƭnz%%zvrb~lair&y4o d`SnP\ds%#pQMVˏ9XffwwJibnTlԴgVl`-%uqw?y-?. Kp(PMƜ~)j644WȭHUj־~HBp2|Zii=i -Ϡd2ƬsM?|=x|[++$ ~ ;h~Q>}e5WFsu*gCGǪ7y K2ǔSt]:.]:K=KBcP(ɋ@UmϏ6!+NsU]ηoSU?<8a0v}QOR Qx_x$O=zAv (=}OXTRi~WAs(Gᱮ0QzHkH;< BUݲ ' 9)DW.$"lٿ?clRItk9{_ :t&ETS~ccssPO h(h|f:-q fY~.B/NDIa{&*îdpZЌDeJW G-VNx<+U<۴93*u~C3 Ɠ#ϭMā+OlMk8r/Q?є*p K4ScW{ 06CyӤ͡U3*jYBv 4\5(S1ֺǺ%eCj*獘$$58jesu4@edsSRZK<9YF.P`UjZ@y\zmǩNsޱ\!z!@_|$MQڎlS4uq-%9ݿOAf8_vǬ>M+7TUY$wtojIgE_Бsyd&3rp1c|3ߠᄶxI3l55a!P9fZ'~@ɛH cZL{{1`SǏFL^^^555cYLl\{=bS3&,jra*Aٲ{anC3&3]ZB'xN%Zxp LlM:QONpWCq0CkڊjzkG:0 0_U__vK턠x]bԳ@73bJVtr=>YX2Kd ։WscVׯ+ {(VM^zf5Clu 62̆3I!۵8dA<#EpFT#}E:b;CʥY3- >e-5A]{!+A'rJ9M>}o )}Ik C] G$EN9b17_8.:W3*S(4>%!gq&7:!!!Y/wK)H^]}@Cj6?߬>?6:lՙ5::Z'I/i\ȠJ͛<\JX:"l{,]C Z`v`^ϱ_ޒx ;R8H{ȫ}¶.KNbnF@<1+̅.`e}RRT>HF/_-xkNmO85阛gI!uJ[@(~?ױ2XwWgF[ 84IM9i^3'!dl%gJ>)LoE*yFI,&;i@mR!3{(W -S ȨSիPnڀ/ON;;;7FKxU'o 瑔<==U6fʽԨ-&&]f(~ eH~fC-b8$lme1uUޣ+V6ѯp== X֖',,r]1C`6gxǸMщV?;CbGG p>\n`=8;`~λ. ^!IH!nN2[ 7ܙm>,bxLFηJ:Xׇ+KA$Q/vwaȍՁ$8/v!Φk D̫XS_H ^b:@Xřek& êrA!UEx7Q-qqy% W.wOs3b =&гܽ=Mm}r/ cхCI*ɀz3^Pѡ#=+cVm {}#* 0)Q&!Zc@m,E#6Y4\͖c gkpl2NQPҰg;cSÄ|kiX ؚ &WZl,R_Z] %,$`K&F&Az}BŶ,ŨXvd?f= dO:]%rQ!i,K*As$yhrvFs@``[>cvj8ݝf<zu> jCJ)gMMM,4ZjD_, H'2tqcdwƼo!M gstn(d3W=??Oǝkٓ( @)@IY9 \oҕC^cٍb:)$e&1^/Q37S*ԥƟ>ydbsѣ E7N,5 H@wZ9zh=bַlgm䭍Nz wJLJMMURRDry"&t]=\)yfQc>|8eϕ6ݖTB${,3ZYY[u{=l^*0r[{Sd)t{)#@YX3 6oO hjH/Х%_+wNIӥO)${#/q!ۘĄ]P\Vػ@̠T>9%`FJ w;{J#Nٖ_}s)x҈gYίX@"C pp|x/']_`L\=5B1N!!!`glAmGO V{x.yF$j#ZZ 8mىaDd6|.l-| 2]e {"KE<7~`twXґg?n;Y q!ޕo>y b t"@k8;Dx |C)P>eXFᅂ\l-l$k &G;m%ѩQ)2F@8u3)h6Bez}[)j .T۲^0)99Րejҝu[tN$:ܤ$|Wy'(ɩl~{9W]y=Tu MP2$XPz{-s+s,&uzzD&%MU9 +2UYSšO==ڌʐw}'F؋!\89׌L2./Ӷǯ>&- &;V)8(SSĪsqʇ[OYP pQr.TUVWF<ȩNK{J7Ig7h7Ƽ8.YE09^(dﺈitq8Mջq1i{PMYy laaj u82Wō*I􏨿Qj@mjd@շ0N]eّoݮἯ3~>-[4}!Lv1{^ךomo~jhbՕ1!{c0mU*Ca|XtTcX*I;?#š(($+@u\5\R{k(7ÿdq乹9-: mG ?M1Ey:dv5 ѐ[7ܞ6Zp޸cY￸QV<:}韏9mCx` .Ic)Lq ņdo҉ޡhfjY2^nGx-(Hlb4((Ha<_5_Qb-q!ʕf WPllOG{LYR*w's1&.++ RUb]Q0g1t,HHO@L S㶌Al5xgADPR()sgCLO է`oP@.i|zvqcwهilP tt +&X~}NN{27{GG#cV >`tT]ᱮ]Ѕ`oX2.d%Kj_bPʔFO^-ʳc3&jjg{:5u5\RO]5I|N[LP%\pkv .x([9`̮]pBlOkuA0|6VÏxx[ErXiQx͘f\ b!nQAVnakBg_{b W m?8߮a.*ܭt5$UKGO\NH,)xJ|ZQ#>ץEp<'|649NL<ӫZNbI(eP]խd,f\] lG=?|*/=JcFDLc oUÜ.ac r7mbΤ/P3ۢ%i>'HCnʹYO o`ӗ(~/gPhCc kr}g8ܢf0l{,h3KXw $l.g8Ws^(?Pa"k흘0@r~H)ciNTZD9v{,+V蟧<޾ ]12sgUߋ[N0Cx=;IDgH7)} b|+cZdeϪl`)g0Oӵ˟͎v'i%*K7 ls5Leߋ]q2$q^fz_͡_$(,]SWdʫ(BFj*kf ]S7[xL0L󏼋{tHX9r6'"SZvMYtHɧ,W+z,\N ;L221ҳg]\L7nuunS沌X $a<:T0^/̼3f[ѪU2gN[@d^{GZ\4\3#{q&>G"Xe=[v.'N3V>\|u#x *i#pά99KTcJ&Y ]‰U 3_݆zM~5oҾ(Wq$o܁bmq/+d7V^ S]3zBn55ו_ XFR>ƩãS`҃+N߭a gYUGMML+bb!YL@m]ٰ557:s_.CdA25OitNs], Lj{#I>r妨o|8PL#x!b5\qQj֞n6e^> _rio9nSBtxbYZ嬎)?J+B8T~5jYpt:p,OHE׺mM'ܤSj>1{wtDB?XaLwaNw΋һ1UE㎋?oDFZږ١햻))G6bKqOV{}/ZnClBDYf>>"R7V%Fv88gxs$]~,-JrC=ZrYu i]%/Q'CI;Y~@-s{Tym5c||Ї;:;ۛ#Ec6n~Q=:Jdo 疂i숪`5 (Qr[;t$\2w_q"?>$[|s6=?{iA!/g(|7U18~/3gkm  )c۵f߹uD lv- O WWO79=Wp2{OinX팫=Tyu,D:x` On7q:^> %ܗc/e;t ym\\/Gqzi q]I'qzψɎZ5g绌:;;#kTJ [VVViqt?Zkl:whYY 2Ld֠U'uz'@"p/7C0Z#ʙd*FisĖ7@x ޚzZdPԵ8#D {‰J|A<;kչ|o_x|Vݖƪ紐gdjSWWx~c1QZХLyObC-\&җ`D*bƓjkE@MrKKzgР.p㧏**YYY2{ ֿ!;x 꿳QQe2ȎJ#F(6LuL"#'whiGbbC(gMa']lt>ϥM 45k;}üO8n'm㸍jY( Y !ZGb:kpŦLֵz e@@bXz<>\8&}ZNބO/xLURz57O$Q>o zԝ͛_˳{:e#6>(27?9v)> (*R oqJtu_x -1Jll% L::n(thYu@ZKגF Ѽ&TvcÍar:/> y zw@'$Y &7:m nK1ݏL_̷BrtОk,~weSAGM Qí2"$whŨR- N\{3  B*..NHDt*&V?Ms($c~גUQ;wܺ|L07ov"P띚XOcccw*a$qQ?!olP7CT!yԋmMx_a- E]664}0֔ ?QR3|£}Ff/ iѓ2 eݢ`/ %tIdWTD" BP1D%T:`ⓒ|ǡquzOfJN xyy Zߟd&$ΖONCDtzĬgONPM /Uk߿p(l3³p[c3@ub:;MWMU$S{^$uwine!bUUCC(9'Fa@%SiN B%N'Z_!UqoNJ(xgc?z<1;;xվ7}MJJF&eܭ?\$ݻƆI6 1S(7O^b<7Iʭzs;F媘~m#/8(eQwP~Op!aJ ~+"lFkL}-..z 2WmFf4P g[_XXC%f!I=2HǩRcɚ_We 666pGjBטʷMU[Vֳ5 ȰX vY Ip;# ),`]!1}& "#\-V'Grr}ǩHط_ܖBiuuˠW>5J\dmlv7BH}tF_\xp_Ɣwtt߿H>PuP>G T['ߦWgrns%)iR]:ڜzWB@kRz }M3&g{xR1}<:/S^?UMd5HTg+2NC[[ё[93ƞ/ᓗ^\}2?b}$yU9x>)IN0t-NW,13|OB(e*l&'G,8E::n|O{~4Zm8 :Q/W̙Mk%|r7!@+%YXYEzl 9M/ [ݵQ~Q%xina'3/H>txut4XO$8,䔻̅GoRA">>>S)&d  ppp`&MOqo|&rjBFu*++Ƣ]ۈ\n߹JUSDRgcfJPxYaaym\g*hJO~$sݩtd]h%c}rrDwloޒhggE]-EQMiag=v)m/*&=*6M=˶D8^oӛ=6{豘\2FFx@;7RsOj]]{9,B^>۽(ު Wm]Wox$wο\@*g;<i6q]?Ҋ ۠{KTDDD NJ<[f&#zQQG¸ ~:nBoS /,DCXf~6S yrγN6n0xY5즩>Z yx,pUPlj^MAJDZ?Y&=oJރz&Ptnt vk&;px& aW/BY8 5idL*+zvvvQK ~QwJK_;7r^@zkI hInNo7gxQKRO"~0nٓpۉ>޾Z̛/?fo\]HO@VTB#1h ^`AFI.%d PrrL ƏƘoܻv0чUDBBBRk 2ԒܮPT S~Z)ܘ!7$㲎'k@}~jdYZ 58WRלlY;B/7ȧXoyk޲Й*}Y3\SȮ PZ;p4@bzػA$BkjSD(d_%iADvufvkңVinC5t8ٝV?ph]m-Q@7^mlMq.fT7eL+{֭>/b+#)+B*!!_<vH2-nv?G#}~p8O&>f߭ط+~fD3%ľDl޼J.]X,gcEGn|\q*.>Ue'~s9c2!KvP0ޏȚ!rz}VcC{pdCrrrW?nGϱܱB"nӧOpB}}W IRF!@$\.ccc|M>zFyH$u999 (~?f``)ϭ8y$%F~?"&4ϟvn}9aY4$I`0`4OVdd2t:Y__ghhH$餲Kc3Rzq\ܭ[$r߿(}&e=׎(//ON:;;ikkczzlo.gYF=ېb\XTĶǯB^G!]~%EQЎli("UWl2؋Dp~N(D,](rbrs;D0kt:rsseCsIENDB`PK yK8oILebwxshell/button-ok.pngUT vYvYux PNG  IHDR9sRGBbKGD pHYsgRtIME 6رtEXtCommentCreated with The GIMPd%noIDATHŖ_hSW?'^cޤ[ZLj6dMPH>\)I؟,L(m&c^Ln`L4ET:)MCr[={ &~;{~K)޹Y4MBuuuT @]H&z4M+ eYܽ}H!ģ](_H޻d4wfi7C~/UVh>DRjѼ/-ˢP(PI4b[Z Ggx3lo!N<я_ɟ3|ӳu}||9s]w1pcWß3WL&û|~E2mɮSjϾ!(B=my> bH >;7oix y"9A$'a tbInnjνccu}}dB|c'M6qH %GY~q]m۸b###Cb9νsdK;ʩV>f9v46>CO[LbS芎 cjL g}j"u-ARDOD9Z ma-~ WoExUswj_aMM(B!g刏 4vn70?h8^.x 0!78']ם\,ae=RuT2UU%!O-,xPGL\B"@J(!$H0Pm].TK.eU,8cÁak}= 6:%Ӕl\.GP(䊢t:q\ _ KIENDB`PKyKV>,ebwxshell/files.htmlUT vYvYux SKo1+NSYh$hģJrz]k ~}ƻTR/~fNWL00@SXL9ex|;]K?,ͯ%oVs0e4|Yt`'W v:AZtBTИ;D+SC=e>4 10n,Ix=ЅA858e_CTw[y,nn~QvE' <$zQ6Ch(M$  k;`'DMj`b sWu ̷71^FȭH\ Jn'jٵuup %4ئER-f׫%O뜒J`)孒!yDfU(`l#(f6%z-J?XBw!t/t+ [4VElF7X,j]Vhʈ}T^$M{K4&s H2}Ҋek˶RntʞfjƿDesXRo5= L DYPKyK(1-hebwxshell/clo.htmlUT vYvYux Umo0_qxbMZIK3ҀIoN|I%vd_N#R;?Kvrݵ0R9%SJ-LZ=9<<8I=Y~\?{ oߟW&iue\xLgpnQTަ׵d rAoȜt-YJu 9E :jΒ$-M)*&4`nz3/0:iThqE]V9}Fg;uqzgp |/gG+ n% @(uq%|D ơPEZ A'EPh#\IMOض=ZXT@j7`VgtO&J_57"KtK4uxW@4褒$K?(Cvvk,J^VWa4܁ ᚕFP mnu]AG#j tZ#h<i c5adCoWr,l&_eܖ ;&Xx*Ky?z# 6E)_Cy1kCtD_Pq[Pk.w yQ`o bFp MWndR'vn9:4՜LȭV]:b\R~~s@9O#@5tb)4յTԄ}!TqQk15b?eAS3" PK yKimages/UT uYvYux PK yK7images/youtube-mini.pngUT uYuYux PNG  IHDRVΎWgAMA abKGD pHYs  tIME"ritEXtCommentCreated with GIMPWNIDAT8˭jQY,$E:ؤi4y!e hgJXAd Ic$X;Yβ\Czz}ںdy&2xL^O/tjL_UAUk0v9ƨq%k߮Skg_m܄O]f{R`hXz+n@3u,$@A-sXk0Ʉ1IYKN]X| X(,蹝V*, QU^JH.( gR W9a\>R;7M7`tkF9IENDB`PKyK42(images/linkedin-mini.pngUT uYuYux  sb``p  $?ORlI. @ĕ&gGd1cv t~ck300z8XۿPDp"$GK'wpn6`ΐӧ=YxD#Jnœb[s7Cٗ_w-g|zem},} *=cZV-lf*HT|.w*CT6+xt>s) 2>pĴUIKO 5w9~^4T8g!Ǒ"'Et++ZQXj\  t,X`=϶(rS2*qkȗ ) PKyKZ+ O images/ebname.jpgUT uYuYux y8ԋc1de˨1 ,9(FX946cw,ʖ Y"eνy~yyef~u}UfggCသv' EBpI铢H$RPD%#DJ GP^NN^I!s@&$A`8qE0;?l`09uB"2ʺN0aU5սr]08, `;Jc0; p c,yo-B&E.,k8>WʱBLEH^j`viGvg< (X5^ cy}kjJ-/2H^7OT͈\kX 3 S7ۨVʨD .\w%SSqN-Ɉ4OoaHkF_5-cº_Xܷj 3Uen#`Ђ$>&$| ^9[M Nlw_,q_c4~K -)"ڷ aaKKΗ݆}gJ;hPK:gpO1o2g7Qs͈pձN8wxoOtOO<&7zOB%tXc o25DCwQF˾h1UjT("8:Zn 0 HLz`e=̗9$ޯ>RoF\;׾Q B =%mgL`9&)2Oa2FTЛ%1N LdŒ,IZA,*7ȠM˄YGz%2b]vDzgax< `D9Yo3/2̍mZr15 -s| 0l_ČG/g*(ОDM[`joJvShWeIǾ</Zҙ،x*xpzPkE29=aב'#x 9)1#~z/'܉/XEJ/vcvfMv@h}  Mp`|s~I ZWtc4u}Qܤ^\{{C4W~H)-6W H߹OT"PI _;[ u s".\UUc`H Ε﹡͟>ld ^\|='һh׺c-YF!Lې˝s]P?R$A&W!1eնDE Rd1Wx=߶%mEŽg\Vh|]$"yTJxFxnܺMj =5s1*dӆ&k˃%okĨ"9b%1Kg kI9$>cOÐE?TA=tQ]7w"-r1sGjfjĠhG:woerns ruWӞM4 -Y CQ='yݴwW~fcE |X6+MsVakۅsyx1ɫ| HF+qwCp:ߗd^О CLkv)ٮV|iM&X=ttB>SA->'8ӂ/l=a-S*/TYPt%}>Jjr󉤯~DK }dꍃ\IdJҙ@g}e-Eo^y-Ԙ0n%l_*okYE i Th#]hYhe{#9,\*CEw{χ4sNWك⪕!j+ķubrzjΩ|v!I|Dj톭Ûl]1n)}6ԋ %ԞK$3D8ѲT0HC@->7LT唌.`] h-vMg60'?d[&QO'\ֈU9ڈ|i%3vp_UCzao+P*v֍6_-)((!(:N޳1' =}MDչPqwqt~D&p{Oy&y!x3YZ֍\ 9eE6g4e6 ?d QPWbv0ſ6f-LgڋbφjH~#' lút"r\{gRh/c׬,Y+&1&Q0Ţ_ϯpچVf!n+?{!a7-̞oػ\R i4MjA}iwp2Z~RVm6mpn"s7 P.$n~'xfX4̊nVo+KQCxalzx1#ԞQm*D/p QBu,g'xp$E#ܶh1/hcm[_. ZA @PDGR#A޹-1}{s<tSrqWN=fs.z CJ9UB> ` cӣpfrk%iXMnjhPAe>CsKx}fy>_/YsYb7Ⰶc =mwSM_PҒ6$ro*D ,pTP;su:[hEXv$)#GHXdfmY-VR#˰T Y.hT`$@T*D_J"?%6SIENDB`PKyKiiimages/perl_powered.pngUT uYuYux ? 7<ǚ|0PñQ921̵ Ӑ )e|Ė-,rM*٨{C4*1#{}>?a1 MPD;r Z_vm][f.ІLbsC|_Ck97CVVCm^lLb$(z6q?m!"(9hF[Ks+ BEeo^=q#] DV!? E"iڭ4 C<'.M$كIY-aO|DH Yz96OYS#] a M0p4ֵ?]WI 8D^/N)(M ZV]V5<R *|a`pMo gW᧘/O'@k̙ç*K3$"-E'# >R30I'O^X#dj.ۓf UYco勵X<Ԓ4EVhAz.bdoS,5](h1g=u#N|RV.icJÂS55Bɑ@o|XҞU<{TcS=+]` &vh,7D۩^ 6BG3qv`yo)KG/A?t ʹwy-> %CesCЈVYb|a;˼u NUv? x,nb3xK݉xDUa8+aFBNS|P 0l(h FVق#\ ծX:ǃ/WlZy"˳ǒ=Vĥo*Z=so:D.<Ѱ"mm8f({'2؋GےAhuW^p|)800.Į( MupDMq=r$[TfL8o^^a灾^_bQiݣdq?> B+󚹋?W ݄3ehP;Q/3Ї-V=}qG홞:/[V_jS _w,@78m.A2Y7Њ[Cf,U=UxO޳krXrk*u%̫w|5(ir4 w-)*Z+դF/`\~/GӖ  mAUPKyKR images/eb.jpgUT uYuYux gPLخ+- =@By*z#]wCHPBUJhD:J&])/=3g|?ggs_=;;? H - fgr f"''MEySnQfXabfcad} dw?ɍ]םF*)$2I`_WT 2rY@INBI~#) n1*&'<,i*(b^j;% !O1]7vv)d@270rR $:7HBِ Z<]V7-0oGg7`F #@u(%%ţdknxK2ܔ ݵg+W<`It(yٲBIf9 u CbjBd#F罯8s'x+ =*@kdtLΟFH Tx%ςxzg>1J߄/|RWt D|o0Wlg7WVjdx|sW5$mXg>S~a BUCOu\._!nc-0LwG@ߣrv^y>^acX1={gr39L3" q6gT2ަ6虄Z8q SL`F*dqESkۃ~ÍC9AFaQmn|jod˹y8m@QztCr]D'E'3`՟߆NBdv~kE_njҪ3m P Ly:~8mы<I2`Pf3!~?g̔աE}_A;hɏ+t% )\> x㓦axسřEp\e"W!|01ٽ@;/*[`w2'ħ]hBFj$T"?JATh }8At<3YמU&Q|6|;l;]I߬V\;TLM&-_$Y׼npvyLG$)imA&xM:Nx`B%9xcEzs rO9++}0[)6XZշ>u{BFp#l8dQGQIi+474fa s6 wGYeeJHa@GHʫMϿʠ<3mxK!+~ f$w "Hyd`MM+\hDevKSiYQrv ?3{|n||#j^/jѵ#G7%0X^΂=-H!g07e"F>ӆ<w3$k&Ί<1Nhyl5 4 @&'7߾DZ޽4ӫ/.!0=8TVw`[ĔT'p:gĩ{[ D9zg4ˇ-_pЏw7ꌆʃS)wp4w؁ps%W6-s~?"WEߗӍAbavjsIFz\T@H =nǑ۬_x<˱ vl45 Oސ2)ݝVjX>wFva[^1bl,>}]QQWRܿJTw-,̻PZ a[MrqrUn)rldo?fp5DACu2r__: b6QᵼSz[ۺ}pR61Kf@̈86Bs8קٯs%C|oѫ[o?Бlyn-[TeDap 넨 Vh! <%`vG4AtT66k?aF_njl_Բ!Kv4]3dy }]yDP *@F9d8/ط^\ $}ŔpTEA:_6u eU{qB|}caoűoTDydiy |)]1^B|'D#2 eo5 X]<Xs(^oHuxuR (a=2ֽ* elWf$H#C&ޫ>ē Ii3 q{o:ިik6Y8.qy)YNbQQ}8GƂ^ͺf[꿬uJEѱZ"e~ٰk^-!xGmyѻ?^!gU VpAD^EOV`P1ӂ}''fQ:, >EÅ)Pm]mZ9kD$c~y&:{ *sdYk7H/Cg=Ș}poNO|ʔUZH"UР߹pv‚c<֍okƶ{C20rյc%>6oī"Ry,25P^Y{I{# F 4^Qjt嬽P6vEjn.~^xiYΘ%o.4'J/R澯3ou&A"ɺ[P󬧄7̈Vw}!Z~w5n뎬yADž`@gsZx:cNJknw35 JcA":\B%k| Y"%Ug9CCyo([эC~{eU]cV9Y\^ϻS/PF >[YH戺Y.dYn*j@,9|uQ3R@ŦrKn7Z 77TS@.yYJ+cG%\̻H^SlۍTp"[kE< X/^9MQ/m92Vx'8Wi#C4`H0plwIϻiOM_TtEx"MޞR[cՠ`6竵vviqbNU*e+ҝ&k@:ڶ!LH`cѯQB{WӠ4M,2I_>Ӭl[0];Q{=6;=b X3!rx{r6D\mk {up+-dM]գsw ʰv;2CX#EIOcRH$ɩL>`y*6bACԔ#u5x|7kQq_3͖J|N3g'Q68nl}zgluj*\psx>mm?W=QG(+Rr9UKr n'nL>9ӭ(q!ޣ+s^WX^XcleBo~r xp6qBU"]}6nO^<ýڇ%'޻l/93pI6j5 Ub Q{-;Bj,/y,ʼn$%-}d!jP~ŽAV;oxd^euΏEV &?1I,jsҨ nD t'2Wj2P饶'Vb>#B_kǍ)5O0q!atTdL%ִaQid-$)*Qw ,jKxLѯR|@o`د/\@cƳ! kxHØLk@?Yj gŒ}(Z 0LW(:lrPd58R^DXq`Hۓxǔq:v ¼§juAȹ7B,ڏDq'KrG{1.lf .x>x&O;Զ[B@[cIO(>>raC,% 5sp''q.qM(yJx'$jxJ<\HWF'\P=fgkCS$~ (#2;0?@2๫f9;=)0[_=waMHa:ŷbE* Px:^j9ΐ߬"\ j9K|NhW邩gy6k`maUZ̊Mcp8eDM /nJ9:g"!X5Ǖ8(@yH./])B|lk{Cx+-uލOCnu;t9<>FO7zR>4^=l^oF;Ғ奫Ƨk4Fl l(ǒA?AG+067~bN̎ZNKk~hluۄV^Vz*+ǭe=gtr|)Ҭ] BM>TQ@O4 {&>d&͐lsj'j};$64KAJh*~N+=GHDN(ߖ$k7c*61Dŗ퇔~K0(kJ»B', 0N_.("3L23`Bj,\Vd kmC$o`}m~J(AuױsUzw8mEY'd뺇ßEEtҿKqEcB%h5V~T5k)k r{zLC%yh+I^/;2km0@UЉm\@5h(GЗH0 ;QF㆚IƵi+9gX)?-,v T@EuqN}~ź;,n]XK5 >?!5t$îQ%F@ m\(y|A @8 w>.ܒU5xwRXI[1CT 7Լxuy u3PE$n:o[)4/}&l뺗Dg:Zi^WxM6:hwKi"M,adPgSpNѡ8!!:T+ 3şjeG tKsrve{pa=Wd r}trQMs>6PyITw X1|f3/ggP4 SqQH:8|y^A3eI tpWɚo x`YwԖϟ4Y.DnlÊ3;j&p׷B;7]$NB}!R>skӱ(/jʲ(B$3"yjS 0? gǐ)pw_--n@ܦZ|W##3…Z4KUѴ,C) FF(MU,[TJm)+$p?h@XGM `\2#C8&Ыm & [ *4LP"ߔw8 -$+̤*CdxυMG` tجd.ƽ{Tm%Qȫ 7;fb/9yT6/nvFv=PK yK`xGGimages/identi-ca-mini.pngUT uYuYux PNG  IHDRasRGBbKGD pHYsgRtIME (DnIDAT8}KlTs޹h;m R` a" Yĕ! C"015,lp(!\H!"C [;ޙN0o9?!*kɆ;7U ,Ady:uу\7"( R.R;Z:6od8XG< S3O*n9PA,:zQ;d:lOSƸ3HOu2;ݛß _>dĺ:ig{Ւ 4/| ` XZ{C8XGKK* 5e̳ _!H6:7?nin02CӮ+9K`y XcnpTZ@ޙˊ <+""8#9gA0N."vP#bUo[fi\p}}Ulć0`vͼF+ʭx2qEնjS?p]|8"".]u {O|#aƂ'G~h-qmTnlf.73qmܺwvfhIԿRd6z= }}Rϟ8+1H]_j{qE᜙ql +kfiq30ʴ\y{|~~vq|_UYO_?O?Y~Wmjfӓc!=IO(zi?zfk´N}/K^Wk]`M/I<$jiF"KIQ>Ps΀nDy$bP3($)}(սF:9Sl\ɬF}"66LU wkKS|X ܇ogNIҹ ! NY^ Ӌo:;[gmÖv\N!hy>9}}Հen^Oc^sUgr654HϢREQyI~%il*ڶKWU!$ʎ<+F\Tﯣv[E4H~<p^ͣѯn+?L`G.РE )|C'-̤<}jA:Ɏ';&ƑKRd{ jk{_ֶ(i|tq,>,<ςp-]cyՂ4FA 2bw؊Kl%nL SuUjJFٺ7se sgKPhx=]ZMG;zq5 &x1dW/ hp^|yeV1V/ILfK PKyK8 ~X inex.htmlUT uYuYux XmSF_q.TRmlƬqBվUB*6`I _OH²SQX=Oƿ>f)m^E& >;;{_'OWw|C}xO|ZnU{}w;G=*/Wv7[_,D4^JKc]ʓq7L%YN/Zr`v-ZX]%w"e-Ǐ+c 65c{Z8?B#H,MiR7*/?V:F7)a/^J2Y4R,Slq>az06<gl9ayclF1( v5)N =Qia"^XY)KX#hMb|[wդC׼eYNM`;ke095V|`L*[A]ի9H`zQD[`0?4]e++kL~~jxˇhMx7z;)l0MGCpEgricfV[2{.j Oe_znrǭXIרI`~FR<8ЧL;7dig KPU<@L{=#I#oI4q/r 8G(6I76 C?Qӆ$BmbSob?~U›2|w-7Qcg *9܃B}RKh =w+n,OQ*C@x1m0G/G,xS`uM\^9tQxgwkwZ8V &@`Vt$ڟ% "BOJW$o}+*/%gT˪b= ةʬSX ldQ-( h +։j2lRu\RB!eAu%r&^7#Tl.oOIF#PK yKinstall/UT uYvYux PKyKǾm*install/index.htmlUT uYuYux UQ]o0 |ϯ`I ;@ -Я E+!)nGDVB4b.g}mg!Lr:ruۧGxs1E|Fظ9lv$fq,ߤ-'5ߠIJ+ָBt$ Q)q#2+INsGHtJ!25ܜ|}[ q{; Ά^߆ˠ/b̨AqsSVYkv\LZ "t$K`܇܆ %/x1#{&j<W'8&PJR ˴F;jsF'5jLL,=ƣ u)v,:[_PK yKintro/UT uYvYux PKyK1Rintro/opening.ebUT uYuYux uTM0+FPd tZԮm{27$d[8y1L16G 0-j9Fi引^aI3j7/R6p 9>5``ؘ\skJKK=*m T04JåAns7""T-ty}4M{ܛD,E-_K=HܐHDo O@.u5$]q&iC5<<"!Q͌f OQsWtMh12z'Ha/NPKyK|F (intro/schema.datUT uYuYux Zn9}HpKJ@ěxsEfyX,辰-;>G̏"e;$ju'[m\VfRg $JldiXڨL( +m!V,UaT(OZYQXe:[J8Dfe 4a~*Rf1\ }>waecL=KV*Uʛ&)M|/>_j R0IZJ~fZY@lfVyRE4` Ox-^K+tf U ET&0]!;=w*k ݘR~}u)Ph!Z0J݂nc Kj)`@kCbqxژezNe7P穘0K#3ƀyKzl靷q[ ﱍ>pzIB_mى"Z\B( M"W+e1LFvNϕ}P|h&nx`//)D2qSz-8evH`@)y@|> ز![%խMK0$aYqM%H˲Obs{:LhJl oIf^2^SW1%8&1gWM1uTjeBFn| <ț}}ss*]H9zJYD 57GfTU},6&'dvQ50zM@"fMp>&^yh0X7k?,܅ ~.#ȻL|ЕAgRdm计7tH6l< "R(Z}E1o7R?AJ#LSn&sWA.ˤd[ki!Tq(n]/&f;,[eݴJkc*x\t* &ݤ{8 =pQ阒}i{ xUȝ*Yb|e):]FIu$nԹg"tyS)lke^DPHGߛqh׊a4|HƏ JSӳ: :bM:u;ʜ0àLHfF[ c?^Bq1(8SWWVܑ V&}L?KgXj\f#38goqr2d_̐d~U= \o-H|!~ -Gtr"[2QPjWgEvOcZ:pX wl#: /:hoLW`<-mʑ_w A岈o>b}[4=$c(dԆ ;"<©0 iJ~&f,3|esW$> n|\['BcT(F[ܿT -4EՋz/pUbl`zAFrd] u,>t(w UA̹7Hh+y0h/wOw6<Żg;x G;xw-Uָ]#<-ڙd؁(&}I32l'(gestӀv_ّ,Cv' {LX}k3ξ]^|] GYG߬JK*\ezK_pgߛ9%D{:ъTOa4B5`R8L1/'{N/VDa ;n!-= /Q >R7M`W+ ߇ @5v4Wkl)8鰶/@JzGT,%܆v"Ń[1Ļh Mg8"U/Dx^imD/g~Ϭ=ԭZJ *2z(2"`NR*0KY.gɇ+//dnCe܃!J_d,\յo}PWtJK.m5{3H57Gԟ3Q;)CAG.?5p LCVMLxUmN>vSeYzlq5ɢMS'TPkT&,iec?z6v(ZBf\)Y|gd#6Z񻾺+g}kMPUP;j/!=w`6xI bD(tnK/Bvj#>PFڀOڑ1׮|?%{=sO&nILth&zMA6p]PKyKZ intro/index.htmlUT uYuYux [s6+bv8dO}i\$GX0A ֯Yvqgݳ.-h['5^׮JooNbէ˻o鯻K*/Uuuw5uq|BwAh*[UK` Zv4~iL|_Yخʘ-ǎ9^Ţjb()=*?$QJjG[VO#z?%Iwm\&5<=y#ٍlҿFxvL$fG5;cmPàfjzDњ=9<z! 9|ݖf/-h[`w)&mL"ԲVMa2900`j:gbaXn5H;䄊2xS-X~1awHZ|-w9OIY鞡- ӕ(TvA=[sSqܓњa`M0Yq]g-N (4DŽk,dJE$#_[ƙܻ]!g=.B)YA@$NX(q}:‘S95w>kQNb%?=Nq"*UDh]<[Bb*j2{F=^BVmh PK٤5-jiT2<30X( eu$qPt/=LhkacM+QzؘJaL9-}8WCA.:j?no^DiRc(Ao[*7|K "ifh,)== ٱ&ggF?;F^ V4Ã}LlDMig]cRy{#`e*oJ^x=U_PKyKb"}intro/relaties.ebUT uYuYux So0H6 mR6UQ!8)udzNvT'{ݝșVF %s,Jn7ڱixX 4/ >3-VzZ4grDEe U@2VB)#]Ӽ}DrBgtbš@6Pn(E=y=m}L[-[-J,xJ/AfXipT۰C6ҋ.-rᰳ D8}LjG#|wHѨ]~} ߥ/j2(9B<_sB_kՄr({ITpʀu54l൦9h sc`_ KpelCn>DLCё` FepxLkgYKCѕPUDcA4XŘL'OR= 4Juu ;B ʎ8.Jдr! RnmkJ-PKyK~ւintro/backups.htmlUT uYuYux U]o6}ׯHI`Xl h(FbDEٵΥ `"y9_:C;vv^e)-]mJ.zuq^'nnћ yMno+zeU<#:NhٰKˠ2~ehےgJp0<4!*ͲQ9KJ* %A*)6 WKg_9#NؽOJv^&57W+Vܼ\ߨ_"_b ^)_{~ kyvq`K li$q(B;@"SͰu8:[CgueC*$mFƈ]p1c)KږC "B{T% ͖y?e(%J=;<ഓb럩@G7C{A ]Q?ٌ@a*l0JzWqrbjt@VTCP6 ^w yjke['2J>T)#04pZe'V9۩!lbj C8Kq' 4tn* #ljUG ϶Ji'^Q߁jEzCʫv9DK)MV:4I¶VDl!þ'ȄYhZc1%.ϓ\0*a2`1P sv1cC1 bZ4a@e2foKΛSmfI!RS%2%9Mt .q505f̪r/%SPKyKSm Iintro/working.htmlUT uYuYux Yko>b%;I*kQ')&ht,4Qɡ;3|rI>H"9q}ҋRioU^̶֛뿾ξ[?}Awtv9˻pյoLZ?|p~rbK^xKZ.ᓯʛ_JjD>ۆ7l6_Ri/_tyz|#c rW|fJdCe!^ɿLsazY7|J,޾Z~fh|_L25nm :.ܪ[ҏ)Ω] Q>Nm}#'rS~XKȢ,]k ׫Ntl1;p& r%tv+ub_`DĞ u7Y{C0A]/#gMcљԪ1îl[.k*]끛7uMƫ>S1"g8D7T^f#Qā?0C<>ƬV]Y<]f0#2ȓ l? =edؚs [B9Rk+?/rS"]/p_ ե}!@ grmVH z(G܂'A,[;!*RX;Spx: P`${ƎphB]ϝM>6-?< -u)71xDG·CQ O}2Tdt8*ATA [\+Zeq1+_| (2υ<>=iڲj8;P=8? hmOT"YR '8{@~ô!>Y`Ll4gA4) KN״3*b#+[3X8tmL#3zNI'.z0BםerMSL! 0PSo%- %2ñ򅣥z4q?O?uzwpf)fB˅<>yr>qU`p92|j`^a듳1%zQ a+zAqbHZmx%ߏF2TVՅBScx7Υ$LN/z5n/.)z|4儳m>`k]Xzm7]3p%<~SAڇ_fHܜN qfܖ;)~q(tؤ箕\F4b~.`Kk[UqڕgN7XhhL(kfҨ- ޮ{nuh!LR1pOZ >weV#v/,8ږ'GSs2lUtXUxݛ Mg`J|Rc.!nPAARjh ԃqV -#M=ć3CF*0 f}![s?G0M6dÀijiaԀ91eKt8,3hdEtͽs`Q - y-yjڥcNUU{ቿ ۜ]OU# s!swqWj)MY1#G4H\E1> אBOgu=1f6=M.ǩAPt&x2* ⯖BW$[h/#z$a`0 D|2,q-Lf4uG,{p|[q zQLx8/'GC,bą4cͮƶ[]PtÓJL[ emlpGaeF6R[lZ5hl‚vwDsč"dT#e" ]S]v*HN5Ɩ6„!yr*isl`@d\#Uos"N2'ag4Rԏ&Que!TL oJ8ƅ2BtaWz*ynKF3A14qo( 'M'&|#P-o~*֢/P`iitWZW6k&eh n`ZJ=!;VED5VS+JQrD18&~<y@AIh<z^نV؆DߍPkC{uu}(Pyam,m|1P< uѵt:ҴMDz%%7{Dd>5Ax3U8թt>>H/F~[i;-i؞@=3F;}&*A f} HfGo9m]%5Lv^DyS,^foJ7uPލIB/']l_ VjPKyKkF# n intro/mutaties.ebUT uYuYux YnSLeƒDR. Im$h8Ǣ8[ؗȋ0HYEQآ9yn&n<;;'IL4dŖÔD]$CNӫs8D"$bK~" uL~E&wl 㞥XN ey4 x8/)HXp#X M;KQgG$\ rNH1 ޒ-R=1B/]~ 3 }1%J_hyIY8} L]MTek)芭 Uo4Ii\%c6dϋņ4_;2=SEid"N4]H&7_>N?IۋcxJT >'70i.g<4y!HRl91!oɚ2;HņC~J~|Gk pWbۚޜm [Xs*rx`*.LyѸܗWZ]PCSؖm̝3S-pP:{PhB&d̩ S-Ξ*ĉr_pPi-NJ=UKٶi[' mg邩 0<_7.%Ƣ$-[*JJW|(˙sN~<o?k}&5mvnޫ/lD]1ݢ,`Hdj$$KXCX yXafKgם <Ǵ}HĤ?Kh8Ѵn`2o2CSwȊlB}m"6Z4-ĝ}3:E:NOg"A\gu@Ƒ}bλdf] (R;fEOLz{(~WHtQrQə Œ=$%0h^V|[a/ jh:/(ET@H5LGw*ѳ*,H2/U}]ƬB5T'4QUgNfg/[9 0Q=X? Ұe3Dx:yZU JZbAʼne%J`[TJ=pƂaк#MCKV|?Ѷ# e$ O']7[C8Peͼ>Ӽ.ײWES_> +{v]X !nB.X|T.K}A? %E*L@R8Ta&= l2ʡ-@\[)kaO$%XO`B!J S[5ήs AJD:'MGuFf{S) g6am:fvuF^| <]0,I~\hĆ5lfX7&5&kC&$poh6nq\fh\jc+8m(P68GCfrӒ͆o1@}էM~̀C&pl־n_E0#~Chz/zo~:X>UJFxTv rstkK^46Xl0xck_"ǻt1ڥRu'oen88:-s,y QuepgRݮkP ;~V%t *`sROü(HM9z]J-B,-L5)XZWQ'J]]j #Q+r.D\690d4j;~*'fj#c2ToPY~hPSP0 SuQ ^e])DD( _rm—\/%fFp*!-xGBn+ķ0sڴZk*Ŷfu'Ri6ѽnPZ36xe "%Ȇ$ՊowE8B(wB#*A6 9dt(f4PZo[^&%:z>.CPz+l\:wc+TxORrڹgPIEkkSUu%LC#e10jUoR#׳T;\ӛ/jLR uuoCŘl!P՚%PG=|wxuu8i2R*R^i90 P\\R[a٢]aK齒yp_KN=BpI{ C#͊V>ܢH2+[\g㓟J KƃhYx,8BQVKH5Ϳtq#meDz\V`/ v,fS&7oq BFg,>wVWD9šk3q;^n{+7D"BrC8~/w<"x XNH8XR(ͬFP5`M.kֺ^ : 7mǢ83ۣvp5άV5僪e#EWEZ&9~"X] l7=hD%|W{ ]aeE!ú -V`)*'ڲU,*8!i}߃>SޤOGjKM3|UEGGJ8SKE"??7 @j` KK..E7i5ջZ+$(T?GD&QMVQ.":o:mf;dg"Yu7ΰ>JQ|MJ<Q u MqrSc>aPKyK$;b; period.htmlUT uYuYux Qo0)󰗦i:J3ICMn|zNCQ쾕0BK3 ] U-:>9y{,W7|Z__%8I/b}1.RXpT$Y}f_Vd5ސ9$Y2r{hkDǠ6]ڄJ~0p.{F -YH <>fga5Ã4xy[[4B w- $K+l56JnL`|Q )Q-W )QEA).fI7Jt>: .sUaًZtvQ] THX(JMH vwG, GE׎$:F,fYJ! y|f_^ -v#jjz'Ӏuǹq\N4aUS#}jrgB|K:w()ϋj i9%skDS07/Mi+FN_`z~* OW碿Byʱyyr05[sv`%})]TEL}o/)dyPm_/Vk,ﱟPK yKreports/UT uYvYux PKyKcGreports/result.htmlUT uYuYux Yo۶W Z@iS;=䵵h]aF[͘"5v;K~I PE4 +V\aiH0z,~ sOo_.޼$a'I~=L+Yf䦢R$oC8?ׅd0g4_2\ 6$W R11 kIzΘɼbaɤb Taٽ!N,m&Jj~Ba.<BlckjsP|xH<*Ye`,tAA[DRyTQv}`Rh6w5K8llkSk˜$TDY d 6nMP\{p 9 L0R"sX-U Jp ǠܔK5AƒFc*wp"gW )nV)n`rUi6Ֆb-H>iP!Hl%׎:3*!3J+Jvdb\:qৢe*Mg6*[v4͸2/0OR{^{ȍ, x,t YTi}91n}W]X(Brs=4oH&L6mEp^ En )F-r^+(]h6W#c$oظZ&5-7'}XۜiʅEL4&F@ɜO앪 F2f%B%@ABwV>=<Ș0P +5=kgc+%m8ĵN;>@r 3Qˀg:J]sӂH &:1\:K<=.|RKm5P@"%NbarƠ8A9DB=\K35`ଳZπmzi m&/Еm?5[zU ) QK sI>v2x( wػ[,H\sz։XB`[;& 5B¶JmنvaakmMCõY0`d  i!%)j$@uYiP974 &3!bEncop ~fȦ2Ty^}̲jXÃ=wr'ۂb kcZCC-q?̶gt9bdF%oo }&K o^4 {H3#LjH^R f6 \ڎ!`eTCz;_\ݧu1mtJivI3GtRǬ9΂kPY E7Kܵ;0K;ɡ늍hx]V \~&q'0. ԞR9{7gioeλ3֬|k0 6WM(M7H؉|tйzGͻ7{aTi{&ת?3NtvW3v7\.3$U CU(h|wb~m)-!Tǫ Yr=2$pgLq/pD90sOh'hD *QM`mQM>S̍8nq,>D 3(<4~mRYps/fOp\brD nayzeQgOTO^Ρ}RWH@e9UYt8.iLgM^Px9kn,m ȺQ;<1ne+οg>_[y(&*0D*9v/А-`'3m v2+U~vd1yӄzį(K7`pDE6fץ+oZPKyKzk|)reports/unpaid.htmlUT uYuYux XmS8_sv /!pNii GĖ|vWrl-iWϮ2~qSl-Z fB-t*UvK{{ab^}~^]=cO^OYK?G$]n0d++py$b)[itxTrg2])uTsmP(2.'gyT=/+˹+p:,^snZh.J͘'cLZxiyA+c+]8g"_1'Rd4HX † geFkʫ8sBe)JFg<[Ԉ#ц>d9]J!,8j~xI ԰e B'WnkcKJjٻ*MJ<ϛm[׃l-znn=mxYjx&k9cKbU!0g=GoژiȰ*BC~UH[g<׋տ,rnq Io.}8}4Twe;ڎs6Zn o1[cM+c+w=0_VG26V9m) w;,v#q2m 4"ã+Z/ }8{hZ_ھu{FuS_7[ũpGXՔl3iڻ^nbp[=DFozs]tonڦ/n!q|Q9qT?F &EmFxϥ%JH@$@fIdфV5 S7 3N=Fl[K\1Mkf3= U6!m F,>AKݥ y2̫ bY[iQ? ?PKyKyreports/proef.htmlUT uYuYux XYs6~ׯ@'a;LԖdk' ,`AP>~}wIIzH{~{ira|=;qJaK{ū^f2||ч" ?q'NHUSgaaF1T+A Ҋv.<ì W@a&e9@LJL62"=)wJӉ3fOO2&FcrrmơLllt(G}@mRY!$97m J|Yd+%9-MV.Y3dlo~䊀zۉ#r`TeB0ç_31c bxA)(=hKpͪ IQW -X-jIxsj.[fl! U%{ eQ8t buv: `07j.hB;*4QG)=83n%lGhs-lLeZ)wNa^¡=GIr&˳`V]ö P/*QM{X#,& wkQ0gzRRo5dn@*͵PMw ZzG̘#T)UgjPZ"E4 k'7|>6 .]Na]{8G@H ]M* ^nGZP9#(Ў ,4lkzزEڣ)c6pi;uӔ.8(^T32, #l?I|_Ռm#T&v}fMlhsCK0iU% F8n 6(f[y ;'b!ƟWh6sudכ&&kVQ k8LD>^b%y0ZwIjV^3luٽ_Ꮙv/eŦeji}d)SdUYj(j|J#KKaw=5ƃAAbeDFL M4c6GUbV,It;b)4JJąu 4s*\z ,\~e]9\^I^4[DU4]mqX|r ΅J6Mp%.cqieQlJ(ɀ#LȜiF^PJC:d#Hݜ }#=_c?Z* h.<8Kt/N0 P+[@‹Зm#(Lr!| :Zw@^G6n42]`ӏصk5춯Up~?K.ו#"=N U7kzu53=oDv'ԨySc\7E ,mcʸZ)ǰ)1x,my@P8藶) [#h]JNJV帺]'zRhn{L#UIXzFxi/ b;;itH?|rf[~-RM黰8d 63P(H˭ZϗD{Jhf߸N/NܺxHmRwon'oL%+\vyME[ꙧxJ'0EPKyKcLreports/grootboek.htmlUT uYuYux Y[s۸~ׯ@SO;#cډt6fv7H<`K@dYQYG$A; _\l6JQ2EʅNU]G$yڛiݿ>޽~yVD8mfÓ(w,*8~>+[Ӟ@xlI4r-jȯ#c`V6p/ K"6>uU̳u}7"-_ 3i;,H^*x5+~s k+Iw, Xᤉ9QuSRCRY4r*Jтld| e3hS4 CDYXȑLXmV})TɃ#o< 8[#2Y[6EpW$|:*F[L6!Sy'13mpWJb\YJ`a6'.pF]*LWJUv%!1RS (-#2eU %7ߵc*#ZȒlGֳT³N)[eV~Q&8<׋mA,riu t+ԕ?G A76[ o_ɬ (H|V]hH,з*QPtר\eWtB[);q`(9'K^˂p zhZ7jRǼzƕg$(Ul02o6Tfy,XT0 J/Q4m_*Қ |WB8Ykd87G`amlD.ڞdFX4a{#*eDy‘@׃&>˘1TG .j3{-}roTq ǟ6;<…"u[QBYuOjۥ}F`ȓjIt L=[@]}0rK델Jӱ+þP^Q?@qv`ۅT/ og^ح!KDu Y:ձ:7|iF`P@Ǻ&g pɒK{P!@J~\ b^K&7j;4$aÑݡiu|vz-BpT!tXʅK$_j  fnp +Z7`ĩv?:K1% Ioh1B;M3:@.xyYw8i V?z ?@ֽ9WO$ *K\R)%Rję,pImxFшI"2ju#$I{vv-^z@nO%ϓ{]gށ?tА?һH.1:Egogn֘g)*s/[U~`\3MUjYr@ZBn3f]!\]ׇoۼ<6^"f#GtH$}6+pz&1{8hIN@={9ӻN]Ob!&uJ픒$~wG˝ST8黋 xh%ze$=n:ۖ;#VܑaNZy{ѝTqv5m]v&7{؁me;XۓW#/ѵ;Ϙ[> }{hEO3igPKyKԎ*v 9(reports/btw.htmlUT uYuYux ZYs6~*9,ɲd#kj<֤rLj$$=uʆ* -9fzqyg=HB(P>,RyP[eLC2i%迴"RJ 5SD TQI$L*'M1Q@0+,#05+arqF̓XyxauY@N1$b,\2xl%2lVK51AfN10/k ƪ̴0 Bx m/ d[):ۗ{]TZ 3U,8Pqh*yRcZavO@]clMνpO<2\BC0Ǝӑ1QI33 ʱDǰ^kh<"fݮg#qƃaQC1Dbu*Y/bI`t TB` }ڠLز(T$+%(ՙ.l.!Zfqa$`!;=BD j Mc-qGZ6=(,ƈc{jxeO75yvFj Ib.%XhFBS$Rۥ2C)pdՒ*,ENhS8(v<7 8 v`K-V;9Y7E"-[ $^s0{v ٪yaK *pk6יl0Y[U8n9лHPWIK\x~Kީzad[FF<>5q"B5xa Ν|\XUe$eY p@<ί<ϫ`?Q*gQ3x=$ٷx)5T2?{oP{A3ުO[O\[c!*g72A؞jh)r?7J:? .)9=ݫ|meZęӷCĀlR8LJ2o^9"3QЋľc^ݾHƥ/PwzQ#=E'{QG:"Rd42Lbt z[\0-cʺpnfb70b~"C1?J~'?TS$ UʘW_5zׇ?'bXoZp598^_8] ui3ewkrIN/*P,rF$jRk,_G΃O(+@rpd۪RMjj}sqr<.UԈ+);8uW\ t  {"9!\Of%7Lq .Xp01.8h3jK |~ Np(:n~J['GO {jGviB}j/8M;=:˧=.O?0$<Ӷ`O?T~%QyOj6#`v!Eo5 \3f3qkxN3BDˍXb`V3Eٷ2(ЋǀL&cڤdrXnއ) {'3W 4oKGJ*S݋9UMjoܨdUi3\BЍ9{ύO)ԁlx ݶ0n$4WӅKYexG샲ە |62:yfJ-<@i jѢ *h崙t| nߴ? c!t˞z#)޼nw@"+~9GZ K3;Lp)6;ك"n4-\yom" Hd"RbyRfz Ko1(MLV5%D_~cيv6 }a:}>`""̵Bی*j [ʸJz(_<}>(d(?à{+I(O̴C(==Q.ogu\s+EﺲbJ!<%!up:)6;-Qoc$ gܿR|pS8 wىI#ފI ^j`<ȄΫyC1M}Rj׉O2]._/>ḷdۀG~j +7UIdj MRvB `i)Ҫ%xW& ȿHRI*[\G٘9 ^N 8>O]O|$(QaJy&Im [n,[ELIO7e:eeD*uu(<* {[4@V{D!A&unn9G¨),UȚZ.ۭHOJ/>ո%Q$C7Gbn`ix+'w}C+h CԟWD:MC`7%dgٚؒ Z;Y&he ( 6` 85Дw7g%#y~Ç\.$q;՝'~Rf&WjֲqM1u^YEݬ|ۘ8t $A(xC5*`XP ̘3A=U@MX"xT]}jm?k}'|qg6*KR^Ӻª^0y4R #.E_V,.]J*a fgO" ˺">bFa E٪B)ʽi3SFz\qw,&4kAn߿PKyK׌;reports/open.htmlUT uYuYux ]SKo0 Wp*b5M:l@mnJjɓɯeR"C4M8?nqTGX\Yf~?[z/o HʟgR^!?"( 1R ik  2d,dkکtkDP\OEUQ1:48O"AoKV0g%GwK@r;tȓRvp::G#@˙ J WPap?zG`:fJ{ ;',d`7(kXz<=wU6%ECJ4(U!o GHlÜW1oFøMZGj7P쥡"RHW/O zq Z^,*B6}yUM\lԺB qxD0*%:AATrm0+0g RK^fip9 PKyKzWreports/crediteuren.htmlUT uYuYux Xs6 So;i]w^6{}-f,Hm+/ j$kȬ2,=7ҋPY=:zvMw7\/o\痯.Dڿ7S7Ljrqm.'/AF+N&%JJd}.\(ܞ^nmBB>p:EH7>LIs,|;eMH-E6Yb~q4<]x9LA\d!<=3BF0#2N'SA#߫҉Cf1jH VDθ`# VV-0dI+j4IB)u+T"~Q}9u=p2]<"dܗ6&h45)܃V$nA[ :{r|d#KEcd($ڇ mIYߌB BQp'e-BFxIȊ %4Zy Kb4%R\5ϲ CP= eZ9aeR Tߠ];wi.ϕ[T:ImI5bu>18tb&LuPzXjKT}mhom3tvqzm(ܑ5CݡVxN}Ax>!ҲO/>u y2.#,XP4P/XwZ/v]Eq$o̗LQfE4.A+U;SG1>ޖaMܜ-TE%EWi1sXp.DVͱ9x X[X.uPґ⣍Łϑgp6D3M.z\ݑgvQ9UILp4yQ(\yl^66n Y&fɆd&oodMyNۻ3yHm(iL=؝2;ݕ*~ \W͂RèxuVv"FT=Iee`6.ڊ=&HjǸ2>b.*0'*t}T3P9I|l`/I}Y{7h4v$D`?ĈfV=*ۏK9`)X.jIebXvb|"XWA{۠SmLKظ5F7Qgl o_q?2wH;Xo+cLɰo2jݛd-o yb+aࠜ 痗[|`;ã&žm~:]]Mx=GLJJo8ѯ_ll2M[i\jKSnyh?xag lв "I"^zk+4$OFsaܤJp>Θ7F=+UUGQ`ꯣ,FbL|L3`G;v^Zv_uQi,^4KO6b/cb M7Tk>VlI|1h#o+_Xд&Wꃊ-r t4-mrUىs q @>qќsvD|b"jTZ֧mPKyK_breports/journaal.htmlUT uYuYux Xs6N=IGN2"[nֹ{o` BrvD#r< b߿}?X.N~܋3"=T;GG;qkogx..?\^?Q۝\O܋Wq/,*e̺FHy6ndbd`<_ZT_26 ("W&K 'ϖ^DĺxT'_4L軟P_D="AbcmӺ,>;k/_RfJ^jXB!ֲ@ |oDjnޫ"̤PEN㪔y-ueG02q %SBJd(ZSHLY4h\AHQx 3/cqLՍXʢJ.0T[uS@1 $ڢv,M,Th W:ЪD,uKt: u򳪂蓮-Zi3dUDHbfKiޭT ڨC\< ₕ 0DMCGV%vwA2q%mTbuYM#Rq`ޝBq f}e01[;ҘR&O!UE DU>ʱXkmMYXLoD!N cvUURܘeLrU!1 S,vjzP=!->ℐ3D nF6@ Y ~ϥ\ژ-M͘] Bm#{SS-|tŜi\K\by+[ \e 񊊯58]R4"ьj^S[A@ZQÇ} 1i drw}F" g+WX/4 ʮXfI sU-,_&!,@roV#a=xPԥPۍj*o`w'ڨ[lW-(Ȑz P,\Ì՛0cAE)q?U 35W3îfz-r㽴hx_$۾ # !a!O\5du8U7).i3*ɜ Ǵ:Q 0 _Ư䭜6qmX 4 L x#k1xtv>T=[Qzrq8SAf߲J}XW stxPd(!rrmz]8aOy~ivpmLHD"4֋\*H!N# Ğ˃0a9v@,;ܴ~ķ*KfX;*_vSPuf>XvLxz_gxI竃)cux`xQ&x*NQB'rQsWǍD.iؚw{KFfjM4{-wSPb'l7wA:)w(zDn[{2_?qYv~nQ3rk;b}P\bY~f KZѩy.;ܡBvQl8ϖNO-AQ]zZN wG=Vʛwi) TklEP#> :9|a|{wّ@fqcu7 wfilvehg7}Yۿc1u kWQ GKݐe u26|Ƶ_gNtc`ns>aۘ"8I0"cބ1М 'uDx |9ZƱ"?MuSpn&4Q pHv}mb>PKyKthreports/debiteuren.htmlUT uYuYux Xo6S`+bN6qchv ڴ.6cDy;eqv%Xw{oi"[eQ؏z=1ӣPY;F˿/ĻˏŗODv=vO/OWQ/.srU&ٟ!4b8: f"(.;ppuFQwbmBpwn}uƧx:1ɏQZ= kh<-d~?Ux3:q cUh<Јe ѩr d!DM+Rpb .9Mg\rR88~0WHkax 7:@$ 52dbqĐ"8 !DﴓVlj-1IG!F.d>2SXH`~nm8yq1"G0Bqb7ç^PL I2h# VVM1`x4$N'\*_qS1zr(pK#p4ctؕ#0].eE Ԁ%\ kA[/gqdhSuDi,0KS? R"4Y@?]BS*(%nkW)r"l8Gl1Gjȧ0 5wʴC_Sp^+l]^(0"tBMa 80|`p,h+y0AŒ"_2)G lLEde,ƕ~V# kAۯO[۬3|C se_nM:GρÈ)o{-m)KK&vQ΋rKҞ>߫kܥ̊huA+6gwڧb|&}ƽ' 9w[LJӎb˥B]@ &JM9xKX[Z)MPױ⭍jp6~-g*]DX]v6s`̱Lh/-SPQ9ظuhhŰ=d^[&oodMIAۻ3yHm(iL=2;ܔ*~ | d-Q: D!zxp9USAl\ȵ5{Lv܎q 6dE)nløVsP]R@&AjJ*ce$&cUinuo_cjSb_wz}Ng!ԈK Q=)ڏvsPB|dڒ;*nc6'_wW7K ~i h7دawŤG .[[E˲yr /Amŀl)$~z|Y=Ų䅦 )o  Z$&K+ic؇KWUͫTy]`O;cM2NUQ׍T~,.;PKyK>ZP[ }reports/balans.htmlUT uYuYux YYsF~篘ejURoY,QLJ|T86$Z_gQ}تA軿 bAit|wzMAD*6UGGo揣_.nJrZ|h?/˛K7닛Tƙ2*n}g& G 1 +FFîPsRxCHٌ4,fӝdYT0 6 }1Moh>MlgmbyXH}qûijĹ /| XdFJ#2czT,[":JidJs#)fd8 5L;nRcNDP2vy\& aG\*n&;VOXrbBuĹK,ta.P %wXc08w4ʣ$du2CS F*k 9H9f{'.hz?XƓhC1s!6m21+OY$kgD%xq ]VsR T4"2( {7.*[(,{KluE\A-.>}0 "DRg`U. .8|ɫ˶$83 "@ 쐜 &NRw[bh DH2#(j2sq4N ;)-DAIJ\c KrTQ^yT R < 9ESO[^HR}GL2! z.)ўl)}`ʭĸ_p!ӑdN])ijm C0"ipXqmGi^;-[=NO,HZ* F+_T POO촉GMSU'>V;>$u 95ˏr*03zn a"W\` )HMQN`4daFvZV@<*$A#jq`XJe] " C,n[,(\HI&& HYŴE8 :=pIZ"-•v$Ȫ+љIO*ξ!A\"Khnդa6xH|_j*( XhżO*7XQrPckU{vhSXU,j + 'W|ޑc`R\8%-CC缶LS|n1w3.A²zsz;rd۲):vBsbEڙm~wǖSප-ʦz*\dѨ:V w[1~ ݽ$?5>Xn$v7h~v%gKWm跴d}ɟN^w9ŏ iTTߖE†LM_j>rEۃjEhGFvZVﰸ-N|W#FϺߴ@ٛ7gg>HK08Zk _uRo-pw k[5(NR5ZlN;Sx}LSEmo@iuu)W`F6ԇ]w,=α)-$ZKg0Zԉ :E(|Zsmbr+Mr Wa:@U&ê)YgUD9 G_}yXbб+}]v<PK yK scrshots/UT vYvYux PKyKȸscrshots/Balans.pngUT uYuYux TY׶(Iwk=Cܓ`wwt?q1NȦvU9ykU03g0 񽈠 v 71O6垀\m)Z:h[ -,imt-l,m`/a9m88\6읢ɼEy7(^bYZ4Yߠ}ɘGW;_J$z j eWI38X=Gc_qدg<#zDtOD/ȋbvJpKBy ٟ.|"hjZ΀^'hn$j áyRN$5qk/ c|nV.e}9>n?Jzڒ#ǡrLM"dD`zH}~I7@YYI,p9Dy3zSf :,I#+3Z+(QSU͸"c#DZZ[ZY:J{EGmޣ!O92 w)'^2ud rDvTEqy4E.NvډB=•vZ=a}_"Rq7ɿ:87zꍁY6H b@|ٔ Z@yứg6tۯ~t f5,:Y$0'yu@oeLJ(酵#6 (Yr.#yU&{w͎o/J=jkkX6yɟ>1y^+5㼞WbY߸2E-#P玤[[!%Do 6NyME };~ZVp.Sƌ;zl9 5 P, :G8Q?jP,.t.?m.?J|{ص#F͆sm;*f bV/{.ݢM 0[{_ݽg'8950Z^1垘b G0h  lO; ,0?=]/;(ycmT-sE! !ϝGw77e|w^DF֢+wK"ZN 1s~^>${1YCa% )k+_ercֳIY`j-FL*JMfS6h:Vr`8J*<5~/)׹re0|fݡKC?*7֒RI޶zUp,cVp v,F⭊qgq]xpj!*mMD,guks~*E|wg3yoČYrn9Ѥs#>j 2Bd$yK{ޮJ/nT4aQ ]h`!D'Ϟ>=N5bPyw0A䛎 %m1YKW\H )aº4.C5#jA7[mGB.ZF 5dW1_%fEhȠG)&=Sw k^R )`q4O'9^໤#$^(w2/]<_.Q#ܐ vz8]%Xւ@| Q: [QUҐ {Ttu%(Hշ[|cX[(R1 &j?yyqc8v},2I%n QlD׷@āCc/Ϻ޶[iJKb8kj\X26*6-1yzHrSo7ټ ɧ ;QC?6x>Hq%S\mI|'xϑ2VNJUUgT2&N̟ܤb; tҨj7ٟvc@"xuuۄkhU4 sSQFˮ\3P)sf\=ȭēNTX0BqfTuԋǞIq*qݑ'94+sD̤/,PȎ-*F+lpVGZNt'-XX\zKA%1='%nF-^Ȝ9)2|# 6󋫥Ղv@2UN 17y ӓ,d>B(|||E}||ݿF|L~LiL8[أ(H]ue|ww/mxXg/1bdPє,9O,¶me3tJ#ջ>S.Cp ՗$йtD^JUβ'O:̉g}dU̹}OQ71>k'O ?5ܹҋ:y LnL%-nOw> XP\)Vz;jTZ㰧YwGOcuq'Bd*<#,L*6k`k~ 'k+lqUy[{LJnboCEĤVRlD$y%Vi+ g+iOp^-͉i}x.X>IQ2UGVsHٴ0 x׌=H]9HaY)F%%%^o)VA#GiY}1Pp߼|I>swܷ@<%!|~tѩ[P̍ []ͬ #嵎.r>zx!w z/SW?hs]2ܲ7|^l7I[AHL94&⣽G%؉t2~Đ?V`̌CLL\a>?/#B6MB5WZ OE..Ƒf&P/n#FBAxnMdo)=VYY¹6kQ~1f|w +|KKX¡%'aeG{sBͱM%aWB w'p~%Rijs0lik;9;:U\XXuXצEj.ҹo2)王>PU689~>38V~-\j\ab\KI@!@-[KAϘ&*Fp?;+7nLLe"<>X/X555hX^#9b}rjKDgFݭ`Cل>ʺw̚DID$oJ1CB8__6yCSU3)ɢA&+U)OΧwo$$V4=V<_~U ͫq%"NΔalBc~Włteׄ@i]WLb-ꢧ,ڨ[} EcY/~D6W_O?s{ *4_/ET(USoG7ɼ ǣ64IYph?c.tTzts\eq!/[s:n&a]-!S__8mSP^y6HuIK\yDz]pmz3$"" a Oo#Wvh߷?Ez:1$((|e(]b8%SQT";ŏ_8wlvg^v+(}k4w Bͩ>}咦ʇ9 d퉵>.|0oǟ.yw΍f, ~&KҦNw*hT`e!F,5_JKOOu;1l׷luTWoQHηae |%N䯷~F.-rKuOHן`bs {v4 oecX##>eY1WmhVwyi;2Qf&{pxHk0|$xm$٨ؕm]Xq>4⸿Ƀqiv}#ŪkMM!&O<:ᰬTD\spj^}yÜKh~wBω;ѯEJvr7%T_NYz"[]BkYsawyʲ^-Olڦp%$s&_UZǐj,AAb0Zncy]*a9ڰmawwKHp: _|ޢ69Kt;@.ߛ1=vx%&m>a%{[}̭Xڞ,&NԥrMe6cH2CG! qz!ap W۳,` j5W{Vt_n{^`^cys ;{ H ]懱lZ==:R<]9m/%H} >xI0ݺK8gpp&ݘ :a}-wWqi ٹ)h jBׄow:8\v-wkKe}wr\i}ۡ0F+'R{;=SbWb/(h0&KuqG 8S窖q ;Q^\u5|~n9[@TSYm^)˗ qI=t Z~kLVyD1"8?9қ-.7=ȝm)b]K1r!rU_j6igj([P(9ƫ4nl[mO!ܜEDm6vkb~p/ii#JJyxDĹśjrCfRS ogkcܜ S.XxN _ nC.Cs \^Ӝ,gt߈q󸃿TsjdN!o&4 _9>D716Qʢ),)sq kf-1Wg?Ԧ?^[B%o)gP1@FhC"ozS$<Ʋ;W.٭JȄ,P[92\uӫa9| se,X`d{̛ǵ5Z50 gHW[\Nc &)y!./4ҡјt gLa;@Ydc {o~*&.=pIa8hw+Z̚r s@#FDLt5.Hegbک5;%cN{7%F( l2&- cؿIs /6'$qzn/{qHSGggTQ8c0Aax9{[ޓԛ:+zI""ŵPB{~2[ W 55z!7]_qӍ`ˉtݧgG}O!5 iҮo=ng3gXȟx./05SCeʧ;^3Ϳ!H{cõDmukUAO,* Rv/p>6(loMOa"YXZ TT.v"ļ*TMHb- ?o+yX1r 'w=ʝ-oq@_@wtu&+^ee7P{tiO;9 ^m) 䲕㽉b'n,焄}#ε 7 Ǐ2y5qp{nOV * Q|.%"<35#f aC}6lS'NGsU{峬?"sUtbƫ똢uQ/6x!NWd qS(R7x_aoOom>bO| ~R>zC /t z)"*^P8ժm+BCrcISv[+݅ ˣ[ZN18ѯ+*[,ɹָOZ:PHHHkMygg4t&K~Ҩ-2Վ :y%5X];k%oR8:;9Tmg2^bÇ7'c%{׺VQA3ȹb >h4:n;1VB‰)s>>Me?PP5b$C-0CxkSI+&X-'zoϸw54(}U#PZ?gգ؉6c%:n5\΁ja(޾}=q>n*[rUZO0=uΞ))*ߑ=zzI#&&*%1s; *;.=3>Fh^cRM6Too_p%}ОOdJ 55ᥟ,&ZxZ[B&ĸB(8q{|wTViPiJî^ݠ{4Dn$~~z,JM{} <`R ðh(6r)݅ k~ p- %bVn'H4ԑS| lڑ,]1'WVqff#[ 3xw4d&VQJS N=5K4W[ڢB"j2PWoQU_s3#ًVMmƙ0W\vWy7?Axjffcxx|Rcrk!*( ُ[xD"%,Sli_.9U+Ra<`j,QՕ'-9ICBS>NO>. E1N&򪸌1Š{QQbZO` qkajm9yݯ^XXv{cmc3aX7uJv (@. QUG{ѱu9Y 7NOnEGG]u" lAʀ1V1'Ѝ |C2)t;2ur3R#>HյMgD^xh7p 9.|b%)~5`.ng:i_YWT{WWQYr)5;ա*wX|pr+ e1*9R*”|+G>{u?W#T6s3|p>B$Օ6̥qrGO|GI{kL=H3w}s@@Pqvg:;d ذ.DƯ\?s2bw!64{HZ$J68/Zdߏ3-s^S^*IC m̋ F-]Ff[E)q[zG}s9l) fBﴵ1Gu'{EٱsI]]Ǐ;P$/4[3yGG o|XHn̓îbۇ|";2# JTuJY+{e hg-R6)Ű׾P2bT&kײ4ue\:;°`} z/;%$CVDkj yD&jls0 TRcyggcKKKJnޅesK,&h@cN,"JM1o.O0%} !N;)s$"~~IIIB^l/Dg+ [jJ&[+sؐQ+Wh;͑qd;m˧9 I{{VFFFp3@+5F&0\U丆>3"/d1'cSm;ņ}E}e3sw GkUƕeCi^*Q\_%ܽu>`6U|sufsyllQs[nxrsUT'''pDE<}MSֺ՜; k/|d6kf8]8_\Tu4-;_'ΰ'8JK̒^\\4[}/i^YZCއ\^M[9E>(`X>3U蟄 84=nΎ oyM'c/ lzW4݉HI[Za;=!\?, ![~-ٞYnKKKp hLU-S+R|>8Ď߄ϗäٙcRS85v9.jpjLX8l=nnooӄ|5#$¤b \^yӕ:ْ#_d?o>`+=] DKvW z*/w|pt4GJJH1q9-p4GyDa MW$-}(i=#E `/y1q1]ZCCC>K?DƐֱ3\B8Tr f)h4K IY[3^Rs9.a̱% Q@xLQ]]r5iiit l|aD7 x[_kadmHx +v-sAqA>\@H&L.}~8qpB^yP[EayظLzߓ Spܧ'GtT;X L*!Jl-,,4y샲diL)+HiZztjq%}h958Q[c;SdaǥI_bIU6.U.C$#-tמf[T af:WexߗL݄+@7È5bl^NV=hŎu^aŚx4SE٬K(Ttty>ޮ닣f""@@<% nG%/~ڰwZyj\}:qGG+r`Gi)0B)ߴ}ݯn/<"ONOlϭBxDnov:6&,Ϗ6 wwwGfŬ#$f8P꾝v"_͛OA]\b`xOF5'",L&ReD3KJS6S̗N=&B؇0RBC{b{mİnwނQv*mpXRrݪ.p4g { ϮD>3 *bwEdrea! f7y}}-:I$q|0o/>*=>^/gS5W[GWW1b`p0ۛ+۽ GhF.`; ^GWw21cGﮮ(:fr +aor}%?>y=976mmKYK:PƮ"!}Jk<T'Kڠq6ې#ɃO?=Msd6o`Y/Y6/jEq: W^1c7٥|j{E>AJX씔9*DDD8v@8quNw۬Ko[I1hU~m`aA}B)Pgq@-3@n647{e,`@٬Y1W坭-3g|䡍:7.P/dm9e^(M/RX)Uq 7^lJ":IJ5G/*\QIA0\Bc }oPT޸r!-Kf*^R趇vuO>)?kBB/֪u/4O8dJ{To<9`vF iEoHe~_RP< jO"9 QZWO:h@`Z*Ua:sH"FGLJ\]ZGne}16s|I*4bɔ%/jb.F_,fH-5R*^_)mpuz pJ`hb-2xm?Y&&e1y[s<<31A[u\TQvA3;p]}J'@8àQҺ.({Dx2z/hl*TAq2T+++P.UXwe'*v5UrЂ*7o~6w1 T *u޽@B6MBaBQC8z?Qj 0oG}|;|r,wt͏K42x.Õ3e1hdd_3"''l}H?`sg0E>WT\\\JBF|g9Te?|^*TֈЕZ 11YYH ...GRB r'--¤x3|2 tid ExT=VePPasze V UmѱX- |(_wiyV\܆q"AQ(EZ9wTnmuJR!0Ϟ1{D‚I2.l)fK0N&| ʺ6666 WV3r$j]x/ØiMJ4mP^xQvGk*#R=_T\P@yKRLj#ΈX2EQɶh1mr檶t)aCW}}VG[7&nI4$nbtbp?B: s2H5W7h&}Qo ;Gx<@ ĕA=Cқo|9*˗9*+VHw}Iq؛ѨxdZu ,^͑llVY~!!BC#.L\Ug 1䜔CFFp=xG8EYqqiq%(YA$x˝X?qv a&@LB\5\,H=RWeArVN)k@: _F.tĄp|O6G I*(5on%~EqO5Ja[%}ii]AL8CCvi 6B6g C7A<|Q~yA Gd76h#4dGPy>K2 y#5JNI0Y`!AwRzϮ)GbΗA,g#<{5RbbKjU%aUDfsKk bIjJ䟪QY _cj|NYscy^0p~y{#jgU}eK!،&xȫXo.lS ͎v .[$ O/oSgAe<Ǥo˱Y3}DU}<KYah`_\\|\?(@YLjp~q1PB&!S6=H 8|8>>>p0P]-iio/EPjK,s㋺Q5Jt6®(zE@Mռ}})-uVE0; .ON{{ meݦ=މȂ(gOP@=&ʾF1\u$\X}~< u4p2^f']_d‹Zh677[h)'Eeii(c7@Wmy;*!a> !ec[IV|Њ?ʦ߉AdT X9'd'2i7=*NT pv\ ~!WTƠXyem |7v;#֭[ԕ4yqCRu#DbBxD7J(hfu B..spnW%Mln*_V]XƮN*ʣ g&䫛D3AmPSv[*@~r`=0~:e)>t@ !d7Ad,&K:F߃pjtLF)XXv+J^.`*V=T>*RԨ`̤U2Ӯ[Noȸjolf5 j1b,1* B5L6vؙ|27`d+Ƣv}ar^ۋ(́CS4]G=y6jj2 (jH߫ A!Oa12YTbkiI<=|bbrPg FO8EGsPg7{L(Hˍx C_#V^dw]/XH4㹝O'f&=l7IBci: è#+~E֭\<RXƒ{=O"{f&~!$A| 3՚VǶyЊRC?,M٦LHӘLqX2*9<'~_G$"3E^wfL1uy^G!upҌ&cPƟ| e m9&8;_FXjq/H#p(6 hGOqrDyr:zoooX$S4㰁A7pxbGFy~^'śI̲u?_9>۞qQ=VOIBl}Q7]{C@kbOO&KNsc ︌Li%9qY |gvɋN3ySkW7uε{ }|**noo:}zzrˆWL'53 ]? u5+#K~I|$61!ARCe/%T"-ж3v9esֆo&*s/' FɔJHH@# sqb^UT^FRZ_?UßڀUSn7˓ZhF]"%:*?$.*,L^"S#X=aDy-NΎݻwk} F#oJ2,s===A$k%Il%7.,,<U(me+v9 >{pOk:kEzw:|zLh@|8<, ا02Rhhʞ <Deh ' @2t59xa]'#z[ 󤯿k6^p⣵Lgc~~~6ZgO~2ĜW#x)VPkEn^˵1_E x(z PRɉwa!#llCȈؗ/7=Xv F?c &jwuwM->3 Yp'dޜLfxVv4J{wK2F.{x8fĥ_hh:@,dgdB^q ѓ߿㨵I!7UVj>ZIu>@Ĕ vFUo)2QIIC<q 2qdBI22x/IOQPdno(99U2[.&O've7N{lf\yz}FFF{{ Ki([tstt~4}`&þT.7L6NOjrjRPzI==!@^;4i'C+]Q57pKonTTW_))$7t~ue=,7KLWW4yAIIϷZpvvO4g3t];غv[_U7`-YW:JXe`bjϥ⨬MZ$%Y0ڮLx'B{DÍ ?uVM4%$Gh{,ŠFt!Nj6ķOwgP'!KtlPGLB7U\) FOjB;`444>%&" h?kՁI۳gofYEAV I2(Z' c5F h-ᷰ;qHb1<67ADF!ۃ)< Uq< u{8}0rm[1sT.UjwCBŅ 2czԲ|M>؝Cȓn/ņK=޿uu<ۣ՝ 9A„+=|۳;D^=YbSnijRv W;\ͦTlxy*ELA!Tc5pR*ӝ1-'7 gG=̀\9.]S7v}(yzzfU\5Pd"CX+>&Gll3EPa AE \_Ha``hXZXKzV=nJ<'/ Lurg~?U#E6]<.X\D=.ŏ?F 44nO=.MNG'}G~u9TVJ%F$/ ɡ={ J@882; #s w8ٔ_X 41ʢy oxnrRRz<j+Xi%%?`@mǥkZ21@Td idAzp?b1>"`9L=if;u`&~VĞ~~dqrΜ~!EϿ(j J7aad%MbPhLž6> %e\Ryyiӕ߿znAe]p<.2D5444P\_*%bvuvwFDD f  kjn W|q/7E53^D=rR:jbڝۛ=:>8t0Ꮽ Ȫ@ҵxPf0|ܺUViFHR0'T/^_\$V.кWwsJZ?bRƑ19%[XrQqsᲚqw獋k.4.o nN:Ol"׆&#TBBYAocOӐ9{wG _aئ!|uBu5+(.n(j>SB֙/c[$X ?^3.>/77W l-| ZRG.0X%%Wb3UPׯ_fAIvCfUD#@]TwA?IteQ$+4E k+=s!^^xxa0hN'pZSԗr)ihcqR?>jyj; i(8/gVk0<]N3Ώ%㛺_C W$*d[dX! &K B(F]]xMz3|ߨ(LPYCiչe=չbʵWRl1St ]٤/\:Y,.bJkJY e_'KF Lagi\AvBMZ ۚ{ʜS=a02`C \k'Jw:F4;[/~00 a 8aϹ5@ϛ2±ݙy,FuW>.>^ozZ\X3龑ZMJ[P=++9 |RooyߌZT^zxx>HQ|"?UĨ0':̔(l` |twg2zDLHC5kzoTkTȩ' @÷?v _M ҺMjTG~imG\gzr.Mvkl ~($355v@;vIrDG& d6k; iO|OeeeA_=t@*SaiQR&g~7@mQ. U [ [339i~{٬K~"L({~^ }l8]վP`iPϢFk(h8UX-=, B\W/t$ /M;}"ihks@ق#!{kw`ppʋ_lw&mz[1`_wlk,L5gmpՍ*@ws2a܂#]nLʟ.qO[ScWj* t:Q=ٜ5tW8¡rcvnȪ)},WvM3;;;?ggg_ߙ3 C^@w1XLW`#1*$ 09 駯X2sm~ ode=aeb "1Jadz=јn n΋@\n.~bΠ6Tֿ6],ӊ&N)S7hK{Hdp9fab672g`Ԟ566V7(\&Q^=56-dVP0L2'VYq|NۗDYYY#Ϳ/+,"GQ{"n('#Nby'>XVFQA(uu@|Ii;;4v6AȪVVy! 5)g0ɥ̒3pkj@1l+6iU} 0#L9‚ AM\6?QeO]$(jɅux.' o?N"guwPadOjlns 2Hm;SЄ4Z7hDwjjxdv{ܛ~<Jk׊B 0RIUUU~?~`Y=nڐ*Se&Vpիl:x/Ͼ&Z],nG`5<-(+{ vDVy=C]\\B?-EAAY~ჲ?C$PT a%?-~(Z=؞x+?``e~ĽryKQ^≶:Ԡj>+s%T$SqHZZs'uKzz|pǀz\ P&'%t>ݦON&JN_i3J@B$b?NslTc ehlN8c8 4<>w<79JE,4"нuTlffo3 d" nne;HsSv=Cmc޷1'7h))4A6^@~} |TPVVjwv6 1 Hh[HD p ;;VVV@@=nb?qFq ~$Kgtz1wQ陝%@BB֫*.)i)n.0KɉvT0twz#4}bKPE000`v ݜNYڡ%jjiy8@rao=hm)0WmqۘS܁ 4{c/선! Wɯ H*@T ^rDžA IQcِ{{{A{q6H oƐICZ@ί˘v jOpO^ϧgf}#4"b@!A m|A( y>7d T^FF9W>;82P`(dN#pj\!80P3@߽mrp5 S98Gw2ڿ&|E**+{{ x?Bޫ [  8ˇmpH,cQ7 5q|0+pUBQKՕ{a!#88jۣ>>Yh*bpʲ^B֐ޫII;])pSeXXHLz2| E $N c`[N̍+h]W6 Lz^ŖCe)@ZLh%D$GVߌw%m_Tdҕȯ χWTʕuGW'7 K}U((4AOq"B;2L6c =#aЂI`BZ!]=Ǟ9sCeS _9C/l׼cziFW&|%IG)1sN4NL6]һG[K@'qNtuԹNW~@'uڠh1z{]wvޙAL.O5'7ȕwCÛm.zz˱*;SUUČKbVvvB%uPPXjMb~2p1оm-s]b9y&'U؛JhJG2VW(5z]iB˙o߾)OL mVw[%%>|M6 gBӣ h[_6)=e7sz7+2O(͗GzncлlxZGpa7T44a5jE3Nfo(߭(z::UiF(LNԻ@;155.0HfLdFַГŲ&ܸjORD%0x# =pppAArPGQ#'%%O|jurC#O5Y@ L a!zL`@WW7""O"^DD̙@LNNf㍡BkkWEVPJ*h:Z#a`(ht?&:i@ńcS ۬v7bj~L=Z=]YYU4ɓ'o}-g ,abЈ(sYݐ1@ *"X4Ef}sgRAMO (E$d t)Bͨd5;l L ^9nrzJAD,h.B"`fvtdz:xg??QQQ Yio_5 Q`U:񧠀th).%Q&⣤̜u>&!a5ú1OSwH[ZsJ}qZUJ'Pc{]'_> ȨK݁&54\sanf>vs?\~U>gPZ=橛Ս*CȦu]\-/.cMFP+GD1rS>*=hrj%J L^N1,rTToݎQ@*BjZFC|*h`Yʏi5Givx}SSxM9NC7- &{x`wu#u~u< "CGАl>Wך <.r Pdeg/-8:2T {12ANҒgM wU]4G9dr+˰//!!`:+@2W2-6EF(ZWButjEf];р)JˁVEnM4Lr)}3]||FU%Cf8_EjT٩eS'|<4Qlh4UF o7 RxPl ϖc3V?yߌ, 땀íhطRFlQQ6[ V{CTԂݶ~VVKPS=5@ 'N) Dw&'FFС@ kXm^K|T;⢢gS9[u˓*;ӽ9J@̨ Lb\lOAGp|6d5O3FCKnȫAJIo@-chnj֋OtW>.^}* .aWm-eI_C622=![T_po K*(`ϔ{,9;;KޙL~^" ,,/{AxI)~7g*] ݊#iK ;?ح%$"]܀ \VtwD6d]ת gA(MwhX&z`Qlc؂Y%mVvbITXߧ7Lut@ڀ|dddM_cGyxhV ]G\[YRӈM |{wUd㒧V 80n`tk6OgD$$ށAEM}ql<JyV9b:Hh]IG0pVOB{pp1Z4m2|њng8xIƗt)b9v_0Xl67xq(M7awzZP bTΔ]A9z܎g Ixaw''[\U>f ׇCֆX7@$`|A: iADA5҅A\OV_/tr%cmmm~0i_R2]#]Z>,U֐>i[@.((<F hEY"\?1q Nk lzFF"֕5h߄fyz>x'$DY2nSggW @QPѥZ[n>Q.3x>AOrhi7$~{-K"##vgdW4SG¦mNŞ0N-S z>VH~[)0+2ObSZ(J9 H~vG >_^6{Cf;9==&lH bf4S0{tt Lt8(~XUج!%ԬwxO ieB^<|.0U{3 ^(0{X:^݃LzF\U|$atNyϡ|MIQ չZBnPp|\U6hE@&Sno+q ,#go߾HH9AEpC>ְO߾bBxebۖ']YT QXVJ5hIJJRac`7ݟ~ f=[ [)&4(, X jKzZ`9ǻGK%{ͺ C඗o#r>/ "Z\In>:$!>9JrU6 F" iccRS HHB}_j]|yxkȧ.& Ǐ{DIJmGG1@@ "߼)(gC& ))| P6a3J0 95)f?ٿfw" T(,h.)HU%ee,jN(_|(z3a<|%1d Ԩf^ˏ!IFNMz_ESݯ+dZm!C@)fy,f@GapnE^ED<L _)f`YFU-[[[΍:O@[@DBk#U9+.(npG . o {Ckk~ KI e}l-]5~) ]ot3jW9('$?Fq/?->Շ|h=F=~Ϲi녋r7<*JN'P'r 4X輠PL/|?*N2S)wM9+lx@0fDІ7qlė5)Ki<5UU<.`cc/ooe PRC!:?|_95tg˜I.a:ֶ;. ""iG ** [ LKTu)jGk}\\\ lG}{zk߿E 9OBC3k{b{𷋋^2,k䒯RQRhK0:{!俟pPׯ7u3 ?:Jw_ggpH^~}ߌBԭd]N]s-aO:rz$6]ME†Ģ Vc`2 N(8*f zgj'`nwQuf-ĺ%ǕO`ްo+S^@H #$ϒIK&2GWIseWu&s POӿ{A:ƿ]%oFzz R=piZ*4i^u׺8Ig}* ;'b59Ty/OweJLFD3!]?71d5ˁnzze(fȌ]? 5fQpd=XЮ/www aZTI!@2W$%Jvu LK(MMM։  OcY *|D jnqɳg@Օtf]WzzJQ a#aZ$LGJ 1SQo(g?D JA%gUn,ZG=<"bBD,+ڋ5}%JѣZ;PږȘ;Ѿw4#F$mٜGbPP0VYmê~奘D*rTj*YO*Ѥ1AE!XNYe3)]Z֕q4Jo@yM$C,D #b*{UY럟`}*Sx[\-]UAp ^ j=vn gvg&]2~6Sa% &'-M˘3*XM AYQSK[[f[[I&&ɖYĠ9rO w"C/@9""'tHqw{ }DK3@w(hig"""lJi4(=6S'@Y !+Ǥ6dyyPX"2r"DdrrrXB/Ns*?U˗0pc@(0kC:ȤDaP*=zbXU2a4s=hӪ~qt &(baPOY`R o Ƞ.gifJJJoh,# nP01ᾉs3}tT]4y~{ 0SsrPSRfJ" nG= EDlz*5$4PW9T`oK,gg4gc;88'|<@@u633yCBo.3!{ m+U|\QIwn21Ǭ&\ >y (wil 6 ז$>ݰO  'h#ׯQ!3kI86彄:K3,eTw7<ǚ(L@m*ޙ{jډ ;[`κ^1eee=‚z^JGBSs%~ۭ TTC}|̨} Ýg), ȉx]{B\L0)^2sP *l7^g m|: U`f{5ЋW1s9/o.]\LbJ&~#9ck&h --QK,JuX:.)aE$l /`S_A \轣X,!ٜToFDM3 \rZjjDç/,.~ѭ. "a?Q4$b;Z"8]ARG  wf?̈́%r>>>~>|`l'`d0dvLm 6=^YYQ&51lmP|~m g ){% A  8aIұb ='PZiNd֧V|\p1z}!N0Xa=iQHFcF>^Vj.gB_)&"DVVF2V c!RNAa! zb`fþo`#Mr,J**T߲5aZ}  joDx>};$n/caԇ(2!)Qm BNVڐOLNB0 0Zn8z/8-.|0 s?pb.~z7U}Oe8oi&~E>{c&M9ύowk523\xW2}GD|/ Ͽz;ܱK9 n#m4\$sfrʯۍ(q(^ DVgE_\[# ]E=1RHe̘>U!O}woa _yyZE11Y&EHH[&#Tw;BŁbHL:E)dL`T]~tl] C|R&nӍTKK$,&_5޹_`[_j}nɐx3Xf0<\ x4 \F,:{[+Voa@TtU5\#4Q(Yq#2Pв`\6{qv?RS]OF1Fx(mM.̈_>22BW,kezNпuquiv]h605șܨ ʡ}j;?<9a\X(ϟk&OLLoȐMi =C<)Vi[^;~5~x&B8zz0JWW\67 #qk hUEEIyʵ|xIL,m066xon>yV\YHȧ^ {be!%4lO< LftL &QL8> A_Š:^iiN3y/y=ABL,I mhph1;w羂BBQQQ45G35NɯȄS.ƃ #))ѨOe\网Q\P6gYNaNb2&xzR_nWE.^kWɷ׮\6K>ʒKSKے5 n)C'Ԇl+4'04T}Omރث(~RJ;ݺAjjkYhS6+F&$Mv9 ]]g3 ;;I: a 5CA@'zQq$TCp;::ONIJ(.1_%\ΔYm GڠM@ q!Aϫ&e HhQ,<l H ⎕PWRe]#HFm`u+}UhMF\Ҧ/ib{xƥʕ\mjpOik>br:CA] J# ĻD` -;T@W@NՁ0T5гGsؤgscҩQ}V+'jP<bU:Ȥh9t)2ϗEii*lbMP# o:7UP\/7 xJvL$ef4 լK3:~=w{c)GZI@h6)2c;0ˏ>]:ԇ&z\,t}sm9U57FO8#[8c33 g0 ai| m#g5bWU?8Y^BH1r@S -f8{fԛ|t+gG%IԨ\ AxAKG_P =zdWi18R%pZs%n"#0p9^Cn,{ ;6aooox~WgwF#z6B+0C׿TLkc0RfP<$X5<^W,hYJFl{!qT)6vuCQ,m0̌j-vtPi< |_ooZx]+@M v'1DӨ"Cx $5꽺0{Atbt]-+#<;oVII):qMrGnsiep/ttu'Kc 00aPz `Y[)'S}F)6660p?g Mff&(uls@V0@ǘ tqML^j@ :`\*oFnMI[GsUk^] Eyj8OjO@eЋz?*(!CC8ζ[^c u!/WSYպ0Qrr~ JQQQw$!P/4ͣ%ƲwI%fr.P[taUG} P UTbkzd>1 ZbddDz B{YqF~#ܓgϊ.mn뢯Izr %07he_j ziWp_O/4HUZoY'8`~\Z`̩ ! ܤvƘD<9`o.mf`0{b |# bOeP&Xaedq&cpcׯy0Fcy?n3B5%40IhI8XN=ZgfI9 @:Ҏs >HQ̤RZha 7 zc#*KQWNEOiC"џ䙣^=cFza+ff9kkkAAD8?ĵKjϋ/ZU- 兠 f 5"Se7;ꦟd_Iq|VFfw6H$LB7# n~oTpfߋ_Mg/r~tjj=OuwL#eg( |k!s@g+ f dƣ(Kˠi&ox@dILIameBQNΫzw}}ͦ͠+ JoNfO1ǘsb=&m֦5!0̧=^?eo# UphŸFxF4oḀOek;94xA۠ a4g)}ݖsyeE^ +@K (H@2s10$7+bcA54JQ Bsw (6 /cCEl`Uڤ.GX"( If(msqͼӨ XKpAy\817-b\5`g@0^~ Py)-€8Cmڝ@gh~PC{*&4^@<>ϦE~7izZ-ݪDٙضXtGgyPZ_,hVlSi*\q<Ez 'Gy`\@Cck.OX̏k'|v|K73 5@CÞƽl \~Ќb~Gq)St }KT-Vy k㒠sxtD;/quj>޽{EFC%l`I@?ioY(Ƒv\=pTȫ՞@fyPP()(#{:5Ԥ)2GaYRRL6Wn(kiَ4/7P׼ɒq5YjJ{v<hg<>_$|p{p6}*GoE]%r$nXߏˀK]jdCEEW'[,\'8bC">DDEՙJÃr u6 5PK@1ګrh!0|hh^;S' _twaMn[:ADDzG9 H&5HO B(Q@zAjUi҃ U:+J 5@(/眙{sgy'KBnΞϳm M"8цZ?43a5`ql<:O@+8I[ƿ*V:I<::ӄ q7~Kut QaKel|##rfI$ȪCC,S&-$wqYI 84zGY(9" K}ʞMseZ3:}(SLrO%`z@U\ S;3#;K.]xiq޽ڜP$ ]oo)@ hgzH>S"++,t!7<PMWL''HMm w|P0տB>ϙNX/̎S;\J@H蓬g}twMU<[,C p(&B}rߵ,,}5`!^444KA9h4?opyWضAׯbpujϟ<$dggGeVVyI?M `_ָ7oX}oebbi+MW^dHb۶nė2cVas(h6`"*kډſ@||ZD$HqXpWu@Ԁ oݸQah#S3Q)15xx8rk`]]zz}9>Eb kCCFT^%'?kxn>4 /OϟT8{] +>rz4`o+KbgPs IbꀒX-?䛤]oZ.݈A{vthn{ud4h&>QaXCD6j8ȳ߈?TO\ ߷TqqrG0L>fo4>1]uSp*&j:=&D2OHfo;EQ@9tD3IOw{/ OSM?m%QP\4pc};&+:oe h[|V(x uN.qGsMw혘μv]ɷ$ ]knZ>M~B_J}}^@)Ve<k`nH-t٘r7 H |*nyWD sHT=Hj=~L/1^A`;1|0-->3)#)`q2f?*'DIY7G@H޼]} |M9P0@y(\2/ڀ}?xI:@)6SC'Y poȧsF1Oʌu@§_v_ Ž1Ÿ%PpgŁUJXP.*yڰVރ[$'c'+ю/ zJbIF$ܢ&p&Z!hOQX9&c~a؉#PPNh Z}ú0 ԉ2b,b.?F9> ^>dBFyjhlSfppFD~z8baRȩPKMW(ZY=d=ϯU>L{ *лw=WUsTr YT\nj&eVS5Pk; Qu3&PSM:J}m}InN0bl1: NF&lLSjzT5E# FPӱPO>}52$s0xR >]<>b]+ё _;ׅiܩh1̓VX  i]Q4)Mqxo̺UUg4l VPVsfέ {8+SōsQ)+FDkyZ {w$ 5 B])*ɐΎ?q $iS)*bΌ[<\]f/dp[Jf]=)`.P*par?SKis_XF0#VձҺG1U\{:Bc1XDTzoBڨ2Hيo4oΚ"Y~C˪䤹P5Ћr_5xnݝ1np[?PHjRH;XSoJaϞY]a7 xy0d'@ ^_Z6bLIt Ӿ.'!(Ww=4ISNk9UVg9\Jֲ 8 6I,(ĉ7TC-o-7EX$MꮋO[<&AHB*M"_yiJR[.6^|0H% ܤy8h,<o+̯QǕ[\2&+CJu?x%ʩ| i+L^1 Qu]~#_zD.KIoClH0Qo?BGqal<?SW]’9[AH '?S{s}&Y d]ZYGӏ̉S*I]3. tdD5C:gR6FkY<öYpClnR*߉rACfG@ kjik=<YC?L6gw7!xS.BcQ# ;lFgxu@0Ua$}H꯷G#q)E>-~$IëǫNXţjZ3jiI6x, z!\ =):2?2q=C$DhKPRmh37ݶK㙧h^uS+=10Q(R3jP)` ZMX9=aK򝲌 2T3Zr~BlOA*g=z4iE:[]1S-pi)ut2X-eU B, w5)) !\(9ds {?)n^QA=%>Ҧ ,}*qzKsEsB4zUFhɱU7B;4~=dzM%.d$ڱP:fy}0>FҤ$NהMb^gu0!ZZw]dk5W _'|\DTGEGEݿA}1/"$\NCx y6w#7ߥ}Qq=oH2ׇg Q`w9Q]58c6uKOH-2'v1z%<sgW!0T'k>߬Ūwht/ }v}xQT)ylϬׯ1ľXݕv[YCz4D%s/Ȣdyå[ie[y"yx"C)S>̓/Mw|Ԋ`f={D𠍳b|>}CZ3Į6_ F rlWCn'6p񦮢TY<&LMLݡ}ֶzlmIS|4% @Υy7k%ׇ(&>~yCG@|ND}BÉNsNN >-ćVi=9&| -nj -޺6F N6 *`So iRc2M"xwyq02Uݭ9ܱO%aC }PĄ ~qo^>nKg캨 Ⱥ^tJT^:܇5{Z)LWOr;3x;ªKo2dЀ*i|^ýA\ $SNtK]6袍G+,qkhQ|}{J%cR\ſMnEkmmaP 'ocݠ׺:^c˶WR 3t{=3iO#ZP+hʶ'S6An]9jT(>:5r}:@B^o}'$xKcLӡu>nH7!˺M(IvCSҐ)l86TJKUK!)ά.k1֏$LK7s 1A 7d/Y~obܿJt'_BGrZ['ksq+< <*2B>4PS~ng^2\̰H9 F31Oz/9eL-ɚ}>D1=* scrshots/index.htmlUT vYvYux Vn6}WLU hX%6n"SAY+TINJv"[/sΜ*|),Q}P.Te:Q7/^7gp7?~O06'Asͤve" g>l!D! PKt(Q )4o@!Z2?…1!=`_K_Yas=*y8](-hݼ&-w67[{Q9}`U˴E y%-T5Brz%n`LX0[XRpɍr4A?E F/&U{-(e/J'H '6g'#4e>9 T95!UE ^rV;vAL'ĝH`|LMP E3r]ȸ(I&sinrLxL47[%G<)|FEe1 'H$j%i̹FEfyVD~I0V7@, E眶NnAq]sZM$h)$4dP8$^pǩ f5dVNjdL$VS ˘vsPҒ~8J\96Gb29mEE3AM#=zx?ؕ|.In5̈DH8'$VƤuOq -g-+aHeYA.xUh؏jJ '4ԍd:hW%eJ<1y[f-{:^o?q WX󘃸AG"q)zHבKX{u)u';: ~SЁrk`45:J2_g!ot`+icnL Jr!us?;clNX|u7Luzr%ZoeDMPCnj҅~iz bO`(:o8A$&B}sNlcM}!DًZz~i!̰uD*),xkՏ;\&J{l|(e} ӀzsB[A,}".}1]n2>a!z@Q]S=ߛ0B1Q@npZt}[ eR0CWKq7C3ޒ@&t$qn\=J);I]be>G$d\6}p7vd݆9if@QYVljUCrxBO_=hK@\ygT1ZDA5,ƧmXA,NebL`ȑ'y l`f]>yBާzҶRp~](+Ƥ*sG7U(R?Yn r}: 5c^uMS4lVho[糥oE ׈Q%wÔɕgP0~PDO\"d2$BEwK$QfpZ ]] m~jNQM|t`+1][bc dГzoY'5r9#R3q0pvR%Uw sbL.֝:E \hYBTs7j|c:'~7KAM=]s894 }kwZKk> HS9 q^SSݔTi39mҎ >aՙbx~6mgG!`\]@U'4RL,'FKPa6ڡHm^ˈId"UM3nUY4f#P).\JS"a axxlLICKW#$=)@,HAWSi;ߚe62FI,P jŦA=-0īF^CgolcGAF_bؼX/*X-qDߋJȑꍜԨcħ@``kJ7, ~@_W]n >5kcݾ,#J[[4owdZ %堎HfC6wat C?btqee~x=ЖL(xoz*FŏO`C6KzYƗWaBDGbO$W"P#pEO=,4(GmK[Bz>35b?NHD~4 ZT-K*#7٠qcP3Ib{rSoPGE S*%o5yx\+n@.R4XӰ!wg|7F^e^ dy"uDR ꊟQp{\V+dw[_>'od4!o{<~#juIyBmdrĀ%E;!ܧ'\ʥ ؼ/Zj*WGo՟oWr͏b Fx )oAk{Z6'͢ҚC;(䩤I ,=uJiii!ո,=TS}Xn%'02K_493"DDX2 W]R+OW;)DQTJd͓U((GM3rEڦ@Mb~.Ë9(c*ԞsRlo,~Q[,@nd3xJʼ]gD{ZIj)p\1I u>) hmE'хXfrtp[3pcy=cK-?0zi#*;UH4x`C[^Mytb,17 oj~dU#c6ާ1Uwx^ "㲒 8K4A4920|wsܑ UR!Я͇ 2}w3%;2fIOW.KyI2˞S枕?^j[=NPU91;jRdT:oӧO\@*;J(i` #E“nKP&b.wK^*O F(}+?#S-#cSM(i0잧PLM;R7lhqeʳ)W"nv<-5jzcnh^-z[2JDn(ǃ?! 0Unш'˿驈h{mq6mw ]sfDrə+ \*m[l_H (5?eIZnLuc6kyizǦrMPL Xwf8>Sez;F[kwWbYH'g+uu_ OM\ScW4\:N.9WCE%xb4mV~]ՙD AVvf kխUS;A/wKȐE/_t4'V^dHbȚԿMd 5On#-zF}/ƓV7[&d|[QDr = OjsFvy [OYŮj%%fLe")JuXcM^Mhb(*͕p"(]w7 $\İ :f|%݂;9e!d0y@toRq5/WH -s0U",:uA6 ILPKD#Xq]K]pw hSNh(iȁi)Nx00rσP K#{j1 ѽhfz1NY/1(8[5uf[KU^T}Quj'l+u$۞bh v~)J)d{'zh=N z$XH\,pYrz1Et?;AL2k88^|ƩX| {| '1ݐ_{OX|leMWS0YXwnG"1M_dE^z .hXP]䱷OCU,BVZjھ/ŞrN7N}8b{c+fc .T5ԹkefRdmuyJ!#[C[J1?gH(1* -* AK5lls' VARr/[ O'(`WOpԓ 2~^VXޭ{UbN#y~}OgDOoNVv[n9]f]@`JIKgruU5.l_$oF-2C K]Ë\&$';2$s(m}{tӂwf};T)Az%aSUVbwolxSC_WWL?P4`9Rd);n&7Yq*HbmAvX eRRJYLٓWNjٟaW=eG/Ȥ:#5SNcm w [W)[["=qnTj'mWQ5E/cKj[#1 o•#jQŧe끶MZ%^vײ %쭺`KfJAJŅ+Mݔ>fMRDac|2_K5 풠 {#.lbBzWP&vF/.3~glbtM dJo[2 :+:dz͏ln2byLę';aQ|3 1 \N l W?u} (݌gkB7xNIl}?6fɷy5zpٱlRY#̿d>-ڳj#jM|xRR_~nnϟ;>+kr2'ŧ=GׯF}kG[K'ӪUTMlS'f6_5htH\훷-lSPq&WW;d붽ܛA7rʡ^옒>hyƇ3, EL[V\:Km5Gu"r!صɣy''HWWWwXlK.G D0q Wa%D7B)jT 1r?lmK˩P?..|v:ndxbؐ +oDI;ߡ P-Q\8-!MDA_J>1y [ruDsZgE1658< Oa:?]s8=&{C$&RHd{3`ʅj/.ollEǏ,-,-kֆz6#b'']|)PɥǛÙ]j2p Je]0lމVo#߿&D)ܸzOAxF dΨ}/u9v׍OU+م5 d[ Du!񐁿|6H簫*g)*}yQq~y_-錋$IP{_K8L4LZ_,4pbLZ-9>$ʍGrmANtpĢU/[Y^o񱻫6pOzdHHpE[j"`claJZ/}jvC5nN5&;fG qDkmҒV E*Ʀf }1a׿t͒=LzcB.1ՅS ƄwH4!Zr]xqyy0yϏgFesپ"1'#tcsy,)696QV]spph쑟_'a6måW%&ajӕ g-i}a$Xo[ooxy߮E PƿH_r AeO#EI+*B&ⅈ jr;&e%]!3]9'9.>yS`phڨvQ[fHx-鼸ɬ5M)1eF-w+hZdĆ#1&;mm| bUD7P߶LꉜBH E7'# J\G\Ew ʔ;]OPOMJJ~fLOƃR..^kCvǛ_YwG/Ps.7 FHy--x[мG=۲XbV,q͜D'$dUbϙgH'3U ~Tř`"\~ʤOĕY݄I$ו*RQ Yf7!@`ַ=#R@0inD'}lWd|}y0 &6pМ76捌)d`**t4[x썽Ts9reN dTf]f5^rc+N;K]W[OIgYo3\8N290#og]JyDlOȩD*fBQG3?G$̳1[_=жaH'ӉLf8W9iNQM-/cMK̳OD3N!eINe 0΂Ŧx#I28ѿ$a >OUOf3xתXATE|͍ ѐ| )i46,2Z"o[:?=ڭ7.)[#y~ >|驆#+&EnWFI ]h'Pw}=/Ywq2b`jm˘>3.ʂ{?9bK*+tۓH" 5 _ fW?< WA;# LxLQAM/Hds"=##CRV<.CyЮ(nBʼNS]CzbŃI:3+X(c*KC8 rI5ep<8܊"o"Rke`I p iPU3m_Ih[D㗥Oa2,!Uyb̮S%>)l|'sP5d0?:eZ1cjYih$C8I?~fJ-txӪMy٧|r=:WWεcyw5^N\f;ytǩ΅qgplzPPzxIoyѵod: 4v"knrҏȋ?ƊIc 1pA[[[s66>:Ʃj|ŝ#duz_lEٍ8bYaUCakA-ԯ^p=.`z0SU|K>p^2rY{#P9S[\/;حꂾ I*GN۷Lm"O; Mqotٰ*mIqak5P-Zж}5()h}v׃`> fz.[Ov\)\Z~>׌ }e9nXSvzp\0Yin os砯Ml9yIݷWOЅhy3nljaGAAˢ)\(, ߮b8ƿfwuW/E`{'hJ s)z U' ItL<νL%Z2v`-wE11GvM<xی45kLV?ʙ*/aX0gAUpZ;u/V$yE^Z/T:4DQet/lR(ZMRom'x!'yALVO _BO56h*?~* z M$[#*)!xcC _qPdT$f)Ǡ*!'.dF?~?`[h7 9(&"DU捳Ќu~S%r>;NCIg eQP]./N<6)|.Xm~&&ۘAFH3=q`α#T,jlZ?:*DCzܜc/sEmH"teZ=2=4w;YgdŰ䚳3w5*xj6+OWڸdr8>vȺ4aKIh:O BC fecJJ]ca ן?{zړm{/k64F7m's䱴%;IbNmyvslm>QUMU2e?:Ln[~mmD Y!899= kKGtۭގe͗plt0GHg`Tu{ۤG+&S3JlC'`i_5beTN.fߥ_ՏA9Xq ++y*Ul}##TTT>_ۄc4!8N'RO>X^࿗Dhx]}%g' Pҙn >ns+C'8yx(ɕ#m.F׮=ýUשr/tW_epn8X(^\e;Potyi743dW-$KX_O}vtÇ)w]0)j[YwILJ'%ZNיZS}`Fɝ:'(wP6|E$RLF1El#Hhz}QQIf!ad&u(ٹ/%#9L{#Rv${{M˅uӘX|^x;I XXw($_&rFޭQV^hjaOx\b_1U^=\ތOJ~L/?$eEش\k{;<+Ogܜok߾ KbSz+>pk??M?o1P4e_Ӊbohu{I#ZCx9UMT5'֜ Q)[T۲N<ů ~rw Dѓ3w~V ,*|qN`qCNc63{:cjwڙ$L{<$+Qѻ62A[ ȶmGVgDo!\ Q=WmAf5l='G; קMK0_WF3mV9ۻY^Pp(վ˜m{oN4B WJƏuh^'z4ý7Hxt?rs8iVf3T1jib+C@ʁ׽}M8wy$<5=hv4s, Uf%zSF⽛긛 :_6y REU=Nc^fX m=*cvȧɱ4BqI7z~~cH ߾v\۩~mPf|v>G&]VVu: /ĸ|:]j-*hqڱ}89u&(n`1V@#}KSw77FY6XOHڂџk K=GYKvC')=O8fcR$$5T-e"%6'zfH—bo D r%[l``9F"S~#2c԰6iNEnIi ~VzXO*ogSEWX/ǿ{E Z/L˪VTGLoxPGF/4r^lwA:+8sE<1$߹ g7~gƒ-1-ztu~~ p d2Ծ "F4<hƅegWLWJR҂umT[z-C4fYÊ4&!fSLvSܬ_&<kjjFGMW}Z/?{+`qRdp;7L^{i5:`R'Jx|"a˾#D_Hӟ:uM(E7DZKUvrinW&t7= sBzɂP5d(ihM^I83vU0bVˣ`uM7 1!^cѠR sivpO4 Inn\pjN2WSI;ut_(bjzg-u޶6<>>67 ܭAk9mR7eQ }\7{q3oHGp4 ꓦfH͢z!LjOq)]I`:(+=6=H^^tA`tWRiQ_%ܚs=rFleǠ[^^Ņ;P /*;-prIUwU6P=p/جwPPXēǏЀIMoO m,4qUf;H >)>.V5uLoݸV_0΂nc__[gx.aصvf)()Isvk430z?>U 1Ŧ6wj 0[vIJ$ӑhB^)Kv2_++YVTRLk(hU.39yp&DViGĄҊt|ɠ)Kj#@= &TUU-9fp9@;65m.++Ks6zL:hAt rL=O;--m Ug#p#7ӎlzy\ /eгFۃȶ^תQ `' R!јڭMO $ 'KONN/s8U6@OP a(ּѯN??r..Nɑo\%cd{m"m,^-#CٙMٹJjl: fJ5T-^<*I3}"`G 1پNj ~/%+^!4%6>ψ"NSCuNтֽOUTصt<]zUm=? Yiy 6 g:nìcffaRq|wkAQ; Vo:F͛'1;hi#<.wYtc"ing>-t$o_w u[=H<ߦSwE6S⳨{39ٛߒU ai*[#MYF͔i.iLєYfWH@%PȇR7}ܯ26:QU ,t6;u_=l$-`67δlF䃗jԂ)fF{||\ARSOZe&雅DF"cC& 3u?^@akee ѽ[Ij7޽SQQgUwL5M;bY;:-yx򭖚R7~NIvN'#d]ZWMS^^^Hһ%foi蝹L9>wlU{}?␉Jh%6hu-{vq i6AQQq`Pݝˮҡu@,FZP1* Oy4 svk 2RK Pe6>M{q+͞2Qchӷ#bzRG=200+UM72gO\^7KMPҴTy0lm Hjk,=_+Nֺ:펖jt|x?ʡknN *1ڳaWI5;(xFV[< EwQ!w9S3 8H^ݬHB";(356>kx{ܔ}`'|nsZ;ż({gu<pZY6ioe54-l'^FyOb N*١Rf GF=0!!]|Jk*@˕TUaS>՘v"_ Y=;q ח$ |p,1Œ5N"s}P ,GK-#B+triTR)^~l } OSEe5zYׇZ3[UזxJ@,Z/5:sZ;~bygPE|7L:&p;[7!1!sԶ/NU rT9;XT1`9Qu &sN@Kg1簞jKqi U_Tɟ ys0llSA;>O93yg>m-x չx03ezşeQTT[_-ݗ".= kWV싖E{Ҭy2eFfziW.pu`Qm'-1ɺW 5_\8JVtyb$(mEqTz^zZJqvɲg: 9YI[B=ݝ+#?_QU5T,*0N|0K,TF69jҊ#bѭE0WՐKrl-`}gg&''g 01n;y$X>>>&};a8ScD_0c+VjR~ykg QpX{֯N-I,=2.j[پCMMu=)uf+/wc| ŭ#%r膞Jd֤)GJKuf%+JSyOd`b VBw=Qlc[9.WWReLśh":^\zvs##X.C ̧8y4t:a.wUpكaĚTDIjP V[x8_O鴂<72u]~#=8gf| G]_L!2[5k'|(ASˏ' }SKXZ[/P>^R*K )"~ Q ѕ1Z lyŰxH>fA j K`rՎ'!T[^E3ы USцS.Ld|)@bsZ1lL|*k9ZmJY!!s/R6#Of^BVY>NCzo3Oؗ.U!<3tFnҿ ,k ҋ!` ih0 < &V3:QñK~ggj@`j_!dУg~% 7I}Dho ߭BԧN/xk| 3AujsI gQYw`Hk>U(em擪ښ\-~kH쐐q+ ,(\ ^;^=m~[XX[+~zSvo"m@KNƽSN\\;oL0v!egO)ە+mEC!HgY0`^HRD;Ȟ>X 8t~VNš{ [02kW0c Ep Rϟͽ^"xAOX|5x1)z-{Ly_IK-,xkѻV tzWvև@ݎo ` |k Yo|0UXP[30;OJkƌSZ\69 Sx"<>?QOu."jԮx (VZ+\8!]۝=>BX_!Ճd !pȈǧ;Io5qfcD) e3cĞ~gG6Bl6g;o3=Ve hrW7_[Y")~Sn -|(ӌza1H[:g`Xzm 55L,ҩY`ǙnVO˺D;UH|/uz8f<$BD@S_yv߭ IͥNEvGs8!eZ:;"=TɺZ /B@:ē?L%,)up`d6%QPnP}d#GF`>_Mq-<ҋy&i 8ADYӟk2,DNJC&NZ5..MO :ߘO,/ WuV. O"S-2^(FHz'!B6!o \n>ü@E"*Ww@0 }K!+dbteE RP`]TRWxl[i;^[(OMĽu1%VC<*~+:T+`[oSPD˧</z|2´]1|:5J2Xm굺 xڟk#^:?xa7 HPPkkk(`bbM47988k3OKDl&44* ǧ АI&۷o@M(ZZZnUE]ɅVT0Z[[ZBr`K.:fmԝDs uvB" x' шQN[OpY }ssJ&[573PH J_%XKXDa~E9#4qB5@• BјƵ׌0v|;peDٙu]4?6@v fٛu-߿j-&|;|+.o 16ֻ[\۟o@וNfM,RIذZm1xS8!!am3Hh% ep\Βqsk|uڮJxzu ޓ榼 ) ">8sEzU[pBj{Hndy +|+?o$ދ i6ԋS^E5 'YB` ~#k ¾ ׎r]vY]!aKET yl}G#=AgRv9e336$<;?Prޟfnc_O,//-,*pN=)n>4l, еACɌaR" :gX{)'~~4VI}NwcQt/S~nQ2YNQlGo9^lϿsT_0))kz5{JN'vx0fWF WN XHp l|$ǃP1E>`3ow[Rٹ%@6]P2̃+}so}x=uc>'#Sщ]5e)ѡpl'{ N3D] c\7K a̜~(% !̆/9{; CCj+^x4=~NY^[KH)JsUF¦#Xr0٨/n눙rvԆY^Avύ2?UhpY~(><LhfTV21PcC޽hw9z}do`PP] .@ b%A+Ce.GG]]9EWUUMUaa?Ra`iԘ|N;2 j0ca@q5"agJ }R3]vv`Ty݂gzx [H? p (ɨ47ʋG 4RRңd62M9-UۆͫX-66v+f%n4'h۷}&C1 B`j*+9&0v-P,EFhq].'.HHH4Hxp 09s#- YX%guX`LaDf=L6 lmeZpzzzW{PvoAEFdlcbW AXU5)ITn XB!@Yň* 8+j`ea8c{r7tbmzխ.(o>=?krڵ Uxv $ɟP]yt 4&`^YۮpZR!Y[BGvs0Y#--r Zhc%mVx+oI4k>#p}0`7}uV!*Vٯh7;E. 0Eʢg~p7B᯲=k8;X|@)dR)(yk P۲6.9ٕLa7/4ʉUNk,aao׬W;xw1uzk).d=|ӃF"9G)' oR854Rc_c##{Z \Sf.Zc-~c%2Aj뇁$ jyEFCn8lp:_"#[13::؈2xO2>\F; 6@_(Ll>qjgo~0eze%gU"n粞0rtO俱aHۊ#ͲE3_%r v4Vd}ڵ;&&{_ fF ZAWW*YM)Lwg:-X6y\ m -2.4TRV>FojX4AxFA~~ٚ=Pp 6E*`|V֍*Yc~I Z͖kse{+/lm%-p,<.xwo~Lt$  >Dd| Ӯ(F@، "~ϵnT08@x?YqH:ss 9;3@դf/@-I.9[בf HXY봸:Xղ:;3G,b;V17OŤyZ[?qq.DEUZ^pHmiWW ߫N #0&9ON!7~`edaeU*b2Mlĥf60cj)obB!GIȋE%Ͱ;=:\Wt]f׃cSmtq,zig)'}9T z_~Cn] Qę|є' FvϦ-l;uM!̍ B5]/%A>4]i^״H2!Fa4ĽN h쀆z˦=FXIcѩ/8iaO_Xi7h`LF}H䔔"񝓓%jb\Gs@BxC}>ښnR\kv]vs8^rHNNe4؛.DsNZ !t:@KL^ :ȖBooVr,p5e|9f崝&>?{t#́3`$,I p:E|#E#Wxxf~8N3 xT\2yE牯n!]tΔx wqȢ#tuJ י@ږOL|: pv zF3yʕwG''pwdz|D2M"*1gs~|ৡYGku"83RTI5rL8;?EYJݡmW1O*Ym?˓,Mp/kc듬'D,-jv'R4xO' B}S~=2wzU{ IfT\+fwR_p++Uݫ;CVзaw_v¢1oyeFe@ Aʸ1Ud:>7T:X,O>Dh O}rlS jjj!OO._N;t5;s^og T^z#jvj;.|$E1-S)H7'hH:\/?rѸ Vb}sب"[vʸ'KJf |oi^fv.).*R6(FP? P_!;B3!E(wmfyY}@N*U\YL', ExD* !99Ʀ?g Z$`VO N_:8Ұ)F[ё~EWCؿʴˆO \nK:ǯ9Q7G\]Oda* :yTƟw+]ƒyzz"A_adr5 &7,u8=߮j7& ~ޡPOhr`  Ku?B7N*}{s=_Jyǐ|:*/|'?)&gu2,0@[Rשw_O"9+"-zxtX+1РJ^r*~ XdKKx/3Ij _3H !F FMG]zms[u//0pX>3}jWL(Oy~qqsR^O9Ocei%m_Y6>{zn&@oZV$UP{pi`N `_E}sN^ b A Q61hWn7i4mXb~߽{`hUbʡ N>X[[[0g3Q-7 kL|lvb/QUז9<^vcFl: U+Ѽ@Wy1 '_:-pޟȯ̊<9QDTgSӹ8)UJasG>\bL${A؟u$29e0ZkFwmGMzml^ ^ Q AM H m|<"s 7>ߒ C"C?u-.7^sۺuK¦b#hZs(} ܑo"f T|MQQQn=9;:[0CػLS C2$w:4qi[< =,S;nnEUB42tiySr-E{ްطfs҆1ZG{{{!`W}Qb7@&Ihu#+Ţ\E++  n ~0his^IGOJ (`{WQuC5^O>׾6ߛ3j }_.Z @6d./{I1*sq$SimoדFw-/&/]RsEp\i7z*YسSzv}A'd133*qsxDGB_XXʗ6177c$SZ/pS6@R=n'ͽ b~4i7PfɌz5fc)Rqt{v9:[-m|k~bݱw0^kpsCX^n)kg5Ez{鮮D&&&6ff7GEijقcGGGsݽ IIqq]CIC Sؓ4肦!Grf(My9/{vTduna>44d$>\#T" v^飝߅[{ r> EZr%31M;Ŭ;^l_Lasl$A@cyw 0ЌY.> zSۻ* ;&Hɯ{ʷխ˱=?&G/U(ŠFu4ak@0\RGc4jl.,kT{`7jz_yy)Ghrqq)0S]Jy\ KFGa7X@=HbL䖝KRXVI :c`ny9{ZZZR~RSwehN@ 0 : lļ4d惤kn2e;o}w0tKRjF1`''$̵ncut[, oz(kg\j8u,e%*XT(>9E^(/,VBHECپ6}gm,V8ퟲFXz8õ&]$"B<"&Jp޾l؃}2Ӝ4` Q["5qI|Rm~~]\1p, K-t XqqT݃_>Hid4ގqbzU?Q7T-`sYE͒I>6CYcm#˞/GtHƦrCGn|kАٿF:O\cwt?HѬI8đEVF !pw f}]Lµ_u[gʇniH;t.Q%,h8b _ xGBbb,,, ෰Rˠk'iK l,6! .륕Fpo)), mf.vnX (&rH ?)͍z5B,&? I+qvܰʑz?72wImI*Z#$S?VgfPR(t ̯#[Ȼv#%$%qjHOoww `Akjw:oU7?/"Qe<. !+f&.`&[k5f,@kv$Z6q8b ݻ-_Hs/b g;Z4hXbJui#i_~p7r  eod "=q;#$'- uV>s`$6;;ώRtuu)hkG1yU-  VRrܲ D$QTw8q{{uVvwcÐȈvK]9;>V@F=mǑ::ezxnn&ɡ^X6m yommpF^7pY924#b^)fo񬙭43?_c> 9..i Ȥ>S *WgHH`3=Q=W:g  A /R6-JNxਜfQ rX>w@J4wϟov9[{BU@|B'(GF"O[i:,$#z%2t,զK77&&" 'v؋;g`װh 1'" LsLg]#@}-1qڼ X!ݯsׄ=< z[ Nk PLG3=.w j-d &Cb lBW-,GN [8Fy~ Sp&o|BeC4àTRn>;މ쬽A(wZ7Z"J,FhCP[TgO[c칛K^9xD +T"f 25pIR<~7Pv>b꒨UTg6\w72dhp=9[5:!lNkkk! yrY]d)]\ٝ͝U}j!5@mgNEN˖I`qۻ//܍6T]+V$0І?EYhiiy 3s# Y+ E)w >7D1E~"y⊈6q ̖6FDE}8[/MHX _1ߓCA7/ ]3m桛1RH # Mg& 0n ~'*ZEOHMM$@2V}}U&Q_qg9x^ p*`V몪"q+B!PG P盜P 8Ⱦ9R͎uq c9.tt'吞UД{%,#2sKt~?7a <"Utܛ]7Rl^XФD8,+O&q~MR?h5" B#v`2fѥ7N;@V?Gnw坥xcC=i.b>amc*Raq v` b8 *+``""ݹ4什[TT}T>:Sg+jk~MBeVj}}:^(O\=Vd鍸8ik^?V(Vʼn<4&Cvxy VV߾̸xy95lQd2ނ  VeOoogg'c6@KX4k/hԜ^zhͼ`)(ؿE2),6"Oª+b0YOJ0iNr[w>,,m7xcY665wEⲮ U(k].#kf{9OeF͌o }mz{_Jv6ZPW~xpHaevϫŦ5%) ,Z汪U7s2;PxjD*Ӫ3{pYyp9@ք-Kkޒ1=D2_;)Sqi <]ߌ;MQX'-N`n>:8fɬЖz⽪//BKz5"?USS*;[[= Bm87OuÀw>6<6S4mԴeDDDNwH:,T}4 ;j೟mht/;F9@DE̎d#qDt) ?E1[:UKKKFE!k_9:jW#\I:#އѫtZ\Ӷ8{.<F8VbkJV)ܼkbT\(gї41,u6,hܗ/ lg5!g/>|h+ja#>%b/!*n>)Э R RJ~c-rVñ7(z<$L]TF h9 i= >#D>bMu!lKKIhW]] H]Wh͋䄎+&Ca}C OONN{PҰ_S[hlWSRJE ܎?,p7hզV=hp !U԰* 4L+xJ'րRV!3|f}#SNifn_'[u)>~{2 خ^ST ۖmqΊ9{OL5v=<Ζ_O60U91DZ0

|OEϚ~9q'B6;,XuX MğTnLUPs59!+  2'.̝[u]gALféFwurZ6ݎB(!I/,d{M xx*mdOѓG͡m$sۡr$ſ}IZWZ8B2>6IOȞvOWʃZj7'ę5)(KFl} R 9{ 'zLmz|9#%[4kG;QJ# &ۡon:)j--%%tLAP{{{FM%f޹ݱCCs.c2`"sp~魯| %\Y媌to24q~cPjAAP6١V"""b+AJ#9Zr2QE 6˸:H<nꫪƛmmM'n005cA115M6 ZZ[vXdldR ,nO>aM7d5*2vuLSlG?YE*d óGKB#  /5TBU3zFr#]zަ@]E 79/V N;?ߊf吻}sJ(_̷+ &%re50arr[_*2XY =`$RLc$$`Z0*Ij GkI&MMW:dL g>DAjJ@H/NXtNpz>>4 pٗ/_c&k-+,媧шNOOKS iMVa!C,|'l }\QGdbKZBam |}Mk5>xr JӰ8T;P2IZ6FX|73MN &n$v>_J$NEm|ܜz$>' 6֊ao܊v^| #IaGIC}W{@B'NI4x]nvszz6IxnzEJ??!BaYC,.$ a11 ݓ#XK{G P&Ā<߻~⺂% .-Wur1Xɤs =y\gQ0r|||iI!663z3i){Y"R%۩T_C`Lbytyqq10]\,X$AѹWDխ˯]3ZjHR"F&b&8Go%Á1~vnM>qh"M)άٱi)d4vD-}{Ke= '`-o"@86;`$csvo&5<cm{_W(whb?Ƹyʂ7V aQ2Dhŷ셃}WW9)UٮSѴ)js Os ̧^Xz4 SԴж$S|c>3qʚ{;*H <@pwQeFz$M R36#Fȯ;)]d2~AK;'1.qVzHuqĿfsf>h>1.j$❀ܓa(y9$ 7cGH P ;mN:bfA3*Y'`m}ցy.NN'4| n_8Q%):&%kIq1FݽVBrKpļn[| >`Lp3wnF@(T6 $3?U !555} 8Tpfםw{ߥK/  dmKe;P:r.'`U=r7|D%%ml]E~qYCDzcv4/D"c%i7'+HcAe0QoK8 4Fym xoD) !F'i7SOPAG y@dw>cip | 0>J6213wƒ0VuWA7x J,`FƆ)` P|0 X . Q4"ҠH# ] * HHJKHH HtwwKttHt÷}{|s1cLvT v@9^2@,2Ųl 0d0G k gmmA1;ӹ.= ”酥_N uM`(c_0ܓy&xe <W lvI~pn#nk^Wa2{ͩ"}ذ1(?LsLFagnlr>"=~;.Aܙ"6ŋuֳnVS^1kאq( M&?VgMMKϹKTy O'BUn{+(EKzMw̼Do`kӐxx^ӹU ?wz{3|&<"1d}1VC$}kڤ|$<d6KOk,?| v.;G)OI 5?T|AmH"`NÈZZZ2K__pأP300,\xNWКb5--b!QQuMTXR201\L zٟW|!HBq#̯U!PY^ OΝSgjPWPG)|c9C, P),ptZ-4`atp =/<:>5SmihHp0--s|x}5`~Lܽ7)dr ^MOYYKOO6 if^0@|؀-1(agsڹh[eC1,S-ںLLL=11kk32$ +jM 46\Cv702}FxxCHp}"6_Cq:ޏB=` ǙH~#>; xe^`1^; HRRR>}ꑦr=v)x~Owe9,/^*?O׋,CwRcs(AM do?u$'#0^1;eSr˙`t3*jguvvsUiO,dFt I\A)f!X)tf3uOC 0SӀ mIn - `4#ଣ> &>>f 3]U0 @Jkȸb,A(/̿UGR䬇#mPQRd5sg9E'BB8~?fed)\v:ڎ Y/^RZ 6G 87,*"5fD\Lzw†U` 3EN 8^̵¬}[f8$-[ڀ\6Y6EcMl*2Fݾ`+-JKKk)/pM Q:(~͟Ȼ)*#g t ep\8jRp1/*8*XAAm0Cܬa03]s%2'f[W';s@KI2_Y->;\ *@[D+ PjfgbƐpѸd Ckt4ak#9+>X++ jv;Mr{7?z٬;|GZ̡[/\@.`fQΠ뵃C{rN(7oަF7d+om]J7=`KXή\vl&{C]Q@5+w%4tl/+*0ʱXMm)*pv1t9ݑ;@wBr|^p{ ]^_EN@Y~zN[^LI@6=c%e9` 䪕 /v媵h6"fhyfUH6A 6D#%bϟC=YABѶ)**zQ\u[|q~pҺ)Yyn営<!C c䔔)8D}ee%߾]|ZHVJq[BBB\WXXda^;_UIdG(Rڭi),VEpM+ؕdϵG''Piڰ3_Pyfco/ G`ð~lAUҘN^RWTjMIۓy=3-ppVROI<ޙ?\^M()pnopqq̃K]D@" Gg|JX_Wʱ`sTƷt3 δ?v.0Ԋ?*Aoef~ lWz#\?qVNi~4c<@Ѡ<7Hlƥx`5Y`+drq]{M5:U*$@ఴ{{{UVTP ;_`+1JA}2Y1#ammRpO,V[6uu=}QRm-!=RROCFpQލK,_gDH j):<7*ѩJ 'qT}B :-OOuty!=pY4;,b$X7gM\GrmcMDOU3ebBMo躠/u g/,5rD\Y}w %! ?$J%e}ykZz +V67Y*ChX4$u}^38>l_ sq,cS]Ɉ(ZW&%w4B?RP\UX7愋CGq!Bn`w:b, ja,WVWsw,$$ߏuvei?=z3Wq"րc(C&)8=>3EPq=<\ ˱'TI| TVn1y=@|*/..z'^G0r$ J ~%RUǻ+-D?~/3%Tt Ԯ.L_^b鶦xRBxq'm/쭏)zhkHgAGGs< Z}&DǣR UGlu}>3%E]{Yw~|׃).x 'W<]FNהWZxtD#яQܯ̺|e&2ݎK-g(ABbK \ ]s=vL"I4X7] .-o`h2}ď<6F#(vp"_S:yFECbģhj  ܳ_WM|{U{^;2sKK>iRQ,Rն?<߽ޮ(>~@+*p,E6VWT.BWCr4燁-7-]!†4\odv)/ v%rynR,, 52BB'R*G}汤~DVH]qd#FX{e"I-2VwiC}ֻ!Eϼ=!m }tg`vQAj/sE 9Or^GDZdj;':JѪ5䎟?p)t|*u|3G9?l7S9<$R\R2zcS&&ORԋu>D)҂ WSSCE )Omc0 `6$E+fwTdd1a1F=߿fbb"ZTRU%Ѣw[tMq}_OmN2Tߦ{}4yB? O~ډ>ooTt߽pLN=_ZJ/ 4?ubUSEERGFB47]SʔE}LO /v\\| f"6U. DoP'kFgN.\om8 )}޽N252+d&zKv2peKm)?~|(iO~GߙPz{g_8Q D{{TwPȚTX8<++rQ&~I'3,A((j0 1$N[A'n 1w;B=(~)!u-%Xg?v9B/K_˫F3G>H.\ 6D#:~ z>-i_ <3G! T\?Z`aajʏ%//9DGY/=~xYZ٪6VG(Ӆ/os[ pBB&Bv+Tݹs6z+$UYx`VZ(*)zהe$7\*&b-KZH]˩adN%=J_+H`ʱk<b;iq]5,L"im劮 [vaga,`cc#O(7Zh 2ϻu|qajwY.?L7he8h`A]Åӭx+dk?fA $77cii[Z5YB&?/,zk{TTTM';U*4\N+,M'5Շ=V۰T}]Q[X3UV 6Yȸr :$;|UGˆߪJS`-,3`y*..3rnb ţ熀VblBPpoSyX>hf3QQQًYSKb]wS%Kve~xx(YS뭖`EzWgG:UjAp:gSOD !m6Ly7WC OOٕ?@>u߉`Ё"}I͆(jϐl'*&C++l+@ "a0l*$$ޣC_>֦3ۗ_^48~IxNW]] F~J - ɧHxt/)-dGvC U‚%?RX1uf}eN# '6v)狋`Vt*N(XV^.8Alll ^dŸO"Du6S. 6bgP(9u}B>/;06JV8(K :f}YHLA[ ɐYCw^ @%w8=IN냚ʕ>d]~ٷ:g:}1++68U7%p^xo)x$!O~`SlCx+IL Wc<'D@K =XʜSSTpzO3,n~]wc#WGS*"o@[2ÞqkUz:to(w| wӂJ W_<ըU apvPE,1kh~Չ, _;Ka?~]҅uEY_6\zedd Yۄlh"f"%Dy{jåsVtPfU1{=Wʯyͣcj[_tFhwrsMv<`T9[I?]_`P1#^֚ udp|- -NUoKJԀ+0\L]`LCRNF7ffhj{\WZq#$w@/!=ĊD1[ 7 JZGR䡤$-/o Ϛ-ZZ~JG54fk̫ `fO$Pao>''g{TJ J~u Q1Q}Qt$+++9PO{0op}c|@ _ٰD3-+Ib䟊!c\?)wQ,ܠ3&Zȑur3Pz ,&9:>N`a.}ch =o8;12eXm ~Y`d ^X\H `vڂSWVZB~"./t>7~Fʸ&Lx,O}͵M'2O/JJmAH_'_^'m싮]'uU*x"2lWǤo߿*DLڠ46X*嶔KdybVm*1E>mBQf#e '.TSKkn[wvKUE_a;rd+,Tu4wD)řC͝-<Ì[oňSw/5`QpS nÇSIŇ%$0U,m=!+˾p_#Ӏ?fçQ CBv?FH(2ӱ~aI!]ޤ\RDDDPϮ$M87;{pyV_֥&m2\4^c-?p|_Gzu/O_&" W_y \1ӄ6Ƭx35J}psyuB>E2q[r\#0!K㷋p%$g"##ݲK@Hn hl'_G&b:M]'2-e_k*z鉞|4R*@Ys4yx,d=gz%F"{:Nj91 9׋Mep:)`#!ìʵ:JX_`It&C~{kwADDDKEo|\w<}us$qtCw- D}db=z+5l4d_浡N4?U!Cԏed^ *&?ano;pUUMj9YYM`]Dd$oOH*q*7c'ծêt+i0B[]|v_eأfۨE6 [3x}jَ<Vu,l7.Ed9=(t$dTi!]ct</@/_,~71vixKG( #گ`^oNr 98,F@&!?~ B=qثu] ٞ?Ζ3/zfF$s_JJ[pT4S))7U>A6a끂 *LzՂc( ojy.frEHAQz1̪VsX Niz1R!bς:LCHGcXNKaQQS(8`㺪?獡ߋ_M` q[DK\GAy_~aii ڠ(58- d 8Xq[ `4yNV+4S¬SSe;iޯ1n1vghh{gT&I"?qC+O#4j0nrvOAczmn^c<w[gWoJ~M/XzEA0oY=9ӾLzVNwbg9 &1mݮIÊwnP D#ʐ ! !sd緉5Om5\&Ko33適o W{ `rL'u *QSRGUQ>iddNi ,,;5oxFc:/Rn`SFt9( @@4Ir'+C>Om5*"IuB-*B-߶ضw'9e45vt`/Ԙpi(2yFLB(ZReJpL>E"I=<3^QRƾ>̜?rwHrS _<+Z5RM=xDWgwvBS-f;BG]+-dϰ|X>~9fTZ%])K^)8##OWlzog λ4A [2U=ȋ,Ōd˙z8%\e'J*(@ݴE?Œ8v =vW:=.@9<ۑB|{Qy+|}Gս/GP\ڔF;z{_kz2ExDr yyI99X.oLtSXJ\;;U(WLlkځ!E,"(/|ioF' UA>{B2&9555cr,"bM `2>&93pૈWZuN\š?^ I `P`Z`V ? 2@_^k|*G&TV5H9 ;cs"w'ߠmbfGEHF7nʊiPW (踳ZB=ب!N5%p#* Bqxkaƕdy\_ _FXᎲ>l~K=Xgj>$FiMLL>MzZQ ߵ[Z$$Q)ɞzz븢tlfWbsHKѼ(dnn6D+?a^n _ >wGO]*5[}F~$& DhXR==">sU֏:[A?;^[_n x-V ue, Qö#f.\[[p5YTJ4^G  ,w޵:]Ã}LwUlx6}O.?"Y*&s5119NּCN}#H ꭲn ,*ǓfU?S4*o8fYN^n.o uCeMܹÇ(r3|Mx~yp%rNuJ j~Tw>7,_]%àaE ]O7+000Z`i``P޷`w ,'N{*pTJG#t:=j?_1rttP7,ǰ8򚆖6>| _l/^y͸f;LU5B>ӿ Cd#:XQl4[Px~y#Ӏ[D€ ץzi&1C'#6VيCoTQcK?$)oиF)n̉VV되q~F 5K^$U)Zl/'"QPPjV֔80/oƠvp4v\[B-K?{<GBkeNѬ0~Ǐ=uu[p5v> ᇏ9I"#u+B"ԯK_5(B1?6W.[R|^h<O^YX& Qst[Z gIuGgz_%afkMH3.[W`5 'XPj/G 2'''8ʀqKXXUio ¦ۈZ'IVrlm'/Wf^trSJyB@w0'C5}1n+ȝp0XP1ݹ Tn/o[o~E+t֗+0wo~>KP|@+sJ1~P$G|%++-8$CMEp;WM)VSG& Ugg.t.}%Pl+ mg` >ppO6od49͛7n/`W eZ),g1yL8VUV+K8X?[zz d=8p{zzt }Y46 QCkknoGIU]pM+0vh{%a?Kowާy~~G#̓ga{ b#'|Jh8*+*FWvo߾]9;G$,z|*81\R_8,K=EY4YpE~euura:I!C qϱz唏G%oLzPʝ*H?]69K}vF$JZH7ރxhs3 `}uFy֣)K8@kAZ>xE^Z۵j3?eF8HyEHH(3?p 8Z|1%P #`桤$XL/x eee}ڠXO[sq~c pӧOa< mTiJ'y@GG'F;YjpGúSdy]Dor꺞`ub)W'⟲?7bC9a5//6ƋP`Џ٧ٓ)F"===٪G )B:@@H"61~r'gbb/N y.x8XrorB_tV$O)ːSf 6Ex9:]ҫ/kFc[%3n 7čBEt 3{{7yNGO>}r6Wa{2;۵aOW BT DsT?#?*wN8>E$`}1{=ơ*qatww*|Ԝ#1tĈ > !v]I ] U~tޗlki\ ZT``XV>1@jfޛū16tsǩ`~J 9+cmCٝőɰ#W75EX8ÙvWjkI _WxM #+?nڎ`jP!|bJЋA!LdQÎ%Fc>xYA])ޠ,}Е(IldZ^hÑQ~ae͎M~xtւ#!/m'+#2 X눨(B׮]^J5g6z~vvkDjJ;I6_afEbQQjնY].`Du߁ӀUdnf {XP}yе`mMΎ W*ʤ{ϯKtypyǏ#t9,m/X˷ E/,U;#akkg Jg9i];!dz^7(]^5!+=76t_oƚbC=߾{hiK)"z%m ҽ 0(ٺ8BSXA4 S3∾7Hb^TIQ|$MИE'N҂sbne3ӅZSyY/ YJTރ#ęhӃ g6p\#33&_BǛ7妐ؤ'z. [qEnjA&}`@|>@z&&o//䛼0 ##Q5d!C[!++ê;]\TT|a-g_(ΚKc9W xS,2EPG}3q&2:i0աo8Q[epNiRmM9xaa8u(֬//\@=,+{GWRdDd(൘+ !"`:|SȪǠښ: .5l(o0mZx6QW] #תi h,3 GI<7SeMM|9>޾^’pq0|zxX;C?x0 'guqY$NbҩלۗsIF #F~l-#|z,q*^+-=db,MURSnJMְh'*eN$m^h>ا|'+(&IVTButTH?<5E5. `~Mwӯˍ7ω86DY+[=#!BOp56˝DWߞHx GU> Tռi|=r"[)z noXP?gabFvΤrcrM鉢p013pebU,d)HsVt(  ?!Mf5c}ܽ"c\ ֳ O2G|Z^/v^ˋK7yLS(OxW.|. ˷*Q[aԄvB?} UnY9H FN1m$ i0mƀ_hn8ح: rA V,unػ)2OSLꎫ`w's= }C?|, YD=MVONߘ39\ XiFA +8HvcͱDIMlY~ l(pDVK:D BSRh`"\ǿ/9`N1l~~##{Gdd% 7&WUv/z-LNJ{CƺNî2yX[pD G*DdS3.D͛7ݐ>!6X >ßAA<P]MtJϓΉRP*eg݁Iӭ6N@ĽdaF@hSHZ͢W#DׯSx$I]Y :66ahH[NTUTn^tTz&i;wєdɥ?"ְ #iP,lL@9UW8Kl80~7,b+1gBv$_ZZjԇڵMW(͞9@ɒ8ǀ##ip=F aAW=_3R䃳s/%1DQRb(qwďnh^zyl&:NHH$8XTB~pY|8![d>ōVMKf{t z[',=i#Spk9ɵLF3{SI2oԌlyێ]Y=dß}}m!xو{'>PT d?Ԉ啑`;YGy?b[38C6yf&ahlioMY`)1 aU`(!WPTT;vn$G[@R^8?*l86o9;#xĄ u`Š (MG!&í&}7~I3pǹQWPIMM]t\]XCF`Q+ Loޮ۪Y][Bjf:g5=RE t `3 _sY6Qy>˦Lߠtݫ<<). <[>tMŮH;ICr:3ω@l4gH =z}cXڸrUG'r>yX?>kTVX|ko ؞oҬQ\Y"fCqI iQ@P0,:cgvo |SR4V".l,Yta˰hoF *,ŽNN ţ۸Jn{?~E1;ήK,{fcv<}I-S5Աz𧟣4Z4eiOn8n;~?áЮ ֨< 1_¤F-//m_cidQ%x(>7oYyD蓦S+3<}6ŭwj/t8Ir-v UOI9x:sx'??/l՝MLR)r N% ÁpЈ.nN< < v PhVlD߼5E_&&"BM7}_Yw>21As& yy`Y9x8noa4,xI 8űa@*.RGT(#ȡE5?%zoafa' [U[\V:V=UT/MuK^7w2tw400ʲ8of'Ay 9k}#>UyR k/5ibU_Ϡ{30 ]SGPFxԮYѥ6 "º"r"$ O p)!dR2?7gXcTN*8;?*t7Ln{{؛"Tjoؕ!O.{~%L'&t{ jc# ' {eㅦJs$.Ą9T,7n܀X6Xhn厖&]+0u{vssncӤ߾}.8X\4yyf9T4g'X r555>n/oF`O_] 8~od}YJ!.vv,֥fvHf~w9ߌ1_I~]u9ͧx=]]g|E鵯M-v~HЩ KI551qq=nm\2)7U|! ̰/ 㳟3ڲnM):&F5z,]^MNWٰ,}=8F2uZ0ղS2SFq?M *J59)X)zB?NH(`edaԄv븝_#9ptɷ* d:V@)x+vMXS XŻjL&(g|?LƂwm;6@:  ,5Y'`ZiO wtvZ1-q^}c4`[/W|h(~.^x·y=`/9A}_ߪ/.."8ǫk]9C%O9E-uGl*iOխ `VRV~kѡل;աkO#>vz7ETGl^n[sSGu;t.vڐ?}m~sR\񚇈^͂l_ǫ0a x]]{h|an.ϟ `;ώwy0iG R3nd OktSSSL~;w-{;8\wS[Wi渘RV^^^Y!D&&!]eWC:n6Ⱥ|Jhjjvq+3g)~`ha[IߝpKz+=D]=Veiy Ŷ R x>kdt?NsԘ`trp[8pm]CzR&9I1p ˜zyK C][ww sA+))͂_'8:;/AnhX}&WfHׇXNWpn}-1So޵W^\LV ͯ_0pq}U9* .{ !٭$q_ڴ1oS؞7tozX@il,tKGLex,|(=yd)$$Dޞ[Ɔ&ѳV&nUToX~r >x'mJYoTrF+/*Ͽ':rrf?-ekBZʠ#j0e5bcӽM_R{6w~8s"(f}kl'f.OЈG6n#8PP0mfH)))ZeyKJZ_q!E7ONN`^]p *\F$TW^?) wů%΀n-==l`tnٽ>#\AIEʤZI -a]:W"5‚ڵkYnGGVgd1qqCPk+`eA &pϟSݾ 8tآM1)>hҥc]H?pANaj~ba!>XNl1x·vm[z1)KKK^bIu#huX8 R^}-?-X7܋k͉CK 5K?K 4|`qDDDfFrQ B0[bNjh ;'Иr\Ij[O̵o[Zs)0\S.3Ig%B:#ɣ\}Z$9^hx f̯aO|Ov6(l?  $K{4zg8mN'kk R n!!0%i`h7 ]7Ѷ~Mv4}`8E}#@^IbRp]}ږs bI[[7*%"_ +Y' @WCc{[s%Yb vq ؓp^8P }Ө^לPuuNcA<ߡHa'5/mG6z@ Ւp`2- '3tvIԛRZcj[2Z(lb~ymx˜_obwv8}\gpߩcx ""F[\Ψ d?Jep[hp=WN 6 @_8pESWSjQꐚz{T0|M[THer/;jCKBH'.e(ێ:a{FmGf}ۏz=122?5 JkcPM YH풦u}f} /3Xc8ϏPZ 7|Η1_HގGiluz`m'$1~1_ v**Vg6p&"}P2_FHw0@& ?q"Va!c6LX̦ʡЅ>ܼN^+#!qeeB#XQX⋣~hbPB@#fRS .bWNDZFg"' n|nGBBP.Y d zoo!6SpzF R=c`;)˺|X/R ޞLpW,1^#̻ݫQ$Qc- d+++㱄W/όUyΘtLTb  頠 s|O__"{q d1Ӧ+J\wOc55_ tJiw2@dZhQvݜBn.`EcpI|XR*W `[`LF D-UXLHܗ缱+[GJH75%]Jh6THܟe#rH\KAw,i84 gP-b,zXp[Z((eQ Y$},V5  lbQ|z}w$op >YY p5{SfǀCd5쉂*'9$4a"x[ WF}qHLGjk>) J , kSb2UNd\i$Mt]Yx";8I''uqRo6#ɢ[BUl9h\x!آ2{~)9Bd{T$go#e}{edY$jPvG^{1W"<;:9TiEJyk"jPߍJcb{܆s{>-eN8D# i =ڒ-rg` 'T޺4`1OɃ~z湆-7ʣe+ *ׯrpK{?.gHBtwgI x&A0 @=Tܺ"T9.O900HgTy?VoUW3wjXF|{+S!xO,sssu_LS41]3ZG0rki=2A1ե +4a8Uʊ2ЎynsZ>T$6Nn՝^ڻCxZ[:ώR/]4]*z-9KJ{AㅎGG̢ilQR:~+O.yzF) ^5.Wa#???Dzp{Ode:F \͗d2<A&|@)T̅1&E>~VHޅVNsycVP'[o0'&>:Qߥq j b7oni \ V1r9 @Es'ŏ+EbF02ܘ(&iڭuᬇL7mV6772uh?g'`NXl@ۧ\as <$`C [$s]EE'fe ٘, ֣d#R CiB%QRB2#Z[2FWI"L7>Oo_ڛ(}Te`فSU\JzY/e8u??tK_/HaTkj>:/BP&/1EJߑ\m6Pޏo~ s =0@mݻL))Sيڝݫ9!?;`Js?dFEE cVqss?d<.J[YQݺ }uuF9ZOL{QA7c<,,PX)Y 5̧9⮇YQ,[2cug\j'N,nmx FkN_?(Pyp?C6--m{3*xLbzr59aء`xdNp` lJɪP E>bԦ|"oFMS /?p<:;?g]i2^*%(ëfT{ZPccd.N皙V):;0yL`{]УN_r(.WD!P_^V`~ts$O5xX̓e,ÝkٖQ-NNخY:3p>OzČTq0TF= 0a Ӕ oU Wl^ydg~=)xP@P"UQB>){#6N1 w9;ĜoXUM/'954y 61dF(l*쫸Q+Cg:/I jvFj dyc(*!%}p^)x_ RlVc4-i >}fӻ'_`}TJ1!_3v7(qha AdN L*YJ'/,]Xʇ" ̏l:̤Bc۲iUU}Lj:z@J M>[zna11>ǹۮK|'f"9L0с1::ړnK)wU\\ח,03*K롈ncU 5OYsC?v8eU}.#Bm< h3g+Oӈ;/L2ihxyyaAUE!XV&zPVzNA}3peٲ,Qxĥeb6=YLǶ'&&&9=ɒPu'ԫ:mL^F*R6{=aIo,cp`}-,I-2< }xzX_k#̓.$e7$Swޅ<\\e&ZRPىg~V~GIi_^zGi1bc1,hhzOz'0F [|q` ,Ǽ0rvV4[5ToAjU +8-WC(Жl,}Kf7'ش~!yya߫o_t.I2o8Ȭpko~,8v!ծk8Q Gz<{zzc4ZP#Xt dL+c, ?̯$ ac4%)]Qbn.H$%I(KFN0222z6X|cg B8!;, ,'RyC .9HƳB!*2@-)@kpqhDėEe%/~~ⷯ5MNƦ^[A8*,[|yh '?s/SA'F丝BqfՅYU[0_Af(l &ׁx=*o? Sxfmw۴W^9 #1ooVatttԦ.1u͵|4H~Py؛ar8߿c`c?Q^S31OVӱ+psš?md?V:~ܱۈ}*΢hvOy&y48ϢU83CYc̳ƺCE4{v:sy`5$xôp"qx-TJGe`6(ɾ󝝝8?..?.&cmsu>55=fU |C5c"{m CeI}ө88r>ʓ YѢ8sp:6LUceг2_ҿA;[zy?@3*M>u K 8cZ3Wu`l.w`Syyej۫y%%y_Eˍ2od%՜cí4~{r]ElhX^Kq)"9!e==7/9t لS/gQc3I\^#!$- G f<,`{v򎓓S.`PY ltG5ӱRH KL~8Z)*%%%Cs~W{~v@wվ"$I#.GV0/Έ 7n*ikע&HKND**x(\uG21D 3, VR Y]1bJ"~~~ œ?~Q c8m{7{^<5WpAۗ#KE6+Fѵ/)QLaU *P#xý4ߪlpP7UܐpUB㝗A|UYnoCIR,6^="@ ق"!6>d I7{g_xw_݄p jjSt sSYpZ~g$4JŧSYWo<{}o%GBg6{Spdoɭ,WPc>G&`do:;;WZyٮ*z  pyU6[F\<>bz^aeJb0ކs]SS,BBB(=4|pU\yJ{_A~XhƠfp:1iil> ?G 7C~# cdsk+-&D(<h%q1[3}|K 1gsުS53o yq;l(U&7T=++x}]wVO9)J^zx A]v-Q]Gc(oni"W>翦o94?0s© U2P=>8k3ӆ-ov^@LƋl{Lky/mW\>9LbQ׉@'뉻s+zXBI8-5:dqg.I{o>}0oҩ/#@d+;[ [U 23!Ш(Ռv N^Jjw/<4"#L4Y~Ȭ43 ~KǏ1}|1Q`&l-,*zY0|z7 Kh.xtvDD>1W-Dy/P Lk(dUO// f18zLu ߮1=/t {ߵ~w^B6RI==j`l_{WNDP ",tH8t2+{=h<=|Dr'z& lX=H a"cT>$TE#5554aT(PPqdn kEʹ?r|VL'ߊ7^B'yx$õ40$OŕA%%P-Jd#7sR餀)S$]\-B% 䪝dN",,̤^YGok0]qr߁9c^ .}Nx$wUC[8ָApB@R빽yev SFŽƈ?vXyV/R?wߗpӂpRDShllJς5,{{{%L%+f+C4a?["OwE)p سV`=`ŸmN$ eVO98ָLLLl&|2Ui~v{gI*=}X#4]==$w/VS68Z>;o5< 6=dߦHg?g>i[oԙ3nθF5K\C _⩸ڭ,./{88' RdR*lYmS$[it[2S@-᰽8{3 x"8b)MVƵQ(MGYɓ5 8]z NT#1%qS 7&]S=Bz TzȰ Pjqo^`M ~^dC 6΍w\.P\K404cVT_K2N7 _N<<&!!lsdo?3V_I)t5NvyU?hSw{I(,t)EK,ל.ucBSZ J.t.wfww:l\E?見Gtk c/H[wBCE@aX׏MQKn__OBQBCB;tޒ5/x$)q9^-fMu975rLwQ8\\/L?2bHkI*,:N(Q( KJa WDp^[OPD7 Cb0FH$괼"/~`` ZVN;RR ˺rMFεA1vbJ++WHx07>[xݗa9uQZE)**/gp;o Jq&)?!&# Ԩ`vi&;@aeX %i!;xG@+yf]**IFRQ';>2??bVE^^[[n*_VٷKP[``6 fiPC/>}ju`jb ҀzEE0Y7UJ a4//j/_ h@ܽ{xg6ZX4 &zfP'I"& ptlu1`P;C0T GgO}ёx 0(>,*r3~_E aaYuW7 'lȘŰPV(G]jᴿwgu`a#d(oOaqЅ7MMUNQ-(&F[izGWԥ@jg-v #ll$!)S(o32_jӎ rA;GFAJDbAJ(zcJS{]uo!gg2rI_Eqwqmn5,=Jb?R$ ,w#$F4hǽbY޳~ˬzfegST:eoWSoooX&*&{~:EZ6<| P ]_QJ.~"TUUr\=wײ9=E-W>;gFI?> :`isnArTzL, f6޿O@ _j(qé/')]Pܠ%Ʈ=;18$z@`  D+)/]`ɶD9Z^`aK~5q%5Sg&1*Ggzr*ڵW:]Xhޑ->yBpC*'* l%KKˢǻ+BRߡ@wVaz)lt#*(  Fb8I%\Q"U!| |f-R烟 w%0rgRƈiJzR鮏utw&eߦIƤ#T>dAޯL z/^w|10 !j6kimEKKK1a;[CB?|y %x}"veQp+;zz@1 YPHZqTy< C MHH(1(ue:+ah} l>T:m!-Ћ_Zz{-<6'w`   Jkfj:Hk*|cdB~ũ̀})aee5JGFͯpJzjj*՝;i'BȧNty;Ȟ{qk4%Q|+Y-6R.M)ioN5ۤ>]fHu ;po<`3n]Jixj׊%qZ)ywKyQ/rm`5챮,M]]>P;KSLAwf+y)լ>؜ZG=w-x^tBvs,2gٟ-%6?i^J[޾`3)"szqW@@GQl1z:IN<TWwu>Mg߽x'S~-w-d ghxxJLQY R~iAb窗aX>Ɔaǻ+ ߪlz-S}.yk`'ou|y15ѣ\+ȟqn^J>tZB_TU]/Ih{IoJ8ŒFG\ ]z'ˎ{?1wS`'CîAM||+rQ=V]5~ IG66q1L &Yb43ۣQ pkV<!8̓מ]˴i\40(g'6}WOH:@P _Wi"`2͝Z^O`| k`+;85>>>**lk;fBD\~xuu^==dؙ$leII<=&yί/F &80_s-ώ^Pa k+^~MB!#'c9ăhNC9HN`~Z\z;x2h#0uCpt(p$۳M(2))RPp(lZB:V&!0__kv'MMs%`3D+KW*w#/ -`[蠆XU3R&IqoN|PWΘoO7y"!\.WF>r_3d)JF6+ +"-6X5+amlRi)'l:` 3A58\C6[Ǵky+1^?\7ؚ* `͡jGղjU!W(qjVV< XhLػK&4iVj1C#8}HV8lp(Gxb^u(!Fy-~MaK:(ƜF`tGw>`yPۅ vSbo,wU8Zɚp(X^. لW G>p;ۖa[aoQJNAJrj**i}꾁_S谥 (:ec_3^ 66Ȱ]EPSSG c~W ;B륮+WPDJ%$:~zt|pؤ+eI~RQ,V7h]E-pYSIlFSK͎LXI$9 V1]rO @?2'ɀu+}y<X"kum@[ZHKxAӣ}iw.z˻ZXWiN`q&Sʋb?6cË+̞LΎz6' ']E90K0"[ z'MO©B5 &VY %*|vf@y{/ċpUC8[ |7z8L @0}8*;I+~KSuݑb GԪuL+DhێI #ɽ&T-;LZPCxY_l(=iʹܞo ׮]nn_NNJlz#D45`=ԍ{pd$ځztx}G+)0 /xH*"8-G<^QQFtd8zL-hm[%0WL:d|vڀU79;s1NH']kgVZ|DbR+N-Hjy S[ [n];{{ا8{sÎ=UMfmhZ__#- _D⟩T? ˌ nwI@I/ԃS"}@inN |8raHjwCf8?A(!#~2ePSZf R-ιED'%%|fXGI(]@̚ ,z28|x/* mzM55#CuX>b_ݸӶ̸3TβN-PF&%otY`]!`:%c`>ᣢ2-/p2Bm#<<\8^~Ӆr~Dł8v+=Iek%Fk[ HMe)eKHUgA.qfHLLQս3XX d.WA4O*GgtGj2α $veevA '{{J92)J$]~Өoy9`tT0)D1c}/=4|3U,4!![Px>㉆kQu@rssaTf0T噁3)oO Uh &ҀKΎwO D`#QlZW ؓ'ODDQ/<6F0rrE_=QuF|Đ֐%ffғ ܄Dh%ajlN-% <>=&&&6kTaU6+w"1bRa:n :T-`jG A_ >xw!Oz*XDϧw

"D;E'mNUtHXѼgjo߾X"fb(Qbƺo4wuq'&FG@'Sf>zDtY]fv 8"p%;h_3 \Wš"^#S'ҕJ.SkPfM@ M Z e)N@'"iگλ Ó*DF4?O5LL+F'vw[Ҥ^ȁseELLLj @`H5`zO8`Y{Gn3hPfv[rJ ,' $گ_{mov qHTt|`PEPř~-:9 0&) oKq;s8>?yޑfoh"p`=8n^'`RTZ:po}*;ug"% httvh Kj+S@f X8}gJSkx+o"#Mbmm 3P.!I|eJl|v]ٳgWȻN&ŀ}]6HY>iH25krYJCIxyya_eC8(g ByYJ#~K>nxA,%g N{**7}8$&%>CH}Lix ڲ00:d="rG!5Тg4=WE ],V5r7eNހd']$ځ sp*MP JXLWQbd o]FFAt:I6]8c9ڱ.(VA`*Or ۩Jʰ(n=0 ҡ( / !( "(C( t H H(!1 !%tt{xwyk}k֯J C?Xص2pCZpn̅0r&%Q`oⵅ(o«EC7{N:::"rLjC$١cX0Di;]9(\@>o>j#eB{H2|?>B@U[Y1ǚ(clT;39d9#Sz=t Ch\1%A[?R1&0m;я6 qWWiG+b{6j;#s1Wݸxۡ'yXb%ONOpea>CD#yC:9K X%%%햧ù&CͲrU-gϰ07xKTmw wTUT<%⓯=5ݢ֠RchHK9oiijS7q{"aGcX З `L?]O}|re[$XI8.L//)<쇒4 J ~_J+XXHPmRRRճܛurv'?l搦&ek1v9u 9aA|7.r*/A__ }:iueJPpp 0={+.eԶʃe1ףmvc=]j`_t𢰙-.0. b_tM5 PN"{meu VN0}V+uZ`w!S54תI>:s="&@Ƙ_PkG^w:ܛ& b%bPF%aè^m0ʕ+0K1\GbS`:K uH.2;;;߿%zY@eQԵ3iC `OQ gZ*vo0?5E 5;X²o޼AG`+!HddDSByI¸+@\zz}*dG4\a;z^5ONcBDŠ~@HM6%)#! uqť|l[X3n&\E'*p8AX fvڧ0۷LxDZWwӪɽ[ o~z06; х^e&&M3Ng)~5d&k)bv񛘘ȱ~,ϴ}xa l(ТpZsdH6 'NBz%$pDƚe4 ń_ؠ_lmLUB>dUF}-ܢƹ2–f0bm!*&f:\g/iͯ ?  P[Nu^i꿨Ϝ߿sC@|x͓ևSSS""Сj|n.^E*OlПH@Nq[/zښ>E&:-L#L?y}S:joʩiiEjBPS, $k*tOHuUDdPU=<|e RS{¦"kK--w(XR{z~#UQz9{rbn ,\YRW¼`X& rm:TfZZt<$SsSfey aeZ%Z <%/bElas %Z 407ɳ;0wjF'bGJ5`Q31рk Ϣ3@ xm= >OWxy5x)WH+AUp%nb{5Xi3[QWpY<;fǀSHSbK:@`4!|='Or/`aV^.dnlE% ޡ`%j`HXac{#: iooy"˳ݑ׵J}1#>⹃3"\hٹn?dsk:q-6ڈpo`Бkz Yk 4gmz5ghzd J @dxB& ---= VVqs_\Zz/Hً^]0 칹fffN !phXLIJ7ђY+ɬq) jA1?< N)Bq Ŷ}n+_ [>NE~S^r~N!vr+'iHEf쟒Q ^{GW7޹$_V؉ cC0xi먨H/(=Js}W_/[FSnjl H`2pggf?x9Vd `qcPjzסjXG͌wil%:kTw׍mqZ叒{NF`;KFu|6\JR |~&3P%Mc@a ՓErƗvxUvN75okggsam,6cm7ڱ*klTp(a0}n#}2!ȱ^s_wtgϟAJ"FH~[35Tc,)4M7D}$=\eܼ<~=bA-n_왪&C&:.K)VXݶ=y }C9_1޲ ]aJWT7O*wgfߴ i(S{xg',s ԓ,w|Yj'gK" "VNT߱WS2:Erpb$/N6TK_aC8=Pʌu"]A{Xd+?oMN}a ,̮JtZz 90X!uQQK64Lz 3j"xƇ$O8ެ:*0üZp3'bpmgwtXYw˓gn:9-&]HmǛ|]\?sY/^w eH9:XnMTN-oZ:d @ 97!zvcV@_{ sW I(M=?rB } ޺o؅E?i^oO3j Wxl^ϟQ\0Rvx-,u*0{7fSך!fC ybF<>n:,wcQ eFl.nl?ԃAXaI gz_J*f_-hom)չVk4_"HO{G!l9 ' n0)07O'rshPS iHɩ3ˢJ#7oh`](T~P7IG/k9K0Zdg@7dKQ>34a)^ji?;7=ffd7Õ'(qo%&E0#5bRdk7]bbهgh9̘DEsJ3nB7hjtZ+Ի8JJ-~{3 djBi&ȻJ[f\mդ:ùOGwSUT%twwk=&x/;B5YZ!x8CtP41q;% hP F vvM Y?6yYҳ3$fy#aP?'KIyxEs?+Z_+NJ̎\H%N%7{I]BW(l/ݪM}c=5OQVU6Ӻpq1+2*jr(켮ѤG.]Vd ABLRGiCIACab$R_L$keXjw8''߯I{%t)=s0_?Zȴswr"2q  Q{R;F;Ӑf:>/GQb@ TkHq|^IR|XMeZ?8:{6AXL*9ҷH6Ώq_J. 24[DNCxpfh{UN)YnBԍfFX"/cwTud4_騭 'uoއ/kXak$@7dNXxݳ] J$"YV؛edɛjR6ڗD]Մ}M_W *OUg',7oGG.LʩQ[5Iqr|K^fkl+짢e\RطO쏟||~Fi$5H%Vy'O8 fuYr;0%r${BFvb6q(c뙠D^y򰂅ǣ6~7 ""s5OiՔ]x =ָ`ZOh”r5i]Tԑ$!w|zL%2#m{6GCrY\HYL--͋Ibp>e&4,fν]ȸd1;GUZ|gġ]s3)Vu·(‘J2l*\:^&Tm}cĬ #|Kզwx]揷X1 ̮qWa%sk9pQA4I+KaGr I`?_q_ 3Iw6kzKRV$b%`I$~WIify ߬$z-{5鲚f?,x_?f[ݒev5f.oDgX2: pfa':sN(dlJ5NY7vD~Xl.Ll)t[CͬR8?]9ؤ#3qQj8>w"Kl+һn[Ug̮G%n4kh]PO-.$jɉ%)O/Q!pQ yi:ճ2@$xayW# 7MW?΢TWe)NJCjh:7bݰO#UjCK "K$6$!n?*瘋xE8# DODF`~E#œu ؎Qe~]8DUx:> CG7ROOp~ldiZӽ(W#12\C2oynsX07HC8&K [W#,)ۜc~FUX9n[f3uc6l*;dΪM60?]%AdprPUyhs-PNW)EH4ɡ/ф?}4''tY04kIa2ГQ7[`}:yi0шp(Ry܍^[3ɞS{ɮR "%Ă[l$N!oB WvD7ejDݣzx~V'}xhbE01 S/i>mQc?3`Q'[ }ɫ(ݙ ZE#ngd]:]8&Y9UdQI9IZE^N2#DJ)0fv4/:Ö(7''ӟ 3y)*=ȧ-RE֔ۜt9B7–:%52ӣu[4K[C߿G_j҆Gw5T ibU.ve0d'Qn}LOPd,kb/& V =KLL˭pn=w*[-b#>B$k8.zKݔZoj]׍!KH 9qW(hC΋b&O8R g}1(L7J}[F1Ol>sѯ0'ݼ[VHݛH+G i=,H F. Ćs|6pb( !&*^ʪ9g1TrMb=1/ZD5@{s(78V$D~@o@8ɷ5ȣ9Ѝf[׭<:WmJ,C(I32(Q/9cIl?Vx:'zgD~@BDCԽhkz6oF$T{iti~`Yk| >,46*lHHoZ\# ,XOm5܇ .FeV/6\=\UxZVK@&A%<3ZS%Bf3_3)Sq* Y~Nx}eAߢ.5[ؾ{yKk g@yuQI)~0Fs #.jҚΗSFfj*]E?FkO76}{ܲV7Զf+ z7òQG­7Z%q9i+C]'Nyܔwx޲Μn}lRVA/z)Ep^Ic #XN(7|"|i\2E?m۪Ԓn(8Ns}H`^ 3(7ԭX⬹JH$=|,lǘAs'VH9bsZf< eqސ|13KK痧&b3l@"Ontɥ+,>%.CQU{e+;Re6j2OQNnߝ7_eF E}sSY5X#37M!e)RR.aeeKΈ6ͿijitZgf$A7~agq`_ݙ 1i VUg Û/KH$sfҳJg|݌簔d5:Q>b`HmȿYm@|‰jyFW6-S]Qֵ6ڂ" 4\_XF'P}M+@cLs=TM\zvyqM}~g_gwk^/iSkDrPeRΔ;py-zQ]J][iYaSHՀe2taa8\Ta2ٸw.weEkK9F\ E6_(..fO SutT=u}x5; "J%tMAG6:_-Tgd?V-W3p#iY=1-l'FG2tT[ɋ|Dt]q,'WfC4_Zlii3P&!f.ovs'~+`l'8m' UlsO0`h^. 3Hݕ 'pHğ?kNj$oiotww:~R?F'ɺ.J?} tǁ]KrrrU?~<(PVNuLG%$:U8 H c?E9l~A͍\8:c>n4y\6 B_Vc(6_ǡFFl G$#mwkEDk5bVD.+I ׂB[RKf|ԟz|i?&ESWj~3@")[,C63nKʔLϦn%$M\IF(l~BDJĤ&ܩFPx̄  2Y[[b*Ɋva݊D 'pl=hkK(9}vE۳89"-]$-ƥeAAɒEZ_VJ8yrsrҩЩR#AB{-d ?BdȎĭxyؗRH10.T*``M.BΎdXiU%}B"OR{yB,GH8 e,v =-Tr6.BiV:oߞdb"iiT{Qg+]a!}Ȩ4DN>NG #mzQ$_!+$<9v%>sis;==>qmvkk\Dq|)DOsZx{fB k12,?oQ\Y{7x,nRە &;~=uq @okЅ3-5E}@u fc?<5 Nh܎ `TđIffܻ0QwR)%Wb/./{fg QH;_xHҌaڤ|qbZb9/gZwXrK^3ALV+ŭ~pqu/Ѭvu16Sk[u;FUKݪ웵7i~}'1)Jmt[+]Rͯsk+̴;#MxoM<ZnH|0AYU}ka2VK֋<$$Eqd~onC\lD%Gt1Y8%Vlaqdt2lH 0i۬0%! Y콤, Q'IS! h't|"WiGtYԽs57*y z [f'L |n'[OgVgi ʲEb/Co#'6ꋛz7g\mN&ߔ <#ljv=qo(VZ]]cU*cylQPZf|ԍH}"5YjٻpzɈo0OAJEv'CBX#ё<#Pr e^mڑ D~ӺCV#)eemX~J 30bmmn'_ʥ'O^86$Ѓ-8Y3snuu5jl6Wd(P/*f Q:w?95qD5-ѧŨąs _ӾCk;pÝQpco.V 4D^8VRD~TW? 9fL*57ǔ,ieu'wB ?OLOM=WIt>ˠR{m.* ҹ֕8'&`'j| ;ϓΏX5##Gϯ&LǭƦ ‰[լO⚚ZYi67<Q9 OF'=kd`vJu,ؕ=M;i#QuQgށVGGw7FbxaN9*EzR$`K@a6N!Q%o*IVNm֢fX+v˱R@&t<9wEv~,KFGą1dKr%q:=#Qgf ykeJtޯz1xj6ycwї._ՃջG~]t˫JoW.1KhNqݯF{.­[lļSTBPU?ccfWw|ViձF8L }ͅ.c\ ӦR<:#?ݭQi NCũx1N'g)~V5n7ppzv %m+mP~;2͝`Dohv vaCn=!GQӎY0,%q^UUd&\7+fA+#%b#W?yʍ]! "֡U56՞?m$&r! 6&TYNtqT7?(&V}< ~>2Ҝ%s1̸Oӈ H^v6Ў1770w÷clN<<y=100 O-ƕnnnJl9<'Oa_ 1RءPR20T:b݇$ KL ЈɃ=eFoF. >x] ;QȶԆ6$IJyPˎhii{3mPf\1ب(7A/kDn3lj^$dEm_wewW~X:u͊' nCb=$V:]G[ajjeg""->Cxs*xi 0bط8GCۧA3y*@ǯj6OL$9`>NOZln{-TzOTuS}yna[m*1W,HOٯYe)V^O遪wקYٿ34UqGx_-jgS519lOI9RbW=;2A;ul嚤^Yjvnvc.OCos4``hKkk^M>? [Y[JDD` 7i|xqfJil * Ή 72s" Q/O6vΐ_+;"z'˅p\آ>|QD>~PнIt<77덍/yyuVVVssh===J4l yLP2ɷZh%D\8Ldֵߺ:W37zJy|N*{Ǖtv}GÆ_a ?ä54pw q|Lc _Sk=`hd !2կ !K170݄ jSѼ]+o_{{ p]'=W:H@Oeޱi뒺3S.Pw9S7=4*UX]V"=]D"W/vxOQ{P2ł_/]7_.[\`6Z 3^E{(MNN$W[sT-B|BsQ^obULnM>OajީRx8ǶPё% {>伲D ]I7$KKe]NID kv>؎wן#'?RAKE{uR2eN2mQ#\,/]a("#oUBřԹcف<7uY?VQSB\(f[q5%-UhJlB"j-k)%q:*j[HvtvfN<8}s̈v1BW}]cl:}|w{&68b0LKj2Ua^AˏPRL9Vtq;\F_],Xq*-8ooI]x6o$]53Yǔ:f lX^Si `ag=g"2.$^.zGАh_{Yz3Wd l8ćG)w~͚= U^iyjT>Lݝ#URcDՀ{M!čtD:NcUV =+7IwSx:FeGswGY" ]w|:2nZWՅf^}15U#qe1@όk~:*k&M[[y5XW|xT,k?y<D vbqԜdހa_l%[hN}))^0IGg8ewY s!:;kkk}.`O\O=@eEW;H?=*ҰdHe绳CN}έftF) ۉ:??iGӴnv́X |TUЍK { ;=)/a.'FI R=/|:l2zoA e^v_@TCÈ8qfwttY5^)'Ց'r:6<7W*sFsr:g6]D]$mcKCCCҨ~7-j%`=?5[hLzF)gFgFqXCK6S'Y>Oׯ-ݑTeדaO5(15~zٳg,>hdll mm>>>5kr{ .iT+C*L'JG(i^S3H`yHyTih~/v{R2Ҝ<ƛq8(đءCi3!IG.^T˱J([Y >GKu?qxb;iAA+\Sd`=,Q 'tZn]H&}"1E0cWrw&,>'?OPYJ3i:gH tWB71+8i# ^El ѿ2`үG;Ro)98$D?2V 9*q  x.a6z0{L0Pf q'z;Vg,:FFʦz܎.}v1?M[sovOrO '4ݼ{b}f/,)o7+`c4$֟iֈ2v} +d?VTgo[NӸ-JQ-')?ЏF Ӝ/Ekc=AON!z )«l7-o5.lK98Џlֹpt"%%E%`  &Wdd1 7@ Hh8W|'P\ezO-jVqj//SD%$4er]doa7yA6Ǐ̡B ])7uN;%]ܮ,.'݁kp=E.1ƍ $W2ǁ/g]b3Y*"K1cΟyTz0Y"DݟH\//Xg`vfڍ`Jv؟/ Irg. pQΏy\N2X,>}:WԘ#&)Yi}.3xfFLL__:˄\e:;g%}yy@!-F%SZPppAQPbn~|t@S2nnnF sA^ k#ᵘ㱰 ٪0=4|,G6K,_T/BM("01qq9 /K2SSSb9疲U subT.&9;(!_۔<_(B'F@'̆$ަ Fu fTJ❄;oՂzRb \",N3{DbxOpoJ$Ƌ*¤Qphb|InSJhrS5WvfQ{8RKrr=ۚ-6uDn&4\%p5HU-//R$jƷo߶L?夦WPPL7lڴ gZ*J\Xapߟĩn?&?>ի=xTcwH[qsU^/6ad*fWIv%Rh 'Fd662(& T<`#,uƘzǖw?-0Վaۯ%FҀ WkGOAsyR JL{ w ,C G4Xt{SsO_9wqMfnݬB͒DZj"L~t/GF|)DAEm WcoR8u?mm591pm0rD} |ό pQTϟ?aQM~ c,fh6평y6?$4Lq:⊖9~FEE5k?~̷_u>_~RRLULj+R\N9ݯ~1sx,/]cvʊġ{A* 32  WE+EDޙƀN+3,bYOLA, +&p*~QK:|Br?IaуI\8'^]}O_J?#5i;M[Ȫ{s4p 1GZ]7ۮ}ig?k7z| ދ/iz,o'iv?8=s,RN<2+<)ra>62]Y^Ye.88!4UZ^bCL!ahepu?%eR}1LoTg3)Zlv[D\z```֪ _fX@Et 9JWUJWd=R"G>,jТ2Ryd3|0U؁i_q:Za*Clg.AϞ LhT-TyrǍ|7--M<䤽7xPDJԇ꽛.Ğ7.Qj3 ER|Ā%Y= =ܮN׻Uqs3+v+ SOo1W./ _4JAߒU\Yi!xf䴽=_Xkp?5?YL `s9y Ax~|I~i;sX- ;m[m@\/89ix^-܆O1"ht3M%;\Z!"ف$:nnn_BC+3J(њ+&4z??BTfЙn}aPdv~o۾8z.50"9g;`㤧N{5߼YLeyΫBWn8> 6h\8;胚fpV")\֪I{L%vy2hNP>2(^KgI(+}2Xn]5kׯ/c4V45YR\ުVud9aovaqZU,cG `s;RRoʰJK:pbPg*a8-`$x@GGfy 31O҃AA|A\W7ͯ<& LIUG?eQ>#7ndHm5]Z\o,qpvn&ifcX*1SAxM}сTM>/pgO(E PK2Z(%=~4Ž=tSSS&[EYY) }}AC?n>!cސ!vbRRZAADa/H~kk8A2j_}#_PGQ?W>XBM^IST*\ Hl@64D@l$ߗ!:[K%[%UնfX/oSwcۊVw #"V.WD/qb Yk\PP!htT^+D X7oU _%op#&&M@4a{wo!R*| /_~R YPTQTޭewQ$ |: ,|ݯϴfl0XRG)f|D2'T?c m,F8t*tܮgIID/>7,v91ߣ[[ZȾf`|t`I [)};y3ET\ky%eNA]#UQ%ژ\{g'lx6>Eϼ9&_E}I2[h$R4[hޫCBAi^ :ٝyԗNp8q(ЗlV0zKm%v2͸>ՊE$p D@tShղDzJ'~sE2YqPYe@gîZ_,;Ǽ:*?bx2Ja͇b䤵eM D)dD Y..V[ngA30`a띞Ko_n.T$$D͑Cq{`v~p+DAA Z*kZ큐P8=_"b2@,[MwE*tvAUjQQ,_PUv Z!1[O[N7spp31 zx4ʰV៶wuZ[[ @lx?44$6s3UޞZ][x;s>\ 1㜈.ۚf j9/VQ-Gʊ͛7 OL(hj^GDNhzzP^g9Lß++YPSp$O6== ۝ bbg\k*8d<(:6AB/ 6OkO 2O*kͱ˧-SSx`qu j^` R>2 AdB"u2j9*1uu@%Tz `qR~_?Pn4!q RuIÇ!esbon;lprFrAwW@&r3Q.S*ps:)VBh[@O$x)z)|oNlgʤ*"00%AWKGXMk~/ˉGH`a!--{|8v(38XXZGӇ9`lG/2~U!~M4TI0y&(##SF_KkZ D @D;8;VS#lB28KkkYۜ^[g9|ZZ/8vD_~3T#Ʌ:P MQ1{Εk;n@ˇȃEj._4ȮTĀV~+xx6 K[G];^}ٓauoy.<{(HUk@l|Z  /Bll, Ljg3"~1֟MC7w?/9'j,HVk5550Z{jIkݝE8Џ_ # 17S?^،E+DHDxnKnWS=f 8q 4u>DvXHI ǏZff!҅=|iLq E_nW{m4]ՅK8dnWFaA|Y$<@(z]m ӃL.Fkuu\u%sziQ8HI(vիvNQme<**R$N i1OZjg䗗FEGרixU*Pq!;MIMyaZAE^=h| ݈[VE.t*_/ t;SR[4e }hk'(' `?cIVK q)ݹ*/̟KHy:87GPى@@X +L 7{0NκqݜtrtCJRS_ܹ7K&qlvqdXI}~ 'V E %y?iЪkv;ҡiTX=OSAOAGupL /Ä[i_)b"fd<"2'◒"pů9HjTJ**%%9Pa 02>566tqy2}>gSy X Ohc2rrA|aՀeow@ hVr A=GiGLU.gs)w,U94<.aF[ c[s)RFF>;UW+! rM~z2\+5u2vpkw 5T<|[7r-f@c5^Mg&e8bTjG̮-$jxLF_ONM-)X\Z*|fvvVeoVD3 ]R+{k;#͉ZmC54 hHܾ?077Od]NMf`>؝wz c9Moip98Ix#())?|x rX^15sNYXũR)$q\66Ŋ ^z'iiibbJ.rm)?jq}啕At$"M(|)?z(s],;.2Ըqlx}0= #lE@҈X=>~JȆIKK{pRQYc k4ࣣ /ޗ/_>18he^n#{8q|7$YbC,EE<6?[c 8iJD}Eojc٬M6o2خC~zK@pm)."'ѣ4` bbb G)$Eg>ML$O~ ࣑S\N7*vo*w`|O=aP m#0hwbla)=^6(~؎}yqt/e8AAUETtkelVZ>U9gr &~D* FvuuEZ_H> מ:M 3V^DH,z!H,tkwH\EaDW8|G߫B(J=󮀍LD [1DW8xpw~26R?PfflH=BDߌ\vv +NpP7I3M-yM29l ~E~ \~%<\zȚ ߇ JesGGM 8mBTTX8\hFd y裣#i9_!tx[s7u!S{sb26.ez¥eeE(TRRR-3@KLJ(%H%e.99R$@]oLɠۉ=:h<$Kq[k_¼?8轻^o#HJdc3Dtz_xN2ByZa⪽BsR[pwMwWI)08RF夑ȠzL*H_e`h}_k?ꞵx>w 1A@xD XAMV' K1NN94's}wfj9k{ Q(b!$asu] -4GhͳP!  ha7 'y]BP D4d]"FshE&]{EuE+0,fJ`Z``^EEt@>Ÿl|^ e2Zݹ%QР rB>w}@խ&G6nԠp_r21ȮK{{1Afnߙ`EPW7VW~i!y< ‚iJ/نKbc2IY>Ap>APd{"|a-+ P.ӂMqoN%?w6UysKK ,X =!4  JWOy|YA?~"#8wVWxlqD,i>Tbv=k/7X̼Q^>}B/]ߞc]k Ú[Hr0C ۯ7+733[ 8<3CWXn%S?xȐ``+uTcYP&`1b1'@Ъ}A9χ@Kp@n0flNpT@PP<h$vn͓H P1@J@W3 q{$llZNf$nrHp2Onv| pU%cʧfUpuǾ}*{<ݿZ>G$/Ϲߑ%a6:=9ؿKPcksB>D91op=sq*<4-=>P3l y4q*ə[1Seu6kr M p#~jdNWW" IC *Nﰣ /=/BdB""mIBH>i %;(gggH]Zs &sO9ґ*9bBz2Rk**Fc,hꤐ$S5h\* "@`kkkb0hg&jI*A`Y?VQA 臙Jip4-` zu^Ŷ" rq S·@_plΗ쿺#hPQ}7&xutu%ۗqrT[@0m-4^G%b䶄Tr#2:|qȁJGġQGDhP ބ5/-=$D<d{fim SDh:%,1񾦦F (?lz%!c"S"&C3Pf/,[ |TT=X T-mK;(D)tB1MJ(b@@A]mAb==Ȝ{B>=F mnNF8JKX1(((@*9X1 ƥ%- 7.6>*ִ$&/n̢KJi 4F;.ֽ>ZK/XѴZD r[|.i[ݦLc(6f҈驩0MLv!/덡ʕϳZlp'F{" {s^{Wz0.w`&gfg |7v|Dwd! ӊtﵿKbU==bU%%%vOONN k $ʸP-#Y&''Ak)P : h/!!MM~V313cUVVV:Lz5^6hHhIx"Ќs@Ix݇V2-bi؈m]qgQ6{HӝS@;>>OOM6BEBG;G0bMl NYrD IXIj11"_cI  @xА7 Gc<'Q`)u.AM ]'n;ظ :5\6_'=2 $KF0&75{dr٬adPyqS!H3"05/O\@Fb*r7h= $Cum|Cj  a>z&M.6>YfPQ{0PU k1 Ds{Gb@! =X.*db:2H :NZ0V80;O5$Q!{p{w||\b6Ř s@2.wQ]k΅Shb.lw W;e@yHA@Jy^ JO!a oMV`cgo hmå>}ݳǏo7p &67Ѩg5,ci9x (앗5U䣍y"ƇfW?V@OhIiJZU@pmӳrtPNK27Lsiߨ13Eb8Tx#vE1Iǯ2vĆ} &S'kLe=6B8 (V7j$~.8 )V]QzРղ\`('ĀӨV]WL6o)H1>~{g,_~cpHHїoKmٙ*J%J!c]ߍ`NeB]ΗOw+XBr$kzV.z49ҙI2%7ǃPML$s9G#I⃀`yGbn}l9'_5==ou:.W$y7%s흝PHTO^ϨaDchI)(3C&@1(>\Ps LrFƧwwwLqFy@cdVnl4u-bM`跪tM0-~:PRm)l<#]9.WR…8`@Ი!C . c}(=Vͫm *,}.R?#A,"T|Y}0;ᖱ1l=?!PI* xwW\AF0(Z Oq]] ^>} hPSm,$4s+)H ʍ='XtoޓA GGGCJ)5ypC@"aǃ]~(cam~UV ˵lpɉ֣gfACII ##+`9_ ߎZ_?1aŀAff47Q .0mKk C丧/X1vD" *x|?C S*7z'; M$ g{<\VoA~5)L {cPW&{ؖlqD&/?_{3G%O߼ɷ%;82F) `LAAAdw&X 29 T*r4\JX> "VʐRBABkm\߽z 0;Ci ݕsC! { Mh4448(uoa! :ÅE*j]aDq) ج^\mӕxҤ@I؉z:Wf2xUϐ^YG\-\GMH0&ַ?5GGuڔLU|ƒU t7 rsl`b҃N͛78RY1EUPRVVN~a.Z/KN&sk4GQ⥈SZb,߿w>k[5&[YɂHz!4!sL>X ת&l:z*;RWK *܏_};v} "3; 3Ew19̤yvMI3Ɵhz޾5V~U`jv_(#*8첇yܯF93y~啐@ДHqyaR]7<]e+] E%ho*BP?gC &IvsĎEF2Q@!'K*$V*uH3DnuL 0KIllrUŵIAZ4Xd"'| **aEEt;;;1iiiPN)P>S@r͐pa@CjqkaIIt ΞQJ|Qy c۷@vz~w_2tFQqsmv$\CA7{ ̉Ccܮ,BdO TY5TvwpuOyrvgTHv/@#wm&l@G<!H'yHZ3e*<8Q_>=7](2U]JJ`cD@&Ҩ~f𶳦Zߵ*Y]]vRR UlfnH{p(#www\sZʼn(7`/+LXX9997~8ϳo%]_mf@ef MM/_2h %%%&E^'C[yEZs_Ybn|L*wg_* ˹lxX~Y13a!++ dЏ]H0Zn4LP!~ݧ(()=G}Bk{DZz#/$@tt~}/(b* Pd2H$'% hp{{"Vz8xz^y2 5*::1?{9rH+~]aHS3TRcKPA.Vڲ#ݰ?Qle_.'/u$<=q9h !Ĺy3_\lABAÂ&@RZRP&0`D A,:;S›-d7hB  F5q]˴SFvC :i0Cvv* hL]Z@i&}-afxMz (hS\}!X1}X͵BhQHJDբRllʔ$3Y*,I8]N^4illQ 6 @$xI(}-)a_6..RB@0}ҳ 2{ K2d y.t!jJFFcBˉLzTTTǗk&++c|QTTp=P &iin[aa;`LO;Jߜ nHIWdz=atJBmB~FI~\tVr;_YX bITS6D*?Iuvpj\t˪wTL:PI7 HG]dlk'[fh5!&뛬] 0A` R;|3EgWcQPP2ɔS,I` 7 a4007ZGfn4exX&3+lohҜ48 D*zS8^7].+ى;0`SbgKPh=sVL0GEʭ*-K OU\ۢ>1114E᎒ J7{g~ڨ5ڶmAU1NጛWf,QH&~:[H:LJjorfK MzNt׺U{f]8:mh)`$7 @LGKIᦢќg4o>y<= ut5 } )***V66&K2~| 02,$0*< eLw HCo2,suu;oll~/s_`q]a()Qߋc5kyy J *EWr1PH eOAto1+į=QԐ+%%%˪'LNNaYtoo\]հWџ'~""7̢k{B- 7yzfamo_mY J Ѿ%" uكU }sb:/&҅C?'%\BPа?w?wzc{{"HH:͜u Xf2EPk1rlj&y h-)QQi{iS4D nH<칇#D5>MxwnKueN6tXn2zç,w$r48PAnh``M~.=4咁lhH*kZBJ*@G)9k W ve6;&$"{<0Q9 Q@AFyԭ(jEi ]W]]SS@2h=oYjw>,הԳ>3W߼126 ݲ,8gX_>| /Vqz71F'+a rޘyz'O胆D|H#Ub :Xb8vH^?G, s;\~o6SݭTiwrrrQ~wwE'ZL!PWv+&R32'C'##cڃ rO3]Kph7N1~'-ĎQ`bCO6Gc`y/m9નwN▵v:]_+*CP?B,$p8m@E`ӊcrǠ{^WG+nVh_{+,5;L;Nw|1<G&q).OJvT"╌W~ZH%ۜ@REuޤQe8ȾWd;3 =MaE9M*p-&أ"&*Qذ;N?c"R)n} kovO33R{A7E 샥x.&" dMq2ҁ &Օ)~NK @>&%BQV+KK|04ذtgF6%ngH p,]قF `X;HA؅ qK95'n'*..$ @M]nCZHHHTc Q!g`#T\zXi+XLDD9c\L54wuL&Cy*@zHC "ԛm>Rhikx\oR ʊeF[kͫWHqٕ[[& w7rJׅUU[=Wz 81.XAÇ ldz{c|!"n0y޹%ջ(kF3aqSy<.=:^!?\;S%`8?GeUUmh#T uǂ|-&#ܺv_'/ W=?Z3/ZlG /N {t p:(G?2ԸifG0:$E8ەSAx{ U:賳j) ӡoô233u-sīᥭ@wh;L *˦18Os՛m0̾PQqH2S 6Z O𡘘&A0WT("6o[SA\Wo c!DE=dI+/qQ WZbz|t*:^OS^^ d[YIUOwSu$jk>v[hl t2uy"n`%8ex\~7U2-lhx?[|dijaL;g2HHoxyI>VK,{('`tʽOS])?=n*(t5Z7vsU"+o@ M` ߞ\*4(zm\oh^[:G醬0jUZ/6YQ0Bh:ӡ j0f<2"^R-G&!*hN: _IJ?M !T]!0~p4i~w.HM#s6dX`_{::qm6;KmbyMMq3zPnX~RRRBqqqdPP&>56tn|uhppE߿~sm2>e1'u5{jBBk ۟gk| 0obN\_]0XL63\ExlbS' Mqqny_6 Nue5Eٸxx62F"4CUvafFLp_ƴ4iz:#dkl*t ???.`&`ԽB]*WͻKN;g1kkUIb)u=~N;i (<I_wGdR{(JM{x#ઁ k !R븏niiٽ ɉ8:>^Z]}EQBZPAńζxZ]@m|:mlJ\^ q #C]*ovj~UĚ 5*+;;w{]}IK)]";~TJgy( c}_ xn\ApZTAh4aF)\cdX-ۊWБ밂Y8'88΀|  Q+`mOF9PA&qp`YHB<kc虘8}10<Rt!MhzFCYUv ,^'Xn@ Ъ^8~~~]wf {rsu:~'r@BCÆW !!A%R*hjⅆ&geU+'MX1G͹Z/s^]cMv;JW:8ŋEFGooֵt()H)tJww+RnBS >9?7ssk E1_rGAbe<9=fs7#ϟ?Qд+"@s&=2(/? xތ8%y'Ffz56mK@@ZB"~w>X@D;I=tw¼llT`2$0\ꐱ Q~>%bҏ;0oa_^'Z^f4:geccpvWHgxC዁2|h22.%+WL7?mwbۮ^bb% %=;*nG{}\'#JERT4м+YE4?yzGx@{7C4ʄ"M /^%/&bm&eʽk?\;va}ܠtj_#hY+޵lJe~Ub \60o>FƆ~&%xGQfi\˛&|F_O/wtt tpjq~<-Ia9C13:;JG 9laܧ Sqn?Um6iPPP AL1wz:ӯu⒯ VK⁰\__KI(Vz 끥UࣇOG8w i]֢cJ&Al*88fκvHv L |z]@EadF{`džQI k-jNz5!=eƦa&ߠFG pEFpæ#j2*!Q54aUxL ^Sq_i/#Vt\ItD3`hOMot4IںA "aLͶef.0?Bw~ )."ff_{&܏)]Hׯ_|Yg| ^b"!!M;/\!$w72b@'ʊܟ 9wwv?^I*$5I7Btv^(6ThB/|lR׻Č lG=ѹ \-Oll,nԞiordz(fU@5It({R )&-nq s`iTdpĕ JЯ`Tm [xT PR eJx9X ^`T]eHM[ j&^+( jWt!d>fjk rI 7C[M8 c̆ǹKRrQl*,E+>8f_VV.@FϿɓdJ!4} \Spzz:<\h0q0.1n$$#{ ˳p8 :J%1dTeci^%$*Lb:s -tÜRһ´%%U@"S]ͫc ewSc9iːQK(Õݏ] mL߽!/yѻՉh@hY<yᅬ2/[9zEf8[*HwxY4/`! `$^(3F*\1n!mv36MBYYY C䀉\pd;+30JKJ&HwMLP#+))q2ښ~ǩiD22;RFV-2M=úy󦖡! ^h @8%Bt>рg+.M ȡ3V+) .SFH|,)gޯ0inim3`mvs{-oS1b=Hn"DM_3 qg3oڅ~}OiHEz72`7 -6-aބ>y=Zlz~#X bvw oOohU?1P>6";w5ڐ ؜®۳Ɩ9BZ{cRJ?xg6.e$ȆoBmn(99lHDA:먇xmOJbXC,\\(>&;~g .;*vuso೜ ._ =#}v }0KD#&aancI}OOF: WOX4]CC xԐrٵDzGEUT4AnCK>C` ӝs)^V Q S˗wsř%!ߟj>5+B-8bM:$cC=mȾs2%ҳOMDQ\8HѸ] ՟):h5հuHN 8X$ >h vj;|/ttᴀ@/(t:>9p??'嵤]8>Wn=ICℍKp5q=c6dĿ4wm6 R趄~7n9fdxU#Ql ƦNF\F"b-<-N4v-+S7<{ < XLwZ6Wc^|/H5]KIu>7_ ݈NPDP"98ELIAj ƴ {au?Hbga~ʹ+Mx7ᒬ*f*@3kL3/²wVףɌKtsZ %,tOuwx(>Ha3'NwR])F\WODD67-Ov\ ~ (}ppAՃ _ W^Ju(A@AY@W8^3嫲<5NQhn7J}idZۓRB^;ZӍ!K}1>%_ m&NV"KHh.J86d#\,A,OI^_78?\isSPMx1ڹZɣ;;;̌ =&F6'2L +GdEYL線5^m\b#Qtuom$ [jB@kaw)hva>lEW^]$n+N :.UuJ~v:UNu{en tLM‰uظVr{g=&=o<{ޫ#Y]t+9$qe(h/ A u&9l*g,̆pBi%v+q׮]W"F^l2T7l0𐭙5 g%^y/a 1f?caOC neDL"M+?Y8^I8J(TFw+nMII .dm(_O6cAlDv.kxXg-0(%+t;'tyP'?z *Zߋ+?mp s?#3imTFDpv̓e冃kDMuvirцO}q^}\}`:W84+p]_];gNŕUU+_2誺!U?iL8o[IWg@%AsJU8t}Kyaصf᎔~}V3/H]Ax-h7k6: aHj9 RSa @}֢޿OX@.PmMlCVz W}%℈=$/ rZuPIdŞmh wzen% `qUUkkb;pb[y^mC9?Ij#q#TmPVڬl;Å)3 ĥ:ŸϞߨǨ8fnIIWsqzMRnщb:'y~)=d綧Gv G͌w>PUdž!--+(Il&`1ymVDNLbG]9Q7Q|كYkBL4lOhU ,|!:iz=#P$VVUJ%˲BzedU8i_FM-aygVqP򳳳_:ZAh0 EVWM ?Wff,;uuNQ?U-Ɔ!`jƏDGRCybGg#aN>5!ǙNf>5}orʪbSe"V8FlTs:pws^e[L# dN2~^;&&f-OSvs?$0'sH!9XljlQ; T0}b 1 I9[ԯ_vo4[&Sϴ[Q(f&YjM.I337{&w{IaKfZu'2WdZM_`ktF]ыz 3x]2[6Ȃ$ n_˗L m㐔2}th]?1pn#fKg AAL퀨K@pF +On*/a]W\6I7<;pYx?|t{ڵ; VGՒ"?L6 9 *o>[3.(I =\|jכ|k#AI_dӻLUGV\eX.=X }G2TBf4wYX|_) WR•$䬉FDON䊰b";6۶dR1ݮf$Ksq#f?vnGgra!y]mѲmw̞~J ztv2,,$OJ5$9KomL$"`Ѹgs3w?VWWOJ/Hx,AAم'F2lā"h8؎qû'Ywkgf6҅MtCQQ$:8(G (aYxx8{`'NHX n"( H*!EpFcҜ ..`FNSegbRX@oߦu ejjpp[<aT)A.BPeb"u_j/oȏ~4usR&>)()7Xk gGxByep 86,ʈ>2"U&!,ܧ"T)ؒՂBUJ¬V {;ݵy*9yPT).97.̌E_r29|愽}B¹g ؑjJb [LghJٮEHܑgX Haƅ\S~$=X6oXqr` N8;555;\:TmZ lVӏ@̖1TS#y'&p\}N^p*dD`*b(Xb ]qlOy#""bUuYQ;`'?~3]i(mamº!eOۅaѡh`( SlHZnee9[ x偁]ee%6j%|.O%E~]nɦC]9_ R a Q,NQ8f㕾UI~^^63m.|#cs7ۃ]ЅBK8.ӎ41~=T\[344〠ocë*te׼ jE= v#Go?S1 XXfuu,ia=Mq셨%{40RXq  fkirP ŕn#Sb:z?8~mVjZT=v;!!qOuxCJKe\7< L*|-Vߠ;^}p^uʤY$}h7OwXPUw¾4Q}23' K)PkVl(9ܢqu3:po+b;jc :֎:z{GPoq+=ߨpuFBe>.Kk#A7x G5[fPn$ã]_y/^Ʀgt>IHD}~g +?i%|E>t^G445)ڝ?J>h:,YlU ”_|0/<}p6,I+*uxDDD+"VIlϳZ;PR.J.#I~`2<EX g9ʢ6(j]\\pXP֤?rBy{Կ]r]qd\WJp?‚ҥqӧg]ZNiZBkGd yy;` 5uد_zȈ?^B=;3QECpsoigrq({!͟`t"?4졩_\P'6LtߏI 䊦ko|Tv ]mu#†B5\fIͯ6 GuSuB=sָ/FpH&6*+^ ~p{`kDeHmE2gL gY{=<:X@Xd1i݇+}nroLjwdHHHS~/uDKPdm=.d>D!.=;=uaw s\Y'5h`T8s*TPA3N6K%5q:) o*~Kݺ ǿN!#7S'O-J%D@tI*R@rl響!**X88AyeqҬ$M t4#[>o-ed"'!91K-||Y2-<0p:) xm,lzY͆9GFZ[]؋6H[sjMj3/)Ŋ$BR}p7w^?+^xխV^Kϟ) ,._5?쉧J~+%cg+߿i kR-Ca0"p, 9p`T[bS%>DP3an0߲ڙĦ9²a>yK ZFmHQtq͝W_V E3'IFEHe%յrpx*6U:qyd yJ'jW?o8S@1KkE|7@ 7CA &^E.9C"d8J\ #&d %tBi\9#ߒ%W3mm$ ׮=1 8ʁذ|gcKr7n:"%z""Y{Kom}(0K-}0yx ?R"B)/wHgffP%7_.cXgS%kk[;:I,5Pk!Iq]1KV rGy*Zٻf+{S`%Hi~ʒC9} X!SiLxtǀy!=z갮HHQvr`3 swoiY<l A466z *-H8J=+WE:=Uljsc&RGo**N5D1V~8_kss]+ryG7"X(uz ~vEt|Yqa5=kwL#"򥷿⇨7,+ٷHtV}nqf6jqy8.`t)߀/Gg8oz-o`.(ݣǏ66dۄ78lnZnooXې3so8~:ɹӟey)!G58=TֿZMC0q#t==Cs^ A<)#@h` NxQ-d+U&AXpoP#^(VF8-Ϩ% q`./Kդ'!zGOlG֘k^SyHv)V|I8Į,]-KF(oX | `sf٩QQQ-G٭sfnL(p;ۮSHe ,5iE&*MK&INlV͍p-۷>;7^|JC ^ Cj #?>1C-VC* +W__mO/laIm &s*5 }UšEO"H`-I<[r aǘVfmI L0"+K#4!%GJ8 @s/f} 9HE9*ndQD悅W)/$qb"uV(;p^{e6D^]WBm:NoP&0KÕ)՜Vݝ+ -9hظ iRz($%:<:"$^$}x`OIôO`4=U0 Za579\wb4w9ިIHߝemxg; 7n%? >)Ŧe9K/U/Nr~9jRϤ 粔;MƝ?UwdQ΃5uN7!JPqs7-b32=Μ܄Bs{?r#`9nKYJsZ])]n4ލ'?GGy sɽXv5E!hVBB!QRŹ߾}nc2) #t}^a և@3?T֬Œ-Opv?yWi;Uiii۷}C&\&tY/h G9NJ:Zo7KΩoN<'v-vu!aN C QWJ ƖB]`|JGϞaDWOXTiy!@C63}$3<ʏ\MaY4h{dPjrxT⩗??#lوY>I%)m$yif|x,ݿ-T-)>}v.|\v ~7%f===k#$\R CNyj.>Č=PpqZjsm&}U($-kũ"v\ð6=}RWBR݂ ';*Z¨@C_ 7'? johŝ AO{.UrHQw|^ ^ hr Ixԗ*2 y|w`{8-D ;.3X2X-r5 W. 1jـwm|WC7K`[bx]{OgAGTY_t\˘ihx_(z}ߚVY6N'Uu (VL.>;8vH O7Oa vz^8ǂguiƏz%$$Ԍ/xMОbQ]B5Zn Ao(8֫!v+[O=.6꒓_\,Q߸M#c>JQ2άvN;) yi֭" ѣrzV+!{<7pVMx&:xHfuV\r6~Md0-qH lx( YfQQE[3`"EPs`Q<}UBΜVNVB {q>_X1nC-=I{Ēvsyۧ7sRZWu^ҟ_ey߆Ϯ4J`}E-q211 5ǜ!گך qZT,2A 4B5<n]ǩI;,] 0v\2v(]v~v;M7`t\"#_?? ʽН^<ˁ;7 m#A$.u\(Y46c|kci+ңjh_q ek 6c{]%_ aQ}H?bTbf:bvf8kxTTh/FDG{=.v88 iX㩔ׄycʦ"YYR`Jۓj#tttJJB^Q`@<e 3ϟ;u(a̎A |@ZELWx\6M޽)׹P ***>`MnxXazIݎa8 ڜx&-v\Rk>^%*GV$$Pe;%zX] {[>gEe.+T䞪Բߗ  ǒj__RG*+ ٳM7. $|[ɱKL>@3bh/@|cg/k0=ӌ1[½;vhŏsv};㯿JTm<ɹHM7W7LJ.^O G/Q+TTr9EV7ƫvwX-2,s̵Zh"##^vNr|'{D#L 肮ߟt2ZM-㶽RC0 NB͕[ XfPcгqz}&|'!P,'5w`цg'xfZlBܗK eDqbUPX0AiayH <6 |[@Y?>]9 BpK/˦Aqnk7 'QN0*w֓D@:VjY̧Dj[?_]r #V9s桕!_3KtvfBaa'}Of'!Hq''*G=[%fddh8Qf1 F?z|[RPKi"JӃ;rr.D p)I_%XmR#nF|LrەN*# ͺmQD)]ۯRt';Y.##$c_.0息ÛF\wa.&֨q5 6ȨV`bqk؅sOi*I:~ AGV-H/׻I@KxAu$0/xEeTa/ ɭOgǏ . x?ߡ}喼.i[ub_e Yv{GPDi?t!}ReVb>֖JsZt!ԕzS/_:gdHi.Z(WVv;FY҂)Wq(=D/d] kY%%w'K5NFM}騄st܍tgclO/({X,̒uEIV8y+)!?Bb^эWWX™,=;2tiwp(~ W{eƱ ҏqWS7?qBfc& l%$_1n)"`'ƣ^wƄXμR""T\v'ܫ%)~jxj`xyEDe2q]3묯T(![Sߝg1{X}"N'6H̊ȅUlֲJIko+~fsLQ pwWmR  wBE;Q[$lwBjyɉ+QD'~O!eﮐ]+;)sqnDXX6&r ؿx3*Hwbwz͖ǂUsLB&gqM'u H[@s}?s  W2s6&[^>jC@--Rf?3m蓬Me6 >pzQ&df6vz=5_q{}āöA!BWH}u]]]ϳ}eDy?*5LMc +8 #Ņj*RZRumJ}kwk*vÚrEXJAHZ^C\ýc6F 4|9s Ej_ Z.h@v roZ:Y^nK-?^KL0:>q߽tQTU*}S^+@J瑹&OK!-NxEQ Bk~.GkW>[Ma΀C'43wgەE%݈͋[.E͛"-80$v1鯂ݍДz[S w.a EƸOx:5c4"1`߶Do}ܕ]KJ֖朩/qWKwe*˞ W~D:qЋ Ed=;bXTvF-ão+ Y6N z5>CwIѼƈLL+Ff'w<ηSGy"& S[q2J YY3422i$/ZgKzdhIժl|-T}cs/kNLfr_GnyS;΍QvReVX1ֻ|ўLK? i8}Aqˤd\9PCpKߓ6J"2o ,:N*}T{6-o12 cǤ/=T m۶!!9犆HdY9t^F!_DyPN LO.bdMԬd>bXVM7մLPU hNB+ ,Dn=O D*3թQDWqAEKK 3SEv^R%wY3\mzdI{e&|WUm2 10ɼ{v{wȺfoz|hEsbx?|bM PT➺sv#W|X1x45i_ⴴ9| ]夲o3S*^pbaO}&HrA3>_XEgev<>D_O/V5X}T/-xi^$~naF[>OsH*/ֻ)N?K-eWlq~;ѴO8:H$ 92la\%~LO)JۊaYŸH8rf✱<9[gq'7]7٠*avm@1Ykw bٺ7l6?Xҙ֘*\O}3h]6> BGN ) ŇdY^2̒]QJ쇈=X.szN ҦURN+Vn['-D^؂d@#?\+(( <--#^(-޳mc,Qbnp4\lRuy95JQڴ3\Ièr jIPfcǜuVԜT:ؒ_|gЍy$TWe}+1#kuʣmsm]>qQ ?}A,r塭i LUj^fI]hFj*qGx6|-_Y_vN64nƤJչ2歇w.2arYxƈܚJ4/ KJ.Ca*, dBj %2WF!DgY>^{F=+BhO\D0偖Q3ýkz_8V]&o\F_:cϧsx/n 9D27ɿKW%zd25Sq'o@o(KŨ$+;YG|$^ҡ[}2 sNz2ğ,URރMYeg<7-Mӓɾ<02bGfL/4R~6 #Z^)8D'[>i !6-d/ۈW_Bq.Nom⟍BHNJsSz99q_O71쨚%K]ϛs~hֹHU]y};r|={,(硖PKyK:'ascrshots/BTW-Aangifte.pngUT vYvYux T].DTBDnPD:.AKJ[Z<~{{콿15ZusgIR)22 {*", =0!>.CO<C qm>*ȚkY Mhu̬ mya0r ;rWM'✛

4L~D/sCƳw"YJH%"5_؂U+Vz// LO7^(l?%t~XXZhfp/r]cF1 *RWHu)ƪQiP{"p&OGƶti;mvU''^!zSo7H2 E&嫿Uiu;M>Zt<~F]7G̳AN4ӑ\s˓7vBYR ~w6ȝ%n1b(p qm ,NbN M:^ {oT]$ f$łeSxr)>@ljQ>ÅN^hRd΄U$}T~\9ٜݓex)D|?i Xl*ki)KfV8~إ<'vͮM7FM)^M +Kʏ)ٵ+_E˚9tfxup ?QDpæwU/qN'xzS25] !hU?u2\ֶ݀p/goZb@Ӓrz]LjxTM⚟頛ۤד6c%QyiIl J&qOZ^iYANjwKE'3b6po5r5FzS ]s'ÈM-OW- 32kOA'\|zpVx#!Alf?[BT(NvY- @LdTSIWcCB9ION1T.k?xF+Ŷq?=2akl$1W5_&#u^h !s{u2L֖(fg zʜڳ^8h(!Z.*Y)x ÙL$:ҫ6TzhI{ w{HZ}D9N̈d>2=Ac77J l,>kc(-Is+«Yш0NEAIL:}iqF#N3mv&$2 7n%gfMLlOKLDO [%iDt.#e9cXhKDbDGeٖ k=Kvmq$|Գ9f-O`Q;\d17]uެ!XT[Dmhb/lW.&XӺSY7hHT.?HOba~Qh%t';\ni.tૌ V.ld;;[-4ޔ>QI" :Eٵ';ÁQmSSI%qUϬ$RቲC_0+W!4>z:9`zxsl~5ܡ_t[dj׹bT#6fraoby: *A?i*pQ#ҤrFВdEs$0OVLdUޣo{0ץz$1 {Tkח%t:2fwX=_zP9Ġ).!aip+E}@M"4|œB Є8oǔ/ dgDtg7Xf`?"# 3Տ`Iy;pC9G%>X!AbEcfEM^O(ms#jJ7GbOTe\*_^+LR̲RW8,]?S]r < ώ ˜Ӑ ,n‡ytY @i^܃ϣeRYŰ9&}_VG^ؽ_Zu_ʢȜZ}CS,!spE0+1V_xܛxW9c|Ky6pW݆HTf.P֯6 ?H.2è,Cnݐ>͞ ILg|W*~&UXc? ^i㋇^hjg27JcgY?\|t 0<[l.XGeaw2QcSz8dkǛl$MoY K[kZcG^tӶ S'q=M ߐcnnt>t@>F7P=a!t|H~k=r&a5וiZW:e݆2.q)rUP?]EQ~ 3BE#2;\ng/j1 vbzaOh44leOof9x:h JJS[(؝EԒIOmaJD#(x, CO;D>왖ZG#ƾ4:m1}0j +T{F>3ٺndiI÷J۪.$ԕ7V3F&yݥ͒=e<p >cuF")0~0RôẄ _8Bp3InS.槈 l~@M|⎅ #R~ /["^r3MQRJh9r x&SMAwIeq= E|VV~?o-$ ̍}/({(h6;ӕ ]R!ҭ3FV)YS^N8{xC,EK%DĖ?pO&}i=sTr#<%V%(oF>er'ݞx.P>p٘mZLRl6ggzE+GvZ/-vHl6~ W2d~eaB3SǧyPi4t+;xs;iN2Uw,ZjNi<^L*+{yyFԴzCCˏ[;[}o%0b+ q '&/[#MD)O{S 1,Sٱboa,/:G~Y~A `LS^NXw\kOIs#״4f챫P_oHͰ˨YQ,Bk`JmWބM5s}6kxkx2^mx>?5l78r s4ˏB4;&9%`Rp7mQʠᛲES'A{kez?Ch&A4RL2 Zsc5<;;e۷'ϟS|XX8?6[Q2ÈS瞤&/?|mYfŢU{[[mei?)@vVVָhLNΝ9 Ts7wj<㞙u$A_9^  ox\MJ+/d~Hmq31Lv_;r/Ud)ՄNoGx)Û I2%z*nrrGmK_b\\ూvp`o~︇k-<**x$$$3 . D@*eoy9lӰIL'.7ޠ@͍~WPQŷoK8&- ZW "kNKLmgꣽpvz2&J> <]iR-}gqFi Kpޔ%"g80z$k3s25FS^y- k|+Ei-Ulwz͂J. R7(MjrkăEoc޼mp6Nh{yy|=_fhxNg`ސ;2THE z#Mk5D3HWl6ɰ>Ϟ6%`OJ~+n_p/pR? NN}1 ho9'Y&) Pc_W+y s_oyFۖ!eHVj j93+hٴy }WxεLF ?lψ7&luoV_i9ƨwm2:mސpquyMKev5xq\%g~b*RL5C&򛜓#)?g4B,S#[^>>qq'K Rn0]-,,`;OoU+oZCsF֏4dz-7t^9VspHv>ߵT\tivMJX2O<^#-}EBD {JPAYf4O4[˴׌PTObIzVWн\RTIrݤΓz*ILsWgbˆ'{}:wiםMlKX9'6M | %67gB]x5ܔK\hPٴW4umɋGUVG.10JF&r}55i=9] NfaoGDAIs>{y0N3ms<]|}"%Auj] ?57T*LD 7 ;B֧Z59+'M[b~ -m6dgL]gq/mbW aMqhxXXJ/M) [h,ia1%ve5BT>eՃ֕UJtLWU3t3 &ϏyVƗ.dw&I}~F$pk;brn~L:H(rչr?\!mUQ43ߘAkBƔӋ9e]]~UUbߡF~ ԭ/) L{]0zdi5{lϟt$"Ae='Ion.TA0wc_j\6 }Lmpl4tqp{Kॲ2T9џy \55XWWW=j!   W  %kq~QNM T6"y|xo;ܥqpמmLӧ/:,GK::#"M'RX*en{NY10m>Mr3I)ˢII wyjJ̍Z$!3;9ЌQ9Mi`! ߀=oAr@!>7WX9kS3_ܷ#^j.y㚝2:u﮹ݸ')wRLhIi_7*iim>uj}3]*ۘdQZAÌT^qs y2i kvviLndDWfĬ Q*ڌq!|Mƅ  ͆_?;v &#Һ 6Wr` N͐Ņ$d%6cA;OT4l6yj|9'4`qY}',ETw ,Ojo D21|CU[rzAKl5!/mxBAɬO0a,59=6d5t7>hO f|>\9_jC\x OwI dGoMO%\q!q;ojoWu2iD.'Ԉ߀ZoVY(tŲT$oD[ \\WWxǭ. iŵHMB|DMtAwww.w4%^ !CFx`>}MMa 6n˰p>K 66{8DE o3}Cu*ff$;=Y(z.Uݽw`e}ZޔfMS; /X}_t&å$>_^n:Y\ Ň |2ٗwI{9>N։Yc}oݗ}vlrKnPi ܏? Nsvu Z}  <$v]Űl4sקZaĝ=WN.8l|\.944dakKk+'0liݨiN4V v\.3 2 /v:16FR,+#<W[ZilmhoAí؟̧b~cF~ZjK x~H?Ѐq-<um3>Qrh>6 M!Y1MJ![]1mªHQi0gz3C+\ Y;~2"K7sIYՠ>L# ּv<$##Hu<7?',뛺_7N@xzT P596Nl?]$V,q>'zYl,Qs>,d3}6N#J7.!4՘>EݙD_ʷEZmAay}]R/@R2x܍JĂ A F?NeQTȏUR΍FV( n-ZfŽt󂳚7?VSWgP#c ZY_ױc>}Ɏ /pmIHj`T}(377vi<65QΖLbϧ#KK`]gP#0׎nI$JJ*p`"C FG^P61@mBZC)s%-% 岝->Œ`d(` Ty6&'6)'  d%I$ xB!3x!q _qfó3/ߝ%RvZ"0-vu< [ɓU #':ِc5Qw{WTWCg,_tk`ZdigtͿ3+¤66 aϟ$`=iFcgc\F&,@L 450{8|n5z˾ ;w:oWι`ҲtL5HI95t'Y5@Ĕ櫔oR444ڼ-࢖(,SLt. cEV*_Q hQW_ԯ<3͡/]7~ lwExA FXt٫5Op_ ^m~ +r:5 RpY}706ߟp;2_A+/,MG8̉]Xr |n+7pDS\k/EHz9N`/HFCU:؁V x|_J3jxN[[otߋQ5%X7(5++՟= ?!y*Mr zrm]PMfk"SHf%lLcצøyx>ٶ(0:~@ } ]oׁ &_YD枲 8@F64<9wĥ]]8ڜRH<|s<}Շ zkHC[*_ +5Pݻ0JsB*7OϯK5@7y]o6'}>z j= @뮶rk3^}&׫-YY˫M+]o֞%]!hMP5?r:]SD|K 3^&[Y*jtv)=5RXxtb78;aBTrj""Jշ|"../Q#$llA 'T*85T#?$222JF W"}!3a1G)r#}5WUV#O54om100.'u҄Bh/CbA3.,7ެқLuIg$@e{0d"s6Ƴ9ń5^g8/?ADFA-;/QS)-7JY`e!fh)*eFÙAxAӪAD<*zQGw%^S(&IQj#gKKʈf-b:UƨnH-M)#P  oెwy鷚U¿ݒeZommd+JMG┥s6tj78~͏Fȣzj7:D;ŌMN>ẀF[A-EkkY/o[9 l7'ӄu@JFV/$%3 cLW)j6l8)5p8X֍ު[9e`x@/_1x))'PqE>c:X.w@Q Pod} Yr*`k0͍Z&ƻ)m9 ӭQ̎~4iZ*$grI 9'MNbwJ4/23ղ䝯B* ,Td7XYŒ^U?7=#B(>PXl;{xT\t{IQBpDn#hR^h*O@we5ݤ=Jḧ́$toh|>q>wDl65]O1a+kkuf||߾={F)s'M9z - 8[ŀ @!YXhd*t{}e?rZ0=[D5te$#( }PVmZl(ۙoŠ(e9V n=w X=[KZ:"(U(LYM?[X^^ѴRٝ*Ve}JAKOyBsZuC2ʅK~5 ~ 18pu9^H |֣v&R6sa{ڷ3{UMyp鯄WV6,,|I&%''lgٍ||_-Xޕ՗}lE-p&ޥ9g|U,?6F#{o?`gT2-,-S# AQPf/x@UŅ#S,m+ir#Hm9̵@@ʀjjvI{;~Xo\Uz}v[seP6aJD$/CFBDZ-^HT)Ќ{B̛p1\fA%& =؝ +2:v4]@EtIIIaYi4bZڑ ٛ7Z!w@6&}J@a7e b@\aW$;$=;UJڏĢfklq"w0@:ͯ=zN<,:5/O BN63 -Зg: >KWܞ,oj{8'==t'[&vxL~~iE8ҟf}y9ͬz5D8yPەUWano:ߠT܂n}yϏۍ<+lٳ&w>k 0r,mP;F4q; iFKzc{rx&J,+! B(# n7P7hScXpppJ4XGGGԲtI33j::=ӻ@e?}L1(({ Ww+Ԩ[?5ݍR5|w+kL59q ,3$ %6fkcm2457|9f;![j2qrRo ]ơ3yUFkبz\ĈZ_Vs P{ Ǚt}˟Z]P۔M1?1ظDptttJUϴQnhvv$Y13W@'mAVFn!>dw#rs.HCx~-АF߃nL>7 xyz`Ht^12b VλhMv\x]쮬B);*cb~t[t'H丂N.0SoO9ci(ͩ7wB&&4U55wZ}d<ɉBG]t2RFmNjFxgZ=bA+ucB P<:Ig:|U(vT>V*CU"8erJ O:xVBv@'-+ƭ5#͜%F{V?~nv02pt8rb3+`9Yߟʊm=ٿ42R,$sIXeί`)읅`"d?0ra0XUV \e1Ф`xHCS@A끝 +#j"1h*+)<So(QqnJ {B>;;ͻj Yty"j8֏9dQyM8 ;&˫-mP +6;4~RY&|>V㖛C -`TX.XUK6 Ul:">Xel';07a* xۛHw[u -'r< kɏo]/%r[ BS6e]ogk;䏑 "3JTuy \+"wLG'#xzqoL̈́qn֞Q[";HKT\arS@z~rن;8'^<sqZXD佥%`i JΎ ve'cHsdEn\{O+[2;iLlS+l=Vez#𥅟p3>܎Gi$\Ƈ?Y9XhhpK|>X_^?1Yedj򀛨wfS7ڢ#4_oY6 adga@oxxp8`eh!k'u=X qcEEE[ sފ B8:ʕp%.⍶c8}}ok2>)5ؙ,}ci]sSJFtf[{[^17AZsݯL _G2QH  G|>7/ ?|ѥ[TZȧx뇱Oh߾}Kʥe >TH]xCtq×it3+hә* <~OOQEZ~>)t%v:*Gm~뺍TlG|5ly{DDx0+P'>\^m| 鹗srwNN˝!]]H Bc%??gSӧP#!Jvd0cA -*.*b{8'HF7׌m<'Qf@ݤ$$$fffh~~eho,x๟D׹DQ|66Fы3S-,ocÌlIMYKa_"We *򒘦* x) o`PJDzWZ+4Ȕ> (!*7;x6ip|D|Ez:)_ kv5ohiu*>kLjf (%>Bz {۷TwoswΞGLRR_8hFecvʤ j~SؐԀq\Tu,_>VWUon>p Mv9;RRR2mPqw7޲a+jp>£O[]ZA x+-)vssjn2Wȹ L{5 .J +r; 㒶+Ŋ+@xue-//fr B3Dnko*m#09km %HB?IP!0Sãb!n4k6pc^b()){>,JM8 GQ}sҒvTr@UIXFT||OdZuɔ3Sk[[=jv́ ψy{]x]:TTxx2z''cgkl@qjsNAxKx8S~~R\ʰĀ˭?U&296^,x"[V^][^Ncz VJjvv5!uI~#$jotR*guct02*P` ]|e \׹\o9( Usq[X7l`ņ%m'3`ڼr\PC/eUU?F̒a..w˨;sS~JS \^bdu8t$S9]O/Dsݸx "Yw{6mt-" ]]v-\m\XuBk+ # qppq~|Twpr8`*#9XFVڗGvs{[}z9K  *hmF <瓟O f1WK)+{ߢh;W |iq!}srxl:ZP;>>HLDd"1Us5UGgW<<|u@s:s4Ռ ^RRw"7ˎЊז#kqsaR!=1jКO 3!c>~f 8u Ù* ia`AAJ4,Os'.:ZH76ƖxfC|XPx!Pz%nWHVFgzw2 yaSs3x31燶%z (u!r}b3* m:͆WaԎ== ^^`1({}G$s>[#"vHã\ >F,a]ތPd3<Ǔ t`pqqAgtGRϔ##!ejbpMLqƊkJIE'&Jy @[EB0Xб HVN LMy*&^-A _?CCmh\$b0*Ю2!۰jd+؈xw *i/bJ8ueGAAVI/eKfq'ؘA^4;I: oc bP߳{ u!ɜI ep(a>2is\cF[P! -0οEp3M6K@ap )/(TP~yAWeKqY;Oh;"O{Z{c|gNgѽQ2q'\ |v^9:O\ր28qKe.+?/ɇO JRp" |<sJn47_i ++"<Et_O WY3|wji+OX΁\+Ύ܃>ii fޚv(n Y&퐯(ys(Fc ***LN6w]N'742[2˗ZLTT$"'9[xBkhZ\\L~-Cbz0*nfށX/^;>?7@f*.3v 4UoYيM$v mml"ݛnu:룡Q3,!;ƛ#S==]]zΐ>Y_߿oS-/-`ѩeZ>۫G)Vͱi+ Y13Sx99)=={k)n}lr7U׬I~bڋ-ޣr8;eqllȻL!^1"7Thq 0L3hpmkK G2{_?V0*@:x "\hf}C^r~yGv6+;9@* (\vS߱[=oPtuvFz.L(G aà h$;">^׋>6c'Rʵv8:ȱ+or #]˶yҐ]8\s >l2EZZ܇qavr$@V5gfCצ MeHv Q_\ sĈ eLĻA@4nas8 ƨP pM~ѷGq~]|Ga[>\'%%9n'@X 3i9 wz%b:]Cn d)ʰO5y]Tzd{㗔+܀ͿJIҷW]]]|oӰ˄ä:YJ1JX(఺GCC ,,-Q"GV塮*pP$>gA77.mad_?PJWx]FF3Fu&h"PZ6koD4j]+'[0^ـiD@@%jflsOϞ=s8 +PGIƔz{=H֦˄ --TBb \r( R|ހ9m6<@Ujw6P^yunnԾ1bxLx9+1٨cKV*F@@$'f$i%T?(U8߯K)4F!!!PN2/ j*J] ɰuͻ ?K4ׯw: r&X^YYD>O)yr )K=TJ`B rm`,ChuM #rN)T-&++Lמܭzss6/7zՕvueWLW"#TJ`@ = 魬ڱ5?PNEPh}}@B@ʠkNk7X\N=D(OS !g" uȆ3QH=+,MwF=yB@W f(-C; ɦ& i'lNT}I+Ўhx z ml %0i G(x@HQYϕ72`݄$? {8HC92 ;)sX~Oy=asbsr&hˋ/1PH 75i&tɇs$qLVWVRRR`=aE&)wGۍ75RrFްsp@!SPpTlLʐ3;.lUTQ/r8N'%%A$J'YHʔOovvnQM92)nqRTf#(>rTK~EABmyJ೰)sj <To>GsLw3_~("[.''ޭ|Ȫ` )$WL5, gďh222h!p*nhG,&{ ps^ON糝FZ}sfdC_\_azH1PMSS ˝|syk"Ft4jII[)fX8:!aD<4}RnԞ3|M}Rժ(p\XZ}Pş(kiA+coOgqt2J56bIS£^?f*J\bwq.w <3 ,Z l``"Ql^pFVv^4X2)&&<^g)N`"w_{SOW[S7ذh9l8DHnmê8 V)UKEMWySm* N"""/?ьz=1X8.\LKdZKT|8[1F BvSNEHc|||CfU^WNRRRŖGܮW/^ CZx5յ^f=}pp08Ֆ$Fcr9qI ; dYkv:A4*%kd$fFd"}7 Kl7 QEn׃(~ ͒d {B63;K]2@LYYyLY>E5>a?X&F+)F'K:3F m%[7Z!3J$ g&Iܸl{myuE=L Tbvdcccm, /{;sqYWWU# tw;85("HL ;;wZ;Z)19܆z~Qmmͬ@@ @KlCbrC8v4b,ZbbbXpD$kS>dh1Fx@ (mjzWLyႨaf0,};#H..O>yLaө& $UYѾ2à4vykH4g NB>X/-}ˆ;a8juaMUcss{Vڙ܊VŨMe#Dt~Cb[CtUז,'|L"AAWnN\YYYoh*j5AIuIC3wu SI܎%$kx\B{MLL )5ĦPw[&ضNBL { %2pHQ2 mZkV:**Lp~LefbDzSAA@C~z';;A{~A?L R]``͝Ҹ8#FA'o.I T|&O%$+>bꧦI\KK2W e| -hFdI...ޥ~Jj="6ZPx̟G_ lf4TX Tgghhh{ <-mh!,,˪[#8Q4`U.#F,Юݺ~*[N84Hs<^/,2pGo+wwwsp=Dl>sphhiHijn׹^h55P+ꟜC\ `kquaaT쪇Tul;88h̠B<5-ac"?U"##WٞLzϻb/*)·WS#P(PCr9hFuaZ @ Dr-a^Pc2MwkK1L2yy4zzͣ|@*\~Vgu8r2(n&h-2[JԴ(tELWLݵ~klE00]S\ R\o 4( j T)|>7>=hQx4o:Y&[2Vs#ٲՍKK1 "u獳 ed$ QP.9*lHJJ FөSWG*\u6jݝ2hOޞ -g:vjhppm-$$0ViU+H;=]hG`y5G!L\?ĵ@,J36YK]& UǑGkj&/?bc@CR? bCáFx@q v.ÒN+L I}R $|?q9,~+T<;XM&Ѐ@h8)@9hϟ\# "e Fc#:[Y(2?.nh/Mvz`OOmP8mOMmADvv(O걲CbѫUd,VR[tUO^֬PM>K)Ԣoҡ!#yh(##C~v[ n{ bpL 5mu BOAA[pcS?4`v: Z:^NO܏{D hڴV]|E3ϑS&~ĽYwJ~y7QS U\&9A3BNw;t3: O]Bگߣiۊ-r *!Е4suP胞#EEE<Ӭ<5/?jz/x2|ϒJ^ZpH UinSz/9fW趩Œizr[ΓCP!]`<_ZXQE cȞ"N5ۙF@!JJJ)NeB @'-8)ՠp)ˆq,NJ?F@@ވ,00!rpY(^ŅGd Ph3r3@iHLllhls1JޟD)wTm#vo Z`dGuN=Rv bk.{:h$t#L@ͷ@EyR㇖3]ﲑ~vk #.  h E+;h;Ngp5.50 Y;N&pSFW}b2(((8\Pv~~ xk$Q/Cw{.Y"( N;+zkKWS.L"+l6eQ=LrIKK`AeY&*сrW8䝠zP .)]%>Bڪ=8 Vp0)L[%fXWW=]=lŊC >Z6ea +JvY7ZhgQz@@$Zy捺oY vsLLVa/f% ?lxge [^ć V2$U##-jة \w3fwW'_U!wZK9~C 7 H% ={quDoǏ@|RS OR}!L}& 쓵ٿ7u>gS(6+D WtZ(0hn PT y`ϋTn+R{~jts{<^hF3spbJ9u.z𮅕/8ǟAc6%57ߚCVtttAA@}3 %~ȟ_3::q-@)Bn: #OH+|~9#>_:NӠݢ,2d% Li(?p_ϐϦ ⣴N^wu>3MN_Ymǎ➖q?>. %SZך,ΏȄжAh+kpϑZd,=h~z$)􎗜4W V   mTT+TULyn: /LhQ@(zg1ͻ_@% ~r"q,RR/RR^6 ^vƈ9yPp\lO= 6b e)P'rѳ7bbtXUi )%q =$p}xrDR V[W}dEzNxfr''^1z[ЩGFbl~D@U0 M0ȄDk)N]꒙QAKfjlQ?? T,ܬ%LB]U+כFso:ڣ* pqꜚ11.LLL@: XX_8*o;? #C{*uжNv>&=BC d6~o+K<#V5ڜڪ:arjMx( p^j,XΎ@Y5@4S1vmjF377;4lEq7:y(.L_OF dXqQџXP6n}F4#ѣGȼ4H3D(k clZOW^y^$aFunUy\Vm4Z\6h{ qmG9*I܎-b⺁ >A 6!mpZf>0? L5Z,p`)&#s )#o***>lH` " Mu:mquGrKZnn{< mι wwj)ڬkFu锟50 Zlho@2'[ :+x^?s(}7>!O('0KCa`YRjRAx,`WYЦU [nhv) :`Aa:]0 0w@X܅Фa}U.,'O!XZl#T-JeѿfPҰ}ZcB1,?^@XԺT -B n:ySygư⦩qt(<!! o[>Z/I> pppcRϏ~7mx%L;`_&np:R֎C13T[@C395{lwhh!2Gm-5tà}ཡp+QLHB5@`koF?{3^`'aełv~_kl7t;vMXEkzt<ъ:a0\G$K4۸Š*5?khh0,ymBCJNО嵠Bck/B3ܪbG.cbBɷ]%fff$X(Km.%Ǯ| bىPQQb#ezȥrc6ЯłFe o{*ʄ>EӪ~ۢetZLM݁:ֈKp/ӕߡԪ< 3((hpw[5q]==KX $ 0H:-B.t tv,kWq/Y!WБ@ ɉ M)C/WB;aO~'cU|B4>|w+C .{>ٙ 3b#kQ u--{\#.J / ?^Y㲮#cۼͻRuI"XS>v-,|$y ^@ p>B$}߽^@K/8zzTT4ٟbat,,E0B-U0{B{=N# zȃafo4p?[|W*ظ]Y>ǰ5]l9,Ch'\O?lJt$e3"+]SϼY48j eggG``@ho 2T111Q$_@_x[\xJvjE"MP򣺺"3SϺhZAl|6NjF|=.{@ ͛7M?xXxE]ʵ;ggJȉ >5gf>~:Xhc4KMabggp0UjHlo"6Or0nF~-Atⳤqc"7 ?A$*&'F&L?A9Rmzi dv.WttόU򡓻 _xZ@CK@NzZ'P@:R[XZB; U(W|ȵ٪ '3:EeearqHQoB.yb 2cjH*[Ъ h7ZD tpz{0Xv1N8DNI#3u)$ik6%\y&-.w FB`Bă ~O&LxUﭸxirT0n I_ү`5BY0h4sk? ؇l%k ">DV,:5_}efx`qr/2Q)CV@kӲt ^oLo?%YyvS窤d==버 =a #J) aaͼ5 :L…\*)ps8))7xH,%jUK1Uckjw`` &'PMet׏ E^!e*' TW$$p6fkZZ['j2 ~{ڟJhrƅ*WϳMGs ,`ԒƦN9Oڭ<>#%*~H:A#]$׳ﺇK ;@n٨?lA9;;yM:z=L=W֖Qٴ9V]ÑڗjZ2xeMD3`)Qc.r>))AE (P8ˮwHZi6B))E G)=“ЩKVCp'.=6N1rCBP{{{S>yk2q0O(`I \@Pyס5Ιůee>D JP/.XT`As\' g{`Xfh)_A nPW蕜+g(@~BbbhL, .VxPDPZCUV'YpEX'tL%tS*^~M*2,9xw;1o'# Ύ`=,x,}qNqKn@%v-OeBG'0]rzCzF\2k^+/9W*؛!y F&Z':1 ֦zyowލXqllDq 4,gCR"7Qzg6[!?>5XuH͘ZrY?BH7CRȍbn;kYR&A2 4?qt>2 ):ȑ_DQQ;QGP>(-$EQr\HjseI,\rPs}c4Y.$'<.r HH +(`Qg$_eqt⦊!qRn bN3kY[X| "qåĠF& ?[ 폁6}B%%2o DNE @ FV>{;1C&[e'#^جb^8a9++ƵxhA&Hu|mWUဈ@{\JWˍ?$Ӄ~<< 4S jǴc: BvvBGvCB|021(..~CCT04,*Ż|a^\d[{ IDТJʿ~yFICCc=ŅPw9.x (j&fE}!s*q4'aŮv]}eE7OQ#WNTT:FB|4]rtwg wU^Т a.Z>,)V_8K\ҏ0G<==C}rrɜP2x/'7tK$LKNB]tnZZZkUnb kjN6M,;RE%J(qEKkp3+NhV̋z=DN[,ąm&&&LlaI1؇>tx0?tE.1&5U>v[9Օ+˜!|"!$h`1>?is͊yKx$ѭ>+ʣ\LfYUo|y[ UilZ另S a8CFEEMȖk|iha9"* Z2 z=@ʽh PR6wGR \S "qHJ(*44呖bܻA_h7־Tbn"&HBG'9Ad?6+,[C)3AQ<2',US#XODV  DQH7r-13C߲- :  ͧxTd`Aͱ]n)q...hOd4l$QȖFhrG'x'ދNǣpdN ݳdOL(MLNr ;ӟȗddgNmѭK e%Wwwj]t h_t;DHIxM= ͮDGvaxNR?x]IY%ÄV޿KxMBW^\ޞ$`zlx9䯀mM}omS$wcX~x :#w ˋ-zH_$5d#nno`lPKR ʛrI%] pϞeN{2ٟRZ(gtYi_fhTs2,5ڑ ,/3qo;ɝ[GeD70=tna(h`b>IdA99?%9a*%HBPR;RrH8HFvquͮKp\֚!v0ι TijzW E|UŬ $U[[G'' 3:GKKF~s^Ғ_7\\#ٲFC{sb2P3=c5[eCƦmifH^1G-W6:>_g (.2:Zёtc0:Ų5 ZhQ^A{R?Y677,0p\Ō%BYK;` v|2 @l9dbbb)?D3NN^d~I13_4e(Lm-7>'` {3 Ў=zυ-dms9vZ>܌^qwp7o"EoN@Ŷa􄎞 ),Tw*WQ&u ?Xu >v0 ؚ-XiVZiW8*/?;,7s.Xx,rIXE"M*&'Ɗ}j$PEStrGp]ɠX+3!_4N1Nb'n?`bblg%9!=UQNrYg#CD^:f8RʷʩQMG+!hP2d@C;.WΦ?*ŜMGN@ ,</큃h{;^=_T3X.V+1 mN$FEޑ᳥R(Ζ=ɞY%dWE)ٛ$ !>>tzq1a^ ;HĞs1ӰQjjSw ؽk\㖣IHZӤ;O!DlU㱸tAi;ڋ@/]kI٭>V-Ǎ6 oԒyϤAx"҉BBZ zoYJ~#S`\*4==}>:xʣ6EmyAgSX.faa9d~}uC@wdky?sǗg'wnh-@"#]DGkYy7ga^ J*jHPl*'=p“/޽ۥVdF~J; h46 X7W|ja_,nS#U-<ĸK??= fSZؚ"R=?4!Y{&FKQ{k('_2Ͱ[=lMu=O' $HBFt/qي\b9>",|7XiQB?DGowڄv9D5d^kTˏa[as=1׫<<~\BJ+)).k <+;Xz:r/b|aNMosL_>,թ7KJQjү_Pٍty=BWC7S\(1iiw2E{}C@S\yy'g>ۺcǎ=(;sf߆  T~,j.bBӈ0KSK; QX\kk e&!dqNEɜiG\Vfj1w,Os;5-#-*aT|ccc[蹻dv{5M@ ''Sr 52bΊ! ,-k74!(jr_=m{RB7ʴ!"qmp/2J7gg(s8 :j/g+iK϶Pf8ljjs|ͅ;-VV<|ެo*=MSѵw%Bae4JWV理J';ׄxg9Op:EWNߙU*1Wzu?+톫sѹab<5 M|xRrrUssbΟ#6NNe3oM-jc6gz\צdTPsz1=;bOakˍ#՞hcH¶7ofuaՙ)OL.33#ǜCCB< riZ@CpG.f?c|8.cfVadػproNsFJvm޲"{n毝y f}L\UpkV*S<4ǎO(tP5;7g ѐC{KJJzYOu:pq;GxE]dCޢ7 ,Dc4U|`PAA(b(V0x\8%ϊe`Jr '՝:%Pi9xs9PMB#xpfm)%C"T~}yIe7mma66lټjeuQj;*,􀂒'\]MJI #|Ȟuj;c8\P˗j%DpKX{X- qGzIRj_]5*\Ӊ6ޚ*JWWWhpEAA*s˶04}ZICA!BRb)kj <}:ߡp^Q"ذAD~۠g8@ݏ牉ĩULm>ذ@w:^l<ÖS~<-eX####3i4ϴӈ)4؀ Hkjy[6݌ZQ [d.~lsD" ×)()]VXlQɏ9Lf ㋞Fp>$L$VSm4U5Ez@W<3 /ucF%{lǏKjX'MoHzk^6.9IIG剧cXイM.'`L+x;r;M6/;oan@uRmTs7m4oeS X;R_ 6$+G::+(*^d2O~ᶧ'& . afT'Hoekh`ܕtt<2gPeQ >rѹH1ϻbN E!XkZ ƛYOJKiN ;ik?V3Jmj:?]CKۇ JJDY?MMmʢN3999 ф' YΏ)Ѩp~;>*77(wAs[mLD|yWWs^%~۾e~?*>*92/`Eud@f1‹gn,,)9{1gH>m*Q'l{5550p5q'$ueq1 9ˋQuSk?F9ls>+<}WQ'e^e7$;Yj <644pleddjMwA`3 ;/>yf]Bm*['4J#mxlmnnn LIJ8"o>:^𺭢?CljSYT-"=܃±XHN YmOq=5kL`4ܝMs= ?s{Cg ;4= װcP{Nhy.{Kwz&*3ꬬ,lFm۰X/Yo1Tğ\g,!2=SǕ#U?O,Z(<ݛfkB$#hlFnY'Tϱ8AgK+b/f YI_{4'O/(H*$ OwEE5S* arvtɇhKL8ug() Hm P_et%!\Wfj7{o !-UnmUFYws;&Gߪ\&6UQ$Or,߼:gZS%JS\QfƹeySsDW7>p0Mc# S|s\4PgsBL,KJI.nrVB\|$BBB,b$2 _OQO餟#he>6bZLΎqvk1;G[%+DAvNQE5*IS?l,&&VC&]Yziv2^g?vX/Ӯi<_{yVf?Wz$k恄TU]jw=EL݅蛮uy, ݇%CD\[O PjOwgIZj;EpJV&-7v.~I$,'Gbnnǂf|ƒpUhl8A ֟`DzBbcBX.ڈO S@ڢ*Q, ǹ-o-> ,>`mp_ k2PT܇<&[wW[RSS?ZdkBV‘9YZ lja?3)q֗vOXahw;sOQQa7A8w2?b|[ڲ1=IrE7@ة^HŽg~W9a$+wZ9.(Y<[RWK=P1?Ph1E&NP%W{jQ 9zsitA0)))$X"e`vfU? uww\heOhrJ۔M^BJd!*p?`ڒT w%x~^ X.N묀G'konn>S[|ʕ +9 Vf?Iݤ,t &On׃{Ƹ{h,]n---#(h7FiGj.yش0Y,PH X+`t,ElVjw{p47gcc3-16PR v&#OB>jiiilI~oޝIywO_v?x!W9n6c3gm^363T#ܛ JՂ1eF ,JW _U@FϟwAv _u?VSIIM {ણ\!2TP jX H;VhbJ0r- NyhOEf3hyNw<s`4v__C|c`&Y;7^zv6=KS';:r<(+d[6Q;Bsai(Bb0q X-Ju1bf&U27Y]'ޒ11 亯 Ja:{䓑0`6Z솿sg[+œpt p8R9?[a$gtivALfzzhلѸO60(j;$Khtu VyLR ,K4fy !/]FɉF\QJ[8X6pLQOĺ1xx0Wϲf,6'UuTDE;l8*h'âu2?!4KگXQa͵ LZrg?Cv_٬p4 19CgYʨs9}R`qqglqT`|XȈ=1}Gyf1q=d˸ IL}#B/ >ZnK[Pk~#8<=`xLݝN_WCJugvK_:t+}ܕ9\@VYI}o8[CRΆ߅XFtA4SPʩkeR_`H6 F%=~|0?/ϸ}kZI)p79 9 H =pZaFVjdm'U)îqtZ aB*@MMEJ/_ނuLvQ0d/eY Xe$brTZXU{(yc)Y"F7s˗/Ӎ&B _4E)Zd&C~{9*ps!SU p#̧2\0%beu܀s*dp2 3F߰ ^ grd{=PTR0QqfTB u%oPK?+?>) }W>%?lX:gƭ=#'ε{4sE<7*mo $sbey2(%乳8jRݽ[exp&x꧆(.rׅP{q `tW wWy|XZJN5Iϫk8>/YXR^X `R `>Id1LόT1~c+`0fz,4-0v 3ՓK>i/o .6`e+VyFey[_/x99NMϝ\,76q @9j@֨ཋK2e3AC(uabrmpq9e,7wOjzwgH_ ]{21swZWv;p@i? !XĉDZ^e lz^х{`G("**TX)-}}pmpaQ`}G$„vC8JğWe5-Lqcq1UcPA2"=(RZJerlWTd6|ρUUU_?Iϯ0d_d1$~_;6("X*...)1%6xeDcɅqJekU s8eԗ7){'mn_׏|iÍ_t磃؝a7s߹H mi(yWV En#$<$!N\jtIA{V~Ӕ;R\98oz鼞HD\\Xuu)6no19<WMgXk==40v4ڜ2_R_3輭(+PnLAAQq>|̈́+G(02q%IS4oY+g#[>Xߔ%[A$el1 pVju_징]M[ NǹKY`wáG61a}F"`p=^w|z;I? O+RdMž;Z,Ϗj}{pttjrP ^Rjp:J ?* x=N\_.9SR\ X~Ta֦z; yb@_Do.28u ( :pXLEm۶,0ÓM=,N7uz*__%xthܥbE7IYPq棒`?{ ||].6BwPW524qP~ixLT! NsS ?(,"͟-X_60St ( T `ſZy6nE~*O]L$.o۵u-/&sHxKϭVzp {9Wa/6Ĩh+W l%o+ VRV=T_ݽ^ 9t^~|鹁)"u /// &L=6P!ri{m]OѓRȥ๮n!؈V%趶fʑɫ1(GfjΓ]%"pAIgAj 'O) ݋WA&:A۷_r@p)X{{wliϼ{\23oѫ - ==?l?n-bCN@9)[JN?5lصqFdמ0waC7>4֖Awd7R7 /~5:MΝ;aҟKK#tێs9TLח`wdd[ GĄnle"턾Jw5j#mRϝB]A œ,\da;f1IfQ,I)XI Z ]O}?1; AF%s23 ;|Þ,5cX}TX-{ysֵT"j_ `N$z#^81bGVcvi.Y$E<; 혚 jq&}~ҁM@5$m:jT$\Woנ_nfU)ksΐ^كT//), c( &qR3?]A*[eeGh5cǏ(܎gMQTD$>!AVQkq@|{+R^ʋoa3@8|xx3. )w?d/(P`ű%@I7oKbfJ{ EMh͛԰.wn##<3dmlđ`EjSpfK26+\_iT~Y.~R+qȶP&R͢ <:}4EHHI@P)NHQgӻK<V͂yHxZii4)s44G$e3EuO+cN9{Ol%tψR.R:)q!1JR_pt,VvLN]: r%|+u=C hVLUU%z|wÓĽBXd> GhSR3'Uhg~N MVDZTWuQ~;>>~Ͼ} 7&,mlc9Z HnxGٶPvW}7\vʣ3cY08<6 n݊[ J%lyw輳7ͱkaG4ˡ+sمw~ȼǻfuM T OwT?\##8Ɔ<3S>Ij!r%kMMY˿bQh],"'ri5#2 ɼ.hr_􄋨7g ̭WP%E VJ K 7MI_~$" 0xzUV TR$pw)2SՂlkz!~pltGËw]J9%Gl>8e)ڎYE6x8WVvS3Ur rP7tj;Jra IAN~Č`dtmDn䒭=7cSc9"ṠR>C_JO<%ocξ|Su>#GvD;?K>2a?[ X6&E~^T/U~g8E{T[ ͶoCDblưPV0az/D𑆩rɯ*ܼ< rM0O ;6TY& m" CJ}H=Q v:Q,D|BNiwJ<} ^MSsnY%8 'ү9Y>G \[~{# L}„R1p!ACYOBp§!r_?l$q};|(3=ϏsrK.UgIM֒"㳵@8x\4onJ޻hPQm \ l\Z\5_ptG"'㘒ErBu'aWmda)t^bgbsmLWgG`*;ܦMED=ZaPRzٌ]픔t^V6 {S1RV9., uCC{}NjDD1,X|HrFo@jOtޚ{ˮPcdXߊa,!nz>`K>IqBJ9>xӧ[Frdb{4$7w9GWe!pVSwru! Y  Hy>0#%~pwMGp;=u&,\z~7_e ybIi3@Wen:m3>)k^tv5gok*1jiy*??]*݋FdX՛7o  zCcE7 %"Q&_!" /Vb9?E )6@iK"~, Dq(^#kxP`cpLxÇ1Gl(|<b``@":gL $ayyy 8-V?4w{ |wNm3Iz8wy^JjƢV2~4/^=Q}AtRP@2RR^p}xM3LI‰}*ͭ~}y?? yss}#4sN&&z p 8pBdt]9cffnUV 7܌^Oj ã8ݛĞH<<7-qli#Mq8ّw8\8`H |d}9d56DzOyd$XrT2²DF34s:.%4i 0J@*}EYYp==­;8[޿oSt+"#p,_ppx`PVQ +pj_fee}߾sgc'ő( UW-e#+1ńs_^76LLLjoW}0+zT88 zZ %Iwῌ#)ll(ę P^aa ''y:C쉕f[o5$pς3A6[7t$%eo3y=0`Z8kp> +8'= n8:|98!-o'n*Z^y!2w䣮omT#_ |)nLrePKFWgʼUڗk7ּz0/.ξN3^q0 |QoL(Ss& }ovmaŔ.)w|Q<`ݛڇ[6;Oe&^2mPcZ^ﱨ,$3]6)닻 }/W#-/|TV/V/I-z۷d=G2'8q~PG;[) hTyUk5]פ̓66?pî;&ef;{lN|$K,hX}PP(\n =.4nbc\p`t"Ow>wtir}7j{ 0wg^*.-e? y V|tΝno\_t;ڒR 褠J}VB_VpO_0R^wda 吗!)-/gPcvK[[[*(($gp1ꧥ?HpŠTpXHg4*sQ vJoɧĻ}AKP7X*pԳ}f.ːLWW76 Ʈ4pϿ:~ի{0S\ϊ ŽdRϝ͢SQWGQՇqGE di?6tݨ<8%m455!W?v6 7^e^{ʞi35'K}ӟΜ^+22>I3 o k_lI1F*HޞU`fR6pý}}3U'c51+Xz@ c_eD/w~x!ab _BR6Zm/{ffcW W=MR%>XUKܿ-&"L%EQ&&a o{9>~%>%TMMrrr͔`N_N*]JH|gac]kws!cv0 \yI  l#՝f9Ↄ[lSQam97٣Yda0`D@p/4BRi.{ n..#~j=p~;-D bo~j'Ij؎n+ge ?R}ꠐ)g]\PGMyY{7TW_YqoQ.:1ƿob{ E0M~^Q nrz[ MNU::e]@>pgK@PɀM~4ҟO,on?<<İֹY0PdQV,fw;~km3JIasmi-{ %%%(] H}4⤖\#N<[Έ &&\! ,M].mTL56աB,X"@j|J-{a~s '4J!B}Q=`caaaM2 Ƞ{z @=nFiEa*"P0go}sdskecޟ~f`=.m낂^ѹdذGH%<ATiKW+ T֬h=||3@{M? "!qI]aEttRSQR7 Ye/%Gu D X>ApO> N#X",M-V!!aEf] {wdk\yX6s8 \NYYȳV$~1d8}葮)4|dfAʐzezyy}&rݲnq@cmIE1'Qė2%y1IF Ka}We{`3R4~ɓ'w>dG8988(wawA5j7rv sGm==äu6cֽ>Ζ5i,K hS}8[Q4/g]9yDbivV칶 a$Qߌ8n,+S-e$*y%w7+JBR۝p1*./e4 dTM:gJ~K&*Θ,5DstE|Ed@ޒYbb+1h$UBHe=`kd _^xR`]t-L;s"¨,o˔zPV$hNx}vۂ0 tM~409\پf7vڳӪ9ـA;,psa/۷POz& x&ϯ(S1ܦ_HF+bg+j$gӘ5ўg@ۉY`{pvH{{J{ΚZ4-v0b0 }==aa̰?bc>η)[|v핍7~W_8|)%M_ixrӎGr~sV Fff5Ŗ<) (@J,W+c !L\XHիZ={T'>ϾL^[)!_-F-,8)XrN(J6nk!'/Cejt}}IMFӫ?p}vvQ[? ~,L(S?φ>)&&I}Hİe~O`ܕWP!1ϟߟ^"VQ)NO l0%YcZiJ[YYY#޾TpSz.wՕos`AoXZùP5k@?UYn7SAQ.bQ...Q9?a>hJNqD|BLӎ-^Å[nUH|Ug`}l~=֠gxNMZS~ۘ("Hht؏kZM`YFF&d, 8eWūlӟ?}ʥZdɦJw$ׯ_  !}_` )gl%JoPkX5E?m޽I@o{Mdd~Y4*.k=(]C℩}882}` )%3cO8j-]0Nn#NZBǁ =Tr|tZRޓ+q'םghw#H;kѓdW&aٝ!{pGƳl?(:n8mNFF 6J-6lr=_>"Nw-ڍՍxoyyԤCjۑ+V8yLyxJ@Gs!b8-fo iHRD&zE)KU?TKAѡ|zIGekV-}U~Jݻcd>O+E%i ljjjMk. 1 kw}%8/ _~űe&|L*Tp)).+7lduz|싴7Bu)aW.Zcc1%e?1T徊%aoXQإcv94h|nq=L90W_CeDs|S:яl8ұg]wJƏ!񃗪gf`xw`q}7%~xIkouЯ^w)WYkE&o*FBLnc&])tu7=#f7d75:|MksS$_Tf!6@55$ȕJkqSx;X_DŽt_m<Dggg3ٳmuSՕVk Ix})+;!a~ -?`1J 8߽{8?OhX0KP/hm3 Qkqמ`۳}\YZ̰͇buF=2=[#U1֦{vJH,͊G6I%m;m ]Yߚ8)87S ehOJ+哒b4֙wXp}fpY kgL+3\αO言\W-`g|hGӎk58SeǏ[w]H;J Ii`OqaGxw MXmF$ q{aM0(2] '㺶 =K3N "8&^XA$~}qyΨ gEX,"`f@نcPHcO>WLpg^~e^bſT;ĭɔr}l t|֯JᾐY~LNÞmMqw}>N`\_ߕH L7Вό.*fL+()Dvȼ([YYdQ;Fvw^Wn?z+\˚o2?x tŋ|RrݘBMSCj6Dq%01=;/-G&̾B?K»k~.sɚg񂵵3@XVB"પɷ\?rW%ʳWkKhK"!a:_%r6-[@@Ӥ@0gUׯc;."x tHThS}, x+N-H@V+vtO`[%FzB;N܊"f P8N܀"Ok$4KQw hyQXxZR&SͬlA]'/_~Y.o+&>7#B"Ӆs߿ D ty$D" ~UU.pMTJmd_GGŞs.0-ϰZXX*?<$'&!#*c{JnRUQq0`KTX"iZ?׷ly7ܭ0mh<\ָ+yYN3iT,[C)<FwgՉBR0?<48_V%ug>PvJ?lJII6xXka+rvfs1C[NG4:;2Ha`'֓&#L:::Rz2`u*/^ 5Oհ&%%鱨D T:5=U V=aVq!\!;s7'Lnsy+%ށX?c[OX;aK-""B~dMuz9)o1%|x =`^& tweVk7m۵ ET˝`K(`dzUw/.afּ`b`WjQDfN6YYWVW雿=w+L/y4;Xq@ٙ.8E;8 nn'-7М,]O(bK*7w) SΩv 'N|ͮoW|JMH)yoƍC~߷ђopt| We޽w6RDD+C0ѵ#@2q/pAkVHn+To˽(ʟV,R?UE xԢM;k=ǏvqJ)t"+P9far5ۺ BEof !s,o}Қm &RmOo)8|L!ڔ:_bڷ/PKyKwBwWscrshots/MenuBalans.pngUT vYvYux e\߻/ O@R$).iiNgZ{9/Lq#Q@E"@@ RbJ,?i ^9H ^N?:)ۚ88CLmlmlZ )1an*|DZ%ED$?c|Ġn)}3y)OZg^ #Ib2}VRz%M=kҗ{\ q0&tB72tLIJ1򨅭|NJCmXcz4!Gvy[F< A8 Z^~Ml)_bHNo|2-^17eE_ҕY;l*OeO%$[=O?$ӕ?GQ?R[aCϹB5aҒePe0:#ҁKr7<=5K5$r{ܫ(\yGE6Z^5l↌eϛփi×&s>sЄ4T7"l㩕?@6`Fxt\?3ys{8j*.#[dR\FgMV]Q[삮&ɭC )8{*Tpb˦LÞG) 5$ZZ ' 4[TiBÈf vnAϴ݇UDk$~FҴ{X~?P !@%dL۟a)pH{`HzS?c}k@sa_n,QÆxBGVɔԖȨVuG 9L\ ƞӛ\~Fux ^y_(lvB)6o쏤,s5񪒬۪n2Lך ~[Ȑ%%#18+zQOl4r+~>4 X=՜oD=9ksC)։p-T`y< M{ɤ#<@x>Sw@uJʻO֦QȗWwB:^͋;о\5+2{(eo/d1l}1xֿ0I,uRڧmyecH)OR2eɒJ̉Q)v"fSnN.)Lf&Ju-"DT,|'e2ezbj{%w'czj93~mB86>jd7*źA¨NfaB+j6itR E 0N 2YH*n[v~G^?Z֜㘌|qU6ž;C5w :iMf lt!.$ n- RJf<*gYyZD2\;gi&Bs'}o ipn^{7?eQ9 7^4P86oyb:V|5YLhOQqr=_>B& ־^ ͏뜏}aN㨞JE_5>go'$B5DQK0Xq9:!{M<04i )4o k@S0ƶ8.%'K&ٯ o:HwAQuXl-3mpB"KGқHw+BbY*;[wjwIGӃӑQXq:=5XrӐsm!6L%~፳z ̜SEs%MqU w"ފ'ԨV&{GĨע>5g˕[#?ʑ@PWڡ\Rƴ(%#~7 Awuл-[ 5mL37>*jcmֿ5)|JhLO>ɢ6(-# YeӓWN.'U3.WlA =״ P|G{vNS\r옊j6:߇2m_ğ۶Nef>* U+>3"..#ٳS3B#K/d:{’_?'"{pw5(Oj0a)xJ-i6VE@N(.u9zDAY84 ߸Ӛ7q.;w&WCŻi=mTi3#q7Mp¶kL';][v1ƽ1f+(D2KsL>NMraNLI.V POvD/@Zd0ܤ|z4y´Go #h #ӫ4>+mq[W֫U[H6VV}[^M}@FLչ'y+Z m;O?lq*Tj3xOiWl"ǛZ42 B˄ŅCzobJyDF^PB_LLf߱zC)21I&3aC><2#3O?>pj$zr;b8Tn\ӭ%?ԨsHBªzzyi 7oN,*i XJIIi79x;NKK#JJ߷ '&4!/+`,}5QZʘW34=$‰ ,#5ba _1 N.v qtצe[Ekt#hKߗǘo|>Q%R{HMT*Lno7v}4εQEx'4ܼ910_jymn]yM*UMS`Y/@4|=hT8crO|jɖg1S҈Zd^ztttG>QFs잰JUE 8Zzsnnn:a˾g&C+?SK[Xij=(^&"W-|X,f0'm_\ M|lF=a=ļn/GPܷ\( 82Eq:2;wpe(ƌz2cނdu>4We*dekV([')W6b]@e<]:-ηU7m>dc+L2HY\oFS{Mg.{ _Ơ EGq|^bs0|9gM!spxnc.eoEM]UgS`8?i BHWR[yH7R] 1DJi] ~ 7ݤFVKa87 y϶5Niӡϭ0B{GwKu7gݘpuYYcE?n}25IM0_1Vd*Or0d*gN.>ik] [Zr-F.Ã< p`Zu&<6襟k U~Ah'+D_G~_$kodVL"IwןmYVmB(8Q;X$LWNK޾|9ܵCbZ60qdIKWLLJ )ګŌKɥ#!S%Sˆ34>zWy[u)lT&|n<>nX֤zejNyK9 ҏXqnow+M_9 ],o"Smspi'^~_!$E PHlzl g g*O@Q!.n A+.FCj6՘D}?ۦS$3U=VxS¸qlu gs=MD.5Ap;]3!$ xQsU,6[^ِhhަߪ)k7}K:Qpvc՜YqH垩!mJ3Vyթj>N~9|Fy FfÉRӧ}b%}9WLJRߔO6ϸ:vuwoՒwi9njWpbrN?D뿦|fjjjP'\O84|/x|1{zOhcwoc=k*]UhfЁp9nHyJ,Dm44@Q[J]_ےP=mhfkZFFҘ%n%HBK_BEcw걝&iTOKmmb&Tdidl1sg ƞlvDgu;U:ܾr杆3m[ѭ_8);r6hn5x%%&Π]ϪXVFOdhYۍǰVP@{)鴫mt2 2~'d ^v+VɃ?O.uH3|Jnھi_n8]v?q@>&g̕ڃf^XFyyg2Ԋ4κqQHybYMG*nF3K$KuΖ<#|u^,*h SRRZ<ǻ۶ggjT 98Tn%- lW[ztlw4EfTȎ93֜|b%ֺ4cCWw5!lqp9RK)*H hoKK1htzOܙAxɒ&][15-9g2{nLO:\ِ(ȕh_Vf$Ө]T.I9iرƎiPu-;C9FS֌wOf}XuB|A;]l*ƖXqg91/nk+՜ dO f[s XN\\vdщo'|as{ذ^ȁK,n/iEN'{E6L-ѿm{ gr973iz͉3_4a-H0Uȋn,^\g|yy#ɶzpRpx>Lf%oQbɼm3Y.l}j!{S9lI<Ř߁^uOHeIhs?lt[ 4E2Nۼjiߊktꨘ`*piKCvtnwuϜ51 '".pYQ꼿n/jaI+^-EIu?W-}9YUk3Y+d]7r, oB gο-yhix|RR3^Jw/~U_Q׮/cS!I@<,1æ#`|+K3?TD{t}'X.*,EB4,_7_hޗAǝk O b9NR:G ٱ.Ap9dve.nwp!OBbO666jy z%bW^QNV`p6//Mf ) 1(.+;{ g!aIG@@ ҢygENxxtZ N&cxYoPsa%]nUy%4:/f56}1T7O?0`,6Āfb62R):}M]EƪlX+ǕD/LO U[ߜͶxgaׄ\YYiۻLOik"""2̀)R/ep0f3HHH%񺖨)7nhz0}zpլ ΦpKV| D?p'&q4]_@fqs_9y6ŋy\ 4-~#Enbca}-*el>h~ `["!-֬;0%tU+(Ax}AޥϤF@?9:Pa tI^q/td||?-O'}BADGg< ~tN4QNzR^@.wm $6R_ yAŸLic=Jx޶պ&q3GlU6''kؘ팭"Vs^0E(l{^qM$ R&[͠30CK0LCCf՚'R71"` 6|07= 0A TR$VV)%2XX;Gls38=D2b,5z22Xy`:Ed~k@bJp_\-t*pDb3v*s4Pko55-X++ٙ 9Ldw !HF~y&Ç+qWV^PHzظP_bj7zcZ% nll,%p9X)o* u}noj֭ogʍ`1LPO!wY1Y2:V2l!wFhD"bbϔ__ q.y߹.kmBg+&޽ 4ulg d_JV\$OdW>={ryпsǮ;;JD\:ۋ?bޕߘ12dqS]CCzzz,7Ƶj̹[AhǗ4j9-V2q7999 WNNJfmEuhhhxxw  C6Nf0f=gnnt\2Hf<*,W}nk[ޑ[XϏמ+K%&eNkYvi f=Z9Жtd$mȶPŋcƃ结EעWf&Ʃ $꧚l~WiAoj1oi|V{[e6Fgn: ~W&Oخw;!pJ Ld],<68Z'36X7z>?=!7ڦxjX!᝶%l&# 0Hks|s67v=,1.\LU?/nϿRٝUgV6ihD)x0+Dd䵝FW0vQQ"k8}ܯI~xJzTV !5"^A @ 7oQ5w<η3 qA/ݸ ;xMswy`t;y܉^e:11jq{1Ċ˘F&oagP:Glcgzyש ΏI5e*MiT+f_ ng;x 7:&F0@VkL6#_ЇO(d@]Π"\t$ %%)?ʾQdP^tKQvv]FGS9,BC@.X"8n'A)öKM-N"d{ձ8YvJ$q9 A"s!SR5|>rv)UJt5sL mi']t kjm ʗH:Nc9/:逅zŖ{9M(0UXR_Ŕx."V? (gj,&*Ɔx0VBS|Dd+JrK ߱ ҌĪX}B:YB~x'XwtQXyxW~ȧ..WK@1C˖ n5 3r_BBtNRE×QpW 6iT c+7~{Wֈ"2>x~ad5 8a[yJā\Ɠp DNƫ]ŅBÙfnA/W 6<ɜ11ت*+ M% {T5oWښ Ү d`pDžtIf[|8^IV(@tR9q@Ubi떗hDB k/j:π4IrX7zѺJިPx+*4= !ˆ7뒜7yY!FJYs=Zx2ܟ!xFl!nr9 &&urZ:ZnIP̫+ƴO38Tr_Γ~)3SkK  bbbLλ*E@뿦~ pL O+p 6ًfXﮎ1v?[۠ꓒ8mItVk`;2p$m9;uo";oL5'u%u#LO'Y)V+Jb2zK Y<3G)| }qˆ5 hr`/ mxv615=}Pe@o|ہr OɮKAw]/^}ܮ6;74tms30%E+j|P^οYq?ƒӎ?M!*'4!YzPF`yc ˱yK-yF$¾"c@žz줂c?G'/\4yI|T۬{P)y|>'Cz۝bǛ JflCyd7XO }6_:hb—]eɧ 8ŁX]_>ߛa0a#'EZqqݥnpuߪ:g2_ J(#eWQ$N 0+mON6k|ݔǙG[N2OF؎X>BZkK0 :tu4C$~ b!I͉ upn~%g%@%]?Zo{n47>蠸bwuu)k`9?\L2$??:bg j%d= EI 4bfOu@ov¸b[pCXk[{ HpWסyKD\P"`_V!!;]Nã=hGfT"y,׌F%U(t|{4r KȕdY r9}J,lw4\B^RE0>L.}yKZڐnǷI0*Aʎ 4el5 MֺUrBEmDiϳPq߮] &kEG |C5 PLkxoϠ8gjoqbO iz'ɤ2Dɹl!=\LkT[@] lLbcmƘVIE|oeںVVlI#?X޾}K cB>J߉M+0*R3t _W.{ݳ?Lh1Tq~=+aISȓHƢ7+! Lp_zͣ G+oN/) #fޗ)jah&.ϯ{X8P??dp3Dfp^w|-Ea[5mߴN O|9Y 2M[mP M j5>q_ $XaҢ#e?p ȕч3lgn7]06ST\Z-a *!qbaUrblDpzZoGnePD2 TR结߿o &~,IZ^\L] s?یJM^4[K=_АW o61iX]w&lLe rc_hI|՗xRNu:d>AqYެ H&U܅I1>btCd?;gc%Ci'۷٬3'*:r8>ͱb~Uυm Ҋ~WET{u>r*ăW_3Ԏ~9^?FWhdGp-2 <Y_boE7ޙXfĨRM l2+TZOL%9'SSL/nu\k)y8e[6_: c_87m1g!XjNor0!<Mn¬KK9GX)4pn %8Ě[~^f9v{ G*<>`2?1s.Foe5~?eɣ{"2S{e O= w$ԕIJ('͑%GSo:@%3X9zNL 1"7@\(o"eOL!#;} vr7T'{>hx?)jPt ڂ ݛ ,y&vO; r|Zlp~ooyu#jdC*G:I+K3O.VW*,,98it cvސ3 ~^Cm˾^R[!}QUx(Gp")bs^wǪjx?%/DefsǃhbZS`{k[^.Y^̮J}`hkF3@lpN? `GOTL3RZ8]ZÍ%:kҫ 'G?קR4s M%Fsϙ BqZHg ymi!ȋ$2 @W$(0eċF;S1MIU[嫸ěVr@*5ߦ/ͼH,μԋ کN*k塯Bǀ׎k k\ےx_<&Ƭ֛N~1'*%-òK/.LI}>Hɣ3yxVH&Țpޱ;ow%ϑِB'Η|mآW _rQڏPy>='OM0~#1kk-'+JmG%lc%7+¹K% 9"_~Lv<='%VѽB7|dOܭpjk쭌kvuyxSC2iTOQNˇ6! b,%uw9n`_ C!K|52)">&.5r.ivj>'+ҼP3u?hiYw)+Ze–sB R(P'c 3Sn$ x75댐޷w5`@ @g)819*:JzޗIzPTCEN氖fQ{ _P)%nգ&Q# HH[덐(P9–^ಚڟ)78M.omic<`2^x>.kf gg#xxd<t9gy}swmQbc8p|ҡJbjcf '-XUSPQ_8CJ̑`PW3k|N3u~%fQ(":hp翬J ~-()Vdog'={G:7@>n;+T^W a"aL݇_mWhsk)['2Mrqslle``RW3>(Ú\m]ԫGG~~pλ cU`bcw+f'8(**^o&<~"M%6N:diկx؋NtASc}˃y߿a[cab-H}ZIU.30)-vL1,R]hmzҬ#W6ŋɸ]MZǛt$~O@`Z-$N{?JJf.p>zV_G<5| +S؈%,%yQ1ޜtCgs%",Ȋc_}\lMT\=Y<5u0wJ**~b̀b-u<[!!pjM۽{#ЪpRjiH뤎#--_@<,t7m0\YYh8{jzI`J^jA͔(!C%:$'#&цn̸9RoxH6'i I?mٮq;BrB/ZĤTB"9mJAʙ܍fzm#<$*!?$$3=dgC ٰIpscIDLKK[]u, ۏDˌGdЍC?>>kz | \@zz %M#_:)FC읝∁$ (b?}u!1tG;E);7}&O.6H`32Sn=QB-k7V*4k##1NH)ń>9pO0=j`~nI0qrjXq?8߶{|{)e[Ey L/KeEmm11hLGΩx+>::߲E\Ov _Cۀ'tg bUi Nm@cvYcy0ó sҲͩNba]z61p+?8vSS@XV_cK.sϵp`:1W?a+DZ*&%33?M^r1Y#سPܿپwB9JdwHھGZz}/xI3ȁiSs3mR_π%`!Zrs@ug1Yϱ׳?[i`djj1iK_TLpy2lZZk- G$Fw+ƎX݊L EGGaQG?UέgVK:pPT(Pٞ*&dae˖ t ԩ4Z)p%b@-!R>D(Sn6D=sٛG5T3 q:0A)$S4(ʲBRpW;',\~3,p}21^<@Fs B-v&BtT+԰ZCJՒ_A5̰s-]#<<Yi $ {OO"n~ԧ`MƂE쏅(dti6|uO.GKa%=.vI3c$GZJ)5@| j܎+hq𤤤^'ݸɧ&Oe[ph[ ^?6{SJuB7V(f$997{^v[0'̓Ojt@ ` *{\XtuufgIiOu E:;;s(ry߲30iL'> :ے:.DTZZI5Ț\(t__m[aڈL|VvٟQNsW`@wXf>$ySw6AR>2*y*4q鋝ﮎpkjjxz>e C7A lHOM1ֺ:ZE !qT&!&.fbileSo6؞D&Lף%QuݝTЈ;ltG{Qi  0Υ6=w+7M}}}hmL5 '#ZnaT4qq">\N^7,H'w͜w,hAxs|q1{ws3΂HBNLPﻹ6T{`@TRreƏ6b5u 9B]]]`% _#/POzO[WB\/?>_)E!))9medi3ΡAz{ hCϿT.azdϨӠRKn BTOOiKgggĐ̸Y=>="s0?78[c74 Re9_~?Ai<_&x~TBBEMg+P-&!a4Sc}Q 2---X]/jCCCvk7{4)Bąw 5'0 A>q6 d@{T o섋4ĉ@)eggd| K s} Yml8MTcl] KW: 9@$}lrcVb8  AI{G2~uÏTMzr@= s >nɏ݅;1Ea@]S .lgߖ$ YNe<W[+I4! c(6KȈijB\FFG{T~Y.4̦Kՠ30 /X;>0}PIdCշo<dAܔ[R_]^ qȋU_}9?<Lt1+dpͶj.ij5kz]x(<HXxNN0]#L%I<32^.AG/%''؃@p9mcx\%q~\CW&GC'~hda1 kQot`w5ɢi{ &jf:҃8H[OhJs0BΎi\_D!T888<(ViD(pO}¨#}b * ZB]SWNL\408$D8:F=B_`!@->I!.'-_S00>107/nU*0+K, \[YV3 k|F]=h6M歯! (G*-/_r0S$gew _l409^ 888/gN F9X1]4akD.S1~z|蘚hCJfj*2`̌-_Y 뫿3:; ,0`~H xWȀԹ`q=E}uu5}o%I9`ŋ޽Y,., 4btT ?qcg^$bkA155|fb5L,<>iXIZIsWhM-r/@-ysYv+d5QVB@" lKD޷텪E!|a{K=3V ,İzepM M@JE\;J@i䣤 \Nl :_M[~f",@6[!EELUC vCmPzpv~Ȉo9M(|!333琐\?RRRߜn ؈m'LgA]Zt1 3z*GB}nɨ7UCX x&~lp^XX`.mD1չ% dudQYM?ܬdm^EZj·y/#y?{o$O\kTtB25Ee:{T&T^WÙ2T~{=E_O~V\4stBb#18 #yW0h+4}TigHF9_:~6G/Rgt218Zj^jլh[.K rn ]3vNĨ0jFϷD(4y,4&f/)))Szdk,=GTBQuίs9u@AAty m3_Ynb(ے 9ba Sv4 //z-zn{2*I9W_6~ bTx_P 'P~;Aow 9;* s'͡npУܩy!+# J?wĶ&7?je՜AcZ}w@kn`G+?hx U&? T}ܓ ,92[ijX*޾};;-ԖFݢ3/1_feyL&"UnnnGgL{ .vcgz- O"|ȋkA ﲊ , mW]cA(gv &Gǟ?*UfG;&'U UzA]I ת1**m*A&=]LճȲ#hʺYW(KMY7LuUoXO摰 X,$foQ6W;PB!)$mLCDVL00`(:/Ǟwg#ȳ_Xu6cyMNn$/Y<CZ1a`ja< k=Ϟ={O vd=2ItS;D WЌH0?g_f!{zdonPD(I i돣 𞂜\VrxYY$:&R?*mѾMRv2ĬVA88EG}@A"vuvNҪjV}[jy{4NIIdPVgv|wԺlP1oZ*coo=bL1-l8ܿy3PB '6k ߔYW5 4w"Wtvݟ!#"&djD){3b[ޤKԑQ_MUinb2TnN|E'{Lݣl ]Eпusk}V6iMg>wt8DHIU.p}T<A;'ȳ >҂H)ekaQxS_U[ão J=ctфu]tcؘ(ȗP)[a`}|vIfx5G)rA)UPw(xi~gi]=ZD_lty"O~m/<$w44"@ )ÇQ%{r211 6~-od^.^^#򉼮 ʼnG&=>=@]Y]pt|~.&)p,/UfТ*\r-?kkI =EUTpLapqqT/L |@ŠXI$&&Ok6XS73Yԏzl`- 0عtz݇I:.Cbr׿dB_>??AxT|<$9E)@y\_5 M~[H*evo.5 ]Nvh? d?.d\$s5@ \.;8 ּ}j@"WPܽ}*o@ZHN?NRJ оé22"m'kEʁRyJHvEnf+iaj /Ҳș+bozo?lཹ=g 8w&iIII  @q?aE-.d$C Nm:.wƶuu(yP^^n?|<NLE#pPVf` D"KvQ@@"GOSY٢I՟bmwrS1xD68.AdddL_Чcib a{*31y Dr |%4a=p:zzfMD&CT{b]kh 666f=Z rotTxk[`Ab|l_Z?R+}Z'XXXvsQEeros30?)GMgh`k# wG@it]Y[Fe-F^]˶9#*?99w$hޫ>LerX{.l5SH\oZ+@\ߨo_kl[CD"U~| V()"<?/ %E&&>)فf+q%\~]VB_ѿݏC*ܬ,@ǻ#2),h%m# $u>&!შ =bb=P^W4X>뜁ȃ;6ͧjt]h%>sq^a*a5AA7|;**BEPYY Yí3SZnIJ -x-''_;R1oU[c`xP8Byk{YOpO`!Bri|!z^[\˭,6898t4VsfJ>7JlBDD2)@D$wƙz>P fTlTuMu YX2瘊w@cb`@8]FQxg* P4\pγd :rphA5U.Tr5j0+3Fe{X7-r+FkXs@X6eŭ1'6upP+@-ߍ '-5{ !iY\f5?>L)5Si."* @H;p›WnЧ^:PPKnkϞ?_-*m)T#dl&' jL>`B`ҠynKXt >3/kArd`?阁Ad(9A_\2%EYe,Ek@7dee] ~ҭ|^R潺^JLHXIJaiiiA~N{/&OT$,X\-j5 mh{rBƦw ?z*;Kf`b<'jz*ynFeen'ٹ|//H t;K5q \mi"q^t)EQAe(Ż7KykzKxh`#fޅűGS}VD8-,Z5 ƔcO/AqbE<@KD,q򚂟xQ{􏬬{%%ǫ R/p{YM;A=x[T2Gi ˌ5ûӽ#Z9_+ߦ6e{v}VlgC $LW!eåJ:n7g'[NLV|{[\X@z#NF~ic1^@:#,Y/L m/gU ABX!-=2 zzjw>]r/  \ڭ+4c<@%_˹Gٳc⻛wh`%~9[lX$=ދ,4ޝI)9q]]1zٜП mssнzQz$+?S$Z#S1r i)J}O=JJt=ZU2$繾ioVMLNV}B{M)AU "V1_NzjOKAZMJJ6,S6'tnؐ5 LLT|aDoi|~󅟆=gD9(Vw}=Z3bLu&͙˔9C)%|̟ L7?L4l_$z1S < ,rs%#GF-OW(^pwc Pn_ηu?Abن~_Oi ŋnӣy(>47w:b٪Ejq"Lop 'WR‰LN4SƓS顋b'0CfOzw8﨩7{OiV#!ueʂX87+UE<k |U7u9!ng^-=3/#LdC fDLLD)>A233d hLܣE*ym!yoaM>IdXڪbz@ D4e]CCK.xl$^u8Kw+0K"{=s/>F|~MP 2[H"!SsםqZeqq@-//> O=ή{,d" Ԫ۫uz"p>62\Yɪ]%PIɉ{|EF ͵t77(9V{2gpڽ=SN1>>^Jj+>i*l&ƻg5s~xZє$jÃ]ZGG\Pz÷r?Oz)2hNM%n$puB-]L[dJhQi5|`r»/A~ⷲ":˖=8 %I`~ uӝOOrN%A\NLysb *޾e"%<"n%3D\uk++]JA - @,є(( g&߉ *] rG< -=eyC +dfUݑ4~&ڶ>pȥx^i~U0B*L+|"U+hemWxBKmZŋ;Q =; = }HEhVXJњ夺3_r$;'ΕɁ<__ŊAsXxYM &Uв FtRp $RI}ȭfa-b!՚a鰀X³nn+]ϥNv=x^雚"(iޯuj9_B=y./ [UƇj#kj mrn]~wY;133`t[yh]y1SϢB0\3&:mQ, 똉=''gҺ5@ B<ڟ]%^E?]C$*3-p6޶uԌ{3k/ChI}Pa 蜦%yz`uO_LVy9'BF瀢 D"h`o^SyYYbP23ߑA.9?5<;m\jN :iG8۷ [Ni@K6;^cA!~\aYEu@\NpZds3?v{Ock(ܖ~戌q~}|iii"s𾩩)\b,񾮮g67wQ>ä/U u Ȁ Loi2"*h/l<({%&d`;46_A d -N/\Ugqq++ҵB,p)T~zWУt/eSGB  VKڪy4J >xX1[ DL|/#g9ЕL Dnjyi,ŗT*&nVZ#.զ=ƠQLkչ@y,; J!G^H+PKyKA糞scrshots/Wizard2.pngUT vYvYux {$= cۙضmgmۜXkb۶ms~UtuWUw^jw%`q`A@@$EA@&A@@CP_kkd$DA>u$~!o5ϝYJN z4ukD RB?WϲuZXG7_7q6"" !\D߹#2hށ2oJBzhPer`0q\͍ܯYxdB7&sج?Wxc.ٲK; V{ j ړm07{s&1#F=2 B\l>KܦrtTs>5dX;݃?}`l,_s"ٽkUi}Вbm eHVbۦ sAF$ݰ۬\\!|礼j |,6 ckP1P3rG)䚆0&X{'o0M-G=O.Sar7:mWOió͑qK}Y&5RjMӻ,뽙G=׿>mݭk,"Nq?Ag#f`8%lxl^_:%l4:t i(Y˧ \\W)ǿϕ&8l'c3Uj+jxHC69*>[u& q>q܊vhL=+xvV[U뼷G04acЗv>QcicgR,22@Kqٚ*zhKrOEZY짇Xg[,ÖEDdZs 2DG,sTU̮+EYF>D"PYa#^K`X6l m=٣ma(Ngm~RҕCܵU5!:=zButOy=25zss+lFloJyœp룛B+bM -xʼ[C8bD0Kb,Aſ %Eg޸-<€[/Ajb9tetlrR40j/:EO:zH^ITo{j18٭T>{*K?\/{Hi>rfGvfILz«sh7׭< W+mr7ۛޮWnQ_ NJus,zWcY`xY{+LzGn'FՁNúh&9"N{2EWR-1,#Hlk9<k{nRe찵:ɯJ1Gm4-֞yƒp R'9Ҽ< rTՄ3acSL9ElYg^dSs2  ǜtշ9qkCZk*]2ZC1 I)F4Daڦ#tw':s}A0bA~ퟅ%9B~_c2Q뼵ʗ+UoڻgpՐr $`EpR+@ i#o=ofDR%i1.=*䚬"E58y~b&2-M◛ZE'%}bl 3⍙T8Dzn}9Ls܂JUT2wık}dX2cȸ?=JXN 2ltZ*p\TE6ŗrhWQo {sl8.3=Ty£&$io=# {6?Oq-k9k׳r⁜Z&p$G ?GKOevT?aq?yIQm&& F5\hϱ2ht/Kn-K{zqUnƽK3IdlA$bg &  z>WeC"D9  IPc~p>HEZy~ - @dL fP:8ජ#*xF7Fa0dX`5R$ ^&Jjݏ4 B ũTdbr;Ni 23OK?)##Ձ*4./ #BWlQ+`UG曲CV&IΛa'gcVdqa?nwza¢IRAZ48f:Ő +a)*1$@,®ns&4Fnl~}_lOb s(@K}ރHB0AhB Z0c#igT6RH1EvOVfN+`i 6aIR05&q&Wj ZD ؜BԴh(@bZFvpx'Hd rdx鮏'8|*p:?4=tՁ(Fto"?JWBl@FC ]#NG+Ois>~T,$ ќH5{WVOкd1@0@=1p͸yr;80bw:84fݾ[@,q1#FB&z4lmk؛[\;(췛ݛ1j'Ͻ&j"˫w X,dgG ]~[[]_z)"ϸ[Q4y06_[&Ս%4[ށ#q:rLd}0N[\]u#6} uuchv^g'ŨiwɥR{g0]-XR\C[{"cq!<" p"X2H  Y]N4=KЛbLfE(}ɩfTT% 7X.on98Z`ʸ@-[drJw{B㑇 3 ړr4"ziiy؋XK[5?E+b-T`aсE _Lg -Xtjĵ<n@1WD*B Q/WՠO<20REM,Sbo`RZͤpj'F.us ij9H^6]Mt:V3ua˂]#d.m}uBur+i'6ӾZlP[surg<{({ .Uy'8fROʂsP%ԳP ױn1i":Uol{|Sk=n9cv0Ġ7䂶;p8&n>7x?<<<3B0z2T[e=E Q+ RR„W nwk+Pk*Cu+>K$&EE Tk$mMS A4QՠzI2|KA&2`S7ba.QKc0[HIiʎo wTR)hIĪx'2c$ #Q ׮r<<[:VYxwzݗ*ZouoB)_)Ro:^ehs>Xufyxki/qLXa=J]ǝ\Q Q+ZJ<_qyoI*M=n&H/ߨC !#pثC㦽GKW%0 xM臘g7n4 toTyQxLi\aB/VLTX8$b@`'NRȂ|8-F JFKN4x [634La&B4E2(FQ# Q$qϑ>.oy+f|XI6f&_УP Ȅ*4qNzcbbUrMZX:myXI`z1zKYː1ʾɔJ&CK!CXװdhlJZ[L4'lɹtFl̩@@JFE30B]ZpLM=aTc0w 2q 1QH"]42P\<(֚Z4!718u3u3v9r/q]cgTkhr21x5*_:)O೏ q/{oޚ' tK6AK5AQu4MVʅnT+o)^m.Zi^1/ѪhvZ-FFi[8x̟tbsVS]uKȆ{\Jc,`~5iv~{xHՈ[.>A.)kLG%WEgq(R7iL)<'caP7F ˾C..j@m%P[Z5+&Ն4`B㢕 BLӋTI.j6?{4nf"J',$姨PDKr??uIa?:b oQ$SkKy}(NժVI+h=o6Ax7O"b-M9|=r^bԟ04-5}ABϦU C7I2UAZC- ,YJiΖLϕ Y&#C ƪ܁ÜiI1@ThW*i }+>V^A?>Lѹbb27a3@}\" SV~P+DJz6࿻8j9`ȣnmWUl8_O9abYKL]SH]%z*lj҇!/ ~*'V{ø~u{t>U:p&*&\6,hТQ;fy%k:ar['3/WFNTѫp8OL} oF/\+YZWzެB~7gJ;!?PݕӇ$*yG>x_mtG`g'0v~++$ڤT(=n=Ld:uNFcBvw׵M\Zu3\Gqԡx͌eZk%mӫnp$FI ;PZOǁEX7lWNS3߉nŭ`ZZY 1pw^}ǧ1UVtʌ*{ NNP€ xN_[Pg 0˶?uV1 5,S԰X0yrJn[vSVrOPVY#|4PVgaH<(ƙJ䈮֐x42RÂ@zڀAke`̣wah"ILR% Eϩv${Zs8X up?N:ty_;|؞~X5q9YtVp]`z?dtUz#,/:}kPE=xֈ?4~sukP @ͭqKzM!#LJD&!L%fݭ!>\w0n9#խD`(STXY Q#xQʛ[AS <0LQxX9hG`p] Ύ7Un AK toeDv]HS"BBRU|ђ+oAZ)@`hMGFB޴ 9QoEU Q!l0Plams-Ah`M~-HCLpL11 @ H!\PD~ooq~hڶD\6nW#'S1H?D,x0_|hƌOGL/\'`.$ya1^ P$ ڋN#*S+XHE-i3~+ +)W0${xzBC.9; )bz ~0*Qmx^z?+Rym*}Rl͍C­xRareed1Vh QvR>t<iFXs}b"|{89rIxzp5݈>I$e<!wM3dU)riZGTf F"RDZ Xĉk5I2gQlF T2Ƭ( HdeĒ&ɋX S 6EB4wbZMYnh҂S47A`PQD$i CW*har}ۗJcj(H.@Ob uý0]>j(X&z1_U0!`=RPܷhtQo/va3E;A%8:qf˔f&5CCp'%Y aH:_kO#|?xۧI8a!6N?oRݺ^u0ӭ3gy+;jMy}lA߅o6p춫2z2+[{oWr !*7`>ja"PJHدKL 0iȭK-zjZ] -#8 }P- _7l-τi_&Pis䒨7&ֈaGpͦ6K!|bAGLAcQGCY*cKm y'EY'AO&HO(Ht0e%V&mP_y* ӕaf8(V ıvj-5 PN԰QDC#+=(h˘A؎RO^'\p,~hԊ=OT"A͈Oؗ_z;~g˃9_IO;H_\Ѽmӝ~> q]߆݌q}iGP׳z$W=\~8n<:] G9%ٮa}yUe G\]| #~{|v~6 = H(5c%GZi!$ w qҌ~Ɛ##Q˻wZAjŽ+*V:X:cu3Jǝ65Ap,N /)Bgk7q %fZ& F( |XŚBjqn7}NLFycCyʝ/b%UPN m0U#X`*Й.P jXVE%KFmd,(R;;A`3=*ѡwz EҶתRXh4.K:Fv=TVaQK;V?gMVO";WJ,} K=9='ԛ;}iVa7qa&[n te=?W|E:~&7s+˃YpS+UK2sRT`e{T,~^V>-P1t>?LnA @w׹{nO/W E OITd8F'{f?1{ 7NvjSCU)C‰q!QuHL,&/j ,v"ߤ 3AZPJف;ua1^,["yD cȃ yʋ$BD摵qZ1lLpQAb0 {-xߝx֯uV>:X>>=K3ٙWQ8}R%޻i,< AtL^WBvm{vvχtV7/eS{?wF%߈i*EoF-="{k zZODiP kiEx­q p-$E$%gaF;_mdBe* 脈i5CJWB,R9j+"]R(e8%K;ϟk-A pʹ;}+%ӥFiNR}qeqǫ~]ۊK\,,A`5=aP+iv D# Tx١%0_+|6 $C[ d1BVDRRi6U1UATFȣBV C㔙7ycO@axUSBjCIIWn/TznstY1\P~Cg``1?pgi".t/[OD8&X'ٸa1=,+91|7尝W C8i $a Fpq^1ZZL[fVHo[= f|B^\X׾_Da{@_}}q!iydHf)q<m̄&vß.eEkaX=| 8(*XQ'k=)DXeܻ z4ɤPQ5T!;C amFA#(~?3(0Ǵ-~(XA|o7xh}Ol2D !<%yX%~\=>GU2_oqj77. S%K3XgK!,Alޏ=-{{D~unn>.]aNGJ]o }.'Au*W?2yM|JwԨ%Tn/?m|Im4g}Lꢎ`aZ0(17!#׍ aMDli͂2q]_#%Ogwcځ?zlga1.6 6|̬XR626g˵:n.oOCfKn'geZ<ͳ]0r}?NW}rxK(3XrOtVTh8j`ofvG~9!2 6AK%;5y{H*"6)*(a!0F-Lju3_7+- AwIξTɛп6,xˆhzFFWc~7'Ļ?-TEmp:{y6(MI4͈f2ּ4 hTW$u LmlϢDdXFJ9֫gjlMޘ 3$,ip30'D? ֱ;7;d}~b$|{!ldUDVPQEClO?4l f_1S=l\,NHq(WXaFYݪV!6I"9X pn Q&ICcG&e񑍇Q!:<na9,A}EO$(h4 ZȒXRjTEZS+Qp|+%P[|B ;a6ٶ4!c Ǝ<لl61wӻ2R~āf?pKۤ6=?Jĸmw s`-)!^D*$}`ГXc3TK{mpqdXU&BH MH4cؐف";u|6[! ]<g,Ec[+dyZ80\]4hq+U;AP0F6߆0@L1 wB6^@āJ'.D Bl)AVeϚ>IƩ4B:A.*Ca&oa{"`" PԘJ@@挷MF_)Dׂ%.*MZRfE(m.R5!g0RX鿶ܙZÍ6Û fV_@Tx1r>dbZ0lv޲>*#nI)P>T8*AXsbG@O$a*:75lE*DP/k_ȧe{YuJEɬ&,/ Bj0NT1c^GlGIC^t@FC֌b|2UKh>Ѫ=w*c3e­` Î-!B:`͒"<Gˇ KCW@M~F J Qy:Bg "]kʕ i]衈CJ?K)akKT\wmYHER Ǫk@q}& /r\Helz{b͊ H8Dҷ"#+:s+90RMr:bVQ;)ǖh7R|WIO Ii>nvF`6:gڥ!b h n: *Dg(pD ^ᦥ $z)5L>5ɂq䭱rCwCFn&wea<88&B^N9ԑRTp#`NN(P@U/Ey1F(\'*Ҕ0b UO܏o\(`*HOPNsxqNt-c I9\am=uĿrbabSf@Rݼ N"\+ ޿e -ǑO$o/΁ 3(3PG.tb}뾅6b26*-Q8Tp^BX Y+(9 /0 FS{m4)nQM0-jFU[/NJhPJ:$۠ %>!e a@ NĊvgײvlBo4TK_;[&xTk=tDI }܌kR±Ӣg*U0~ ^3d aQJ4@-ݓ0Erǚ$p$uI*T֜ {Y apRKpE1jw1벪bmQA7MӑwQ;!$b ^rTKs<ݾ뮴2D:т},IҾ3i([);4Oo*߃0U_ǩ3Փxh!Q%d(@+OH~acwrbȵbw1"(Aa@5QE-p7 =<"R$ d~m OS*ԔhOJpMN!9ZN?LaKv8ӠdbOvAQӨצѺW:H (dž~ۡIk;俙q"ai*WAgℐIG l4$ O#}f8I扥g!v~VE[A%0RyĴ΄׃¨:Q0A}BC$IIlx "l1Cv^#ߖ%Rs,>yi_ "J!+ R:#>GC]-1EL E0ٞ47Ib2]HlW0 SXHta%I)je?Co!FsZKPe>BsL]9/D n(m,Fϣ{cr:@ W.snhY| 0QJ8S5jd*z"NEJ}A{qɋk3%l=5аH @.]4vEg9^y yq AR ) P>}U ih,q,ڱɄ"Ug'rmN.:h++T\H}aLՇCkji2iTo_l7u/g][>EK$Y[R :CCpe~NuvmθGWz9O Ȱ夈@q4x;-8^!gZlNbT54C1(J2ugX•$>ݴR˦ 1b25҅ZDSwΫlAA~*9_<%ddzɔFa_+_dEsp|e+dB x9 pŬsvA|sol7zvKo sM͋+;,!bpXSVfKi̺㜉 k|[S[7rfvH8Ip4qJ|Uڸ~pI\NƙzBR{PÒ/}2WA޴;NfpsB <4 Է٪я `uQ)?w4,fBa\09ᾩW}:l4.%_X)~?lxmҷO"~)c'O,+fY#n=R4]~C"YDC Z\RH=릫81WXj] xsKMȿZTBgjу!gMxvף˦F*dnZ\0Da?h]# m,i8%a #~UCV'T :{yʦTjV>jup[9:܈"4HRwOWK?& an1A^YL9y{~Ҟg?Rx_v^vrNBP$JOU f*)c+[7.W!7̊g$PƇԼǀ˃AG\+kߺW vgD$D *]ضB8:*"v).'VLXEL /|jϨȻx]Agt2_t4u~;i|ml;'p޸>TV;yM%Hj)EEA ~?*t?<^Zkc¯aa^cJeMdEqS 9LU&{T^!UNX$VC:2q45AR$LZws!Azݾ C`bM̫P,;la-wͺr1ϵ{L'68Gy \p";5~6,X!y^&Hg~컃E1|/sgN)b0e#2$;@-&_7<$MC r(/3S _ćNG P]f;ݫ촺goZf, ɒf~1(ԕp }CvETX*9=bmFE_cew2^?ZAR?i0Nޭ$A8As[w*Z?:~,-R]}F9|Rn} \v}Uy4?v:F0 \nAT+vmC霪R< 8-kyvTUl\~te5eE)hcʙ jX {(2} ((KjW<ך&Fs.晠ٲ crǟlrv%ż# Xh "k(VV!qZKu I/`L?%zh0녜aGDq*a+֠+ ݁"՛lb@55Vj*+Y2-uaEF3V2 #[mQK"S"Z,d=n({c@"Ž$3̀]xPt5ֻ\F[Xeq;PN ^ )ѼY\Xwݮ+n}5T-r 飽x:i,..ήm -ϢO00}fg&F|yER$Nw%4tYub_R!ߠIX jJ߿wޠN> pwGslJJH@#+@;O'7ql9Eg*QY S|Ck6v߉,1`#γmP=c㪪Ʒ,աމTUv~2#"%A3:2ƅ w `/so)b,%K!EEI"2ѰPkLC7)HbAq'Ek>:dJ͊k| rF\/ٌ> ZurͽE.De` QՑj䧮 @W9:jSMV&gvEqª&ZZo)mvr9N$k& JdH-M疺mQљLBSruLWM,,YaF d"[LSB&Q:cY/iNhfğ""q];#߻>/S ]l%]*( ֜WjWgH6.y2Y/#(( )~&qi;Q|aff|vfZ?Ƨ:R yH? CkMFP\pMGP t(JCEhao%T縒?v Q2Ѯ󣸆j'3 * {H3 n2 )I4FBGVS8Ј85  P'$ʨ8I=]jq7ؘ3FZ {xƅ Tt[bm1WAETs ?> yʯGΕ]-dFIvl R(<9>]3II&(Җ9xL8G_Î}WAJ Ē6z/u`=0%ly; vF-  0Γ( ܚ 6ulFe"9íMO"4@ QӼ9;jMm=H/;Ƒ4A(;ETWK<ՙ v=Nh$]E+8&t-巆QB$$(ރӶאc}2Qе_qbQmΘ(%ewė+on{P8mxp4dN\)j¿锞C(`y"8C\W Z@i6@v"\BKKR:QnQa:MpqNJBܦdΎj~yӹ`4nʖAyvNivqLr5l)t@;̦r|_Tۯ#HX?ɂ[&LCWڥ VròAsCÏduǻ 7vE?GK~|<?D~uKngS_džHc8wIl| z@&ubxo9'> A/A0$t?5Nxm2)5?/ZZN+8УK/h661Um>>| c4ɨbl-It^wXc\ Jm#zjZV|AS$t߃Eo<8{}N˶J DlaeYшpaRbTjVah#X3$-VK~<?p'ſ&D; ybV_tJFlvN"f 3iN6V̸d+U:?[X6=+4"5Wu&w4̈]NZ JMjJGȰp%Ose ,o^tW7_ؤ$EbrmɡKl]S\W%gۘ,%q9 =F8e7Gvw,3`Ddy r?s#wz?Agu6w0cWw4Zm%O$?m6 L񿞅u /|*ܠ~g4f__gEf}@29}wLOJէ\u՗|r]mnQב1X˻zmX9#ѪC-䩾sRͲ${![Wcsou1fJi4ױ&mh6]bc{yL7E?9  " Iiބ `#R(?ѱnWL#ٔDH*aOZ.>^ONE/C!KšPD\#Vh8qJi̶@UDp4+ Q,BMT6,wi'/~.J<&Z8Ә[$ ]Yv/b2<xwƣ7D,Zl0%J[ 8Gglwܡ)-z=lT;bYFjKzͰP; Jy2edݪlV*Ljxe*${d$,(_-+ѧD ЄZS* G$!i 3&P`:@ Rx{)s4rwu"Wuz+PI˪B*M٭V\ՆL{ H>ƃRdciLh{,nViW]`x;bZwͶ.YjHJRt~mD4P!HhP#Z*~VNt7SkgG[LSu`Q 6 4j@yEz܌NEFL䤁Ԍ88r "cFsE|A9((51,A# 67k,{LRXYuHUJ'MW34'5,6mq4e8]L-o]%[d)s~!@n ]/ $/hbnu_hX<ٯ{2Z3z5Ԭ~1$^M쀟kTT8@R^πK.ypyیަ^0MQh]"7M0æj&U"4E>2_{VHA[ŢX88@:T HF/uX"AocϐUqkd/*slfN3l 6ХSnFxaW/ivdj.(yѲ,SC^-XL"_PuZ*p1P@pU5p?m b-1*_LR Δ]HB*BA$_%-{ ,ѯa{Z08Oa9eF%TDXYD7v xx~͔MmiO6nd,BP0pF2KS” . kWKrR|tzd6|E3FbN0g9Rg}IHTwImk?B6zٕEHo?;璍k%=h\C_99hB/F̯6}S=1Kfk%7nID+Age4b 7?]y(B?+sϊck6Z|UVUv k?[`!r}';v;&7+H_;Sg0qpE1F<]ް;ʜn @<]2t[7:7b"̬7EQJ=x)vS` CpӊC0W q/D&8~Rb/)$.X.i/:?^ YG^:GAmTΎ09&y]7BK|= D%@;{ת{htޑ˲Yl9d VJL>($r4";^fm)#sTon`IrE!i&BTa!VkeVh>/N]p|JC^o_=D€7OӎFWʚ{-Go+uvsߝw(n@WR.bu~lxUi8 7;9DcxoU\g+%7O-t ڻNEAT&N)KiA?;M`G'NP5}HQP$|'8'84=@yA{PSV!r86ZNT90r;sGq*:w{6-v̽9FG&%Yi1ap8\1׋Afc#._6?ABrf!N^WZJMR9JjtW,_hGg.矟8g)IީDREbWl@Q1 Nv#UiPk$j R(#eHq'4?{`x`hGu P֌G_&:M{(UfK|jgLk_J'j$8iPPaiyu߽ruAޘpaF,m0rϛ𥖒UD8D=@%"`|%,%] ѐZ%ކi(߸gR@`q>jP_tZ? 8h%mA;[WxSZ]Nרlp3ڻqIVҁl|7^BD%e8c TBgB^rC%KGSo;Å6v0HxR_Ph?mBi8Nۈq&J.0[~DoØH m6I:i,G԰"b>C@4()Mܣx LÁK aҳNw|q듟[OLU =K]Ҟ˂S4TNbU>9˚,*'L Ѕ J(aͯm̾FhtOpxdB c&˴TJ ]7RNi:̆|yj̳S(vpm"<,7 Եr@F3*$ G3!5"X i2S +I `6UN;=,JӐ8F#G#HjKJϫ$J00X^$600GL/;TCM`-"2>@ /7 )"l2bc$!lfs)oп Jlj V*@ '#$A@QVD,L!YB7.M"o`b깕Js$VA" RBx֛h0p# E:c~wߩKUb{i[pU7wiý7q-J̟ljP6M87̆2^"mFMibqTOi 6$Wqg/c6jQeg)-9)k/tYrBTXF(IMyKyg{<.DuϿ9gh)7,dLS!#u&!5[\VɮAbɧ437Pv/1E-6FiF!^ 㻠H[r HRt5+<644* Lpۭ,R"fD1gL  *4,BVj0Bp)dhޚ:Eiもi#wf1O}LO/$,{+O5[4v_o_PZ%.YuPxvi3kni"[rvFl9:RQus&ax8sBe"YXQ/?+z'X3˖ۊ'n¥"w[ClBM N2pr@Xy=zyUlO/ҫF-[FPj3Dum6JB5yd h֢x4R:}2N_Fjho:EޗA]Wmq=cFDqD*HGNaӉ"@ gEQ"iEZG_h2fW -,= T`DE{Jx)2R*bL=^?+ NӓÊ ^3 {o|Λ-4P*Ll8Y~rl4QMĜqL EՔCԮI$rdoS?[W F6!~im9Gryey9H7H7s ~8RI^[QX1v"+i6$`a̧wjOG{qN*>l;rxJHoܺ I՛0 e#iI|H٘ŵDD02\M'Ė_ D-֬w1&VQO=2O3' '73$Ws1L"d#E',`7b('Ll7Vtvx;tQb*qo0{yg'sc%1p|ᝳX?EX !漴K@MO:rw 1E 3#"[4˴X< ($?;;CO3vdpB\ ˙fV:ثSVʖM 휩3mY2,C1R.`m ?J)"E!NBm9ŕՐ(4l]XsNR BI)oW+"˹fAvbD:Iu7>WA.c)Bȩiua7'{K| $kZJ5tJM4nAڤαk,ĔYxO9w@Ӓ}@@7ƺ + Hx4esojK\&;(!0W3!lA_ lʧ& [XHKT{7p4vu{Xݔit`mʋ1NvA?f%j#P7-Y17o)xx=HbJS@Zš 4ٹ:_ϵBKmmQCEV Ԡ& x4]:#R*8,H)9|3T0dw4$ybN2ޞ8$Lߋ(Yx=oi̩) HBb(,amP&&є\mZ/1# XR(=+F̉)0ᢓ-N:@p %WII`._aCa􌸯@IʋN$yF#Õ-EH#j 'Ƶ%eȈ̉,as$il9> ToF618>?if~s7 }OjE2%@Oլzr^c)av55D+Ӄ(<r1*bߜ˥?\JWX#9%q^b󱼞5sJc+Cs3`X1F{s9sH4 m'{Un~NHxP)2Pc'I) 2#eԙ/6׷!6|9ڬR(H~VH 6Kɭj+isN *Lpd<3 2k*۪}Q0Q8P) l2f+I)aPZ"R'R[e*1D$@* zП]"^J@aE 3(E,^4Wd 48$ J뭁)7_мώry"hh軣_N8@ӆP¸W(?E>?C+#Jz`nFR,P[:J)Ek@rjx_XkjSŏj-1`!7T0/ -B,!-#52Hx/ ŋIemͱ1\BU#8]G2^$d LFk {#).1Ww z'Clv`CE-iXcHiz4Bi͂rY$Ʊ&)Tye8R~⨿61%d"X-lB>T֌MY݀SGg$'j_EC_8/Ԣj{n)?͞[^2skTO(B^$I*B LE"䫍~3dmCDVya.UV~ݔjݫ) s\{UD5aAф&-Jps|h1Ո)œa=DճeBy/ VWiqQk6H "._j:J u0mXk]сWI ^cSY}\jftE~hD.tw2%-MU˂xZ,&@a"0Fok(qr>h>3big3Z%G2xLJ|b8 ?43Byh<Ͷ-&{W042dnui_Z$a5U*Y2\"Gߎ('wVZcw]EwwzFn Ybe *BMa/ߪeha'PY~+f3(ZW&8;2^[Ee#hVA(q0r%0x6@&qֽev+V?s RГѳ%0T0 Q]4ڤD*:#VAV.T`,s{ڈ:57N6Bt~_ϰVe m5as7bI A5 t5Y!2) lIʍn(Ґ xՑbwtT~?kNC[Tj⋸] i5iqFMGhOhr9qLAG=I%NBDDTABm.$!DMŗ"(@ z43]pP#u%%륅Mወ+JčL(dυh|Kv"0lNRdqF\|?lcC^7y:'^!ElWTVV@Gy_e_ ߹ᣢS#ikl$]^)Tpwc;727Y-Y(C KǣJnOsTg@UGt%b0ϽG³KJFK˓0#][oy&Nj5zi  ;FuUґ9H*ǘ&RZ* ޸~|jMۤIghmAB㶕to<6![#gFN>QSwmLBЌO/[ȉK0ױ& $I O S@~H _F$^WIiaU46Px;k쯋n˪ J" \*˒:o-tr)agcaPy=c09_mg@rJG7ֆVOEly`\__z7V(0H&, yp& 2O̼81?=Τ`%>+kE3\%CIܔ&ܦ"j(}t/gD&7_9yЌoԙCc^nI1M'4[њ+sFUuYVTM@ߙ [#-Hb!qz-K-Z()⽠tvAs,t/͡ȍG;i*lS(<|MԿZxpԯҭnʎAuB8DSDm7pa(VvK-h-'gf=z*?S~Sڃ&$&~D;0~۠tGrŌUݔ=#6f,B V7>| 6pԂ:ppOSS&KE&*쬼` an} <f2n u7-t#ʿA!|Z0 0BؕU/?Wb9Vd&:n[dl.0KD)}ϒ EmDTN2A›NL#wɋ#@ Ǵ{^ r ˴MZ[V(-XF dŽg\rbuRtt|?U}r-DrpL)k=g )TZ6aن,MAA\n4JyByű6_:g"#:?)͊8 I(O*I`ņ/niP BUsS,t5*?aЍx VGe α!Pij7`o"B ؟F"%v]f4?Xj[P Hm\l߰~ w-}JgEFLRgLy#ЕM2/ c%l2Bۏ\8~"I9vhs}KVy:K,So\ueoGx_ݯ[Sx!&r$>!|^/FqomH)<؟2fʎ'e%[[ *['`PH &'ضmg2ضm۶1m۞vr9uz&;KSv՛VwfNzdž]e^tL'ͣW2g;uxsԺߙP''-X [v`n/Z8]#ym΂5Y>78&8dZ5-V@mҰFr ]^;Y O`$qr#\rvvvESK-0C By\0+usnp}b\<l9>| ή\4&>`ME2zB^${!ɵQA|qsv - BD}}q%0 z,E8`#L xڭU%'v>T"o/Z^3='+[/e `(RV($@r%!Yǿ}~s h k,D-ZC)e&o? gp+46_}΀/ f©@ySBRUG K0;,+Ϝ9! v2ef,.DP-E =O7Lin!o3LZR%Aߋ-O&MJde!Dy,Er\ \-/źX`Ә+ݓ:T` f mڏA@۝e*A;6N nAˋϗc%xۜdG6@=>>j>'xS# ]=es^x~*X_o&%uVYa < @&#A!o܂<w`"$HpYEH~5q5L/⅌Y2sQ%? Hs$v]0(N6y2?zgFK@Tʂ$V?d}[n7-@#7x@k*@51v9Hd^`\7|*"G6Ϊ΀Ŗ' /Y· ZHl|Tp[o[|]WwڃXBf(RY=7]u #m0P[6_q':s:4g 1/9rO+>TWh}ދt?~}(&F Zdslۼvy}{kl;ӹXJhcp4vnI֫2A?s5JR%:t^X MHhXS|1&|P#;%]g(b y5˾(,eQ61+RT.Q=8#@卵k@VQN 2g @}FvCNak\> ;قSnNQm?Xm0nOIa6ބTOH@۠bU^aW~jGDގ uLٚKtL2eҼDD\tcVL:`csRr|YBP=Dϝef6Ij.c)?H3ee(fot1DM$ \y 2-Z!Wˌ?qJҘ.S,מ?\[쎮ڳRUv]k pwSNxNto~6]'%Gٮ?R}^AvQUwRus 8v'aݒ4[j4Ls?A~cx.9yOJsMN<|$Dޡ53x, x_"| pK1Bgc14qu}b|"3>@rGZLÏ`}`7 &kMW5Tu[Ǖ;pS^|1顋W3J)+?j&6C%g+=K#_`M+U0I+yE„@w/`'WІyhD*I@F&N.pg_Cȸ[N!Ϳ7`(KƩ,9/<<7Sna F'y,?+BcAB$[2&}8(Gkp&_9vy2RO8.7*'>jw}  4= ~jrORe%&n%p0d88֟ՂcSkYdEȜ dj'ѕ%|z7ʷ 9{9.!6Fc >JFS86jSiRW#4sPE WHŏOooS!X}MX mQ~iFEFeUK<i'S|8=&+c;}I޲1=!)TBxT/(IDπ>nB7y%޽p<Zmm)BbB{ U/*bq3a;fšX>urv}9aɷӾSw|P%:E˚~-~KA01U2<Ȱ*O gp:db]I!Q%Ϳ I1nvڃ`jCWX {8ӗ8_rDBYIeI{e%^39p5wSDY<4 }H{"T-:[phjO#L6 d&1Dex$Q܏*Qju<刅$\ Ǎ~3&2t~;8=TQw˥ޱ]$VPRMa?2$iUC4:Lwn{ ܂X8SOjYi܍NUnG&͈d(jbfN a{Dli*cVC2ŕ7 a# -G 6g3"jܙ#u^¿`D[|Adj)}>{P^qlKyg497 *nvdoh糢M( ldLH` USf܍+,H[aSYD i؂=f)B*&?BS,Mw)dn"^}ߌF~~zbj., @v*[UᓟaffζI5 IԤ!FGLj]9y] } Jxa}(TMv|؉zvGu #8LJnQΤ2)Zlx]Ͳ~ɬQ+|,B3py Hiw2%R:xD>D9^wrXTVQ[_Gt/xۭS49_O̠X;W&r9OH?XSCVJ{Ѳuu3\!NSBcB`-¤L9%7"@r8_&/ ow|N@k?b٪=>C}C .><#Cg`Ng(%qC|Rh7{gGDRsv0+mGy.(cR͹+!\m陥Gnq6dDdDIhɱٟDfr:Df"nT !'`=LdcËd%wZl[;c1əx>hVxc60q<γI7olADN\rVgB)rb s5¨?m1?Q(%"0氎m!%QPB BoUvR)>7f39)tptfco+0Ws$wj 47G$}oՙ$[pyTJԜ#! [keW8397u X ¼ ~W_0tRHl.*,̄=E p"jZCIr&qHDsZ_798p *(M5{V6+aRSr@rzXq +XyY/M\G#:S5fk!m"AH9D_Hot5/'^s2 -g?>tn^jLc7O7ω睡 QMB'v@љ_hH ZYͳREmoȩg.j09PpĨoj<'YpmI ;J.9@!:CJC'ųV.Q@qŽJ,'GHU'+LuPRui2͇Etjٟ=D{Xə 3DRz$YgU mK&8e8f7e\,!˜[2|lա=FX/dѼKAG YW[\cC4' *" 9jԂxIq}JT\B N1*X?H{+,H0ިJ;FImV *DDU V!PQ¨uN-+Ɗc\'JhXe^P$=)Gv"1nv;hצX;oҜGjsؖ)|M,,MOT$Њ׊IO0KXۅZbb=3줫y4΄j_QXQkY8tіơ{ygj  ˪X]@D8ܶk7ڢ Zzs Fkʣ7RiC${o(QH2u@a>tO)϶딉r lҿD Bn9o:0:} Dܨ^m$">"5Q!#9A83jQac_TN ~r$C !;| JQt/@@FI*$/Ӧ-ʔCeĈOc-$$9A3_7nMOPH5Z[,Vкf^yCw Tp=N>8¬\OB \Jtb& )Û"$RpH@5m`\0"uf/:bݾZf#;%VrLFJP_j)=ٴdeٵMkxL* |25!Y59c3W-~/G&!~BV*=4MIoQqRm?;aY d,M\&cHN_;d̑‹I4͡hcU֪ #KSj#vM=ڄJnBQC4bv!8ͬ>KSd{][?VJűz؅CFб1㚚1 }aZD¼zsḕ_IflB$X<=7UR-.ES8-8~7֪?8Gڄ!й{H7-ɋnP&&$r[Nfl JFV$+DFf+bn%*Vxdx4M;-yV趩~Jw ʾ%%m:!q6)"nhiFQ2 I3;/H^&K@BC[Xۥ@UE9a,U)EKh ,g-,O(0mh`B3BBoODya)?6];Znn[[to? ;L%YХ 5+ג(<\Pb*Dq~^ng:uu z} \-i\fco3vÞ5FE!ORv ޼ŗ_H} Q؍f"}U'BCrZ٘fl=5ћ\F.M[%F;ze!7w[blqHwGXI}u~|OZTW{ZޗHH`~|3>);d^>6.tGb`~1øinDA˵BQ9RAd<0g8C-X7Ŋ8qlɶcfܛnA ǷmBOZy֒ѣq'ۅ&>6B'S/I(q>GcʵŊYUw1.~AZ -Dl:CBzxJxd몍~Kی:lGZETrwݓѥ6oOu?E|q_YsyE BE[cǜ"øDqXP{ܪwH|8: wE3[k`aNڮ|HZi{MTk+0#+a| ;i& W:5tD V?֐_&L Ú1DK sDslyN5O4WX}Cyv$^קoosNЕBBק3+ܒz^Z:~HP~_dZu W }E`"4<"Y|r$(P)=;^J񴖾i-&JJvեV[)frL(,__)+8jY{S_Z3lgKw;ALua@ROCق$%y#\.>u?'VpIe/РIT;c*H\w$" 7pԬF nMJ4p F".C`Vl_/mM8o26]lfd50B A>sG,XC !d+%,hd8}1")fG#Cn=2c5h%ApH|nih~qbK%V28+O"a ,B;_Hg18y56flbX$W E ̽2 6 \JѪ؇#3UߡeOOn/Hßm>llH_6b~}z̵'HFDbAdy,}jgS 䪦(楼5MMyu& U%I3LcN izXTt8˗}ߺڴy"~9;C;SRr]dz=K9#)I4"lq32ćb=ų#r)%:H1&%ȘB J 5S#Pm@?cQ Ǻޡ%ZhoDl}IWXDE38#:' +nz~z{!Ď:Zt1a_fl|2[y=י=>Nnmq9M/؟n5ˢYwpP"6x䧕g7yd3c``k׭l^0t^m9 ʐ' diJ9d֭8">JZ~RsuerW?tl*yhQITRl0 (0FGt"iӵR$iіa*og[3\ L`%NLRcG'$VðϿO:I>m_};"ܟT1rz72\oy=3\?*ۇ;66'}J?M}kr²Џ"TOga1,nb:b,UȰ!q?+m{s}QZ2OpA&''ѱ"r9퉑snaĥGm}4\@岘"N |#Mnɾ J֐Ed:.'Â.La#rͿ;\l#z iC{#\Ƙ#Z:ġAv|{AMh~Ze%܅܌(O@,>䄫w"Dwhclkw„i4Grnюh$F@сVBwR8S z+&|ok,Y7oNiF:SM?NZʠ/D0ͩt.8eAuGS#6'ۯ`_&mގI"`5C |<;>c0!\4@Q]R3#Uǽ>߮)Cբ`2]K蟉aUB8:j%>Rc6-VyQ3d=)zKmX I @nCR_ ;ťlVXhA}RZ*Iu^h=Dq V {+]/͒lڵ`$Y:jc=&$^ƥG. ܟΰ CH>*B3IlcDͮU: D q%lOI!{#:^f9Nn0pi0Ux?iu`QgЎgO-3YBxBZ[['Ǧ.>ͽUiK:l şTQQc%UoCQUen&=B8d$J:IY,hĔ6z#k@JcQu4mw<9wX}[']%/( >T)F"~8B6ۖԆU8">YIvVX5j㘁Rwr٠8*IΔF294F9XֺJ)BbJ7jA~5}a{Qx)8 b>D ĮZ$Rdh qOVJ7hq{dj>KТ,- -9Ym|ӯ~יwH:$Ià!:7}!o9tr xw/k”+g˱mgC9׻-_9|9.=@P<>;#xv&"Ź9O.g"FwM6TI5v _ LD+<ߝYX@=NPe̩+uP"-f~(Xѡ,2Z*X5OhR% qz詘j vE-,NȽY ]qG!;EODҤ\ioʊj~JhAlqvivyZwI!=l !R{fX6RDD]6vIl5Z;}Ǻ_gimUS,t1Hg36NOMj>T6OMXxua+csb3FdN1x-)sUg%N'!|u+ ,\s>Tz#;Eyzޔn3D):4 ,K,D_E9|\FJNbhpR%T@#Y"+M!3KQFV7dDv-[bd+0ڳ7?"j%-$Iwikq7!x[ ,LnSՑj56lBz9ݞ&cT2X tvo>߮EDD[ں0%µ9 /4,(wKߟ1eDh&8roJ]BV ^.T4|Y*xPIqb1g@6nPt:m~Mb)HN~~g ;sNpUP)luW[j|ֈC&O9 W^^<%fe$QMN"fLȔ̸CiBϾFOxZ2\۠Iε~\uZWd%m0GW*5((EgWKp!ݖ--p I2|/kYߢw֞5њ/?0AANIwᎫ:nMnyۄ.R hb(t= i[;@Cbnuroz0KlDi>h8C0ڑ:!ߩ;]PP}/;_ب|Sa%< R,zEN,m9vpK(Ίݘ6+W6% aZk #ślކ1<9DXX[ߡ7L·n|ro_-qM됕3 .4m|aOlL,_c6NKz;`2A8^`\|QWOec7Lja} %E4LT$N渞9ޗ\\3'hfe5DT\IPUOרm@<8R)@<GLߞ03wJ%0jB5U-֑h1Wo^u<aVFsZ+F>Џ:0dUk!( iOG޴>)>__rO'ٔMln}g岲~ %>Zy&ʶ32&}rՙv=V8I5y cͰ=$`l縓QYv?8K^Ayս5"j)sBox<I mu{wrHTF?_R4D?U_}Mz@An'/NVA?F^D)F6C5-TtK,gC4vgj,m/\70wM5q &5VqxĞߪ:GYׁHSYv{*%}اuKó>@X*[NSqdx #ȞֵxPK:,Rk-4Abavv~ٷ_LN͝u?NUo/10CzLgŰfxױ[;=}ޏ'x}(,* Jx޲A3Bg[G `,8-W#m;ă媠hm׭QX1@@Y5$x JZZ hdUas NhM*)6ܼ嚎2yҴƃ1|m4~)4U*`t;U D0#Xݸoĺ 4R"PĞ{ Ӊ ?:EuDz(wy]# '"Gmw@}ѥS$Ie4L}h1)hu,*Ț.US}w4m ] >B#p =CŸ4yr\h%԰W|ddЙ4_>:rcQmmL ;"~/#fQ#UY*e= 5qZ w?/egnR߃E.7놙mxqpqә !kW/&9F∞?|ģ{U` ,,-fRx|$wO neeeFEU]g/>/M ȩ_o$uXMkQ@ q[8 ץ >_Kiy-;bh^^8ߣO棫9n{0q .ϖk QÁg/.ۯbyo@Fjmy~g2ذG#,$6vjWQ488|EwRx|V,kX$1j_#KS$67{4UHe~i~ h^r|)302}}<U1fЀy?yIߢۦ>:liTkRVtO*vk(P~IMf z}кM{p|2b/Lۮt]'V-EkNxM.`M1&ʴihήT_pBLz** -|^O6|.w[<xxC>?Z_34~0 C!KHg60K1kދPRƈ[=5~r^Dl? 盅r1tW3ᨫߟχAKxCMP[Ԋvjtrn(tg||}+3WŀBS an &--41w(ΆLTnGJ'˛}?Q{u$ER؞@@ `s]ݫ"Y>o23 j|/IZ +zq)S>Zr9;T6m綞Nms /n{0xrV~>Xlz1ZS]aQ>c3EwWZ g_Ĩq@,z_*f5Ӵ3n9Qfa 1s|ozOB̿E*.Mפ#^ nMUֳ'~xoوb~[>1id ُko%+bpSC?9fŌMo "NJg[V *y?nx܈$֞|"Q-3 /..\nԣ}JG@uC Eς7^g'"_C|yڦg1Ǝ@K}$.{y8%;dF1Tu~;1t>fpj)~q-lT=ޏ7P/rD{c4; sM{G9?T'6>5|hhz:#?\1#£!~}ޏ ?w$T{a$Fb+^k1ȰbmKk¦/C#:}w8 E{o iji6 m"=o_˶Z(5]Yj$\nnܦcZK]s\3_C^_*E CNqӀT_,(˝6MVwVt>GҠTl:H.%Qj6Ga}S JJW]ņq[LF@2,Z>\!u<\p(ۺ iFDཧ*췚/NrmkpLHPp%M[3&@:n%(tVAy @LOΝ+B'NoUJN[_tqՕRbbiE$S TZIL ֭Wz6hJ(- v|}`rrq5~P31c>z}dWyT-z3G'Wܶ1ߝŦl9lR?_e]~)bq]*T?U8\]? `<@Es2](xDz-rnM7;M_qazTLoӠU8l#y*enUjUd@dy"Ɔ=nKZ +ٲ\O_G,P׵xf35vK˛mΆk eZN7Awr ݣP~q{T+N'Kg,9^)ˑ[dDhG#n_$tf-Rh5+҇)ړ|9'EW-^7_3C]^_6t~odm\fktDZ_j)r&p&Q@_nb: E3V)w{>?(Xg~65߼>+4į q8o;Nzk.&͞9"1%ڨв#BR[Ϳq)?\Z$謧.+\g*॓^؄`@p8f5WkD"y( :vX +Q,f&T]c\^o~𥘵}ZRb5T?6|aߓך${Q%3\-@R>km1wq1HkBwsdgG!$9 .`;OvI¶F4nc;oHumCP[M+w )h NpbEB6|~w7wåv=f۷ҷWSq32stG~mddIM\M?k%N-I: OןƟlz\?>@O2Ϯf>NѨj%Ӝ(iDcU}qEVix"n0l-+ '.p9BD&p!K{Rb~vl0K嫍UHTJy#cL/C@s}"Wr T]>6w!3w؜rRs};Ozv+)֢uv6~<3TYR*]IFKF>܆>jðxjŲ3Arݔx-k rfynɺiךeakFCӴVIȰW7x=ݡ\K˥Ls#]l|x@tdzXSG{ؙ^Av̾UpщR,/lE0>⢅ ,WJǣrǶW<Ѷ 8i_)fTTg4̥*7k-ix]SqXz4!uYX1zs jTؔ[fvW1+j>._W4)bl"xUe=АOBWVeő72<\!}+fnZN00Gn6^[Yݢ-Xں|Xǭ8 mt73禂y+X*?̭8uu27lEo|^t~zdV$p7Mh|9lW6h C|wRuh)usZΝ>j1jqjWUÆTș(tr;SBs*o}!z'hQ ҝؖUQBѴ4"A2ecLvz_|{I<;5^mpUmyx}UC~ySTy0181 5k>`Յ湶q3(ilri\$^fA1n$je:],'wh+cw?G9_]%!k[==Zv˲VOыzUt )?Hwq4XH>!XGv;`~*][`mG?>_-5ݹs[dڗW*eMIģN@T M,.?5ϑ=egg6>ϷOqG'n`՘ʯ;up 'ӥ.>ZcUZw{ oPX,&)bܞxdqLk )=8N9]}܁/)xNhף\$$ywܯ;n(ʴkf>|Z|H7ۓ=uqI~u-?/k2YZ1Dv-xղ-CTx&Wd.4ζɳYu{)LQ~O7Pj?Ԗ͛n['DWEeut;6(8Qz\5%phSۚ5_\m'w_%MSe&poB{cм}ccMcpޟ·fmh7 X(/;IR20M )|4~qw725G`U\Zv~?Yo(:3.111e߳MYb>c{C${*::xvLo>6NHPϏ7ejUPFtI{bۥc;E b088HatjSn[Z܍[CVMgbR ,.jC16 rUa(** T)C7;s5MXXؐQ?2| 4aJJJ eL#M JQa  *tnae}ks˳A)XISGKq7x'>E%)qNg8g&td+~Hsގ\>.vfF+ |{!8V~%1iLN#ȧji!B^!Bw]+un-[LY= 5>ݹ% 9(t45]ԁPHCGwufOF#>жZoىOuDDP/E&珘ǵm`Ĭx0Ιb`06 x^HZoΖϚ8GC e49bsx_8 NX\!E""9`,d|}E=5 S/򛮷Ie|}MtHz=FGӴ%p2`-¬ׁ{VSok5OZ:㦪, F!ED8bpG$ ?%nـx8[vqm[>Ŋ6?r?[nTdC[ݏM5uÈ:>/mOM_kۋ[@%m~}@]W[_Tv47m9oE'hbwK{!AF @`N_JQ^gG;J>`V[j dO[\O75]{nuqjۮ;[?\MׇgˣL mq~h?Q'4m$iY ^A$d qX[~][.\^GDOwS${PvI`i55sB@3eQJYk׶5v0ؖ@(Od1{sfNbm " G݁rvCf1Ö)G`˦]7/ ynx2%5v ^ޅ_uZ\ 6Ϗ5LJgu&R(K2~#mN-K}211 W>EuuӾw^[5/͆N-.dΑx7HL:aGs+1Rd;wU[x=B떖7r T!{sZ2w+?Ng ,X<.D2+G>͠(Jjj#llbw+6| j;mA#@;W:s#"_if|K]Y a^7\~_2}yRڎeKbfC)7ԏgXVﶝUIt ~H'ߧ=WI<!-zinj 6C:M. /\i^1$Vq2YSRv`[a9AUUx+k? ZC\1q8Lηoq5{vגzb~4NlA*l[VAS}fd | n_!/= Wг"+QC $*+iןZarh"p,s1Jh8).3 UvBT>#:c¦7bmm| $%Է)<ثR$.(I[W_.:)U% [F_IRI'R[.|\6<+< \v0]6Fr'/8[-HJvRl⨪@]Z `fU0y0k*% !=za/'kSu2 >,Upg.R8~, mk2ws*_:E< #F$xsLL`"Bu4p^!\ӴiյI-:2e\P Qw@2Y1+̚$bh04SWVvܾ><<4@))yFY[_!i[!X)VSi&MF3Y-LZ(P,{-vgL\L:K=urHyEy^5qHHƿMFxX\;n:ťA(‰L;0BCK"0E fD7ED^ Q5t &/{7/E79],3'$YUXܠKQ] $(a~}wИ{KSK/ +:7hne7E%i})fnixfnNU0"0^0Y?ac]l/3{=%e9I9,Za7[Y#/.4 fk(p͸1DBcx.jCψtߎR ;CyrpT =^T"9DdDGJ_e)#D׫>#T(7s[QJq<"RT<ȋ=vmށY|qNP˿jFWx>tl,1go鑮k gA`bݖ%?✰$>Qy(_i\P]%%Z@b0yA{{bM[j#2.v0H !!&$r}O>x}N`J+ΏZTՕ#SmoQ`P*@RQޑxq"j>|{ nK{@_'IvlR#ǜ@Hb6lw3u<$lX@k lsm5x@tYVq.gtgv-dDN Âx$D? Y)0%[[29Ce?]#Vrn,JrUdIWXAF2tIs](2)Qo{?}7e4BN+ -'uMӳqOaXON 0p`!A,x|A \ Cm;3cSoVxj&$ r6TxDwz99~zq?' 0qSGwY\hn!=:l8U-Y}G*Aɏ &-# Ò # 끆)"O$ xq_h냒%C?,S(q^E,Ok_V[)$d=W'2zAYX$tl.lolp2sUv2BfRS!'8|UYR`RGWC H4HPە@D_fl/FӦj pPYI,om^rAUUd&㲶0k^R9 JRF0m;5v%./VO&܀l $LiY *PvEr5.|Oz3сՈ2g脿x{؝ˆ ωZxJ RBc\Ax1 G;Yb 4'Ozȵ%Kg'|W#\7g3e<,?kSRfbxE$S& iߙ -䓔 ;R,W $z6jF ]Ӄ Ktss$m̓D:(SE=K4IP2Z`&,}4TZӍ,-%տpA-:dWD<q-l:jD@=Pe{l&cjmN:^d"Uݚwq~Aiz>xe d{X"컣飗ܣPj["(Z` ֐kXH uHWNeo)S  z{l8ooN1ڊQӽ}VVjzvA]`='R, A8/k5YKӯ-ȰXOX EY DLB;Ѝ Zkf(286v hɨ^FAlM y\60kW4Z%d]Zs_^t&$Tif2< 75\g;Xߪbpjj2JRT@L~d"LΧ]5wIBkkc>w_\8gtvf+ ߷`.Rֵgdfg/\sTJqx#p72?I|-'#f;'/qѺk¨NǺ>w~bܜ}h5O&-eRv~)\72Y/l: JO2_D:> r+$7w^ G,D~?-fu; ܎|\KT0=etyhCb[hu|'T8MP]Rjf 0巄 xo0hvS\GvDoU&5Vr- IUJ"EXy@<8 ,ox\/0Kb[&!@x\韶}tR,h?حDkSA }X])2e}wlv]HĽ9)Eu,L\>Ɲ0T$|R3ɊKVJdNҌ th>K|)DέpNʘuzsrz~ 7zvmd.g''.f/7_OWuț% *9f\f26x֧FA!;7(Pݾ`[YQk*Wtniޱ9Ho qY(N ҘGIiiqp8RditӅ2ޛ馥V%+żY@W2/餀g1B[~:^>(޻G:x  m^\TnhtQdFn%ؽ-Ayq4 E8l"X Ui(۴GCKPsHcx%G]8b9c)&h , tC Zhc~p° p9KzBБbF Z m+45C[];i)0:h٤H}RET[e˖E;^.]jMa 0F`U04d:-D3Lg.24a]}@pxv$-.d$g&2`" iidYǺ$vR-vg,0MNцepa!IG;lP--5tC ԞB4jPfxIї(4y4LI.y"Wol84/Q!(Mh%qWj)?#$+INƘ@ɂɐN/1G*$3-4"2e=loOyיsLn~޶m~M?fHmUoI,Ȑ?? Vs-ؘxjַIX}no6tl@_MGL-}\yP@ˋ E%&REy)TtzYJ VWm:O1B$3Đ?4rN@LR6)fnAjR9ol7˚OFSC LFUT,F?X4D_{ԌGO2\'\=+(tY1[Zt>V00q 1.&n!`0a=Woԛl@γ)4{%mDVo<|M]lPBa_ 'bE85u*ެ\|ۙ ܨk0]( 60ܼ! u$B;p+55E USܛK$Y̥ +sK6[PI H6F Q9H@3Վl,gRySϺXLD8)b3?І?݄̉,@ |n]HMɷѭA8aJ"E\-],_K1l}+ajA^ya:f|R 6ڍd,Þ&r|<{%Bu*0̷2U}~>,dcT|a65MotϕicMn|K(Q4 )pCjuߘy (꿛W+gA#xd>FF8?Xm,t֚/w rO'DL8A@<Q`SYz6/{gQCB왍?l{ow^]k* r C>7 JHˆ*G'5ݻ5'L{;v&bQEr]SjdfUi?}pNB0^Gl!@?V-on7">ʮ,-qM6?Ð?h|}މ|\^ȼ eVpNn{ hr~mER'_]%np@*F˟ GyB"$'I&]RC,QFAѦ31 [sUfbz†-W8b _;o0ν:6,*aǞ{҂AVAQ0]&Hqk튽a,;~ǎ?q =mk!rр]-ߏRVmNzF옑T;v(z8'UbkwCta݋ 3gL~ #YvIN D$9|KdaYy u  =MeEf>ܦuބ`Q ɧ5,ջT֤՗"$d 5,.M_O'"FYZV3̎,g|<\z%dt Qb'K[:꽝SfԤqzbfn`P:aSSאI*$<%h!t/Ṅ0W"CֳboZqh%~L/9%0LtH}?cYʠs$&A{u䠴 oe8bRo0Eꙭ.EM G0ȠlYH,C}|r+$_o0XP3>^<2Q>{- ,t lPP~h;dQϓKl $ ý.)(:{$zy\{e8rUeyBJ k]п%J\ب DT$Wށ91N7]vou.}˹chl&d&aH4;gGW1C7O2LK#"\POQtM0vj۶mj۶mj۶m۶_c+ƖESdvWd?Mw+hnzk|a1Gy- s2L(wSK : /d$!wa%#H+$PCpș“ ) %BQ d(AcGj茯JD_rk3fS@za0CJ$xwj g[3o)0HIx5NeAz>UÃC0#o#Ȃ+?b 0 }֘$ xO^4&i T\f%#K4i 6E #m`WJGk1TmKT;q*l.ON4.xG)[I, J{E~ݒ APƴ.\-9w;~"g<^jߧ֭[km<1 13`Ut$9MQm઻:đ!ʤQ!4h5ty «7(Bv!%a"Z nid7;?#WcQYVt Fp= E6[!WX2)VHC joIE%@5 Csg% ) Z;#NB \wx^L4*DOfx[6c/Їrc1j(WQkhP6F&9) w;R%d%Kz_VomSY C! M A.AQ7Iܜ(XSYn(kvx^h_7Em t#(?^@&q7!r}de]fCZKJFރ1-GH1*!D9LՆ8,Z\8W MB{з LV;Ze 8$]FҼBcMHtnsO/~) F4{<PN( VT/BW#12"4LYN.7C 8 EĜrT[:yUMjbt5t gƣ\LsAm{F2qu$+za&(0,AH棣U bf4pİsi7m}ͨ<`fSs/I[XK\X۩B)>V"쥧dEBN$)UFFX! K84GR'W"1\NLg) O*ӫf B{2UQ+WW猴"· :|JԿ O%h|pi"Z\Q23w@{4 y9!`:a4?0E*@j1@!{[H<$)HOUAlZ8Qʵ;t kB{o71Ǵ[Klk RǩupY~ 9v"9`|8PXYo*$,X,[ 4?\{̥s8KZ6Ji-hep)Y bG)@K EB9u7_zSQk/N f,Px|[R5P6|Fq3LT7E hY3H aQ&H`&=BJɽÂ1ƥ㷣-Bg"y ĒZcb%ٵKK,8AM3/=K㷽ntVjT+@V"bqg'4mzxhd큟ߨ^:v#*O nR\*EhRGH f<xx+'3d'g'_<LY{EɥM@zO66q $TH{X`Y.l\ #?J}y"1H׃UͶG>tLu[~: ʡUj-! Du R Bo@c-DlQ/GYmW_ԯS^$ 2 #& QQ|.5S&%g@@((cVy ^!$ {X{М= XFn{M5ʶiuL})h 4:ZyRH57lu)k0)Qth&Ko]-9R>lsUhΥ`cl7 NA? S^# mwF9۽ՍzlY*aok;ȏ O,5XOe@!5>&_#\ P zT#-PťI`ȧKƴ;E 7&!"G%B6@틞zDn-RN+ Ϡdk2?ah[XLj.g-0H%%cJGvGh(zKwo?S`%6>4V2Ncj2ÝJdƊ8JǗT<j=ٚK Hq 5DM<8wCod|`ljS2uBJYjlBe_;#)M/U)~>o=Kݗi|7j!^6RCL/Jحk`6n?{c-lύ`EݡvK7 s C]#KP&1R;JkIq%r !ɹr~s_M.y*l>s5 B|}~G>פjjwԣ+5 ЦԴg:5#65vD6$3'}wݳ XrSR2ms[.IC@G /pΏqz /H/s!Q\S޽>uֽT>nY)9Xr}Ӻc3=a v|*阦%[?7LTe=*uX8noS(!KW3KP1vKgj@_NXi/h NM<0^0RU#r%ޑ#^M wF1K<]wry#t=QYy$ 1&Ĉgi p#r*0sK Yu{SOPxɺ ))&)!3VF< LAdY! y[!k4\nV揗lf1q /}Rp6MnGx_oĐ&k?ƈlP`#q Ιf1qpW Q2nKq㊰ @.7鈆6+脐rrK 2~oCOJz.7\g}=ڸ}Ujf9 usdhhR-X5YJ:$#ЏF%Zߢi)k,y9&,ۋ}'B4sձ6lcl#AvKQ,`:;Xō8/;Л`=AS\X{y ^eattU" ~, =.a I"5 /٦#f3r%c23Ø PvS!U=GX3jw$;Ed'ANGj+{ 82X+V W7aGgbi>ƈC7{ (;+UpJY*jyeT4Jfc\]k̉%'ӫ1S%D Po#t'+?m /r[w}87!kM-nL  4H¬<{}} l+h\vFK̇ۧ\1֭7[; Tf8tTcy$fu1Z5fN:\OE.0d\Q)?a J]x"̟Qϙem $`0(:'ypps~P@2H|GRgVZRn I%#DDpA#CbiQ-+Zw_]mԄެGﱅ㝤y`"!@&ZCX;92CЩsyVU"w4G 6xǭK?ۋImqR8lJk,yӝ)`. _y>%oߵxwUeQVE[`\G :#xȡ_Gtl\t(W[l]Г3ҏ+\#Ȳ- 1bL@,W%^A¹:obg0sۢ>~}B?O[XԑǑ=&h?5?3׮?n…0;/p9>MH]O=$ уL&'ӌ}~q\b\{b:F@/(>w|~[6/(G *r3D7mGRCAaCE {)T`s|ѿm~w|?)w܏H(`Yc o:- 2B!s`r_3=G5d3cv!y~JP}sb9q)CpO~f_>-ۮؐ3DFonDa>ԙPC~M}>|Ëz-3A-WDq[']L#"̨iff(; Gd;; ڢJ͖{ϜTq^Tk2g:cN`NÅؽND^@(DZ..]R]0&K4pr fz & BYՓxR$u"L&B8\cT[?AX bM'zh@2-h*t7g窞. Y*gso[e{))y%n hʐP<`w _ҽ抄- Ë<3@ע#Y10;n5]3"aU89EfI Fz|3hKG, 9q>,by{ (LvVnJb-а&iX׿iVOIdD/ -.Lz-.h3[8OEAYlF1Ҟ ׌yZDQPVwl=Y/nj{ 1_?@p(7r7G=xZtrJU5{\/Cp J /e0NvqCT\9rLY?=bbc8&[gk!B]:O\k )ǒD ·f_]E#UNO`Ramxka0{5߬z_ϸ?׉ WZU !gH|׮@'9t~⯜'XpTZљ.٤rԮ1fDEY~Hh4#f&Y "y:OX"w%YbGU8':::Nӄuyvsר}jGH F#&bUn$aHZ6cU8C9cB.;Pf4\XU!̃"w mUdiu-O\ufD Zh> J(TP2M|#rW8Y*t,!I84r_TܵrEsDۚx$ξ FenmG'/ 냞X-PZ 퀹9Hh)XQFt dZ?&wO,s K $yVI(mXV)٭" MjhsNʔ1 o?1Mg>lz}#WZ]InocgFB[؋MzX.بit~øzqb0x; Ikhҕ@ t(Q*P(R]Jp#^OLF{Ec5x,Yxb<#p5")k֠^'K<+%cfƿݵtJD dƄU^!RGVTMNJZm3{ OXSpFI<3,n*W0h瑗o#EDL)fpƆ>0_u+mRSa&$,}WpMYkk|c TJ|N}EQQKszC^Q5k:6;.8^CX~mҔzv}}s̞Z-~rTc}N+ f̚OvC7dOv/Ӻ&[b|cҕQwKM& jDRT(dL}HH6(fl "e %+{ 42kV&3Y1ӓtl8tlWMח7` 3t>W}˖ lM&uA}Z{ hH,h,ol|ZR2h-74 #U'Lbx S"\mM>5V\qcU#)`^7NOW$ROղ!B"I5-hV\i /TxGuN .4Ӊfe}8$j? IhβAsGog`*@+FvA*D+w"ECMj6z+KYd2zD`gL^sf#c9A'& N1i`+%i"MA qGXx&$}e)fuxnj70x/nlY u,_16`q H7߷5h+|Ƣ~]1 WE ] Uaǖ|;~]Wa*"N<ߟ&ϼPI B"9a1-]lNef͘tWz?oNLJԴ)wp" ķ Qq0ng>n-Xg0YF_NnSՙ*Fbj. JL~`k0AYelw"BMn.8}S"a& DZD#1k`FY5s9IE-G:ëUoXN}}ք](X y$'/7Gyi ܷ9^tc4Vl #@CN &B$}'t:9Vz<6@Ro *EQӖ`j#@!ȝY3CeI)1'>@xop C.>ҰMi;<$:|:{bdR11wq4Mu N=&<ǝj*V , ;[Qׇ;sBdÜA-on\WMRVZ˅t/c"E_,E1 bE\؋^ZK7΃Ko,ݏa6[),sVHv-N6&̴p:7lDI䶳wL쑾;jykh}ֲx#t~Lc/lhjӌECK'+>2vsjjC dj%"q0 ,>`W߃Σwbdlλj,#V[kZ4)ƞ1;xpB xLCMzQ̼ TH CڝM XG%rٲUx?K4651c)l#Ʊu6 嚍pʌьL̑4RnCCR\brʻ`K,|%k nc- Ri'uyąR FmH ,+w' H~/Kh?k.(X1:Rӭs.4jm}l׿g ubzvQb )>EM{ /\ G֯],_-'V"?KWPn%9Vh%7.?)El:Xظ68&iH. NF.ܱ6,0$5UVuOAK@&|@tep.sasܼagZAL^`,Qoӡޥ.P7t4fGTqWP{q,Ksn{u곍eFFqjAfƬ *K 4|"QÃ]xDL9Լ9*.VjecrZd˒xoJ繋[ W3?pӥbg\C1 ވήn1Q/~}$)!/#Gi^ j+EmVWӦĨ*!OqI~AAuhϚS+8~|X|`ĄS8g1u|y j%XbӍz޴Cnw 12K>Y1ٹ #Vb*~LEy6k#&aq)XKh;Y*U1JaJ%f61R+nY-.^;2{'-HXA|[A'Xx1صI; ema@H~"ưt-$u>@@of@0q1OldLPWOYk Qcnbi\L{r4"t:`FoZ#Gbi^grB@PbQޗ2(.|BG:fg~3igVOÃ"7mcuRc( p#F^Un\wD5G# !fܚnR&5AJ%FYI9,Ѹ Z H1Dth 0{Yy*/e؄cأr<GF;6sO ab؟ݐ2}˖Ɔ~1+%5(s8zvWv{H\?sX V5n"Zxd (eis~m!HQ&50RBuX0c 6i=͐N/#(DVZ, [փWL%`*4ch/+M ޿c }s2!(/$1Da /!nޜ\fʪ% ֢~Bp;UX9EgPet mu޽y g-mgXL]1\{* J,^mYR(VN j% I}BfJ^ OG,Z.8u?f$Ҷ7炗54i0;hgjwEEpO8!A-اed8`k*DMMAG9$'W(|܉odi5g}ta#shmȃX""YT{fY#}&wx2LD1S&ctH49U> DcN8+#6}b1?)DAYtƑ)V%EW),tryz, L[wO`ZɈ1:OshcujZ%"H 2h A쮛q154 K$J4_E;rj2,6Hsr1N{z/y(&5jiQ"F$˅Z)^RUcJKv-I FȞ} I}l`0 ̈xr聙fF]7['Mnx%U ْ 12qv}F2a iD2F~ggՙI¸0BrMKmWX>V9|ı.qAPS9۟)W& Pb%kNcfk&vr*L>RE8b Bi!#`Q!x#(y;}Jt?\alC:YaGN.y*&CޛhރESyKu,c"y񽑅6r8x"H_PZptISy \0]8. NPbAG|f Q/|g;]\ˠЂX jXW4si 5p"NPkk)6BchANQ 5δȌIsy:7+&'b၎M9k|JcAx4NUCh&u*,"Rb*g >ZwNOm*S6J,mwhBe?|^kpP^Pt~My$zژY\D2\[3"IN2ꦟ$UEzF3Q8}gKx#nj( *1XDH.+B~bbfM1b )w e&0LfȔ,Nϥ5;>99/D\2Q QT† <D'" :mg$q-VN W7FAU̸9$T""C9KdC`ra/H3ϸ#s"KLRB򾅶-S Inbi~lTV̔`Ofb )iZ9a,mX5 z@iTcn0bt% s@}|:Ƽҟ0Ǘ[} Ө^g. YBZ˕bI/WXi*Of3֎ܴ* < #Fӫ+"xvM# ]K4MbTB2\_ h囬䤓ڎ2+$ Ȇ>u0ON13|Zjr}kԔ7@J p8Qen/WDӉ3eӴHTs%u^FoQƘoQ:/%}U("r||72dR~pO WS)FXx-SPKmO[=a)g3?_n5[N2tv>@; SԆ-ҮlJȧc&f^03k$C|e,/rSglZN$Fpq T?S@r$9yoyfxd(Rc"ѱ}$I${%_%ToKĥğ~y߉5<b="1kvtT?9EjQ &],j'n C.6_`FYUmbhF5L{F@jt0pW b\nY q (C͈n4!|%Jph L"Tx瓀Ymfbޜτa12`P\f Ԍ!O$1FT頒(">lk mdw|z'.躎L&LSߙ/vg'x??h (H4*(""[/8~P^ef 21]JaxW.Ԩ<颥&8p Z!lt'?~ƅKY_M%z7^Cj `C*>Şm뼰ȯ`FUK ѯmc N^YOeA”.(`ݤH7>}]UL!!JXя53G !!YTAM~ʧb_Dϲ\R/j6[1 *c'ϯ);wR;m/ր!)cŕKl!dpKj$Fq2yvbPEɢ% :r?-pn:{qX{Q@MĒ,B&}Ym:W`(\.03e k !tzli<-9HSfcJPwwC$t @@ l8Eͩ#:CEZ 엡m"% 1(J+#`g9+DM껹9[[~U`nR }doh4( # ǞG7U*ni~Ru%BTU~ XSSFe?632@|kkOn)Y Hs&쎍1HҸ"T>5"Gzd~0,F%;Vњa bBq1f֜\gv?f@ J^  1VzH 1W=-U"yCrRRʓbyQPeԭUԅD_UI4:VDB,k,w(asؽjOt7dGC3u({P@W/5:霦ʒNXlzW. /gtUvy#4Aߘ-QBR2x~ݴK4Ur7buS?~_Js}LXN6밗XqTRo*NN-I4{3hnpY)R%D%K4 @x*Ƿ?rm 30^;5Tf ",,{k3G^0VR~X$h@scy\=I ZsDgxQixeNC;Aa/cFA g YG'wΉ&aH܇AEu+Y jݖz+H[BЙQiMŶe\8/f30!$xA}Eݜ^4. x~.P o8 Nsȟ2Nwݽ !er\1!A\.o=v:j.'TVs&W>o+_Zp},Pr=xth8}-3*\J8Fnjˉ!5HcΕ! u6o+){6~} BP ) Mv!$|y oPU)DQ!Oh2a{2fLKqxzؔ)]J_8"ǸfJſut(i~Rtphф-zl; :%FR ĄX Y$i@6T<d.7HB!XI"Cڀi)n8=?CUZxj-lVAѣ̑%e'wEf4th ǻUDu;EdY**3qHABOvLJ|p3q5G g(BQFQŮǓl .*Xu7r|;! f5}PV@ c~_!*#0 !.$9(;b?+߭!\j-@d܅ a<1lBh8/|ZbF ƄV%*idD K 9v{SJ_{S%s?:Ypʆu#-q]Bj<✒ă'KcշZY=b7x0},V YUY<3!d:X_j@YGܐÝ,߬"}`N!H EULQӆ,F[ byM# vݒOASa lD]FW]ʝ6&* )2+D/%,,C#f[޺m}nk9䪦4J6V];aWQ@ͤEFqta"`mF~Hbۂ?'k6r gªgY?PY–bTV ՈO4c9aLʕrH^:[zYljm<4C>a~/) S/_5@o1?2|n_NuEEv*h:ZzH0fOH>m@pT),%.ۓ|)8>P~KIg: r{li4{h"Đk~ nzxCsz TD7eh=יR`8'$6GgLM D_:b`0: iI,(t.yeQ@P->5\>F$|\+qmɡ#b'@N?R"DVYHa35 [d#Gg vgFcA&\9\,nvD2iW$M,uYK \UjS>|:`?fCkʣS{ |$ߋ#7D6Yi_R0GLL !*BH,8}N96⳧xdDRgzۄK (?)Vvi J_ޏ4:T2?Qp+ ڥ$4q;YmwcM,y&u/MsRP1!-lS C_Ph)( Ɖe{z ?>ȑHe05㉉=!TBi{(?Ȉf.[j*u-~-I|s[Sp jPpwS3HqB1h W6I3Mozq '; :s`09@h€z@bp#My>$>?sR6W.,t>!1"@(e/O>Ƈ=rӰm ;E$3o!ס##nd: G4X>OPg {Pu2#ak%j<2X<2o5Lglz2@?^@Y@˘$4ś tABw e rkх"˜Y<.T3P!%sae?A?MwVwveNPBCrGᄀxo,%.QvP2:[/>O׫|.6=}_|Ӈ<-Af;Ow;ܼmpcC$ݔBAO@>iH%z}P 7 5Vs,a)qcK.VRC:,ST̆?Uwnf>MviQxE|M  +*G|6́XKu܏1\-b>A k@(o ,j\AI껶59g,8m.bJIJ?g>o+1Ct!u2Xu88״X,Ff ~ϰ]U_Sz%rt4 &b!-ݞM=&O~Px P\T4W,VcNʖ9z%z4qb2#)#̎KU"`rDo' Avj(zzn&_\ڎa4RT~iZo(4hIf+1Lϔ E;)vި>\uz}*qYñ9XS~q|<~lQEjӒQ"A|y;vs}ou2UQH*R]|'kɎDc!߬Md=~4C]u,NObȥktxxRMuD{f[F.]Ԁ.aգT^)]l׆J̿uE~[Y"]zIȹUd&AF%jBYxvX6nXkupIA$oO elTZ:\qNcSi.} b ZɴB٧{ZJJcBJʲ![Atg6)y*~R?SQnI2>W:DJTͮW ,;+Y\賴\6rkGEPEn*#ChI(Z8޲▧~J%KG ĉCTL3> w N6w+8iwL jB!(*\|Vv(EpݽFc'GgƙH"Y&"CwwDC]D QNSmgϗ01EY`?{L D%iÌA}}t Co9c PwRY> =Zߥ5J|dB|tݍG#"$g, 5dEȳ`eX1RMⶂ2A)q4JgPo /U[$Q!vm0~y0+e%/)/rHRE𿆰Ϋ*E^j޲SYDUE<"G%?,W]_˂4w%~.,r&gkXF~}xYCiŷ.!`5l`g*=u_M ,b5jn6;hYuH4ԻE<'Ъ${nIn˂8qbȂ{&o<يgw7_v`BR 1Js>]O..[/n7*7ӥ*V!A&7o ezAx8p]PmȘ+|i(۫-Sj@.#p+*[; foޔoJQy!-PN{!Wa'`@qi| FNO4`_;4ᓸxiD}goҳC:N<$(p,M|L*>UBiunTZ¨یwwV"6-hRߑ]23LཟI:41&|ŬrSb0*9 es'\c |VO'=,7g(8Z%"yBu+)Çgkkid %ax˹ tpyuߡQXG8I.ϼ6Vx%C')&: rUT3q)ʗ[NhA1T -. !j?ץiv`>1'кlBTqD1MVP5wJx=gEy(-~8:Dsc +ȓz2tܤ (~<6TM]Q%HeKi?,(A%( (O0XDuGTҷV俜.ȱ秉o)c!7w||@f]"j"Y oJU3EۃbjoD{pBd '7YY%a; Cc#%07Sl>̺*LDcGI} X< He 'CɭbkhuP5H.8tCF۟bJ\mqᾢu4־m;1'jm7.xoOnZs~JmBu3[IDK㛔48ev)Y'A~v|TQړ c8F]QHLpݎFI"q!'_+Lbc8 Xs>% ;p؜6J F=A I ģ2S'y-6=diq<~ȥ$Kg=dF?S :*M6L $% :R &ƣNh󙍜E8VHzklM.Vl!_Ƶ^'oQQ$ U1P$%tyW e#[!ŕϸ `/vpÒ_ ÈڻSUS(02&hb=u2Ջ慓C?[9H 4I[Oh|1pIC, ^ϴ(ˍ|\lͦ"xg/sOH8Ae)A"SPˡDw zyNkw$b&E" -͚;G#ъ[0(,w73Ŋ#kQQeXb_(9!(U!BQW~kÉdFq,k@ "SP7Ux|O%I|'_`>mķ񋞓AL:/0,j Gf*MZhtPLL̳ ŪKA3jnc5ÓT݆mD?%qY C(#,\q7~?s Pz毜`H$`[0АQM2 ysq%X{j/jw1)q˺UD+*4ZZ獲fYaD@ IH@Cc̟U0;`&Ap]`p=P}xڗkϷo5Vve0#*O q DSì7lʠ~U sy0!!*CAUmN!#WV[6fkGk JXc-ۃC9#úP6_կ^ҡ4.G84BWYޓ 8U0Z|fz^~lаH:rbdVO#W)~&|o}1+]}дFR.4V;35XҍQ\78\o-3r0 ;M7tFaJKa~gUKU; YIJdmemA}M\u 'Hy5ժ>_:G8.l>&9nQS^qٚ 2 EjLKp]Ys!dgF@>3҇l,qܥ~jT:kdbN PGvzݐOfA/m5^"٠&.>;}2.zq?/zjzb~쯝fZy=y<]Db`1bSu8): 6zCR1h$wr[l{=v +`53 ]1ۦO1sm} :=6Sv7,rq+6?]cs;1dB̺㊗sit95-z3  LS=tMSg־|wR)}l5MM]kqsK{.a~WMJ>Ė1o9$׿:oa͹63R!71EeێAAM>"z1zhGy3_Jt߉ 65瀌s]g} _*[{֊N>0AA%R3l2CΧJswnQ%ECp;R=,;jjY]n-핵q%lqQ=Si:),?yf'_+F t[LNo7=#z MLGhq;~t|V|uw~N,[ROH Icff j/> %{2[G踁cBP @j_|9<St<CG`q_w~@.D  X%|qQ%_>3X EZa~d꺡\i:8%UY5\O*ԝ?ڽ@s&TLU0qq N<+q?B~=D1;0vYfuLAi4y ACǬ|ض9]c >q߽r_7tzGzݞnCHqaNLViґ9k ϺD)oݭ-–vVJ(n(#2=q4gbbBpR{QKw]5m}ICP^c*]gaO쁬YoZِTS꣨غP KJiiGv[>#{"nf L&TܑѵtU˘\~)9iwtZ[3OxZlL3N&.]=FAcLK1m&,.^|?`p4R۫S=_O;OG}myօ=liQB(9nqkL`n_  ooA9q|KGNGoؕ  p17)g ƍ:%D[fǻ&l>cRWߋ1 Ow'\KTm/Z,9K$nOqjom1ugsb.Sկdy[_JǸ>  OˈV?'Y-QѲ=uPLE m+ m4 <^ +ckYƦV:/̦Y/&m/Bh8”7)&OC| I[t $bk›%^M,i@%J?LO!Q7*v '*==RZz<㶹i`S,7H8USϣMn0IVdH@!K$2{]S۳R!R~u/o{ܣӢ F[ YCkᜭSn c ۯ |@<߻Mr[ඏX!SZn:0Vs􌃇%Ѽtim^J|S;_S;9/k'q(_Ct#g`ՇK7>KHYnmHא֠US5-G/[2W \C,+:K/l!]V<;͚SB۝ךALUk{IiBZ /Ie*τDoC5 CΖ~C\c0'?1T3Ԛ4_/ʡ޺g% _=P@dO /xSk߷Vu~0u%Tϫ3~GBEU5t 2v#vFVj jOm:\Oqy:GBBe b.i/EwGO"fRSO\V=l9nZ6)REUx`A 5P$;K~||>}5!Ӏ \|=KQ0wRxvi{"5-h i[On~Kxsb;~T}r/3W4nxS~SSkzN3 Y1c89T2{0<$#x|cp"Ղ('I/FHvλe|ٓ_sF>}|=fw?TzUL}2u^%"%4cQ$j.lJG{ ~ZȄH49kN! I= Hql"挍1U3Vک ' 2%)թ eٍ/i;e G۲aJhȃ8,\g,븰72K.+$( F.F08c*k*#VyyZ!/Ph)1`Dk$JJ&PfS1p `&rVQ#JC)ė '!KΚBX$_jKEF!w( g*NB& h$-#Kyt=`ueIϱy8dš@%&#Aê[p"tANbߑiYkR/~ "̥+c@m %2Eq':o&$,$J 38(K$9 16 HQկX:<bNT_ )g]?bm>^YV@Y@Ku)/!,ԏAH $+!di|7ka^!/^V'_<\>H(?,,wh`5H|9P "$\Dj>@|? ?! >3>s><_A>nDEr sa#T~1>ͱGʴ CZFjq.L=^4>փcR-AC~2š3I~% tV*n _q(rr̈d3Hg}iˆa;6pW\7UZSŤ%&y4LX|~"fYeP&&)''jvuB lWZA@ֻRL̇ȅF1 v{xДZ/Q FaEAx E|cfLOPe756 :e"<֯g] F P?i ykJJ)f_?\7'ih*t:dqu^zm |V\v~NRVtu?̋]O{8;uv4[AvO(~2}wKQgh? Rnn(Ԛ87i9^Vaa]|x5y~Yf=w*)2 +'AfE[VFLi(0@}3+8H8LrPMKndA@[ONc Gxip.3Vp&CA|~²[h7 ڹ4s mibqBD7\D_`~0U:Zy]]4<" 3O#I`JOB:  [Y5B3CP#Z`b .@I3>8wtH+!i鄿5MHH l)jCV1lr@/RXw|~a3pN NX9vv6*ٜ LX'4#rFHVTJZjݬ ]No!p>=e8H\orFG8SyA# !k0/0QwfA߅+<0%꣟ϨQo` -|ǎoly9% Dl \+EbG6W * %t|y*B1WG?CvkHIJ$H}髧F! "l듋}XMg񖒪uV0އy%:<˲-ZK5E@0]$YK8`IJc 1@mw[m$jmD6d◣]$?SNrS2<1FFg GJJI@\La?q'z,TN3AUY%tBېh8YAC^͙Zc@~!jfm6F?KK,0QǂNK" Vj4l](i mZc6[:__+{ʹж{mG0rz3 8~ڣEb&Ӟmq?-* =h6ED@QRR6#LHhxH#V7cVm9|Z{vYq**Zs瓓\lNޏ?GG7ȩc\7YttSio?.כRRgs$$$gAmNO+3!X5ک) Nñxr41T5E+w5}-;>sb3{k5{~*p$ 5j b^f=WuE5QQ@T@bF4#"( )i!h(-RBD1h @h"B I{:`|oo߾ͥdkT+W>d-yQCb2 sO g1?αM}7x rasG*Izʆ'm Y\AQ D=Ө@f׮^WzKѕ)ʭU¦ΎVqi)BLsVPـ bdviH=54h٧y};B:Fo, ܫc-;}w"K񀛱Z1q8''gނ<rr-c"kG* "gl0MUm]Q ?%`HY^7ҺfFG&{/ =J`4L=1(3a:i'XܶRw2 .]  4Og,cQ ~su?ډ}{I (Mz1BOt(fÛR*wR v&C€F@.o@nMU1(&RvSI` |9?4X=VZ_!q2V2LR i\]Ζˌw=j*ZB S Ov=Mݑ(fY .zۅoR+%P<$hjvquL~\V-m!I4 hfh% H-c5A JJ}pk駡z(j1XgSOU!zܐceƢ!b… jSEх8"MP Vw܊("ʭvʟ ˽^&ʇW̄zY8s:s7""b=":h\Aq;[O{.%7fDi}f`6 T}X_4Ue9avQ Oj]:$j5I$?P2]a31I LM.i0` :z1 nm6m@-kXndqW;젌@E5>(lNf nևO}=rg8΂d*[VKGP?uB{6II5V&`E 6?c-6% 0BfO*sT|F^#O +If+ ͯwͯpC3s=c:RRSV<=ؾYӸ BZ'NvAM8[/=Oyd_뾓`""?!29YRwhV-%XG>hbgה x;\ɃEI8_a Ŗ#i}`粶=z,Tiy4ӏ=cǕן =ȫ?bj2 B \7M"8*>_]oxK{(`B@K=>|ib!A`Op[4Lh\*RBel^E Q]cj D xFlTyeխN*%$lJu*='¾B9 -+++T}va[s䌠Dظg塉)9b$!$03.o=[%)ޡJ6_(R C5:;w os_+`PN"TX.Ajڲ67ōϼ ̳&P߇/cV2ԍ'5 f hK,GƝd40^/=]+"z>*2$kOd7kw$poC4n+K8DΈ{ugCbi798OY ^<[q7PKyKl7Jscrshots/Journaal.pngUT vYvYux uX]/ OPB@B)iS@VPR)CZ[@^k> L91cc\_ˈ=F!D`߉``08wdD7m=;yK;G}>F &.Z)agIm`2j'+|πWHu|FB"G՛Lͨo6c}}>12+wh{xt/0rր,"m!(8 ]s;GRy8B-m,{ҿ L DH[y*Q畊jh2(fŢ~2>޲Һj PgmhTp2SGAs^lv/ZK] &)WZg2gbL)4/o(;/UKG`gfӿH/56qcH|̌lQݣT UDn:=/_keHeğت5F*_eUTa*8c `x9!\Yl5(qe~|b[ު 64c l3yE}u)O/~ƽYhÛoE9{@-m$2wI}Fo4隒;,8[fſ{+9OϰOE:<23BcZ)Dr7mtz*D6KcCRO͗aQX좎GeGXT{H*]<W ~e$7҉rSK+|;;K N/2<:,\,GXVկ9*O䘴_/f}AE!/ϒSM+9 Eezrbeh2Ԋk>^c^Ң[߻2z{_SQX7v|aH+SKl6C\$Ym9Q}|ᕢϾ\[#*x>8X:\ FAW I>, 4ՂLkG#+[ϳg㸌pD'^sdRTʶdx[a#Fћi0k6*a =Ad&4AB!560Tgd{- ^p%E Sm3!27"IlU쎸ը>w1o*7q5M΢he^rDzuScbZ)tv{n#ؠ~yXdM!iiu {Xo:3 0ؿ_yZ[AdQpAWq JBR6V$+o2gEc^-u0?3}dB2h'rTp4n_R91^0\H~u\e3:=Ew  ^M?;z6ym.i\KD|P!M:+o$7ݹA#^ SƊ0걭MzPJE0+apNhpO|.-"P@G0zk d鼼3d3)U:)OLvmj(7HTX)bȟCzkm0зQq nq05{\?)Ԝ YA{r8c}td$MNSF&= jsN+QEk/S&[x2u0H.bݾHuq ٽ궤+1\F.-oSS` b9@X%W%"]-b4xNWVv\ULݏWrqѱ~ GxC;`TTԱRfiĨ 犰&\ ZFR xLIq?^;>j"_a>BU*^c῾ׄ7]c#pLNO h X [*їtKЮ]j#9C{9_$" +xVT-3M+ٔMWJGGE6'ښW|^Y]Љ/*j ,{E4QQ0:w:Ip}iՍ_3kAmYoet=oF =.鎪q-ސa{9*R&Hm_g)@&.Nikhhl6E*+$pwWeU])ewƄG ó BLDn~oLr+kk@z1Wactzxȵ=.o'W2=2Ebd|x}!|E!Kfq|J4>RcBPTY0gMBϳA;O?,KVv4yHc #w|Dz[cU2uy~:>2Ll/OKvD=WI6\SΕglsa&p#ae\jBq&?vw7z =r̊9]ʎ "llaoI/x}.--m{ͅ%w\ڞ|{N..2l%[lf.ej09u2ej*gӖuoPrq3o# ccUW('OccapW< =8>l9hm$Hv?:s2{N Y 3ן. 6Ӧ nn-j^S:d Ҕ%}"L̉G#콆JP 7zE8\bɂϪ#}Aq àmu Jz4!00<Q577cy{qA|3ߢ,++ kJ\6mgжa#|p{a^>I(+YX_Q @5rEgGh(>lۃaNRndtV3H<(Q4 ,.Wc|ϨVIt|H0dv'r,QH_& |T8zQZޞ?M~*k7OO?3gU9>13sV _i} /E2i\=|ZJsg3%kӯ`vKLvEU@pn݆}%|XTw!w$9kp돨(53Ӣz 󩏣]UԈͯ_oq8ijo=} \w2$9mr58@Ąqs3cc~h^ MGj?D F\Zbh2:['ڵVV,„[yǧ"m.oY:;~}['!3aoodk%S?>?8qe7VJjAD|[ϑX^tΌ?wPu 1Q!4Ns|x*\Dwav8ݨ|l 1~=^Nr@en.fyO/1JyЕWfTape/E-ؤIC'n#\}\Ikd=|~އ|F۸qrn=6(0r88>8TmUzϭ:zz?TltJcmq+Eښyce P^,_.so$-=y56 ^mzzw<#KtEV~RTy})맍e%N<Iу OVz ٙRޛ:RZd^q.UW0H߸=̝"Fl]жϘ}S1l۾w~z yŖ|Crl«2Qb^;"w]N ս[$TV'ڂAW+kkiӊD?o![6ݰSܻ퓁Ax*׿3Sa}bMo~-.M_ySsp+D' dTW\pbևzkçG8c IC !Sn)}txawGވ>k I )fbK X].|4ftm^߻dU8ܨ-hvsHEMf`\tjdsOggsKێ'$!ۛJEXߣm<)HFFOofG&i Byt\@*zy,Η5_g?.M Q0oI_4G]~*icBcņfa~$Ug_vrDZS[&d|" zbpC*VUS%9 yu%rXj5Ks-)=ն&@M=v ]88cNxщ22.۟E&*5W*1PBL2'j;wV>Ah|hz-Y+t/j|;; xq-5R>| {tsFvdge JQ=\idӞj΍2psrWńWJmD9QcKi@XRۭ_TSrtj9GzKc#3Es|.ZL,dY (xs5^ϖY=7HlxOKF xck:_ſ8}898>$GC4m LSO-B$尣+Q8rHhhpe([mOO-"[j ;ඓZf $N ph$lsGdc727\Wi>a>b>4ևCδS6dWh;o SrvjH & xMg}Zz;|cBy Fj8B͚g<2@s?oZX ]R>$(Ҏ5g>3ayeCڥå'CJ..jn+[?=Zi;zKހ66,l-}y]* &$祐Pe90- ^(aԨ^z*ghg)q޶G[WIf4 6^5l$k\qPfߨbʥSTBId0ё"N]/^~|% %+pquȻaWfqy៊ي6=j~(3Ÿ <IF^)$%k7fc'9s$|%;R CKoXr`ݤR'^&VA'V>vXژ0qssӠsXޔ{IfҎ45;xxaa_{nF$ړm[i ~t=%3).0SHPhv B%l#˂diOWD|lON*s r>FۨFw @,2ͧ0(?PhWP~zyp hW*=4?BX;?eMo博:☼˝u7N[Xȕ;u+w|RޔNrO%W 9eOiڴ|A\*f60:O).vrrnh$OR7W"0>AM8^$J#r2񰶺NJWwW}Qr=0)gWɔK88;54'bs;@8{T^ +:W_TYpy1E9Z<8?zP`BGo0Ƈ1op@Pڑa0r\zyceWB ùxcѷ߫×",3M]n~vPMYgPu?+B7DWE[3ID$h\5 r@-mq_.""l*--4#=D \of4<^ ]ew}2E=ݳ3/fX .=n\*NOE@wt )r:ŢA3> "&(eVJ}C3ҍPw&#ZSQV5 [ꚿ/^mCϪO"xX#e"ELB?{ &BsYEk+k"POBlv]LիS75]4UvprOˈ!?|BBA'C2Œx@1Ô8A(a^RZH"Svv̆=D{PWcU5ЎaۣCwocYt01ۏs;?|E}-#  ATa$8-6#GG¬~JjIŰ<&8]Ղjim& 9_wBJuG37O;RPR$^:|}K j]QwF] rO$o ~iu{eo7hhǭZrhf-PG*ź% ӕHmF,_;LQJJK=3u긧-Nj]8Es';|hЗ`\fN:f v(F|Kpy?:?9u^7.\edҬ+m0n"˗ mG|dj9o"WDFAyҰǥ~3Q>©H$_ ^*пQQu/ndBD'%"&~cgWR+ 8ۂ\IJ?R7}0}||mbVri7o-/c|F{/ӎ~7{uھnl-.,MԻVn z[YYa&?(dyZO/<ã|0R( 0o 7w&KOǵn.IH#ܓ'O0IH"m1hTaOrZd^enXjZ.6'޾*#ib(jsF$W/?6vfs*[AmNdf@PA8p$. NnmN6>T"~e&7RvY iimAdlW( yuRtɾV ehxC~3ׯ~u>-4_5Wl}J)R?#&O 'j &[#ϻ,Kނ@Lk DySd44bLǤxvAכƮN v XJ.y/!9=k A_ɒ4wR'U«R6\8}TAN A?cm*2cRRR` Zdo `K eKo}ӳeS& Erf/ջoQ|429])ӭr ScvN7Xsf?JKK'K|,. qщ?|q57HRPP^@|=@9ژ[_|Tq@ppy_uׁ^US(A0!;[ftp~7pSҰmRf >-`<)H9H ))I<T@c>O>ؼ2[rW"J[K+|4:<< d>Љ7)M6_3[DLwŨnR0 W聈6qyrIy>dԈI%;)k9X\Qr"j#D %iʔ֣Ayc |8.O#zxo::m6@QQQS gFm@쀌') 2s^UtHJoE|o PBBB6fk+{R>HNbCPvU\i^fq^v1-<eoyAR/@FĮ'K Ɋjd~cն3@Ғlޙ++ F7"r}ޫ@~GZyBԣr|.GZXLdCB?ˀk 9R{q3;-xeBiuO}pᯙ\̮$bq&:xbUuCq|`v,_ HPEzU}!0)ģ\r+rd,==qySͥefO44MP|ὑ066xAK+çDӕbNNNlLslR,d3`"ɣMf;F`/ z2vɖM?Ņ:ux C.3EI ],\>$"2|^Έ5ل2醬&\$ u~=(vr@DDǪ!I? ?NjZǝ‚~$2\;DݚƎ^45}1)j0:WqHA^Gtęhŝ`mMqYYZ-|Hsl#9XSV+kWrE[MIcEuoӁ{nJ ÷Ωg tRƸ"lj}qQ_Ss-uw% ?L܆oMjgO"$Ct ,@ ^nSɊhGȏ5>7R|4WqcQ8/:οa8'|b׽,77T\;[155>]q6yu@VVp`Dn ĀSn[?ɴNrYb:5i9$] ee 'Dd{|~52(p%P\>ZY=FS`n`tZ*lJ)_feo {tNЌQp̸s|%9/z(FCjkgƕ?{,fK U1Fopx6>ZNMdQxصd({y68Q~)hZ$ t%4' %%$99$% YXXl9s4M$CSs"y/ֲ 1%%\?tb Pԛ"ߺ@~fOyy%n|+F.6CLM92}qnSWQ0"*xZVH NMi#ڤ.Unͽ,}syQm.exsH?=e_i?- }>}cablBlA'D9: P(J %F<&j)#J>ɲv,*1@:#j"awQ z>~ݵV9cf yda?Mں8۷'0QP>f5YN>/`mwT &췺essX#l꘡7imWy=zkI լbL`,f[>6TVwއ8; LetT pK=GѶ \L+^OL($d13ۣ<)6e7>i^=٬kϛOOK@Ą[ px׽ E`c}Q =ƅ?"1]YɹbXW-**JԞ&ץBQ`+A+OpփHHBH oHꉹ`BpaTP).]zz~ c aCŅ{}\rasӸF#XƦd\4KLL 1F~b_\dw2JZ@X D T3M5QSi⾞(R&9ݘ1Q،`I#o2?NXc=t;lf/>>(e$^UJMM}ΐ] N,+5*;Ցct@"~݊;!2g+Љypl,6!Am\^_)^`wUm<;4n nd?|ĦVn9V`Q.K:^ ! )Vʃ)Vn &Mb}pskA(Ԭ58(Fҭ64Rqzv:'-": Rލ$J˵Xim,rŇUG=S &NW!m?Q&Do)o~=#BSt^+pA ʣz{{3yr2]jFJ7R(G9ZPkb߃ce`z3lGZGy4;86}D0T2eeo)/ 8}X  А!W M@+vKo N'x /ýz1WWU.~wLPrBI^1܎PdL o)P]]#;;{GjryA{ /lɵr~O{'䯋#JH_>0Kipz'bSZyԁ3&$ 83Fg$jnt\;<:FNCH:3{x|I,//%>9>shz*Lj),R]//$mkW%*r%gGf~{­Hu$GQ@2݋ vȂ$-`p@Y\XCMɅwrED~FtcZ&nks@e|~8;GfRl&&&zo9fWzI1PyiFK_^$on֟ҵ|Ɂ .y,Z)-h^TᣱBLnm_<;sK5Ů w_UP`o+,wT$09<6/Y[<=:׌[w7:$"a&CIH{T?^OR<juvd6~BSz ~Ah@A6/L0@$xTU8gE*R'( y3Tu=8٭|9h ~cQ.!A'MS'7ڂ1im}[<>^BmKX0^ hxN>|&u]Ώ ܮ IbɔU ٬4&bG4ʞ8Mx|N)?r,lʓmЙg/;TҗBO4OtyN b u+UWRvQn_ O'ʸ_L"սe>ʧ{=KLxe¢>cRG;gf98C]ݾ.ft3g7/ 9y9'en=ɫp/+0PASqIpsHU5"// 4T9urgk$nb?v<[/Ѫ)Buk>|\ N9F"bFղߖ~nߨ|E{9 "3_՛#EE4jwVr.VBQcpH5Tjh'U]Lmp !"`S#vڔ#q?ztLZEDʬzXaX O-֨%\2$%i^6Bjf .nk ݛRGUG5vԘďW*]~U9vz'oUGevsDadcMc,#%pli01S4 s(ԩTyTt?:NHJ98EB8{$F q 4:iOJGy$~h$ -pn&ǔ4474#"PBe{14$gxs?f:8Kדݑ2w$Q@@-'u&-;ph2k^#U:U @SA',5yHqf6Cq;h4<h ܆$kKm4MN -ezf@L/or5'qe]ґ[z2s>Q!!S=zi(1&Cާ񥆟K3jr.*FNoxWթ*1`zS 3ʩ-6lTljb6]JU_V˩&[;~^l*"#Z'H)a,U!l-&@ ._I/&ѷ==4uF8(+գA3Gk먡 ܔ>/SEZ;8ċ"fx@_$Q$ b=_^z&/"c8vliK@?b<ƕuuGh/2 @^>"2Ļvdm1jٲ[[4 9ڱdѤ=_?i+Z/}.僃-oDf ySdY{iiL~byť/GǍ[P` $qt23xiS 9~kuk4([r(tm=&1Cf!1;,5~Άp1 s^+khAg{O&54Ty՝z==S+ۘV\\/(J]JڔX iQuW"?sRO()۫_Vd|L.MOv=['с&t洋F@?N[f-sdAʪkV]W 6:rIK$'saU(: 7eIj" F#cIץ/qF~nQ𠗳[sQ#na ι+UUy~ѐ%HY΢H%tu ]. GFNoP.D*4/CDxQp33x wMF)D% Ȏ$J~׳wqkI1a->dr7gW(qPsZ.Ū׫|0'kjpB7F$!\_5xA21 b\WĔ+],3` ı:x!_7 7_1XKIӿoہϮɭ . kcQ6Jح;-PgG o$gϧH%65u"!-FJS hFgjjOT333drKI??@$ xDCCSU]MǤsH[h7b4/1x,*pSw'7&ȣ+pv,"NP04lwQZdop^ں?ǀZo3j!٣pYdϻiiiER+-h酗ۃǺlz齿Q@zF!vAO tF#zXh/Vrأ#4R}#nwٳ1WVW~VWW Ab"gA/C3h*ee7E_`ZT9s@h產n~KHe$U$}VۥVZZڦm&;Wc𲺠;6驐b H:RM[1?JQL{z"$bB5YDTҮ;09&Gն&cꖃE `5Icks&''zjTSd~ ⥪sBY_*_ָ_W\L6ZG*|ZTԤ<.K:G}tEͪDRkF j 0;B^`BtXLL}$2Ө~~HKU|v/C. QLs|nA\y$׹/qHV Mmu"Ɗ5sTLGsLf8-ĺ:;SSRj j<8yʫIIdRONMYgQ^_:QP{FR)Oϟ?rtNmf^ΌRF%=R#}k44SSf=s>2l 9t aǣ!!!?Hy7*(]1UKHzJEM{sqXag3T2Nen@䗲Wfi0u9[- @U{FXJLŢ?kҢbb+-+G5喼gkQoPeI_5 ¤:~O| G֡~w/||}Hrrr^;ϗS.W/oA@u PAV[ d)2HN?wYfgcV{lH8w,~,FMjM۵& :::T)7; LR^@ /$>߯3Se}u)" $q9`b}AKϖ!;5wkp=8,en ژ#h^aR%9 8tTT>sS?lZ+qu}n, SZf>ߟmxݨ/{&K7 @bn 42<"t r`qqPW5nMMf%?qlPJrb|RՕ.5㱘D\4eeR#j*nT*Z2G\;3 t"Uב:,5{#-A?-?|LMJb,,$.PEC[4K 9;s6ӝ77qrrB?DTU5v4\,[&8D{L(MyxU 缛7_ w5P+Z/QponnZZZ0 S:g&Ƽۿ !z;8<&0n{c_l RNd]XVJ؆>h7@UTP-[,'Ԟg**P=|7.njAE8#%'xZw0!AWV>7h@|= O[(S.vޞZ@|Qת zR@@6{.pC,`uwW1q~;;f:!h[{8^L' y}wY' //J IB$~S1uNhy3T]I=000K$ @ziV{/us JPP*Ps>ۙNw6!c&(w 56 rPjBY =<8NΔӹUK640HOm elT'TioDjue(lD^Ghh8LYEfFlj_:!!zcuY.>nOK>d<<A~GRT>&#<t~cGڛ/VVV@LTZ&]&POUNo ׯRS#ޝbyEG}b#ȒNC 4P~20o$ƾ|D b0mH;qfV:olc# Yim! FsIФvA3t.ښL"\=3&YhFOOZ@?w-B=V+E=\fii^.D{XG|| *J1zbA{PGlc|X@bRbKڞO^LoR TOm "xɢahXXXXHtޕĘݙj̀@@%5))4H]|)9ۓ"m1--%ͬ+ǒܦRƭR>;}w/);dQ((ҷ;T.ZxWXXxW44U5Z]U(//v1˖Y-V#VTTt!1R&OXXX@Bjx""";-ajdd2CCCw7[j7KJ=@AE-ȿtҞc~P5 H H27\| /  N ,E1gWd( qe>3ۜ ߚo ]؛u,/&.1f>"Gq(`r{Q5)oYdz?P&_g ˛/{B^j Sݮq;Bn|ǏC:$׾.)R^H浰a|1ȅ7j&@∅_oWbk/sqMaF!#9%?DF\ ~kKuatcT\Ϭ݀A;m^©BЪlrȡvR9~~y~8,+ $"l'P\{DoCIuZRE *eЗH,POw7Y=?%sCy&PY%HAh_uiU|2#%FQqdrIRRPM[Xc{~|\YH-[vGgfe-s $l[Y@@FETOk9ku9q5@dhG8PfnRvZi9?F7nh&MHW>&i!DoyB"+W{帧QYc/3/{j&-e$'/o'("$nnKL%+ u;~DddDDe=cHS0VǴb;R?};{W@$L*s(h:!1y+o8Ҝ 45z=w#ԋ gu¦v>(z0{-ҽ lZo+D +Kr%`JkX!RxP 2ճn_ʷ1!_bt<[v?QA<|Ϡ^Q^!f4,3\@I=#[!&Кcq<.Y@8M ]P2i@L 42*pv]d #ysD2x0:ڞiZa^YX2) 5d]w: :UUՇ^{٧ p)/ 6 zuuuIEY湘M%m/@=iDE' g,lQ8@*ɨ0Y^H$4+ :<Qh=;M spɤ ?7'#[vV%G{La(d`{; 9 TmqAٷVm|Ϣ)A#m SrdI)Oj&Zh\Or1^2#`Q.륇iuu-oA ! ي!8Bwbhh(M-z::(a8v^2VV,p[x-1ׯ?; zf.Fdhb{dluҫ 60٘ZoǐT})5Y 6&e3GjжP !] 45 >(U?G|,us8{0|;c5 D6QU%p9+(wSP܇>RPP@z`EFFRW^) [(8-fB,IM_]0/&Y[<4"V66-^p0JUD$$o^1$ _Tu8n1`53=[Ml;LOW}'j_xQ{e<6Pa|29:t$l&8DԾݫ\vZɉ]1/.A׆j7~9+{mg>#O`>GD!b=NP ytt;7(CRVD|66JywLLp~unr (̗q90DE3 #^i)SލPM6c#a2+rkԸZ\1dŴia t&`(dlzb)jvj{""p}/cJUT ů%/<@߀+-7>rmt?rW/cuckI(SΘqXD>0b,A*=Yw-OZ^N ^l襤gF b 92)nh&*a1 b\8d@U$EYc e@_4z }uZ( d{Uկs@fiq m[Y[m[` E◙v}{`V*pׂgw43 he 9E1S(!Vo/vJ!t[V`x_o̘TEY:)T\J"n*. &utEۼ}0t~[[43Z:%ZY_{Hƞ'&qW_oVg2}N XMEV)av@*g*NJeSSSXLg :KXX8E.:wGN*.ǏdDd K`L%Rbg# ZIEnLQ;ȆwhJඵڟ+*"1MU#wdT?LH\ZOZg/h<.ivwGJf(8u6>7VEܙx0wXr =4~b|6j7LrF %npw- Ř۾bQTB龭q$I9vtZf);[m럐`cwIXZkNsҌQys|2(F >ot>ŋȨ(9gTJ)2228$$2` n_z|YEĴڄ@.1>hOB08׺L띏yxddr!===ㅦ.c a?j^n4Z-+29>ͅfزS22Am5BǜBzu{a;+O@(fh|ĄhbY4>|L99^&np@P{p1<*^Pj CAA@KH|k>5PJ,ȠbЪÇ|y+6q x~Ŷj'0sQmcߋ~lۃpxeeew}Cϥb`ɯQ2٢ϟCuvUU9 R'n66(B>9C窕IbQJdB$ zA;ļ)K%Eӂ/@HXl|p=%UsKn5pkC_ Vkp&`*VVi3!/r@]l߀>-L{qxUVQSjUOfR<BGlA]ݛ :99m6Uk޵2n5Z[ͧ5<}WRee+3wG1fj_SwVkJ@|/Ζ+^A+cנ%\a BFt087mR붟>} nTXi_ijl١RףT@v:+b׻ oEj4\Y:d @<::t8(dlՍ))Ҡ|R{Ch[[[?[){hy~~~ $ 7G5 zvs@ TYQQSǕ4hkl=W*#1HIIK_1kTy}( ޚpb<$TDE=!ZtZ٣j0!@A ʶj2e:G8 yO.r,r9T  OY#`44HiO\KaBNM'6s`1*)~_4۹ߞ;mTta2̻_ p}Ǽqk4q84R Qny<Tpλ]^ZzSVꁯg tBQ,|@Cǔ BdLz*4[VTw%Kq&a] h <)/ \GE_yt늠3&|o[; ׽ס!mm|JOA،(@B#|7 BO_LL@zZI9Uf QzIIq^. _ nqs ڝ2Yya BH*‚PS3=R?NR54:څOGeIj?mGI螆WwTWf+p [E^a:vvwry}= ό Q ˈmOOh4$/bϟ_w,7V&ۦqK<03ڢWXq3H_`H\w˳,ys?DZ^=_Q0,u]P?S}q+a2MaҌnQ)(ۓ~:9u;Ҵw9Ód?n{Pt@]m(= lvtY~ݽ\~Me1\-ET{;+)5g44,Z+w\nfsduambAH$=V |,#mZQDK= 5#hpDSxx6FCC~&_({xӭbe?Ƴ1~ll (wW:Q{*pE$4c=HéC70C9햏WS:?U].|7?tGmҷsZW$,=kYyxkYa2"Q<}Z]|7:[]X4-${*+8c-E8m}/ȨZEb 8H=)]%|nCLh^EEZ&rT>;$R7uJ:BI;ʌ`@ް]?77`ciTY\?-r(hWŅ ˗؊ %V㚎@%{qC5?xƺ?]]%P໖ؗwUvaۇb@1ǯLu*}8#TuuvHah`\j|yyI/Gx7P54 ~4ߞ\e&g[TxzLy@ Ms~Tnez~~Y?hoιҧlι=SU(ǏOOJ㨖ۃ*- `nD|/-)yٟ/DOOeY0+J=ϦTSOzHob}s0 Y..{/ zXtPbk19+PTTUMʁ3Oۗa[\jދ牼eIg]%R=?9&JڒY=iύ%KGUsn.ƎwRx!h⋀$X` j{;9MMF 24`Z>?*//O ֓g^>xR8y o, ֟ |!`iXlUiR~Etq8ˉ]ODqۮg F3iyymV@nb܊`|;$K9tpt 7pڍZSږE1C%{98p4hSSrݫ094BZ{iHzNLm @Nt> V"cZf (0n2::(hdмRķ@h^.f4@ *lHa970[3?p5xC֊rrsNe[@mG)|BHHt_Kþ?[yȄ 5M5 ]/WeWv&Km6ȗ݆yr)e3~Iy1?B늖;NJ@ᵽf%kzXf_CV*𘟀WB~St:xDDDy9Cv֋cY:T[}ˉ5b5:q{O^õEi_3na~~lMgJ/*EXt4 0Y(g;W=?!"bPUU5R-)Ek{'ܯ[Nm?. 1d(7_500 \S=qq}CWᠳ|U( ?ԹoFD)IvVF̛B".kWW?HZ(тc'FNNB,i,c,Y&t۷}DHfYc6<,99uszfRn {4hle/L|NTIJui((Ci_,;sq_zM'MX_ܶv=-kTӞ<ח:9`=Ci>{SA^^zy aF5#KW63ݍ*L} _jCQ?=̶)>a֭[g΄@-ܡ?pwP"Z:@mQ6RaI$ Àd2<%w:m!]qTRRjoollA0mm\WȈF-,8x,pBSoN $ bM+~w ,"^'&IK_D_>XGCDzssà*F+,1QK8,ڂU+Ztڦ\e5n-| ^r'7l}:lh"T7q>ZȽ8ˬθ)K@!A(akt8Kh`:_50ZZHgc?5vBF:ccRRc!m1'„D=u\ޓ,9FA2.-P(χ3@N0;BWcD0-P߿zKɷ^%%=vS{6ȧe M $ Z  ~<yŔqϚf~o_2\O/^В*R#ײbe2|| в28XBG!,rɒ`88O.W\.j/>҅|.{q6mpyqwG @ 9j"غ:;WF}'ބqW޻} bjs/A~{7ڡD~FHJ(7qAP8aͶ'#:)jf*Db>*aY^[ Y6ZzXl2mv# v8`55t -qta\g>lD|dsY^Tk+<>MJOhG/0w,٥ͷX~o@nl b{HHLU#^c0ab廊Ps:a;Š"} ~ sN:ۆTKV+ #Iq/^`BO 3n 4Fg>JLϾrЫη7m( y}R*<Ɖ(-0O"{~pެ X" d.`Ir<*j 1e`o{ܫ[4~}XtcT'AD$˗rr*AA,oYT=%LHR'vfcs0{~YLFhp͖Ƞ2(b;}+h`8Ϋ!Gqh8'2$/1C{9RE +:c18._lVbH٤wx긷i3훕 b@sKtPk{'xQQu-LSǻBX'eRt#+*ȑ=:>`R]UͬB8n31e/&;!Cb47OA(o#?M{..Kl&$hgDŽB !i)(ߴ$SL;աoʉ:*Q̗GEqz;-EN2F\Qcљ?4 M;޸R 4rDS+ZGNO%!`w%;Q2Y#F}n(Ll(EW1 '9X .V(S*%-i)O-$M.1+̳^Qƈ>-̺uBaJJҦ,5 Flg/OR#TkS N(!c>z_^kW*^()-q\*wUA22> , _kB)0k>4sHJU#T#19FևpmH|h~İx770ոMTBT7|h}HRgeXeur 9!ݳ[r.;a0@\xhbGKϺg6VLxŧiK̆uϚiSSX' Q|xp`@>|"3?^S_Xw|Mػhayf.zwWwO4Ph/yrْeˀ;`j<.tr~<[4l-MEGBm}+n,',uFǘsBix zy鹚5)@~#Y99=[ wcP=.DJ/.v,Ch\=(QTե1}dHtLW7F>G;As)B}dl:Ejr|2YH{pU?Qϡ_QFIc߫)OO; d7J6g89%<+囯GC\*P߳?#9'>Y x/vCq WQ$,y8 U#D*䆑)J?YmEf*T}<:TQUZWnMℽ]gaSn!L$سAqK SUܯlwN+F*FaGWWݍOl贽Is5Le9Vw$9v6s=FEefc3(´ Lu15 o}"gG\lIJi~G`g2*koo975f]ErY:6N*q,B֮ـ -M lv:vv=59F@'^ؿѸn* V.#{|/X{?ydS:d(?wgyݫOL''z* % n k;4{쭹D-işƈ__̀2 QzK1P^Dڈ^`!LE1{,!BFP'M8S]"'J(]JM"k &ED!փ&'M:kQ4UnkX+UӁ;sI3-M^t\0vLT{bYddž9˖o wP U&e3wq}b|3~v 5p{~M'C҉"˕ &nV\&#o$cڳs Ǘ7ӆ"fr "zW⛎=A5+2s-5*6S, 3orlJ M0ư>+/\j.$*~\qۻ`5!>dַ' PD7<-TK&8($]|ӌrE8%/"zN`BBAu.,xe- j!dM(L2;D-wigDKbrS*T`~*~dK'jR<;L!@#5{JVp(Rp;PUt-:?P'~Q6-7s(b` )80jFpHD (8Yj)Br0M{Qv#MI +; {t㍕0*"zsQcKʝ6 rA ݈PDv2Nsbdƚ4Ya]GvY!fQ00T++F7(2AV47 6/W#u  Y!(P6&Cy' nkCBҺ9[ВJ(8!nU٫b;q2#:|LiE&la#P wv_Jwȼ{RǺEN6BT|!kQmUρSe ^\;r+%^hYVti sxp~X۶.*\1}f?iw'pa)@N P'dl%ʄK@ FA ",2ֱr6)nb,* nnH9TtzsFRY@P:!5>+ ,.}dqCf۳be6v' zV]̕1CIR]ċ"(?DlXbgtni|<*B.Q18VݕR˓}'~l)Lzq~qsvSA@˦xl0 5d iKaVwF?a',Sf~J/$ѫk|v:uf |BRQL3X j0_G>d)"gpޭ> SI6IaVn[-_ezD!F#!^ ,^rӼmin^h=Up|Ih4c*a@˰.Q}\\bh|-B|qe2F1B^gANio&ͱ3b^'b4 Y@E7-˭m2 n(]KsX/$e-؞9X|?(!kɫ_}e=}?RyHy(WF=O=P_)Weg2.$;֙OtZA%Y_Y'!ã4 db˷"+##Uk@L%gƹ4& N [؁!ȭ.ݘlʨO"@޺jDKiI~g,s,=-IDC~3yB$q C@I0HqIՁW㢊Z D?HP:Ծ8Zf:ɚ:m73:i$7I`v8\98"8v"VmEKM%k#@" kqUT>,:fq%D& 5!| t%USCЃWX8o$G_|G=hn i7zusNsrp.;2O\wfFҶMvD=Ti6ך [<`G:RYs"BLMǐ*LPW|f[Q+$$!_ߕ:<,2]=$p/('0)< P؅ꓸqTHm¿N&SG0CLh\&g[2fA^K) IXVcphQwx;[N6?vjĨ&DVhUZ~ lP&ɏffEgL [϶K=l߻#w YF]u":5<&%n,kд~xޞ$HII6f:Lbv~?}N|_UxTvҵU{>y3e>A+}3ez7~.g^[[.b* 5ZOMbgx!yޅ~wKO|˲?~xM) 鼩p[Fǂm+3q,Yt -55ӣp_6rj_ς.z'w#SBe^WS;)'KZ9fKԷ&%j&v mBty G V 0ූ/S#IdEy ѵ eh(FpM?cur"W{zSs u<5A+1Fշ)~k=9nlL, c~dv⋋a0NX]cXE7FsbqVX}^fw&<@27 ,0C,P"nӼP&̗ ɒibNF{isƷܢ"5栰CDKPtlW7(`*5BS+NeS{IEʬmQa+ʡ_LAq [qB|D#%3p'%3!yUt:9Y\r̯DB30d`Kȃ}t:Yɒ'o]eؗÎ8Nwl YZ d<;|9=Ih0Y8 bLªz/GSXVQ93h51Lj,u >؉a?e**O<7ݪU+7κ?#X\Z|v;Z6t[N-1ץ)SƋuK폅=*ݱT[:-oV[Y{. ֆ)GXFӧvxzeoک6/jM y+i60яUFj[o&ʗ6ڎw=` c@n\5hBUT?/yjNOփ/1Y2?7TUf'INi6_vzҏ;V;)Jy(;Ä)@-,"Diw6 ,":T5ҲkYt^ m^]ew_}h5[./R WʯZ .00P.[ {|EPœGf!mon?V[W!A3"9ԃ"0`HʣbR4}9SQQírkkr'qQw{%F6chp$j?}=eZT4tS7߰nO9 6͆kވt,GXZΓ|pu%d8CԞ^7[ϱǛ+N/xS2RܯFL 1dgȦrk@gy+gj!9HôNAkw.et_~{-YtE/~R(S'm_PҍĜ 4ey:9.noN\ʩ\:$XBquMiVlh n}M\@?.\ USi5ٺhݹCgʃ|ZӗN\|`/XIֻɯ厞X @}*<چ.<7 ˠ.9]k6gпl h V N-:.?\äZc0PU30jK/yp^ZJP'$,AH;T-#B%i@O")BqQR;IVYŪ̚MLf,p(;0@M@[fXC}_m~Y9>0ѣfH~Yx 4͓3:$W3yF`_ڸ X:ݱԬokͰ~hg[Y/o,xN"d I 8"/gt ՞wzr>>t H`="c(XL:r22>1i`! Bܚ^єTppS9BNlVzF5]'Ic:S)zl):*@*LY&3Q3%DȈ|>QLa?iE!&g\{M[B^a%&g[rc0mѩ~'MܨW=DߓX5gvHܼ;؄mPYbVRr4Mc~g$ LTn Ҏ-mZ49EL"AV8#1&;:a"z MSoyaF+ZIXMȴ)lYUjSw o;뮚!'GpѢKHpۅ ai1pa=-42XӮ6Yq{+ T8oBrssc>M0 9J"rkَL0 I@kx\,};WjE`8>G+C?ൗw:%H^moT@sbW ; ˗z-\v/|yZ Ri=7<8_GF.vJCzҰ*P2i^D±kW6Z5BuJP8HdE(46[ډ%㋨8|*haS3OHH@g?quYSw貞P<|\\?XXfY ;H=5^5Aj%(a8stMXв6EEbgb0Y +BDMK׶+ u4XC9W \ڬ b J\a5Cs ɒѠ k#ݧ>XhuJ³ :&_6/b@ÇmSpVGr FiOHuVmPrkj\?@_(#z.u![`e SlueR [)NuBŠ&4- PחAJ>J 9(?T!Dl4l$]N4{`s$Ze{Baq"q2?=+>n®8Vu&Ya؟6:vp#b[C_ '0H,4l(LeKMR91nNohGl_3_Мɫ8FM8xq"vTj/`ڳxpa'܅Y|0V9|ttIVȾcJwfGlĦo_y(C?D7Fӫ>HXx= X6xI\hcWoY+1hr :GeÀyfvElg-20hC``Ip_|tJ||*X5;~yr#Q$B_8yu[m0+'VZ@N".mRP #UGǾ{<49eYSC!>=&tt~)Tnə4N#tHJCq>q$>^-iY(NbW=2N/|K L;t*$%&Z-B!Rx0=_f>*Q6JYHW#t0&8&}g\gX>p`6 8H ִ2XaYȪx;4e'^#)m^Q\Xʮ3[XK6| Qv(]oIvy9́=xcÔt̻P w̘5d㭌aIl UZcg4ǻECH{PF%I)F%HI>!j'~R?xt8jR[%EX&2كAIĹ|٘ {5 }oѤr] >;q"dmGku:?|r/["J%;w~d^{>G +I5 [u[:9qW>!Kל1C5ƹ=(WQi9Ul p%oQz#Qy#c)1kEI:0! rtb3 13BEqפ*#0ڒ;wh"xZ8Qp7JU + /~DžNd ;YQX85C}$ƛ"#KQOGHP< !M=N֘krÝoTd<FKE\N-M3F??P!5c^SLe%+R/3xޱmL?z`<3V :A>zg8=q c oy6sDs<FQdk*K@o*M"vǧ'+[Ezg.)%Q^j~D%|zYBȨĀu Wc CE˗x dPv͎pF{tìC O_Q& jK1XR2k?G?vh؎6"rIUL*ƅBWڵƅ@{l T$"8z(伢rfzU~ caU!/W&HW(]Kn&/p F@ &z<4L% hrȁcJD@2ZN+Ò6*RXܦ!f #+٠}R]v[$T`15j ppPU=}i;:Т8sbYJ =qOᜬPr 9l[ hD*.U#2 lxٹ_=(s.|a+ؿ2Spi(-hA P⌹pxUzOsRCLj5, 3пUXJpv0s` XBYb#(Pl/"(k^1`g> (Ix^Js5$k|aCfNċU4eFxE/a +4- gS؏3_yÑأV Aܶ|H-,Qd +8e9qBMbcqa6u' (dzmB6mAdm=:2_N~"S!M㩆@p=Y +<TB>`eGe:<嫠GփFS?j'~uЇęepHb X#x'!KqvAlb˱*HS:kb+}B)#6j*Qmq|[*T_^AW[PuD.~wllf Ѷsq`u2)MuEyu%-#քtthj>{kAWODBAA e EOx~ ҉Hovgɧy8pzf6ᙂ-tղ(sѳb&C6dսЏPNms$_%~bO>V_#FeWLZmo<'Mk8K#Ρ{ߢeQ,/F2ܛt iR=l83iDz6᡻x@ĺv<27'o:*SX [3WO Lt)KA%bj";mlN,L~R'S%7;* (ȥap!fhb" d8m"%?FY;tM2Xj> 5 C/`4SG ˸UyA dhjL""vkA,*17njyН{OrWWs PY4pcl8EjX/͘ 70kpψt' Xa`җ[b26gxNtQSL4~]Ty9n2n1rsC3$4*)i!U_w(˫m@[.1C) 'ʞ8ݳ'_|}sPM}+*k:;;?irx;жj"VLVVZW@(0 ~yxx6 A J@T>˾Wvuu{M~aWXdd-y> WgL/N0":$ZqM*3fF&Ј9l7[\s7k8!*ej$#"T0N 2 Ta.WY+T o VDpÂ\F踖"?EX+> C:6ӇwZ&G!m,bl4]`Lqv ף mg,oVJI]Бbbbb3Ι,~5/ k Ն}v5UƯ4Z=MƳٗ+W 8ޞU.ޕ7L ))II68VUܨh 칭GZV/vمץ.%9/M50fרʙ |fxhbPr(9@XW|nd昦d05Gm-B'a t~Z Ӵ4 ԯ$ܦTy_Uā:tp>S*U}83,>Rcsmċ}nM_yndz;OAJ _P872X_L #fQ` äJ]O6ߧ0i'So6O^`^ H5[c zdQcdKqU&/TpS#m7<hx9 =D|L>]ZȤIZ-B _ʉSZy,rݺ blzX;~"T*UC5wPTa)NyoD3.\.N텾W;PIMn#t}@;O1Sh:|%Gd1 Bp CR^& G 5^@-QyO6dO^8l$e9wY\d^;=4T"Љր*͖1ƩcF._OO+#<,ۓ`ؽ&&?;3j&0;!!!: 6)MoM15\J{ 9rwZuX23e+1#uꩬ\}/I^r5L oD(<./A7x&7Owp8غtOtFrH8BWU#+q3dP q!~@ riO,+ G nD3GܔlovI;pq9-ˣ?oh:-Ͱ0ktY#yvJr ̓|H:κTsTl> Ɍ]@KF ,9}֗y{ni=INJ?b@V6h²G\hlܙ1oKeFVwJ9uI9GD}L-'%:6h ggb_&D`,#pj$Pv1PgI?MGhc(c^kcfymס`YPN) Cqy~Yz7De#U[]/uYgމO3t_Gm/_gN4$Ҧel.)~h&kf}\cYO1A//bCNLp#3ǰn-qkQ_1T!{v (SkJ}r0 K9"L=eS3U^I^S|}?X%SFr!v'GE"Qpp@sGo  GI7"T( mCDt:*]#w~wTj'N2PknT܈B Ljcaj&,.segc{+>>uWLnekDw{]_%cU-5@O82}*\'x6vq݄6Z AF7aHAfa;q?hX]R=WXF C7tZ ȁfowuǖu"kJK_lfqaI}& 9G ֲK%YuK?^) @r\X%{jZ#>Û/;_S`&J̊28(bB$B0`uX0«΍͖Iͤ''Eqd;!d9I]T[/0.rYED!WQ#FFrhM&`@D=UBE^ZY(re3HinsqHʑL WOTx5v -̈n#T+  bb_3bRIrr#_<biGo`] &i" \#8w`Cxm9XokT |{xzU$9SsxgTr<He#^֗j:A͑4S#=6շ\πD!ظ3'=܈:ʜPj ! Eq'RPBSt_ f'&`0K KȻGߖTܠK^,<̢CKr1 ;~Vlpz:H.Aw ր*d3;/1cX!1d3MX hMWFLj@"P3ݩkLH1LrYLFh؇7%l[v=fGhfB'AYhubgQH#,oU6TZ[+\\C,]H"."P]/}ܬ |$5ĩx83) EFCB h 4!2"xNKA},ֱjO qx{62KN4+@%(BZ3\ 5M|j^oSn5C>a Q_g:M\SbzӰ9ng2jT U7/69r qAW]!?};1%T^?!LglI]/*P&L~d ezs<(2 JW'- Xރ~b0%H7EC!H텎 R="9z9>` %l,(nwZDf&{rȈdx>QBy76_?7jˋ҆KF#Dr[x酳+T""အgՑW*"p<~:{)i9Y&<[~)~(&%f0Eqdr&fR{3+kkp6r t0q5GK9G\SE(JM~^艒dC^D O,0*8iв8fw+%icA&ߊmx] 8gJJg'fG|/Lě7w osۥMfc}kk %UwZgz7(f j;d$5 %8&s@Âևx.9t|"Z=D{+:&&(q.zc6a[t+%Juw{Wi i8׉q7$ {ozbgg0Uccddܑ?PPh&vr}z $F/i>qsR2$\g@i<tfAzF!{twYlO@Fْu̔n۠>˛aEh0D>>,rʐ2}iyB'q/ W+(bufNq ټP X sV}FM6$ n\mmr@&{ޝ3zŦJ!] H;0{"r#'WUzUb"'R(]m^`G%jt #tpذz WKJ4+R[\Z'Rn6[a`gtd9 R2 Hާy|@)BvLP YvA *!wlZ7L3{~\|H !y6ℱp 4靎xQUC{o7u ߩ^7XɔA- qc[H+1ڣa)FQnuM"9JcD…sE5\k^3Ahrr*/õK#.\P،fcJPlBJ$zE[Ǵr~:-6BɈT 8\(>BZ-'x/|RD&|~Arz+leR$iLNd%m ~D4zQ#xxuI#hxBUO7 Bwªez\bVRw"3HHK<Lzd'&J0q܂^ hy m<>oY%(Cx8{/ Yވ9 M.wF-@)!r'Bs,rĐ8zsM)sŒ>͟v8yP>qbEpkxȔquAs My7 "t~GN4]\TqQ)fvC\'ĉĻ# c1}[lD$9Qdm !u0ݚ ɘ|S@J8-V{g3 U$P46@"?E ϠSs}u7GWF 5M=d~|V,E82hULTcRd^19w/ 4P/+>|P`8lFݴ+A2:eNvNOZ@>i-S,@"4iW%}M!`mm8'5$K../R.Y*-D?zLW&X<{>T%i^.jA?l;YNVpKXT #&"Le!ld|P^8PU]R%-̞$((up{9WA*Pקd8r𖣲XԍŁcMǑR+3dL~?L>Dy(1Zc+8zLwׂ#f1y!RE5?;T۷"^PRyE|%2 RuwFp1!QfJl#^.[z5c$̍D?#oɲNRI@I$+TdQ,O ӛcjDV*dljV,@@PXY| (}^O{\b-i6^PMͪOX qŹ!&Ct 9AO Cq t)hTkZŗ-+6ʇVq؛1?<7xa[oz+;@JbJbo daApX99"xiXMç"Fkjc:" d[X-4t32gSJ!ײrw)@Od<㌝Ę$P` S-yEc$ -oU8?9V!+*$fDHz!@iφQ(qTkU3a4`XD;]/<ϧ젠lNg§\F7@F~޹EXde'.y~XCГ,oܑsS m 7o3n#i^L9s;PtB VaĉWx9o vgLq~ |-[u Z.B$壥YaT8O[ڤB(y!,3#2~r )"^3+b#P),":kl݁Vj@0y"^NCU䞈Oz^2Vn#<= I1u[ZOrc}Z8@>'!.I$KGQ_ @]vI땬)IL+:mT{ᚊ)1(! TIx*ct {ȿǁ#I8͘Nfq>`t`*sj<=ЄVi42ĉv?kƖ7& nCV/"?/r°2bD\DHDh4k ,'62si3'!/L$kX nymށɛo N] *IXQ۩ѣĵ!:(B\0_?1?2I8J*GrDxŇ~Tb3aR @$r!b3vtR38-/3zK! /Ȳ Ml5~l R鴤],eCA|c}(@h$CfT ݁Faj7)=@$ŁCӦ*hrsir_ylk粸{ASÐKf_ HPfHp)Z8d('%oN b]vf O; t+enY,"$4^k-f?Y[ׇlORpf 7+EG`(hj2/aX/͏ CQ=t~h :I, ]HXg7290"<opf<%S!\' ^H;=2RcK`QC;jL?H5AkFk3.Yh"] Jgd>x-~Q hh IEFą0jMR9o.:Яe9mPaڈk+yClLceԖ3r7>,rɥLkXE9@idyM\PiFcAW\*faCtт0?n}Uǜ_H&BoJ&S:(nE@CS#3g C3 Xaf B2KnȎ$ʙ8JȕjRN@+"KGZE "B)).зF-MHЌX :0whHOfv1َ:yc GSbƈ#{O,["dfE ŭt罥nɀz/I۶l,;W ( "vddW"|~E8œ\O&}f2<9{E&*kf (`k p"D7 @AY( Zt46Ϝj楡(QJ97N+x1V[lݟOWn`}AZxabh!M@ݯ78>8LX>T6 ReK^$jfaGTt~Ba )L>K iƹDaZ )&3癭>¾1g.EcQQ#.V)wVQӯ;'=[һrɥ"<uK,檀7(3B^fe=d)3C3yNTUV0Z>fӖg=owg悶ɂ2uJ|"{)O-NFu{No, >>3|_+htI;HA^) ͚3 ؖ+h{r*F}4VѪ£b9 wعe,'*F_=(PL)`|%W'0B״K+6}$;A\SA|7M(f(` RV T ul2OG^/o&Wb6Os:IF"qm˵{H̓ \@TO%kQ&e w#$%J$7j2:=P|=vLe֊P|PT6;pLRAV5Y[JR +qh[̥NlǀnBH<ɒB:A ? o 92HQ/·~vKe=sM39 ]?dTTvۣ'`!<26:}怉ċd?qG сiOq-!K!bT?TY8|L8Wh! #v*V̈O2QP08 ^j[U ,LP*JTb?d|g21&6FKeT8Xp#QZКZf)X51F%HI0OvZȢU u|ٻ9\fۃC'kx:pG^GJ&@.?u H;XF&QQ{Ѳb㻻H n|1*TM@=ew!hՏ NLD!e#~vT=PBOhMrafXFcԏHa.PJ~ɳFu!e($2ԙ DP9"Of}"@QŌ6}#Ks9굊G+Q,as (3aB%5 kL_(S?** {2YC`2:!`CBH#``C7Hg#b\xM~ ! ,%ӟa|v@H*G)0Za(("D(RIwXA)#P5l4e,ĩ$vh(IOd77INu,sI*1%D.대9Sd0nVM@zG&KIO}V ] W4TէNZTntQKc=_iv̛ሼ?ĵyyDkjᐠİ^yӕ4Wpppd?w9NGyD[_3 "J3|yXb8Iqj'Y)1(ZS+HQ3TMY47L9@lXP$ k(ZeR֋i=}$N}RtlaXWd^x,dyeӑ)|G]PO߯Xܓ qRjD4#t&rSZ n,H2J RZ Ħ0Ez'f|_X1 N/Cw\^!l3!1 C8?r'3XoS}hvꏐDf(L` p`O3EAE:(Ouh2C{neqn^aHft#V$OrĹX$ҫ,&ۨ&q'X2WZ*4'9Ҿ:QD18fB$%=T0#:mt{ic4=&?.PUkZ"]_:?Did/D*j>\(g\وS^Nj ?Qӆ{g;rq͝n|q&ƒze;Ͱi}a$}kւAnO6/ R߄3jF׍}DRCԕ"-T1y`,1,kpz#ۥkEw`=BRj/Iw:-Nןr2yR'DC&%>r*t w gJG ưXI<ԹO/627+k@T<#%ɝ}l=h~c\?lij:XD-t^@]5V3phrp t( &\~.b%,rb.9gbgiW4[=Fs 'c  XaXWCf w]i:}=`|5І0`>XyL?(%4|7 _-]/&@ErI^ķe,=A3voԆXz2 @Eϟ(Q 7(<) Ԯ3Grz6'VDX|u1+DS07Xkݲ)Qo헨_^ 9G{Mm_od_ֶ@>Ic׭_.E77@ChGʪc+=T'9 3 hڃƩ"'a#Z.kN'p^~6mGhݽ=/;S`<6W;mg#;,˕>:,YgУ@lljG544\kUO[t} Y3+B{RN%DRiʢuҤ $% "He|# Uv}71-,*UͦJVTQR8v̩VBM!|˝Ofa9дؒ(KP,_)KC(4T(ϏPvEl;}LIR(Z-yn՘{-T:۬r"*F)?eQ92cȯ,O8\ X=8 U*蹦@(TNzLRVWwבWLwHR -T+Ux Q0^#,Pwi9{o)^DGL:IW(Y¾`N)e\-dpOj>=9<[,rċn>,l=-JjW_}:e'vZ_ 8CC| čS_>w~VG˕+T $VW&S|n~t,,KJ\O?Ob} =<<|,uZH /kut?SkzϡZ<)PXyl=]X`UaPA~鸑_]A}.fc\skt qWxGOjȠ2㳮ski:Zw@Doab8j՛/m:Viw\ $+2www|qG#}xn $ r5sX*QGjQWrzAaIm5d˄5p;p|$Б0?T 0g Yq@e#ά9 %=,rb4}@33ߊ|VWj2 0H# #䒈P/|s3;Bioi*{D={ i>\;z [ C2c ۥ+T=2v70p<#>,NUv{<`[ VlXZtX Um֋'oyOGOr_Vl5I.es 6=H7bcz^MCwuig Č{C0xq i] ;OVnyډ<{x`8m7J_ffk_VЇiDaR,aaGr}U 2{+ @%k7o}+K( h`/2k)3W[} YPKXr y.q5eu$ҹg2!^8EG私!5JB%t 7RSon!3oA+0+(9`z[0qM2?pe(f!D i H6Mƅ) \3ADiPtyd`~g{ᢂrSAi@+3 –aK&6yeT."):GVb]I]2]XH*2(N&ְyHT "u 3dXJ^AgemYt-/LrZmpZmwh5GlPh|^ v<Uj9ѵ8 ҏ:h:yw׃8rd|?y7y)͞9e~@CC˗\ϧ+Ӆ~臾Z^"-O0Ȇ9W9z q<#ˇʖ}.n1zv%+Y rIF \9/_lc|<O|~g䁢bF}QYZ"AfnNCWxhf0FS9¯5\ᬐ;/}X^^>ZcT$6BO=ӕV{M\.Qiflo>7EO='$FV> $suby9}dV|}`G.AuST*}B3-#2OL%g;- kvg@tLцe7?7FeF ]et eQq`t[Bc)??nkyz`{\wwڗv5?N$;j("8lPV۪2;%s4 9,{ b4Klz{ùoK kXF4<75 q|#~ø dF^'ku{7io@6k- %2iF4j,Mj߅XN/j'7K/, <<P{tK¯aUyW<7GtV1=e;V ~_%~(&|Q*5-x͎֨Jb~5t{F͏ɾpFQoZjux0}b¾=5 X۩019 vLB9jx8Vƨ}/-|ӈ/<nQHx^F>Skߕ 5'[]M,R0w!l+(XaP \BuY;sgO.-l>=,`rq?Ѧz$%SV7Qtݹ'BSZt p7м~% W߁=-$- `Еځ7$pp_+{nBx,+o.NA5 xD|||ݏ׹cLz/3iN_qݻ\U{|TEoKy Ny x],u[2\::.y;8z7x>m9oZ5#Z\ G ~7c\߻Ț/.Rէ=x'^OiVȭ_'%6$Xbȑ.iYX1;Ȇө2s.;P8 7&Bh£Ed^{j8g?44K8OӮF y*33 RS\4RlmZϵ1q7d"M$Ԯwj \O]lVJ58wChutgH.K osoݼ 'ؓАbaRNRI:V^E|Fw(mZƘ:>K8bJhIjJd1^\;mTZpkܱ You5%EW0~Ƞ/  S3T$_a%4wW~{Qv,KR-\wyojNt|ט[YE6wW87Mq*W*[3x^_m*s"aI\uiB`t,nwo "Azb!Asø /l.9voH%z Ra8U61,+q@&`- f9v7/QpH;ATu&gÚ@AS dMwޛVz_7\Xi50L I>k>:;SۢHosD9!F `'c7niX$}hym{|"#AY"庄>*4Gܟ?R-t8lJw-Sz#:]boh.c%7 N*Zb2sHP5Un ޚg'Qf.c_1,(R"n^ o-"Ƙ(&@,5 RQQO(*yEݐ98!Zv[<4[nB{^qp#Ƙ4"HLj @Qjc*>|][IDP7EWI3Iv=ڥ; pڎZ*g-X}#xx)DNtg; ܎9da$'$2[Z_ VRZ|IP>@a޶g/jϝG~[i% Yٻp8|9m8 jٮ 6m)~)+uV/CsDc8~M1/׀&?(΅h,(Z~(D$"'d (S)D)3m/)'xdFd=} m G_Khnzt *´8 ӕ =`v);a0+\ y&VhVleT#(]PTA׮:Pͧ[L!9ܡI* *t]>Ls\.L[jF_xidv| | dUrIVrPX)&uRK懡xzXcAIPXS vبP$}E!$U:N7sϴBoC 3ɩB2sWGVH(Xz%RI+lFLI{ `I,@"p:7g#Sv+sKjjcw۸(wXm*^A 0:9 Yf )B4a((EjV)V 6Bka[4zxB^9Ըm.ФY 7\mqAXG,[ra- YMX;hri4-k.[ꆫ' Y~m?ԛ1M$Y,*t Z*[q3%4X(/"=6D߄-x FSdQN|h} IYNHCLܣN;@& Jfz{Fy ֣1' xZp7hU,<$ׁ?D俽LrS\*,0~غPyRTBa1{`&""ɋQ1Cٻm٧jTb'yu[Ém=Z+<)k /&ڱblD qV{u3ӌnQ W5UH- "3Ώ0;3v "ߞ@04(]"D53O4Y*,2$jh#JAZ]zeȸS1(hXst3b:kvJD[ 6uFA 0*WsW.rQ@% )$dh_L2Pa"9#tjI]Iq͑At$??LpcDpy !tD)ٓ$$g[!/YԺhh:ӄ x` fRj◝ &"+W*V]V[.P+/0YubcO) !gyoⒻc!ib)X$`Tj:-ZR~61edG[|haiG )̔FJcn:475@x0c|z%ޠqc8u $VͤscFlV6=3'Vc z,5&XY+L^F6 ͈NV%S~#؜daidaJ9I"?Vmx.k**]9FD`'--]%frCT|hBNbJoXfU/N /y&}KO.T+&$xXgQS'{`&sb WZl~ yclD_/֟OOEJKxYJz͏)JImŇ+M /,6Ȍ\wox:nz쓟==Jj.. ɐɩᨽBbMV4iw QgDaPS>>^1WjA^(dxnTߥR}FgC&YZflf\KzjqO#GNVr%/b}qIJy$@ Ҵ3[] iF/;L+fZcۛ몇>8OZ)Y L+j#L-#Z֛q|(AOgm^O i<`b&qً79#vHl G7>ǶPϜK]f8o74uf qHZ,!Z~w?K} zKry+;ߑa)QCkCoWr Q!ǵ%M#{W e @pBy}kTuQQ+jK/eiYDՍA$Ek$ !So{* Gخ\Im<,@aƸ_{}ݐT sYbay|( #g IrnC븽8S֐cCfb@zVq7"73mTp{iUe8P:=v"% NNVnvb R~-:?M+0ГU+L}xOXZj33z4~%xPa@h5AA)р M)|*ZޔP%}x"ć"{-,e% rNrrj hi ڒ8!ɭc;ɀ5_=8N83'cVtWo`*l E2lᘎp].[?t2 VX̄'C{ETC3^vMQM%m J;CL}Y\ ~ ^+6.hȬJK·g&b=> D  &`oQT4Zˑ4A2r9j7Ifrʔ=5rJ~{Rr̃pg;Ő'yР{;H Vu_7 &'],2cV0`LUյ2ߒDHL%. T J[.xMӑҌ DQcOg\6FEiܸS$[՛ n|D f P!@DcO[qi̶9E~~/ꈰdHXXP]\FPl.0-1,LUtE O8b*pzyPR{?>/=MjN/#OΌCp}go ;BLJI%BE.lzJ';"@X@!tk/o% ]i| 0A3#U79] Gmߤ0)&*ͨmz76mE<㔫|[\U^p:C?p5!A] 8ֱ.XbR@i!cj[B,hōll'Jj>ciYjLe*bPNoc?3_ a~QkvX;u-?ϥp..X@Ί.j6Aw#fj\V} ^+Pq:sk~f %6:vfǫeU X"6{V- *KO?Cv(59AT5A/^h]F(t!W^܈ykJ=f0ola W<8^,P>VoklUZ儵EÄ:g$|klt^JM㏑6+Y<YkxADY$Zo} $'J:#XVja9MHJ4\ttf `HȖcs>ڧf"n 66X77G萁? ) Q-IwX`g Vn'J(hq^gpa^&)Vf>5z{K(nT_ p_dKye0nO@e1!ٖ sƝ/c%8-A@Ic@ڂbQdh6CHbM6H$ˈJ! tEHvTlfV%Ĺ#eHsa$&6@xu E T7M~5 C_A0Ą9bf48fEve;\8#<!"j L%^ן234@aє~޶:eZRH0wPa8r.w UBwL;^|n2^L-'M 8 &#i~gnmɷZXG-^4ݖA\ dL\ EլYw).m`5ʰ@(2uxVBϬ4a\č"=XQ`OwF`.`:NC皀O~Pct<%B(N3HN"V(\Ng9@23ž:g!y#m5ͤUr{Hpk3:vHb 9:d;@ Y \v`o^=;e|f_y\ t\,yr)_0+[ u& uBz2zo]mq8ν[=Z2-ٱᱥ:z0PαBJ \p%VO):m ,@$+?oB\e%SUσ ڶVLWqxkSm0෬2ƈb\7 @ dEXiIp8 v@Μ3,`X N&TI'42Lp=iuZڛ]{!=6 |?!VKNNq|fC6a۞v2zHbvjj|rh?/vyZ d8>҅}g|̡{!nK08TllvϦ t0물\~ê(%ge/i3 S$]wH i5Zcw՝3m^(k\tm-edbb"S W+q ڻ.6:i[q`p:&v\AZC"*}17z߳(S}lA4%Q;ܱ]&y>&>7?vs|o3g.Q;|?d܎z2 <NOror 5?T?׸gq%Q(] }ltx~]#!&4O05?-۾ZQVwŮKq |,>=]muN"'u_*ir`EKu̧8" kӌqgXbpI.}2pS7Ih F!mj#?D$PKOεl:)D"-4s4>^<s^2訡|, `=pv3R퇹:c=BM'-mc __uuesAT.5<3Wziy?\^]mjͧ>DiRxSn<100D =@OJͱBk޹\C.RaInm6I׺u mӦ:*UE>Tpsoi^<WL3תO>5?M'BgReN4ǹ*M '5Cvu_ˉRKV]l{JLX(->v{x{Pk-9}B>7[Q:kNct}tjXKd+lg!+N6kWTT 0y_mK.o-lyikȠ?"wK}NqR=s=ޮ׺D躯`Yv=@i}ȴ4k53} <̴YiXw 06w6]# ,wA0-v3:y9~^9~3ys ! kQp#"h=5=v3\ 4UV+4 UUU&_1;v_l%~fff:b "ljοUd Q~AȦ>@V*`Ȧs&|~bgVA$ԘE 9nH٧t$arc|;*;0t8\}6Soo:,ǡ Alz/ myzGXП{uwj[єM,y˲ressp *ծ/Q҂O}Z4v(H}֪-à+ zcoUuMICqe3N@}(b9TC/x"Gm&TǦ+Rb]sl[s.g Vf}fʨVwf~rj߉^XbqƊ\uB4hNZҾ| Gx8j|s,9׿;.-N뎇nj>Yrɼ ^ȉ׮>v2QvU?ٚ vitO8xp1FMO NPc_TqN䱟ι/r{6^.FWי)Jx2H$p4&3\{g.OUT$Ƌ~NS~%@}= a!P/1%yF>\) 3A` Ut FbN.0z;lZuWKzBL$ _'o*<2  z{˶ 9G@ޮX[Vmq3;Q.Çf~n7F} :*` AA`9_{zjF wfw(?nřq?ߏ+}kWS!#lpӻVuo #ZAg4JۓR?o;_XZpcoqe@.N:p{4Ӷ}[ oi߰x=^1p~ G.xѨUPj68bz# m^vg;ϐhS]ϓlBAǁ2J2Nm^{^Cs׽74,cU;¾i Dp$gsLo݇<{bQspRooNVMAeƱ!IF;!P^G@Yk뼟kζ>b'oj$yef>ˡćNUQmԼQ9@/lf+T 7$n;;49.w{5 tN['> #({zP0רAd<>kps=t֩Tf,oxuZ]vV% q:hސ֮5?_sH;Vfzy\kUQQy|Mg _*_3999J>Q!s3qZ&.%o}&(s|rN!aӤw[W<^+/jNWLMFk 56yMW>Ee%ӄ0_7ahz)6iY"_ 5raiO|`o*Zzr=,kye Cs;_4t)/GG}^ß {z׃8X!ax^y zkv~{  v9lH{߅Ak{-Ї_VN7$RؓOwDhEtY#k,^Gz M?: Oe^?W^G]797 󼯪8࿽qwa9ˮYS&yG%;;r=J<`]*o~{e9S;Au&|>Wvշz`yv?Bƾx`Jx]>6Lb21:پTxMK/1yhEùBˍEϳw5M3}=D*5`̙J92zDS8`G$vaq_O[bs ]&ߴjo<$ P9nxgmZUozR|^e;Os,ꦭ<>c??2:&Sb_vg2,9D={l y *PK\YO{X24=5MYYR%<|WgXB x}]=~?SF@b|&fVkg˓Ŋeaq DGwG7*r<@XH$:&^m>]Rh$xgJ'he|0)k 3usK:g?>i2ٳU)x]~Y%W)Rn=v&{hjjfqp瞭6F4֟Cxzܧ;yUdd].v`(.Q鲦ˠ'5E!צ;5``?kvoλ3#jfCߟUw`Vk:W&@3#G ҥN60?oLNMf| qq/#{wfѿVhI%nbF5/H$oKҞ:Rsjs?eKZe8o82HŞ( ~i,N1Hy N#c/_s1ų3[Y/Ոγٹ5k@3GlZ`onwmHӟu_~$As ?{qdmc|o;Τ@fIKyvvvSby~Ҭئ3[B}f`\S`muQ*`2Vpƾ ]r/wէ#Cv^'bu. Es/ 8At8Tk2ر2_^ڴ\o@;Sռit(r'4p@ (^>cI[XcTUU=QdgXvf{C(n;j]IZ8w6lπja:  p^85ަ,{?E.=ɋsK\Or sl,mk\]Lm޵` }ccޤc-s\PQ[XQ/݂F oܜ}IULA]Ey: |q$^y̏~Ndjj G.=Bq6sJ7O֖N&.Fik<'V]+b"y5L&vJ,*\lQ6>e, ;-OsWE.(EږQ}ǚת.n 1-Yhh(Y}ŚyO ַ~4YqKᆘ y.'sTWWQ 7?HVx#tp; HOvvonV~0h 9IJ?~.-%T&=~Uj\ԙˈɭ?:Y>!,jL' -F!rTʐ}oNj5zrl_m\AgW|vt'"v4 zC lvᡗ˕ JRHL LcA3y$ 0P: mm),|iwexⱘ_Ugֱ2} 6dO`<'jU;_~zI༺ {7gF~_/h|bS7dž ʣP0o 0>v0b$I']nu=O򪦤 ]OǫϚxg';bk@VupU]Flˈo767޹]0%yOoAW]VKY& SXjҖzU8C΃yQ~xrl9ډr۔H+AN,Ԛn2ZlzSF>UW+NfR B~GDF6QE_Q7Ù@313::sV1\9Q#s&&j y6eR6jSWqרj^9>z6o,A2iM!7&qǫ( M:`K؉jfŪ{ 3I|#9 rZd {?V蘿DTFLBRwyP !Ϧj o__OS# cUg4xz /(7b:,bŽ *p b=y " ä0 lZmr43$g J!gNͬu C1_opai_2Ӏ,7sJ2Xe*Vmd n!GDxN`CDHqCCSxݛy(yA,MHݩmէAfN;?v!Lzodɑ Vv]s2X̉Cƭ$`/ڢ,kfm-23lHl5 8b𢡄y.ߦMY,4BűQ0YwI„`m$ ڇX˭ \ E@$ N Hl&aCˡgG`_%'RLl#A"Gu?9 kJGXfZ΂QtLj ~$ -: .||p%vY]S4bn@R|4k ai[/~u s!\=!B\  |nFk9zJIO/.aʵmq1$UX %x 57;˅e΍ zl"W _s h"j=$Z , $*K,.bN6b 2O7JRᰥ~BKޠ= YƙQ6pxtgeܶjcLp+2w*uz]^i Fc]mلYUp KK__Nb7ƣPj$e"~A]>PgR8J8ۧ6D04!EO<7?Zzڻ%ʔ2F?s*kŌ*}ʿ51̢<GHƍ Œ_gJ`!JRuou6'}=le=]FK"nMKO \>y eY3󃕃v?MJcJ{}R9ļ'qXnyx;[iblM*a'#oK$e%F= oMQA@Lv/ؒRʝ#O B TkmK!nB,! R^'ݢe eh #f$p2l-kQ#s LVsAA *WԜ(V9YZa/IӃGI~o2cqkkΒ&HYf\1!dK" Y777k߼YL ytu]] `:;4I3Ն0 (g<8,f`'x?n}nF(d҄9y g:-=$Y%m[f93 rE7]X#K8'F1ҫGX7S@x9Q`GLt8<}x_O=G?!*E*)0ά.-&} & {c+3;Z*P]gt(3o ,uR*Gx溛qF Q8z4,urn~DHsH ;3fm^+^;}$SWˉm%yu$}G{S@޵c]jZUlK}~o_]{Ll,DfWH8-opTc'0v a@Pb~ٮ*r J X16o0Q/r ) aR~&I<?`/[zP`H0q<ǰ聇5%Tkl**Y86oKV {2`",Iq#^f,F4.C}GpA^"T%%% w_ 0%zW r'K$v6d ^1R =UVgy_LTSHE@XSX/Tr|vڗi:.60ɿfQp?D>!+롖1ܧO D[,^.]nVq5BZ8Gl-[< I)I",I!ARu ,򌪄g'QZxmR=Je$[Mx(S4۝H:bھ%.n\nR#΍|c}i}3gc}|lF/` o жL%i#`" $p=W:77Sk4jo.ܻ?K76ns.O԰JLFj/<&kjbk;&I℗ݾ"8FT^cp՚5jz8P!G\K 0{SD-c뛎l $lXXXwAu 1XŲa*at@,SivK )PB O _ )%YLo=r,N%RgfJ$6YTVpxu ۷sb:$f@*b53d̃vDc4j_Z<>jpy 1o#|ۣ03Fۆ=*i~:cÃDfu祐?ێ:jP{.4%f;~URk}𶴵UQISoE0Wsؐ`Xԍ hқ մְ\gѶɓ^q/=x<.7ǾVrPe_Թl_wa{n? 0ѕ n8T O'*P8LOr)-`ސALV).S,\$f*m=_ËY9w{_B MS>Et|BMWG""H>ovXo=#6AyZ?۪eaE4#hZ^/q\X.6&u\uUBw(C\TbQC&0ck2컰_[ѿfXlQ__#yËC+-?6uyqAAbD}(-g 6GgMٓٻ׷DhĄ*HfocHspC`wTOAmx3R>Aݡj0) ^icbĩCht*&L M%,n39Ȟl$F>B:PNUjfjsx=ak>yہaF$Z!]\˅D"ԴX4:(g/G^b =J#u~iWءgLS})M{YU)͠, ZswG(7m1煽Z7}>ƌOWtf o{Ԉbӊf R܌J!$ [N&L7hn%TZd|+G<2D!IP|.,b% uj_ KpY!qv% HfIQA(KKYb͸iF|HW8`lPYSA+:ֶ!I\Ro/~)"c$' .LMd!Md3.xhLh01gJq0 1 ]Xmt{ɠ3l7O|arB/{ּQ2=Ͽr[Mg~IFܲGX6fJY}s/#RB\ dM2U߂U=MuPS#G W [N`(^9 o_H;,%Ssw@ˉ* Kd@'"ZeY B(5˵@ h S== ;/+d +pȑ[OVmo 1m*(Ezp@t:¨ I&́E`֥d@ acl+Fn^@yk~# m1 )P~054 n)5ى`knx 8q{*cھwT?d>q S]:*$R>4`(ޟ?i* \3!f|{Er11j4dJG J2 }F4HB5O!WBZR) V}0~pCueB鴓Mn iD)k({ŧ0Zad4xBՉv!ETٌFi(y+Y7[637s_J Mq|*6 9sH+">3 o-k}lWryRS`_*}mJD4/7m2] >n("1hɎs>ZEtA~d˜$Ǻv29́* ]dP/-fAlmV +Z`4>pE?P\N$1,ο$o:vbF)2ѥ057D!+e&ЉYfD e6'W-O?xIRI0"Yf7c O;d[CdFP%CF"dDHn|헛 1-yɅmOUd( ✿ r4Q12}Z.c:T!SR⃵XL::cP}?(G]'EBRM^*ێ֪8F^ ؛=ݦ믜+]Uo-6xnS[&^Eof<ü4Ceu &OF+k+(̜i|U^zD gDUJLFs է\yq}a~jCuj-BZi'{DXkl H!*>EZvLOBQt*Wxu:[*6bS%9ߺ3Vh`tܢF̊f/XRNU؍gk3%dZ M:Io7VW8fڂm|*~9tެ4֊[V hX`oS[(KgӋ6ŔGw JO^PJvd7,P@bߦ0%leOW)Woey^( 8^ >[)* ?wty?-ƭ}f D(Lcv+s듩ޑw_;`Sb*nN›7 zD? edBj#㉌o-C& U'JQ uWUw<}aZAYm-ue5\ƅZSܙ=P#p*e/Gr#=Tn(O$_jx4PcySg uH $ X# eկ`}Wl;,-Tڊd$@i6ok>ܘsCj =H*M`M G[1\~;n\~T_Wd=M Ȭ`"OQEA7F6@3@ , -sF$pWbBdž4Rgt+|P GgD)#* $lg-R*0"+pMm* J.6!"[zq? r.Z"gMh$HsFJ ,+Do%2re;#}r/,Gb;ZpK/sQWuDoM{!ef2Uk(]\{JY&$zg<a+GYM2|IR@RfV6?ۆ>sʍP 2,A=I9Oa"g=Է`12 W}_)$՞^tj&9l}PJDtHVJyƪ …Kh[ B 15VJ̡DJs>bIҁƇ~CT;h/+;;i[Z!551Ѻ(d)(JAe[Y6"̜rUMzo*I@4lRS˗D( MUyQX@t#6WĀd{ΙU6C)8WSq{T,ˈͣt}Xxx*LhH}vYػ =[ ЋncGOlD RY*X-<5!s p'"dc`h]d{:Rѕ~ݨ7ՃKh`ӁSIҒe߀%/Ͷz68>*TX4M|Bћ諭x˙#7jH +Y7}t*r cxws ZG'x%izAcu&Xr(^]!ȈGq U}S@w%=Z:P6[@%2n PG;j3Leٽی Ww>^-C}9MPAthG }Y =x ~6X<_eM#lt4EbցDdq!4Jk!oPS3ݔ$EvQH!| f2b/%~H'l\-]xH6gボ}?T@|UD]e:<.qTMjtou+$7;be~"DF [uID{^SKG6oJ lj|#"P*ҙ:pأ%Pu $ECm"LGK$}Bʳ7㷖MXlX4I=Q]@"eY CĠ"z/i)X5_P}'׈̪jppxۂ6]oǞ:\s^ntIY =T WP(9Z,Kpom}?bJ8dF  n|Ȣ !+` .E&h[06rʻW{ yoQA. (OVcwjYFC9T܇^%ZW&uKwd &3(#$X&YXg=PT$(MS2CZ8IK4i!woXW% AOM8 )E b(D,q:džSFeewǤPڂj V!rtCL-EԚqJe w˓>(z7E5wv*=&joRaW!b ?ߐtQ4Q\YڐqYuǎmY &oȋj;TGgRt\\lS Zm"KMsC:Ebxx}V{fv|ٯ19jph:\x0ۓqQBHF8BԳ%ĔZ&\`߷ o[Doׁq G|jƏ. Db?d%Ro檶1D#Pt;(璊z\ E`A> hYx$+X#x0o{$ɖ*gF>.p;%z_"}w|e JQhn2?)e1YͶ[u#wwd!iXdx`DB1$$MۘAGDc}a^@E,{r.^'5x^\AS#f1]u1B7Zo}ϗ+5\{r>+l!FSTmzJ 5*moH+<220a 3)_~\6{&CvKݧm#(,> e{:?'ZzUE ٜ Q׿N}|5;iֵ?%eq0g\8OYLWWO9:=5,D>?!cEt$/ sa1-WD83Ï*s'Z'ʁDgaE:(|?,v۝MZ}tFc&au0/cv ? ]}dڝJaQF7=fQ{;>\a 8x^Yhk8Po kP(`k,Q"At}dٓ,۽'BX`ȔHD,R#&J5㔮)=7R&˘Y<"TE"hi*\ezꆽgH;ch65`;de I}pF{-tRuEfkak#lu c5NJʳ͊fd!7Nv]Ig2xq)Hih^!x4Sܙ{V\^0g㜽5#Ø"cqsFew8 °e}8JJ/ܦ?#/ J NXJAa((Cjb8ºߜuyF,<_!RZf&>'Iͷgy/. gN?Xz<`e.O}F3n+*1sIY!> l?^_![rz_#hm٠egrZ~24P0e7_WNiѱ,?.T^R#c.|/W\銹C u[SY U2fF *XC6dZk QdG!]$8:S1=R頢EuRkS}X8IBoHըETzIaAK zg o8O; PBdk2j5XoeglIXy,$R(Bb0Zmz'=qClHMC$T%3:xZF"qGak*Ї"͐(4,w J!YfSCHr)a\N)CaZ㋋Av:k'%LVSa٥XO.&UhI ؿ\BsWH͗z4yNi$ 5sȕ׫Q3Q[k/:cܬBMAA.QOҋ*sV`DS>M^ˍ:fDP^ӺfxяG£^AH+`?A8 ~֯/3'xZȲ\d:`Od7]+ԡ͘c &ooByv5Az!Y'trd6=5ea˝=~aDĜg $a^i&=0 #.o޵d}dz,OkGFeս;,*܇眔bM>|~\Eo ~ic "m2\,!rԻ}BD9 6&1󘦽G34prqKq s{?K'A2^rS Â+Rk]iTύ<"O -ԥi=y&p\#B fVVe!roE48kro/]L|d zl iA+hyAkޒX½Mg|^˽U+;[oa)HұB+nl;pJZ2ygp_P, C|7{ ]"Z Tkny[L-~]+ n.>&[6,ֳ{',c)=[vSXyGVe#KIM9LgxD3琞3Bk ?١?M2ɡ7Ē5ʏ7ep*,|cG9 G,)7!og0c஦2pETYJyҁ AXx-6#ԎI1%|x;8ʌ[*.BRD(4w9eX,,&,k25Z#TEcP7Tiy|z5 wtB I3TI2+\2]%lٰZ!t9\kHMh0`~S3M_m\wN*qka+'+&.3sW0s<|ol#l }<y=k{uޯ"X"&e#:mmF\2QoO z#5Nk _%&lTOQ1yT :)$2 V* J T\0O^a/ HM]YZ|)+mg/ ?AZV0οgYZ)N7>Kb* ~V?~Fp'(䭄\&~4[έF~[+h>pU ejYǩ{8|kXp<[3zG *x[tO7S=t<ީg o?j[RfG#gm}Lօ:%7ogQOgk#a̽^W:>㭧,|wzCҨlJ'wP@fv_tIVW|0C_pjdG~\9$V32+,喪K`-1ʳ\/jO!D<$M-!'9z>$ܽua/,(lx1 Qbl74%Cɹ12L;,/Ɍ4t#LAaDt_Q0Q@xM")!aR!ٽOO\4a߂9&Dgo^e#9%*RCåF3%#x1ٵXBSD[S&;Fei HnHr53Pd­Vkg1śTDNd~O ii[2+D3nQ\ Z g0FeE .KD2;kP4T)XkQϰv$O4İE;`V/bVσyԶZ}UNqq]$:7J.U\0uLcdf G-{2)M0ҏfninggvBM JFV6#6=[t$4TO3Sb}|`YT>z,q"|'||jE=(%y(TA=k߉վ}ҍrڻXT;j>RШCC\2HQ׭һ8'x:hߺ0144Tn:pxР!+Adа'9ΐQT(o8fUeUײ݂.2í?jrx\+.?ީs} ?i-?O8D.?wT,NxbhPRQ82XChmSzYA ]1`)'#‹]ۃA;m'MX@y-Ӯ1,| GŔ1ZOld24u VYz*9L~y~Z}~px>8"q/6G&<Q\xo+YsxF}d+/&qJbf:@>P4 ;/Y-dw(fof#bа{U$9atŎ]nģSZAK8o,g3K$Oz!mtsKXNl*g;d,LLD6Ꮶ95;ZQbNl'^M1\=7E6 &}-ѧ4YTh}ޑ jvnur'Τibxx 0DF9p_L}`U\BR%Zٴ"4uLc@Py8,}FTwQ >kq0RQ%^:~mp2)Ob>yTb]a.|nf=r͛Zh!-/ Fx7I0uBƢ@, uXZֈ*] sHUxCTiQHUaԏvBLT$aR1GŠ'#Q_' C)dmmK?=rLdB԰~VKb$tF2>{V"xC P-;?F+g*+2PqlYa ` !fܞNf5m`M((d&XԪc;0|}Ẹ>X.1rՎ0M1NOdeem~Mc KΣ7X &ڮO}NU)<} nQsl2U Po0c8h gyáy$\ /=)nZ x:L ]ﰱk@M\: ?3hk|qeg溸ft O~ -['OtpZ X" ɔ^(3[,#%H3drfANtQwS9M&8S.OP䋥el-^Cdg):۔;%+a bp+B)k/X^?3H _+kw. $ڳa~I㟔 \OOcE4"P(;ׯOoׄo}p[}L=* >I趝mN EXFOd]9.7V &e ӵȍ-jf>NF~RfoL<N1^6$cZ|Il,[qQbIL\]4Tk/#'''oq6iVo)Cۿv7f Q3VWzj,$ ;)1פ< hW| r t<9XމrNM ?RK8xNơMnm>;'*-Kl c_H, ,S7>ٌw@9 tcN `[A 0(밅hIiw;?lBuv4-Y z>;  &"$3K~p>sz@UpK8M~|-i+ HvCg9;$*#D_NJ*,)Ys /M=Axc<⌅YN|<\ S DN d y2Ƶ#{p:^-f!MeYm_*B$+SgDNv eVCܞ\1N{[*!F P&&R5 (|mr#J !Ka0 ϝ7@-Qvz lYЙ1S:.a1Sw &CDFKVWrNTڞMt+C[A*Us֖8y[*4j6%:*Cg p4os)P)c; ,/8|^ƺ+wfq VR@NOq;Cݟ'OÂ#]^RKջ?q{HMlc _x fBd2qmiݰ@嚈vPzvv!۽ J)cK\>?1E;-aaȮ* gdifa1Qvxf]#NwO <;;]9~~(sAT,T\!ԫ[D Z`ډzy}δ>7OMr}A`:%3It#? &|0bk)\ i'$1In@vNeGM&?6d@,[4.Y$?Owԣ+y:SdJ׻ ;@c/WI^ya̕>'&qNy$˷]&xRc5-z9!48& ~ϵ6 j.9E3 p$jBԦ9}S'{rsq ḷ \\гN70+$+1b(pi|4'!lOwqA3/,^^ $OsUi "=F $i `<4nHc?:etw^]kjbo]ף 9*Vu LY9^çgfX8&"W|)ڶIN%]Svur[Lhj(|P :E2)]K Ȱ#ٙ>4[WWL#hD*/k#JMRRԔr=GrhE{}_uV8R*uiVOlV3yx(B%d nl͖EKBR(>@L д4lwl$D&.8Ln)U\WJILm,QNC^,aW;N]#7DÔ-H{4 ~GfI6'lO螵vHoV ̳E˻[ K7d6mϾVka$f&&ؾIh^=)̮;C Z`,n?gp^`m ^i5l3OkKkp6$p촒TXa{-;TI۠cX=oxĄrU)C*ܯ6 1dDi0Ҳ}ݧ׹߮2ӲH' >E2],9zCKC/_+ش&*N z کjÀeΞ8R̝J"p_lI)f?BSuy6 < -l[v)CB?H>O8(ШZWH8[2KE[7j!"?ϐ@ˇL]m\sOMo딕_)PS6U.tCk's@cY=kY&X0"~ErdwwlcF<ˆ"d'M#_)OvFK:`= .Y"Z%9 IkznEjVO]uĨڙ$ kBA o%)fxbJ~@+C=BrAǠnL" KȽ0v`^%kzET' ︢J䤡2AE֖.J`{pT6s%{ToU6T–f#2ZYU-p&+c [.Qs|&6VU)"Q3c4+iqqP߿p '| T!Yy 1\d2|Ӝc rs>t ͑t| h-CaF+iݦyVPm&Hjl8ZpU?S77xN(b"J~+8IjDCj Zܓx}DH wMڠt4U_W c&zMeB*ΐzxfh,*&~ki4DA*LUGPxkUEskyvy8;dyB츼5&E+ٙGo2`ԭրzl y!M)IKBq/8Zܮ[~z5'(ЈXϥ F$Ŷ uwk\,t %e ^*?d9x̍4˜`_]GPUgQ8S#,jEp N2Y pQ_U-&H؝Nhﭗ墏Wd銄{>0u$&Bg-;x01|Azqzy$\ X!O/pRm#cPJT*#gkv :9Plw֙/>"vzVns >wS:3HmaR$*샂 UϤJbrkocYYFwYq%AO#_O][~ po:NXNNH/X8xF] eg1aaJ(UMJc};;DnMY4X asNߵsch :eUM]&s0^a$HŻh>Q״0'[-i녕}OU4i-Yk:)-ˬ=\ bVPE Z~0Aye ;`aan065z =nQR3jiNU.yڱpp 'z˄n`4;s DdܩT7[r0Lɣ6G|A!CF)"+%;P4I-&qs OH,{zC>wHd`QL/vr7z6BG* :\/~*hޛAsqr8~Q|O[:eouRU04 q&q[x@;mi"C~hx/5L1N @5yUf~#燃_k#tw ۂ#a`ұr}oV%+a  Ce,"x w'xƪ&2Fθ>PQ_sGن SAr@ڛT)uϓ&GgЛ Yo1{qkc2GF 'ak{c9"2!gZҌo k(gb}|SJs-zF]1k%uf8OZX.-l3@ݖa!oL) &HjE8WD26J(b3G5$>&'9sVH$Q\F1N7ڎGdqc,Vq4\({ǭ7g)?7lzr;S k&Cmڮ t=C 9uHx>c- {g\Mc%U?=~PtYx K\m j!:7mn53mwˎe8'ߥŞ8yF](|+c<tػ-Tlv /L.}@0'Tڭ\dq8u>'АRUȕGaz&!Oo*3Bn/;t80덛Rn T|V턗)\AMN[Y!L*]0J!Xgz<=;Y7|[;LxVz۾XymQ7v&:yo|g,.8?JPftRʚ\&H#ԁI<(ioG5CCԹ36d2v RBVi5\_N,TяljCІIO)㑊?kǓd)QoJ9 2!-EJk]w#nʧ64ҥf+)"Fe՚l2MBB&HĩSKdCׂ]{­Q, 3 [tp3M$|œvrYEB-$&W=gcn3Ay=E6+x U}t;J9n 7>[~󼎅3vMd j}~D”mڎϏlr6:J0u>"Pu6VI,sF3°c}֦!߫brєM׏d"UY%Ks:l+%\R0 9גq¢hM Hl;0_#j3UQ{M+tn}Vi{)L;"&dg6qd#LiTY霫JRvA7>Nh;&EB,mj+ݘ*E\B 49h{yp=XDS N\=A:#]8 #M>T \щL^GXH*{1)s^C Ө̩PAu4(*+Dǎ5`L!Aܝ1Um>IZQ9/x0]'_8QR4Φ-'x焅!xr^C_&Q[{BUs;]dxkrR` 76k~ɢ%E2oU1mJ)C^۔|D⧜ɽ7眍Z!,4gudzD"%e(3wMm e:3 ~x,*逼~}:BcEkVH !irB=`Q*\l(r$p!#b ZG]}4<0PLNE'؊V1}^ uۑp(,8ԲKC0=  :Y|ޡKgd *aP~rHLȐ`y6[C#C[=N-T|%?ntHzqRHkߩDQEϬ#h[}XO2,ASZMXt.YsM h۴d>N,=|<93qe}pybw\$  &ٌ#blly3d#@J!E jL d/ÿGۦ̮" < J-IGUOHFx혞vd&Sgk,i%<o?96)Eŀ.#1+}#"dO b۹<1K%jaJR Jϰ3FaJc7,Z2~sW$'@Sjlwo0{c7ǡcn]yxh\ {u{#W< TR1;5l'; 48Z0(Qc :d!ZSO3V:,):(bڻ|(YRa/1} !zwGn|ߑnb@Q3WfM!pc'1~HIB͠}߁ uJIS40LG&+/CN/&mn5ܩ LN`c6fec“(̅V/$ӿ.CNjAjcZ;jj;ٜ8*7w=5T:yI7^'jک;X.,5)p\ړR}\C9oȓJI`DAXM8|X/}$+82){EqE<]u ^V1ɓabYa;*n%á2g,eeJOԞg,};@2!ڝ:& IRt_TJw!;_ D"4 -PTcYTXMG(hD6jq>ynrz?*%<5]uwk|Ι#B!7z`mClM>UH ':&O۲ 1%b~3_]jտe,;oӶ+0C$ϬɾHly6CH$lZ ~jÔ"J <N6. LLե[{oL;}IƆpt }‘!(,wl!jR"diy8l )+sW|gEӑufB4%2c,Ռ*_wvq^FI, &/2G&N'ZI,՗ȗ}Dbݑ \5 t_*seFw&"e &5o⤆%&C >Ui6YR/7k ˄M+JDL6[vMVDKĽs{3Q[r'3Չ-TaXyA^%2 Ps o:?t8H:ЊevpAJΔa=f0aG nwYM$/Ӆ]DGF;nmJuD622c ߶֔58Q\v:)XMU0d ֗QZZq]L>cj*==h0&wVl6$_% WNg/2?ߏrbA>lcETЙ#ßїSg/ ?t82d]T xO;G&Y.{,G:(%/We UINeWp_y.Vlӑ,x]E?ZZŏ[`l;i^5l&yΞ S; bK\B̭r%b-Ekۚ˷~f4snӢƥ o"E}g{rN} aG13DJx!ٟ×-aGSu%Jϛو3Y}trŝ"3 8ls'(/ŷ5UOffޟ/Dj[ow "{3Lbjs"e`LL-=!ϝu3Uld=#ͩ+v502#ۺnt) C2­ ِK Z nM3h=Ob~t:j}Ղ%;bT:[#. ؜V b uUiB5< AA9p=]p|nvɷ} Ɲ\,DZ-\eC]籰iO>cŦRz6k4 ~f'zJʜЊ\ ! d S?.-i/{֒(ےs-6ڪ:YL/\Ruۖdk7i}Q(U3\G XQe M֫ʰhY$$3GtΣ_Z+înZ1noi~>hX&u]vR|sqgILbǬKL\X(]Z13_6ew|86WJ÷ 77He[)/8 :^8᫧'r[KtTe"GQE]Eb%PJ]am9Q"&#mMs &c1/r)Kg`eD-͘n]+(؈ՔGW *Pr g0SY~7;=WtM[h<98SDٷde ی~&JmGp~K|ycաAn jgGj;.I[V_ګhQKM|c{/'~P#bkIvU2Yw*i5nh0BONNZuP2͆mv:>F^3d֊!KpP0p(S KouoփD墼vPFn0e}٪"bCׄ(%վԒw/0ё.jfRYJ+3 ?- K煄.XUզlQTX>;bsgΰg5_㸛? g8:UH#R2eO y L(U#^/bfC%D\v~oDZ&SkuwǺk5Q/5Ds11Lhsʓ)ą$cy9[5s[kcvhN75X4G ֖.Qfb^Z߲?;~K0/8rfUTMPu1dT*.lP0{]~dr sSc*gp\i{'fSU$9@T0K#f-n^d4Zw+/G$ǭY`7Ppi6LK[L/Nr%K,w|F~ր)}`Ipv2$0[\՞~؛N\m՞\̡ZV?ޚb dչ&f~M%4>Bo~pqPn|=!Jq)L1CJHIzr|rzϲR8YZo bcxjATĉqh3;fKF=L؁ƕcgSqݷo?("ۖ] ;jćWjfh4)0|i6:ԩE$G`4BnV 12AGy"iZeiռROkbȨ͹"?@G ~+#z2O!Ho>tVl-\9Nj|G ×RȣS:CB*I*_{ j`75+9\[xsVv:81jA4%Hm<l*ںt0!D 9jo (l`d`8jLRΡKKFcG,mРdq.L6o[ v-;(U5/ io%}(hA$bh`i+4/+ Gn!1xng6n¥jsI1~Ѯo:Ua|N NEɢ:'sW"5p4u/v-K?a@@3b1ȧct?O~!\yK1;@q/>d` ṭYnH-vUga hȜZܟ̝G "C."(p` Z8F`*@sv t">7_AgM] ~|c;tmb T{:(J$à J׾]@CNRzcQ{߼;聶otڝ25Y ص{4wߵ^T8<PBZ$;]UwYT~Ś8y9"!.pf(8#4V 9A*@SaEAj A ɵJ}^{_~ sy&F0=/>61-( .aJJL O-,N9C(cCj7ytȅN1dDpwD|wea7r|&)' 9.Z =?"SIptM5ԶQQ`G5^*6V"dJèK ΀]]7{l}Qh"]ocТWoYc;ѐz̄J#@vw͞@^ǭ S;Il!8C`joKNniaq[Svh 顝Smfl2JxuQGa.쟿OKA+#g-ݶc sږٟFE>}tX=R|W=5e(y" "4d2[?.J?8o}(/[!30&cS- vA8My) |ffI<0mF = .0 Q3s[o7z~|Q> Wȉ8ܕ՞z>N hԑm=QuH\Ghv=ǎzh{nmTS㺄ᮄ% V;CUi!2gWgJ]Մ1yE;] ĎG>M7I?zz 0OD'F:=b _ŻX K!ȢNj3te"W>نm f [OηGr`}`򓵽! _gi歱m%OW_D@IAwߓݖqWO:~x}r{}+ܼ(i^(-WDTz90Sa#33GBh FEFeH 1Gv Y +ÏPozXQ92ҕ~1p剡ʓczvPz@ݭ)&s_}xwy:9EET3}ޟ>?W.S]సGQv$ٜ0b I,uj|W 9L'-j$ŻswDT.J+~t<~J Pb$ .MdM Oˑ9,qyk5^On=]FOJ!'m'Ľ Mn7E $ TD'g*4^j}nOS?M3ǂ a|5Dׅ 6 G\|1.EE#fc޻{!OYzx7鷔,Oܜwƛ Mz~^~'ۉQ!%/MX.w-p2jeh NGϩnN!lEp]KjKo4DTkm? ,Naݠ#NWSǭbnsh}4S|_:v?|ի5{}\v!Y?5cޓJX{ -xaϥ~{rvCc@_~`2t} ꜖Voؘ ZHB_;&Fńk;&&,hzH>2 ż*2v}O'l{>8 a>$yz֓0'zH|(83ϋ;\i߮ CE-i{>7жM d{F۵DeZo*>'4iܑ\7P70(㘂ՙL5S2i%f,wdpXs5wUX4ϣouuZƠ)z4gFo1]ZАK9'&-:N0/w!Ay22}zJބ7KniqTymiwt$Jy!4; RD>) xlG| _q]rZuct<KSV ] fK:1/X-ޔR^֔"cz22z-HUW&y8aryf;b7\8u[`9)P6=Ԇ0?kҥfx~rf>bO֛\q$3 ކkmz5?ȚvW,VhN3r%ߎ & /L希uIN`hG1eB<ǥUyUN[koD\Z-ldE2)LU3w tސVDlG!Tm7`hH+!gO-=,3^ n{ksˀI>afB[)?*MdߋN9lFC@IOjz`2f2mюN}{Ohccgtt2 F呋 !!Trk+YN-jA,y1׬_G݆@) =r6~v@f[~zWjm2c0$cPoGďW~,_5P+LyeZ xC j};JjP͙YZ'zG^{c'zTPEXs`9IQ LB <"8kcBÁpKT.Rthp -ë8r{ ѥ04΁Apee.R6߽L1(-KtwlGjj@6 x2tӕrDTӑBjY[痻gX"yySlaDރ}m e>*ӣ&G{@XmٴŪ L'CGŢI$1WA0<_2LY/ALr yƉhCė"y;fn+6Elf~4$uH3]qRs;jz~Z2gvY[cFA3fr hōШ"5[%t vݳ}_xs~Z%$iƕ_Bڶ\< 4ߓ6!(*=!8>Pɝ-/5{Q%|W<0..{^^$LxZ{vD<Ǧ`Y4r"b7BKm`JsKVm<~^AT[[Xn?'òJ)d]DCC gdܒHNPA0M:ћezc.uL|oqtKsMf.P '%b.W 5V@^frR$&t{5{ݡty3<tyly-^Yrxȴ <: $ի밺y6z*o#z՟ǚS`ybwa9 Dj2yFQ?ݟv˽/gГ6rRx j:kL5>ma-A敳Z Xȿ8o<70X 0jgi'nMR=m!` ,@HpEiA[Q2Y<bH`hluUM7ՀN`c G1It6V*e5D+]s/_35WEصT^75¬~́ ߒ= I_ lJpݟVsxZ0Pn$3hf"3ۢ pT@|+ [;`)psIZL],EL ]JJpX(g6*VX" ƇU];.Iu | #_Zǯ4Cy@LBB@$);A:*1B^DQ(rL  '!ۡ UN%C1/(3Kf1Xނ_o@Xe9]ǐdFQ̱) ֍1B(ꫦ_v ;梈!DKc+9i@ΦcZTm0uߛڮ7}޼ 5@` 'XT+ C(P+OO۾űȠFx]7zUߥ\+7y"i %Bwrfh,xNE6t-ky4D¨ܙK!-:4 L];7ܝk?JKDFձm/ѽ v+Fu /L_LSk.[c"0x8 +'Rm;AzXFMcD*)/%YN L$(8wj5b5{mݜkLq݁۵RD[G&f2|ؚ!K_&jS.v[:5vK<>JLpUK[+S.^M&G,ןާ]Xo@y;NHSrY M~UIʵa5RހQш2;5D <:X;WI8àQDsC \f.(,2MGA]cO+id@6?*B(e{RNH ~V"N(,sFUMx F6nMJ2HLB\]L@ YX4;T{9XޚЏ\o'Irt"sHB$\9Yل6}2h[eF"Ο`09t-"* ސp;QfJT j{x5k+_i06Zi!Hk#*Ƞ P5Lm\pG%o~C`>ҠFwRIn*>0-~q4-5NYH$9nkg>% 3CS]])ڃE:-gFnfbV /4psCvF(p& {"7CVy0WچWirۜد~4"RӔ!IMa'TC6'k_ )|(RA$|.aS [Sx HR.ErW<׀;p4&==yo}(E!Yi2P]<j6"kIT7ݏ%q [>K>KYįxI=\N}ie{8hf1Wc9){vfͩ'Ώ?kxN 9i3KXȄF5JY䷗&*+`Odۗ(T~ߏێ-u;q5r fٮ0,^LQ5:`SGfkr-)"xb8OFico?cE,mz`xj3@mILd[< HIb:P[ODsڣK.“w甿s=$jn@"2 2|``sM68uak0:VHts &@7h]UX E(o'߱yi4p - C,<;!T>S!A)<$p~RF9KFc:t%,} _BY-JX-i͑ˡЩP͈E.(sA7$fKŘ]FlX$YVGtXb*^*@} JMt1={G".π"t`oi6o]l'&"^Xm)݇E*O7Int=ÕVjk6~vfbf҄ð^.t/ou~J₩ D,7xc&p#}\ZS״ѣ|}Hg]-",5de($'+gB5os)lgwrѲlh2[kߛi΂2(l]acJ'd '?>˦ªH RZ7bXK _{Bwp qv]߻_Lsn=~כqF jl2|>OmӿXq{GqmuloWI94Y7] B>MuMU;Q\~^s#p H;j\?GSv[H񤗦/X"@ۜ-?Yt5a|s惶/9L,('_U"l];q ;!bg O/-`z;WzOgRѰyOr~\-LC?5t]#4˺?sUb}k5/&vOkYK^f5TTP=- {44P|U(3Au:!Y\NgWYMV*prҾΐ 0< @0//O8Ob ӽ>;Lh P{yEUѯ}]N*՟':0uWdlyřv Yw^k !+tM_|꫌S<_t>MF2Kutej=1擋])Bk_}7eJdMhz9q~Jq[]>㷧kӌm!AO,k,!OЕ;5B>WӯSWLb6ϱHف[> IOn˛Ob뗐H"WX$H,K_W}Ϳm 13"\Fz> 0J'-U1 ɱ^o(Y[aS+$TTTpR9f>z/Jڈ`uR^.χ Om̾bNulJ3k;apwKVIe̹q1E9Qo}j5k3b+p>tiDU%9%'1mssPDw}.[؊]=3ULacz 7ywF7~癵Uaj|"4 ǔK${rYRYyzy% Fn\H;%FtJ&ޜ]<h"ʪJ}e}<ס ~*ٮۇ g-?f o:r])1oU"?PKyKCt~scrshots/Administratiekeuze.pngUT vYvYux <|t%ml۶m۶&6&mN&mvfb;yɽ+j]; rPXP"J@!`?{TN? E~J@t@Gr;IʊoB"A(vHww⊦}U;ul"SeDE4~"5b芋j8( BBHCHfw2J㕬-%TgiGEEKI`I^K&Snxv=T9V;bix$~},GOJʢ/H}WW4 37bYW^ؽ,jzjsP Dnٶ "ő%|{sqyD9͉Ex]%Dn'A6e}X[!8}!5VRO=EPųCtAi8ZG[QڰQWpbf@=։}oPR*O|W9]]e1=9BkQFDgO촙 j^m4|Lܼ_>\DA`~*=kv)cKA7tMiRef񋔠%ɞ޼n2_ eTYG]4#xt Ns"MC5\*t=B.iF9Oo9zrIl0AwB?1e}*۶3dnqr\ko3\^]1Tт"zn3k&|Z(n+尶y=ޤ_7ͣzxr9(Qz86r;*\IʬƼP_or|9Kq5˻#wFdwأ @ dL3%)s✇9}tyt_go:b{e4|:]GSv<vTڡE/YԒN+tx>{o:w漯BvGip g]Kj+W:2c oc+5HO}fì51cbB /ܦ+|zo YNkD.hȩ'療*`gۗ+Lv(z^: RJ]ImOq:Gm0$m;-\UcZ*^',HeF.&~Xi j`?νE=wTr̦SWQ(/YV.>3dQVp&gm7sW=^*i_րқj0Q1ē,L ٵAh֫Gc̏{_gt*Cb{= aL\ s_ m¯²h8'ZBR=Y(&ۂTհ&c0FO̗1 cXxd 9Em[@ "G~X4.mӶVM/r}9md[?=P>Sy56e8iWGoMDX k4'>֮}ܸ7E @^Z>SNMsIBWn'^3ƌ H(wkz'(⥷|X*yLJef6%іѲoLFWekWT$v"Q j7Pjjan8@gǐ͚ida#e _q} du|{*F{ɕi'E>x>["ݗ^#ThD$G{4)jxe0v<+{"`dۈ"=Lr@<1avfΘt_vp8$K Ǯ <ʑ[CwRƎQ aF@3.m+,L?- ]{}R><ȶG7dv]#|:iI4mFFwrL8Rs]glĚjiPl2+xyL n@k}^q;%u;rÐ]mfݘMvrs7;)m6u ("?Үnʿ܃6 |e[FEjv~ukE=dMǬV_Դe;f7$yv$/fnxoٔbyRI AT26{?xygbHh;,.{\-h6cN^oXe4-f:MdsYp< b_ LXLun$#a߶d4$QX7I3nۤ)3DbL{adc]KAL6rݨF | DEȤwmG[n4,Z{7aolM7<z_-s^.]м=j\]}!P¿{B *TY y@jE2?w>t+Yik"^,Yz-09H-^n*4[Oob~džyen>9LL"~Psxhljjy͆N;:FY=°-nI~d^ѝdoOBl9fߙlZ9Ne}?7[k@VsFN?tdLgn NuX^3sh6ژ[8s@ <]k n\V_})k>+j+xY?_(9@kl6]/ T0z;5D`9X`-? B1*V~EF,a1s$(s #Y?>ApҿD^i (zArdǥr5-Y+`ihbiY$tC09# A) 4 >Luc ,O]F}Z ZzJ:d`oc\P>24c5q W8)JJX%aBu} g# T2pbŢ RbfE d!UCy vC_pH!vz>[6W|OP*tnL|<ێUpd96=xfY4Nz^~Bݼjtj;aeM!vҿ>uٙ_?]/ɦu@} a帛2|J͚Έ0 b c;1OQs`+fԯOJ lq$[SngL"DPkC,Y K8D@C2! eh4 TZ&G!<Q-oe)(%J)2ܺm~وbǸOT#82282 Xxq ZxDo D vxE0e@^)9"P5Ir&g?T@+}7 >;v!3zO} b%Huz!AvE&.c=p GH~yY⌼ =d3}9=,u^S{_f9@)K8{m{ == 7RY^·?PǖrU;dht:|/cΩ='+&7G5>MP4g2@s?NJϵgk7U-;޴*rѻo'9% }ifjQj^^,+")<-#ru=I>#ۡ㡂˭/`oyG8D!"Z 5Z,PpnlEj*⵶W7NՃf 0OfeZ#UUsоjceQaczzː͌a?!Q9\'Ye4d|,ِDVsu@53|/ + vBɰD+KcǴQH$B(bycnL4*J,],!lhFBSŎR7"MU *XAC.XMXLT EZ"籬NεvX\r "(Fh|J62x=,2nc\yэ6oX'\lA x]p(cn]Æ\מּ>A'ߙiHրj:v:]=]L=?9 ,9sHpr|E3ޓ]N޹/aC˛ !з$tzSQ4{|bՀ%qI_I*B$QR"<L3Wìj;ohԖ $+`R@:ɋHk8FQ{f9{+Q+"ϵL*Z"!0/Ft/oiձ?8IA,9ǘ|;Raj ȁZTۑiOOa|"I$qwEpy}׷{3!;f9Rϳ]X9qalͿRt#.Y11p<0]j=1SHBvGI A:Oi6W̟:~^!cjg"PzO.KͬA+7À-"0c @"Ū{$K9\Cr I%@:[)jF&"wv]3 q !LH)Q#|I8_,1”L쨡KqYX,)"_ )FF ]juy!t կ"UB#U)lEa&WSvr|%T"+{L.M܂:4}#}_䈨Ԃ@D .8d(&BڞAg']k7vA!zG?^?Dj2]!!̗uL΀ߛӢ"DcC-ȏ1}-Vςpi+{z #8'ɕ-/ti:ktT>.ߟonsww|/u>n9:mֲލ <-:/~17+K.1;OƟS;r+_q8q†.^9=ͻ:s0Lcd˂:8(<lM+soz!E}2Imҿ -;ʷ6iEʆ!HtVP# !֤B=?O yd+%(!.m)ib"nGqq|URV #De( Bu *fC+;2_Dm I&n J1)9`6fi໗kB(Y~ OU8ZŐ)5Q Ei :w)W|PHzಀbF~yTg"))vzr3"u@pڐ|ޯYnq{ 6%%qR@cKcX ,-N!E*5h. !+m| k3r' vրULP#@*sGҳߖ dMm䚈+[hzzAiĂ%"@" cITh@i]&BS%N﷾,+A%!HP,ȲLT)i(_Иe$y"l< F 1/FI&g5Ԉ  ,%)DboX8ȪA@VB98LABU81q+F]] u#2PB\xo `G`[m]V F ZR׃Ql4d@&" !Jrr,&.H" I @4.~: Z~DH=J\2Lhn\~q6rTUU0JӒe /dxpM@Ov~ƭy g`bu5teDsRe"*?\*  %?ZH?I*$ =LEĔgx]6 4,yEF"pu/>I0d s "Tb[u}ʂT(F<"JrYVojBO#2P<3@ҌqY-p<$Y`^-06Gx;H!`}LAc>G^bC3HEZpGP ܌!N#Ȓ4-/T`n>Z:&5! f*ԗ*@I/gFUygzƊHpPhKs2X@9Ei2h%d8nLLb1빇6?a p_DHRa{#Ԩ00σC5BhP&EF"AC¬EB+\ Y!#Hڒ$9V2eNɵ[%h4H@"ќ46*ʸJs:0U/j>%sShQ sfMTt4pǫ\)PF"ID0u@y@ʨl E}2J JTm3IcW2R@Ð`-/F0"뀄}r@i?ӉLjߚZ]6Ќn%on8d*bY11$dUYFX:ONR2ۊ-*G[`l@zO@b uUO+Hh,1 2Z5e5uWW B."Yuo+Ǹ>ƾiRx.'N$:nfȔú{ij͝{OL} &J4. LS&+$ ]9AJ2#ï@R(H^JDm@[T"Y t@3C%Яqp*eq[vԚWM)F/-JrC؀7NTo?:E ">|hmaZՔHR\QIz14I&TQ,^EcWa,S=ˌ {?:v:>U( xK9qp#x4~HqQP[Y\is DG6k,2b1IxzP⍉;ٗAFu(!)~$q zghB ̶ϤWӕGUvD.|xYgbTzj;b,ч$9 [PE;\$QNqBzJF@աN%`΄Tɠ}@z,6gm25$pٵ$On(>3o41P}9x0Z 1wF%@~Fx v$ F -.0m2A!rrSC?u!,-pPebӪ1|;H=eE0Mc_B1lde?@xSint:JZ$HI &&d׆ᶑޔ~4>MSEJ$FujętYqL $" '/iSCvҊ !*T@V0B@Zuy-o|D!~!c$VvS D"XziE@$qR7^ t@jmg.s5_ ԁҙu8$@:Z:DRMҤƩVS})$51{qq ҢZ6t%H1,%ݢiZ3OLHf}f?Fd dB`z(20+QdيR(W\;7J,۶LJ_eS !FV}})Lhatْ ^uJ Y"^Q9c$ @+JT.V `FQ4٨ ͶA[5 ŖpSbIh@N)nÙ{kBN?rJM0A5@0C@dBd2`WU-ݟX_y͑@)7 h+Ja)U3Yj@0&Dkm X"ڗP"H!JAdIWB24Aq!KcZԦ0䄪\b@' #2PFj%P@s= jKl!Ӵ3R LW@e*Rǧ:/4![5YpSؗWqI|4bT01Di7 fd>Jn;4"s00*W fAR[Tvcɼ((RԴὁzcrRB<a6c›ϛmS[!-\+4{Nե宇'ޫ%E2ˀFHHTu3,,|>ͷ$c(^,Ot#s1S4ЂfH STG O}rVmm)BPT"Pd,Z4"$s&A:TS,ira:"`+} 60񲍈`>4"Ƕ [DZQ5QB0 %qiq&F7q}$u}`ȠX3%{^yؐ̇ ǍTãH1$`cw“:k'!h˙/끠t1Gzx~ِbь Z𥠘KђuK CA2ެeK"fE4O5LWEZ a2h,RJ&AE/AJ/@(p\%o}ʦαV<.{,V}Zf:,.͑H3L^hK-րxvq{P2̒`P]r!MP$Ha $DpDjC  mZHUn؇Hpf\ʤ蒬J*ِwH0ъs|bx b$$w(!A=S_]?Dr y#TD!_9'm{9I"#EFUYPxD !q#\ds:<-`,8.*,* AUWԟ^\%HHUVFrtB:5xb\, k?-`жJl05` ~x:9Q)]a cۦCDr.NL]xM0KC@v夂 |"\hG܉5IN9̓Tb@WD!YM2ZD+eeA t"$0 t.aWw}& ὎,2(ddt7ΏQ1>s\je&xP[€NDWJd>V2,k@"psx*F <1vcmYi ͍lœ AE'D[c 1__(n;p瀳BKG ɢ)[ݝ!jeHP$*_ Q"AKƤ4|jst?. [E/pqUIq#On4 @u:2ᠢ^c__<{]7###ߺ$JeWWɕĮP<T/>ficsCr-gAd&z%:]_?C9^f|zq]74?.ט| ydj BqgC~+qH(Đp꾛}&zwBߝuWT9[啢otQ -.Li%}eA>Za(Qk" w>#} fc[.>}kRG\\ݦ߂U AKN9stVM\ % ڧ N RloTm҉'<>\vMW܀p]\\t^:|jP*ӂR U~WWaeq]HwT:a  πIz7ٳv,2LW#=^zOʝI!1Xpq[g IEx녮 Ky- *ݣj9,oW=խ@[tmA99xzn{m8ߟg5=9v^؍655'voF{۝?F]6]oeiIrquP^;A?mo}~ԓuHql?F{A{2sp<. O~W0xD䜭mxRx":0~}uCkwrC \]7`ǹs#ṃN[3G*`[[[N..ǃ5 =߽nĔCfxdM[i݌{W).n%-+{ۖ(dzGOVX:_2?Ҹk)G*T-'>w2QB>T[UTN1K$73H9i)#=&R_`jK03$ زe0c"d^[ulg0WPΦ܁O@3ݟaHz 2H:lg?hSU:cVV5,'foK{@XhrrMA"iR(^;KoŚ1% f}@AgQLy,,!jY6٘gmoF|eeyuhK#%LHBhDe2N_1=}vA2 )#j]=s(Kd3mZUu`7{q#P9N5a?CO8#hvTT6tY.kԷlneTlv.k&o$P-v;1I Cܗmr~>ׁ/^{Еu@~>YӜRcc乓_sYXXYnj_^Nr_ګg/kK~ľ{h=8l {s;?|vIF_WIUs_k]UULELL "X+o$yfIo7򉠾¡ZW}01 8)L+mmtZ|EVF+YVev1䕨r.eDx_eXyG?B`8/,@ ߉!(8[ޮh(\i x:I٤]e) %D_D"q]S\=!Cǰq:!wT4("azJ93TZٯ'e i*S\}::wg&(eҡN669{ !3N˖5XEQdm$-q$=nm& Q΀a)t4>ZхD7{ҷ+V[|wբ̎F5)bn \bTk258Fo<d &5ucC;dZ̃(67}# cX7g'h[j8F3o̞AD~QH.R/c867EEO4Fvo2鵵t4aDZ BkI|l\d.ʾM{a>z8#Dgd ;|S/Qt_өGLvA{r˕׭>B|~cwuud̩V^}y7O|*6tݤ;&W~눸r h۵խM'TQq5ɍB=xgg ?Z,,0Dq@a΢M4^g;mi&D HD%Mbh7QK/L%Ҝ`Y"?ʭ asdfHUʼn ӝPXU` QbjrNF L "``Zz(B*\l̉Ge3B%  h2/7(uP?F1#Hd" z]d!KfU'b#+h-f.;bIKcŷd1Pw7GِcdQ+"Ֆ>Ø2b6hC \G-Q؃(7Ú( Ɋ1Brk3V(QJҕ% T1f1!6„t HFs u˂>F:Nj6C3ذb8U_` /$^rIqَ Y4i "6͈8/?Y@(D7sc9uSN1q⨬`]#eao$nBa#vg<˲&1lvl'>88t;N47'u™.f]"}yT F vO rlab<@7Uƻzқ.>[+ /oiw\Р}JՓzC̡O I=lu[r )}Nnn'xAQ~Ao1+牢u pp (FAL谕U1~(D9`/#~?C`9] OB,m|9ɔȰ>D 3B%5QX'e J٫K:(cQB(PWк=sI ²=j8&>\,'<@9x42:1g )Wփ#[=UVخͰzZ"-bD(".E JVK)j<l8QiI.SWw\"2FB$V`[ĺ $8~3_HQږ~MlVͩv-.1yqR} 0VV,u ׅܒ`AmGG l[M*Ƕb%Wo0[EjO:f~k̭88W̎'a鯿Gܘq7e|COvo:#;t`|5b;BMok!pZ/7Z˸?,+%kj׻\hm}>tDr<B}3ϓ˻ioϩ丼kk$/mMxnG7}>~P L _u/prYE [w!BUt;#̳ޱ0`;5e,rw "\[e(*iPԲ{ua*~/Z9"Lzp+̊BTYwX E\\D+*_&>C5P)_ e'c65q0\W9G2h rf $![$W5(`q3he 0jρ c uA=VDl29qn)Rbv Wfda &dH6~x?pp~u~/̪댪~,; B5t{y~F7f̋<*﵏|d6?VP  3s{4l&wDF`s[>j;B$!`2׃*ݯw 8+ K.Ag]f[sen| ӏj'w.IkA䈌 0 Zh>kzZ辡(&{d)H{mgaAh+uց"Hţ(7˿~{B[H1s$|&.[f̘%Rag+(iZ=el6v4$`[fH6^r^2dH4F[ؑs^V$'AU5fDnb^TZI7T0(|W:M>Aa*ǧoLZ^"nW?|9x#6 r E'7 HLbɪ>1!V DPHk'@5MCxEϪny'3R4&"7bY0*)"u91%L'WtGǃT~^unvowK#a)[笋1&EA\l9բ$D:NŒwj6Y$;lScRN8r.k$˺, y~^NlWsSjl\g *p{~g:<>5b珡wx.% ݪ*I 8A=sWf:%D$lqU-5]P=48eYfc^މzN <iM߶w RLdsJik/H"Ow}a1Hܫ,(ihbvd#OG̿1 %Qy(ne ,I 8CAQ868.gb{Wx|a!0 0q!JK/o-^91cwTsWLBʐ`kkR/ˮ40U)bLPFah1ڐɘqΙɝG%`zQGUe6,K_L&SMH,O)@(}noamڱ^]lL-@c{(D2[0vAtyU ST? u"}W"ҢVDc`ދ0HM7"Dg+ 8Lvu6/ OAdP #=ס=]!QK30|`]ap~$QZ K=D&8UI(3qʴ<`ڣD&Z@i*XX̧]`;/.-;_ MNPyt[k "`udꚝžNQïCnaϝ!f$r͵ 샡|YXYuf8^H=!n#'t*Ev+a+cc*^rOsk$Zz4! Վ)š@~n*>$41$mQ8ɁJ8L\ߐɢ[.XuQXL|R 9RcL'Fw7OAuA1M1y!RSnLglOSABE]0do?/PX)A"6O&)H omoJk`!PC+%xqHv=a!{3Z6pXal@ۂ489XiF\3('hzk' L5Df>zi,1*'lYG8`F)抶B)ӮX>.̽_n,)81FA9z7}NXP1({Fx{V )hQ |L;JKgr1;(`IE {5_տoX8S.I4?|N.UvM={ډ^ $2&: tC,he bE&*y@K` EDSֈ"y:?/q1 8ʈ',&D:>B6!8#]pQQB6bl˕AW)@Pq{>} {1bמaOFHwpDJXhs:uu}E>2?<A:D87Y1`!8SuFq =\JEppH  m7̰!Ab1% W$ $1qG9᫊UԀoFr2)tM%ZI7Z#Xq '-S&~SGG>^~Ɛ}&(Ź<߃ ZDPu(b 8NcD^0qJDl򌭁ʔ6bF8[lR(V|P1xeੀFH (I,,W̵h7xׄD^ |/3tEi2z jM>ua~&t@сT@ Dt~B<u$]?@7-rfUxs.IUr"CtAZ ?Pt^B q r?Ü'p$qmE lsB ظa@*@LjHO}xsĸ 1J5k R=h(G -PDNLҶvRRi i\+בb@,I  4).JŅ+M )*N7 i Ng|npԫŜ00eJz\l~R!n/&Q=|5?k[Rd\5#% ^PA0K"I2F^x6'TR57z b2 eAwu@Lgm &9x`1xIMqI&lFC!o\ɵ.AWs-"MX%xAHʇ47[{Гᅤe& ʙWE1J *Y{5>ߴ_`bVd53J!g|=(8Y2Xyޞ\l6i @Vf# =塄_|CoArd+QEcX~">0fW"XmnSc{irFg3HE(. 1lj.h݁ak 19.C9` P)p$u&>ma?QLY C ְ TL$/,5S~$0$ ɽw(2`ô .p`|c:Œ-otEq)w ㇜_UݨuE5:q@pX  XpAF5y;Zq&NXv!" 1b84DrŐaJऎ 8>GSFL]gr֙%#%` ߰\>$aϬ"g;$/P$P+^%9URZĢ B656{QTH)ĬёfRZIB2Q:gyDzz7'(,,`% dmFcDw7 )*!-|0EPkl^:_c84Xh K$m`1_btk"paj"(kIv**@Fڲ0.Ӄ}`|SYZFY:kar6x1s&Di #o25ޡX V|GeDx1UpH-dbd H (P@3b-̙"GA?QS{ѽ `HT1g AfgrY\F@=Eԟho| x c'1C;,%!; O q:[If.Q@]ZY^oVJW>7S*cWe8pSrWӐK̕o6xҲ'1,oWa; ϧ!h `}[;sѿn8P'$S aB.c,LpaZܭljA`HṾh2 QWߝ"_7B @_GU4`6Ѫit^K&., Qǽ/ _).)mDЗzM3'SeX;Cذ]cin>5_(@DZzt_kUǯ UA>QA8@Q{@`w]D@PA=!dEuPF?zJ 3'W[GYO[ JfUƪO6u4 sl=wx]noˌC2G@}E{vyoX %yZG;* lM\vxsJkiuQ "O\3 o9]4J4%%ayW%ʫTˣ3|@Yi9t 0Z d`zb/Ht iȹ=\*C8ל\&J']`e3hdς24*`&4t$\E:VؐF'`L L3]+Ga\=Fξӧ FWewGQ |L%Q'_(!qgv)3b>׷ӫяp |"TTђZvWA0 _52yxzik&hw{v0@ܮ~ !*^Oq/IJV~:pc_|[c{ӂMW*)? <,8^hhJ KJD4ZXxlb::vWT64_ Dk! rS)5aY3m,4Mfbe2)$jSy9AG)2Ae\D.ɝ+p*ԠE%t`%t]$o@v!)b7-YASlL3>Ã59y|\:涠 B"\1 ꅭ}oR4Qx,-P.*u 6嚻-~I7[9+zia,[ʆ+'$#]e%6bR21"KP"80 m7{tKgs ]^2Q "ä=rǰeKt-:p%Dzrzh9_/zQYaI{crtӫ-I_)&sss};.9>{)t辶?拥h"٦9Opn_l;oĎgrcm6h~VMFܫR~S% ɳz2; `?;  n"\6 A<0Z r Dy(IKfAmaٺ'%.HGcHU%Ðh]§Qw aci_LdM=.(ˀ[A{D aqT2K&c 7=`s*?%`8 ,aH 8SWd)P䝡uG" O/FXd #" EuﲯjM&Ԫ~8o'}%`*5B*#d3wnfn]?~3> ?H֛^ɨ#2rhqIҙL}C~`X洞ץƫ$25RJxD~epU9DU H }ricDҠL%#0i&!Wc6[٬{7ʰ<THNg1 H`Ar>@qʸFTaŐ7Оǽ6G/lbU+W^ aYZX20!0rHѤV!s9A nبGdmJNB*҃U^ GT' #QA (& 6K㶦LAm"^V H QwKUk_ ,`5C *C,[ t2k ,u>3 TR/!E2L1Fiw\Rq,N8lCl]QAh^pY]qNs^\|}|>硂滃66f#A~_?vlQt^O6j5o;_;OmiiggƦe.+ ZM ߋ!&e~e%,{[.5@ᄭ]χFI[[kJЊweu0ODAi/)̊LJt<~@q^BLg p]Wy|6v8G-Jѿ+O7\NdW.WiݏtcC}ZY󯴜3VBa"zb]XeNX`U3Pt*CFqoK>*dZYqp 񐲣ȨXtJ(wQKXYY3lh}a}JI$@Ӹ@0¤R<<)ƿ:*lvB~@/AԚ%V"@Ucd`+E&zM(Q r9XMI{AfgXȄZA!'Fવ  lGvꨴ*j"@]XԷƐ=ﬣY) hSArvC@D' 팭;Bz-]5ӂH(Olm3٢|̉#N+rUUUOוAIbZq_w̷/<jUϗu?֛ ]4ox_]C3^y%8ϝs c Jo 754 pͻr ,, '}k4u ~;e(Oy'ys{~W|VgS;8qoK "Ńb 8?Pԑ%Fb0AT-Nt")!J(P81ӯ2{%Yrwd܎_%"qUVŤ #$aE8dD Tͬ?DpVznA&r~ZFXf>7-$^BITm(M 5h(]K`s7`<5HIق`:?fq#OnFi`YuGU7p|ߵ&HtS~=p|'Ԫ+E=WMף]n )TZ@RBtCτaד(vVlhsyI([ط@޾ssD][ ?3AU$̦0J%mm׃Ec`s_nv2rGI+ZTɭ|@񈱲!͖ +dH7#wm3޶վ.?"6X>Z@AXFG2 P5:m,"qu_}/8B slM21_ڢ*VWrfF` ƒm.}jxK0@S칤hvu)n]!R [z0T/DC+@`h"PZD.J܈ XMcfC g1|3|v`-sNUl13 UjT꘷Q$28xݷi BX@ eǵ^CNa 0O K,ezgtӰ#s2r)s~Kai>bTjbvN"龏BFcf2hQ)ϳDL*)㲟|(vb r~B˔yOrO! nFge*T8sQJJKqB%HnavqjM֊mϫ\\j&-zYA#Zob.xG*apehB #4/tDRaSrIHN .t +0:却S2P2A"J9)%eJak3PGYFJQ{~\Fl14h_\oEO@Ȥ~^m7,Zg|r]gW&߰07&Pdc `0٦ҳӰ I{cggH]"V1NI3)8 =/c#< _Eu_’ɓI4ߺ !B. SR;Zy2VU~u3akt!R2XD ĤN`x6Ȣ m۶mm۶mNұmNn~12:Uٵk|f9uNP,ZO11Sbd槩^Ck 0ڒ> %qDd3)qZ=li{AUb(8KUg^F;sD῭?Yah%oG6?dԛZ'r^jjSL>0"SHQUg@?8 akN7tϔW7 6 Uي=/(Z9v@Qz" u!Fێۓ 0}hJ߲*5 yRFۅEހׅ-wemq**b(ydff_]4LrEg<z#?~%:NmQncc煛{T|-RXИ 2u^Zd(;UauӤSâ9 psum}\nY$+>uX-%ʒofYa8 $Hr 'ZryJO;9~c9g\Vk0'zk? cS(TT$P0;KX[1ӔEG\T<L)~/l#EQ2?!A&9LW o Ӣ#7Lj[;{h-CA0ZhLi= @dR"c i`զ8zۘ +ͯ s UMdD;#H1v}(`x|ڗ@ I}9vȭRAay9ƹI,H`TT]0S)|N0au7.uͥiqOQ ZtEu }Xk+n>R58fsd_(VI0X'$T>iHޱJ6Op_QVu{PZ @t>!ȯP pܒ^VzZ+jw@(|0]!|n ؘSh!2Z|s_\,Pnd>mr2}8]{ҎgJj5_\y8Mr?L]m}zylz X镕@Zߥs<`κb{ L}I[[ZϹ1*a a&T).r;%OGOXE08^ }D)1$'TBjZ27\m`}6E(LHMqJQYɥȊ8,':GA (%>;]@$e}sR| B`Ϣ$/捖_Cb`ȷB"/Ql#!%05(BE+~-4`][?}&)d`- 6= -_V:зJ T#'+D+fRʍbA+/+B';2VЂ6}^F*FkWI iW_Ǚ`Iqx^ rnT ^@ʸՆ#O `V>+"?LƒOA+8Y'q(AzʤHA}pK_m#Þs>gL`jb;g6P fSTeL,:;zWH^-KzZw26n\WwA~avOfX  3ɿ%| t86wXK::2O%IcolÛ)7yڮY!sBHT6~ߡ^~~'d+pI3 ? Ӈ>!._W!I2Ss3v=Rfk Jݸ C(-XÔh勌.ݯm6hi#Jj QBIrׂFnM.h_TPH^~ڒ8X$IԖ;( w7Dp=;io:y#s:.,9 w1<sŷ (3/}$\7taeڪ#g,*.h5Vrrf#LTs$YTqBA;f<J ,iHn9P^(3iv1εט ;I!uzh@%+6N 3J4TI l,?IG#-ZϽqϤj*ɒdggyَ&^M=_pzp^Bſ⻢k?nX'.BQߒr#d1gb# U8 CYq?;3#$!i 7_ b8]Sw TQ8S{T/4!n ÛCq^`~bBXy`TXp)"< a͞?Rep<|m }6ᷥhERG$H?0T`97[Q%R|'<a2 A2L|t\o b+ᖙ8 zn [RŶ6R Krrz:Dl1?'Hm-"KywfsO# p_̪Iô]j2Ep,IQrBґ4+0\TK%($ڶM0 @QDO-\q))]=-:)*%*U;Wnv vj\+ՂKPc,N0«HlT7#DG][ETM;p 8쥆ѥQ˽ D+ rL!ZPqz jxxF)³ѨB`t!\ D(jquUBߪ`~Q/v2[?rJkh$J 1^GkCؙJi>QV1@`^.E Q GUhgU$w׶'ydx Вӻ!EeB.fv h`h+ńY<Ԛ!;ϙdbCMEq4-bU0?ff ~ AuCzq^ Gn1{FH8ZXT1kPtTɄ&t\bn o7~#fO '2˜.&BY _4):a荛Pe!=.HtXp书>OELA -i>ʓh5ZZ88\2'AaPN]ww@s$#EjSiVՔ|܅eSi tO]q' ӽ6!FϾ\Kёyh{eHȬekBzy;ڤh&}B7#jԪ#:&;+'x/.!lR"rkRY!Q:e}# ":KG%`o[l6о-FC8DphSNkUrœ7TJ׋!;n  yavMxa)AYڡoFab)F)S0pyS`~wXzUh+Gy+"_MYŗ$ׯי$4ܒ3 uم|qDqBc c!wfl-i+=>O#zûFkkK,gvbm75NP+.>an_TI?I;s!M헧VB!n yU,k(Q }`%{]4T{Y|9݃ o22ODsxx%e;s] i\JArd5،٭eRǛŋK8;޸'Qx?VEfm+(26Hʴ0Ss&:dlRog9}Un ZncJ(|"YJ[ҿG- Pv:9m u]|~@f$fݒMtS9gjl+eo"# .C`itñf۰{a'BK4s(纸^oɈ4?lӲADIs\Kan*_Ny!m+"c>Wnz<[!RJh>c&F]Y'[@A՟^#1pYI`>Ѕȧ"cLm^?Q8tP]_*ǟW0 t1+/R(Trr1]߇rgEX3#oy۟oDQFG,u|†DPD}Ӭ%AumxӲUF;,Q ʸbjZYe2Z\r갢dl*b7$D:^ d h]D'|R.j4I;_/ }{O"sf`VEUdY܌J<9lPA{nJ#,2& kߎF9XuY!UPjۈp FZCq Jrlj54 =:9!9gd te=:m6sʚ38f E_..v!*6\3GjyἪV ,A|LT'r$J5_Qj񷣹UeAS[HNPC\i0H(epw!6E=e( 1Q02(4?(îK"CmC3եމ/XSUT1b28@}՛mw9Ͳ%C& `7ܱ(_A[)BzPk+W`M:vMLuO3ЎiMH ?^0 oE g\dS]Gl3 YP1Iʜ ϻRlgF3 H aEȁ [Vg˜h"NQ&⒫t}$1(B1ᖆD0 Rl|`w0꽊IV]<](Kęٕ !D6`y[d 7UiL8Kx>dxWxEt( E 10Viq)ڒ,5EU(QgF4;i>Z0O*'+lU8'F˧@>DPlj郿2--Rp`zx%#0g>@ԝv/\jtF/HU , |w)H:Q<|uba(82EuLnzguwe{Bra'odRGS. rȇ5AMA|zy'M,ӭ}2@6ZS?BQBW~Ck 6xqz` KYfW==t|*Z >8Tcx(:F'oDiΎ3Lf?EQzd *uu1*EA4rp\'ȆC49\I fS/!3~d_r%U9Q?cVA亱'hCBl81E3UF}'@9(!dP'dϖa(rqÓ"!'ѰtV' gps&P( [PY?ňvU*f}iF'yNة߼vͯߘ$",MC'. A18BF>=Iol$ &ԻYiO|p_A (ޛA,"$Qe@JFR o aR1~NR&AQ-I1=Kg rnZ`Mv0b8Q@w)eB{m> a'GЦ%`$Nv`T6$swYQ{%GL ?CGYZegHl TiE5rh5_ VW >>^|Mg`kҁ⁕}d  Y.G#鯚[^`1˴ZOs5]eQdơ()#{, EgxT2 JghZws2 c˰q+-5X<dPbXNG¯  Op!e\z+Ͱ0ҍ4Y( 8Z ե¡j Ԑjk=i/' Pgsګqt3͝\OӋX؋lmMz2psTB(N/!c1(/q=jkkWWffeeYa psmҡ ϝ\|< |Pu]vҴڨhhdJ]3$Ix.I$+T[թ1gggalsEV)}(__~rTQ,PZ8B+}`]UT[%-4m WFFn}+IS|3n8Rph2 +þ'Rwf&?4]dko; pTjox/g]?dR/p䟇2@'>Mm{$WؒXxT4U2t^yu{F#cp@\cͪ1JTPJQYXE Q*14c2wؿsMXl'QEIsQe:9%U9j- zCF_Z!I{zǛ;/"!cCcD) I~yI; 6-|#|gқGGMNH)T4zkOlX⹌j @Phɘy湕39gBVPlZG=,X'Ku0z,3aK~ HDC?#0[\ MLUxA- wjU[b tHQ/-, )I0|캢j&[[7hi60 =\9>8(\Z_|̽Rn魯19ǥ!d1¸hxpmrȼk5!21h$t*7)u5cIXqRxF3㦓80}i51SlFiSH5V!anĆqۏ{al@K&xP` GWPNzoCb y*rD3e{E=ugvSCo :v)<>_ jFb{PTD=Ce"'lJU=%I6 .* '; :O hCZVSC {^Z!!%]j,1zDI ~LM-NbVvy6n4@nYSt` 5ڛbq،zop\ u/ TPI.4PbWtW nn-#ZDL |DbuPeG(Kߐ(ӣ<I" I4]R SEi[Ep*ojD&BDo$5^[7O:$(STUUش7S_U\˹ ])z|;%]v/M8q^{;< kjE7vzb켃&' _qb FO1 }Zz@:D./)6jsrcRj-d9sGEbU IĐF!b%&F'\(hN)D%&ݤ$"C^qM=糓l:KROk3 H h7 W7A;!Em>;(l0с|%bxF2A_Iծg#wee 2'?=!eiS@,f(5J׺ƻQqb x"`c؃ϫ3p]q掹zD`tn$;bb@9996W,㶙;YV+>nϫ0 )Z7~Og6i&>?gz+ˁrf٣5mc|OY%pTɖN[m ߕTaQeYNxyS{Y#?l.ҋλ19$oc*Q>1-,*0M~qU*z!\y'Alp #RB7D  WN$T%Q"K5n.H(ZBDW&/I έ@2ؗQ!XiB_lZ UvZ$D)&pI 4E'4S܄P{5'3V6 ;;|NS >8VA^#*Պ?0b#i 4 @ʌ5~T OEñԲ$(#4e01 O b`XmѢ{kĝ}Hw!AڤIc_-d++#:;!8l߅t,`82@aCߝ]ȼZlI0W -ehQ??HO$ Bd DYK<ꔟOnG'eyYvݏV$7]!K|;`cuIwg~=Pу".*c}YZ1ϛiMr#{aw6kkQCX5w)>ʎlHq8`eED*-@)}d!Mt+a¯g\GYYEe`4joժC~G[^d6:s> J`Eq77=$0$0}&QeG!t1`%>Ht 7.=嘅QPx#S6u) sK-wG;)P?! A%Ѳ?<5% (yHI(-H%{93>~-UА}98ptPy=fw'6q]y`eEQ}99Q\t}wVL?z^zcL;jàQɯ ^};J1*bo:k'W< pG8)@6Rbe*9v;W8|uC'@35&2ժ,F g8CtISp~W-6Dh!0aԖNOkwzvFI[.@>IFa#P,*yp=V`=Prk+Ӌʅ{gW!pџ?%ź?!P)b =ѶCcŧs35K~J(%PJ@#P_Cޜ/Pel[8lYyvV^^Յ}|;mFèH{oId+K`FyTtIBEPQ K+֦&J(K6 &>>} ,&[I  j]Vpb Ʈ.2Fr.`CE3 B#+,D)A%3XLpM ;D&oo< wKA.TӟHPJ(5 RqI ʜ#-+@z)ҝUf\oꁘ1~wv9jXx#y d@.P+414+V1QtM-kp(0BN uilMpaJ#Fye;k%=7Kz@kND,ao'mSHX?xʈ^#(W%'+X?zYq<(\i Gd<91е*fp|jUkh Tt|pQL3f$}";™APD%?=/gTR4PP"Uo:PKЄ"ce.z{UX4SR 2'C @p1l JQ 5e#9AF@1D>ͧ Ij֣y&3CrF'.1aZ 烵?1:9 פ@$C}%>#C [+O 0L&j(lءFri1E<^'a(\X;ᦫ *N0.q0+[+Ȋ5(]St3ZHADx"BJZL9tU]>(?{X+l+OxCP0faDP~1`}UyA^Xx[FP0 i`K.Sbg=9bwӶ.\\AxF=)޾uHmr;\aJN'o_Vʿ ݜTUnζX&Vz.nL/m/lLpy"G_fd|D/<(^̃@ȼg,M|~ꢫX'4yY| D}Ȉ"b T.OkS̟fucZl(s֚ ä |[SdN͙+%BN,ݿ#<,Jݱ[mvJ:5%ufaKa[jxw&@MI^[7vo>ExgCyH?i8o Tͼo&nv{q[ĦZ.Fouⱀae|g:9dޭ' ;WSU~cs۫c0YIvU~l. 6BV*LB5sȷלsXs 'ʍ[Oޣ47&h3tC΅Iq\ 뜆[*`N#+?jZ 7cxG|)y4Y%& o_Xg- lG8~xSYuN^z2NSIHے&[9[VO qyaxdI :Mncjg1"bN!4ҁ3LB<-bP6lJU)'3l~cUd/Xby嚮lzs6D^r&ߎe#?2y-j-o8&N:{!tZ\t[=p/Wss +.LwuxS'IWrUMI+7V,@<)abG>a)䘲2LF~/_7w"<__>|"qI4՗nZ,?:(۟MHO_ xZW'өgaz> 43ZƧ窜 #ym< ˬ$VEf0p׸JVI~A%mT]-Oٰ>D ʍ:xD,<4o+H_8t/wC |V )/9YwQI+Vy$Rcð6Ogby.iӞ#&ID #xV?LO-F ݙ늢3؟~rb>P+B9Wo> 9녲Uv'=*4cF8MRuAh!U]62vNyo&E%뭙ez@" ۔#;8Ly۱ξQF5dcoR3Y"6r.C.PkPgy>W {grgMT v9#ަw)?6.=뭨%D%˔]x +lZܞhP0N K-N-r9h!^Ay) sm2?Oi 8!ܗm=ޗߓiЅ7F&YH5uv+eES4az~ >C܋@sCqpi.MTתSJY)m^긅)q1PqVKh2 qԾB[N&̱k[^WZ=WdDj:6qq#K~-uR s`l gUקKg <2] :΍nMA!&B&C( })MMZkdGER OH<+"&әԛMǬs!*Ŧ^>wҝPkf\߃p!Xv)2=,7<b@ BվCKo*Zۆ@=;E%sK˓l4/3Z u_+١/: \JP/fB@O:"m )HŭRDp8FiP7ME}x}]Q(oU% +=ԬCVI}OZY?OWOO(ϼ獜,O?5PLL Z.[n.O߇;u#{>t}+uB35UmtST dX0( Z ",OO|9-i(<-_o`Q jJ~DxYvJ9 +}#(7,% %!e/[yS\OYʛr[[ h0FVQ޲ik1%=WiKW[(%ɓ'G)q[ׯv[י2K|ϯmVJϺqފ}CC?(DgQ2m0B^X3@HکcBaZ9scio5yD[yC7qJREH X-D=!, R^\]/8`zn#6ZaDqtdRE0x0R PHbwCd%iUVjj3xUD[%qHHJ'Z] XYQ T`󩍒Ig5tX,kQRORĞ,;?KR %s]6o_"PԢ,Q8Hmo=+Kgۿh2;_nv%A&W!9Mr}_+<XgP#FFFQڐ6 mJr8Q%þڢ2cΟ1I4)plh )iFW*yi42èmm(g#iXli4ՅAIRSA rk<h*MWVy4 ]B?8ON?&<њ)O'4_( ̛8F2a8e|˹(7a;pl.'グt^feJ Bֶ-_Ka@xgR-NoQ@ s{ͦaűT!L7AMfm 9SqQIvu$P2gwykP6PM|*` JE}&csphd>fۻpx J7ˊFAwߴM * 04?FRȦ*mJjruީȡ;p1^O#E#[[sE,x"|&RvWL$c L>˄^˫M$`9Sۥn*eH[b^RwtAKMTp:eeqRKk]{v{f J¨$ J-qm )F|C쾓wcegop `.<^V}0"Cm}&k( 5j?mL8a[_O',X //ߺ8ۺyۥi Dь  D&Ґ,"1Yi``XԺJ`Xd@3(kowbAn;&OOQ6DӪ]Me q#k,Yk(6BiG`}g^`S׸捳WsaMz8 `::Q{!tXÅlo{dm|ZZU9,  `~KZļtJSK{ CBFvnxtyZ`PIԓQ{Q+?[v}ĿzOJ#l`*m<:.X E;;ı/,jPmuv m#)$ɓhݪM| sr/..%I3MqWx}HR`/F0{tl#G+b1D-qW%MQ+:%Ɉ% T-,N8ǡ)LT&lj241\VK ܜ,$z"! lXWh"DAH`x| iV KZ? W~/kV1FXPğ: !.ᤴeвU )Tڜ@%3Ԃ3FH~ 9_JD pBMX&}cNC>$Ke78ڨ|""Ȍv:tyT3y JV-atZ-G tZ 0X#;ػI#m@!ۿcw_w Q^nJhlXGy4i|[{u۬5Ak}R=Լ+r;XߑBۨĢ0Ģ|_v.hy|@:OZ\Ҿb@z8YNf6WBuw똣R P>bzLhblED7( l0Ļ/L9$Ѵ% C4,tWy@SlkSl\G[̢x1m p|@.HS$Idc}t6yxeج=^6zFz|w*Uv^kkvvw]41XʝbN̲[^ +߮N" ]B]Q65%|q{vp9C@|%=;]{S%FNAyO !Xo9G~qD ;gݽ] ?q!sҵ }+2!D!aRh#d@+;hJ$+dڞ>PVd Ew3+x%51;ۋ3cQ0j qs󧩗r<::kn*?jZn|pj{~3{Č5e1ģop$3~y` "=ѦAeU͆@6kx2¢ocy۸UMt9[TQ-Үi4EIV'> Pkmey1DOUiԙ=j5O\:U@;qղ*xlv~ok0W{ŖE60zn[_W6k2,jEH>y1ٮs ;s2$!ܕly_9 J2!-ZTrr2jS+<ԬUЈr=2s&w;nd}h551 ~Bo֋Cn5_LFU\[o6G24ʿi;9,:Η7?'N%([kƬ(f [ج}g8{R,cO SoЦmc; 5fMwsU-P?m O %O6p*N&cWr#S"`^?댹< 7M5 jo|)u%#F컌~z*;I:e*C[]YOiLCa)EmLWyg$)d_Lv3foʐ=S}qn^1 ub-I_PmB[:|45SzPT`2mOJҖY<M.Z8G%'=wH'(0e B߾1Sfk::JϹ;M⮶WvY`6qҌ@F,_Ofؕy&$ ( [s=baf` FPȡ0[OP-+Z(JKm ?ux,SbG*uUfLخ+?p ɏౡH%Es'οoijJfuۄ2pڸ^mcvGJ7؞a;c]]s77'Pax*5hqTipyQΔKRpv1Wg 'n_caC{-i#=D%҈07Hn+ MZ_@Mu-2 'Ob7%By.ؽcx-8<1Jd6kR3n&t|v,[jT%._FC[lWHUTςZv 'Rp_LFhf|b*JGL~W8V#X5^ؒ?1IL6Eh9qF0R!JwAD;# zahHJGírs}L[HaDp*C.fxKK9_I.ŜZ8[a{i"?A%a1cİ{ Z@a>gKYJMG6P }dbB 0Xwr 3Yke &j:|,"!Ep$©/^ޖpqH qsᨷS5:d1D3)L\U&1*e@?9>< gϝLI8>mZt;EK\v1I$ wbin+N`m ThF+7W'dHIkBxC0,IJ8zBh$٣2*ω @|  ÀB,TF~u2קSHx?U47cVh4'/ 6Z\& F.Z3j!!gݡsg? K5S5؄o'{YZ&zmWK%,垎Jf=T}_i%)mZRnLZh/ ՙB6 (Xequ}~eŰ-0O-+\3M(yAl^HT0!)Jr|౽w7ѵeդ䮊-K_ﰇ!8kQ?̈́NŹה>lgHn*{',8:) :t$ҥ#;5Bs֨])iM& ˍ7(ꙇ./T|:'xL%zErɔ$2 maZopXPvV⮍Z*gV}%3(} B 4!0$(0 tܾoQ)w-gQ6 URjfD Gu#my e$Z0t(TꞫ%5d2ɠ3N:jA\ls̅rj_?HuWoaTN iQruK凣4*L _J2Ē[ZX2qu4 $)'@ÔANC$ThVʸ=@"j0l,P*!Q x>3kMNMj'H!3Tu=yߑlz~֝fqKc9D*ށI rT{)rw%/^ң:GaE6rD~MzKC">8JEv|7PD&nBk`Ef"-r蛑  KƔP=$9(Z.rzY!|f_3h*mNZaN.g]2N-)ъNJ6x[UMi~J1b 7b*H#֧Wt=o}\}9%tT*&v*@YCi60#/)GI{Vw0M"."^[SD'!qi4~]S^*6Q}n{87NWcګoʡӞӟ>(v%2Y- iB/A%ч+(;,\jpN6leckpU5 _=]]eQ'8CK4IZ,eyudPV08&ZԨdͳX$hJv_14*2gztnuӔdw?E3xbpjwy&BfH5N$L7q~#gy\iRxl ܂Kwo2v@ŽzoY?4rL9()T f5u%2 5$(>nZ=Z,ߩ%{@&tWCrO6TF uPֈbf48D!È޴siU"DYF Q_CeJs(SOd]̂FrAFר! *#eC!/ܺhy?eEXm5OlD'=47[  NӃ(mAsk5ar-Ne! HKQ.e̬IJT?c\-0f9 r pv"]]5[JK=D+V,UK$5knkՂѐ,EW(o Kfk5Ot fT|-TtO0d鮤 \n17L;jĂzϿ̙|H7YFܽ~/Q1@ȒOXdAW!%0 N(#{b 2yҍDoTx7Tc', êB509(?t cA w_rw>S^}|~l>wz~U> އ8CݰN]5ϓs #U6ǿ>yٞ)b(U&,ji.~^.qnSx^Am|ɍ\0#[L(JP^.iL jG_5~K#<,ʝ~SZhZ`ŗv}V&8؀``|6W,$ "T~Q6`m ka= P}^)"H[ItڑSujG9;hoxBGӢRy>)Gof:jf(:_K>b+үө #8|e?RJTӀܲf *K.:D_*6yHBx j u`%Hdoyh:)$\ji++Pct"oJC=r ,F%QpD~{EҸ;͜>W\aٖ1 p<ӶS BZ/F=_$%(ԱB\8|kmXQ X< 7,kw+iL$oԶXErA2N"s4'0X6 LDLx0gD\xQ &lkVUam 6ۜZ?yxi#) ] qӲMI 0٧ܚ6@txJ%jإZ\Z[Fe^hLCH;C(gdkfe#ER,=<ۖ׳BPdX )[lBQR$kmt ,.}`sR>'LXiT'Z{VήŒQiYYI,7MIizNҏzUyh b$rz~p<5|wbF01D rj*26N}u6߃6v2bM7<@% Ra@5XVcKxɱ0.CL^'v 2T23waX. [w.[,hOrán?`E =Up(_'a@C^ǙK-'~4ϙ蜳ۤ`~H︝[͇I3P_b/x'&(;f,'ۊ_Xj$SY~TVK &&laN譔ѵ9c(J삈Xeã >-ScuNrگQsz2?7<Ep cʢ>UCW0m̦, :~HFCD. 5Uq27įGfF  `Y"w _#EĽiJh&!/TҶGɪ7Cعҝ"b "2gU,Jy?Ίw`T|7?ִZOdzgz"vf UjY!>SgO :t)+qN;Ӥozuԍ8_d@ ߃vho.OB.IXpfi`xZ-/P\RAC6+9*XvjCd*pNI5#Ґ_'qvEHvzFUu=ƒBܱy?z c PKo2sneYV6c$Jo#EuoI{k^o ++׿~@2ؤ*>gOdI0'["6:aB\1Kz LȄ,תsBGnxrA Sѓnusa~+ŠQψbK5E?.!) |v~F- -o6պr M:00sm$)r4N핵i]0yvC9=Y0b -ugI 36>Yag9GDH2s) G 8:BO oLa@H cj׽.qڍ+ZT+׫4Gp}av$ڬi?@\>zw0&_:wM޼D6I7ɞ>)jaARS=Yјr- 1)sn(V,R1\tS/ dKs`ue_xVp`yʌL"n)M"lz}h;Bgw龯O>G1׿":䱞ruj͘\jhIB 3¡onKk)Xd[zv£ TL.XV T?r:y|V2QcO[HBD9JoEPVei\wǛlI.l剅Ch4XV9}Dˋ; J+"42Q~ qq]ۦwRE!R9rpw=c^GPǓWdh@dB=TH2G,\p3~¾IZZ2øC\*WնCXJS̡_}wSJvdZ7!kC^gK﷈Ɵ = /(_~_@AI쇓ZN;e> j}7Yst(ѽIBs>AÎqsͦ7͛\DE+v[H4x ^^oIڢ&(sy?S:Ցm[Cxi9 erKm4 &ܺ肸y'162Cǿ7G1e\Y)JG NdêPi4,ٶm Rp%x)2`6 f5x .9PH372O(^T6G. ޶bkՌcН,@7Zȹv> 4 SkP}"{')%vph*G6U@CՌ?u8#]a-ъP:#<$H %P"~E T[~ A&ZW`,y{s{6PH.=0F.oOXV`Qn 6:.:PY\`yet!Fc,NASbÍPif5SV1[\?)W\/W z#oSh!\48xFvщdi02̒]|9s̀$řIx\a4>!ifFg[4jz?\`&- \z%%R &3s2_mɈvl0$ ikqaDe8&S|VX8Ҧ>r#)W H}T4 6VfuwGMݼ6; &O-%)Y2o7[A-NJGlz;4l#wu&vtv9 Bdܜ'K2uI[&%GV^6f>xN@ol2Ѯ&6G>\b^3y5)(0S`c( Uf@FW'φ_ y&o`z+7qRDI"7/xcoqzj0;YQɍ2U*~ID / u}:=8Y5$O(45/ Ua/TҺ&tܩXz巟1Y7RSNNx96I;k/hU**U[ةlm䌗mk~gסMsad5k#簔,a(Y4$b$ođISfns]_?6I[wBXG:&b$썱id!섘ƸLtoȷW*Ec4"JxRi5[4qkSɿ4qIdT!5q-y̲umؕ s m'nXs:{Ah3?),DQYd]ޏim9cθ\.*H9*,l*7fY'3kޏ~~8`8^S؅)l–)9TvV@˪ܟ*1.WEJsȬs!/Dj(f f0 {j㬺A&@^z@p(' 1i(iD>6zc7cδSN~㩴c }|zF'p P.buYMR> 8͗ȗ(ifv1l/Y!l^?52^?Wݟ1TO&_ i`Ms]!WS?Dӹl!D4f~*GN׸|x}[SP MД5,QC-b8z%JTQV=bȞ1Ѣ c3[Q]_=d{uyu)!x]|Yv1\rY+Ӿ߿i7Ljѝ(Mpێg]]ɸ|q\V25m<>+ tg[z$t~>ϳu>i* x%$NE\j1h7wr1:U5u׸ZdCj&!w"zRP;Su"-Z؂29k;~0T//Y5snX.b 5& dH`izGIk j]JVXt#׹,Nʨhf_kJj%%j֍z:/Oz<]b(Bz C߂dy -XK,I9[DбL,z_[RTr͇Eppb z18pc/ s 00. /43IӝD?oN:O3iC:x%0m*ϪXp{lpG T$ )DZ~:{}N{FFq&![ _E=A4ANeTSr>{.w<*TŠ4i y>@Nĸt#IC"%_Ci}r#[@\?=92i͢'`IhnwEˡg̎*>HKދxV?bACѼ+T^RU4I^CݼgF=;<оxFHJ%qAo@mѝO= wW<2 u[w[dȋ76x47#D^vq_:>qM7MZWUB'+]|[}ҫƿ[d\[܂PW3SX5h/șYvr! <{ߠ,3t'v} )))1#f)lNSĆQuM2ZP q.F9ʾ@8^ai-Iҿ7%J:AN }=˛#2!q XߜSiT1=Z 8{h ~lf=PBL-~ 8[ 1b%K{6i\TRuZL"^E%L},QfZùhÑr5o"3A|w6׸G"vnx©ٔ.ba!c(:$ ZOMM<4򙭭?j0OCE4Ҳ0 QYDj8 ̒S,q:==Noi(I[(]j(&:wq;:vq->_LܺBBnQ_I쳃 9  ۫ٓ5#Q,Vis}~g|> SпTXڶlaB(Oh`FN@uN9f%>GΫ7 vDIsA$qseHs#*<%i/7;^.2B|Nbx=כ^nJ7$9f+s\; Kg~'Q2[S F 3!2݌NNPQ]V޿B $(ݦ7,D:3N43X}ێH|Ȍev^aZ?X=#O߿-FjzZ د-ၶByd JuWݦT J=Qmh?@ZV]?L@9cSGKmcxܴ|"jVE=3Ze׼^W{&Hr*oz4q:~=,ZYLBI&CLhY JN7zp \Ĥ`HA 6uIff{7ǹPa S$JuA!50'YzW8 *oJv dԥ d4Q N! J9~%E%*믚e qy_kўFh\7p*5,6oR4 QWDeԺV@ZT0G%*]$ iۂ5Z{Ffcw)PQ EZүaÇC^wP\?9,lZ. >=Qy|fټADzEkmRhO;?ht2{^U#14.;oʻ w^#ZY3kTҲ34 wj`xQO6TyLlQڛ*oS'GRoaZCĤ~OGA~n!jfF?Q ~X}:ml/Dd4mjFP:fqs_6Y&eڊVi+~ $KbZ`-CP Ֆ!땍qxz?B_<ԀӶԧ8 9uA+w?pu7$P)蛦_Gعb͛X4i_viRbwN} qܜ. eq &pѲ|l+~TQ;Cs[<098A_->IK"_kj+hm2X(GWU쾬otMݢSSCm0oHH:.WUNzJI@:#$Sͥ"Vv޸ !tԽR`NK̀a,@%xI;AJ cUh`0ep"Yzf.A`ch -*@ECKq8`Y jjkbS(""?L%+]; `ma 0(GUŦ }gxeL\<)Ŷy.v{}j\6][y$C,&VT k4N!{?$svB/q0>Q̃ig$#,Xj@{ Oٹ[xˇKأeoOo{EaG@Yj(Ա9po5zyIzLt9o=}t qxG7wr:M+i)-O^a3;lʌ1T6W辘M>iGT_>"7sA`7~1 svWbE(>9T/޷tӆ'grsF yFyI,͞Q1r {ciHce!AOeJElb[6RۗOyfZAK{LF1MLYn)U|}ޞ}Gvn5-[&_183] fѳpj$I{A_-?˩p([!neb`WH4I޵FQSg  \.3rѳ+Ѓmzju 0щ9o(O_3=>7`Ny߂W}:.p"페Tר8".кݩrc<[iL`{@,t8s%v}2-GĦ˟EfKoxۧљC" hP 蘺5YE$z linb7l[#"IpyS\` TwU^!45?"kcaos=6Joe ঽ?`'E[w/<9~4u*{΅WѴ%#ʛ.^w=}}x $50 k2E*$>y?*9wg D9Q.[W!r vAQ`CvM3K\O?Dᇭ;V7C?bNOT[Eͣw^5Ww 0hPyuF\5G->Dh^_[;a9YUO,02)¼ٿ[fMi>uQ~^+~ snMpL,~j侀N>PUTU,sB~Uss Ҹ9Ojo꧞jPN.rJG;;x 57;#Bڼv流A_wݓThMjM&^^a84`}.yް1n վT?q̢y{Fexs]m=Ba% vS^(d0pGuDejkpjw{'jhHtsIJ%YN^Tu[G'IL7m}p.L%柊9][^XGw@e 'c5'2wM'+B" ۴%z#ׂA-4I"CZ:?ma.:pUj<>^V8CFymr]}*=mHۊVTVXMǏ * ֫2 \Ǥg v\>ۇ px! WsxTbsɦO0iX8W:{>o :bp>#݂ARP9>-Qy+=蒑oLh7Xݯ^WW mq4***39 fsVwܮsM}ΎxDJ D/e=jG=|ԴnsӃk}XH1=A5Uohڴf=v˗ R라\9:;Rnx|$*ȨLaw=tHf Ev}GP2* ^moo0iV~?ءZ˃MvvE :B ›*&ٝ`5u[ΑٰDdhPgb%J,6=Tɧ;;$kSW8]o5;e^w>mM~=BL Mˡ2Ls$y>O{܅m$֢Ϥn5N:-;^MW*X:?::bw~%p'P:Vn V/)19JBmZۛ8\z&Xdlq=zV: _d^}|.`UPٰF!CӊTCMh5\.7C͗$A!KJ4@ҭW|7<$}Kfo\ی82QNexxghCց!e~nԋӪi\%i5%њluY} u}rUT2q.ɖeWwK'W̾x')t^Py  "NI= ~-k( ׮+؈:zEDtZ6n501nA6-\[4cEʡFo!pzTF\ct]O05 3G/Al.NR;P)X~sy[ki}R~F R| lmѦҲ6n-m#聿Sh/)cyTj 6ާ|⿞3C鐜P$q9ȁY4hbw<[yg/dBiO1he 浏{zr3,/ I4J|!ևV$ѥW_;)L\JN dhRb6qp@ 5S,I;N(oJ]4oo=](G˾JcOI@c3d!55@/,Ե-e\7{>X4bVum1л844jD00l ϚˍK[ke-eJgIfiDr΀쏂Ple@W_K0&VQeV^v,qGA26J&Bs]DBY̜W跣[Z2gxKJ[)FFG,F<Ɯ 9X, Jzgf321rOtN\~[8ϬSgO=M7VjBtd6!Ӝr=bRZ(sbJԠMwA) *jlnn*ɛ;7T=D\lOP< L 3Ȭq6A;qGv[&:Fb5n^ͶHn"?*aN -"ZT4f\T,N9oָ[H* KUC@FZRJFFuԤ~)``}g&6;!< )*7u;>ECueCiCM BہIr2id ~pib%㣲LqoH|)ʹvK|4LC7d>"~>Rslc7Z[f̘0߾/`D&zn_+UB_,6q^Ǿ~PYPt~cbi쾱E#臖t8O*ωRY94UVXܵCvߧ;k:ޱCXĐ  T4dz6Lu`ª%I⭻ϭ"/I  %+gLJPhT=3Y"gJbm!6ups:QJVwNc`N-VJym'pg okEt$r3.*T߳WMDc(~֪mV˙ ĴjsjiW3ڴW<'"^'.')AO[& JH^ q{l@kJZwnr_+NBR"Q6vxcGYqd aMvYUQ55ꌊa{1"pap1è 2򲊷j١/!Te0 )QdLhk5I-z ͮ>Y[O 6 m=\-Ǔcbe_Z- v?"T;XGߎ1A*hDŽ1BX NMBK}Q}ޏ5h( [glX^!OyX(xDRk8쉉kW8@v5pN,W4&"M'mgUDyIk$HV:=;'Hxb#$]Ņfq􃂃GK N$)VEX!B!xyzD)%z>CkNLsb/(mMh ؗ\7TTGM`FR&a9}IᬒΐW>d`oz{z1|4f&Жx ^4( PY“8*8ƺNPzRmKo(riڱlBJ漯Ռu3O]RP:aDN %2Aޕ򴟝7LAD,u>vD."[M7c>9$;3C#ѡ< r%-c3.{#z/^R 3z$q}1 [ڮƻPR,n뚾? _#y,b?3=1pkg0#}*{kA㢞A qi pECAq$"LcH"J=q>-y<]gNݍXxJbHR<F ED9%1 =s1 A$v.;{b[@e 2SUHizFi!Ev6=Ɉ=8 `#z-zX@h&Ƶ+pHw p_{61'yN(ۊU`gPgaXYsj;Aqւ9Aҥb.IkCI+(,ӈQc tXXAp|\b !ȿ&'% ۼ(~[{u?p|fMD匍:}v`e]dϑLqzz[LeB+F c؜!),;}kn0Ch N3$;z$$&{DJA⽹4O r~q.q8D@!borcOAI~ 3 d#/ݧJp{&y=x8=bBu {YEtSKJI'ZjxBGQa8t[Fj8x$RNne1r9 V#0=*12 `q_ cU˛C@p?D~{]=mJ7OLtM6(_50 $~SʂG'Я9fT3va '4dучiFngϡxZbx4KA! ( ZKouHxɋY2BFrBDl$@_P0X/OM JjI-YA3PQ|S$f$3Pb3p$[S0-DD%tr6@@p@bap0 Ĭ4r(dPs!tg!:2J3xzp}Oԟ}ٮ[˱9; ~5iL:!z72B؟c4zAH착tC2_U/ʰxn-ӂ,c٠Yv X=nI]r^tą9}B'g0bDLBEqul<ĪE*<.~ܝ.Zeb\~)RYQrǎS` V:snLQ r9+h)d#V%(C5*Eʔ9s֥&!v4b #&T5!PJd\]R5s$BӘ!Jj9?8j2Ң~Dyg]Z KzV0(D^_DG?z |0u>Рކ&` pؾ:ςEkʄR#t=$A= [@Yf;bڎ3ᔉ33:~jAmBLRh q6Ms; @>3FV&3ԒlYt;gdĴ"9R=~up߄!2I-Fr(Nj!LX'W#%s{# %^xX,}[d<5 7^sFZ y@9[$Q87( ED," mF$ĺŕ2j3IcIXRj Hx#+!p J<ɮ}ߙ`[hw%E;_AaJ0F1B0h K5)9E:W*d}#"2W55)UA] NFw!ĺj#K~9e}5eɣMta^'2ήt5W.֧-QTjy&FgpGMtA 96@GVSO?"y7AWv1s~2|ܡ@2UY&4?3"u8wgx,nuUZt゚yQ#bt%IdB)QS`8yj%!g*6D`e f?'Tr(^ j9` (qDb*́Q`N nEv._ ZSjk_<3AI$Ly&%{-rZ7hv/ R= A( sJ bַ_E -TV(aX6 IP10Awmh*r'Tu.Cy3IzPcV(@ZS jjC3,BGgPlQ + QyF'E/&+3tjGIm\h boLO8lOLo |퀙?,,:Z!y맫ݟG} Bp6)8Oʾ^}00AZiK VTazlZD8,2 3a޵ UV`ދ_0Ò/4Ѓ}W7sٜr/(|VZt歾`I44|?za!~b$ 1ֽXf8a?qg (YAuB;uprsG&,_`}w=y1ߡVXh%"+ޮlK V;״YѦ0L ZY0 WAY8C1W:1ӝQIW"(1STAA. rBr%֋O'@&ҳɳ.vƧc%% n͊'jb;gHx`9 Me~ItI\._O4:7919!#/(v7b˦a P>YEz^yhz$@E:&S#tVR|4᱖i++/Tn,d~r\i2Į>-#>&3F/ׇPvbWr;RqOP^%,G|fxcՃr~zo(X? LbMែu-ɻoDh C yjh ,Sf66!&w,\>12>hG1$hTmdő+sJ[ѫc%MDywr!W$j6vE<}ˤOy}ŭ͑Z.2ڲns2qՔ zǓpgZ(_,i&&c̾ ͇QoTGr ]!7m9yyuWH᩾zXE'0#c:mˑw#j95#66HY][Bi'aVMRԇiBw!s|_=>8F%x%pjZbaj'T O{jˬrR`\ǰ&KC 9/T8)tX aí.ҳhr;B #}qp & Jh'Bۗ,[oFZ.I?[ d-&aP%mijC5E*5r7 I(P\ U50S,~Q(=[pqcYqydQ(6|[:\ȄJO_G!:*= M1X98 QwL5ն_ӢuG=|2`k|کΫQUDi}CvwQeT+>Ԛ=`W"#P&+>8o{k(AJ6vއU~)_.U贇4}؜lWs鑓lLyN»j[gcoдFJS0XSU*WX,9쭡iهÇ5~"ga<'SWC㠜\pV+@ yXrq&/Z"FvcA۵/HyO&^{0. ^!haV6^7L/0q9,26&c nXRP ̰ 5Lj2Y;?S덚 4E)n`)=͎)P1ؽص)91ytrmr;:}*3Ωb;"9On6|>0XJ$cs10>p?1x{s?'yXi4zv)]2qs;̖U. \oy޸G}y|UxxSc#oՙV)뒩^?TEnθl՚ .ڻqi?b8!u>~+p89~N=ٙ(RU|Mѳ*Җ+=3usu; ݝ\I^~WՆ|zO~|=:;dzg25u/KlT{N~0#ĀIAv,`;>ޖl [Ӎd?TTt #C$h' 1 cYg|e?y?s#<BmlIДL`"nHNef&\w%8nh#Emi}s wxܕ/=%NݏjS|Yu#bT vZ\b!15M\ Xk &W(m;]4^Sr3GZX]c3v#h5`񊭚6]J.F4˖D8m7\%<ݸB7CRil0䴗ɢ~X l'߯Ɣ EKZїmo>*0fWFWG;f$X'n~FOX\S_Za_c6/_>czF>Ax(5+֖(S˟iƐ`8L7LLg| Ki>2&bo[XC,1xAUɶk5%|I-{9z'>ElLR;U O]i>@6Zek욕{PǘŬ/GuFyubmwB* H!qZTF?xPٷ6RE5;WQvd/v/+0;o: ʔr use5xxBÔbLVx$YRl I\v=e#]Y]$ O[{Ŀa)>e_U? A}:ǯ'4$G{6yl5/xIae)GnEP]Ge2ȝ֚(~&q".УL.8[a@[(O{kG#f3TaH0A+l;4(FU蝁!eŁ//V~89Us?ݞ]2wTcu|tIw4@K>"UrQSmHEJ]t~% }R%Pfx]-ͷcW,k&5(=%ktO~Pc=Rnk%ݞz:0[&g6'+&ׁ| U h853ώs6T01d2 g5`Њ 6\:h?6@p疈4kΝv}j_Rsť%>߰^|6̈́gl,wXA=?4 ftߛTY_v`p,$.ڀVBaPGOlb @Jz/ Y xv݃`+4Bpv9gϵOܬ&l jQ|x1+a=Y(lޖ"Vs Wcdv.JڴR:,PFo.U f@Ex쵇L꽣6r-zlih,iK Nj2NY# [./JeD~ajE:npql;PNgJۋD.gC;ߕϙ%3IhWfϝn8n7R_m0 T2Y@iuVO" )t8%T4]Q< ΁'@qsX??䲻Ddެ#Rjw] XHs=crߣFKz_󼖪gX+~uO5d]t<Jj̬AJ$*V (XiEע<^KCRC٩C[2pr buX077zbz9n ğt;r+cIlF0++mX izۨRfT0GBg;'?v֖GFDؽ`.*we[œ_jE}ݞ~}÷YI0>՟ @CSݾ;F[<@㿋ǵ-@Uow6]gt}gg0qkZ3ItK%cYՊ+3O˿^rAJxK~=B#>@% ZF27fR `HP$)t<,iFq^؍'7#$60&7痻 tG(۩{k˰]fc o$f ['ōм$ހgk11㺍 =&eKmd kF n?p}?7\3نh=kg?5&uіi5 hByHR9g"ǣ}/t:wx˶u,eťmQ{?FŨc& ɆgW,PMWޞH< Y2>{-nah+W)þg MF|, mZeta~^@ՊAbD`JXqkq~ն ISeAm+Pu+xm1h0&SB#L"}вxȡ$"$~7F$K'y`Av`Aw2q#ʳB^]j6*~^u/8-z#Ҽ!j 1[vZ]LK!s7/i˅·_ՕS jMRU9 *!Tz|=|]f׿.ʤ7}mW@ѮYW+pO+Pmzwc5%m~g`Qe(}ӬP( iȈco2WrS$E(Դx(4R!Q p=juAhh%tH.*ISt]ЂdC8oh̠ )#FCE:F'oInILi\2xIH(I߾(Ej {U47FB rjtI$ʉѥ?QE 0WLH O~ j&PSG\)Q TȀ%DG&I &jPpc'n @;* [̼)B`+\K=uK״۝2"Bl%$Hp!gH KR+oZA%} r{k=dv4~tc#"BDy(˱"MNԵA2ʈ3ȧxM475Ba4FN%ʩfHm!~9 |5pm73QבBv-) =%T5fQ f^m4D ^,}y긡 a4@teC:,J\+tLeyJk΍^J'cn*R&(G||"UjeR=X/-L"Nx(@`&nu+-3)h O*5'̃Jd"qЪ$Z\K\445a8(t..Pr4 +OUl%.5(Ӣ1—NS*K =UrϤ/gR5˴Lw!25cܵ/p_q ~|U#P$q4`@F#A 㷙bAu͕+9FM#hEHI bIo SZ[ G]kyy̶71J.pu<2H/s g fҹБ5IhPj٧mVk~6c9Cjl5K % =6NI(!88/NJZU)9[y@#%AG?Ʀʐ:Q!&ԗH&39'f;E;\]ˠ%[zaRv:mjE %~g&2⢇#)zPBnX7*ZoIA6GPBJdy4/S?bO"eY^AGOI7vlj!d!}bIԯpǨTobpqVP\%^n4<w=BcV(<y<&'e?eT2{:{0ʽ8ĐoKߪD<҂+3Cvշ/:)my=t<Wd%jZg\egĕmkyy gDxn"߭< k2סℑA!eB2!P6C炚=899Y$JGO:Zi$mFsG>" Lc.'CRc}ab}G-,dUgF֏էHG%zBgܐXRnEؒgofwi fs;*^ ;;SRtz3 6 +mhަ yrmGGm\ QF[r?=||EӸose.p.0Wv̋cv v;IOmюuK\É4qׇp ?9UY,? Tʯ^׌u=#|@7(ܭ,4d9}aYEg4@6"Jk|4vn,\0rq.uAgkmۋ :O:1=h7ɾ+U[h+D2vl; F~9%qnLK&ǷYЛ7;s*c׻eYD:y&fD`sFHUH480' ϢQxӛl\$w2mkmWr"Xm j}nIݴ{0lVCXF_OS?G|b$T~;.Ý:Qj:&,?@sE۲H<*ǃn!9s/\kƗ;ŪݩoGӹũ:c+s-oߟXMo6ܩ /8vnrϗݟgݷcT hNgǣdFZx8}5_*kxzRx.h>m QԽRe$fOyG+21.3@ˤcNE]/4c ʷmNKxw[q.}}|SuBlvΪOL]oV[^ks?tm)&;X噩\hyycP2(\Xp7f[o EYCQ 6۩1l\!xoIcpAyg ^Xjo~]cw2k!>J0ebt&kzI<1CFr:E2TKuT&ul8*ZCgʦY-̪yq!pUP.ÂV 9*{뫆5OU(O4}!Dپ;O^%KWU)ȳiֿ%tQ sn~IuuWk8|nǗ5NDVo9ޮ,'%b՗E~{=HgG z-7W5g]%R}mgjuF ~'-zI]lkw/)kkk!4h6Q4 Z'`onBbi7 :ӯ4@ӗ^0W-..𳋋盗w۟MhHhZvtO~zߚ^7{zގ4i3x#tm P!./Xo˭4w`vghyј弤N^\t5dI3hmskkmL@ÙuGG&2Y#Ld%%zGSㆱwʪړd?#c]zŒ&Xz)Jr%aWCI},Ueky*WcFU7}URס|{0+7-.6ݶXgЫ ?HV.Y NOfgg{KVvm65mFg쇕F$m[h"㷟ۉ]Jg L0}LJeC VzfZѰ Fwr:O9[ lbI:k/$1v򿳻=HtLc:ɥڽqq5Ѻj1\wٜw 1P浏]TXhpw4iTZ=5gcai;{ay˃u Jy}{l2K<=@ޜڮ8՝:N0$qjXDc~]gKs6~Hde]/do{O_:wߵQG;d[ ^U}2OUk*KgEfAUFUn;G/-]E _]7(cOUכ?.dϲ&}o!p]|Â߇}~*[ Nvd2 Ih﷩;S\W㺟Zc旞~ߖr}1ő(>v\e 0IP{\Vc0Vi!XfݍӉ<*1b#u[c (?x6I(!wRiU ]߄K%(\+;^20R8Rc} YXGmb-]WO}ii)H 6{wP,lJ7OǦ, (4ׇS.;z?m+we|o s;yJ#gWD@%U}M'·^Hy_㼬qfSc^+1vm+'iu)]8èM|NoL }/Sƺ1_F\s{{ҵֽm e+≟F`̓ .64"\x8?>_x[\T`EQ"`ԗ_~`ܽC|A 9z"\AX*:7k/ԔGgÁ7da[님#/QY_,6&7&td7ye}E#o^ݘEٵ" NBWwp>{|_~?+rD_; ;ŧ@}R$zzTخ 'JNghC2UoC_B6@kUJ&> ?[a#A/gToFa߄&~hk4;7VYwGsHWeD"id]]G{>,G2vUxMQGG?[K.To,8\z\/.v_J0^Zrz9BG֬7Nf}qhc-k`)bȻJ0gz{`5NU—9Iuw ȧI*uF{}ShtiݯS ڧ${s1E2|[DT(6¼XT\?ZօL%~Vn\eHc&C%e6^^oi*k)‘=g=ibjh_'<.Lw!^wRIM#sχ+X,N?W ܅(08 ?ecEĶQ !Y?" zb0 T~7'Dvg{r4w:QE.dFx<'/T.2;嵥 UqoHR1e^VSsFt K6ݍ'Yi䫓.GO{aI&eœ^hX3aee?>ޜ_h..No/uLFq?Vp%wEWmM9qX_U) )<9J~ߍKL+h1kء'Pi,'p?txw?mu6;EWI"8Y#fl ?%\Dnw? IKw#[cxX=ESE QϿ?Hr>g|bZ3g7T1Ξ=c&M_)|gj蜇 L`ō ͛Qn^5D~!#+9\- b~V='ou4TqѨtU%.R2< w_+ .5ę E,a.Psvpu 2|)Y$z9]ÓgQnY(k=xs߻rW.R<]W@Y BAm'Gy4|Ƥy$.$#F!%bn[​x|7" ܈G~6Ie>dT9gT$AƓfא%nH{U-Hy!K={c=vq|1;Mb;<1@Rޝ@kxOTlvxKaU/|S!|OM7_aŜ,-tЙNQŭO$[4͓#c)KBn|9߾BQ4VAثpUnSWᚰGح˅9F3RS}lGָr_5K]v`uTJ>+>zpa .RTަfܣΝ C;W{di&ݕ{T:m7 .e=wY,s_*oLsډsn8ep%;Gq=`'󩠏,v2lQeGҘ@*s*|RoQjZ1v:~c$1\\K7GqeJn:e?khqS9: Co?FZ'=GH[2 Og IdCt˳7@"n`@9#-KaE_MGI=#jD{f֦qԎ߸y#qf٬"Ȟ/zPp }M7)9KS`_^l3yv rVҊ iНR?/KLiㅪwyJR0;vFu3˕Ʈ͠GLRN"ƧV l2t2f#Rϫf1+PNpY$}Bz.޹ +3S)(5 ~285P)ZMGkbpWj+x^?u*jޒ<^d4L muT@CZҢq^b.pO*bKo+%6$^nNě!=J&s? .E[kP滥Y*3 FrPLNvm'?p8#>SRyzu oS1ziS[QD#zbJ 5Mvf,4%`N %ev 8l^<D@P.2O|Ž =nJJjU<5c)''q̣G>;xĞN&Ct~O ԛ$>ؔ=}4yİHWgEjۼ=7|?o=cٽ۷#dixV5ߦ Y2OvwT&%@=(!Mɸdl?Xw^h;r-`d¶5o{Օ_<_jwV0Tk`Պ~t m8OÊCea_h.Ty.Q )㺠Le7XWa7`qfWu Y6vy,0_iM+QP/8L)Ze|KMIϨ̔ 1U84g iK~Ӱ@Ps xw)2QߕGnRX'—'(%Xh3LkSu\#rF>?0.O/~(Cf% iK4عJeCQOS.gffzuz!1c{.IIOv! x4p=;ʩfJk.h:mrwwmaGw7*Ygi̪?h F brXuWyWsp{FK9Nc!aÚp].'"VcBN-|NPڪWr8{P\XX_I?:`R!8 YzXpY?k6c_|Q}{;x"{bMj8@a|a~fq."JRgtAq {σ6{uppRl-(onKY^k(70sU&v-P/ M1ks=c\12>߬"Ȅ|q3>r/I3VV6ӜK`Nߡn[ڳuB.O>X_(Fa-^[hTaH?rWwAt>[RhlJZ]_7mn]n i/ M B/S闃Fe",,0;& C ۙ, e4 6-R\JVFREܒ%>2L"~^Iq:şdWloqͳ*5T5Vm[oobF[ 1]73|B;[L3DcwꦫsMU.WXGcO+"72 VN6ՙITO4'2 t|HvGZ޴4ᨡT~om^lZcs4ED)v}"õ}9I}_ )))N?&vBU*_?Z̭=*tDyb.q^ff0::AQl;޾dJ%y;t¼ y̙跎Һh9iZ _f-$ʰ8"Sz*qݓm4h* DO\YLon\`ǶG#OaGǗE6C3UfȻ㙒.WTtT0wa"=bIZ5SSKtѸ8A ꎳ =՜P'KP׻;;`MvQ $tw:Z'׭ʵWn.)ݐkaS˩)!{{N~;ɸ3ۄC&q=R|4`,U*KkE/wNz|qu_ոb\2|t4  B$t<$tYx`7ޛx6ږSDYPT{d>!#ѩK~r=JCb..y,U>|vp`E~GNZPP0hPTf+gw*oTS. w/uD{ngj7| x0quT^’μx\ĵvA]׶ymgܯAki1k/鳼5c w}*{zDBME*ώn'YS M<aSgv`| niF@A'FI_RKQ;^z6c~N,t4" fk"rr |jĹ.</߿_b[8\W7qr+ow&ˡm]9H,GGQ'4gM[v9y:Dr| 2w)uN8hpwG~;Unl_Snp1 eX(Y4: UP$,41%!%/$r8.^_]s$\(Ku=L_d7~G{Y nT~?..AX\Ybߌ#5?jSΉH9g͹G{ɧF4g|l~/;pqUٺcU͙4rJ%ぷk};3M8)6'Lምe~Dȓ{KJIXEV~VOcBRzHx q۟Ŵp,.11=_9qSۏϷ, ZQ[)k Ĥ`/wL|%ҭ-_ ΗeJ9-r%z*fW+G )6wܟ۹Eȓ (D{DĽy1qʨd[sӧ i Dn?>3$_e ϓRPTolq}N7 <5+pzwJyp)ylbW?פptAy.t9W G7$y"173lSuVQu-{y_~6S[oD#)ɤq,.@mQ#""qibDF}d^|@%ytuUh+beejɇU %So SRaIjsZd@e.VE\aV,x;㸞@UqKrcq:ɲ!⃼ZDM-;g<]R*UHqtE=qmxB@F&Jʉ 뫫iqN,Ɯ^BwmjeHs"@jI() I #෰jşSٮҽ vyqQш^Z{/zŁdOëE\b'1N'GQIYb [u(Af:6+ܯ'O࿔q~)?{Bd_w^:8Cf D1e-%ц3H%%VV~W:Ŷ}D;,3 c:j :ڻ3Χ$NoڍW-GK逤` Uyr`E:̲"KKnw$W(|Ɇè.&3/E1#9'mɟ k̼gh];}Q3+&hHC %5ΉO#n'ǬY~x7:ڕ|˕$уHG+o6+C+-"K2[&KK(T?N/g.gks\8H":sgrTTl,_*Ti=OOBęY3 Wo*!Yvt6tMpa':pmaz6*BBd777\ugi{;߫pp`S1TFNyO"z/@uq揀BB64b|Ǘ6ݻ )F=|Xz-c k]jŘ/7ag{;l7&Fߝbs _G 5qYJ WOq+5؉?X^>ٱv9s>e>Y(':>[wr{.g:FJgvJ$ =1 dǗ9`MK`Sͱ/pxUVKK2)VAF/=zӭC6$흙:b)vkBOo??~RN+Erۺ`:A2ɺS_@ovt'ȕ=ۍҒW~t=()}O?~!--6 -vtxsn"m:ײxtfmO]آtuG)Bč糡l;HVx7ͪD/8Xw#NvQ Wڼj;$PloW(JOx` >}"sڼ.gTmzmd[5 AGrǖlbI[45+^{t}>el&G{v_p(E 68rfbU!bʷ1D8$:QV+y캘Ԫw`kVX۔?9ެ\(S ~OwLOGl6",6͜FپpfY/*fw(0Dž8c fhvm?}vB0vM !+1 !!~LK } 5/g8no3q8b:W on#gOT.4.zxxh\%g8yxr5rB bG>6W¬tr [9~qul&摍/YNē8w]7|R?gsK64` @K" b]9y4]]]/TYLS7xv6/f}ysҤB:pDfU]RGYֶϺ p|C ]JkKBI*Pb _W-Z>:`4VghXF|a0[!&~9kѸ_J dspJ ӭ!BZ֖ČOFө?@fOջ>i+|.8)KU%O F;6dߖ҇iO3mjj{kLke"w!$TjG,W)_+*@46]x>ߠ1`3~kݛg:RN`:%Pcԭf1hdI˧urx46*!]ss:F$;N_wiD%?gWzSRk& 5YY^<sށ]o9Zpr2DFX+# *K}bP}0fNp+QvUʔ1`ߥAxLR*2+_x[.bxI,;MZJ c.u7E=Jo%.ZB{D<_xn"i57V(g;P !\zrgK2Iuw4~4eK=WW<[&B]r6/E@j֥?oC{ڎoΏIMza?'_J'Ԟ㑎>1ױPTY : >b#zyy cwi=}11Plܒ^%b2.ruE',#h2U/H߇IijޗW U,IoN$l6hP;lޗOpL'\Bi=A-nڬ)ӗ$bȞ Ps^{RDd$ݎGcә*5:Er؟Oʳc2P.Hrdvɖ% < \ܮ8D<&j^>>)O=KQopUVJOI nSuwMFI'2Ç Āpn5k;>8ۙ$<"^4ܝ3xiQYnJ 1Fij [$]. E񑄇jjA Js,*!2FcLV_bcAđL4+**8ƲH]Y672"~F/"66[JZ:.jf*'?n'XCmpk9o__P{@Y6L-%n5IgNuj[#IHromCK-JR9p_C.iӨkdsq8]TZ8֬l&X^m|x*nbDQC܊͹}\E:p7R o;)Uuuu$ Ct_&UΫ'fdV*R`߮Qin_hgzzjQ;h t$aDVI)_[ia>qLxd[,!գs$M(Ϫw ɚK_j/>Br+^RCiXR)"+:@L}aaa:=DMM X&UkDx*:pi>}g Ԭ=5u[1ѣ :X|Mm@dueﳙ'Jm$Fι֯A`,ݖd 1O439.דR7ߖ>gIjLB,#bj fpTlbLiZkJQi"x!˘c&͞J}w~"j@c56Rr+A˰ZjR˝N* :Z_n6i~B׫Fe:/v6_h7}{^E`KAa\o>& \?~!2'bc?hRhxpFOΎtѸ42+W77'݌so`nsr*R4yHmPHŖ (ݥkي!=&FPAxE@O nlvʱ-4>\-K9B?aV TMݩcW{HD=_U_n=1>a0L`՚(4HƬ NۛٔURJt54>/rO4#RqNC%yGe/E9kE*Ot2"$$L-z_;bb}5d|O,3ã...]mC3AusȌf3pk g<9V'7GWMӧ$I.K R wSUlY/ Đ,g?7ݙ(F~bΉv]k>t6/5]AEV5gT{ \`qYU|y*U/˲wE~C^<+s ŋfp*,]].[ۓRiLse*ހtڼ-j]Z#鯷$8skœ,& 'KwvL?sK9_D Kpw77jt >iZ.6"oUM'L˃b\C5[qWXnɜvGhW)+E-O-_'+ M09㽊- {1Q۳Kp8*xN6 ɁA1-upG쟳fb 2VVŴP⸿9+s$!S@>4sڨ,[08 Mp.tJ,sX"{\!Xȇ2YDn ˔t˔"ZsȤ+V-kəVd]Q)~3s,OJC$q`Zzzvi)}Q@ticd`oejQ7qJZٕj^{UBs%+^f͹߻ι]C&L]R<󜺶­Dg!lN$R pc4u4>p`<͟9bDa'qacwApE KqlpO=w{>H[qqqGWU K~ݙR!FRn84ZpY._ǵh+ELg̨p^G*(0Dx*y d ~J EI G,k*f- ¶ oo.lꆛerS0Fkk2.o՜{IFڂdsd>*!!K$+L0=X-҄>|b[Qܧ1Zֶl rʟ`>W ZR 6EPަ5ˬjSVNN C Txm0AX@`XcɔLz?PRڊ;`гU+~j@A7}Eӻ4+Pnq/.. yh!~Z|컻;*wy7*\IEuEzB›%'gl2 ^ZҺ1 nxPP^I+ n7"эõ`ZL[0-2t+^Rxz_.qxǑ PaL];*ĔJJJ SŋA''\HSrurﯿ N֤ ej3ќȈ&u8 >5 ySe-7@-qrbp:ɴoQ*34й]J݆X0]l8L 7 L9pS({(dB# 0je_"7* T-%%\tyxXTb${ "PEt;򥳫K Xj\k3\r;]{}ʌE_*,߳U̻ky_AzS2^b~R^bvY&ve֍1H/Rԏ$0*+q@0c*@ˆJR#F1R6C # p(O]UxD$C.D1rvW@(X#tch:C믖nPX#p@h;"H ıYDJXOx1csݞ} d؋^-,QZғg+1HL0VEc+ٱ5osUڶZ n>6T|)aWwTÀ~)UI Fܦ8^ґG5+EyW&0xw%'U*]vKo$R ,TyJe:hXX IP.f=Ǥeއñ\j66 M_ _`'MbjE!%ﺌ l❂NSeoCٹ=匲4 bwt ow6??uSG 2|)*v-mjF F@nuS?G,ID/%JJ ]Lxx߿on{LpFuzU@5HL+P/pX|߳pTa]]]ثvMjªl8s95ØJn[Njxj(g7oFn.e!C#>6SAqibP٬W4^,mPe$^a1$ \EvAȾJ)+tjeu?lVZ$[߁Xb9Tif#͍vht:Zv~^2`斖Qk @7FpՂCM=&ȚABD ݎpߺx[[[/./~NcNV,khH*KF@Pв|zyhqjzwNmfH wcq?i pG~bhh~2%)yh"ٚnZ@uF7QyuЋ5{)cjOj~ ɚƶ,4@3a ݤy~ۆU.O57Pv{.@uݹuut{=I\Ia* @4m_?- {stL1\&a G$`v{eyˤ]Daú`xh[\t Ǿw%.V@n6U g˒񽅄?>ZSE7l砉{x;Náw+h@d9\j'ex<U*6.T9q=vN7}voktE3 x@ȱ5u$p+{ MNy-3֡FsUL; n daasʕ˹jK٤!h,WQdBp/{(CzXTlWXRM(W&Ej9/P[[[_w}u8&]F :*,1¢T./Q/~#|pgbY4`t=oXz5Tr~Gpԩ@pЮgox57x(Os8G9Cy`BܽՖUwUnn{Cl4jj{aߠ2ycޫM]80/אs\(9_yp2>ᖘx; b7Y{F1Sg*˭n.$3IzJb;اY@ew_/):w$&aĀ>Z0sl6;IGVC˰uL"^ްV'J _9kuC %U [fip%늈ヤ@`)ݖäPh^W'=WYdF/ܬV3 ,0ZbKlon0f*d}){.{:蜳gۇPdqqx{ @&'?LQ(PyP[!nt>|ڟbanj6[9-ku]nCVxHtui9/tzc[}{PJjJ[:;> K`oѶ8˽!o5I1uǢPpL\_EW=0<<:bxA8B釥գ+FE]p J2rSA&IJۘ"mZQs;׏)3?kP1˅;b8WSWPaEij&:ILBJꇊ|TTD/a^z呛KQRTHAD(Zx)'(=iZ٣֜FyXYXjlTncζe ǧW8] '[;D`@>JNN`&C4?Ƿo:5_%&>܌ 2r:jV--jwT֎*cK'r22h w]Ù¤٦} lLLLEEC6gt g*-<έrq hJsaRsYc<iCST*ӊgT/vl?W!cqa=JrJ4ֻ}16 QIr߷nBAVUS# | \񛐰p &_- XrBW,OAѳʎC"`Ig4i_3Z/w>j\huxOO5Jڙ[9c;s[$p1WGJ[`]רT_ǚS Ic˫F[ʊvE”nP];1˸q,_d?i}<8 8xxǏ[F?*!!2Ç*(9'!!!0!eILL̃l47h'%"w2*''iNY@+qh=) ^WtASxބŋ$ rr 2dzcbp  |&ę,jzH'P8Lb)OH!IKwsZSkRlϪ?t21:gO]ՏPaoG<=<+t8LQqml~+MXNP!$74)ˠ!"w XQ0FVfb{?eb`x#tɔ+I.'4}*u4x > ,fX`Slv́:/K|RP@ Ly}?Tc~ t?^@)67mvH}8ǷN6L&ioےZ*()i\rY.@7Ma0 "CPn$盱tvkJ9ln W5\c9;G28jN"=,+|fGIzңF 81ݯa9l:=DObbm 7߀Pg!H]gˍ"3 B0 Ck߀bJ μuAClu '99LdBP6v6-ϑ}{<e,zb'%Gw-q;& mox5`1+ZqӊaoS:n@2u$}ESOJ%0bT?^#Ze^13c{0=]tmy.ґ7Aʩ0w G7=jgֆ}}}3j/Ɵnٛ~ g\-Ygk s̊չ\w)@Y"^:t|4Qʾ Iѥ44^A8ncZTZ=a?6{z`|T\" n3_g4EYmxnI(]׻V 6Ciy _|u_؉L sysW{}kjcoO",,͙G]lMꞿ;ո4z-FǥLx9ϰ5m(k]GImeKH 7FV<*6jʊ[˃?mHW[9u`s \b`䰗iիW0QQJ bo[h<ۙ*M(f0>[Һ/)/AB <@~߅Mbڛ} ++n`ហMt⋢RYK_ہ_CT|Bypb]]B'չ:gf=|z$0L޽{s?TTTwLsovlT˒h0?rik:d=2p=͋E9946:zzZl-Mi[XZ6}%O<8JX5|xLS\twpoisX4nz›+=ъ5֩v%<_+rtjR! 0AAAoj>(D< BͲٝ€l 0tiQl"[J?v$4iVlES|JVyy_eڅj`kkyK?}Paa!oVNF4S<Ϧj͑9-mP7(A$&MO`u~B9ϲ%~nkr[6dK;V2@h_fC^7[jhHeiӪMD4OXtJm`_hV44}#6_~i]xPR"=\{</NF/Y(1Z'9[f8 06;r#_3 ơ4%I*ǛH HC4~I[5`4<R2E~0\'xvs$S?zzpQQWGgrW( 4*tzn(E9];:lSsrm6M߇W ѻ"w15Ɗac ;+u7Ds/\65UVOLI r ]3#9/&8LrO7Jnʿ-tSˮr|4*)9۷h8'|&q}$SJ1અKĕ .W] A֤KZկ =~' wΣܔ\>h>,/|Nr`㷹?& 񴤵Jjm4Nիo6nWrOĖxMaш;=ąͬhuA&/Ejm:WReI|P8>N#Z=P?yIA*D0Lq킴xNv⢢Nx5LnOM'J8?04M6 ؟ԑߚk ]NFR~9Ć̐:[o1U{_m4 Uۍzz::HŚ>➠LP PƠ۝@ypuȃq$4CѤS?i\*{{~?b4^0 Z'J|_HBfau{H܇[MIB{a-(݀DzGڸDvfd`wr9uƱl1ZIJȗMiujSVj =*]ͳ}¢5_NeyH2\&ŻD>/qo%2(>1m2t4 vBc|+tPYY,:8ڀ)z x׳ ȵxT, x55RTQ\g&8pvvvZ V3NՉ!\aI殮.8Z7׶ h ÉgM&Bm~ϟmwv}NTEudjbrAKrٱA7~ :./(GGPȈr@>)B:k2iiiV+}I\閗xLf~Ƿ\E:JZ$$hvG/_F5~00RVxp~/)vtt400h$3S%ed*+lp"kY3Qhuu:ِ-=Z46 {_xx'^ݞMӡf*T?B8UA$P]l-V32pw5z]w[l0?sK}8S@\K>EACHsec4}dqa/"7߾(~4àtuEV$(DkC61.:[bX1g;Y)]r+++?T~ӳY`rf}#ЬOq/*|h/חWWДTrVP45XQ4911Xrhfp؏C yMss<V%#㡌PdUݸWOL& %j+7Fy,Y H|JQ0HuXRM-ض|=iDPpۭϟ?M oj&IrIWX} 8TlRi @<\]NN(*&&qo ~_=њ.7[ࣀ>5]V=@O)"8wehxhhao/FmcwTf6 qInWdsAHxrsX8oNO*v5n߻DZ !zذPV z_F)j\Hu0 ed~3j/WuK8 00,&IH,pkB`iX~65VZ}/)-]{xߐ :C7r充 ^Y\Xgsf:ۛ͑LbUN%dEX1:;;gfQc׫B_W]cw&y8*! *ښ) Σ .,RRzo6hOijlmm`#UlN|.7_dUIA|XRX|P2RbbY1/$¢ OG_9]c^DŽP"@"v(^ 8lJ4'<9 53Ϝzxeg.VSHYJJ k>!<)<ܳ<N/ tpi]xg]s2^ 1:ARIVVv +ϏdxRyjkFb! [>{<;%бz<83&&Xf7?"QK9xF9I\O@@FIl6[ r(%XZY[o%. xcukKh8C<#\JNtkTxrp6>d,_UX@-mhH*ӕ`(CLSPB{@E2KKgesSpP~9(D+Cr*!CxLq"UVsVrҺEOH{At/ߒ:ֺ$+[4`w lr̠*\fqqTTT*~? E37"IOL= 1~< eyygx>A9eI6U ȍK#/v=Khn72ټXП< )=Qn~=!ߟK,W S__лq*ZwS^8o|ĠmhIoծ;q٦(&''A|𫣓ߗ%];qޡ?#gWX <ᑤr8cƞr@*1SD6Չ꺴\C; \XDKpkQb|B?w &"WWC`VN#`lgkj:|l# @'k\$[-<.xTꝷZ_T4.LZY3Ù{ ./oo*f2RzYT<^`:ŅFw$wwѧC;ᔑ;80>:, ;;ƛ[ٮڱHWm✗3*Ҋfwee ذٛVbelsޞH1|RTἿ|kRܰ*{b|hO ##SI~,]\L;#cꋍЕ#aQ>UU,U&'O~-)0'Rht ((fOdjv+ $a!!!KcJZ޵ VT }FZ+A^el >2RDvoÓtLrD@FfT)Ks:mGh!/{@Rxjfv6v' _ޥ{W|űPڇB}=a*_r.@бR$աrQKwdd>GG\\\l/ݹ;U]lZ@~),7DJuXO?7<-))i~9wDURI֚,?##ǣg}*JIK닇.S"l 9.acwJ7AWu}1P܄t@ {Q寏B/ Yk^| F2\~P`"777 q|xR"'8/?`0=0R ߂-QZX Tųs07/; B>4? QI`<_ʒ'ѕe910,€UU%Tn{ b4x@?2$yzvB{La; &//ywsyu @BieeLPLPllڼOBv0ѱ0Tm&U fW 0`R? 2@@"ik8^ ,1LeV0#A& ] KL !WQU ӋJ@s.Ǣ Ckoo7iVG5Ƌ@,7 wWtuF../xZuA|#Gޏrb%\\C_߷T>pW38L(N @z+K*+4Ųϖ苃A[H@\iQW[@%ĉ `)!4 L^9+Ӛ-!׻;j#ze[pZ8~Ù5  D5x 'wP/>vuu lx'5ι=XÉ00 8J5V' FPKT1&N-^ǔk{܊ZF e)g( |Z۵!dsdd$ӧ]k2voӉ̔rw<;+!0~"2R/d+81txm\l^# aifqv9KuU\Z3 Vlpߵ-2ܰ[wחkԢ#dq`u"r"g =۔͍ d`vuq]cꦇo}}  t: hm޸zߟOc_E6_vnivlǐzoˁW2nL8z1WZZ)C(ٗ'JT\B6 ;!)|+8*W@l`8/bO J @fN"#VF P?n''V@| 'a]xUln zJZzR-9>>~%;mCa}??R*Ɛ /h1ӴV񽽂oPѠ}C@Rt ?+΃]T~pHƛQpi=j I_d mϢFU[-<_32{f  Mo+6:o߾ Bfh#wΨeox v.A._S-+΀^>gY}> TWr c숰n|H /cqXX|py] :m8Ł/̶[)))Ђ\56{1L rMpac#[KI}]0*}dbjoEa,`~_|`Xiә/sŰR#L`: I"UF1rS[8\tauElRh66 ?a_F''(Hȃ ZXa>/g XYZw#}(}ABf1M<„n(Z? D`}Q@t0'`cEZJ wԙJKOcOwff*'X]w˃1OR84NMS, !W]3DWV@o\*ԛ tLL)Mצ h_n'ʃgffFo, G~R" # r @.V0YO`pl@KhP.0y2r@ӭHcVНr D8P:lJ\? {Rwa*,V^fsLf3/}T(݃m\n?K~FqebD08KR@x%y4 AEuAy|Zƍmj@EyCŌ,b0o^,_="`+BvӠ:63+kjy _)r[+w_B퓵%>f¾^ŮIP>6`JS4])XdL ,7qOkL=N/4QQ4Mp KUW\\D@eCGKL@bi7E?7,,Jjkk5 n^spRLB;;;zz>@ ]cx{ qeQmOY!jzHZ\ӧ@u>'Lч5 s+ JSRS%%%ԿߺpT_p^]8#5|T1i|cPJ`!ɥ!MiL!TpM+۞XkIRX/6$fڋN.cPEIP)o It:?Bpp0nlK iۙztd maW7'(ģ%]$v{"L-95 a4m&+}p`!kx+q`xVĬ_L;2O'w=Ȉ~kld/I]f~3j`ȕf1=V*5竍_CUT& wPRWF<zPf[!{0Q/&d\F<]4cv6"|jUHO -WvGtJ`ΎO=* Ϙ Ѧ8[E7S4::.`ʧB3ZQs _jsuΝq *ZqmMS2$$K:햍Ek9 4.,X-{7CHk-)%:B]tfl %'@=L,J:B`*y6777]InWOahy?}vccoɟ'Q`BoWԭ:ԬNйq͡ ~!!!!@KY 較*FÉEGGjJfba//Ro0N1aWTā=,ҩ66p0 {#* @B<:-t?4w\q8Ѐ5B%}!. Ɓwwb^*EMLL*4n::abJ_[:U޽ex_#p5Qh:ڳ(e(Cڅ5gX,|ڙz 8ݒew|C J%,Ǘ8/iuKTD3 T&G#עuMĎ))("hb,pq욅Lg-*h/wuc(`ŏTk욆_~A\9vA,R珘_b|M ӣ큇nV m/ ,1qTr' grá*$ӓ}}!/[7&KHB8=k_,֞&]&Fc`bj]lvtw/Q ƥ1«'&& n?add_e TIdGA^#TPրw+_#@>}2ƾ3.E#"Kz,p-Jn[Aخ:Y'9p(f`@&5 &!S/tN TNN3S֭.ccߠl.b_{zD-:PGhii ͠ VqhO| /7/ VkC^PF^NDo\vc R&c@[[+E &=1hKhf7P P)777/~&FG1^uSKJI}c0Uliӫ/ {{Is1Ox-n>>UuaG*uȿ&&Ǖ+klrgǾM7Mj͏@ |L& 6r*Ў#nŁ^d>8ZEѿȠr䧪:+ӕ|P8ǣFFdh!"7i?BTA_<ݍc~g8Ip-D2BSS TޥvAz+d94Q[ˎ`Im wLLLa`bvMd"-/7m' wY UDۃ1"|P򂄄d*bKR SHHhdWLLF+Jmޟ?’iֳGÊU%$@wtpa`X= L[$DK KZ$]x+pX0Mv-藖m/}_S08BNyF=mF d'ԅ_[K>.Q3Hyz:x>4Pwyi]: D$+CVD[As͢eke St 95R}a^FS>4U 6Ψv69}j{ͱ;P?_3̜9yo;&o@OCg`` 4OjJv+ۨPf,Xib3S@|C{N:$277-vp>><$FO*(iCA[[}1?>{k:ݖcKHxP:X*2uu]Ά9%!y^@ddIObqPa(Tt>][HM7E=]]o^|SgekKӧ\zz6^)6w0m;8HX_ b^6_WWNyՠ*+aLPRRr&wO-_=ozsŊ諕U^ dTT!3emonnHч2VPc5K)?zm&"*98I3'IrLg竼A;r7gYAh{n,G0]{<5;- [Wnn\ q M?CBJk%z&Bz=^RB-8:JaiZzϕJ 9W,ɞdF<: PܤK@5)W SgLx6Pn: SQQ1h 9.hx6Xfەq:5!V{Mlxhm-jd@z:14ZETX,~zlMZh.T/iNu@# Wا$oNπ)9mȠP2Te 6v,vpq PBn B_n.דf͈ԧic$NEh冈H~{#PO@uZ`?UZHꜙZ=JJN)*x6hgOڽʻ;hnndX\PsԱ4m P?cA!uT$Պ@ȯ2 dTpJ]%" K%-(@쳧{GToqPHGWj[amKp^0 ΐߟ/b9<8<<(Р*VQgkkboeO'26)`鋣#Kvv0fӃP"(e~b\34M)ԝBu8[8N{suݳ`-\eA*UTUp 2(A\_yϸUxwÉfg/?RP λ69bճ_ ՝k7?c|%YBLG}dׯsx%!a.u.Sۥ@j 963؅.CR f$B/?gTV." HP$ (* Q@"Qɠ 9% sNJNH5޽s\֚kV̪z*9#N 0'޸5Շ LfG+~X@cy1IsW o*[x[ƽ eÍJ׬ɀ?K꧐?Dɴ+[\Op l4((S4a\܉z /56ɴwIynu66nipI;;]{8:#4 Now akW QKT 6y8j OFdmWim%Ld—`RZV{4YXCjI___ibdpsWW`fdb "jt,4á䢫) '564פZWgY,N<[["{ncVUs6TRD|1Uƀ6;;O':u4\nXlR]b㶊aFș,boj6wܭ`xswhiXAaa{0)[[v||1>`yGqTʦml߽{wٰ\e5Fe=)SyRr*Rr>:[ Hy[uO~6`t ' 7Q֒9sz,LR~uHۚKfU/E EFRy%ܺ~~nUfI N_G^+FMtZR;|eQXFe$ w&hG\vg7X>%_`hgI9y~U{-bk#6$ ( 2߿_~@h%bϟ?o M+I=20o-}]rw~X9L7fp.RS2;oLǩ%T*+xũl.;373u߱29nnS5nGy7u#]s?Woxͽ8v^`妞J?Q(Q0t͛#;Y^;s=x`B=')TՅ4ufZ+K™_u^pte*STƎ{ ܔDUoXg3H;PѣV~za3WRkI&m_woFrKʩdνG"heݸZ%C7c`]{f&/l72n~uU|tAj5-Ŋw`AUCB8փed`?Ufjpf}tȲL;J3 =<劦F f mvDqD9z[V,}LN-[tˑ%';Sm\b$|oAib&5\St\>p@ckk )bFQRpU^YJ^l+>ǩ,CH34Ɨ#5 5 Q9Xpaadhrt+fVn޿q t9z[[/Y荌 ]ijjmR9Mͳj.jif$ OZIO%vb6Ƒq% H@2w:\!Ab|Vy+*ssD9 檪*x5do+a MO~!FT[c}~_հ--ЮËKHnF(KeH;7izPA%3$pFD[WevQ۷([TBWUr:?Q5`V1TW6TMa0{5]םh q¢zow\HٓWf' u똻w#MN>T#@fevd `c-Flk]r%6'quCŧߪŶz+='EI[j-{: vJ#CLG|_6-m JRR'Hw:)s ~`: np/ԇyx?!&h$&"rC9߲EDDNybޞ`TcQ|ڭ +֓2GJs6G4k1OQԓz+nu7ZnxJlndnD`="ók@4ebx?|baq $jęo] :O#MͲ G|Ūg&ҀAo;zA08Q9 J|/t?CmpO cdT~19 NfT$T֠>vL(Ǯ^&chBN{nEq/It`bbzfIKK \&U[{r V;۳x(J+_]lzZϚ[ jmL&HG>}#8T1e? ORX ֍&W^] Φy&9KqakkKcw٧N;BșҬt,::]ߗ**1DxwBx9Q:o|ey .؝FOcqd+Q49:/Y;a[ -PC"?p;MU.//_ , +ԏ))X~q h=_ u5O&8 }4++,Xqgbt"PEY4w%f!]rlH㓕Hcogan8߄ QSpj=?mLj20ࢗSP ۸ϭIܴB6sU%! *W+\뼻Pq15 dSPV2O9[iǀ9<Wts|zy1v5gߵSI"F2#}aH.e?%,羅s9F-&''|5 9ۥ$Euׯ_#YNV a  =PIA`RRRttY(tA$ PGPV]TB+ր 100p^zoq!d!;ʷ1bk7P1s͙   =~e` %禽&YVk}} GDDmhrR?l=tZFЧ9K__i%m<Ġ輫z{I">.joSMe2^ƣ&$$|P {3j}jb<4,Ϛ 0\VҹNs1.++Ӱs}߹ȶ[׷9s*)<9]_2QFs$-lYa nG&&Rbbf#?v0?sKDqWDd9%wnvVRFx?WgsIHHF(<ϲSp288SM͍NFӺl=MW/L)hNXʇ(|S.qkЁC/qs+֡,"u?t___V>}s\ã랉 kwOӂsߕt.ߢ |R^Y f:oO=22J٨mn*JjV]Z bKvT{J BXzX'D`{K=*9.(H '-|񶥍_gn z(2-{fFgl'i2SbۥK{w5X3Yzf#_ٟR;VJU6cGE{=!|| 7){wfh( 1c_58xBjDSGzz`v(b#O䈊PA+KKJr>54v7ZD;,&FƮU%zϬGO;$b҅4"7Z@{p :9P -H5&wv酌auؼV/Bږ\GiŭB3vww-]5|.L n^ t&H~ywԩ/ͲY|OE?]jp<K) _Tڏ t8֎ 6G<-)75fD^+ޤtv\~Rׯ~n`ŋJeQ|kx(965P;M9zONq-v{3=J޹eeZZZOU Lgq1t&h 1C' U{:d8:$L!)rY_` f AiaGROCP& kQk|((Olmq1ig'DSV32V.h6oʥ XY]Y#(2ҿG'^ / Bc:?:(L/_phLTuOӡ~,u h}~a7y'+\SSS'Tw@]t#xB8$\#NR;4~?,CbAΒDO#fw}vvY>=‚)&??tѱfx3zqNw1@GC_]sfqhc٤S$$ʿ. x'yFH=fU䶴8":T-,,/%t70pj DVluu8L p<$dϊzkZmp|N[٩Mn41>1:NZ7/Y"V{{K ֑ # fh//v͑KWo `4qߒVG*#PFOOOHC7eR#AtuuE5(v0Nף1)gޡ{{|Tʯf.YYY~/: ƞxq|%f(?e(5l&ukOF1ǂMYоEH 8L7LkG )ZXXr;L?T^ԬY_~M_N h?~\ ޥvO`YJ 3'{kC ~;O/!zB[[e`5G18 ?Z.s0m@_!O+8WRirBgkq]^֪>aoKt b+X+DnkYK0N_[[[ 2Hx:?a˫B.xpϒ~||7tΏLVfvl60#GLLzX P}u("3շo)2 dOz%ɆQUӷ<} lUUU',̕,]olS\'BF-g\\h&\^[%((^u_ ؄GH\zoo/I,0211~~A{c;x Xs$@늪s%%$ఖԬ2IZ\ T.4֩5/$X]`Q-G]/b6]룯MtEĭ8<@ U5KΉķ@5ԏ{-_\_#j_ӊ5TUb7T]\_&U;7fkmd$LF j  ē~umfhL=4NIz`&eӢ$g`ΎC* +Ծ?t' C `ؾԂ7T0 FºHsn 9ծ5XSxm6q LbkJaC%K%Krد!Z8y rs .1))|Y}=Nbg(mX~D|Kϔ MW/kVPQIQSW9v为|m-cF$[nIoq'$>i2>ߊ`+y`wdhlurE ̵ =uw:OG`jI\i -栖`6~wY11 0P st}Bףּa!%;bVkӲK;ًU f.? #cԪIBS0L^Q@WTuc1xL&CY8qJCRWzQ% (h6v4TlAYPtW#u'S1r/AL VoKW &eR :/a?8^ƾ|]TDế']LmZVj3s9{FGvWhpەP T@aS?FߋZYJ磬ї.DѣG+{5\OV <|ܺ{CA3\s8p]}SS/U6 KKw޶~+'lp8IqL=@mSZۉ1OZ-EqV/~R00HVn*Ĕ]^^^hDvo)CU-9QuS03|ɩGػ{lā 44ׁI63LϏ7%>A.k%SxݲfBɢٜrλ3$ܽ{n`G=?&>B?W Clд\bbB^ၳe7[\6 9ΒMU$8SJUé\I(=`Um"As<;h>ߑPAm_mT Œ&kS{>0Iλݰ`4J6+"ao\QLU9q*5'55=#,q?cR>_ %fWS?`K. 싟^lpd ί4Po}I21.Cxgbχ4ي߾Ֆm˃-A#O֝;zQί Z**kHeDoG m]?x=?Ҝ^NUыQU&ip[ᱩ)&IvchڽQqA(qbRŁPF,T8ȝteN:7|s*`̓wzSuj^ONkζ_ F /ߜܢgMP/:F=41$vSܼB[ő_=\i$hZ"ߊ?ڶqD3y t¢r1Jʕ{ի{ͽ|DH?6A=\I^^'*8Qf*(mI Ο>5vHII &2L ^zȒ(Xf*pw@D!8BE}[XTen!]Q_K g,l))黎* -VX2ZEC@qsZ~X#iikTTT㵾$ttX7AOOON4#a ؘ)))Zt꧘вa]wu>B}n{6%S;ӑr)LRn| 8WSO·i m >#Q`ΰhavV9Y;jI>⿝6[g3,D Uzl%;nl6i'Iqsrrx6NZe4NSkVwf=ݜ*rܘ0p,4Wɉ piSFX*V?fmm1g)jke9=M2VnSPY :A@'l3o_GHziڏ,33sy_E]"=vT:`r.m cL*/hz.f `Shs??3}_䅽zEAq62*U=o[h]_~i52 WǍ(^ `IqqMMM Rn6w>]vЉ5qNvPϹΐ_tk?_ɆGDK۪bHv-,~1;kiřkFSLhotx|UɟӧOє+Hϐ]X쬶F++(FM^ЖG)'vɉDi!BY콧fT٩!(%K8)Kc='d0]] !w(sEIMWk9o |ɓHhJ`%7[y:Cxn]8;Y,N~{ozVQl,wE`]× 쌃70 LE@@@S[//>;;wI ?"Ytw}̛w|5DBBrQ^D :C ]_oZ׽9 @5hR6AXkМ##e7] =H^Ǹd&2,X{G:'媾~ﬧ/Mf|^pRpfU.F+a~o7R9c mu%bbbM05e6\7Z^_ihJtoFTv?oŖ͑ :X.t&- HWm@q µT8|wsIkc$g5 sG^{[m2 &M>3$z>ۍ@ϰU$[joPΥBe[* v;RQ^vSK80, 5ZlI~xfHVq6lCg;h$9juŘ86jL8q6 _}owmӭid(=i72RT%&=B^TFʝшp0˻K؟ȼ :048% %&59V`+. `9qo~ƨfdp[.΢#j977Dz4\hK;xmkNHJBvtC\1u103Àst|LMeAs5q <o, 'HQdd3FC-%35~d?{CCCPjeX7ቇh6D[{qK(pwwc۴7=RD}('СCN"oϝx|wHrINnrvW)g /BZ-y;YDn>r"d 3'^:\n4,-j^mhGq'w!9%4)[OD=w Jd(?xlJ$@B'fb-6"S9'/]m5'1+d#u[#$$tʊIJ~dG(RG$&%pɓL,훡o_E1r:.\y+q2峥R+)iBYnVZV=vԫVg098TnmHUPиԨn1e!KV Q{{B,°90'ϊ pD\LX֙l Y Pj}ͪ;Ó([~Qaaa( Lǁzjvaӧ6:7QA:<W0}(y:K`|ckc<Õ?D*>\ӢH;a?Z'D5/cseY* _3,%ެō ,*b<ַqRzs-f:Бͻ/;bdj%:>[ͫXa {W'xD}ԉW- )&&^snثO{ +Bڥ;Y4F=6;[/˷oJz}P|I7vcP| ƲB?MJ \m儬)D#j:W{CME=JHw&K:|0j! AlڵGF܋JLMG#"#Y~L!Mq5hd케t899>.@XQ)"̅o!}yFdjh!{\dqdND{d&ShS9"tꚚvsFɕ-ߐky TtLL+{N㡊KxD(i%yD_C<$~xGFFrSp~ _yΟ!]ڧɔb4:Ys8kYҽ}eAܪ@ɎL Sws]9y$7rMOšS7ȸt?_?hX \򵼎.Qբ+㸸eYMLV]!mW$ J Bj=gΰt"ABXxyyQF+ 7iby7_`b)$BHX+'r"w\BRx_]va3Zz(?Q4,xLWEgKlVPy\^O^bf#yM͞D^~---% i I_4S20JIDwڃG?ͳ~ UTUe\bHm+ԝ2 e@,O`BI<6@򿞕QV&8%0U6,T MrEߣWlU cJTIZYyү%&--;r%8nj&88؀hjC$~-&ߎ&Ey5*qk4KU᡹HQ:DF*I >Bgk a-QW wSLJf#1 BIJ*>,zҐ&yg6RNh/P\,[r $` CJxQQrtM~i[°${/ket<<p)eVDEelJBا7s<Ҥ﵌,w:g3(s6KD5d{Aiv^&(+4QtB=rK7wcПg|+`83QAAdFSbbbD˝U9nv1QBN_P/.. 6S02ΐqJIn mNbFU猍W!g5=ү3v&lnjld_jqR#g:\z ,Zqئz|¹)^@v]L;L2vvwTD\1UW7]OS1D}T`P̵ƛp}*;J[#14?\q ;M1eD,|". 1xǏ.e<#rP}i*u3;'ǿ ~i+ =4/ Hϖ^jc)[qQwٳg? |DaCqガd I9žfelNU{+Tdn* i yQItomo޼ ˰&-RB3at=sDUMm./#RNmqi ȉd .#݁|F6 y3ٮɟocs{&'%UOhH[.^mf _¸Uyn;췬JhШ`q;#S oY"!/'9mj>6t8^s(""7Lc߭a]OS%8ZJ="/|F19[%6=搗&sooka~/֝D%1^{nw ((H+DV!WUpyNzxi0/a]ӎ_#M# p~kL o{JW'!<Ç+kj#@ 7}"i"~!YWW\t CgpPMm~ͪa>,YRAٳg宏{k3̛I?sYo``ok(\nr!ʧ/![~?8ҢciY~f|NybW xb;?CmOW! r()Q;9 370p\OO(eYa\\?xy(jCf>Iy-xngЙWWOVxI.jv-A{*Q)%3?{34qN؈5!*=A})W6 p[ 3+i.; ELRU=wqL-yd >/^DߧڥR/s>Y߸rzŕyoz`D}wueCcNV 1 䵗 &:V8ƈ>~Irar<wm''Xc;tU}HKK@LlSxLXhO'^s'( T5P-\dI!0`3_ =k82y9 Ĉ7K $'ܮ\AlC҆QG!W7Uy؞𢇶 ~ne%0v.KwRd)pT-j!'aYFoMS)v񢿓n1R7 RPG u&Y_5C%A%쭄>̭DF{)e,ޔU!H J#3-)4ˊcѸCW]p`Wetw ,2w ,:a1P92bKڠd.$Ǹ^\KHCVjG!ySF}]z]@(4^724.9ySh,{̎Ϝ],e<GhapK[6*ڰaH8w: @1W'76p0}}}]I}%ljMn[:Z\x^E%>eE4DtL%T ^$?63s1>%K\K;c/ XuNʁc火%JG~TH7pC88t䲲{OF&h1 ԿpM06^qS-F'rGֵfoϬw䊝?3肺73ۉq \.†G_O[ ^0Iը@ tժ0t@eLx ]݄yTP[;$Bs0Z[šx/^"~t0H$ӧO'#؎blh^kM*^i_u'鷶  (Yb"ກN }}F萨SFns=q~F"aI-:'y?&,0&P7 䟘ʯrj뾀(ŵ0mMg1SbYU;rfLgV!ʇ% Kk*Q^ez?wG+! {J*RD=IhP x%> ]?YZ[(a2Mq0?:ӵ;v[X?[sC)zRs&&54FܖYh[2}]҂Ұx5,,04RjEؘϟ}BH GWh]jxT~QI ݸNӬojja#_ ԛgTR{J 3<{u7ejsB`1]\034G p0#Bُے9ClhBFkXt$jH5;8SXȋ44fqK8yA2uug?iA];8vck`)@HVH|Z {@bE#fYSfYthPBkjDĔͪCciLڋEEEkNP7e0G_v0#cGE;;;a{ 2K7,&ͣS< aOC.JJJB9eXD'' ӯ{~8'uB)Jq4MfB" {{>U6o e&l:A7oo ]@[H;'UR/k3M5>Љwɓ؞̛[DXgsb6!#;>>߿KiVQ?yyosK*@3&-6 ݞue6}77y%NKv """!R7Ӧk+4#ZR#܇멕lLvDS\?h3Ya7~nuY]knl>^xDrJ򱞮$nԡ(g7*o#;=A1@OډGG&!+9G;玳 "y֫VtSŴ; %. ;-qc"Oj5//{l0xӧ;F2*pNrmVήteN/#ͯ-u"7hl$CsWDVLtL*\ۘd~n+Ǽ8JK*DDJM.l9s-(?F2%IY˚Y(HL3c(?f]HFvzjOx] ,Uxw *ȅ:3ZX((($|02uKѤD@\¡V5!ݗNp]6ս@75a8/F38`g8:dt`a35'|W:'y3g ڰA6kӱ%99#QMIw~wqs\6!k)b*Yo8+[$v(EδȹFH 1wg#0Psq} On3cK[1 |8qܯ5Hvl7|C~zMyE]VHqI|Dݺg/3a0xX>|Iğ "@(Pv)Ԃ1؍P 1G5|S^sE)"b>SݫsnV'1yN)9DRD1]%Zڍi}D*e.E1m CXKIbP1A?"R .`Oxo+*LE5;i~-u`Lcwz)Ș~f353NS` 9K"Y{xΩ%Xq'!cOWLlcu ߈/&:Ͻߴ=M() 1.qUțvWK>]B޾}ΑG @@{(BFRSݎ7n[,iwxh{RFqC[]ˤd ׳ھ_C>vF#!jV ڵkdf.ud)DA`g,.bSߨ(1V<*Q^`I;_d*N(Z9MfE0P,:ьbȅM~M0Lڽ͵(|߭_#n_}NؽL_D%iusH>1p$4=Tw!8r_P64Rc?Mu,Kb*wJ2*m%Bѻnr61OFjWX%mfzOHcoH2^{bYm5_Va}Y! 4FC^}MMS;CWg}4>vjYFB>1VrEzj3SBRco.*,VZte[?#,?h֦f'lEEZ)Ckt|ܤy0)I. ~܀t@|sW9Ӯ7H֠^$C荏zhErQ=kZSǣ]C4qLjωtz%~ ,!ե[K*#XVbWmnL#I"+0./E4_7[<܎P& ZРE+PvdcaE3{JMnڼD~ςF} „ʺPV9^.?ϥgO% 9?8FIzNy;5My_Og7չU\PsOtJd+Uέ}Ҙ>Sſ:LZB,8:i,>UϤMuN}z;Քvtf%}vXVyN4l~%3)\!hWLUxpLu EnJ/||a({jͷ^/aEn. $S_w7) )/nd FtAc0꘿ MNN-{8\q@<{FH8Cf2aEglEa@=eH9)>‚xoF>EiYGnٙmd[qS;y Td+n-n}t(n;L,W$pY8u0ܹa;>1Lmփ%z&Y,q&xG,NGƉn~H"r02aJ?[ !mr7B7N: E1yGPTZFO$}><5'=-$.Sn\P^ΐ^ׅF,ݬWl߆;یlZ0@"ٖή65J0N4͓>L6t%:*!L4%:۟TM1*`q>STrgr0\}t*\bJ=7D)`]~n\'むzi]4`7^=]vVe K) iU$h"/Xl ^*Lf"0oE[GhMp"Hw. )"9:IU+ LHHG8ȴyb[F[[DF5|y NjffɬleD%A{Cm7lH}OmYߖ-Ĉ-I`/tq%tYQ\Xc2]e:z#ٳ{h KT2Y9SMMaBG 6@p ٛʴ4VTwj_PY d$=x}ݕT6iLyhԝ G,j 7VHOӮlRg'%iw2e ĤZЦt>hxN/FJ߭a\!I(Ǜ&ñjZ2WUׇOC56O^ ӫahQ(iZ=j  I<Ԕ|mC=ʎ5HDᅧslgpg^|+Lr{# (M.O>yMwZ$pRÝ0_]lHjRy- b"QF~66b/3׳Ǫ쇚lM7Ҿ:h|tX2́dw\4(T s__`]=-D`tf@x:{F}W:A:{{Wc]Wíu058Uwj'*yޥ⣴}]b_󾍕Qq!.x*ӕz ^~,&諣0(ﹸ4aP߲zϛgbO fgwXMv(ILr>*XpgvsѮ]2Tvsy5VW`ɪQ~jz\ 3DY//K|---$ ~ X"$UJ_=jvͥp~7(C\v{aeTϟgȡ(؟aNė96\֤Poۻ9%iz/+IBg̀1y'[ :uABt' RaC!r݅9jdt¤/ +S::I^5DnYY 拃dwebL!Ff"&< s_p^5ol.6%'$ݠ 9^=>ʖJ`ssgMѪPϻzȟLPmІE@!7.Zr]_JWb˖-kUxѭ[qyN;RhQ\짥K>*~&Qcԉ/[wW/ޗ I1GTaz7'OJ}U ͎vºd5qʼn`={|m[wPkhڨC'@~ y' t>/v \j{azF"3uU$+~N{+]G J(ª1wwW׾x+hV Rr:gsx(i;ϻ5Ň:ap}bκ2H7 G6e{LEU- ƢR]j~h(?Z^! ! L\n}Dhܛ: #SB}B32{QZlu H"wΦ{4Fs'>/={A?k=Guw*m'`)/VkaмMPi J~#rCbO:iM"7X0K 3 ̐J7LPC; `tFk֣h *-4fvv% +K?|J]^[_Oܥ}L:+3*#W6QH:]+w4Sm&ot4K-)*l7UM* Yktҵcf(v2 G|_얼W*#c/6;hz2Ԩf>_ﳗ~ ߬J6,6ɽƄ-Lb;Llley͹Sj"A!}>VJY!CfMm#WO`۱~qX٭NU 'l 1LM3\644qn[H`ɎKyCzߨԞ n[DrDoT? I^ 1 5dj\YrÔT`3L;bTU~j{:+''+[Kr){8QHٚ=[mc˦K% u:_waMO~YFC\0vy-^Ӛ.L5`t1,@Md"Q=#أ:EqRL#9D!!8f gْn4 oߞlBs$DRR6,Ǩ2'z#J۷gfMVy_GnJzv񒔤U(ԫmȡ߯ <#laoWQ/ y"kx9ҥߩ{uh]xػ (J&LNǮ>Bx*aڜ5I)$ss[|c`]?ٟ^68vf 'Z/_ݑNbi^LQ_Xx/0B蝍{W]aƑLtck}5`Ȗ%>46_5uTA{njM5,, #M\%VVKrZi'E=`E;!b0?Rv1{WMSs` !+찀^TT!GGL*^E:'':}ޗFAB:xujzwO'FZ&L{Cm`g'Aa|7]mљF QS{'?;/ױ ^1 }JΕ݁dPa:צ/=<6eƴgVe}3NORq2QtҿAwٲ4\?RikH Sǡҿ81Vv#ϑEt6iEŮ>,zh8]10paGwȩ1FTlzhvo 966d).嫗^FWW7QJl,wѤ UHޞNma"+zdG\Rrݰu! }#|3D%Բ)|zXQe8~?3Ryp04S,z5DQh دjL]CjlflMp! I;흯ѥ3g77hz1myPt9.ڲAv,vq6]\Q^R'OȫE>P<׫Z+LgW}ZtnK~l8?̟11]u]]K5K5M rt9LnD*[iTkyPMXYTiKr-U nnHxxx_hI ֓c<:!zf=_:@LhNq_&$CѧaL M[9j U{d_^~ <JD6JM ;V5rt_=YJz%)@正㝃#RvSpȘj ow'WW!͞vw'ƫ=0#Am!Xf6ȑ}ME-gjGH/W:;Aэ 5[8WLbј&5!??~W=9ef#T˂U(xOf<nxKJP8bVml\sgL d\fN[?8lXV/8Yx"+OyɘR6q*J¯ 䈥k -?H5 45 ^Z֮҄WN?iy \ ­[ӣ;Zn׊M[V[QUL:;al..9p勢F=[]Z3?B\[DhH0lk3e$ 2:$,‹?qqtēؿ.6x<ϺCM5ӺKռz*@,օD;w[咹ݜ-a2Yd9`_1Yzm j=QS5UTtmRÃRj&.`p3&EVrəFw:wWcEɠWGZk?I,-R.//Vz"PZ<ߋa4ْ{zP}kk>t\$k⋆ͥ<d _VJ\,֓'0zpD>x6C4%rff3)K &^>>%/s1UZQD]^L ?R1ךW*!pÕ]h12F.4ѢU_Al g>>sVoڎ SUxSa!a {pp 3%}\|Ȧt!o\ܜuGQMelts;B bs;YM'^xj`?eWlq&xO@8z$; CI8;k@V >e4u{7 4,HM*5C*==GHHRֹ/ nG^Qc@I5%Tj4qg2L0Q^{2Z%2.ȍA.i/v[#wj/`ḻfCaY.ɴc?[师YS"Ahhu:%@R(.1HH |i@ƥ2ߡ @ua.|hYٶ,@נZxj 6`ڿhhn$l4SDkfiY2\ћ߿l j&2;_ `4伥p :NY\GMes(439`w0a`^L v:F_~ؘx@ȌJ<$5fS=3+D{X\$p6(:5ٓ ɵg#̩`4Q|ȹ(Mϸj3(y·d뻻yῃhj|^kckp>*Qc4PHcѢ7-2-VH7p%4U ~lXⳠIaƾ2^,+775RׇR Zi^Ր$cfRXM/t1IH͙OS"!Miv:xUO^j,b@ŻzYE$irYՔCCCQ :Cގ+BD)@(@'ҿ `Eј&5eqy|iL㣂Esh WwotB&oDkz# 9@m%(» S{m'ExHM) ÁDA IqFxxxd EN p\M@&L%/&-34'k UÚkK1hX V0FsT<*LJ[Ʒ❋!3_.V-88$8Lc#[Z ?`[l"H" e=HET@H)RKC|!x5us?\bt> >4ꫯga6%_lYhXܥ 4\73|̈y6y;#gpowډ+ppȕu4+ͫب%onrAٌm4~s:BrLݮ<\6څɾ]I$rDQ*YD*e{d1)s+F7a'cR2sR->#[tIdhM%|=UkɇұU㹯AAۨ-Js=s-ز$(ര8D֨22Qo^)ע>)pu h u:n @+:ǂNܔIJ}u>.@øЮlBtʙ͛#h 4ClyHc'*J^sS0) :"Rm~5,s hFAI99 "+2 @AƲG" Nt g`ʶiX.qÿ^ٯ%h3dHZ|]DwЖH:3Sa#4Q<pb1X|(PYzJ5Dz#s---JdV҉o@FA6;*eF a]OQJJJB³!]riUmT,|ƍ3 F%֩C7AF&Ǻh`^ގ._oؽ7]vӑhlOE33ѣUTT풉cHK\aâ t$@| o۲UܯYu 9G9lfܼGΊq1tlcHl!=S,~c+#1lWjvf5 r-:&oDVOP 9@$U566.0s"j<~ED ^>ke!@[hy*6mUtq#`|Bme+1p[ `V~-y\XB/Scsٖ-6QGƃ_ M$àq4բ~se@}n]_H$LXll7zz=Oj@%3VЎxH /ZQ@8nX \rdHe=E' Dã,D9|WPR͹! ¦g@|5Z `qLb-[*}UwwoKzJIb? t nÇډ"oW,@ ?G& M '\ͼ1Be#>2@^~ &jF ޹l]@WYY Vϲg v=23*5TLm$Q(x4jBy]OxG_n%MFDw=*e+9:B['ڵ0@ dծV"$lJ#""~T.=??-1/PD۲n0q5NΞK\xJ 0=4ٕfP'ORwg뮭+&FM.Of!HXē yϓS,’ӓiV??rn̕YS|$;A켌R‚鋃;يGˏr\T)lt!F{j&_cg\ 1%ўc2?G"z)*pL?PkÛ/ Vi?hVӳ-D"Bxd2=lm(6Oj7ek7U`44hbb XOn&Wsr33}I[#ˣ6Q&((SpzQeB=u_80q6on0NP,Y|hr2AooI4!Sl:CLnJs|ϵ S\yy邡CSmqܗ8 V ]u-?*'].VW[S3 s zs%I!;yE! .뛛no+g.4C&9%xd ˧ۍ/KcA[Va2d:5Zey{{^1<;2cm$M@Jjku_(OFuL d:];( =V-@g}}M02ȞAa$ 7BN MwtS=n+_ ܎׬Y0p:NPWORV4c5k ϧ(`\Mvi)׼7e6Ϝ.%cNJ_)BVtŠN:=<-}Z^ё% ႚ s7vy5#SjPx\p>{<.5(v,9g56Yd{_ X΢7?EnTK?ھɶ4sP[U^ZZZLtJ{f3nΌ>|8;8j5s)yybݢoʥsuxWOX23= 9o9AE;Vh6qbCа w2r6W-Z4cv rdEfJHHtN@IAy㙚J`D?ԔrzNkv(ն+{[ fQg+(;ʢ2kP֔"3S/&n[oB" A>g$Ufm&.Op9ivS'dp5E`5% vO 8 P$q1jQxvR!.'ݟ2=6ޥB?;9n *in?jʑvJ2[ct=>1QN$h1fl(_āP %>teR T S ~u 7Mu`aa;#vRϧ<*pڄNm U0_>L?o"e{2 yF{Fj^_m#Qy'uu>@fpm^0IԳZòN-,S2nfMV y+K700`FhzbY̝jjjL, GyAOb+)Rșw\nIn,-5M-|gg K+?#B$$$Mbn9<>UDեñՅEx [~nd"H4mcU"&=(B@HX:טH/^;Dd%8(B;4v'SesJ Sr$$MTYhG*ijcm% zKזVf6A)p's6{wקzl)#uu?T=u . Z\`IN)C<9POS NvL]q_E= 1DsXAۻg߲Q᤽ W=Ql ŀ>CyB =ݳpw_o=%D2mt*r3M-;L$tBSDŽ[㔦Ht}"e̵ r_V JxCп'yC).*qFKudn፩Xˆб 3H+>ڌzv6|-K$3<;U/{zgg_@I;RV'}6[Lxl$xĉ!+EF"F g _S3 H?j2J#>)3mp}ld[Oγrs óƆr_y Zn:^}~5wq'6Z7= ed@1ʊ|]Mș;9W:ZwӁdJ*2-O ([pgt>.>NpL?7n^hLMxx￴~x?Yx<̽ԇ<Nq* [,{anDP'gm=V|&ʗBI"qgCb{RRn11, JN5CDu`&cO+YJ W RרdNa՛pfDǫ\:܇r"!{m&BIF2Lħ%!藑VÛIc[u|g]}llZk pJWTܩ[.i=p:%# }h*A\|-f]C%ç# tY{G+u{|/b4zs4`i6'@UuK8AWVi12`f(1*ݶDss]l>Zt'tm=mXptZC?,;@hjEV ۬q{֡ r B$MobW}]ߠ*[JgT {p#n12qEN3Dp5w;6q9#Iq[bTΟF U"b|qAdwG7EN W\:A'?g)gXKVX留a-Xsrwwx"Ԭ3vu|7ky"Kw7E W)-418O[EG-7G2Ԝ΄gї Q-&X4nHȫMpG[7UK'+jR"`)W“D6Wٯ:G̻T W7ɷ9w{ín.SҁCܹ>d$"TҮhRx4\rN!(VH(5V,ߜ+4>[k%2^X\K0d˨ ri?;3l-L~uF]:(T$qlDǵl~g4)"29A~y2>(q;GoZnJPaS2yncs8u :N{X=lddVXD'$e|s]xuC2{/a+pâ#Up\_`mnim?R7*:GNo7 5d3:n|ZY」w+[qcOrr NCeW7/G CE1^Nc5V7.kQ5'XԎGכT]B1QgۭX\mCsfM\AQQY0vU F|:M2%PXLF0L8fܤMLB2H{MfQnsi3DVNvVQqZ4^Q?A~|P0\ygѼ̘ª]WU\d'Ё8uSWCz p_lt;ޭrF^3zgH ;q[j -!b Utb-?>}Do$݊c1VBbGt?pԷ(O]'솁?M-@ԌK|X9G=f^X2f BCYd^lmn#M`XAF\iz_2q/|'Vo/h,A醒HtFп}pP*mY0m̼x͍Y;F) ^(~|;4!YұK9nvB@onl(1%%* ȸwѱ=VRT:KA^o?MAφE:l}[檞-r(ݫg1 ,E74Qº=rЀܗX] 1&DC`nβ̳6ObW!i:2BAD$@=S{i &JJb?)E]D4SbQO:=5q(<]ϯ==9lk)˳KhI)@, N=J n gL+:3t'H)~䑣Z'ae&θ`e48¤~G#3rUDWsٌyгI7=d*Oj^&;#߾UϽP7=3j=!@kDo,4y4oݙ -W48 12H* 8::{|̜hIl+Hr/6W]  BuwD߫p+׾z:,;zE{ e/]֦N|$ᐢjb4! a'daSWX~MQ 7Gf6˼3A~Xq3w]UrVM)]CSk8l.[GElpN$$ΞFjgRn[8dryܚS41Is\@UO\iیpek !GgtK/26g}{OۭoWo4 DfM&O=(@/bjBVLA|\3x&t眔qy m/! 7 \FY2W4s7,Y=3۸=ogb=iw7:3wB?(N:JskL8PUq"ŘLz/@΍LCT#łgE+(of`t耻%tN Kn0==ޤFQ(6sA='-<4qv3* Ku.o٫GZn<"n"Hސ>?Sj1> ANTI|7> j*Dfp̋env$^O, ʜ`Glge㘓Iq #`./+l[ۃS2H PepZi>;td?-#wus#֚"ewaۓ0d :' `HLr0c}__/(_1Dq0E>Vr [LXԆ Wgoٲ=ӍNiC1ӅX'''ٞiA_ ׭7VVWqt {S%:^&FapT,媵Y8uii_ЃhO98~@ϔ%srq)CMDD#UT t DQN.rڹ`K!y&=$&ߓ136>7ƇX Zp جOЁ(Jes\s 돧:fzeAQ?y ˛^7<<<^UdA69>3LJ\ύ:mllSZ'څ،?4x [sbm_xGB#7귗/$@$ͤ=Y3nKK?ES &W[ZYY0[#!#'%s8FQkD@'/g8"! :1)2f/J5帿T4jzʄ{ 5tA#N\Q[_ReMNNNLt[LH}}PWkϟho A.aǏt-ֻ%iiiO{P@ 6N\^$Rk:7Vﯟ>B0SU|hRYpR]SuяM 3(6B܀e?|mbn _BhL&(67uwcXl2aiU*/g`;(<Xl. PDY6YFV֛T&3Etqȃ艒 Hд'PHRq1M+o› 活#4 UkheK ؝̫VULx{pU4Ȑ:<,}!anoiJ{ n _2]{e% u$evN_f<%S(Rbg(jNd={/~5ۇOsr` l/<Nwv>}$`;*]MBN{gUh4vz"-U2!,jV9mTUU} GK<33Y , r^ 4͌9B`-xw|%# ]7beE;2:89=?vwvgk׳_ۼ $Rh#:|Qp%(,L*Ĝ9j}Otmc#{s {SSMvvvsٙjK0ͳ,&4,lc0p2GqW"ߚ B3]/J踓`uTp,1phX<z? a苭Fўnhaab/jč"pchՌ .]?#Ҳ啕'>ZQ www ;p>^$rY;| %;VL ,qL4||ΰ-(K=cfԍ42٢:fcYk1nu=qzfT?1 X)SeΔB*]ߟē!C/Fz}}% |nd]bXH\d Nhɺ)ZZ+/hkFF޽/& OX6;r@qr\&|Х0JgM=55*!)C*`Ŀh:C0)FU%g;bII)36&[` Q&`dJ(Y$aAc%kkK5uueWW:!l{ػU2$K^{&Pu[ZZD#JVDGE>810@M)|JS3(v|ϟ1NְJ\o:uϧj/}oSNA9>~㥍w׳q`L@ JotI%nJKK+jj7BAG32:ڤ;~f<+[n+tQ^NNXݮ1QTLgQ%\N]TvMԃEKr2E=':ǫr"Kr{/.d/?$Ņnw }:, a9h>WU]/2`D9DsxxNteMMMWZ ίQz ToB_+^jт?߽菿Zր. .̈M:_~brd .:JEB:4F#*(;oS%:r}yo/^37[% $sd SzLs {)Tl6A{`bE+چ- P@U'baQeD D(hD 8VWWx]np/8JǏ_l6D)4ځ,:,((N)(hnXC!P~cА$mW QѶ0BQ@e{ ʼ.;**_sd㞓GnP{PbrРmJl=fnn>UDJV?TjC=94ۍmLoЕoaqfi@(wޢ"6VWw;,1]i6])t17Xwyju$jt:Å&555)5 N~O j"=::j.50iWtSYaݾ Tٰש nokK-dM.(pY:n58Q=<<)$,L-Y+8)) r{ {t d%om NC~{4`Ŧt-|Gu] }y!:mVVW_XHfLmmm+hFƤx7˳-|ɮ'{x}qQQ:6@Sύ? d*'@tuwO;*(eK}v=˗^h&O2=.LvحV/wf+Ll,-5s֠o6B>qȹ!!! 37NΉ թ8:?m{ 4?&΋q''VTkwHOBn4Sw DIkLLh-,޾x80kU^@mdyAn Od@ߪt&`J%PM~km+o%q;j~ro5(sz7Л[XH c?W3j?Nh`(tS.{8nj 8S3]v 6)hh'&Udr!j)eu( oMh`[[[&}6_0e g{\ҰPuv 1{N-D$ezH$t/ 2Nn~=M)->@ ްABx 4܇ԥ! p\&ݦ"A'~w{N.Pof0a5{uG`ӹ~ys2퇊+j钑ᇇT 5T }S85`=E-e*̎v>(C;/;qRuW:;sex"+PA(MwƐ ;[[~rYy:$+a(RWNmk?h2"Sk8LN쿶 dBC NPe(t ?5ճSQ&Ĥ A@IK...gۣFFF6}-)<ߗ>Əh=)vO@Cn0jK[e O{;L9OZbLּONO&^j#Ͻ9?e.R0~8;\$p㑓W"%{buMti-`]WFIoT3\J to h?PUB;RG# 7Zg4tFN? 2>|N ^r)Ó'Oęεu|p1p|Œ'apJ/hh+DAA)JM)܎##[!M'!!]31ER~z݉t0tҬW0_O\ݻUN>Hқ(;ݜ\ttЏ>='pלVӾ׆Mx:}h6-`h<<^7{N*m nK+W + ! l o#^ɴygq,?Z2tpU_z (PϡE*J(AjqU{noAԈ1 ȕh?) /"}a`axwpRm G>˿;\O)4 ζ1Ovf$ '@-ޤ} `_A PwW\rrpt: ",rex%B =h`?& .@[W-3@ҽV;];l ^S8c$ w loZFrA>)hqW i0BG:q@~㳙/.ya;:0b~\V*'BiViT<=?>[rm\r)S۠0RR7kJD>&,JUg[^ވ!݆&$&.=9L V)A91.x'PM-A%I0ݡs"0Ya .㚏ZF%$A3T1p 5— p ee1f*L"111}A)`?@Mx%NNRRu]Jj\ l}66* zoǯb\@sua:͹2ٰ tsV]]ݔLx9`!h;^]_k5{IHtX!8uNNTg/^Cx'v/E@2O9/Hpec 8 ֫ 6Y>++JO!hhhGP Eaa{ֿE'~><\B.b=*k ω11~EFjUX-,,uBG_ut#"N(5-#[*rgZG4̙8(q-7eK-^B[1Mq @gyzBquZIbTriGng )T]kDЭNcӉn{5/6؅:{E@gS5Pɏ"Q4-@]La];](3@v- &0q p: cԕ6n%YQ@rqqNP6\̦=] jX'9dtJm:_)?5a+5 ?VOkA<]K#YܸGK—:ٖ IC>X[1Tm 8lxL̔˩ԤH na=UAJQ{&>k@?VCiB狃vUYdSM Oh|^g 6P9FΑ"(d+҄׀3UL)wdPx撋f`,=wxo- {VB!Y؀H*R3I[dƫyy2gFvc1sI!) ?[Q999 lwwhʈ|ppr.ZY] o2Yu7 [3ΒV&Kd|ߏ/:"e_@++1_X\%?eGZ’31w;$ f-`kPC6W=2:A_ GQe^DE23 dݝq<+ 4?pVHغ:ۭP# [Ձy%WWv@)=A :ߟ&@nAd?XptiI8{=SDD$8J R$'M V<1ہnhVar|_LXn@9ے$Vܤ q#$P/&WfG](wwӎK񏀛:AQTj=T.*#:4cNzcA%7p̜ *݅;UBWhUgWG}y3%ܔwO(nX\oBnZQn2DL OzTKx}o"JJ83U įDk\V "#mH-:4fɽUI |VAU΋߿B$> =*~I뾨ڄ&7@.תqeXkPA>>>X &>A/f~GG ҠֳԻ njwVhXX~FZD2XO8ϟGuo Ζ)~nthdu IƆ !n&Cs5 i LLm:|"?t77]nl.wv`E`Շ3`; \lMЇn7|bXlg&NX"5C{ȋ Pڝp6%;22k``#,"6: O ͳ=H?pj@nl JʔJ'Vo j&3eJ+ 5>tz%Cd x>3UEkQlz]t9TB7ErAGmө>3O^s8D˩EBqOKK pWQǍ|9D EwD^w:8hz?-ظ^Wİ9PxJp7V:C>{aiJ<#Z2'¤:`b`aAd]3mauZa}y8AQs l+Paq푛ZPS!N !խuho'##?V1UχBq[?~@>OwxyyÇws@4iff.]:ÆK5kǯ_ޑ}@_>Zn}#[C[= [*KHJ/- x LLֻH7BހA ձ9Jʬa׭XmED` /**pLAgga'ot)7Ǻk 3Dd,Hʔ!SH(󘄈$"< d2yŞI¬v`m;㬩zק;GjOFԕ"6gv궄kzF ;&'' L#_Yõ WO/˗q!_KmBeYF3klkfWpҿ?ȻgҞ8[*v[K릝]@g-ظj]# xg֖:WtΓDSS+R@=28[έ3cmm͐a:e<3*gjǬ*Z  Z)nqӅ} 3"T_ױ~eKhDx<rh J/N=e@3fcj)CY-$3""oR_{ 37ዬ,x (<R΂xl-1.au}I7<} ;tAA^~|W^[bUoUK݊6Y9;of~*fZn5ԫnTqˤddBZ&]]oLؒj?$w~Y"l-,f2=2?$@UAo?\Q>/cDPLJ]>/;n"=pv9隈":7ImM~OVn."K<~xsrQ%s;+= G]}}=-{i*s-Q`Q\IvҊi%LsXٯ>]QW N$y+-C*QdHY$s?߭@C #saTpci0;@Cf ]&G|`wЮ\o KWw~%v8p$5'xV`ո{z/Bbl|ɓ'7TTa߻:5s4gh֪=JfsӻKjRLvWiNHLy:"ؗh)z4}hfjjjt|\3::z`hl:[3+kh^?XJ0{67ꚛY1٨Qyvq/0&ʇsvX҇EkņFF,9ץk>뼽JYh1ʨe+I`|6Xjwbe{Bw΃%_Ws"Zrr\~ۭlyl]6_9~m;]'Uת@K^IBaczK|n;pcwzuN8^b՗/.2$DQL"JՔQ{PhjVyS}Yeѓ5Em&zU5k۽7iḦ́w;Z$!_w6~5S<$؜[)aIg2`G[WW2W]6z.RG/`7CWWZ-ԹFo!1/a5=m/,QIS@PE!V9]'[%+CX=9鹹YOixX>R_RY_*`e/¢6L:-d;IlffFLJʐOt}bs' 2ǩ(kiߓAe朋 -` "ַZ 6S+QT-e. 0]aKJ"YS# pzA)wpި̕s kք[<|lGW-lHg lc*FH0f;򩔔Iyy<{`NիWLq~|]\qd:A$m:b(0OOgiũ!ZPƫVQZ(ũSLő[\[ށHA;vXрBAO0Ii k5zDjc^èP D۷k\Mj%&.،+%|QY̔pqE-$ԝ4]}s81C l&$TС99cho~>SpEQLo]S(U'y&:g6}dbY msTBw<&r%U-4TUYo8 W:W=&J2 QF/$d7r.rqq}p4%CPd?%G$2+0)s}4gãlL/-XD|^HGUvX,Z<ṸPv4x%K `@~o{lVUWX⺃= RM\^ eRx0EEEGI[`gz|B}4AwYod}qzUcBJJj@O(tN/ĖlseRS 5R|=>?cxxB ^q$\wV]E6 𥥥CO癖%x yb(6]2 o7B lsMZ.<ɩsh%CC[!vFKf ucmJZ[Z;(vyќ)H?  ˣ-^@٣IX]988qhľB_x`37=*K|r_|mRGOF9oAT1ܱ|^XbB:*[JT؟rz "=~b1A)ߜ?2uLt#״D7T|ji}!C&{ |!/,`9}WU]XCylEO>hv`0pCCt?c- r8oERZ$=1%/JN?[ɪ(q5Rۘ5 9ax֕J@`Qd!!1K{;0eATcsOM5O slɮT"}ѱ{{{tڏjk+`&;RέTݻ_i}7FQրc;L Gjf\~$.gy\!h$x>L^w9 Ya5n9 D7H1.伝=PDhe+I@߰%󇯠E\vL?N}C8wz FG[<~,}>|*TI8|]Q`f&?P8v1wIxL&{'8Ԃa^jkl8VaxyO«PTxo5RU$9/IEDG\3JHpNg``8&{w_"Ӭ QoϜWP6NǏgd&*vk&:z치@uar"F7՞yNPxZ. KI^C# 5b upwpr2Z\Y&a\gߌpzWWj2s]8$Uvc^*Gɣ.Ql{mWAcPNTYW^ C"`3ғ#v2nW?0ɪxɪ`:?;AL-MRl)>Gm/JMGPHHH|錪J---w)v8$vUCC=Neeb(7pVLo,f6lok &۫I`ZXX|kjNa<3|zGdzgٷDIWEAMKSSVYOꔿx3/.>Dg1R]B oOt@q!{|}Q=Qm($466 ,qpFPk`%^=;N"!)TrTgWoLX]F”ᑑ ~Y踤hA;<Зff_A S jO}@cj^~8KtBuc U`h JJQvʂ/$8u ]hqcU ʂ9~8r=> z;HH|cx!&Jż5-V䤸rAL杇_IH}T~C##,Lt8s۰<| Ux 5@c34 PԑHYYP[c¼6Q固(%T. Nv|HH×o53یsAKVs~YS V9&斷Ӱ4g`| bN:t3 ,Zk^5`YPߥ~4sw_?zGs=U)彶?|͏Jb{/SMs^FG+ 0}VL,a<- \P'#uP[ss<;>CO+\.4Px$z\$NVVUNPT{{{yx^:?ƿ}GXMI?ģ;ȯ{Cr30TiY]\/IOT&%k]l3敒zbH"Z<ˉ)`\:GƤKZ!Q v)&3E~K. ;i]~9)ikDK7, Ο܉{拏?v̋nԊ{OUEu7⣪Á Z"GuUKKOPuHHEJgmbd⼎V{D uz* z_ ^WBOᇂPӨz AtNMݮ{.+N2gv9γgφ@Eze&V7?D()!Wm'cZW.rqq<[W(X}r

dة+(۷!f'V?ί6X zh{# kEb),?O2^v(PJĠn29kJ(ۢ/_mFֳ.6D +sSyUQf*͡Wp9\ * &'';ՖVzf\f&)80BFA{0 Qw*x<xǏov$wub.\ah|n,ƪVUiDDPnRQ|Y,ipCAtͽb/Sy3択z^Y;;m.V[793㇢d,s+{ShtW>R+ͨյ%JI+%FiEp?5ċKIa 1bee\qtDn`^Ȉ,a, W~T####Ms$˰ 2| q9ӥ\me)+86֪J6H[7뛛e~,4[?Cȵڲi΃/MM.Hl?J{󆍞jLoqQ/(\NT{QJpaOq0~,E_OmW&*l1y,9qF`e."&9||\*&= oh`i};&TkHUۿP3A$e)-v0{θV[i[G}?>QY-48c0P|B`{X{#5q"NCdW3(}Fk.Ѕɟ ^~jq/4?tܮLxߐwTO#!}?R+ UgLYy?׏(?urϵ,}P1ِ#PCѺ[;2mk`]X]3o^xtE=}}KUV}("`!.l?cJJ9&_A=ӦIX3LzŎQ['Ѷggg z RHUUu((|UT'H888zzxyAQC~1jv3G=L9*rYͅ2BBC+;W̵Ө_[l5:4*СiBQGMyj\nJ*bbdĂ\"˳w>,+[C8GM"z%(h"&..8pJ+˩Z_p^ EzҰ\Dmt:OO4N}nHUb~S!g6N:UPfn@i? T_6n9h$9n/2, uX\\[$ʰQCt`VWDdf:NMuNH+Α %̀MJ ,dB2;IT߶GLVYn?{IeB>n[8_ЏEH]@I &KI.|~ŋa l&ᓡV̳\)s˯1Ubs11ۯoOExRh;?۱O:SKP;L~_XҗuVֿ5mmm]~ySj*a Hu.jBpyEGs?'u Kz9NO/Gd 4EFE6Mzݙйon.РJp!wI(D6U+=S =ez fB aԬ VUii)!6 l׷\ޠns<=ħ(VgS1;p (D+{5Pl*+u>veއxZZBtJ^JinrO⥍\f+(3a777jguΨ!\Du ꇃ|mw&f/L Jd,|.yǏW3x[$MO5~x_3'WQ(ӫ45B'k?>Mud˯&SPZCݗ"Q`ю۷o﯆Q8NBU!^,^ l xhs޸AM-i}\5R 3bbn@(fg`إ\I4^^LaefFq>UjbWTΗefdĹN4/ٶl1׻RT)  ෴o|} Q5@rV .U ?atq=sq/G  Ma3=QI;n7_t ᕘ# Gb~΍UU_cRr=b"Vwz hQ.}4XFn%ύ,b<c_7+~P^d.)E26Jx>76\ÞOʣ\Tp3b/ cULlfugZ (ٟRtgw{)k!j~5AKEP8MWF'[¢?2GZ UQqwV >3 ~. IoL'3s䀰Sr!}Yr4j9 gfz2??; v u[18Tz`M9H?4 \MPb§QtS7 3h\2xFEQhe:GR:#6zqOlzVSD۫Qd`%D71"t3s =aG[%UY&0/C%g9gQg/lVRdkƗ aUcN 0%~wy[E;y6@[o{Qij) uu=OrZ4eQ==GsTs 7'hq-(=ēeKrOI1a(3?\r-ZfNYz,#W*O[a1tg5#RSXÇ7N UOP^.r5R֔gs/ShvYijX5ju$毉‹H Uơ:r-')ĠZV\,l6P| j܈u D<Tx.Bmq 3?Roim} gkood]1f hdKa NM Epn=I#O6+p7&[yŔ"#QhQw 06m6ik{q͛ɉ2/ NnZͬ1ɣ\m^HuH\[ |*FZUUUТbXZRKՔVVV~f HbE^]xQ%4peKjnAGg'cZ&h#+(79T𙣣>ߌy@H32jiWұtJ6{uRmO XV̽,}A+F#E&)Fq`朧ܟP0j=Y %[Ey{G+\~覢"ޞy>Gyզ{>b|axPNL|GG˘ERXY>u}hI!Hi2iMMYؾ!oxxmiB\x&!AhH?{-Cq[.с9#ц4򵹎qa 6t&'%Ek!mג6+K\'>ri?n7p#/Ӎ|tS6oDT^ 929.OPISL,)T?qj,'v_p(j|¡pQg qV,/"DL|`S['qiDvߋRՒU-̢=~P:0, [_z%/T?VH-wkM(O/f0?0͊̔^iaa*|4{i(({aE>OaҁT" 2[PD]-Kn^[W8.sHHJj|%{7:aZ&TĈl{Β]:R#]}.}4~02*N_#oQ}̊9^\'55)vLI8 `8\<#Šiqk*ؕBSق4AwayL/I=nCCuCjӳ堆:@#2ƥy]D+N_ ے,N!*T3ʒ;smΤ< "y=ީ]?70+˝O5Wp0˭iN$ *f!Fe%Q{㧴<}w yJ,2EJ6t =M%8sUZQ]PK yKsetup/UT uYvYux PKyKȿ, setup/relaties.htmlUT uYuYux Vn6}WL6)TA|icIf@^X+BNgHj/ D gΜ93Tiͦ/u;O1qyŋ/''yp zxwEO.($ϒ|q_<¨/-:I.ؿM=(]K-m4RmEYۯ5+f,Ne'Sdv<-[y]K]k3]1bK6a]1Ic_&^])V9@l4q+4s{0܂^:3G xnoܚZ?9蛲mbK\jNU)k&պ'0a`fT[e،js8˰덪p&47Xef(+*%4^itFcˀՊ-;6BI<{p=6iG}??h#-7}5hejD*7eT 1$ons@n*u\tCANb^*jۢ& ƒ^H2(џ5\Y sa0 #T¸v*2#h6wV;.PO^)U[7OE8p/),V@t=ٹwI[HlG@4.>K M{ilSj߲{ %T6(e!4CJs40dyP}q#:GM&l;|*i"zyJ?cxdo=Թ=Q<]nr%ЗАYտF/kXcLg~) 駘~&[_a 1y18`noC4+(HBM+SޮE`sqİ;z, ȍggH}&ҵ2s+M~Fpx&S" "8K1,W^;年8Kg`.9Oy|[]SNKܻÉF &3/l;n~Adp=3ٛ+差ٴHu`Y/w54'OtĕѹC"̹/c1ľ'0ˑڍa[H%c `7Ld}Q/Otd5I]^OO{Z,@'C>UVi?PKyK|_~Fsetup/index.htmlUT uYuYux }TQO0~ﯸy/C1eT$Z&ڣcGR~Iڕ2IeύϟZ'N4:a:7e¤3dzٗ);O'| ?n1/d K+P'#7*@\(hK00%u Uœ(tgPY|LX9Nтߴ0>|`شL̍26aQ~'=v4uA|6= ^}iz׾fQ4RK)S(nk`{L BgT΋E5-QhHSGYF\6!֦)\bN#LpB7!z$b6b 5>\RӡvG1Qv&f3jR:| eiDZ[vP$#x[N-¥(@RO=ySZ)un(z *—PR]V}"$S'ߖ&de2S]B Og :,ڌ _?=FX⥲”;e*F"Vb: >7*uWₗYC^еXWjeMuVSN["Ge%Wkˌ1ʻt]"UK٨5$)N L[SċWh*ǙO:RHt L4ͧThjk}OUU܌LegenDs9)nuIT*}r n>,K օ2?CTV 2\ -3)-~V,k%e˴XMTtܾ8b$W8Im YvDh {CwU:[D7nRQ5Yͪr)kŇ '6 ɟOK3ɢP@֦QYy.Zʄ̩Ɍ 1"% 1Tv%*2E}iStY w] xXPr\Y3an Z54 TUQZK(k!krK$CsL(ToL,^1]Χ_Ķ1T:Qj L0!(>˄_-'"q+m7F?I` ͹ңGc:,u$) tsޯ)6=#)WDRK v§XTKCsVM&n_kU`"M#&UhPVVv`fî0/,8dynjpWd `/+b4o&',); ڀCi"Jeh _:K2" )5WV"rG9 $JEv"pA%cn'[vTQR! zrD@& 0Ւ(#+h[0RY[$4GEg􋡊]>@e )نߑm9 Z#["ԟI]XdȪZ΃I|՟ۊ?!1 MB5I($<@J!p&*l U -LL&ڔb6{2M -(^u UoT۱];5*#dYR CQB~|Mrߗ)'w䋾ukn=k]]sq'EC L A"sZb~,.fH8댓^MP)ԉ>a&jj{tR^`iO`O;?iٟ?Sgs[ݧkQ]fGOHxE 6z22w >Gb*/]]eGǩ kh؜@;1P yRF; Oτ ` j3o'7XG--MmJξ3Apӊs/ROR11~6cث5j  qK?Tw)00"RcxtlȌPUg `>IKBw Jvv]!2qM>0 XgW~O~LXSm["_ڗ%Z#Go-K^8 a +4\5UaBhN @Zs-:? m{GQїāg9Lq0yq}Oy涴3CEwު&[ k:=8ۆNR-q=ߍiHżGJ/s|_s>d!7Z6ŃX-#MdTT=2%HERfr|xأ%SUMַMQ7~!Dfl-l>PA8kCpY59C bó=V">)4Gk&R0YZR/~׏ǴeVZ^;P&76h*3i:bGPKyKڜwZsetup/init.htmlUT uYuYux TQO0 ~WI0mӴǴ142`C*UMN˓c/A}RGGod_O~\ )EQ|?<-z:xU>YbT unAAm %Yr*+g} R%w6`zS*s^(@ t1a .ĥzq| b(?=:8puZNa=m:m":dRez8 =Y%ph봎7~`ŏs5iRkK`7 AL8j\ >bzuwYYP?@)-7 +9X,8ţD|HHCvI(fl@cDBL@E?A\6At 0u!4HX3hZ3L`2>'ùI~!4GB_Kƽx6;]J*/"Jrdbir~HLT*SRv"v\Nf砪fxi.'V}bB6V&$V۵Mu9_3C0z?A?IW紊9ޝ]]2KM]*,v9q"niK]JZ*S) {,&e"UbSP826k4Hst3MJorw[ߌi-Vs)m bx0[UJY*o7U8sC6`E*|47 Fד@R*˫9VlBJveh=ϽSXYi⍦X"*!O+#q,SE>Y9+p牎Ӆ_TԷ,1VR$Ny{m gSxSzR`.$h!')UվR:O<U ~ЦLڬȱͽ0PvPy<'<8``#*^,໬`r1#>E!eFG^URYnZUZ4 HxJq)z q-LU^3v`FSzG,A5P3^Sq/ewl;cXgӟ4ڳ 2H[2)NQ㤹8-V/X$X-|F8ӛ4"^īme% #׭$rkrէ\ﳆl8FhбELnս{{ǡ~wpd, :D 1{ow~u&A{(sWd*Ha0q&+Xs Yܬ3X Te]_NI'W2G$ YAM\[}}S(aׁIw[8}wo=O2ݔW9{y|'8M A78^xn"E|hoɐtR: CCO}igw_D}p.)])$2xO$kp^)S{r2Pfl=! }w݈Lf `AcVsJԹٻ̚Bc xŘ?%ős2p)7:uNS`8IB~%װ`ȜGH3ghxc:S6oI J7MHu a:5"i 5oBN4?`B.>\MM ??\aAÔHt0%c5,cOmAEA6q 6L׏7ԩ཯!䂨u;2D+N( J(j( <9Sa ΅Gic/F4~ Cʥzp.<ЎZHnQ;\ՑM.1YN !Z+eZI+V|`wgbPM5̜|fh*mQ 4Qz 'eqrVSdY6j#$7zͤ+7v^jKºh +3E+jϨ 96ƥI} {CrY`d\&K3[ћ%\̔ȦXSatp.{*!CQe|{h6aNErPNFr9D@H#Rsn c57acKcGIpk 9"Y"Ӻ%$n*>ߩTc !񂀷YMdD? X3uGVȲ)\S!%92xϴBcPbv?#B0 .#!Alc5!7K3x*K":w)1K|ٞzD9QJnҮ*B34W(9,.:_v;DgE-nW7G[_gʊ#_eE)-)WxQ<-:CH״7++v+߈>.dҌތ)D$hJǁ񦗍Iz-L.>dp׺K> q[,7q/hR]dh{2dq2֒ywxn ]L޳t1xt1mzU-Uڤv'@ZuJz ^3"U6f(1c!Rn<Bǝ$~t*f!X;z+|=>YQt=~Wh9Xs[PQďdc.VN!-,('uز_oityn ̄_rdVB+KqQ$jpk2nw+91Lwfz`4^UkH~l jncitYӑ7~O.,'E/q`NN QAńl!9;%W@/VM隦4.)B̚4qv8BXy> +߶xօiN95_u:buƼ Ϛw=z oO}󝒹//nqc \^.Χ(/=/In'ӓ[dKHsztMuNB2ѥAܿTgHrW*G=RtsrV@@)G܎l!KN{w r55/%H'qs` :!q?tӐvPH-O$ғ}嵅 HFh|Ҕ; yU .EX`|(XXH*F7c~h{(SV|^iz8vAo"UL]*8$n &kHZa k[Ȗs_PKyKD Rsetup/opening.htmlUT uYuYux XmSH_1J1lU.MquV[z46 $Z>fgfӗTj$9suv98=}`tMͿ?_7>{n܇pn]T]׿ؿUytjjs[t2 PykIjUjѵJI뼵90zxb[~Wjm[K jW*ՒlѬYE[c*]PweI6z5fT#Y\tA֝iR#;'Ku.W{j-1%ĥR|;ץT4bC "TFmnսe6,SmוCo7y:ocSmV3]>:%n~DFJy> %}aX~ 2-Gw%nt_P1H3 ҭ*\+K_5&ңj]}&jJ3/6c^=Y_,k+ǯ2x:dh}"F}WzA9!Ck6d:k &b 3{&dzEQ~au˛? KQeFpQLFS緵لxAYDqŠ g|]ΐ|6\Ƭlj ZeUGȚS5FJc)I'-7) h,LuΓXL)cU*5^90/y;`C(t-VP4DMu9mt5`Ma$'rJVgu̲Mo6k||XB*pH;_ @ /e<69B81jWN|9=j*9}u<:y> @<_L$9:>Dpx<:DIq]=4 n1.S,p[0ˈk$Kx[R*`]#LZ 严Na yo(#ԫ#LW}yQcVN>%P?%G׼.uF02"m:'P5Sk&kEom{創;A{fZ@6h5XЅ]TؖgNHH< :Lx כ8S;vL ж3gO-><Q?oSgPZئ~\z*, ΢/Z>t ^W5xoIi3tt\mɫKaކZ@?l0Xh Yc8 k b\f[S%_sq w S?+ힳT&x苲Ez[}/y{!ϋˡ`,/X>̦C~J|{ -qA9̊W>|yQkn7 (:O%2q13\ ]RY?Y_Y~+I Cd9K]]S18koYD?F** >\ >oq!oh{zluhM;׌PKyKxJsetup/mutaties.htmlUT uYuYux mRn0 +8"%;t@uQ9[,e4юnxE)~- .+qM&Lb%$}S|?ڂX(mU{\.h J~oyiR2d1Oyk\m&",dBJUŨX%oi | Fiu]M8`)F)sס_o7ˑ5uܮ] ) @ Fe&P m{tuJ4A Ԇ  }%C C-5gpDuoF!xіNiZG>hνI(N;'䇮CIi6,aVk讒~<1fb/am^pW?:PKyK stdacc.htmlUT uYuYux WQo6~1XZ id5<{(,ӢD$~GR!5 Iɻ#}`J݌ذ?`MlV_\<Y/ny<>Nw_;O/?d2ā7V:Uh*A:G.I0KzMՈYو&aZ1.^oS/J;)< /" < ٤ծx>^UgݶHc%62Dk)GMÜ·Zb!^+l6FKp[]2aO6ڼ8doF`, 0Z^WtWf'-ؠ/ 6&Hp8Hy/Rc-sy|‹eQ&< P>>A#cKީҽPJt&Yv8u~T&[ 3,PDwxjIEd\!OFCk)ܜz T"w,hC|+YYr 2/YςKG^lG'cĊ lDBZ6$v/fv$ux*Y5<,G\Sd5A!nd:ahrSοp\OLoN̵.q#qvXtpU49.)ly*QLRЈp^}+>-4@ې8?:d}ȶ#4~ i.}?Z:E^,^ :}xTKzkcCڇk'T]O'僔}sC n'Oii{EOw=0 )*J =Je?PKyK5ctopics/kas.htmlUT vYvYux =s ]^;SKǮ. 8R1sFHzDF֭U9*W[,I2XjC[Pm2m OG&BUG2~+UOU͊mr wɆm2D WAd$-ZQ:""h4 4EnqxQјyuʈO EyBct,!5 ~n;s5d&P-+6HM&@`-X52;HHDաcɥ@>!<ᙕd\ 3}~?N Ԙ']GNcJ$?ŁL PKyK0CNtopics/btwaangifte.htmlUT vYvYux TM0+F= 6iI#-ZaWBbi&{l7+3G?%y3%m3Te*YzLaMj'cC;1R"]PKyKhثtopics/rapporten.htmlUT vYvYux ͔Mo +F{zHHЪ7, n~}̶ɭc``xxAYOhD{65Z#Pz4u';g%D8Vc#,nKm7 ZC$MGQ5u|ti,/l}+bqkn˫+a:msjZ6H*UPce'àVz<I=vx.BY2QEJ}V~_J_|j4BPO7^[Ky΂l~PKyK%CK[Qmtopics/dagboeken.htmlUT vYvYux ).)KKILOONͳчp؅()dfd*%)$'gdf'%*)5%XCH$cPKyK|J9bVtopics/toon.htmlUT vYvYux RN0j4;X gٗDӦ!Ut}{YODtDNFj j.ЁqX`O}/bo@~ݹ:9ȳ(JSgʹ@_SͲP V0Jk2_"EZ)6Ia&=މ_+Z1<ΕI?z#"^eF!f֐Niٴ wmW΅+ds2Εƒ,*G)A4T$;Ω((f9TL`VJg<ћr N&sBà56RIa2i S8c PKyK3%gtopics/memoriaal.htmlUT vYvYux ;O0w>ũ^,l8%K{U6d\PB誜< $Yh][Pm2`'x Jw?ڦ/R*UYmCr0&ٰM|3qPV-LKt.d CVSFȘZI^D\wig2a`NVȶ,@"y.w 激X<]_ΜC-)#2'/ʹ~uRSɁ" Z \#X.s`}TDt\1\JZ#YIFOȕ@8WsD7c pr^yпPKyK}֗topics/adm_begindatum.htmlUT vYvYux ePN@ D'J/ANIۗ6NN;Dcɣ{f"%Ѣ L{Loz'*Ɗ#Wz#W, Hz DStTfIg k_+\I.8]Sib{-{GöM~O3`?z\O#ue@3Lj*eGwm LCuQU$m5-ZR*ڌqH%PKyKȉ&htopics/grootboek.htmlUT vYvYux R=o0 +pMDgSKxOV-̻E|(>thC?#)7i]("\{\aNdD %zH>\g5og^x;.lz}AF:=mm/SL1fWzRiS+v_Q< hkӤȵ-q5 DT%:Q9P1IθK4}C đǑÞ'Wm8}|2-j_/ソ ́ mDI)_hezgė7QmVsVv-vp))1DI>y"hl_#Z)PKyKbQ9Y topics/adm_open.htmlUT vYvYux V6+‹=e i9=֢((s,Ib-7) (qo>jS*mc}f~ω!;:)G+g0G%iywHVvcR==iz t@~NC]A3 111 kxJ .#}&,stMV^+ӀߔxMᖇnABxI$b }˱"Miz+b3ST& "(EQHY@=>iށjy!_㵞Qt oA =EK4Be RN\CWSzt(DY$It~{=.l@_ $og"{ځe2]^%mdfv#?'mWZB%RGV\dke~ao~5nͺkj5 pcܼ% 3.]VFluRr["@4ZQ__=vn/FnTPV رm'iK5?kLPX-('F#DaEx{ 2K*a,~ԟ_F"2F :8TCч XP:$.[ƽC>ed-Hj1].r B-Hi&ALˎ4[oy]>^d7*t)-/}q*u'w,meL{[&c</PKyKNȀKtopics/adm_naam.htmlUT vYvYux u;0 {Nb`RQo͎( ̞;n2 WA|l\#5qC-AI FcڃTWcPÞ\ǝS<;v9?cq_[f0&#G6M5_` K,I.Ȍ Q  YVq[j}O?,]PȗnOPKyKujk/topics/schema.htmlUT vYvYux SN0 7}VZwb2ݶNׯN`аtl?/Uq+;TcbKa' 32lH`!] =\o:bʌ997qZ~pں0+p RtAg<SH-c]ӥZUFZA١;b3۪=TYeO u%i^}썞;Ј}f mffiXs A \Y֫֫)w4I@zѰdž->=}rQo&a2w:z4 l}/ԑCa%,Mhu @-^u]fPKyK)|rtopics/adm_boekjaarcode.htmlUT vYvYux ]Qr0  aKO`#sB$~}m\$(]~#6ѓ+on35rCz2 FgȈ\9o3R/v&?E(LbwdFI[hxhSUP|xF93,.([+@G'^ey 2J<9uHaJ;;ISjtoNј6ky"qY7Mo0&wtG}/BQv}~l3Iek ,9w̦yBt5Ԧ >@}ܷjq .Z%y8HוzR`25`YZ A"~ }FJjzz'*0PKyK(0topics/adm_btwperiode.htmlUT vYvYux UOIj@9JX$1S,<>Ł\zsSIk؅1C|r0z~18r1ηLz(EH J.R--f(0(󵌡8:{"v^iHcWT:XAlcUJ dAdaBVyfI>IG5PKyKV|topics/crediteuren.htmlUT vYvYux N0D|*nZ @LS6K|=v"$T.Ir=P /YO;v݈ϙxڝqgk=F$PH[&90TѿMNPKyKDwtopics/verwijder.htmlUT vYvYux ePn0 +%[_.E]Ype8JWyE,R$qia2\L,?V1@29z!2cFjAMqy _z:*9 ` *{:\Tq0َ|]S-bwvn=S?1+u7ry,fNn B; DZ$72t`}졵:JhW0cmm@quQPy 8j㬾'֍PKyK^topics/verkoop.htmlUT vYvYux uN0 D|Oܶ{ |CJlhGO+!ebfR3'sΤ0<"u~ҹ Im-oSݔӄv+0О2G)3:\p7qzH\BU-_,+o^>#,5avɳ tpbo$oc^Ԁ f{-Ut8vxa hV'/1<>G PKyK[topics/bijlage.htmlUT vYvYux PN0  L\C.m!ⶲ={z?b)ߏe[4 w.P?pc;BD؆p Ap(: @6Qׂ5iq(q,9IJX!3޽ή~ZHVFtVs.1RǧJ:9g|8{3k4V?㈃"fؕ+Ԩy2itN Xs3~SIajS{m+冠 #UrPKyK2Xtopics/sql.htmlUT vYvYux E=N@ {N1+U*J( nLb7xM+lO1[i9?.Kaeı ad6auxdfh0 N8A93&2RnHŌ3EI\x[򵙌떝Cד碱X /We۟?YU=SYYh"4-Yw|PKyK[topics/openstaand.htmlUT vYvYux ?O1 w>u[i$f@ { ő'^ $hGvtyvT;ΔFELޚytc{eN D xGKwdXԎa_O:x FP2GIw?mzЧe",Gr?Fͧ,צ_h6cOa^(RDxZjP X1ַ:CuV0sxA /"VF0gqtc@ PC2J@ h7PKyK2Ytopics/adm_balans.htmlUT vYvYux Ur0 >.C<@]f-K` q$wy6IH%}Y*릿ڎSn73W36R 2d,K 32qL9w3?P<ДT,:ohkqDPfh<: P ZI0kG:`Q]otf2wa"Hv|#=D&eWww߉ Wig\dH+[tbC71d*HV3USA4}&w&8@2c4c~v¢xvSڪml:աM_iPH:oE6TeL^1Pif"zU;Fd?PKyKg|topics/journaal.htmlUT vYvYux TN0 $r.G6,Ma_l V*ɳ߳8zWWo~UzDaAqi^q AAK?V5,Кڍà:uw hmQ%17d (%sTFTH,|mKZbІƺy N;VVp%KwH}wߔM`Y֫W&-7/6z(h Gr:$F7VOG=ڌ0d0e&y? 3>l/N]I y(i4#]ʭq? x(jA+&t4B nڮUd<75آ8(SZ&LD|$ZPKyKJztopics/debiteuren.htmlUT vYvYux MN0 4{H#qEx:a8rM?T &ygU{QU<E4!,0-Ǿ vo Zx1/߽$GEa 6kU:׶fn=m M%!!ܲmiT]+E `c[MtW@D?%X_Jn Dw4svy4mxj*)gO}!T501PH^${9/PKyKVܳ0htopics/balans.htmlUT vYvYux R0 wB^MԱ|w-YO?)b{)Z`[376w$ BGJ!w`M^X41snSik5a>F_fiK(:m=QawK9g-y 1MZ:ܙס%԰ <q]ЃGFvg`Hܱ:q.!9_0˞fӫڍE8Utr5\cK%\@-ZPmT7;5sPKyKKD~dtopics/bank.htmlUT vYvYux =n0 PC=uP wn\PN[6쮴iv)$gc'& +m3}Uv.&I֎XwƗ5\!QDH:j@(A#8Ǯ[2\KBlg .}=E!D'Ȏ#4Ą|ꀆ|luDhz_V|'GYD@%4YBۑt0 MMVކ"{ݫ>/Чiy0Sr.JѰyP#:S2{_Gaq<#blb,~xɬ'9>0wƮ0PKyKKadjtopics/export.htmlUT vYvYux Sj0+B }oCɩB dk(%#nGz/^ѮJ.MH庬$,R(p DU@UVWۑ'%"ՕI,Ro!ԟ-$|4ib9LBfVW+b/$V4Cm➵JbC"0cGNQ.ti3Yr'xEZ7\XT\rtq:2|vC%3)E%,/-ݚ*yp7G Nz']5=omK@*gn~LZq4A F# w R#.pp.%hJdyDזm%<+yW| S/PKyKCg topics/jaareinde.htmlUT vYvYux R=o@ + kO E2tТ),%OݠEI=SVb$b+Ce8s#%z6{x";Dɳo, ރ~L M(LcS&ppuJQ)g(CqCYIpL(i&!HLsL-acv-Feȧ3 @j_hYQ);shPԤ@epBSΈTq,+bTdP+;_.~@ɕ, 9|X 끪2Ev6p"+, -6X ޽BQÞx:ͫҭ09…;]1vVK˚O8IKwi4fr1$".>}lNYwRZ-N(e_&`޲oH*O_ \hSW5! 5YX Œ~k]ģO+q&+PKyKtopics/inkoop.htmlUT vYvYux uPR0 MlMb5I$ߣ8I8`I=ɍ*LI1gWoqfH2vN$4|\J0{oeW2H혟ץfwujNG$ '(NÂ݋r9'5"$ka3x[-bGҝ$_R=\QAY]{؀Y4M:*LlF*APKyK:Z&itopics/adm_relatie.htmlUT vYvYux eR1n0 "C"[K3s.l2mK2$bxwRSJ߀Ji=Us=cK!?I)f,TV>4Ap4gg|6AEcZDZE5ƶ4kPU۪OLssӄ \ip/X u{k1W73_NŐ- بI(ʀ"4n y >JI+36[*ޏws?.>h&\=}N^h*} WRDdC}kT'ugWq˼m`daCem&,4nEcrA`zrįLAOL)Rt"|y~z KYMNo㋟GljvңU}痾RKK`g?(KfAS%ObΝ$KS ãf0~f(cO‡E|{ևˌ7WT|9L 4[sk ͆ +-zzLnC؃Ls2qecж+z4p[@Ĉ NM|L1Iǖ෠+DŽ墒Z:o W[KPrU Aj]YMΔ6#+H'hژgH{NX#=!` =\DyZLLJLZ 2f1,   NkB+,_s;oyFNI('@v Zɹ`(t'Ӵ DSds8c3ҏ&b]%4o E_D, ؛Cy9/wElH0 1X}»dwl-y6.2OZXQ|JA; DƎ\iFĂ+ Hu\)xOEvidZ(A2+ P(X| 16-Slm, 9lXBNuGqĠMA)x֌5+4-vL얋0P#(b<c 65FDsP&^ QݾMl]:sBMkNU^D3~X-kcuAR狝 "*?RVR70vMmAQD{p/bȓp4]J03\~VWm6w3x;j}wMxmϒL?8w/PK yK Abookings/UTuYux PKyK띃j{Cbookings/receivable.htmlUTuYux PKyKi^@bookings/index.htmlUTuYux PKyKdrC 1bookings/btw.htmlUTuYux PKyK4ABRTbookings/memorial.htmlUTuYux PKyKBE{bookings/oneline.ttUTuYux PKyK`Fbookings/refcode.ttUTuYux PKyK= Qbookings/payable.htmlUTuYux PKyK>YN*bookings/cash.htmlUTuYux PKyK`| O'I,bookings/bank.htmlUTuYux PKyK[Bi "8commands.htmlUTvYux PKyKORD 8config.htmlUTuYux PK yKA Mcss/UTuYux PKyKV, KMcss/cheat.cssUTuYux PKyK%խY #Ncss/site.cssUTuYux PKyK:j Pdate.htmlUTuYux PKyKZHR/Sdocs.hhcUTuYux PKyKCKfKWdocs.hhkUTuYux PKyKeQ_Wdocs.hhpUTuYux PK yKAXebshell/UTuYux PKyK MbuXebshell/index.htmlUTuYux PKyKL`ebshell/files.htmlUTuYux PKyKaXJhbebshell/clo.htmlUTuYux PKyK]#Ggebshell/commands.htmlUTuYux PK yK Aoebwxhelp/UTuYux PKyK2/UqRoebwxhelp/ebwxhelp.pngUTuYux PKyKP|@+ebwxhelp/index.htmlUTuYux PK yK A[ebwxshell/UTvYux PKyKfHCIebwxshell/edit.pngUTvYux PKyK*Y ebwxshell/index.htmlUTvYux PKyK6 MrTebwxshell/ebwxshell.pngUTvYux PK yKDY]ebwxshell/button-edit.pngUTvYux PK yK8oILbebwxshell/button-ok.pngUTvYux PKyKV>,febwxshell/files.htmlUTvYux PKyK(1-hgiebwxshell/clo.htmlUTvYux PK yKAlimages/UTuYux PK yK7!mimages/youtube-mini.pngUTuYux PKyK42(hoimages/linkedin-mini.pngUTuYux PKyKZ+ O qimages/ebname.jpgUTuYux PK yK;Fʧ.|images/twitter-mini.pngUTuYux PKyKii~images/perl_powered.pngUTuYux PKyKR Aimages/eb.jpgUTuYux PK yK`xGG3images/identi-ca-mini.pngUTuYux PKyK$NC ͢index.htmlUTuYux PKyK8 ~X inex.htmlUTuYux PK yKARinstall/UTuYux PKyKǾm*install/index.htmlUTuYux PK yKAMintro/UTuYux PKyK1Rintro/opening.ebUTuYux PKyK|F ()intro/schema.datUTuYux PKyKZ @intro/index.htmlUTuYux PKyKb"}yintro/relaties.ebUTuYux PKyK~ւintro/backups.htmlUTuYux PKyKSm Iintro/working.htmlUTuYux PKyKkF# n intro/mutaties.ebUTuYux PKyK#sGintro/eekboek.confUTuYux PKyK3B license.htmlUTuYux PKyK$;b; period.htmlUTuYux PK yKA_reports/UTuYux PKyKcGreports/result.htmlUTuYux PKyKzk|)reports/unpaid.htmlUTuYux PKyKy6reports/proef.htmlUTuYux PKyKhX reports/index.htmlUTuYux PKyKcLU reports/grootboek.htmlUTuYux PKyKԎ*v 9(reports/btw.htmlUTuYux PKyK׌;reports/open.htmlUTuYux PKyKzW7!reports/crediteuren.htmlUTuYux PKyK_b(reports/journaal.htmlUTuYux PKyKth=1reports/debiteuren.htmlUTuYux PKyK>ZP[ }8reports/balans.htmlUTuYux PK yK ARBscrshots/UTvYux PKyKȸBscrshots/Balans.pngUTuYux PKyK>=* yscrshots/index.htmlUTvYux PKyK=4c3Pscrshots/Help_Index.pngUTvYux PKyKN'"scrshots/Help_crediteuren.pngUTvYux PKyK:'ascrshots/BTW-Aangifte.pngUTvYux PKyKwBwWpscrshots/MenuBalans.pngUTvYux PKyKA糞Tscrshots/Wizard2.pngUTvYux PKyKl7Jscrshots/Journaal.pngUTvYux PKyK=%ц scrshots/Wizard1.pngUTvYux PKyKCt~  scrshots/Administratiekeuze.pngUTvYux PKyK'`&f$v scrshots/Debiteurenadministratie.pngUTvYux PKyK0_#d scrshots/Grootboek.pngUTvYux PK yKA+setup/UTuYux PKyKȿ, +setup/relaties.htmlUTuYux PKyK|_~FT1setup/index.htmlUTuYux PKyKt 3setup/config.htmlUTuYux PKyKڜwZ=setup/init.htmlUTuYux PKyKM,@setup/schema.htmlUTuYux PKyKD RPsetup/opening.htmlUTuYux PKyKxJYsetup/mutaties.htmlUTuYux PKyK [stdacc.htmlUTuYux PK yKA`topics/UTvYux PKyK7W`topics/relatie.htmlUTvYux PKyK5catopics/kas.htmlUTvYux PKyK0CNcctopics/btwaangifte.htmlUTvYux PKyKpO[! ftopics/result.htmlUTvYux PKyKb ogtopics/periodes.htmlUTvYux PKyKhثhtopics/rapporten.htmlUTvYux PKyK%CK[Qmjtopics/dagboeken.htmlUTvYux PKyK|J9bVktopics/toon.htmlUTvYux PKyK3%g8mtopics/memoriaal.htmlUTvYux PKyK}֗ntopics/adm_begindatum.htmlUTvYux PKyKȉ&h?ptopics/grootboek.htmlUTvYux PKyKbQ9Y qtopics/adm_open.htmlUTvYux PKyKNȀKutopics/adm_naam.htmlUTvYux PKyKujk/vtopics/schema.htmlUTvYux PKyK)|rxtopics/adm_boekjaarcode.htmlUTvYux PKyKWO= 0 AND jnl_type <= 1); -- Bump version. UPDATE Constants SET value = '16' WHERE name = 'SCM_REVISION' AND value = '15'; UPDATE Metadata SET adm_scm_revision = (SELECT int2(value) FROM Constants WHERE name = 'SCM_REVISION'); COMMIT WORK; EekBoek-2.030.1/lib/EB/res/migrate/001000010001000011.sql0000644000400000040000000000256112725476602016621 0ustar jvjvBEGIN WORK; -- Drop foreign keys to Relaties. ALTER TABLE Boekstukregels DROP CONSTRAINT "boekstukregels_bsr_rel_code_fkey"; ALTER TABLE Journal DROP CONSTRAINT "journal_jnl_rel_fkey"; -- Drop primary key Relaties. ALTER TABLE Relaties DROP CONSTRAINT "relaties_pkey"; -- New PK constraint for Relaties. ALTER TABLE Relaties ADD CONSTRAINT "relaties_pkey" PRIMARY KEY (rel_code, rel_ledger); -- Add column bsr_dbk_id for Boekstukregels. ALTER TABLE Boekstukregels ADD COLUMN bsr_dbk_id VARCHAR(4) REFERENCES Dagboeken; -- Fix FK to Relaties. ALTER TABLE Boekstukregels ADD CONSTRAINT "bsr_fk_rel" FOREIGN KEY (bsr_rel_code, bsr_dbk_id) REFERENCES Relaties; -- Fill. UPDATE Boekstukregels SET bsr_dbk_id = ( SELECT rel_ledger FROM Relaties WHERE rel_code = Boekstukregels.bsr_rel_code ); -- Add column jnl_rel_dbk_id for Journal. ALTER TABLE Journal ADD COLUMN jnl_rel_dbk VARCHAR(4) REFERENCES Dagboeken; -- Fix FK to Relaties. ALTER TABLE Journal ADD CONSTRAINT "jnl_fk_rel" FOREIGN KEY (jnl_rel, jnl_rel_dbk) REFERENCES Relaties; -- Fill. UPDATE Journal SET jnl_rel_dbk = ( SELECT rel_ledger FROM Relaties WHERE rel_code = Journal.jnl_rel_dbk); -- Bump version. UPDATE Constants SET value = '11' WHERE name = 'SCM_REVISION' AND value = '10'; UPDATE Metadata SET adm_scm_revision = (SELECT int2(value) FROM Constants WHERE name = 'SCM_REVISION'); COMMIT WORK; EekBoek-2.030.1/lib/EB/res/migrate/001000013001000014.sql0000644000400000040000000000102712725476602016623 0ustar jvjvBEGIN WORK; -- ONLY: SQLite SELECT * INTO TEMP TAccounts FROM Accounts WHERE acc_id = 0; ALTER TABLE Accounts ADD COLUMN acc_dcfixed boolean; -- fixed d/c -- ONLY: SQLite ALTER TABLE TAccounts ADD COLUMN acc_dcfixed boolean; -- fixed d/c UPDATE Accounts SET acc_dcfixed = 'f' WHERE acc_balres; -- Bump version. UPDATE Constants SET value = '14' WHERE name = 'SCM_REVISION' AND value = '13'; UPDATE Metadata SET adm_scm_revision = (SELECT int2(value) FROM Constants WHERE name = 'SCM_REVISION'); COMMIT WORK; EekBoek-2.030.1/lib/EB/res/migrate/001000014001000015.sql0000644000400000040000000000046612725476602016633 0ustar jvjvBEGIN WORK; ALTER TABLE Boekstukregels ADD COLUMN bsr_ref text; -- reference -- Bump version. UPDATE Constants SET value = '15' WHERE name = 'SCM_REVISION' AND value = '14'; UPDATE Metadata SET adm_scm_revision = (SELECT int2(value) FROM Constants WHERE name = 'SCM_REVISION'); COMMIT WORK; EekBoek-2.030.1/lib/EB/res/migrate/001000011001000012.sql0000644000400000040000000000052312725476602016617 0ustar jvjvBEGIN WORK; ALTER TABLE Boekstukken ADD COLUMN bsk_ref TEXT; ALTER TABLE Journal ADD COLUMN jnl_bsk_ref TEXT; -- Bump version. UPDATE Constants SET value = '12' WHERE name = 'SCM_REVISION' AND value = '11'; UPDATE Metadata SET adm_scm_revision = (SELECT int2(value) FROM Constants WHERE name = 'SCM_REVISION'); COMMIT WORK; EekBoek-2.030.1/lib/EB/res/migrate/001000012001000013.sql0000644000400000040000000000173712725476602016631 0ustar jvjvBEGIN WORK; ALTER TABLE Standaardrekeningen ADD COLUMN std_acc_btw_vp int references Accounts; -- BTW verkoop priv ALTER TABLE Standaardrekeningen ADD COLUMN std_acc_btw_ip int references Accounts; -- BTW inkoop priv ALTER TABLE Standaardrekeningen ADD COLUMN std_acc_btw_va int references Accounts; -- BTW verkoop anders ALTER TABLE Standaardrekeningen ADD COLUMN std_acc_btw_ia int references Accounts; -- BTW inkoop anders INSERT INTO Constants (name, value) VALUES ('BTWTARIEF_PRIV', '3'); INSERT INTO Constants (name, value) VALUES ('BTWTARIEF_ANDERS', '4'); ALTER TABLE ONLY BTWTabel DROP CONSTRAINT "btw_tariefgroep"; ALTER TABLE ONLY BTWTabel ADD CONSTRAINT "btw_tariefgroep" CHECK (btw_tariefgroep >= 0 AND btw_tariefgroep <= 4); -- Bump version. UPDATE Constants SET value = '13' WHERE name = 'SCM_REVISION' AND value = '12'; UPDATE Metadata SET adm_scm_revision = (SELECT int2(value) FROM Constants WHERE name = 'SCM_REVISION'); COMMIT WORK; EekBoek-2.030.1/lib/EB/res/migrate/001000008001000009.pl0000644000400000040000000000406612725476602016455 0ustar jvjv# -- Migratie EekBoek database van versie 1.0.8 naar 1.0.9 (EB 0.92). package main; our $cfg; our $dbh; package EB::DatabaseMigrator; use strict; use warnings; use EB; use EB::Tools::SQLEngine; my $en = EB::Tools::SQLEngine->new(dbh => $dbh->dbh, trace => $cfg->val(qw(internal trace_migration), 0)); $en->process(<trace($cfg->val(qw(internal trace_migration), 0)); my $sth1 = $dbh->sql_exec("SELECT dbk_id". " FROM Dagboeken". " WHERE dbk_type = ? OR dbk_type = ?", DBKTYPE_BANK, DBKTYPE_KAS); while ( my $rr1 = $sth1->fetchrow_arrayref ) { my ($dbk_id) = @$rr1; my $sth3 = $dbh->sql_exec("SELECT bky_code FROM Boekjaren"); while ( my $rb = $sth3->fetchrow_arrayref ) { my $bky = $rb->[0]; my %saldi; my %amt; my $sth2 = $dbh->sql_exec("SELECT bsk_nr,bsk_amount,bsk_saldo". " FROM Boekstukken". " WHERE bsk_dbk_id = ?". " AND bsk_bky = ?", $dbk_id, $bky); while ( my $rr2 = $sth2->fetchrow_arrayref ) { $amt{$rr2->[0]} = $rr2->[1]; $saldi{$rr2->[0]} = $rr2->[2]; } $sth2->finish; foreach my $bsk_nr ( keys(%saldi) ) { if ( exists $saldi{$bsk_nr-1} ) { warn("SALDO MISMATCH: dbk=$dbk_id nr=$bsk_nr -- PLEASE REBUILD DATABASE\n") unless $saldi{$bsk_nr-1} == $saldi{$bsk_nr} - $amt{$bsk_nr}; $dbh->sql_exec("UPDATE Boekstukken". " SET bsk_isaldo = ?". " WHERE bsk_nr = ?". " AND bsk_dbk_id = ?". " AND bsk_bky = ?", $saldi{$bsk_nr-1}, $bsk_nr, $dbk_id, $bky)->finish; } else { $dbh->sql_exec("UPDATE Boekstukken". " SET bsk_isaldo = bsk_saldo - bsk_amount". " WHERE bsk_nr = ?". " AND bsk_dbk_id = ?". " AND bsk_bky = ?", $bsk_nr, $dbk_id, $bky)->finish; } } } } $en->process(<2-@q(0777H)L&Cww7\?8訝rL8fjjrBa5:BPp۶6Bt])n(B4d4evvt:iRJ.//n $ gccR&dm ]1Ezzzxzzz?`Yx#(JÇ,j:G>h~:}~~VR\yi8mK{l6bx}+˛}Pg 2kŤlIENDB`EekBoek-2.030.1/lib/EB/res/Wx/icons/eb.ico0000644000400000040000000052054612725476601015426 0ustar jvjv  (((L00 %>00B00_  6n  ~  h.hh( ŠhB"S¸JAU7r!°q+\–ˆÇ0i“±»nV†¨¸¨ƒ<*h“¯¹Ÿp R¸º¨‡CFy¢¶¹®J>r™³—a/j±»´nfffeeefeffefffeEexfxfFeefe eje}f`febe@emeqfLfeeedesf`feefee]ezekf,fefd eSeofmf<efeEeyevfDfehXdeedeeffjbMdfdeee'ej] ceedeefebAdedeee5ia1dfeeeeag`!dfddee~ ceeeeeffju{yrjfeftb2pz{tlfee \kut{zrjfeVd%oz{vmgefbmy|wngfeOXlw|xpieeviu{yrjfe~fevJpfeGewhff{)pfeYehxiet}ke~elfa,tDqge7  ped ; yge ~  qe }guKgj{ l^p  pfe ƽ##2244-- nb --5500!!tfF ##2255-- n_#t--6622##x{))4433&&}y''5544** p##2244,, me0 CC^^``RR55|f.Ҹ77TTccYY@@## ht  CC]]ccTT77bAН55UUcc\\CC'' --OO``^^GG++ ((JJbbaaNN00 CC^^``SS55yj2 66jjSS++ x.$$XXdd99wx 55jjVV,,jO UUgg>>JJ||ooDDBBttxxLL$$ 77kkTT++ z/ Cpe#HJqq::0 s5V SS !!-- MM..6 00xxMM2i ")./ /0678AGHtt==u6UU! D>1%?? rr 66(( DD22**.."" $ ""ܦ*+ssSS!!'ee]]'' *)YYhh11JJqq::UUJRBB :s44YY""# N HODD ߏ 77)Ĝe$.__%% r h% pqll,, @ U&^byy77PPBB }DD=>a&%||UU!`.A??S|oU$ vw[[ ]\ehh'(7zIUww22Q~FF>> fl&O$qvkj%+0';;||͘˝˝̜юmm72rLU@@YFEN!ksmm--]MEDƱЎoo;;&&rrΕ̝˞̜ΓuuEE ~>PEE}lT9>QQQLH3__**𣣽mmF&&vvjj%%''Ɵ9W [G3mnmm9=[ɣ¹KR[zzNNSR¸˜K<1hnnn<<vuſğ~~ЍƮ_KW||SS!(  CJ{|\\&*) BAvxee00Ŀmq88nnnn99~~  o)G!!,-"$4H QQъƭˠQQ r)*'( kkþ66,A\ >L+. #(*»͛ԋteƷt,,_``~~ɦȪgg^#*++! ()ky5&*,Yc9",."69öԃi`b@!!--$$..DXXpW  "ffɿII]| cw W987 d< 0000 ##pqOO4Equ8 ee*fe::16  1ee fffdf?S+ 5577? 6is!ee  r7>M<NVC" roeeeecffgEc9if5Q`?%heeee]fhbd{ed6Q* GG4 WB<N>Lp8g<)Vfee>gf''d2Usqmk `(PGonjgeefc<jnmlk]$6TnmjfeexhWhmnkjer8M) frokj0R^rnigeeEe)B[zo_pA~mffMem|xkYbK{lfeTw~qe&>>-/ qvjLG .gwjfee1   qh;  pewV  jg:   ob}A  u:O L (Go |eD  jdke gWs""''!! `zO ''## le/$$'' )XtZ""&&"" i &&$$ r UU22* %%&&|b?; $$&& ~id <911HHNNFF//v***BBOOFF22 ef 55JJNNCC++t,//GGNNFF00{++DDOOHH44 &B99MMLL>>&&o44JJKK@@))se5#%RRvvqqNN**KKqqvvVV00pz ++XXyyllHH%%  ""NNvvssPP--IIppwwVV115&& I66aa}}}}ee@@ --[[||mmGG## s: 58yypp==,,llxxEEyv AAhh66 44uussBB++kk||HH6Y44GPP]]-- BCee44,, XK ADKKK44UU!!O MMBB ۸<>,,??ґz__UB$qDDll%*$$HC4ww33 F&ɥ{r7=E\\:>ك}O82x~hh,, ~KKSS??\\CCaa##--ϼooܰ<44ow|tlgeg;X{~}vnnKGcow~|tmj]mfu~}vnhfflIs}~xohee1 .Yh~yql aAT~{sjfeeeB ~MsgbLz$xm(51shc`yjct |je5q>M6peezz>FF  s` z1T{ te_ zd ~huL p me$$ t LL!˿&&889911j ##44::44""u  :2((($%%5599"" 2'S%%66::11r 449944##q 11;;66&&u..;;77))TO++8899,, h++))&&$=d M3""GGccffXX99BB``hh\\??!!  "GGcchhXX:: @@__gg^^@@$$ ;;[[ii``GG''33TThhbbKK,, ,,PPffeeQQ33 o U##699qqXX..//hhaa44  68nnYY..++bbbb99$$\\kk>>QQssFFFF{{zzNN$$  V GGjj)JJuu<< @@FF -FJww>>47:KK00{{RR!!$$ll\\(( (^^hh00  `?== EEOOBB DDOO X GOEE)y3=SSط44]]##&&vvhh++Ieevv55 So m944 AAtAA<<m_77HH c| s w wv |  n3>>>cs8>.MMѨD**yyWWffcc#% _ PVpp// ]lXj t  ; "))mmee'''``qq,2 , &%iihh'*' mS\vv55 UNN??_a??HJj.8/}UUF@aa F  7 $$ O55aavvbb55O/++XXvvei5>#`<11__vvaa35.WE*-VWuuii@@{##OOssnnGGFFnnpsIR"#X lI9alrwRY#*; qoo99 w : @$$,,$$B-!!1-K"dRN 9$$..#%+貹Fw L!--((` }--**jh.*F%W{UpU$Tw$--< t99-, 11H // )+  F%.!/ 5 V.%>>.II  ^33$ 2  R]$$<! 3@@@ 0 ++)) y :: BBLL "hh jj 3 $$ tI??XXWA44'' N3pp,,ff77 J * pLL00::"PP=QQ++ p v,82 n'f--(( f q**YY> V**nn c0kkFF( 88+  R//22 i <33T T22ccG 8 d.. II BBMM55FF'' 7 KK\\ &}}WW >!! ]eexMff?R# r44WW.. U>>DD 2B($$$$$$$$$$!!$%2 H s ..OOm Y44(((I T77 $ t.%%< T m ,,SS p22 :: _X 00""$$! ],,//&& |s g]U F@3((+))VVnnHH##HH'((& &.++56 6=%%FEENUUU_e dent ts _9  ~ nbVGFU V^d kst     vE44 ww0 >|8?`?@???`???????? ???p?    pp???????(¿¿fffeeefeffefffeeffeefeeeffebeeeffeeeeffeefeeeeffefdeeffefeeeffehXdeedeeffjbdfdeeeej]ceedeefebdedeeeiadfeeeeg`dfddee ceeeeeffju{yrjfeftbpz{tlfee\kt{zrjfeVdoz{vmgefbmy|wngfeXlw|xpieeiu{yrjfefevpfeewhff{pfeehxie}ke~lfatqge  ped yge  qe }gugj l^  pfe##2244-- nb--5500!!tf##2255-- n_--6622##x{))4433&&}y''5544** p##2244,, me CC^^``RR55|f77TTccYY@@## h CC]]ccTT77b55UUcc\\CC'' --OO``^^GG++ ((JJbbaaNN00 CC^^``SS55yj 66jjSS++ x$$XXdd99w 55jjVV,,j UUgg>>JJ||ooDDBBttxxLL$$ 77kkTT++ z p#HJqq::0 sVSS!!--MM..6 00xxMM2i  8GHtt==uUU ??rr66((DD22**..""  "*+ssSS!!'ee]]'' *)YYhh11JJqq::UJRBB :s44YY""# N HODD  7e$.__%% r h% pqll,, @ U&^byy77PPBB }DD=>a&%||UU!`.A??S|$ vw[[ ]\ehh'(Ϭ7zIUww22FF>> &O$qvkj%+0';;||͘˝˝̜юmm72rLU@@YFEN!ksmm--]MEƱЎoo;;&&rrΕ̝˞̜ΓuuEE ~>PEE}lT9>QQQLH3郆__**⣣mm&&vvjj%%''㏏ [G3mnmm9=[ɣľ¿¹KR[zzNNSR޺¸˜K<1hnnn<<vuſ~~Ѝ¿Ʈ_KW||SS!(  CJ{|\\&*) BAvxee00Ŀmq88nnnn99~~ o)!!,-"$4ٷH QQъƭˠQQ r)*'( kkݹþ66 >L+. #(*»͛ԋƷ,,``~~ɦȪgg^#*++! ()y5&*,Yc9",."69öԃi`!!--$$..XXp ffɿII W97 < 0000 ##pOO4E eefe::1  eefffdf?S 5577 6see  r7>M<NVC" reeeeffgEcif5Q`?%heeeefhbded6Q* GG WB<N>Lp8g<)Vfeegf''2Usqmk `(PGonjgeefcjnmlk]$6TnmjfeehWhmnkjer8) frokj0R^rnigeeeB[zo_pA~mffem|xkYbK{lfew~qe&>>-/ qvjLG .gwjfee1   qh;  pew  jg:   ob}  u:O  Go |eD  jde Ws""''!! `zO ''## le$$'' )XtZ""&&"" i &&$$ r UU22 %%&&|b?; $$&& ~id 911HHNNFF//v***BBOOFF22 e55JJNNCC++t,//GGNNFF00{++DDOOHH44 &99MMLL>>&&o44JJKK@@))se5#%RRvvqqNN**KKqqvvVV00p++XXyyllHH%%  ""NNvvssPP--IIppwwVV115&&66aa}}}}ee@@ --[[||mmGG## s: 58yypp==,,llxxEEyAAhh66 44uussBB++kk||HH644PP]]-- BCee44,, K ADKKK44UU!!MMBB <>,,??ґDDll%*$$HC4ww33 ɥ{r7=E\\:>帐ك}O82x~hh,, ~KKSS??ṹ\\CCaa##--ꢢϼoo<M6peezzFF  s` z1T te zd ~hu p me$$  LL&&889911j ##44::44""u  ((%%5599""'%%66::11r 449944##q 11;;66&&u..;;77))TO++8899,, h++))&& ""GGccffXX99BB``hh\\??!!  "GGcchhXX:: @@__gg^^@@$$ ;;[[ii``GG''33TThhbbKK,, ,,PPffeeQQ33 o ##99qqXX..//hhaa44  68nnYY..++bbbb99$$\\kk>>QQssFFFF{{zzNN$$   GGjjJJuu<< @@FF -FJww>>47:KK00{{RR!!$$ll\\(( (^^hh00  == EEOOBB DDOO X GOEE)y3=SS44]]##&&vvhh++ۍIeevv55 So 44AAAA<<77HH c|    n3>>>cs8>.MM**yyWWffcc#% _ PVpp// ]l   ))mmee''``qq,2 , &%iihh'*' mS\vv55 NN????HJj.8/}UUF@aa  $$ 55aavvbb55++XXvvei5>#`11__vvaa35.WE*-VWuuii@@##OOssnnGGFFnnpsIR"#X lI9alrwRY#*; oo99   $$,,$$!!1-K"dR $$..#%+Fw !--(( --**.*F%W{UpU$Tw$-- 991нH //   5ǰV.%>>II  33 2  $$ @@  ++)) :: BBLL hhjj  $$??XX44'' pp,,ff77   LL00::PPQQ++  --((  **YY **nn kkFF 88  //22  33 22cc  .. II BBMM55FF''  KK\\}}WW !! eeff 44WW..>>DD$$$$$$!!  ..OO 44(( 77 %%  ,,SS22 ::00""$$ ,,//&&   (())VVnnHH##HH(( ++ %%             44 ww0 >|8?`?@???`???????? ???p?    pp???????(  b?UDHI&?M#NIl?.4S^0U\b}9^G&cu@h2>Tdk*_m%s H4nrx ZuaTmLw@WRJ/t\ybs:+o{5mu j|;YF a z a& w ;.' &r4$)VM F+ Z -*j +a"7;/;7KQ%!!A4A;%!"*'G(;&455HHD-,,/0&/PR4/TTE7A=976>48N6;A?=<C<1>]aAA_~YDE9ILHeo@KWVMOGQMVTQqqUWPX]Zxq^`fc{ln`h׃~hipl{ykpqqӋswѐ{yw~~Ι̜ȣƮijù¼Ϻ))*##)*##)))#!'))##!)),')),#)))#/QQQL.#*=QQQ/).?HQL/!=UQJ8#=QBJ9*!8?HQ9.!9?HQL*#?M\uiH9#9Ubu}inL)=huiHL#U\{dQ.'QY}bnQ.Dh}}{H.!?h}}id8#yW/!}viL#yd/!}yiL))}y{Q)*yH.#eH.!sd*`n9eĺU.h99s{8/y{Q.}U)zӺ{9QsϾb=sƵ}UQʸUQsϷh?eӼ{/+ͤ}?:jsڳh $I$+ͪ}U)++jojIxݺY_۾{dƦbDyǤu?"|ӫs>伏]$$qۮyVK]0ǝu>ϪeM׵U+CרsF+伎J$Tڪy2+羓b|ɔV XϜt׮sƔfλkڪz$$ʜyλ~λC۱w05vR3侓ƞ+++4ɦTٌӳI$6ʪz|Ϻg+ZڼgZĠêʪl3؟k++ܴzRTA+++t&$++$$++++$$$I$$++++I++$ +#!! $ +$)#'!  !!'!!!! $!#!!!!+$+ ##'!$##'+/L9.)! /99/*'*/8L.)$/99/)!).8L/)! +(889*#  9L9.)!+$ Lh{inQ.!/h{{nQ/#9Bh{ndJ.! /h{inQ/!)BMhihU/)2Uh{nd8*%Jh{idL*+;\y{H.-\yid9!}iQ.0`y{H.!]H/!$+`iQ#>`yiQ*!+O{H)@sH*\viQ'@H)Bd9 $eh=(ViQ#fʷY.Yʼ{=yƷh9nʼ{9Yͼ}B$$syĮH8eƸh.+cʵ?bϱU)ƪ}D\ʱD\ӷh+ݾ{L}Ʀb8O۷BS༏Y׫M຅M༔]ʤ\ElϫuDZݸ>4y]۱sYsཔ]ed$++Ӭs-Rڵy~ӵmFc۷\Ϡm۱y۷m$[~[$+ǒg3ʝyܿŧǜt۷zëǞέδ~ϮvFkݼGy6w~臻yCXc~ANToTNXGGI$I~[+[~3GANN+$+$$$++$I$$$++$$ $ $$!!!!!!! !'!"!!I!).*#'*)*##!+#).*!'#)*#!#**#!*.)#!+.*)#+*8BHQL.#/QdHQ/) +*/BHHJ.)9?dHQ/,.=dHQL.'=UHHL*!=BHdL.!+$+P}{d8#Y}bd=)h}{dL!MuV?)M}nL)D{nQ.#7]iU9'+++]yd9!dyn?)jIVyn8!Uen?!=y{Q)9eviH* }viH/j+$$++ed.{ƾW.bƾd/hh.Ui/B{=/sƽQ+ڼbLeuD׼b={?\ʮQPϷUBzϷh,+++ͮ}BeӮuDxͮJfڳDݷM།]@\7I$ڱsvJ$|ۮy_Z༄]uYeƍe%ϝy1ӪyP۳z<+++++Aګv<&ݷy`伔\Y^ʦy+++tsʒ$tgϠzӪڱzFzSIƝT$gT3ƫDZɸRAͽc+$wz^5w3atpC5kpa$++3++4+I+$$$$$++$$+++$$$++$$$$$+$++$$$$$$+$+$$+$+++++$$+j++$$$$$$+$$$$$+$$++$$$$$++++j+++++++++++++++++++++++++++?8__W_`?8?@? ?wPWwp*w ???????? u@???p?0 _"  * ?pG??????Wt?*? ??ꪯ(0`     !    k²r Š@g²wRbªv²m np-b c>> np*s cCCi m(o-yzshay2xmdElyztha`xVxmc'yowje{uhmzshai""l#!!zg""l& %%v $$ }$$ ""n O%zz + #푑``)1' xx!!:'' 77뙙YY AA@@aa00 zz * Z>,u03 X<2%kOƯ! _;w~gjRSZZDF廬55FF'<wbP{Q cccΖϒOgIEGɗPJ /QQvytyyԄ͗Ћ//8dj7?+x{wYw "nQt>rfXbcmmǼn +j  #=3Y   e  Z? !y ,   8Zfijc)eqxm0kmeHtscā9j]BTMmgo^ dm mV|r\Uo y ,aD3  Fgip@tuff !SS1ggxxttii~~UU>> ?MN*) jjww* *Jb&l- c22ᄎ77-  00S *IDB /0kVtNk[iTuZMICgb}ih`痘͍ccbbssܘӋppRSqMG{{̘~~::Ζ1wKЩmnF{hBӖ   &G 00 +3# RR ))_^rl'     NnukmDMv;COd?R3 6oid+pnhHHDRc@7Xaf Q }  %dO  rp cH s?448 - 2VVcc aaUT |SUdd __VV hhFF))oo99;;nn#*bTa n//ܽs6.E00 [[qs({tKUW A ??99rr΂##9vvmj r : w2qo̓u7lymm}77?VVeMMkZC:2b-GN! #K **##. L$7e((:"2y0"% ((!!>H)w;w;XZ >. @ F 2H z&&%%h & FOO 2 111 6$$v"" s`  X !(V &&mmKK%%++ **  ++    ϏLJ?|??~xx(0`¿ npb c>> nps cCCimoyzshayxmdlyztha`xxmcywje{uhmzsha""l!!z""l %%v $$ }$$ ""nO%zz  #``)1'xx!!''77YY AA@@aa00 zz  Z>,u03 X<2%kƯ _;w~gjRSZZDF嬬55FFbP{Qԣ cccΖϒOgIEGPJ /QΌQvyyyԄ͗Ћ//8dj7?+{wYw "nQt>rfXbcmmݼ +  #3Yˮ   Z? !y ,  8Zfijceqxm0kmetsc9j]BTMmg^ dm mV|rUo y ,aD  Fgi@tuff !SS1ggxxttii~~UU>> MN*) jjww*b&l- 22ﺺ77-  00IDB /0VtNk[iTuZMIgb}ih`ٗccbbss֘ppRSqMG{{̘~~::Ζ1wKЁmnF{hB  &G 00 +#RR))_^rl    nkmv;COd?R3 6oidpnhHHDRc@7Xaf }  %d  rp cH s44 2VVcc aaUT |SUdd __VV hhFF))oo99;;nn#*bT //s6.E00 [[qs({tKUW ??99rr##vvmj r  wqou7lymm77VVMMZC:2b-ĵG!  **## L$7((:"y" ((>)Z   &&%% OO 11 $$""    &&mmKK%%++ **  ++  ϏLJ?|??~xx(0` 0\Cx;7a@AO>QVL>eHCTk jg8[eb7W%d&-bnmktw) aT<(Eg8~ ym#ZdnUn W{[ v a Uf @}  s'  +* v 0"u & $m4Bm$kCd!':6! L&08 $$)#;%a*0l-%(!$7(t1-+-,KM,+009312QGv=Oh:6]:6948FTqTx?>F>>ZCOLCCKEdbGGEFPOJzRKLkPYvYIUSUe_ZVkZUWPXYZhs^`|zphc`b{hdeggsrlhcihin҄pozrӋsssvixyw{yΒw~̕~͙ù-$0"-$0 $$ |Cio0Q|CY^${L.h?9xC}X}LAfqJO/a/Hrz^$Afo4:zc0F{XdjC+fo5tL߼qed߾D ///ߘcj]y}\a2<2PçʽӼǚƃuB /// //    Xd0YW?cc-=cL LX9$WfI Mi5n^_̼W RczɾLm̲AӝWӎ(_Gw|_s3TgӁb)t,   / // // //////////ϏLJ |//p???~UDxD( @ =n.z;o_`\i//~%b$22$ff%\\%]-`Bi]2a Lf}yQj^+ABVV~35aa=>XXvv MNKJ wwBBWWӌ[9]]\V_4]qJkpp44bbLLjepk{v8Aw~⇇__ʉ>., (// 6 8)$651('3u8.(+ *<5ջ, J WFC}_1eyjz~q9gQx\j_a2+QQ33II _`**RRa_ cb86GG"P-~?:[pttᕙ##޽>>ll׫|00<<Ζo=!`K jSOi`>3J% l55 P@7U+--P}u$ KH''YS\ M Uz{pp86-fv8w|,]GG*{f{]rc889a\C!na4uk**88LLz}")99KK!!AAGG'FF!yZyy45ztJ99ggֵ䷾BI}?< ^ 99!!'((pE0u, %I$ׅ35h1,,xA-e:{ )   ZctrG XGN <KK O (>  DDbb//  ,  ??   #&..!cッ``s{~>pXXvv MNKJ wwBBWW[̂9]]\V_Ӝ4]ӆqJpp44bbLLjepk{v8Aw~__>., ( 8)$51('u8.(+ *<ջ  WFC}_eyj~q9gQx\j_a2+QQ33II _`**RRa_ cb86GGϠ-~?:[Ϊtt##>>ll|00<<Ζ!K ŋjޒi`>3J% l55 Pؔ--}u$ KH''YS M Uzpp8-fv8w,]GG{f{rc89a\C!na**88LL")99KK!!AAGG'FF!yy45ztJ99gg侾BI}?< 99!!((E0, I$35,,A-:{   Z  KK  DDbb//   ??  ..!cッ``s{~>p :> ! 8 Mj Uu v l%JP< j $ e |{''(')$(+.,00' 44513JK -~<<##!!4I$**")**2+((KHLLE03345}?88358699?:3599qJYS>>*<\V8A=>]]AABBABbbFFGGGGIIBIKJKKLLMNQQ__RR[[pp]VVWW_XX_`}u_aaacbjggllpztttvvwwyyk{w~ڽھ?2<>3C-DB6ڗڇIړڸX\g$yڧoW[PВ4Ei=(FdpceL0#f/5*7+;, 8 &Jh~@ڃOj{1nZtԊڷwϏ^lvQs:rSRUqڮYaHK" ')! }Mb|N`xGkmA ں]ՄڶT֌͝Vڂ%zu9 _ . wgS`Aa@G qp{p>A?AAA(AAAAAAA'$A)+5.A- A3&,AAA% "AA @701A2A;!#AA6AA AAA AA8A4A*9:A/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADEEekBoek-2.030.1/lib/EB/res/Wx/icons/eb.icns0000644000400000040000000007322612725476602015607 0ustar jvjvicnsvit3262 CY, 4        " ) .   .  $ $  +F+ 016   ' 0  $ @        6 aC !+ ǖ? 5|ҭfB{ $ LfC4 W V!@  gAX^(ÙX  ޠ jˀ7Y ӓߤ3֛駻{q +̐3Ďҍؐࡎk џkܭx ԥrܱsvr˕Z ֬|Uڶ`C $ ٮ~\ݸ\߿`{ǘl=͡rT ť^LȬeA2ŧ_PˮeOrͲiT^йo[~ҾwYO$g~s^SMczzcY 2hzu^TMmyzdVNNt~fVPqj\;(n[QLZbjf^XSPIDeihaYY61IZbif_YUJX_ig`YTRJW]hhbZTQN Tijd\XMAkif]VRQIRSTRRPK VXWX8 KQUXUY0@RTTRRPQPSTRRPN D[WXJ 8[WTRP+ 3NQPO3] ! LRPO9MOPPI' '9 .@̿̿ $XePGD9 Pgz2^`^N[澱39DD@)#} 6dY"(da,Mdy>䷳#佲´ǔ#nǬ']tg ~_ ܒjyŇ4ְⳮvE;|T" _湅]2+384. .}6ߺu@hЀ Gߩ嚓nܨ!yٗt ׍ޠc͘ܖ( ʂh sDžZ{~ȏ'ڣ}n[ʙaПkP_̛fԣt ䷃Z翌^G^ĝqL=ʥvXLܿkEGƟsT|ʦz]׷g/tݽiUK$q\, u[QzmV+r[Nfx`= YgQ3kVO@Hyue[K1vvhYROUfx~rcWF 8vvfXQO`qxi\Q(\~|oaV6S{~qbVRM B^\YWL6[YVSPPMUYYXVJ @YYVRQQ@SYYWVP* R][WV@J]YUSPN );<2\QPQP@LUQ>/RPQPPIFOQP? 2<:* -CRON JON!fMPN@R;  ']D   [̀+  ̄)' 6?w?Ӷ#  -ǴwݳLjT  O뿴pKų GGӰ 9Ŭ jz  xm𽲴ű ,h{Y%4m4{Z,^a4 iW@:حٷ hM  Lf! (ܤ߲ | v % P+TѤޞy [,Ґ[$U9- U  'Ԝ^ +mU 3  겎Ŝҋl {^ ӑb T)ښ⠏寇wdΜgNݱvTѠkK~s羄xǑpΜdU ѦxXH ݸ_P ԨzXI߼ceÕgc̞oZѦvXI ξz[P@ pŪdSM fо~\P)vǭgS_˲nSU͸tXIν{[PM `zq[ROkybTR dtq[QP'j{cUQlhWPh}mXRK^zp\SOV`fd]VQO@MZef_XRPN+U_fe]VRQ'L[efaYSQJMXdgbYSQQ8, 5w40 3"7'?2+(0.~ɓ jǫX)8""7'b!+q}C'{k7fN41yr9(C)l~HW!bP pvhc90dhC '`lL{YUlUg ]Q dxS  8QTG, 2NVJ1 ?8QVG- 2MUL2 -IVN8 'CVP;" "?TS@' +,& (-(D*-&  (,( &.*  $.*  B!+,"   %2         ۈ      /  ,: 2z8J9 ۈ|h}o9@͊|Ӕzg 2ĵ13#Ȳ}}Ё-3-2Ȥ7.. ")5(>)<61(%:8#+ʵ ѸmE/5$rl+4'1Dl/sJ-З+eU" ,;}vB1I4pO#[-gVཷ뿷Hm5p_=x? /i׺r2 z5S:2&s׭h* &`սw40UĂ?MDZ4ӟY4xԮc' e3˂=*"rӐG7w3 +~χ@%pגKɛIg) nNЮk1-)f]/"Ye6 3nV* (b`3!Wi8?z~K# 3oS('Acl^>  ;^pcE% !GfmY8  >cl`?# 8]ldE&x *OjjS2  #IilZ8 +&8>7$ !3?7&  ):>4! !$8>7% !5?8(  ,=<0(:;2 E  g   a    O-    U     T     ,6  s  3]N ;#& ?(_ $_/.D݃(M(E./]T /D"(ƺ _ X A .Vq[/b ų*M;mhBp4hmJ t3cpS%}Y+[p[,j">]X%¿_%  4LNB) &(#   #)% ')# ) #*&  (' )(  &("        &               t8mk@|sg]UF@3+'&&.566=FEENUUU_edentts_9~nbVGFUV^dkstvE!] _X p$t.]xM78di<TTG+R(>Vc0n'ffq pv,82*p"=N3J3 tIWA" 3@0y^$R]fI1YeB m&P;ix>'{y- PHdoD ZoP-(N/3}6|Pil ,TqrpXk`7+j{nrre? d|mrs\߁mrpV+G9xljM"&ԥ⦰ē5 DV`aVM3$ z__UB$qF%d XO 8v YGz I8*61 +?i!qquW "]|cw 8dGߋ,A\tet_kb@DWlDF9oUQ~fUﵦ7)ö/Ce5  ").//067A6!D>1%    $"2.xO0.t A F #t ; ~K{p JG)Yte,D72 u%Ov~M' A51a!~ExxF j}`@mqLds`]zk, Som<EyvD0inV<*hp RCFyJ>ra/jnq+\ޖފhB"SJAU7r!މEekBoek-2.030.1/lib/EB/res/Wx/icons/ebwiz.jpg0000644000400000040000000003605012725476602016157 0ustar jvjvJFIFCreated with The GIMPC  !"$"$C" P !1"A2Qaq#BR$37rs &CUb4SVt<!1AQaq"2R4r#BSb ?ܺRD»QYz}ah|G GwⱌN`&ֶԓY.z.rHű!MJ S ?UY55%~7}mzo S綣@ʹyh֫H%ODXϧْZ:6;jwŶOE~|UҘO&nKjmc,%Kud'88J>u9}e+?+wXwQ+sõZsRzD;]*^/SfrS{?|Zjd}*wpII BڹTxE* 95)J;N]QҝKf{aَ B_-~v? }+VXnZcR\4|N9"JNtb *ds^VCƤp# mͻ˜2 nT|nZnSLxZSϺBA*Q 1^]0ߺj=VBxWDv$[~;-Ӊ JF H<A#|'Nbt얳eۢ-0nډN1$|\ [㘀 Ng,R=N[/ISV޿ڷi~_`⺈t'E޺iije\nm{[Hmr$rSG~~&V: ʹ3C#I#rI휟ewNͤt˽lYIb{UB]2s݃TO7Cu FvĸP>jB>WSN)-I=]r#]:*̒ Gƭ":&?mZ#4GCuz;VRܗ[;!Бz׉Զ59\$%)JªpD4'yiN:[BFJpce.y6 O*%W+4icu7 $_v\>^YuR$/mRWI~q?8za_ֽŬu! [I>nER6Ph%"7ɖe?5A)IҶx{LlP#[BBO)Y̟Œ+p#&Z+.3 n JVZtlmw@R*OXĶRI5{韶:͕1dshksaת31NrtQT踹V bfl0[m 씤mq@!)%D`bF]u:&r4))UʘCh>fXW:FRN>cl+bWl%?DsR!Gu,Ʈ:=uq*H"ý3I'SnP'S7k6TAb;'2GUmnҳZB^{ őגCrnc> my ::obߧMxP0ZOw?2NI>W8/]'˒ܭ)JTj+&ڈ.ܺƗ*d]Q8 3vo:KV7ٳu&>Im/m>}q'>Տ]"k]EĎ@ *CH'V#.sZ^ęaDX3Y-熬(%w$ gDԧp["©auWH,O ~ӕLdyGIVZCWk ;jE7[{QeJY$k~,q;|B0lgWHBq̓J6i/֣FֶLswn{LePIB %a p99GƳ=?N]K~@*l_{Bi<;Tԭ^ŲҖ/ Rm`>$b/slj:9O\- 5%QVEc dXklhh$+ހU&#%KiHT%Z4+}InQpUBXk7`6N 6AYF='8Rg[64;vFI22-$bƻKz:rh[f֔FpqA$3eӧ궝_ % _| $k3:&ޛnr7e6#BwxIە/eIO3klK};b.toDX-E1Pģ*J* RӜOj[r_uXjSqz)َO:8 \N'뜭t-nJ+Gv}3nRThI'ӹ7k⺷mJY';mI_i}wh"i.3Hnro.y-u.~\$Fn*]js?$ @TkD =/ GoIc.\'TQJVݸ{ڝ' V뮈tVfFnALwPmWRї{FP-i} }cɸA1-{(œP>sۏNV_}";qZG&. en7cHem}pwqbϣSjgpx޶tU*k)an$~qaJYݏ59idީ5un{r]QK)X.(_q..-iF~RéV{I7@KFoMFwwŸSW֐Ѭ/[ZC\~48?!*?ժAs^G+5-Ek6Y 6$),0)j8 $xBu?%S)R\unU+l-'!C :~#,p`iJwu{4m' )UTJL0q kR ھ tM_fsq`(QG{`NT;,$ VMnIHbdNq ߊnNw_!sd2ڹ(O3E"d9**; c/awY,q!ևWIK BJJx>\,aN2NTy Jy!MϥWr$+U@=H?/ TLiܵD9N0`s8qWO*g~.σKft4'LH+kOZuV΅ Z6vy;-NG+z}7/.ozBԑ?,kkI4!p1_Զ=3C!nK9@g*K vmK!AăwJpq,"eoӪ6[E/k1)L||E`>@"ce&$7ĦR㌜hue\+F℟AO`T:v>Jqv#Q\鲫Z͡趙…G9Ůzv:ELM1iעqX`I 661֨2%yۄUQ+gisCڈh^hgn,oZCZ}sxHPP9/gLКW.Q.WTEܦ R(TG|y]!27{G<},[y.wxV<ž|ٽ9Hh~oZzŶ'RRJ8=8N'kvᦦ;8&}&nW X-/+ZUh-{tu-5E}qf;d* G^E9.-HK]A bc 7UnL{@nT9tu TN0--I!ĩHL#g͚qR}Ci!)ўqI'> oVn Hn& Op_}y-zwܤ\:SIǭcm5j*umŻKG% sVX =q\Ґ_zK> :RBf0-8@p))Q1rsg[eW♗QM#y +N7v5uޭp'h𯾼66bUrJǽajYU)d]֝9쯨LWj[t%ɋVߔo:'0TiQBRRU*٣f2RղM\)GE'+ h'x_t6oQnV(֝]2o)Jv9@)ܤQXcы˳-퐴(6xT,j#6>{d93WUeN=֛;)SQNi6U$v>:b>%R^l6H\KE):zߣ}ݦ#ĕ PmnI JPq Vv8ĞI[lZE͛Skj1e[[>\edO"ɧmn<,,A[p\kp)C ` mZy;I]20\u)0@x9)@q$VC9ui\y-&ceqS/!۩ճiǡ8Cl#mzkT[ &][!/!IYZd;ПCxo]@՚mizݩ/Lʅ1! Bi! nX)* cx檭-K^6 9kY\aVұsUjqFڻ6-d$r "*a | p)&BS'aN0/L14=.F TN2rT;v$k閫tUJi/*@N IRBNlW^=g K"ΤFy! )Iu+Z+L[kI͖^v Uw! VF89'+RiJ"f(7ZuN;$g#t!<˅dmQe!Y7.jVB.ꔌ ~5K3a.MΊ BފhQRWYB c@ߙU]b,s5,I#V?ZU@;+{_ן ^ĩ#n2s{z" mr[ O2{`$rr1LT" mwq8r 2]S P!@)ް._Vy!*~F)#9QW| ,Lo.ςiƩ_g?.JKW\q\q(5TU5zHhH_#m +#-OH!ITBRTɬabL06%%%`}REC#X^RE*Z3Z)vP*x[`VW]WԘh2ft #@%E\d *'[lX2Z$ T|΍8q5=ŲRh]HZޠ7Q GX4eMd;|=k1bxm:#܌eO؛uL\ZA<葤ڕlqFp4kpd"덴ڜuiB2({"'eE]r^j3 }MZ$;W֤=! P@EU=o굆OAnZKDxeЅ!c< 3-ի6@ |UU]S su[BȑlLS>\ae5T7 2|F CEF 'zVdftRݏdaZV.RSGԕ-DM[vnM廴8+LTVܗM&:h'|g,uZˊ@C/oiKHm d>8?>ֺ骬-sbCe%䩐R#$]qP;w6WS0iwl_q mWȌ4{p9y+J6TTGCVJ#mKC % S~oB@}ɀ5Dvb#A҇aO2Y|QSجRڞ #ﺋܧ8 H+k )c>n8VVf<ou52m(+BNI!8r1+MyƌnXb7fN\&xN'*ڱ_{ݧܺ2(T8NRQH~!VIjZhzǨI\.N-G#,dwʶ0_){r5-3Z_>J _nZv5KGpܒ qJ8H&u55]3$-1kBFUP >Iz9v5Uy.PYv]w$f.́zJq*Vr S#ިǽx&#i䶧Tv,86*mHA;-i C[3޲2&g]l/l:NhkQ@>v[M!֖{ԯ`AJG<<"iM>nxOKqJ q .ҫN͞{QE@ORm:kMLg=.%*1ҝ-Yn$6H ǡ6XwDiGڱ_orCIszS*Y*(I< >M٪4g]$ܹ"@y)ԕKv[agocnG>KFCe*rGpFy #֥q+g'A07'UZ*Uש2}QFT;e Ճ=jPoEex\u@fDhlE8$02{7K.;Iaݑ'PSoص\T~ኦtu*ׯArb35@2ƭCgRTkM_h{5+.䰉PIlw=Y,w$@rhm<Vʳ8Dz'X"P068O֦]n{Zىb DŁ m!O/IBsگqFWm!ǚ}v+Rӽ=7Lf]mFZZZnGq2ں|_J }l#ZD|T3թq 6ZfJ4T&rZh 2ʏ'w Qi=*şDi юJ! euQԳ:K[.tr l5'tIJkrܱZLZYm$+\pAZAvA&^05v23Ij2YKI1 !>=|})MFՐRBqTcjgYox-xPq 1cc;6ֽZrNV<\rJ;n/C\q'TW U0:bȌACmխS n*Ϩ74pZk#rV ΪV%'jBNT6}?ZuHQPq;g CMm5KYd95Xn\wyFRFG*9ُ"S^YMr!NAv Z֋9XqpmH *MRJmk F)sXdڕqKɺJږ.6~#ĸ'9nr LycKckBqs T15{"tsy!A?8R0 3ںt+>{Sń볣Y xm Qws/$4CbNs]_$ˡyF___~%G]`=dR41pL%ڤS %#T2ys%G]O0ܘaє,aB*Opih-a_G2l\ܞ+ **8Jw,ҫ+oK[gUK \iNmX(T>:_HX4yv +qc$O=|j ׈KHʉ<}~ 8~-nJm)N56]ԏ(a@=;M!]5<8f-I$+k ' 5z2lBPF0к[^5D(I;gmVR4iIZau;T\e>Ydԏ <}+ek: % NxHuEӳ,sm蒚-8Ӕk.򴄫ޟӓW2ZSrR%I) qv}92yLaUKޞO{`M*RMDt2))=f&>ml Ô -$r8r!6-GQu#TrJ$y5.'I$4O}P5Jow l".4H}6H}zCi=O]=7i Nܲ\Z+nA'ɭٴ ڢ p ?=HfHOmĂ?ebqVnܩ*Mt-+3Š;|8G'뎁%=XϺ/Q†#*Al7wǧstfyG5]9(_jPފfӤ)).HxBa~Ǧ5.t=rHi!Xqjl&2X+)p5**Lwڴ !'}t痿I 8Fmw\- $HFeū v )C)Ǘ 5 OGxq}>,IVݧqRVRQzP4 *«__R]QF12meCN;GF*3g[JR;!DȆ\$UsڰI&*=vK*HyQ SN;a > {OYԨV\\l7)(iSxu*p' FV2{ڊk*@H*K%_JBTnp?"ϮsGcMԶzvn C1Qr~VԖan), ޠRU)W'}n;uSp}8jA%^ Q8i@y9W 8l}F<ĉh4~6egqJ@ExJ%IڕK!]1(N[$hZ$wҪDAYqGlp_eĝ ռmPZpAHP+'J#z,NEaf[ϱ2#BV]SBV`(m#Ӣ^*kyt(%ֈQuEIQ^啁s0Xhaeef1׼鶣A-i+RJL3BJ‚Aݓ8B0Um| /dIU ҽH[>"OxN^H'9Uݛ:,~[S~z,t9!˒qN)*8mjIAV3vC8#zd 6>[{hwd2N8YZUKw ֨ݜzoxx`Z-gΟ8nL\ޥ%('ʄ vpۧNjs2lym9 S3d)Ljf͘lKQ#+e%jyjp:A~!;FsؑۊV BK JDÕ( Vg!Y:U;6U>2t"(8O>$$$ Sfi<ߏeMRV^-N÷)ٳU>a^ҶYr|+AhKJVohb@v,\SpDcEj#d 67yݒuC:$!/5k9K|ROpugP෕h$ gC> /ti׏ J3.i' e[^'8Ը؇͏ PЖя1aZɾ#z=ޔb&n٦Vލ=/ui#`}(e(]~ TUQbgj7GX\ߖQB銀@銭/SNP@q:7-v͖|5/IV : PYlsߣI xlIENDB`EekBoek-2.030.1/lib/EB/res/Wx/icons/ebicon.png0000644000400000040000000007043112725476601016302 0ustar jvjvPNG  IHDRQOsRGBbKGD pHYs u u-xutIME  m: IDATxieU97U*JUeIUGKeI Cz0M@~4`<63d˖d[e5T*+;q>s3Sx//"Wĩsޛk}`[e[e[e[e[e[e[e[e[e[e[e[e[e[e[e[e[e[e[e[e[e[e[e[e[e[e[e[e[e[e[e[e[e[e[e[,JDExPҁ Z0Њ ` ( )14N AރPePh  ƀUP9(Kރ{l{g9HJAy E*t[n_  P1AT |{:0ӂ];.ړs'1L6av&['n6&c+‘A9(|NCՇl{(<6H0CZo?s^YLU`1(|5_Qy\#$`4u2O7Yn2P0RQyZ a03әemEk5*N@$Q 6rTznq]Q8?XU Y*4U -\ǟ< &ne# "%|+xMB0Q2v2L4K31IYU>]%h&`XZ[hTGBk*QG l#HD1TȀƀ+J—^ #" *F2+1Ơ1%@FaM!ȴ,Z(Sl&^z(aT x 0vP4QR!Cb0acEY9hRWW? B4RB$¾IVVDZh65iH%Jڬ4im2LKQD4$b'Q4EQx1O6{O+-PޓhӊڔE HR8NoD'EL8'T>*ՒhE!dg5 e^ N *0J$_r.k_]@hcmР,@0K5#EyơیhlSe/Xvhr4ʆbJDxe[*hǑ !Jw2Ko}={W@k" yp 6 "hcS9y!Edbhu1뒴&ɋTZRe(DimAW)Zܭ|SЪ2$1+dD Y)h\G^Q૔.(AJNwD װc6lx㛏2=hK^hLNR9Ώ'裪zABTCQx$C7TxYF>Y#=FGJP*$MrD4 KU>G%m|YPhDk[467gOqLV3 ńy"@wQJj2x &|CʃuKĴ:B-ĥA(k7F{ek;vbD!o @#!!,-8iΞg4Ϋ=.";AY905 |SG1D FF%0 IH 9Uy/u_T"I `Mpy"AZ_>Cp+;KaHS8u Oq:4Zu4ݚgh *|ˀI\gyO|M\riH!^dn$RH)"x"LdX"?!r2; p\ A/]! v$RPSA5P`YL#cri4WdGw> "iyNsQQr(\gD>Q5i8!(Fr(Je/{JD|}lxՇs"E)RV"y%U"Lde 7. pϤ8RTT t%(yh/uL<)Diǵu~O,uDJd|^wkA~DIhDVFOH=@.-BT , F"q"t_d(#rᱏz&2"J/)8EI_ dH*"}?3k"VO$S.EX#c Q H(E l$kC\ BN>/Bϊ1$R]02fdо60/0x G>)gUy=RD\Ug$^F;/y&D"S xTT}Ϻ%Bzc'qSB/ʆIcU{E(@U.(׋H!au|i X[4AYЦUug4+BW[n˸+A.:$bԼ@&0(fIeB/uW>*i)R{52DFaNev/kyo>&NKCW{\P RZq.mNqrX_>?>ʱD)D|*2EXz~SEN0yqa˵Dپ4dq]DOIHk|GQa p`G>@H#|ޠĠ/, R09]jx_\ـ7-HF*sqM?ſch "M@¡ .!QE+¢`Jչsk,b ooDoϿ6];]kwaD٤ʇD&* o(&yx|0#Ʊ{WnFE #~հk/vZ$p(<5@s5$x $X&@ :Go 7~*xI%L*P(zRk` t6݇( AT6\ 7cWۦe`,Hb(D {m :T&VA=Z7h׃yNA nحs(e(]BUn|b=@@jhՖsqZ*,CF ׿ !w⨁֚eQeW`ϾqrԮWy!VؚU0DWظz^q4:pJlu (r*)ym ^4,nR9 ,:%kшhDT5aVBGzF<j7 +I |+gp2<^w9P}U[PMb+R(o-*LNβ,gP5Ia nzQQS9e̸-7L* R&+nVxwfк) /a|u ]#T"[Qړ͠U# )-j0`;܇{(BFX ̝Wx2(r0&GY*~:F|yo05Ё8}]=(lt5B aw r0ݘaUTՊj _/0ӧɧBT6$_ŋB0aBxnxi]GXoGm 8'I!@-e9:=ً-ӌA+X^hqN׾_6 { R>m?c?5jDpĝe,qs9|q0Clc"c:ʆ7 @{w}CXr_%pu_wb84AO _A=^5Y]$D1/ C8.56 K*LNq+=.ݍL86sMTu?MPփB%(,^j_&{KVƅ(Zx'=^wU`C+s J.[נX^6pJc \5 L7c!fCDٖo0@NC(!Hw_$`@N?υ THxk.*@`!x?޴ƴJ= p4|1WcUFz!amWQp8A 95(*I0O}n 26`DꔵDIQJ/y1 x¡`/3Bò*Syip&Q$%;GvGkֳ \ɀJK'Pj[BI |aCNDVhJ x"pM1U(tbL)e^F lW| h_."r,<q+5@ mCE J4TRp4zz-x{FiKވ Wp$)OU YxCUu@,$#*yP=^~a5'C(o0RP8 n,JXUK\9 >z bPRgZ#5b+Dv׾0ک1g P6^ocCB6Ij~3)=М!Z]Tٿ5^4zPja1ē'M N*nt 7 qc/aZcKfPe  Hr`[_=iE+dr&cL EF۵8hd1(n޴ T$еZ(GQUz4\0(m72!gZ_W*‡uFukw>HلpŁWq-4u#j8p~K/ 7ҷx9|V} 4sOÙE8viy7Ah4Z%$+څC)PhlլvP>$ q2“ L9A&CEW 'цa;\cS-k6jˁHTu yA%@rpxI H1k3Yj(i ϟ&YDBY&00$қ@ -U$Lެk6Cy2@S09>i֪ Tuxm@Y^r_qohiMB4t^{-BekVnK3 ʛ: %r/= u BT> |3R DQ!(6JָeGt@32_mM{5 zОlV? zӌJWmf f Ե2`P3wWs5|ͷL">}7X1O4fmlTBEǿgpEyTHI * .f+瘖C,pߜcJ@5`I0 ]'8 )@CŸoXx;#0J V4qU{&^~45%6e0 ݡ,Xy"*gT4Z\]ETżPgBR`L yކ7jwpuh߻#JluK~4cx$v?v|VPir\ .<*9KR%=Ӕ̀" 4Ri2)PSm$*7<`sǹbK6NCuBh r{>C@.69&L PE^-yz/ QQYP8߽j2Pn]k_B]Xq+(@"0v\,T)Yk2J'z",\ CY j}.a@Qʣ>0ZEH>AJ GtIGuX MT7CᜃךAbն(Cm&8D0!d.hFh퐡V|!fRH G,q`٣U'ʃpp/lDAl>hz0Z}ʀKlM\ל'wi(i[ > ]Wv #bH DL@K&+g8xn kǐE \1Wm`o'Qy]4>_Ct]zw`+2 :1xI=ڳs|seEW0 +ti^ 84.yv6i>'| Ose4Y5/O{_Σԙ0Cb+j_vP<+v&M'<3wϟhr(TIqtY^qhpvY Ws^o>rfMlW_n\:ӵ<i#Ӝ< B,ɍ Z׵KyBUwj"U:-τx"Do| FgDƂaߟw]3G?Ƿ?i]xazN:>_˿؅7?`S<_{=rKUv W%k(LN&}JY^~KU&1 ٕ$59p{%hؒ[9*Ȥ=~vIf5,aG=k IDAT8q[QUU~{w|.R v朕.fu+j.NQ~c%N&DL.L `_ĵ75K\dwsy^yvy``C '<*\y/仾İ(>BVOJCݰ]2m?kx[­5"(KI'8t *(<~SٿN gZW2y]'꒗3N?x?]v):vO1?a"1(vjȳ#rXf?rGp3VUh jXh(;xp7ٹc?\~94'Ai~,KIy)̉9rˡk_W^UP|s\c/|QV?~f`41Lj_JeyZO%oU?reWa4`J"2{|iA.XMa$tYG9^9) ͉@[:y8,|?=@VGe:'hSU*UInO^[~CIJqMCi 9OSʈ. f]MG>4Sr_oGSS;g H^v3tBsͮ3_e2Dcslo=1pSbyId;/fK?L!AoVg8>͉w05p >su< 4}МMyJ V:ZV1v/9W]~.<c@TY . `ѐS|;B9Fw.ܷ n);>Ñ#p7t9o4Z! Xܨ.]'?~vM.h5L@Ԡ,-?}_t v@k %}<$(hqAs4<#"0ds<_N&]&Uѡb&aXPzTɇ07!;1Lqͱ\z\w\x LN׍~M'it/cdH}3Bry ?ΌQ! ]`;c4XUulXstt5k0*h`0V͜$) hLh K[↥ i6Y.,s<^")DC91Ӭr Y0;`R Rl VW82uSPp柆0QXo|?Nb XX? y?nwtL-3X$3ZaHq9 ),5i9qDU aUk&1.PUh ;v'{< ] -JmT!4% 6mvm){; # pvFC]as\.5(F)+2x$gu {I4D:UOZ )eHBN`,U5j1̖&y9. V=%Qt1%jQ(-.3<4ĖA^ :Y,ƒNlaueu4ȓszx24-,StW#FVX3=I^_y8qa4[ìi&'нYXH5it1?C[a}}W4MrVk'+>)"|hGƠaŽ-p g8,H}UÆHŠcJZQn(DÜ5ZP Qcr:moun(cQVPơ?ouD CVҞ>S)̓-zrXiP&gNbL(!"[\duyK#KW4Bu^)aUE.,* at h֘jMmMZčFC[EF%KN2L0d=GcA $E3gةE6v =$͆NH'[X&?9h0bBl"2$'];"rgOG9yNyv&Y+:qF3ZJG V(Ks24ROci@iz$j|igkOa?71׾5) =KoP-zb@؅y<A`Ͻ泟Y#&MW0 ;FYCت3[l:yw47,Xf,%ό z};GbfxuRgKEwuHwq_1W̰^VGDy>!"w삏a;PiR**msž |f mQ4kOژ5+[+YV #Òl%H9X,'MMeWXXs.{=_爂gѬ#QDS:-,SgWY8{?0ݒG2e3\pz L&25Ѳ 5&*5ז3N:pῼlh@v "χ?,S낾ߋ`!!u%!rqNt!K}>=>㽿OBܪtJ[MߵzתQ-8x>~n;Fztӌn!K̳!OQݿɏ}F%$ggH,WeuqhpsXuR:!#c+W9tp` $P讷Z'Y՞(0\}5|k*ء'2dX,[o}~AZ`nb89;"' ?tm 2\*nzrz0=3Qe{G=Wv.򻿃=tĐJ Z='~2/{ѿ 7Bdzf>1C}Tgo>WJJnS )yQd#r / Sb9mp'U.'8xGº,Ś/_3tD,@44-X~c@6׿^ N4H#&|- &l76t~7HװUUṏ; Oʁ215W\ŧ︃S]d3E`2%g뿦yPE.}wp=C"9CO]Ⱥr3}!PP"J\IOsK/A Q%^hrBQҌsn'=P*LʲdΣ4pM8׾©uҜ! xEE~W/{KǕy=_n:;%=,;Z;PN,ZJ r2&`1c_gsx=\2 ` $MZRsWN'k{Wu O}zvٖ 8׿wZܴ?:E'C* "#],%^w(l2P -9| vq)EEZWtZa)?`VPAipЪ<2*rQ6}:{qEB$AJ˱A'gJ*兯7?N5|k?ZbY]a-"5]RHstFn+_K2 䏐h)0q yybUQcS̱.е3{Njx߃ilo|Q҉4OnEq5^K?G_N^qxa?KးZ?3q`*|C1+3°-5ǚ:oKྔd0"Q$"Zd3ꄥ7[(\C9)"_P;"qs10 a# 翴fKZ/-$.Wlώ\Gѫs)^v^^YPpN{%@oUB^K:BE} <@\9}/WkLTA6g% {57 uQq5)n}rMFG@HaT&JRHJQ֗|:9]K*7y/?jA>6fɝ>\ב9cU+P2 p_>?|&`/Fm <2fiA>Ĵ 쯥 {?Ϳz\n%Acsf G븹b%(_y!= 2UPb 2EII&0b6 sĮxJeakp(ߌTS8O u }K+H#a#ЌK@AְMNh2nUZ>/-W 8+_m ]_h=,ilAIٵChp-.T 0왉nu!Q4%~YBH JX/ɹbD4מ!ҷB2ɐ *0xn`#ˆܪc Ǻ sX67pTUJ8G,`# ﳘ.*' ĊAhg5( V}aRs'uyVA2,$UDB)ˆ B44MT(au<@W.OHpu;`y0>]' xSwNPCHLi1,|V^_ޡdIrvSSRPK y!Z&#CYhKӜ0 rHmc7T|qqCTsD.*WU|\PtB4UQeCjBp烷Xb3rQE[!o6z :>u{Chqql fk*#p˹N.ADcY2 C ޣ$wYudgJ` 3İ@J2)NmN3V`J2Hc I322BOK6O7KZ._\c.>6k6پТx(XovLa&CejcQ␍ad(d/>1Axu?S׎pK=!ڠkYJe G~HCm4a!H=įx&i,a6nUBw'?O}"`lEmI0 iۀ#9}~#40:J  D չMo;5Ϊ/U9BL[w0mɅr'(*d {I4Ri)=;kz]y(GH^GxzQQɂQ*Iz@(k$E&`@FE#5_xϟ9}Ԉ \nu99#ͻ9qLc1O`pi1]5>0?G0A ݇ > tGHIȣLI 4BMaK o{[GLLc1)78{83j~ޅ^zsouK+r^pL&ϢY !"4&JLÀԇKxwxƑ1&JΗng~DyS~';zskhC~G]-Z"ẽ{{)*q z ;.>V8u)S_[~$(&; NX[6&0uLߢZ}L2Z069MurE;f$W rGHsf+ǭ78~S{C20 SUZf}ܥyc Ʀ|fg2U 5")RBN>#'~+0&Iص nj'7zhsP sx ʭ"O~AV7NH|ƾpL{1|?&/Ȃ 8dGj3z H朇BWܢj;Uha<ƒCy?+>i(9|߾ǩ>Gųu@ys[l xyxw ce3SϬO  Z9l,r1>Di<""ae3cs 4htW9/yQkjM#R.MS)qQR*cBKEF`Ɛ4%tFʱ-/8orttʞ2<({6CpBDm\!na@yc)A3塯}MςW$5&q_A}U6 jQ&`lyG1Tz4jx)"5cdLF R&܌s3Rd蒥6HTAxT0LBvIR)Qƶ2^2 N*F!90).!tIc_"I P7%=*q$Y1rph zEkާS2]oqeiTa @Oɣd8nfGߔ#A:[yR0'1k )>c qN@c<3o€,yꇏ -JJ80dg؏[P"*Ll}*{9 ˭>VTȈTj5'jܑ 0B]lS&TdY -GyXʩ~ZDByω VHɂ*p`C狡pAKB퀺 XIF;hpHE9LuekJ Dwc ~F (u*<'۱M3͊*ns}[5ʻx bJE79j[z60PB bdP]- #n۳mCtZʯv VNsIŕz./8ˆhQrWK$.Q@&h-aS4WݾsveA=s. TVΊTc#ւ$ڄh$N1}5A0UY#nD٘&#CW%Lrrs~JMsV Z$J'RlEV[-aJŋ^ynIi)=z>AJҧB1.Rd;ZCº|6m2anJ>̝z^"wzCM- ,)+l71 5VY]Y0Y6!iV4,u|U16;׶nS>ΝJ%? *OIk^2`SJΣM7i R45l.̰Zx 14ZtVQ$?]Q~Ǫt 6\{]|_Ɣ% OD ؈V؈!ʬ)V6ۤi:m9m _lk~u-?@ch'd.3fA7]c-mY S"5$i+<.Ӈ+GnE.ŷ!eiyvԛP$eN=P;TiʜL̙\0$(cV6+u ey#lF\2a$lwB֓m /KŘW)%RZhtm kǺ0,qZ͔} t$K ` !]RSbJNAE  r7>HrU ZQWe~RDsm?g~\k01%m)IlkXNaKGY'G_$n3xiBfe*#f+.a16,DTL+# @]+M0"b(JXBaBCKh:r?iIH.aFkTC'%ɪ|3-?GC_a48A~OOMz 9%s(-]nMx/B(Wbny]! (ijC"#K0$aI"YfE}ʌdsIZ$EDO V5q+ں#kqN!)T)7Oy(`/ߥT%*|Pz&!="YzY%Q#Ź0K*ѐm1obvy]yV2Z$$:ztdto@g.DgܙBϕ& ;R ocPϱ'Idf(! =2|C4[_ZV@ f",㬟11HC-^ Z-]󇁍Z;w!$FvEG7ʈ8 i+Lg _VVtcɲӰ1y;~Zr"ˢvox;x~0\"[O0ЦMD~ݐ9W/'Fk~MZ8𧟺ޚ+*M;ש+K_)*U" ?Z2ރGPIX#!RKxl`26yE++ꡇkq]LC>OD8 re!GSΏ$hȐ>\-*DLw%@; -w2ec@ 3O/sϖ(d~7,%ܖ'߾QVW ʌUkC0ڨllȾ1IJ%B SBQ7c+y;3picݬ'Cg<-CT@RMO3@Ut%n0")x &:s1DHM:ɯ,QʨW& ׏@/J%ags|K>o|*NkұE&-BBYb ⋼qKp pA+;ŽXc*m Xq xF(}*Q2N PxV<+- VH)&)|st( :{ {|%Z.s1ۧ .$cnV(:d\C $4)*1uʸ5`F,쬉‘vJC7}ZXɊ4E'z8{#2p9À AS iMy阹{&TeLtKl\`6x/ ^Y6N^'t]W9a"EA>r{$<0|/qc?B8$OI #_Pm7w0f;HpQQqq؋6Bj|CR>Y[H*)F?HbZt2:7gus5à EH@].|9*cL}do0RX.(D J8K@ ggZq랄hFMl$xnB_o}{Vzl,3`_F >ôY<4Elpjlrgp-I5yCy~nƆ[&4)ci)z*pϴMp[,}sXbT9MDgqYcM,mnƖGC/mza6ޔ F}ryzSLߡSghc1P'8=mϜ$Pl$ >VY>kcGBn9QCX_lrnq%r~7/b#(\acs ۶20V+@O0gz#q:TJTH)ȴ0G@X ܀?~e.felĝKTXQ o^}Oȱgt _ę'q U^Ob9ܮoxމQ/Tl }<ЪMKf21` ¹CxCl3tΟc)kx[UB'8rz~~>GoLsLsc};#o=H'a\r}}`߂XݠzQ O.fN᯳_߿ }Z\^Ĵs^n+_ӳ\faHdԐk+#=ӛ5/kaJ,ySŁ23x\7?,2>^ AhR.̙.':=|!m~7snω iddYBj7XYpt#TTbJr~>\IcHVFk;U7taVq;>c#RC0 /;75c꣔V ;Iv[ V[-c.%U(T~_ej~J0SĻ|sdb;n{bTjF3<'\|yDw",fNpDŽJ* E0Ӄ%jGDwC'9DC$7ʃڗxqs `NzeJ^qz{h~-TaacJ,&CJdhr@>'90¾Y!Q'|e'6? 3b~[_JnFJ§CΥ$R L pI9ThFnU}ZRy86{YS4'8tڇ2vnJuvÇcqL~pFYJup47Ntkq \srs$6≻[OU,&Oܐ".A30Ge.E-yɶ0KO\^RSW_ƺ)j6s0IRBVcӦ=Jja&QO؆G q͔OثL)ƶ] Tj`k|?^±NL5:.F954,"^fomrot,Nͽom,|!?*.e*]Ĉz 1ɔİ (KeYBdBp% av(.9H MrZce&7Ol1exG(lX114 񀉹\>ʅ$Fe0p.րq(ǘ%(9YLx| 3`?{K%y'Bk"\i*-覄U8s<ހ ބ2 <񪍭5y(}AHX 6/=8M^b W\P1R|c9܏3GJ@`k S~}4fr ^<6: !7yE{ ֖H{lH Mc+L7c[i.7[{No!kJ aFM 6I3b=3nP*B%ٙip >ٓzhٳDfLV=>L7s eeJ^ \{C=/B%#).z|C_/`T_I1^L|Qr?~v.\Á-o27Y{F j2KK0Hriho4#Agn W&| ʰסդL%z+]fm3`ٵ|!)/S5[25I f&?hX&č3^Ef]KKp@;H2Y44) ͏A88uIDATi9ip*h"TH5bYȠrnfDy&G!-f_܈?ṵv6qqC_buZ[?ǣX#RٰvE}RWe[5I_?"I 2@ kya@&"]x:dy+`r*v"4;S+S :ۈeԓY)*f$#i@7(Dm`@ hn-tT˜km"c ۋԯ!]oq]xÀUַF%a121sRnWM &#{yor8g> FA(E$$C3 jlG Hw L2ϻ`AƈH7W%M$Acu"2YiifsW(1zYXqhdHWhGE٪XjD#4$I*u?̞^ێ$d7OӍ,X4%"m*C/ dˏq1-\Mep Zm|V6&ve2i97zԲh/o_& B EL.&&ؘ˖=kz!PxNȩӤ#zNN66ʵ]\E&Fjg0F\⁤M@zaF;pvc fn l-]zIFDa@PQʞ9Ǹ,c:U5>qVXLJE  :ဖ0\&>*Sz/Kiw Ki#Q?? I w+e?SͩM\^ƠRLk ʼRpd0XJm2fdLx'`0Hd7`t`m$bZr~Cナ/}XUZ:.>yƠ&z^~^Wt:bjBMHZp%׼G -10PB[09Lr|K\;NYˆ xY.>,Qc"$):"5E|]neO|+_fu 5- W2UOqiD(+|KlLzr|>=?Ůl":7wW_&5Q8Y8v!s~ګ M:8zO9tY㜸Z~}yy9\kBԡ(Z? ɕ>1a/ G6eE:SHBP jdM{qǹ|e i.xPȸE(Y +(̍,ZAĝ#GXY_lyɑ䣟?KE@>`iCm7k9aUp)-gTk075 L(|4S)Q]]Kopish.:yG?s@^hudPDB!:›BXk \jRE-s%Ɩu J謝n7Srfr*yk-֖I̶ѓ`g٧JgS@T$8fh .3B aH.$Zba >W֥Age RJgmb(bͣhc@k]D&y9J=? dZF?+Z[]3}cz,01Zk܅YA1bčkAk]/J={Z3kP3f v**;!<4CE՘^<IhA*T5 śx+ƷZ-:Z !_S P#s>?RZ-jqqϜ֚~O\*M48?mżwL&RMfuh4b00+B1QU;>Yka2TtFAV^ό1jFQhiU6LX__geeb#@)%%Ny<Fs/qO_RGV$M.V%.vʛ10B\qDe~RqOl~} Toj$W&(?>YPj7qEmVI$dQj xN$+POpDTqc)*x1pV= <ښ-%_?9sW_Tڋn2:bD(zNFZ֑UZ= kuJZ|J8=9⡛v(WSN 68>ڽx#Zyk#$`(MZT<(k,%S| !_`H?I;AJw{t%M2S}lTHR2t>[ ȝ)x)V{%) dv;]ͤmD6C_)3*9jfzhr#lJq BpRpzA^7OT\5Ze\PTGֿ^M4d7zGk- #[QBU!UWP9g$pzuj6~)(Hv'YIQ:>&"f*nMnSH>APu86E$wh-9sv2R\*סqj(YYBҧ@3A ˴&6;d#:ʇG)>4B5%Cm QcH 0OԄ}t֯HKվTALĂ?y*-dtd"[u [_:"Ȱ> QH_ *„ݦp:i: z+v(u٤RZ-LO+"{̞+G:tZE,Ai#=U{gwEp&ZJ.EXpzP@3hiNY[j+].4n4#9m]BBF0|vDYa0heWj(Y3HEKhEKV+}}n8ܔ;v, M<!E 9@ 9*2(Nİ u!Ry(t`?A'hIv6sM5Z\׻{s&PaeA+NH1TjLޅ'+dur_&uSiP*`6r:;?g )] $+V|nm 5j:T$s1Ge?̵%##D ڹ&#(kOum,Ik!R>lB]JOL!]^"qHҐz6; *%$ne04 rC1t„5!rCZI[YR2I> ;󴔦T=DDJ( :[5Xe$ƩiH mh# овz̸Zبu.gQH;iB}{3S!₏2R_J>x_MSۙ6T'ˊVAs侾({ «U&+' o wv뫊SbiPK 2 2=5Zi1Kǐ+8³G> E]]M|.If<9_GlJ8Q7`}#Xn^Ŷ,%-y!=g*)O`?a%Z.Zʮ25fÀ+s9$+qR-UHӤw%=[ e3&YJX&W-'rgjp*AeUN2ˆAz骤ʭgw/4JCJ)|'!d}HӃpUD&G"epWP }3 YzuʤEH9)j;e(eSFngWT-)%H nAQKlHNI@Ӭ Ͽ'w_i*ڛ6:G5S>vTYu n jtJH Θ ꍰs.+q3gs*S ?r篘=^s7l;54,ip<`ʲN>'PqLhALĵ T)Lp3]zxR3nt6%%,gCj*#ѪICEJ~G*JBsbWoL:T.HmCl@h5ʙ%uIZ\\P(YV-ڵf1("4ťP{-~zu>T)J+Fʠ3JguOh=Y$'bJcO@Ts RGnhWNhL{z6^$G\uF }ā!|yH9G"~:c? ~2Dr} !*#zGjz ~ECpuז]mP.!ƜHR;Ma1ԆD0zPPاJs[JN[ \'ĖRvRJOV,[riFԮ}T1$_UM+W`G=N2HKQ>}V!$J*CߙK] *Z^jRQ4R/QI}U6_pJUyiuӊ*RϯzkӸU~PnFQ̗P`-!\x>.X3E*HU)r_R H1ɶSŌWهyGL|Jܰ+7Ce΄ #==4!pWVQlZ>_[,u:"7ʤqKe$)@3Zz[.YԚfbNX܉m8M_XPğ).SR\.h+9GYrf+-:IEd~%:zN?N;O.ɐ }%X *`*$zR^e n,)_>*^7EС?[L@g)ԣN뽛S-~\H- G ĢI?\ui:ny(3_KgC GCX _ȠR[p[_㩤6[ːΉSo};R% 2g\qJW̝6kgoϥ><)T$2˸ERqWm]UHd)HӖ}m:wtAizJUK>=KC[N&\-1H•VxHXv2̴i! 3夫-DJ%GhTh@OA}@8Ԣ~l%1r~rڏfX !VrZ]g̉ ),+ʏSݵYX ηrMN$KDvV|JVU`Rh݋%O+ %)SjGQAƜ7#16`hKܭլuv3YGhen2|@TI\iՕ8JH&`#R mNҊB_ٶ,wv*YRR;ZsL\O% dc'' ]˚(uHLv*ՏFPzΖm mR *4MlNj@B-neM*>RG{{uvկ{bSMni A oI#V^iKB(ZL JV[*ӎ(c:I|˜+PLs\t< ^|A(2bI$e'Xzt6u}||I-™Bp q9(O>`26uMd:rV9`:[MA(Ą,<`;yÓ]{.JRĔ>j)%#Ӑ¾ښПdmM.V<qE\>Rq hĠvJdFޏ>6֔^uUURT40?MMMtfb!L#l/>%5PuII!OjjDS\-S@Kߦ[\C.6ˏSSR$|\ rd)?NJiM+'|響-MV* e9:ԉSSSR$cT_R('W#ܕilҚQ'|響2*r)$(-z}cV-JpqG/jjjD8ZT4|u\3J,"%~ԉ,{lx_oMMMMHEekBoek-2.030.1/lib/EB/res/schema/0000755000400000040000000000000013151742350014046 5ustar jvjvEekBoek-2.030.1/lib/EB/res/schema/eekboek.sql0000644000400000040000000002215713044346163016206 0ustar jvjv-- eekboek.sql -- EekBoek Database Schema -- Author : Johan Vromans -- Created On : Thu Jul 14 12:54:08 2005 -- Last Modified By: Johan Vromans -- Last Modified On: Tue Oct 13 16:34:40 2015 -- Update Count : 138 -- Constants -- These are generated by the EB::Globals module. -- Use varchar(24). MySQL cannot handle indexed text keys. CREATE TABLE Constants ( name varchar(24) not null primary key, value text ); \i constants.sql -- Verdichtingen / group accounts CREATE TABLE Verdichtingen ( vdi_id int not null primary key, vdi_desc text not null, vdi_balres boolean, -- t:balans f:resultaten vdi_kstomz boolean, -- t:kosten f:omzet vdi_struct int references Verdichtingen ); \i vrd.sql -- Grootboekrekeningen / ledger accounts CREATE TABLE Accounts ( acc_id int not null primary key, acc_desc text not null, acc_struct int references Verdichtingen, acc_balres boolean, -- t:balans f:resultaten acc_debcrd boolean, -- t:debet f:credit acc_dcfixed boolean, -- always d/c despite sign acc_kstomz boolean, -- t:kosten f:omzet acc_btw smallint, -- references BTWTabel (constraint postponed) acc_ibalance int8, -- openingsbalanswaarde acc_balance int8 ); \i acc.sql -- Standaardrekeningen bevat details van de rekeningen, en is tevens -- referentietabel naar tabel Accounts. -- De gekoppelde rekeningen (voor crediteuren, debiteuren, winst, btw, etc). CREATE TABLE Standaardrekeningen ( std_acc_deb int references Accounts, -- debiteurenrekening std_acc_crd int references Accounts, -- crediteurenrekening std_acc_btw_ih int references Accounts, -- BTW inkoop hoog std_acc_btw_il int references Accounts, -- BTW inkoop laag std_acc_btw_vh int references Accounts, -- BTW verkoop hoog std_acc_btw_vl int references Accounts, -- BTW verkoop laag std_acc_btw_vp int references Accounts, -- BTW verkoop privé std_acc_btw_ip int references Accounts, -- BTW inkoop privé std_acc_btw_va int references Accounts, -- BTW verkoop anders std_acc_btw_ia int references Accounts, -- BTW inkoop anders std_acc_btw_ok int references Accounts, -- BTW betaald std_acc_winst int references Accounts -- Winstrekening ); \i std.sql -- BTW tarieven / VAT tariffs CREATE TABLE BTWTabel ( btw_id smallint not null primary key, btw_alias varchar(10) unique, btw_desc text not null, btw_perc int not null, -- perc * BTWSCALE btw_tariefgroep smallint not null, -- 0 (Geen) 1 (Hoog) 2 (Laag) btw_incl boolean, -- inclusief / exclusief btw_start date, -- valid as of btw_end date, -- valid until CONSTRAINT "btw_tariefgroep" CHECK (btw_tariefgroep >= 0 AND btw_tariefgroep <= 4) ); \i btw.sql -- Create a foreign key reference from Accounts to BTWTabel ALTER TABLE ONLY Accounts ADD CONSTRAINT "acc_btw_fk_btw_id" FOREIGN KEY (acc_btw) REFERENCES BTWTabel(btw_id); -- Dagboeken / Daybooks CREATE TABLE Dagboeken ( dbk_id varchar(4) primary key, dbk_desc text not null, dbk_type smallint not null, -- inkoop, verkoop, bank/giro, kas, memoriaal dbk_dcsplit boolean default false, -- splits journaal bedrag in debet/credit dbk_acc_id int references Accounts, CONSTRAINT "dbk_types" CHECK (dbk_type >= 1 AND dbk_type <= 5) ); \i dbk.sql -- Sequence voor openstaande / vorig boekjaar boekingen. CREATE SEQUENCE bsk_nr_0_seq; -- Debiteuren / Crediteuren -- Note that rel_debcrd is for convenience only, since it always -- matches acc_debcrd of rec_acc_id. CREATE TABLE Relaties ( rel_code char(10) not null, rel_desc text not null, rel_debcrd boolean, -- t: debiteur f: crediteur rel_btw_status smallint default 0, -- BTWTYPE NORMAAL, VERLEGD, INTRA, EXTRA. rel_ledger varchar(4) references Dagboeken, -- verkoop/inkoopdagboek rel_acc_id int references Accounts, -- standaard grootboekrekening CONSTRAINT "relaties_pkey" PRIMARY KEY (rel_code, rel_ledger), CONSTRAINT "rel_btw_status" CHECK (rel_btw_status >= 0 AND rel_btw_status <= 3) ); -- Boekjaren / Financial years CREATE TABLE Boekjaren ( bky_code varchar(4) not null primary key, bky_name text not null, bky_begin date not null, bky_end date not null, -- btw periode: 0 = geen, 1 = jaar, 4 = kwartaal, 12 = maand bky_btwperiod smallint, bky_opened date, -- openingsdatum bky_closed date, -- sluitdatum CONSTRAINT "bky_btwperiod" CHECK (bky_btwperiod = 0 OR bky_btwperiod = 1 OR bky_btwperiod = 4 OR bky_btwperiod = 12) ); -- Verplichte entry voor openstaande boekingen (openingsbalans). INSERT INTO Boekjaren (bky_code, bky_name, bky_begin, bky_end, bky_btwperiod, bky_opened) VALUES('<<<<', 'Voorgaand boekjaar', '1900-01-01', '2099-12-31', 0, (SELECT now())); -- Attachments. CREATE TABLE Attachments ( att_id int primary key, att_name text NOT NULL, att_size int NOT NULL, att_encoding smallint -- 0 = none, 1 = uri, 2 = base62 ); CREATE SEQUENCE attachments_id_seq; ALTER SEQUENCE attachments_id_seq OWNED BY Attachments.att_id; -- ONLY: PostgreSQL ALTER TABLE Attachments ADD COLUMN att_content text; -- Boekstukken / postings CREATE TABLE Boekstukken ( bsk_id int not null primary key, bsk_nr int not null, -- serienummer bsk_desc text not null, bsk_ref text, -- referentie bsk_dbk_id varchar(4) references Dagboeken, bsk_date date, bsk_bky VARCHAR(4) references Boekjaren, bsk_amount int8, -- bedrag, negatief voor inkoop bsk_open int8, -- openstaand bedrag bsk_isaldo int8, -- beginsaldo boeking bsk_saldo int8, -- eindsaldo na boeking bsk_att int references Attachments, UNIQUE(bsk_nr, bsk_dbk_id, bsk_bky) ); -- Sequence voor Boekstuknummers CREATE SEQUENCE boekstukken_bsk_id_seq; -- Boekstukregels CREATE TABLE Boekstukregels ( bsr_nr int, -- volgnummer in dit boekstuk (1, 2, 3, ...) bsr_date date, bsr_bsk_id int references Boekstukken, bsr_desc text, -- editable copy of bsk_desc bsr_amount int8, bsr_btw_id smallint references BTWTabel, bsr_btw_acc int references Accounts, bsr_btw_class int, -- see BTWKLASSE definitions bsr_type smallint, -- I: Standaard, [- Artikel (levering van) -], ..., -- Open post vorige periode -- BKM: Standaard, Debiteur (betaling), Crediteur (betaling) -- V: -, ..., -- Open post vorige periode bsr_acc_id int references Accounts, -- IBKM: Standaard -- V -- #bsr_art_id I: Artikel (levering van) -- #bsr_art_num I: Artikel (levering van) bsr_rel_code CHAR(10), -- BKM: Debiteur (betaling van), Crediteur (betaling aan) -- I: Crediteur, V: Debiteur (alle bsrs dezelfde) bsr_dbk_id VARCHAR(4) references Dagboeken, bsr_paid int references Boekstukken, -- Boekstuknummer dat door deze bsr wordt betaald bsr_ref text, UNIQUE(bsr_nr, bsr_bsk_id), CONSTRAINT "bsr_fk_rel" FOREIGN KEY (bsr_rel_code, bsr_dbk_id) REFERENCES Relaties, CONSTRAINT "bsr_type" CHECK (bsr_type >= 0 AND bsr_type <= 2 OR bsr_type = 9) ); -- Journals CREATE TABLE Journal ( jnl_date date not null, -- boekstukdatum jnl_dbk_id varchar(4) references Dagboeken, jnl_bsk_id int not null references Boekstukken, jnl_bsk_ref text, jnl_bsr_date date not null, -- boekstukregeldatum jnl_bsr_seq int, -- boekstukregelvolgnummer jnl_seq int not null, -- volgnummer journaalregel jnl_type smallint, -- 0 = primary, 1 = derived (VAT, ...), ... jnl_acc_id int references Accounts, jnl_amount int8, -- total amount jnl_damount int8, -- debet portion jnl_desc text, jnl_rel CHAR(10), jnl_rel_dbk varchar(4) references Dagboeken, CONSTRAINT "jnl_fk_rel" FOREIGN KEY (jnl_rel, jnl_rel_dbk) REFERENCES Relaties, CONSTRAINT "jnl_type" CHECK(jnl_type >= 0 AND jnl_type <= 1), UNIQUE(jnl_bsk_id, jnl_dbk_id, jnl_seq) ); -- Balance of financial year -- Rekeningsaldi ten bate van semi-temporary table TAccounts CREATE TABLE Boekjaarbalans ( bkb_bky varchar(4) references Boekjaren, bkb_end date, bkb_acc_id int references Accounts, bkb_balance int8 ); -- Metadata of the administration CREATE TABLE Metadata ( adm_scm_majversion smallint NOT NULL, adm_scm_minversion smallint NOT NULL, adm_scm_revision smallint NOT NULL, adm_bky varchar(4) references Boekjaren, adm_btwbegin date -- starting date of current VAT period ); -- Database (Schema) version. -- Deze moet overeenkomen met de hardgecodeerde waarde in EB::DB. -- Bij wijziging van het schema in de code kan aan de hand van deze -- versie de automigratie een bestaande database bijwerken. INSERT INTO Metadata (adm_scm_majversion, adm_scm_minversion, adm_scm_revision) VALUES (1, 0, 17); UPDATE Metadata SET adm_bky = '<<<<'; -- Voorgaand boekjaar EekBoek-2.030.1/lib/EB/res/templates/0000755000400000040000000000000013151742350014604 5ustar jvjvEekBoek-2.030.1/lib/EB/res/templates/nl/0000755000400000040000000000000013151742350015215 5ustar jvjvEekBoek-2.030.1/lib/EB/res/templates/nl/vereniging.ebz0000644000400000040000000000664413147544225020074 0ustar jvjvPKNHO - schema.datUT }VWȞYux ZR:}nBu"nhs$L„Er8U%nzl!' "\ch96dZ_J1vBteH)7֥D@ޓ̰qZL>qۘj$_XNH\@ EgRGk.cm#{Eτ~!!j vM}C~QM]c+p-K!zokLa2uDRPBcWK7մq\K5Nv4LJöF<%jә~zq}ZW1獫U&Qu"D4cDv1ӓeWe]Dj5uscJrm@ߦO+g0G?d-(gh鞜g!,Qd& d) Aj6ՀA"0u Y[ ޥ^u#dQ1WzHǪaCװK 6Y,>򌫺`(45 1u`] "W-JBULmZDMZ>RۜNžHaJ#g47SbGy\Hj{1Ri DjP*&c-Fid7yVgi{lHo.J@ '2T2ɉGniV \|;E5 f)o4zM=h5ɉ=9\wi#MtSԆiFμ(8oH֤iiH:"I@;8Np[]iXb M4g V228"^irs"ÐDOU⇱8p6\IgjɷZweZ5Ǧ7h֑;gެZ9g" ;< ژ2%nڷڛ˅-?bsw"ݬfзS8^y=yHJuŘW3?"FU29+h LV:6J9񓷀I.hIk6tj7%l#R"F@l8|̻L#MmSVrIOytwB\Ҭ1?vOP舼~&` l}T<ܼi)pk>qK,=J]d|\1S%NJ“!:-u[{! 3 n*鯕!vQcJiO+1]?9(i4`\2[J@%sϘYv:b+9VR=yy~:Щi;k1o#5Lgd?cpyO !|-lD'̇3FNgl+O=PmGG]5iZh^Y}=쫌( ̾kOmc5,-fc7,aX +4=)`%k*hgݸ\M~ bզ[Ձo}^wi߂r۾}Lya\;mu-Jal'؟8Lc3A8M̉MС!ZͣGIɑD㊫~0ls={={=nGM9g{,Zb,p{қw9lD樋>c]_ȱ4w2`nv3&ӊEeϨ=|TÅg12Es.5+3yUr|mγR9<ḣ3z8X^V==~<~<Z _Z)bw A/ K '‡gB# \E (h?t"),ʴJvRptߢ:8o?~;/oB(7?eLv з YZCKDaXp Â}H92O6Z n74nD>:s<|iR!*O Sk_fKVPpoO6P*ec s>˔@3Hӷbc<j cUcL0M\ oNkPY ?1qT"7 ҡvR+swJo0 ɼofa>ԷktGڭN(Z{—ÝcQ+rΛg!32QYM4%"МRt򳈴Bl@aR~ /aN70:R@k0XBG$c.}X|oOΌ̧v"׏g%5@r:3=/?-[C|>r\yۨ*'m-| ZvA>(Q!UUܝebL.$(=PKNHO - schema.datUT}VWux PKP VDataset vereniging.ebz aangemaakt door bootstrap Omschrijving: Vereniging / StichtingEekBoek-2.030.1/lib/EB/res/templates/nl/eenmanszaak.ebz0000644000400000040000000001254713147544225020233 0ustar jvjvPKfAJ AqD schema.datUT s̑XȞYux \r8IlE(V.q4N8U{"4$%'~ݚy~=Hvi ?aXѢzthM9[ $[! cyFJd/tVT6vlh?bA rW DCh2r]vƦ$JH4:hH~ϴ.9q](rلD)P< _ 6EƎF{!SYQZcRuNydej|xp$g[ç/'dNn_ݒr>.Oo/9q}sv~R:8zV5EF26_ sF0?Flζk"4[KZsF K~CuL{Kmo&4_+ɪM^SZ7 o!Do立?HMK N9[WQӟ%pWDzgFOH@_lO؜&qV g7 @7(\fz պr.5[E.E2$SE[s GhNws~y~5P g+m^(t7"s(_0f @1咕=p bmah>]JeX"R[U}lI% 0QinՔ2F2ށXJ~%;Yx(Ti-%Ig XHDP;ۜ笾gkjж{OXBGf:Y}^ Dmh-/sfu34/ 2s0 [&''J x1 =G!$%LYA>O " M&o ͛o9ηuɷ_󝢙WԵXJ {] p ~DI3r_bfbMfSNs4Z@-bS:mIaLtZf^TFOJ 8捲)>b)c(i2`>.|%!#E6\oϵ44WLaj((c SOQWḓ_pFj:g(ڄ$k6 Z1DZ{ytQY Hih0=@gUd{1~Q8}q_(j#jKFqgX?6Ό' Ƥt/=CpVtӎ-l3!SC 6i C'hKrS`Էn懌a2L:rR12/N DPRwHehJҬc#?oQlV+N`.*yqH SVҪD2 ̛Qu@$S=W'_avh -ӈI'2,p>9\U!C7aWVJ\e#͜>GFTlJZ`(ѲeQlpmb(N]bf#RXXj..\VXĸo&PkH90SMD9D_aedSȢ 50Q[(EP!DwX0d.(WܥԦ=j*t(УdӜXҋQ2@)bhXAB~q]|rg36(}'e Z~= qeqe}:1&'W'_n)- bdm//jb㫋# IZ>[m3~ ֝TFӸ 2ݙuqSUM'_ ی6͏j ;S˪@8mi!o%fb5Zަ>@HPhj|Jw\래//㚯5d`'\EC斯r Q-6hTԋWAL+ V;a 6a9:[ #Av$SC~uF4'th7|GXo:n:[WU_-Ul\l=:-ȝc;Rd(?a3ڏ}zqᑡeS˻=mgp,ԩ 9M:4n6+W_G (63.#%UfS6*CW'VɧƄ9Rͷcx'f3>mm&}cR`5Č+Zv0͌[R.q|dJdܖ(9=.qNz#㩶Z=irKuՄDyFs^y]؁1z`^t_"7-P)JoaGFNf"#c!l*a\zn7sw PoګrD!s1%/-T.ZG݁}d28o݉$6Zr%N#&0ؑ~#x!< $6sꝢWs2`&^8` :~|&c+_f2m3a0DHl0[unYz$%aK[G}`d % n4ČOn]ꅌlF`mƧGvIV<]\YΦxu :.dSj ([^dE!Yڃ>jJ']YqI  UHE;|'pF>1ФSSHPxv h,:nu+W9{gOS2?} [uff1wo(-@stfnqv9֐\AaN܋=Z&:> }0s%e=mŔcYY>@Bk,'茜ā(FC%5!o<7LnM}; /f8mv"!#ZN9q{{:ή&3 s6a:@ZQ~Sfun G8; n:୓n:HsC-m2#ȟ4/TR[{rsK 4Jv2!:TYjB9ƪa_}}Tu ~a+!nz$ˍ|KX!aЧFi._g)8\?:f,Odc|GLNJ'\hASu_[z'$,_d5V=A5dy6\gBBYr&_Jf#gRF ~H$pgS^ao{) *8Ve-I/G|22aT'^OooLXZ>k}Qڥ(i;6rywR5@iWqXXxB9`=y{r3>3.X׺v%|.3}~b_j}Z=~wL |{ ӫ}nmY]b(edLz ^n2U>o9 h,u M7 h~هyp#VzPA-@<`r~F]=f?!Ԅ:! y ;/ԣGOc@y "F;O.n<6E7OȤRn+2 Z<'b '_ x9  sHxl'-UVN?TG~@]*O I?l1?7r6䖌ef5-d ?@&=W82 8Fա1}D>Gh٫{ _}ŗ_Oߍ;Ud={b&٫`PKfAJ AqD schema.datUTs̑Xux PKPLDataset eenmanszaak.ebz aangemaakt door bootstrap Omschrijving: EenmanszaakEekBoek-2.030.1/lib/EB/res/templates/nl/ondernemer.ebz0000644000400000040000000001425713147544225020074 0ustar jvjvPKfAJ"K͂R schema.datUT s̑XȞYux \YsƖ~~E]oi!E&vF"8)hA ݚcX܋[DOcq-W\Or- Zxb)g^*ex+./v^$~WKo(=BDc.D-N&豸%zqO ~4|J:=Nd'4  2.]p-XBe 9~xv _D""&d4f㞊8e wQ K^Um/am,ɩgCq<8䙔|9=;"*N./e$]Ql ?:`8O̝9dQ R+yQ&26PO HtwwwJ]%b&GW2et"du(OEi=?I<8p7Ψ^2_;ytyL:S~ b/×|s1lzAbB>}drmb&̋|"W&00ĸz4K;<H./ Y& VHRs!dPyKBJd̩lxzLv{K ϿKHu2+H(&6L/~ |= n!W+ⱸaD@?(4&2#?edMaEܗLA3$EJ),Kp [K-*J'򽬊Oo?_ro_ _a@!2xKrKЀ2V1[8^p?25daspTLi])Ӏyceܹ;%6ld+8׎YѐfIoR#oXBRfxoI\E"}ʓBld}S<@gdGBbp(Ev: ,Id qU_'()~焸ewϢ<,/ʯmW#3OM̱j nל8&dB*[*[9 ([CY@d`u*6(`EA"`d)<|{ _nh5VE褱GckhS X}u%pϰ GҬذ( ̄l4چ)DlbI5 n))EQȃ -f2Wp ނ78m4KCNt}3:>ֽUťbԳJ뼁.''Cceg'yuکz u#wp NUZ٬.SN(t"FfIu$'ztE{GQ2J:w) ÔE2/u *HD>0 ײhnF^ewMBԹwkȕւN=9U?7C3b>caw2vaO 3}J(㑘9eCj L 4J0[ udK@"1@_0xXrTH&Lx7B"%aFh`㋖!sx/<(zTJNca*d"hcXX-vCv:Q ڣj]BpD"Uhy&/J!Jq0d/75c}E*x.2MT5SC<Sy.-c,4,ׁkS`ΐ9x>€X8F sb4FK}IɺE5:!4&>`FDF$_%MS@}=l t,dfȚ[x/(H.=;,굵CKv<ve[ 聱A vѣk$"QFi˨aVH'zr"ԑx˻Gyj:au*_Jbr]IK1JyyW~*уپxVdks"V[ka}XkGq}\k?o:Z%*EE?5R3 Z1k41pD.F`״#3Jj߸nK8РTU(|V^` , rߑRf[m]&e:ؕ{R@W &:DMM}N=nQ '&@Y=Qǿ,?JISK=]+Ɣ1̱5%U :n%|@((!]n<g."vI?킟zVNӷ;]w.~?S_]j^R)ҜʲJ3Fۨ OqG< x>,Oؔ yi j E+(PAZi:T9u} +`^j x/y9y 7e|G,+YYhg%Ql*erDނw>H{z?7fJ44!uol`7RрŽ),hЮN KMע/%yUYՏ9qvdw"'!2CvFU~C-j#22#@jXGtQ gLcm6fjkvKYlKsp gҀIUm&xașr#L-gdPQD~.p -z|01k;ܯiz>s)a~% TcfQ |>͂9Sèߙ4t^0C)Vܱ)|,xS"=qIbW]sKqu4osz^&T5BQu;UZh>s)^MG.uV[O׌(Q!T-OQqQj^ zfPy37Tc& >RDFc0~NeļmiTt=aGq$iGrky1ZHojy!RKKd&?ELv9 X}'BEgIlmfަ4g԰퐗+J̒o<ȝ9qܘT7ݧx~fdI>rfz ,uS עV9eឳpU2H`i}Sc+THtz{*i5GuQ rBJ˱y]HS:dӴ El|'sVǭU'ҫNkMQ?뫼U} * }dTYPђ4~RUr_žOZ` )h>Nkڊ5+?z Qې~?}8Jx) )={ :CǬW9$ _ Ӧ^IJ]\k$硷v>~zniSsѷLe *Ȩdhڋk\Y ,5NtA*[EmRQ6:F LMTq\]Sa@[@٭#*\I 8jšVr \a 6cSnָȊazFQ.wQZ?/9%[j0s XF T|yds(pE=G:3֝wY1k`˿C\顴#=#"-^ RΨrhr3jEuC]q(8}8>þx0 /, s,a27/Ȍ5Y#=n vU &6,&[XpG%JKy)bv?r/ +1U81h!H[2\]߃:1oi+^T RpS FQ9umϼ6doKWW7t= I`.A(;3 O/1[۱^:VWL@MDs>!o`K3_/I5m._oxNx00*"x2DiV??%iOuCpm ۗ!D# R;Rb#Y[&L]_Rx˃ho-m]n&)$m'b[Zn.YyS¥Khsn(WWVN^Z߰sA |hs(uvaL}Pc}럑Og545ٸ9 7oI |Wn|ㆉ\O]Fwf=GtS !?NU% jmK"%m#=da[2n~xU7j<V\CׯHCF޼Mta]%0D&=ziJۈSȯtJ*.#2w+A}-Ĝ[Iã=Th洎/o0̕GNsB~5GUZaWP|h D$GQ`D \\vuëOo~y{!&zj.AA"J|{7ItQݒnl1D0^s=ˬ ̎ovcP%aR2T3r/EXt,+?p0c&NLe2z:?T=T7oW4\ÅxGፏ?f"kZHxE@:Ae i !GqPKfAJ"K͂R schema.datUTs̑Xux PKPJDataset ondernemer.ebz aangemaakt door bootstrap Omschrijving: OndernemerEekBoek-2.030.1/lib/EB/res/templates/nl/templates.txt0000644000400000040000000000002212725476602017760 0ustar jvjvNiet verwijderen! EekBoek-2.030.1/lib/EB/res/templates/nl/sampledb.ebz0000644000400000040000000001701313147544225017516 0ustar jvjvPKfAJP\ &) schema.datUT s̑XȞYux Zn9}HpKJ@; X辰-;>G̏"e;$ju'OŹόŕUe9_T1P*a{)p/3Yo)]T|Sqc?3, 3PV"0'yAyax/Vť:"A*GXETNIٞ;}NzmO/?ۻOۋmiRB7a@jɗ$"R0V,X^1h|eo2/S1%UavG0;osAc}XbO^3/E*,I`%Q@H;D.^C( m`)]"Md9__RgUdZ8pRl130 2^(Ho3/-)RF}eC>wJ;} ٛ`$^zh0=P6+?,X߇ ~>#LוAgRdmn7tH6l< "R(Z}M1o;R?AJ#LQn&sA.ʤdki!Tq(n]/&f;,ZeݴJkc*x\t* &ݤ{8 =pQ阒}i{ xUȝ*Y`le9:]FIu$nչg"tnxS)lje^DPH'ߚph7a4|HƏ JSӳ: :bM;u;ʜ0àLHfV[ c?^Bq1(8SW~ǿK3w$ G6)!b$ө+k+ [ ٗDzm43mTcۧs_g$*.e `YS'ØV}.Z ڴC;-%}KFrCBP,-0[ Ġأtߖ)MԒd #6AAYG\86FA=ПVi0deal !{8әrZN""p;c|륋Ty.CZ;הFq-0F."xuap2wGpC$S kD2u̿ hW#j!S~SzU諾JTm3U/]K [TwqQ@Їso. *ŜxTM=/  2{~7tgmx~;~ie{0ڥ=ӢzZ>΂21kɫs+yDӮ[qBit3Og>WJ/|5AjH{--7YizHjxX6z2&ȇhCqXJ+N L0 24tFd^b)QNS1m!6JlL,!AdvIl2l1!P.Bف[+SE'x[ԦyP 4kOxQUfjq>d؁(&}I32lg(gefstο|%i9x|moʲzVх,ft]57!, 80=lw'ǁG1~˽xOQ?M] :h\rU˜Bޣ> M^;KSΔ}@;qFu|,]l iaИtT g܄Q!-NpB'DE 3xrԟzqS|a+eDNԎbgt,VLulP& ӭhѵ & |sٰHqAn@6,~ D2Z1'^ k0+ڡx$ @qn?w!#g7:~Uˬ*ʪ,:~]`H~b3Iv(F__ sa2t~ɶ;.~)XW| 8Ɏ 'sX݁öZ䉿N|'3dtH."mps0owէbgi8q!hmd<90ix7Y/.&9۱J4߬ڮ:WCԬ<R()S(Ja?O=B V u&̊5vS8B=K߇y O*篁8/D\qZ~p ULcʄ1ýx?J[kM!pW"2s)C[SھاkTGI( kwOGVpiB"Y2j7+}` z* ӻh޾}FKLL6{}YӵDd1@[: /kDV&,$R}K6^Ho]3eyW}If$-b'\h4+=ֈֺ4շo(;S[¿>]g?P<@fUBX=Wy/[ v^}HΆ<ެȱ-q إVw׉V줪~ Sdy8Asz" wPoh|(Phlqi| omW<ӸL_H@l>PZdEHI} (R*p0u=4W'vT%-6(4tꈹ&]Gch:Y<z!Mo#zQ{fAnzVJUy{,DpzYYr9O>\~y$s:, Q O cẮ}wڀ pdWZr.ޛA =JIUHAZ8py9~7Sufj e«j[tz8;x׫|8*c ImR>\2fA_/;ķC2Rɲ4< kׂ?^:[i:-P{ ;LZ(#ys[rSư8q2k:>kGߺhx F|3-VzZ4grDEe U@2VB)#]Ӽ}DrBgtbš@6Pn(E=y=m}L[-[-J,xJ/AfXipT۰C6ҋ.-rᰳ D8}LjG#|wHѨ]~} ߥ/j2(9B<_sB_kՄr({ITpʀu54l൦9h sc`_ KpelCn>DLCё` FepxLkgYKCѕPUDcA4XŘL'OR= 4Juu ;B ʎ8.Jдr! RnmkJ-PKfAJkF# n mutaties.ebUT s̑XXux YnSLeƒDR. Im$h8Ǣ8[ؗȋ0HYEQآ9yn&n<;;'IL4dŖÔD]$CNӫs8D"$bK~" uL~E&wl 㞥XN ey4 x8/)HXp#X M;KQgG$\ rNH1 ޒ-R=1B/]~ 3 }1%J_hyIY8} L]MTek)芭 Uo4Ii\%c6dϋņ4_;2=SEid"N4]H&7_>N?IۋcxJT >'70i.g<4y!HRl91!oɚ2;HņC~J~|Gk pWbۚޜm [Xs*rx`*.LyѸܗWZ]PCSؖm̝3S-pP:{PhB&d̩ S-Ξ*ĉr_pPi-NJ=UKٶi[' mg邩 0<_7.%Ƣ$-[*JJW|(˙sN~<o?k}&5mvnޫ/lD]1ݢ,`Hdj$$KXCX yXafKgם <Ǵ}HĤ?Kh8Ѵn`2o2CSwȊlB}m"6Z4-ĝ}3:E:NOg"A\gu@Ƒ}bλdf] (R;fEOLz{(~WHtQrQə Œ=$%0h^V|[a/ jh:/(ET@H5LGw*ѳ*,H2/U}]ƬB5T'4QUgNfg/[9 0Q=X? Ұe3Dx:yZU JZbAʼne%J`[TJ=pƂaк#MCKV|?Ѷ# e$ O']7[C8Peͼ>Ӽ.ײWES_> +{v]X !nB.X|T.K}A? %E*L@R8Ta&= l2ʡ-@\[)kaO$%XO`B!J S[5ήs AJD:'MGuFf{S) g6am:fvuF^| <]0,I~\hĆ5lfX7&5&kC&$poh6nq\fh\jc+8m(P68GCfrӒ͆o1@}էM~̀C&pl־n_E0#~Chz/zo~:X>UJFxTv rstkK^46Xl0xck_"ǻt1ڥRu'oen88:-s,y QuepgRݮkP ;~V%t *`sROü(HM9z]J-B,-L5)XZWQ'J]]j #Q+r.D\690d4j;~*'fj#c2ToPY~hPSP0 SuQ ^e])DD( _rm—\/%fFp*!-xGBn+ķ0sڴZk*Ŷfu'Ri6ѽnPZ36xe "%Ȇ$ՊowE8B(wB#*A6ryZ(_8תC ," -\QB9^h9۱0`CYN^B^ȷ?:39q +Vvߡl%Jh jED{jA)da2^qi6n3 K,'Qazȫ ь2¢v8[),Umssq O2]~cA8HJrM= l4ݠ's<녣X;E*JR?NoOnZJܝeB$(A G0 ]C,b:Ax+8P qlpYQ~4'c9(0.e? !Y"mIwO_rNw* xwoW^Ѫ=N schema.datUT s̑XȞYux \r۸}TIlŤ =+v;>Nv楋!E萔M|Dq"667#]IM9]M]c<%%]"+lI A(-;rHeR&5MM? "$ O T5lhKF' lGdrA?600J>mQ2Ŋ_zBjɓ2[&eEkqј./N>|zy;9w斜_^W=;F)^_?NbLV5IQ瓓{NmHP,$dJ:)RyVd-k9%; % ;ZTJ5઺L62э:!KwKIWO-}Im^'Iݼp 4YL> uRfQO>ӂꯢN~-w~ J)]dE$jIW#OLgH -7%)-'|.!Gk)KMW`MYQ,( ")Jj-{ CQt'9=:fGŕvV%(L2g` (_0@) %C1'-{Vd `RP>y%hϽi}&%*\5|RUِ>AqZ?}*yLhʓ)N+NꆭFBID fCsjCgYT}z o'ϟ\1+*&@ge @yL2y/lnKnYblQ v20@ xKgDBS#.ѷ,Czj-KB'K46P% O!y[ gU@7 ­UHf#A` MaCĚQLu1MEh<܌ =?ɼʷ^O_T9v$C-x>#ȬRW/u+NTy0hLI0m䔬d1ՂC|n!w|-x*6}hIS<^c-2'YIv uC0L:O|P1"2/ DP&h+oT?QFY!# F4~@خ ZXD:~HQ} bվY'DgIEu3[c 6zIM,M"`TrQ ^O AKÄY:}d%E]ッr<};#&Tl}*#>.9ʐ5wZB!kĀp1 X(ӹQ_,\` RJ\t0$>Æi'GQI7leKh7oO!0^Co3}E/$iҺLrlN4Fglk,^B3r`[xi`DYTת?O+Lz&(MLPl3Uxԋ%8D I{_9gnh-0Rn}"\C.n|NgE ӇDKaSy8/Xv2IMK/X{Y1c2)06[MBdBr T}Ǿ?҇r$H~Q2 qIąn;/xme (v S>ь a)x}5єA:[S\ -vC'&T 䞒93acEKdZ5Q# \>dLio~PrU;ZaV&8K:˓5uR]z)niE { DhdBBTDYg+B:W)FN44F #ٿ>N{>59v{C&I@.T]cUCG;kzחMNKn.H7jfS~w:6NhЅ0^F)UX.?ֵ7ZR)uRQ%`\QHgd]mZX&@VQ_ ͹lE~" maMM(j B9L)+LfV㸍 G5Ƭ ]o㤪 &a.6r$V@fࡅXw!+:-WGhh#E۶gŠ,Iw[}b؄vƄMV}4eb2`vk[XIӚB)#|E6+l!Ff;)v#mr:y:_S](]y6kEP Kq֌ViqMm`Ÿ&y1 Netpת\̋ѱmlk '˩3Kڕ J{j64Qm¬.l_iKRr0 S6[{#<`\ Cqѷ.Ƈac8ěA't^{:=d9[Ӛ]p`:^~RJaMe 7F9TL h6f%<GD;v3j*įd4Rl/-?U=m V6RV5۲e^K_eMAYu$ OspEAr"[ќ_*F -v^AMեyv4KԵ&e~yRUb [LUO1cU]fm:,%E r,7q{Pi#za27y#$0P8j͛7ݣ txRLYK$~"+ڃkb6b5Yk:P\z=*@lI r @sj^(3hk&Dw|,INB^:*ڝ9$zUQ@? [X2pJXk܊#AI$5I#vq߅u"I\`D=xЁgw`qDE=IL7⣁[R|CО;Łk|O=YzlI/6u/謹?&4t=>%NZFDHS \6Wz{(9vTKˆo~)WRRjy<"-T̎s\~Qf*~U鿶|]@TRRVhլ6uŷĢJMXLog)y$_\īlx( #MDlWrY[묺xPk˂SqM}G}-PKfAJG>N schema.datUTs̑Xux PKPNDataset bvnv.ebz aangemaakt door bootstrap Omschrijving: BV / NV Flags: -btwEekBoek-2.030.1/lib/EB/res/templates/sample.conf0000644000400000040000000000454413044346163016746 0ustar jvjv; Example EekBoek config file. ; ; This file will be placed in your current directory when you execute ; the command: ; ; $ ebshell --createsampleconfig ; ; Change as needed. See http://www.eekboek.nl/docs/config.html ; for details. ; ; NOTE THAT FOR MOST PURPOSES, ONLY THE DATABASE NAME AND DRIVER NEED ; TO BE SPECIFIED. ALL OTHER SETTINGS MAY REMAIN AS THEY ARE. [database] ; Name of the database to use. This is the name EekBoek uses to ; identify the database. Note that the actual name as used by the ; database system may be different. name = sample ; The database driver (postgres or sqlite). driver = sqlite ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; NOTE THAT FOR MOST PURPOSES, ALL OTHER SETTINGS MAY REMAIN AS THEY ; ARE. ; THESE ARE EXAMPLES. See http://www.eekboek.nl/docs/config.html ; for details. [general] ; Default location for administrations. ;admdir = $HOME/.eekboek/admdir ; Force use of selection wizard even if a config is present. ;wizard = 1 [preferences] ; Show journal after each booking. ;journal = 1 [database] ; Name of the database to use. This is the name EekBoek uses to ; identify the database. Note that the actual name as used by the ; database system may be different. ;name = sample ; The database driver (postgres or sqlite). ;driver = sqlite ; Name of the system that runs the database, if not local. ;host = dbhost.example.com ; Access port for the database, if not local. ;port = 5432 ; User to access the database, if not current. ;user = eekboek ; Password for database access, if needed. ;password = secret [strategy] ; Method for rounding numbers (ieee, posix, bankers). ;round = ieee ; Combine bookings to match a payment. ;bkm_multi = 1 ; Do not try an alternative calculation if BTW does not match. ;iv_vc = 0 [shell] ; Private module with EekBoek extensions. ;userdefs = Userdefs [format] ; Date format (YYYY-MM-DD, DD-MM-YYY, DD-MM). ;date = DD-MM-YYYY ; Format for amounts (1.234,56 1,234.56 1234.56 1234,56) ;amount = 1.234,56 ; ; If you need big numbers, just increase the format accordingly, e.g. ;amount = 1.234.567,89 [html] ; Where to find stylesheets. If omitted, default styles will be included. ; See the docs. ;cssdir = css [csv] ; Field separator for generated CSV files. ;separator = , [security] ; Microsoft Vista users may need to set this. ;override_security_for_vista = 1 EekBoek-2.030.1/lib/EB/IniWiz.pm0000644000400000040000000003267413151741104013574 0ustar jvjv#! perl -- -*- coding: utf-8 -*- use utf8; package main; use strict; use warnings; use EekBoek; use EB; our $cfg; package EB::IniWiz; use EB; use EB::Tools::MiniAdm; use File::Basename; use Encode; my @adm_dirs; my @adm_names; my $default = _T("--standaard--"); sub getadm { # STATIC my ( $pkg, $opts ) = @_; chdir($opts->{admdir}); my %h; $h{$_} = 1 foreach glob( "*/" . $cfg->std_config ); $h{$_} = 1 foreach glob( "*/" . $cfg->std_config_alt ); my @files = keys(%h); foreach ( sort @files ) { push( @adm_dirs, dirname($_) ); } my $ret = -1; if ( @adm_dirs ) { print STDERR (__x("Beschikbare administraties in {dir}:", dir => $opts->{admdir}), "\n\n"); for ( my $i = 0; $i < @adm_dirs; $i++ ) { my $desc = $adm_dirs[$i]; if ( open( my $fd, '<:utf8', $adm_dirs[$i]."/opening.eb" ) ) { while ( <$fd> ) { next unless /adm_naam\s+"(.+)"/; $desc = $1; last; } close($fd); } printf STDERR ("%3d: %s\n", $i+1, $desc); push( @adm_names, $desc ); } print STDERR ("\n"); while ( 1 ) { print STDERR (_T("Uw keuze"), " <1", @adm_dirs > 1 ? "..".scalar(@adm_dirs) : "", _T(", of N om een nieuwe administratie aan te maken>"), ": " ); my $ans = ; $ans = '', print STDERR "\n" unless defined $ans; return unless $ans; chomp($ans); return -1 if lc($ans) eq 'n'; next unless $ans =~ /^\d+$/; next unless $ans && $ans <= @adm_dirs; $ret = $ans; chdir( $adm_dirs[ $ret-1 ] ) || die("chdir"); last; } } return $ret; } sub run { my ( $self, $opts ) = @_; my $admdir = $opts->{admdir} || $cfg->val(qw(general admdir), $cfg->user_dir("admdir")); $admdir =~ s/\$([A-Z_]+)/$ENV{$1}/ge; mkdir($admdir) unless -d $admdir; die("No admdir $admdir: $!") unless -d $admdir; $opts->{admdir} = $admdir; my $ret = EB::IniWiz->getadm($opts); if ( defined $ret ) { $ret = EB::IniWiz->runwizard($opts) if $ret < 0; $opts->{runeb} = $ret >= 0; } } sub find_db_drivers { my %drivers; if ( $App::Packager::PACKAGED ) { # Trust packager. unless ( $App::Packager::PACKAGED ) { # Ignored, but force packaging. require EB::DB::Postgres; require EB::DB::Sqlite; } return { sqlite => "SQLite", postgres => "PostgreSQL", }; } foreach my $lib ( @INC ) { next unless -d "$lib/EB/DB"; foreach my $drv ( glob("$lib/EB/DB/*.pm") ) { open( my $fd, "<", $drv ) or next; while ( <$fd> ) { if ( /sub\s+type\s*{\s*\"([^\"]+)\"\s*;?\s*}/ ) { my $s = $1; my $t = substr($drv,length("$lib/EB/DB/")); $t =~ s/\.pm$//; $drivers{lc($t)} ||= $s; last; } } close($fd); } } \%drivers; } sub findchoice { my ( $choice, $choices ) = @_; $choice = lc($choice); my $i = 0; while ( $i < @$choices ) { return $i if lc($choices->[$i]) eq $choice; $i++; } return; } sub runwizard { my ( $self ) = @_; my $year = 1900 + (localtime(time))[5]; my $dir = dirname( findlib( "templates.txt", "templates" ) ); my @ebz = map { [ $_, "" ] } glob( "$dir/*.ebz" ); my @ebz_desc = ( _T("Lege administratie") ); my $i = 0; my $dp = quotemeta( _T("Omschrijving").": " ); foreach my $ebz ( @ebz ) { require Archive::Zip; my $zip = Archive::Zip->new(); next unless $zip->read($ebz->[0]) == 0; my $desc = $zip->zipfileComment; if ( $desc =~ /flags:\s*(.*)/i ) { $ebz->[1] = $1; } if ( $desc =~ /^$dp\s*(.*)$/m ) { $desc = $1; } elsif ( $desc =~ /export van (.*) aangemaakt door eekboek/i ) { $desc = _T($1); } else { $desc = $1 if $ebz->[0] =~ m/([^\\\/]+)\.ebz$/i; } $desc =~ s/[\n\r]+$//; # can't happen? think again... push( @ebz_desc, $desc); $i++; } unshift (@ebz, undef ); # skeleton # Enumerate DB drivers. my $drivers = find_db_drivers(); my @db_drivers; foreach ( sort keys %$drivers ) { push( @db_drivers, $_ ); } my $db_default = findchoice( "sqlite", \@db_drivers ); my @btw = ( _T("Maand"), _T("Kwartaal"), _T("Jaar") ); my @noyes = ( _T("Nee"), _T("Ja") ); my $answers = { admname => _T("Mijn eerste EekBoek"), begindate => $year, admbtw => 1, btwperiod => findchoice( _T("Kwartaal"), \@btw ), template => findchoice( _T("EekBoek Voorbeeldadministratie"), \@ebz_desc ), dbdriver => $db_default, dbcreate => 1, }; $answers->{dbhost} = $ENV{EB_DB_HOST} || $default; $answers->{dbport} = $ENV{EB_DB_PORT} || $default; $answers->{dbuser} = $ENV{EB_DB_USER} || $default; $answers->{dbpassword} = $ENV{EB_DB_PASSWORD} || ""; $answers->{dbcr_config} = 1; $answers->{dbcr_admin} = 1; $answers->{dbcr_database} = 1; my $queries; $queries = [ { code => "admname", text => _T(< "string", prompt => _T("Naam"), post => sub { my $c = shift; foreach ( @adm_names ) { next unless lc($_) eq lc($c); warn(_T("Er bestaat al een administratie met deze naam.")."\n"); return; } $c = lc($c); $c =~ s/\W+/_/g; $c .= "_" . $answers->{begindate}, $answers->{admcode} = $c; return 1; }, }, { code => "begindate", text => _T(< _T("Begindatum"), type => "int", range => [ $year-20, $year+10 ], post => sub { my $c = shift; return unless $answers->{admcode}; $answers->{admcode} =~ s/_\d\d\d\d$/_$c/; return 1; }, }, { code => "admcode", text => _T(< "string", prompt => _T("Code"), pre => sub { return if $answers->{admcode}; my $c = $answers->{admname}; $c = lc($c); $c =~ s/\W+/_/g; $c .= "_" . $answers->{begindate}, $answers->{admcode} = $c; return 1; }, post => sub { my $c = shift; foreach ( @adm_dirs ) { next unless lc($_) eq lc($c); warn(__x("Er bestaat al een administratie met code \"{code}\"", code => $c)."\n"); return; } return 1; }, }, { code => "template", text => _T(< "choice", prompt => _T("Sjabloon"), choices => \@ebz_desc, post => sub { my $c = shift; if ( $c == 0 ) { $queries->[4]->{skip} = 0; $queries->[5]->{skip} = 0; } elsif ( $ebz[$c]->[1] =~ /\B-btw\b/i ) { $answers->{admbtw} = 0; $queries->[4]->{skip} = 1; $queries->[5]->{skip} = 1; } else { $answers->{admbtw} = 1; $queries->[4]->{skip} = 1; $queries->[5]->{skip} = 0; } return 1; }, }, { code => "admbtw", prompt => _T("Moet BTW worden toegepast in deze administratie"), type => "bool", post => sub { my $c = shift; $queries->[5]->{skip} = !$c; return 1; }, }, { code => "btwperiod", prompt => _T("Aangifteperiode voor de BTW"), type => "choice", choices => \@btw, }, { code => "dbdriver", text => _T(< "choice", prompt => _T("Database"), choices => \@db_drivers, post => sub { my $c = shift; $queries->[$_]->{skip} = $c == $db_default for ( 7 .. 10 ); return 1; } }, { code => "dbhost", prompt => _T("Database server host, indien niet lokaal"), type => "string", skip => 1, }, { code => "dbport", prompt => _T("Database server netwerk poort, indien niet standaard"), type => "int", skip => 1, }, { code => "dbuser", prompt => _T("Usernaam voor de database"), type => "string", skip => 1, }, { code => "dbpassword", prompt => _T("Password voor de database user"), type => "string", skip => 1, }, { code => "dbcr_config", prompt => _T("Moet het configuratiebestand worden aangemaakt"), type => "bool", }, { code => "dbcr_admin", prompt => _T("Moeten de administratiebestanden worden aangemaakt"), type => "bool", }, { code => "dbcr_database", prompt => _T("Moet de database worden aangemaakt"), type => "bool", }, { code => "dbcreate", text => _T("Gereed om de bestanden aan te maken."), prompt => _T("Doorgaan"), type => "bool", }, ]; QL: for ( my $i = 0; $i < @$queries; $i++ ) { $i = 0 if $i < 0; my $q = $queries->[$i]; next if $q->{skip}; my $code = $q->{code}; print STDERR ( "\n" ); print STDERR ( $q->{text}, "\n" ) if $q->{text}; QQ: while ( 1 ) { $q->{pre}->() if $q->{pre}; if ( $q->{choices} ) { for ( my $i = 0; $i < @{ $q->{choices} }; $i++ ) { printf STDERR ( "%3d: %s\n", $i+1, $q->{choices}->[$i] ); } print STDERR ("\n"); $q->{range} = [ 1, scalar(@{ $q->{choices} }) ]; } print STDERR ( $q->{prompt} ); print STDERR ( " <", $q->{range}->[0], "..", $q->{range}->[1], ">" ) if $q->{range}; print STDERR ( " [", $q->{type} eq 'choice' ? $answers->{$code}+1 : $q->{type} eq 'bool' ? $noyes[$answers->{$code}] : $answers->{$code}, "]" ) if defined $answers->{$code}; print STDERR ( ": " ); my $a = decode_utf8( scalar ); $a = "-\n" unless defined $a; chomp($a); if ( $a eq '-' ) { while ( $i > 0 ) { $i--; redo QL unless $queries->[$i]->{skip}; } } if ( $q->{type} eq 'string' ) { if ( $a eq '' ) { $a = $answers->{$code}; } } elsif ( $q->{type} eq 'bool' ) { if ( $a eq '' ) { $a = $answers->{$code}; } elsif ( $a =~ /^(ja?|ne?e?)$/i ) { $a = $a =~ /^j/i ? 1 : 0; } #### FIXME elsif ( $a =~ /^(ye?s?|no?)$/i ) { $a = $a =~ /^y/i ? 1 : 0; } else { warn( _T("Antwoordt 'ja' of 'nee' a.u.b.") ); redo QQ; } } elsif ( $q->{type} eq 'int' || $q->{type} eq 'choice' ) { if ( $a eq '' ) { $a = $answers->{$code}; $a++ if $q->{type} eq 'choice'; } elsif ( $a !~ /^\d+$/ or $q->{range} && ( $a < $q->{range}->[0] || $a > $q->{range}->[1] ) ) { if ( $q->{range} ) { warn(__x("Ongeldig antwoord, het moet een getal tussen {first} en {last} zijn", first => $q->{range}->[0], last => $q->{range}->[1]) . "\n"); } else { warn(_T("Ongeldig antwoord, het moet een getal zijn")."\n"); } redo QQ; } $a-- if $q->{type} eq 'choice'; } else { die("PROGRAM ERROR: Unhandled request type: ", $q->{type}, "\n"); } if ( $q->{post} ) { redo QQ unless $q->{post}->($a, $answers->{$code}); } $answers->{$code} = $a; last QQ if defined $answers->{$code}; } } return -1 unless $answers->{dbcreate}; my %opts; $opts{adm_naam} = $answers->{admname}; $opts{adm_code} = $answers->{admcode}; $opts{adm_begindatum} = $answers->{begindate}; $opts{db_naam} = $answers->{admcode}; $opts{db_driver} = $db_drivers[$answers->{dbdriver}]; unless ( $answers->{dbdriver} == $db_default ) { $opts{db_host} = $answers->{dbhost} if $answers->{dbhost} && $answers->{dbhost} ne $default; $opts{db_port} = $answers->{dbport} if $answers->{dbport} && $answers->{dbport} ne $default; $opts{db_user} = $answers->{dbuser} if $answers->{dbuser} && $answers->{dbuser} ne $default; $opts{db_password} = $answers->{dbpassword} if $answers->{dbpassword} && $answers->{dbpassword} ne ""; } $opts{"has_$_"} = 1 foreach qw(debiteuren crediteuren kas bank); $opts{has_btw} = $answers->{admbtw}; $opts{"create_$_"} = $answers->{dbcr_admin} foreach qw(schema relaties opening mutaties); $opts{"create_$_"} = $answers->{"dbcr_$_"} foreach qw(config database); $opts{adm_btwperiode} = @btw[ $answers->{btwperiod} ] if $opts{has_btw}; $opts{template} = $ebz[ $answers->{template} ]->[0]; if ( $opts{adm_code} ) { mkdir($opts{adm_code}) unless -d $opts{adm_code}; chdir($opts{adm_code}) or die("chdir($opts{adm_code}): $!\n");; } EB::Tools::MiniAdm->sanitize(\%opts); # warn Dumper \%opts; my @req = qw(config schema relaties opening mutaties database); my $req = @req; foreach my $c ( @req ) { if ( $c eq "database" ) { next unless $opts{create_database}; $req--; my $ret; undef $cfg; EB->app_init( { app => $EekBoek::PACKAGE, %opts } ); require EB::Main; local @ARGV = qw( --init ); $ret = EB::Main->run; die(_T("Er is een probleem opgetreden. Raadplaag uw systeembeheerder.")."\n") if $ret; } else { $req--; my $m = "generate_". $c; EB::Tools::MiniAdm->$m(\%opts); } } if ( $req ) { print STDERR ("\n", _T("De gewenste bestanden zijn aangemaakt."), "\n\n"); return -1; } print STDERR ("\n", _T("De gewenste bestanden zijn aangemaakt."), " ", _T("U kunt meteen aan de slag.")."\n\n"); return 0; } 1; EekBoek-2.030.1/lib/EB/Config/0000755000400000040000000000000013151742350013222 5ustar jvjvEekBoek-2.030.1/lib/EB/Config/Data.pm0000644000400000040000000001205112725476602014442 0ustar jvjv#! perl # Data.pm -- Multi-purpose definition of config data # Author : Johan Vromans # Created On : Sat Oct 24 21:30:54 2009 # Last Modified By: Johan Vromans # Last Modified On: Wed Mar 16 20:22:16 2011 # Update Count : 17 # Status : Unknown, Use with caution! use strict; use warnings; package EB::Config::Data; use EB; my $data = [ { section => "cpy", tag => N__("Bedrijfsgegevens"), keys => [ { name => "name", tag => N__("Naam"), type => 'string', value => undef }, { name => "id", tag => N__("Administratienummer"), type => 'string', value => undef }, { name => "address", tag => N__("Adres"), type => 'string', value => undef }, { name => "zip", tag => N__("Postcode"), type => 'string', value => undef }, { name => "city", tag => N__("Plaats"), type => 'string', value => undef }, { name => "taxreg", tag => N__("Fiscaal nummer"), type => 'string', value => undef }, ], }, { section => "general", tag => N__("Algemeen"), keys => [ { name => "admdir", tag => N__("Folder voor administraties"), type => 'folder', value => '$HOME/.eekboek/admdir' }, { name => "wizard", tag => N__("Forceer wizard"), type => 'bool', value => undef }, ], }, { section => "prefs", tag => N__("Voorkeursinstellingen"), keys => [ { name => "journal", tag => N__("Toon journaalpost na elke boeking"), type => 'bool', value => undef }, ], }, { section => "Database", keys => [ { name => "name", tag => N__("Naam"), type => 'string', value => undef }, { name => "driver", tag => N__("Driver"), type => 'choice', value => undef, choices => [ qw(SQLite PostgreSQL) ], values => [ qw(sqlite postgres) ], }, { name => "user", tag => N__("Gebruikersnaam"), type => 'string', value => undef }, { name => "password", tag => N__("Toegangscode"), type => 'string', value => undef }, { name => "host", tag => N__("Server systeem"), type => 'string', value => undef }, { name => "port", tag => N__("Server poort"), type => 'int', value => undef }, ], }, { section => "Strategy", tag => N__("Strategie"), keys => [ { name => "round", tag => N__("Afrondingsmethode"), type => 'choice', value => undef, choices => [ qw(IEEE Bankers POSIX) ], values => [ qw(ieee bankers posix) ], }, { name => "bkm_multi", tag => N__("Meervoudig afboeken"), type => 'bool', value => undef }, { name => "iv_vc", tag => N__("BTW correcties"), type => 'bool', value => undef }, ], }, { section => "shell", tag => N__("Shell"), keys => [ { name => "prompt", tag => N__("Prompt"), type => 'string', value => undef }, { name => "userdefs", tag => N__("Eigen uitbreidingen"), type => 'string', value => undef }, ], }, { section => "Format", tag => N__("Formaten"), keys => [ { name => "numfmt", tag => N__("Getalformaat"), type => 'choice', value => undef, choices => [ "12345,99 (decimaalkomma)", "12345.99 (decimaalpunt)", "12.345,99 (duizendpunt + decimaalkomma)", "12,345.99 (duizendkomma + decimaalpunt)" ], values => [ "12345,99", "12345.99", "12.345,99", "12,345.99" ], }, { name => "date", tag => N__("Datumformaat"), type => 'choice', value => undef, choices => [ "2008-05-31 (ISO)", "31-05-2008 (NEN)", "31-05 (NEN, verkort)" ], values => [ "YYYY-MM-DD", "DD-MM-YYYY", "DD-MM" ], }, ], }, { section => "text", tag => N__("Tekstrapporten"), keys => [ { name => "numwidth", tag => N__("Kolombreedte voor getallen"), type => 'slider', range => [5, 20, 9], value => undef, } ], }, { section => "html", tag => N__("HTML rapporten"), keys => [ { name => "cssdir", tag => N__("Style sheets"), type => 'folder', value => undef, }, ], }, { section => "csv", tag => N__("CSV rapporten"), keys => [ { name => "separator", tag => N__("Scheidingsteken"), type => 'choice', value => undef, choices => [ ", (komma)", "; (puntkomma)", ": (dubbelpunt)", "Tab", ], values => [ ",", ";", ":", "\t", ], }, ], }, { section => "security", tag => N__("Beveiliging"), keys => [ { name => "override_security_for_vista", tag => N__("Beveiliging voor MS Vista uitschakelen"), type => 'bool', value => undef, }, ], }, ]; sub get_data { # class method return bless $data; } sub get_name { my ($self) = $_; "EekBoek"; } sub get_site_url { my ($self) = $_; "http://www.eekboek.nl/"; } sub get_help_url { my ($self) = @_; $self->get_site_url . "docs/config.html"; } sub get_topic_help_url { my ($self, $section, $key) = @_; $self->get_help_url . "#" . join("_", map { lc } $section, $key ); } unless ( caller ) { require YAML; # Use Bless to reorder the data a bit. foreach ( @$data ) { YAML::Bless($_)->keys([qw(section tag keys)]); foreach ( @{$_->{keys}} ) { my %h = map { $_ => 1 } keys %$_; delete @h{qw(name tag type value)}; YAML::Bless($_)->keys([qw(name tag type value), keys(%h)]); } } warn YAML::Dump($data); } 1; EekBoek-2.030.1/lib/EB/Globals.pm0000644000400000040000000000555713044346163013755 0ustar jvjv#! perl # Globals.pm -- # Author : Johan Vromans # Created On : Thu Jul 14 12:54:08 200 # Last Modified By: Johan Vromans # Last Modified On: Thu Sep 24 22:27:58 2015 # Update Count : 113 # Status : Unknown, Use with caution! use utf8; package EB::Globals; use strict; use warnings; use base qw(Exporter); our @EXPORT; # Define new constant subroutine, and add it to @EXPORT. sub _newconst($$) { my $t = $_[1]; $t = "'$t'" unless $t =~ /^\d+$/ || $t =~ /^\[.*\]$/; #warn("sub $_[0](){$t}\n"); eval("sub $_[0](){$t}"); push(@EXPORT, $_[0]); } # Define an enumeration of constant subroutines. sub _enumconst($@) { my ($pfx, @list) = @_; my $index = 0; foreach ( @list ) { my $key = $pfx.$_; if ( $key =~ /^(.*)=(\d+)$/ ) { $key = $1; $index = $2; } _newconst( $key, $index++ ); } } # To defeat gettext. Strings here are not for translation. sub N__($) { $_[0] } _newconst("SCM_MAJVERSION", 1); _newconst("SCM_MINVERSION", 0); _newconst("SCM_REVISION", 17); _newconst("AMTPRECISION", 2); _newconst("AMTWIDTH", 9); _newconst("NUMGROUPS", 3); _newconst("BTWPRECISION", 4); _newconst("BTWWIDTH", 5); _newconst("AMTSCALE", 100); _newconst("BTWSCALE", 10000); _newconst("BKY_PREVIOUS", "<<<<"); _enumconst("DBKTYPE_", qw(INKOOP=1 VERKOOP BANK KAS MEMORIAAL) ); _newconst("DBKTYPES", "[qw(".N__("-- Inkoop Verkoop Bank Kas Memoriaal").")]"); _enumconst("BTWTARIEF_", qw(NUL=0 HOOG LAAG PRIV ANDERS) ); _newconst("BTWTARIEVEN", "[qw(".N__("Nul Hoog Laag Privé Anders").")]"); _newconst("BTWPERIODES", "[qw(".N__("Geen Jaar 2 3 Kwartaal 5 6 7 8 9 10 11 Maand").")]"); _newconst("BTWPER_GEEN", 0); _newconst("BTWPER_JAAR", 1); _newconst("BTWPER_KWARTAAL", 4); _newconst("BTWPER_MAAND", 12); _enumconst("BTWTYPE_", qw(NORMAAL=0 VERLEGD INTRA EXTRA) ); _newconst("BTWTYPES", "[qw(".N__("Normaal Verlegd Intra Extra").")]"); _newconst("BTWKLASSE_BTW_BIT", 0x200); _newconst("BTWKLASSE_KO_BIT", 0x100); _newconst("BTWKLASSE_TYPE_BITS", 0x0ff); # Starting value for automatically defined BTW codes. _newconst("BTW_CODE_AUTO", 1024); # Eval, since it uses the (run-time defined) subroutines. eval( 'sub BTWKLASSE($$$) {'. ' ($_[0] ? BTWKLASSE_BTW_BIT : 0)'. ' | ($_[1] ? ($_[1] & BTWKLASSE_TYPE_BITS) : 0)'. ' | ($_[2] ? BTWKLASSE_KO_BIT : 0);'. '}' ); push(@EXPORT, qw(BTWKLASSE)); _newconst("ATTENCODINGS", "[qw(".N__("none uri base64").")]"); _enumconst("ATTENCODING_", qw( NONE=0 URI BASE64 )); unless ( caller ) { print STDOUT ("-- Constants\n\n", "COMMENT ON TABLE Constants IS\n", " 'This is generated from ", __PACKAGE__, ". DO NOT CHANGE.';\n\n", "COPY Constants (name, value) FROM stdin;\n"); foreach my $key ( sort(@EXPORT) ) { no strict; next if ref($key->()); print STDOUT ("$key\t", $key->(), "\n"); } print STDOUT ("\\.\n"); } 1; EekBoek-2.030.1/lib/EB/DB.pm0000644000400000040000000005037213151741111012641 0ustar jvjv#! perl -- -*- coding: utf-8 -*- use utf8; # Author : Johan Vromans # Created On : Sat May 7 09:18:15 2005 # Last Modified By: Johan Vromans # Last Modified On: Thu Aug 31 10:01:13 2017 # Update Count : 457 # Status : Unknown, Use with caution! ################ Common stuff ################ package main; our $cfg; package EB::DB; use strict; use warnings; use EB; use DBI; my $dbh; # singleton for DB my $verbose = 0; my $trace = 0; ################ high level ################ sub check_db { my ($self) = @_; my $fail = 0; # Check the existence of the required tables. my %tables = map { $_, 1 } @{$self->tablesdb}; foreach my $table ( qw(constants standaardrekeningen verdichtingen accounts relaties accounts boekstukken boekstukregels btwtabel journal metadata) ) { next if $tables{$table}; $fail++; warn("?".__x("Tabel {table} ontbreekt in database {db}", table => $table, db => $dbh->{Name}) . "\n"); } warn(join(" ", sort keys %tables)."\n") if $fail; die("?".__x("Ongeldige EekBoek database: {db}.", db => $dbh->{Name}) . " " . _T("Wellicht is de database nog niet geïnitialiseerd?")."\n") if $fail; # Check version, and try automatic upgrade. my ($maj, $min, $rev) = @{$self->do("SELECT adm_scm_majversion, adm_scm_minversion, adm_scm_revision". " FROM Metadata")}; while ( !($maj == SCM_MAJVERSION && sprintf("%03d%03d", $min, $rev) eq sprintf("%03d%03d", SCM_MINVERSION, SCM_REVISION)) ) { # Basically, this will migrate to the highest possibly version, and then retry. my $cur = sprintf("%03d%03d%03d", $maj, $min, $rev); my $tmpl = libfile("migrate/$cur?????????.*l"); my @a = reverse sort glob($tmpl); last unless @a == 1; if ( $a[0] =~ /\.sql$/ && open(my $fh, "<:encoding(utf-8)", $a[0])) { warn("!"._T("De database wordt aangepast aan de nieuwere versie")."\n"); local($/); # slurp mode my $sql = <$fh>; # slurp close($fh); require EB::Tools::SQLEngine; eval { EB::Tools::SQLEngine->new(dbh => $self, trace => $trace)->process($sql); }; warn("?".$@) if $@; $dbh->rollback if $@; } elsif ( $a[0] =~ /\.pl$/ ) { warn("!"._T("De database wordt aangepast aan de nieuwere versie")."\n"); my $sd = $::dbh; $::dbh = $self; eval { require $a[0] }; $::dbh = $sd; warn("?".$@) if $@; } ($maj, $min, $rev) = @{$self->do("SELECT adm_scm_majversion, adm_scm_minversion, adm_scm_revision". " FROM Metadata")}; die("?"._T("De migratie is mislukt. Gelieve de documentatie te raadplegen.")."\n") if $cur eq sprintf("%03d%03d%03d", $maj, $min, $rev); } die("?".__x("Ongeldige EekBoek database: {db} versie {ver}.". " Benodigde versie is {req}.", db => $dbh->{Name}, ver => "$maj.$min.$rev", req => join(".", SCM_MAJVERSION, SCM_MINVERSION, SCM_REVISION)) . "\n") unless $maj == SCM_MAJVERSION && sprintf("%03d%03d", $min, $rev) eq sprintf("%03d%03d", SCM_MINVERSION, SCM_REVISION); # Verify koppelingen. for ( $self->std_acc("deb", undef) ) { next unless defined; my $rr = $self->do("SELECT acc_debcrd, acc_balres FROM Accounts where acc_id = ?", $_); $fail++, warn("?".__x("Geen grootboekrekening voor {dc} ({acct})", dc => _T("Debiteuren"), acct => $_)."\n") unless $rr; # $fail++, warn("?".__x("Foutieve grootboekrekening voor {dc} ({acct})", dc => _T("Debiteuren"), acct => $_)."\n") unless $rr->[0] && $rr->[1]; } for ( $self->std_acc("crd", undef) ) { next unless defined; my $rr = $self->do("SELECT acc_debcrd, acc_balres FROM Accounts where acc_id = ?", $_); $fail++, warn("?".__x("Geen grootboekrekening voor {dc} ({acct})", dc => _T("Crediteuren"), acct => $_)."\n") unless $rr; # $fail++, warn("?".__x("Foutieve grootboekrekening voor {dc} ({acct})", dc => _T("Crediteuren"), acct => $_)."\n") if $rr->[0] || !$rr->[1]; } for ( $self->std_acc("btw_ok", undef) ) { next unless defined; my $rr = $self->do("SELECT acc_balres FROM Accounts where acc_id = ?", $_); $fail++, warn("?".__x("Geen grootboekrekening voor {dc} ({acct})", dc => _T("BTW betaald"), acct => $_)."\n") unless $rr; warn("?".__x("Foutieve grootboekrekening voor {dc} ({acct})", dc => _T("BTW betaald"), acct => $_)."\n") unless $rr->[0]; } for ( $self->std_acc("winst") ) { my $rr = $self->do("SELECT acc_balres FROM Accounts where acc_id = ?", $_); $fail++, warn("?".__x("Geen grootboekrekening voor {dc} ({acct})", dc => _T("overboeking winst"), acct => $_)."\n") unless $rr; warn("?".__x("Foutieve grootboekrekening voor {dc} ({acct})", dc => _T("overboeking winst"), acct => $_)."\n") unless $rr->[0]; } die("?"._T("CONSISTENTIE-VERIFICATIE STANDAARDREKENINGEN MISLUKT")."\n") if $fail; $self->setup; } sub setup { my ($self) = @_; $dbh->begin_work; setupdb(); # Create temp table for account mangling. # This table has the purpose of copying the data from Accounts, so that # data from already completed financial years can be corrected when # creating overviews, such as Balance statements and Result accounts. # This way no backdated calculations need to be made when transitions # to previous financial years are involved. my $sql = "SELECT * INTO TEMP TAccounts FROM Accounts WHERE acc_id = 0"; $sql = $self->feature("filter")->($sql) if $self->feature("filter"); $dbh->do($sql) if $sql; # Make it semi-permanent (this connection only). $dbh->commit; } #### UNUSED sub upd_account { my ($self, $acc, $amt) = @_; my $op = '+'; # perfectionism if ( $amt < 0 ) { $amt = -$amt; $op = '-'; } $self->sql_exec("UPDATE Accounts". " SET acc_balance = acc_balance $op ?". " WHERE acc_id = ?", $amt, $acc); } sub store_journal { my ($self, $jnl) = @_; foreach ( @$jnl ) { $self->sql_insert("Journal", [qw(jnl_date jnl_dbk_id jnl_bsk_id jnl_bsr_date jnl_bsr_seq jnl_seq jnl_type jnl_acc_id jnl_amount jnl_damount jnl_desc jnl_rel jnl_rel_dbk jnl_bsk_ref)], @$_); } } sub bskid { my ($self, $nr, $bky) = @_; return $nr if $nr =~ /^\d+$/ && !wantarray; # Formats: # NNN # DBK:NNN # DBK:BKY:NNN # REL:REF # REL:BKY:REF my $rr; $bky = $self->adm("bky") unless defined($bky); if ( $nr =~ /^([[:alpha:]][^:]+)(?::([^:]+))?:(.*?\D.*)$/ and $rr = $self->do("SELECT rel_code, rel_desc". " FROM Relaties". " WHERE upper(rel_code) = ?", uc($1)) ) { my ($rel_id, $rel_desc) = @$rr; if ( defined($2) ) { unless ( defined $self->lookup($2, qw(Boekjaren bky_code bky_code)) ) { return wantarray ? (undef, undef, __x("Onbekend boekjaar: {bky}", bky => $2)) : undef; } $bky = $2; } $rr = $self->do("SELECT bsk_id, bsk_dbk_id". " FROM Boekstukken, Boekstukregels". " WHERE bsr_rel_code = ?". " AND bsr_bsk_id = bsk_id". " AND upper(bsk_ref) = ?". " AND bsk_bky = ?", $rel_id, uc($3), $bky); unless ( $rr ) { return wantarray ? (undef, undef, __x("Onbekend boekstuk {ref} voor relatie {rel} ({desc})", rel => $rel_id, desc => $rel_desc, ref => $3)) : undef; } $bky = $bky eq $self->adm("bky") ? "" : ":$bky"; return wantarray ? ($rr->[0], $self->lookup($rr->[1], qw(Dagboeken dbk_id dbk_desc))."$bky:$3", undef) : $rr->[0]; } if ( $nr =~ /^([[:alpha:]][^:]+)(?::([^:]+))?:(\d+)$/ ) { $rr = $self->do("SELECT dbk_id, dbk_desc". " FROM Dagboeken". " WHERE upper(dbk_desc) LIKE ?", uc($1)); unless ( $rr ) { return wantarray ? (undef, undef, __x("Onbekend dagboek: {dbk}", dbk => $1)) : undef; } my ($dbk_id, $dbk_desc) = @$rr; if ( defined($2) ) { unless ( defined $self->lookup($2, qw(Boekjaren bky_code bky_code)) ) { return wantarray ? (undef, undef, __x("Onbekend boekjaar: {bky}", bky => $2)) : undef; } $bky = $2; } $rr = $self->do("SELECT bsk_id". " FROM Boekstukken". " WHERE bsk_nr = ?". " AND bsk_bky = ?". " AND bsk_dbk_id = ?", $3, $bky, $dbk_id); unless ( $rr ) { return wantarray ? (undef, undef, __x("Onbekend boekstuk {bsk} in dagboek {dbk}", dbk => $dbk_desc, bsk => $3)) : undef; } $bky = $bky eq $self->adm("bky") ? "" : ":$bky"; return wantarray ? ($rr->[0], "$dbk_desc$bky:$3", undef) : $rr->[0]; } if ( $nr =~ /^(\d+)$/ ) { $rr = $self->do("SELECT bsk_nr, dbk_id, dbk_desc, bsk_bky". " FROM Boekstukken, Dagboeken". " WHERE bsk_dbk_id = dbk_id". " AND bsk_id = ?", $nr); unless ( $rr ) { return wantarray ? (undef, undef, __x("Onbekend boekstuk: {bsk}", bsk => $nr)) : undef; } my ($bsk_nr, $dbk_id, $dbk_desc, $bsk_bky) = @$rr; $bsk_nr =~ s/\s+$//; $bky = $bsk_bky eq $self->adm("bky") ? "" : ":$bsk_bky"; return wantarray ? ($nr, "$dbk_desc$bky:$bsk_nr", undef) : $nr; } die("?".__x("Ongeldige boekstukaanduiding: {bsk}", bsk => $nr)."\n"); } ################ low level ################ sub new { my ($pkg, %atts) = @_; $pkg = ref($pkg) || $pkg; $verbose = delete($atts{verbose}) || 0; $trace = delete($atts{trace}) || 0; my $self = {}; bless $self, $pkg; $self->_init; $self; } sub _init { my ($self) = @_; } my %adm; sub adm { my ($self, $name, $value, $notx) = @_; if ( $name eq "" ) { %adm = (); return; } unless ( %adm ) { $self->connectdb; my $sth = $self->sql_exec("SELECT *". " FROM Metadata, Boekjaren". " WHERE adm_bky = bky_code"); my $rr = $sth->fetchrow_hashref; $sth->finish; while ( my($k,$v) = each(%$rr) ) { my $k1 = $k; $k =~ s/^(adm|bky)_//; $adm{lc($k)} = [$k1, $v]; } } exists $adm{lc($name)} || die("?".__x("Niet-bestaande administratie-eigenschap: {adm}", adm => $name)."\n"); $name = lc($name); if ( @_ >= 3 ) { $self->begin_work unless $notx; $self->sql_exec("UPDATE Metadata". " SET ".$adm{$name}->[0]." = ?", $value)->finish; $self->commit unless $notx; $adm{$name}->[1] = $value; } else { defined $adm{$name} ? $adm{$name}->[1] : ""; } } sub dbver { my ($self) = @_; sprintf("%03d%03d%03d", $self->adm("scm_majversion"), $self->adm("scm_minversion")||0, $self->adm("scm_revision")); } my %std_acc; my @std_acc; sub std_acc { my ($self, $name, $def) = @_; if ( $name eq "" ) { %std_acc = (); @std_acc = (); return; } $self->std_accs unless %std_acc; return $std_acc{lc($name)} if defined($std_acc{lc($name)}); return $def if @_ > 2; die("?".__x("Niet-bestaande standaardrekening: {std}", std => $name)."\n"); } sub std_accs { my ($self) = @_; unless ( @std_acc ) { $self->connectdb; my $sth = $self->sql_exec("SELECT * FROM Standaardrekeningen"); my $rr = $sth->fetchrow_hashref; $sth->finish; while ( my($k,$v) = each(%$rr) ) { next unless defined $v; $k =~ s/^std_acc_//; $std_acc{lc($k)} = $v; } @std_acc = sort(keys(%std_acc)); } \@std_acc; } my $accts; sub accts { my ($self, $sel) = @_; $sel = $sel ? " WHERE $sel" : ""; return $accts->{$sel} if $accts->{$sel}; my $sth = $self->sql_exec("SELECT acc_id,acc_desc". " FROM Accounts". $sel. " ORDER BY acc_id"); my $rr; while ( $rr = $sth->fetchrow_arrayref ) { $accts->{$sel}->{$rr->[0]} = $rr->[1]; } $accts->{$sel}; } sub acc_inuse { my ($dbh, $acc) = @_; my $rr; $rr = $dbh->do("SELECT jnl_acc_id FROM Journal". " WHERE jnl_acc_id = ?". " LIMIT 1", $acc); return 1 if $rr && $rr->[0]; $rr = $dbh->do("SELECT dbk_acc_id FROM Dagboeken". " WHERE dbk_acc_id = ?". " LIMIT 1", $acc); return 1 if $rr && $rr->[0]; $rr = $dbh->do("SELECT rel_acc_id FROM Relaties". " WHERE rel_acc_id = ?". " LIMIT 1", $acc); return 1 if $rr && $rr->[0]; $rr = $dbh->do("SELECT bkb_acc_id FROM Boekjaarbalans". " WHERE bkb_acc_id = ?", $acc); return 1 if $rr && $rr->[0]; if ( $rr = $dbh->do("SELECT * FROM Standaardrekeningen") ) { for ( @$rr ) { return 1 if defined($_) && $_ == $acc; } } return; } sub dbh{ $dbh; } sub adm_open { my ($self) = @_; $self->connectdb; $self->adm("bky") ne BKY_PREVIOUS; } sub adm_busy { my ($self) = @_; $self->connectdb; $self->do("SELECT COUNT(*) FROM Journal")->[0]; } sub does_btw { my ($self) = @_; $self->connectdb; return defined($self->adm("btwbegin")) if $self->adm_open; $self->do("SELECT COUNT(*)". " FROM BTWTabel". " WHERE btw_tariefgroep != 0")->[0]; } ################ API calls for simple applications ################ sub connect { my $dataset = $cfg->val(qw(database name)); if ( !$dataset ) { die(_T("Geen dataset opgegeven.". " Specificeer een dataset in de configuratiefile."). "\n"); } $::dbh = EB::DB::->new(); } sub disconnect { $::dbh->disconnectdb; undef $::dbh; } ################ API calls for database backend ################ my $tx; my $dbpkg; sub connectdb { my ($self, $nocheck) = @_; return $dbh if $dbh; my $pkg = $dbpkg || $self->_loaddbbackend; my $dbname = $cfg->val(qw(database name)); croak("?INTERNAL ERROR: No database name") unless defined $dbname; eval { $dbh = $pkg->connect($dbname) or die("?".__x("Database verbindingsprobleem: {err}", err => $DBI::errstr)."\n"); }; die($@) if $@; $dbpkg = $pkg; $dbh->{RaiseError} = 1; #$dbh->{AutoCommit} = 0; $dbh->{ChopBlanks} = 1; $self->check_db unless $nocheck; $tx = 0; $dbh; } sub disconnectdb { my ($self) = shift; return unless $dbpkg; return unless $dbh; resetdbcache($self); $dbpkg->disconnect; $tx = 0; undef $dbh; } sub feature { my ($self) = shift; $dbpkg ||= $self->_loaddbbackend; $dbpkg->feature(@_); } sub setupdb { my ($self) = shift; $dbpkg ||= $self->_loaddbbackend; $dbpkg->setup; } sub listdb { my ($self) = shift; $dbpkg ||= $self->_loaddbbackend; $dbpkg->list; } sub tablesdb { my ($self) = shift; $dbpkg ||= $self->_loaddbbackend; $dbpkg->get_tables; } sub cleardb { my ($self) = shift; $dbpkg ||= $self->_loaddbbackend; $self->resetdbcache; $dbpkg->clear; } sub createdb { my ($self, $dbname) = @_; $dbpkg ||= $self->_loaddbbackend; Carp::confess("DB backend setup failed") unless $dbpkg; $self->resetdbcache; $dbpkg->create($dbname); } sub driverdb { my ($self) = shift; $dbpkg ||= $self->_loaddbbackend; $dbpkg->type; } sub isql { my ($self) = shift; $dbpkg ||= $self->_loaddbbackend; $dbpkg->isql(@_); } sub get_sequence { my ($self) = shift; warn("=> GET-SEQUENCE ", $_[0], "\n") if $trace; $self->connectdb; Carp::confess("DB backend setup failed") unless $dbpkg; Carp::croak("INTERNAL ERROR: get_sequence takes only one argument") if @_ != 1; $dbpkg->get_sequence(@_); } sub set_sequence { my ($self) = shift; warn("=> SET-SEQUENCE ", $_[0], " TO ", $_[1], "\n") if $trace; $self->connectdb; Carp::confess("DB backend setup failed") unless $dbpkg; $dbpkg->set_sequence(@_); } sub store_attachment { my ($self) = shift; warn("=> STORE-ATTACHMENT ", $_[0], "\n") if $trace; $self->connectdb; Carp::confess("DB backend setup failed") unless $dbpkg; Carp::croak("INTERNAL ERROR: store_attachment takes one argument") if @_ != 1; $dbpkg->store_attachment(@_); } sub get_attachment { my ($self) = shift; warn("=> GET-ATTACHMENT ", $_[0], "\n") if $trace; $self->connectdb; Carp::confess("DB backend setup failed") unless $dbpkg; Carp::croak("INTERNAL ERROR: get_attachment takes one or two arguments") if @_ < 1 || @_ > 2; $dbpkg->get_attachment(@_); } sub drop_attachment { my ($self) = shift; warn("=> DROP-ATTACHMENT ", $_[0], "\n") if $trace; $self->connectdb; Carp::confess("DB backend setup failed") unless $dbpkg; Carp::croak("INTERNAL ERROR: get_attachment takes only one argument") if @_ != 1; $dbpkg->drop_attachment(@_); } sub _loaddbbackend { my ($self) = @_; my $dbtype = $cfg->val(qw(database driver), "sqlite"); # Trim whitespace for stupid users. for ( $dbtype ) { s/^\s+//; s/\s+$//; } my $pkg = __PACKAGE__ . "::" . ucfirst(lc($dbtype)); my $pkgfile = __PACKAGE__ . "::" . ucfirst(lc($dbtype)) . ".pm"; $pkgfile =~ s/::/\//g; eval { require $pkgfile }; die("?".__x("Geen ondersteuning voor database type {db}", db => $dbtype)."\n$@") if $@; #Carp::cluck("Returning: $pkg"); return $pkg; } ################ End API calls for database backend ################ sub trace { my ($self, $value) = @_; my $cur = $trace; $trace = !$trace, return $cur unless defined $value; $trace = $value; $cur; } sub sql_insert { my ($self, $table, $columns, @args) = @_; $self->sql_exec("INSERT INTO $table ". "(" . join(",", @$columns) . ") ". "VALUES (" . join(",", ("?") x @$columns) . ")", @args); } my %sth; my $sql_prep_cache_hits; my $sql_prep_cache_miss; sub sql_prep { my ($self, $sql) = @_; $dbh ||= $self->connectdb(); $sql = $self->feature("filter")->($sql) if $self->feature("filter"); return $dbh->prepare($sql) unless $self->feature("prepcache"); if ( defined($sth{$sql}) ) { $sql_prep_cache_hits++; return $sth{$sql}; } $sql_prep_cache_miss++; $sth{$sql} = $dbh->prepare($sql); } sub prepstats { warn("SQL Prep Cache: number of hits = ", $sql_prep_cache_hits || 0, ", misses = ", $sql_prep_cache_miss || 0, "\n") if %sth && $cfg->val("internal sql", qw(prepstats), 0); } sub resetdbcache { my ($self) = @_; %sth = (); return unless $self; $self->std_acc(""); $self->adm(""); } sub show_sql($$@) { my ($self, $sql, @args) = @_; my @a = map { !defined($_) ? "NULL" : /^[0-9]+$/ ? $_ : $dbh->quote($_) } @args; $sql =~ s/\?/shift(@a)/eg; warn("=> $sql;\n"); } sub sql_exec { my ($self, $sql, @args) = @_; $dbh ||= $self->connectdb(); $self->show_sql($sql, @args) if $trace; checktx($sql); my $sth = $self->sql_prep($sql); $sth->execute(@args); $sth; } sub lookup($$$$$;$) { my ($self, $value, $table, $arg, $res, $op) = @_; $op ||= "="; my $sth = $self->sql_exec("SELECT $res FROM $table". " WHERE $arg $op ?", $value); my $rr = $sth->fetchrow_arrayref; $sth->finish; return ($rr && defined($rr->[0]) ? $rr->[0] : undef); } sub get_value { my ($self, $column, $table) = @_; my $sth = $self->sql_exec("SELECT $column FROM $table"); my $rr = $sth->fetchrow_arrayref; $sth->finish; return ($rr && defined($rr->[0]) ? $rr->[0] : undef); } sub do { my $self = shift; my $sql = shift; my $atts = ref($_[0]) eq 'HASH' ? shift : undef; my @args = @_; my $sth = $self->sql_exec($sql, @args); my $rr = $sth->fetchrow_arrayref; $sth->finish; $rr; } sub da { # do_all my $self = shift; my $sql = shift; my $atts = ref($_[0]) eq 'HASH' ? shift : undef; my @args = @_; my $sth = $self->sql_exec($sql, @args); my $res; while ( my $rr = $sth->fetchrow_arrayref ) { push( @$res, [@$rr] ); } $sth->finish; $res; } sub errstr { $dbh->errstr; } sub in_transaction { my $self = shift; $tx; } sub checktx { my ($sql, $allow) = @_; return if $tx; $sql =~ /^\s*(\w+)\s+(\S+)/i; my $cmd = $1 ? uc($1) : die("?INTERNAL ERROR: Invalid SQL command: $sql\n"); return if $cmd eq "SELECT"; my $msg = "INTERNAL ERROR: $cmd $2 while not in transaction"; $allow ? warn("!$msg\n") : die("?$msg\n"); } # # http://en.wikipedia.org/wiki/Database_transaction#In_SQL sub begin_work { my ($self) = @_; warn("=> BEGIN WORK;", $dbh ? "" : " (ignored)", "\n") if $trace; return unless $dbh; die("?INTERNAL ERROR: BEGIN WORK while in transaction\n") if $tx++; $dbh->begin_work; } sub commit { my ($self) = @_; warn("=> COMMIT WORK;", $dbh ? "" : " (ignored)", "\n") if $trace; return unless $dbh; die("?INTERNAL ERROR: COMMIT while not in transaction\n") unless $tx; $tx = 0; $dbh->commit; } sub rollback { my ($self) = @_; warn("=> ROLLBACK WORK;", $dbh ? "" : " (ignored)", "\n") if $trace; return unless $dbh; die("?INTERNAL ERROR: ROLLBACK while not in transaction\n") unless $tx; $tx = 0; $dbh->rollback } END { prepstats(); disconnectdb(); } 1; EekBoek-2.030.1/lib/EB/Shell/0000755000400000040000000000000013151742350013064 5ustar jvjvEekBoek-2.030.1/lib/EB/Shell/Base.pm0000644000400000040000000004177413044346163014314 0ustar jvjv#! perl package main; our $cfg; package EB::Shell::Base; # ---------------------------------------------------------------------- # Shell::Base - A generic class to build line-oriented command interpreters. # ---------------------------------------------------------------------- # Copyright (C) 2003 darren chamberlain # # This module is free software; you can redistribute it and/or # modify it under the same terms as Perl itself. # ---------------------------------------------------------------------- # # Modified for use by EekBoek by Johan Vromans. use strict; use EB; use Text::ParseWords qw(shellwords); # ---------------------------------------------------------------------- # new(\%args) # # Basic constructor. # # new() calls initialization methods: # # - init_rl # # o Initializes the Term::ReadLine instance # # - init_help # # o Initializes the list of help methods # # - init_completions # # o Initializes the list of tab-completable commands # # - init # # o Subclass-specific intializations. # # ---------------------------------------------------------------------- sub new { my $class = shift; $class = ref($class) || $class; # make it work with derived classes - jv my $args = UNIVERSAL::isa($_[0], 'HASH') ? shift : { @_ }; my $self = bless { COMPLETIONS => undef, # tab completion HELPS => undef, # help methods HISTFILE => undef, # history file PROMPT => "eb> ", # default prompt TERM => undef, # Term::ReadLine instance RL_DEBUG => $cfg->val(qw(readline debug), 0), } => $class; $self->init_cm($args); $self->init_rl($args); $self->init_completions($args); $self->init_help($args); $self->init($args); return $self; } # ---------------------------------------------------------------------- # init_km(\%args) # # Initialize command name maps for translation. # ---------------------------------------------------------------------- sub init_cm { my ($self, $args) = @_; # See EB::Utils for __XN, __xt and N__ . my %cm = map { __XN($_) => __xt($_) } # Opening. N__("cmd:adm_balans"), N__("cmd:adm_balanstotaal"), N__("cmd:adm_begindatum"), N__("cmd:adm_boekjaarcode"), N__("cmd:adm_btwperiode"), N__("cmd:adm_naam"), N__("cmd:adm_open"), N__("cmd:adm_relatie"), # Globale settings. N__("cmd:boekjaar"), # Rapporten. N__("cmd:balans"), N__("cmd:btwaangifte"), N__("cmd:crediteuren"), N__("cmd:debiteuren"), N__("cmd:grootboek"), N__("cmd:journaal"), N__("cmd:openstaand"), N__("cmd:proefensaldibalans"), N__("cmd:result"), # Informatie. N__("cmd:dagboeken"), N__("cmd:database"), N__("cmd:periodes"), N__("cmd:rapporten"), # Bewerkingen. N__("cmd:export"), N__("cmd:import"), N__("cmd:jaareinde"), N__("cmd:relatie"), N__("cmd:schema"), N__("cmd:toon"), N__("cmd:verwijder"), # Diversen. N__("cmd:include"), N__("cmd:sql"), ; $self->{cm} = \%cm; } # ---------------------------------------------------------------------- # init_rl(\%args) # # Initialize Term::ReadLine. Subclasses can override this method if # readline support is not needed or wanted. # ---------------------------------------------------------------------- sub init_rl { my ($self, $args) = @_; my ($term, $attr); $ENV{PERL_READLINE_NOWARN} = 1 unless $self->{RL_DEBUG}; require Term::ReadLine; warn("\%Trying: ReadLine (", $ENV{PERL_RL}||"default", ")\n") if $self->{RL_DEBUG}; $term = Term::ReadLine->new(ref $self); warn("\%Using: ", $term->ReadLine, "\n") if $self->{RL_DEBUG}; $self->term($term); # Setup default tab-completion function. # Note that this will be overridden by EB::Shell->new. $attr = $term->Attribs; $attr->{completion_function} = sub { $self->complete(@_) }; if (my $histfile = $args->{ HISTFILE }) { # Should use $term->Features->{addhistory} . $self->histfile($histfile); if ( $term->can("ReadHistory") ) { $term->ReadHistory($histfile); } elsif ( open( my $fd, '<:encoding(utf8)', $histfile ) ) { $self->{_history} = []; while ( <$fd> ) { chomp; $term->addhistory($_); push( @{ $self->{_history} }, $_, "\n" ); } close($fd); } } return $self; } # ---------------------------------------------------------------------- # init_help() # # Initializes the internal HELPS list, which is a list of all the # help_foo methods defined within the current class, and all the # classes from which the current class inherits from. # ---------------------------------------------------------------------- sub init_help { my $self = shift; my $class = ref $self || $self; my %uniq = (); no strict qw(refs); $self->helps( grep { ++$uniq{$_} == 1 } map { s/^help_//; $self->{cm}->{$_}||$_ } grep /^help_/, map({ %{"$_\::"} } @{"$class\::ISA"}), keys %{"$class\::"}); } sub _xtr { my ( $self, $t ) = @_; (my $pfx, $t) = ( $1, $2 ) if $t =~ /^(.*):(.*)/; keys( %{$self->{cm}} ); # reset iteration while ( my ($k, $v) = each %{$self->{cm}} ) { next unless $t eq $v; return $1 if $k =~ /^tg_(.*)/; return $k; } undef; } # ---------------------------------------------------------------------- # init_completions() # # Initializes the internal COMPLETIONS list, which is used by the # complete method, which is, in turn, used by Term::ReadLine to # do tab-compleion. # ---------------------------------------------------------------------- sub init_completions { my $self = shift; my $class = ref $self || $self; my %uniq = (); no strict qw(refs); $self->completions( sort "help", grep { ++$uniq{$_} == 1 } map { s/^(do|pp)_//; $self->{cm}->{$_}||$_ } grep /^(do|pp)_/, map({ %{"$_\::"} } @{"$class\::ISA"}), keys %{"$class\::"}); } # ---------------------------------------------------------------------- # init(\%args) # # Basic init method; subclasses can override this as needed. This is # the place to do any subclass-specific initialization. # # Command completion is initialized here, so subclasses should call # $self->SUPER::init(@_) within overridden init methods if they want # this completion to be setup. # ---------------------------------------------------------------------- sub init { my ($self, $args) = @_; return $self; } # ---------------------------------------------------------------------- # run() # # run is the main() of the interpreter. Its duties are: # # - Get a line of input, via $self->term->readline. # This begins the run loop. # # o Pass this line to $self->parseline for splitting into # (command_name, arguments) # # o Check contents of command_name; there are a few special # cases: # # + If the line is a help line, then call $self->help(@args) # # + If the line is a quit line, then return with $self->quit() # # + Otherwise, attempt to invoke $self->do_$command_name # # o The output from whichever of the above is chosen will be # be printed via $self->print() if defined. # # o The prompt is reset, and control returns to the top of # the run loop. # ---------------------------------------------------------------------- sub run { my $self = shift; my $prompt = $self->prompt; my $anyfail; while (defined (my $line = $self->readline($prompt))) { my (@args, $cmd, $output); ($cmd, @args) = $self->parseline($line); # If there's a quoting mistake, parseline returns nothing. if ( $line =~ /\S/ && $cmd !~ /\S/ ) { warn("?"._T("Fout in de invoerregel. Controleer de \" en ' tekens.")."\n"); next; } if (! length($cmd)) { next; } elsif ( $cmd =~ /^\s*(help|\?)/i ) { $output = $self->help(@args); } elsif ( $cmd =~ /^\s*(exit|quit|logout)/i ) { return $self->quit($anyfail?1:0); } else { my $meth = "pp_".lc($self->_xtr("cmd:$cmd")||$cmd); if ( $self->can($meth) ) { eval { ($cmd, @args) = $self->$meth($cmd, @args); }; if ($@) { my $err = $@; chomp $err; warn "?$err\n"; next; } } $meth = "do_".lc($self->_xtr("cmd:".lc($cmd))||$cmd); $meth =~ s/\s+/_/g; if ( $self->can($meth) ) { eval { # Check warnings for ? (errors). my $fail = 0; local $SIG{__WARN__} = sub { $fail++ if $_[0] =~ /^\?/; warn(@_); }; $output = $self->$meth(@args); # Throw error if errors detected. die(bless {}, 'FatalError') if $fail && $self->{errexit}; }; if ( !$@ && $self->{errexit} && $output =~ /^\?/m ) { eval { die($output) }; } if ($@) { $anyfail++; unless ( UNIVERSAL::isa($@, 'FatalError') ) { my $err = $@; chomp $err; # jv warn "$output ($err)\n"; warn "?$err\n"; } if ( $self->{errexit} ) { warn("?"._T(" ****** Afgebroken wegens fouten in de invoer ******")."\n"); return $self->quit(1); } } } else { warn("?".__x("Onbekende opdracht \"{cmd}\".\n\"help\" geeft een lijst van mogelijke opdrachten.", cmd => $cmd)."\n"); undef($output); return $self->quit(1) if $self->{errexit}; } } # Suppress the newline if there's nothing to print. if ( defined $output ) { $output =~ s/\n*$//; chomp $output; $self->print("$output\n") if $output; } # Make sure we're not in a pending transaction. if ( $::dbh->in_transaction ) { warn("?INTERNAL ERROR: Command failed but did not rollback.\n") unless $cfg->val( qw(internal transdbg), 0 );; $::dbh->rollback; } # In case someone modified the prompt, we recollect it before # displaying it. $prompt = $self->prompt(); } $self->quit($anyfail?1:0); } # ---------------------------------------------------------------------- # readline() # # Calls readline on the internal Term::ReadLine instance. Provided # as a separate method within Shell::Base so that subclasses which # do not want to use Term::ReadLine don't have to. # ---------------------------------------------------------------------- sub __orig_readline { my ($self, $prompt) = @_; return $self->term->readline($prompt); } sub readline { my ($self, $prompt) = @_; my $line = $self->term->readline($prompt); push( @{ $self->{_history} }, $line."\n" ) if $line =~ /\S/; return $line; } # ---------------------------------------------------------------------- # print(@data) # # This method is here to that subclasses can redirect their output # stream without having to do silly things like tie STDOUT (although # they still can if they want, by overriding this method). # ---------------------------------------------------------------------- sub __orig_print { my ($self, @stuff) = @_; my $OUT = $self->term->Attribs->{'outstream'}; $OUT ||= *STDOUT; CORE::print $OUT @stuff; } sub print { my ($self, @stuff) = @_; CORE::print STDOUT @stuff; } # ---------------------------------------------------------------------- # quit([$status]) # # Exits the interpreter with $status as the exit status (0 by default). # ---------------------------------------------------------------------- sub quit { my ($self, $status) = @_; $status = 0 unless defined $status; if (my $h = $self->histfile) { # XXX Can this be better encapsulated? if ( $self->term->can("WriteHistory") ) { $self->term->WriteHistory($h); } elsif ( open( my $fd, '>:encoding(utf8)', $h ) ) { print { $fd } @{ $self->{_history} }; close($fd); } } return $status; } # ---------------------------------------------------------------------- # do_version() # # Show version. # ---------------------------------------------------------------------- sub do_version { my $self = shift; return $EB::ident; } sub help_version { return _T("Toon versie."); } # ---------------------------------------------------------------------- # parseline($line) # # parseline splits a line into three components: # # 1. Command # # 3. Arguments # # returns an array that looks like: # # ($cmd, @args) # # This parseline method doesn't handle pipelines gracefully; pipes # ill treated like any other token. # ---------------------------------------------------------------------- sub parseline { my ($self, $line) = @_; my ($cmd, @args); @args = shellwords($line); while (@args) { $cmd = shift @args; last; } return (($cmd or ""), @args); } # ---------------------------------------------------------------------- # term() # # Returns the Term::ReadLine instance. Useful if the subclass needs # do something like modify attributes on the instance. # ---------------------------------------------------------------------- sub term { my $self = shift; $self->{ TERM } = shift if (@_); return $self->{ TERM }; } # ---------------------------------------------------------------------- # histfile([$histfile]) # # Gets/set the history file. # ---------------------------------------------------------------------- sub histfile { my $self = shift; $self->{ HISTFILE } = shift if (@_); return $self->{ HISTFILE }; } # ---------------------------------------------------------------------- # prompt([$prompt[, @args]]) # # The prompt can be modified using this method. For example, multiline # commands (which much be handled by the subclass) might modify the # prompt, e.g., PS1 and PS2 in bash. If $prompt is a coderef, it is # executed with $self and @args: # # $self->{ PROMPT } = &$prompt($self, @args); # ---------------------------------------------------------------------- sub prompt { my $self = shift; if (@_) { my $p = shift; if (ref($p) eq 'CODE') { $self->{ PROMPT } = &$p($self, @_); } else { $self->{ PROMPT } = $p; } } return $self->{ PROMPT }; } # ---------------------------------------------------------------------- # help([$topic[, @args]]) # # Displays help. With $topic, it attempts to call $self->help_$topic, # which is expected to return a string. Without $topic, it lists the # available help topics, which is a list of methods that begin with # help_; these names are massaged with s/^help_// before being displayed. # ---------------------------------------------------------------------- sub help { my ($self, $topic, @args) = @_; my @ret; if ($topic) { if (my $sub = $self->can("help_". ($self->_xtr("cmd:".lc($topic))||lc($topic)))) { push @ret, $self->$sub(@_); push(@ret, _T("Opdrachtnamen zijn hoofdletterongevoelig.") ) unless $topic eq lc($topic); } else { push @ret, __x("Sorry, geen hulp voor {topic}.", topic => $topic); } } else { my @helps = $self->helps; if (@helps) { push( @ret, _T("Hulp is beschikbaar voor de volgende onderwerpen."), _T("Typ 'help [onderwerp]' voor meer gedetailleerde informatie."), _T("Opdrachtnamen zijn hoofdletterongevoelig.") ); my $t = "=" x max( length($ret[-1]), length($ret[-2]) ); push(@ret, $t, map({ " * $_" } sort @helps), $t); } else { push @ret, _T("Geen hulp beschikbaar."); } } return join "\n", @ret; } # ---------------------------------------------------------------------- # helps([@helps]) # # Returns or sets a list of possible help functions. # ---------------------------------------------------------------------- sub helps { my $self = shift; if (@_) { $self->{ HELPS } = \@_; } return @{ $self->{ HELPS } }; } # ---------------------------------------------------------------------- # complete(@_) # # Command completion -- this method is designed to be assigned as: # # $term->Attribs->{completion_function} = sub { $self->complete(@_) }; # # Note the silly setup -- it will be called as a function, without # any references to $self, so we need to force $self into the equation # using a closure. # ---------------------------------------------------------------------- sub complete { my ($self, $word, $line, $pos) = @_; #warn "Completing '$word' in '$line' (pos $pos)"; # This is grossly suboptimal, and only completes on # defined keywords. A better idea is to: # 1. If subtr($line, ' ') is less than $pos, # then we are completing a command # (the current method does this correctly) # 2. Otherwise, we are completing something else. # By default, this should defer to regular filename # completion. return grep { /$word/ } $self->completions; } sub completions { my $self = shift; if (@_) { $self->{ COMPLETIONS } = \@_; } return @{ $self->{ COMPLETIONS } }; } 1; # =head1 AUTHOR # # darren chamberlain Edarren@cpan.orgE # # Modified for EekBoek by Ejv@cpan.orgE # # =head1 COPYRIGHT # # Copyright (C) 2003 darren chamberlain. All Rights Reserved. # # This module is free software; you can redistribute it and/or # modify it under the same terms as Perl itself. EekBoek-2.030.1/lib/EB/Shell/DeLuxe.pm0000644000400000040000000001104212725476602014620 0ustar jvjv#! perl -- -*- coding: utf-8 -*- use utf8; # Author : Johan Vromans # Created On : Thu Jul 7 15:53:48 2005 # Last Modified By: Johan Vromans # Last Modified On: Sat Aug 25 22:48:50 2012 # Update Count : 294 # Status : Unknown, Use with caution! ################ Common stuff ################ ################ WARNING: This file crashes xgettext. # Translateable strings should be maintained in DeLuxe_Fake.pm as well. ################ package main; our $cfg; package EB::Shell::DeLuxe; use strict; use base qw(EB::Shell::Base); use EB; sub new { my $class = shift; $class = ref($class) || $class; my $opts = UNIVERSAL::isa($_[0], 'HASH') ? shift : { @_ }; $opts->{interactive} = 0 if $opts->{command}; $opts->{interactive} = -t unless defined $opts->{interactive}; unless ( $opts->{interactive} ) { no strict 'refs'; *{"init_rl"} = sub {}; *{"histfile"} = sub {}; *{"print"} = sub { shift; CORE::print @_ }; } else { no strict 'refs'; *{"init_rl"} = sub { shift->SUPER::init_rl(@_) }; *{"histfile"} = sub { shift->SUPER::histfile(@_) }; *{"print"} = sub { shift->SUPER::print(@_) }; } my $self = $class->SUPER::new($opts); $self->{$_} = $opts->{$_} foreach keys(%$opts); if ( $opts->{command} ) { $self->{readline} = \&readline_command; } elsif ( $opts->{interactive} ) { $self->{readline} = \&readline_interactive; } else { $self->{readline} = sub { $self->readline_file(sub { }) }; } $self->{inputstack} = []; $self->{errexit} = -t STDIN ? 0 : $opts->{errexit}; $self; } sub readline_interactive { my ($self, $prompt) = @_; return $self->SUPER::readline($prompt); } use Encode; sub readline_file { my ($self, $rl) = @_; my $line; my $pre = ""; while ( 1 ) { $line = $rl->(); unless ( $line ) { warn("?"._T("Vervolgregel ontbreekt in de invoer.")."\n") if $pre; return; } if ( $line =~ /^\# \s* content-type: \s* text (?: \s* \/ \s* plain)? \s* ; \s* charset \s* = \s* (\S+) \s* $/ix ) { my $charset = lc($1); if ( $charset =~ /^(?:utf-?8)$/i ) { next; } die("?"._T("Invoer moet Unicode (UTF-8) zijn.")."\n"); } =begin thismustbefixed if ( $self->{unicode} xor $cfg->unicode ) { my $s = $line; eval { if ( $cfg->unicode ) { $line = decode($self->{unicode} ? 'utf8' : 'latin1', $s, 1); } else { Encode::from_to($line, 'utf8', 'latin1', 1); } }; if ( $@ ) { warn("?".__x("Geen geldige {cs} tekens in regel {line} van de invoer", cs => $self->{unicode} ? "UTF-8" : "Latin1", line => $.)."\n".$line."\n"); next; } } =cut my $s = $line; my $t = "".$line; eval { $line = decode('utf8', $s, 1); }; if ( $@ ) { warn("?".__x("Geen geldige UTF-8 tekens in regel {line} van de invoer", line => $.)."\n".$t."\n"); next; } if ( $self->{echo} ) { my $pr = $self->{echo}; $pr =~ s/\>/>>/ if $pre; print($pr, $line); } unless ( $line =~ /\S/ ) { # Empty line will stop \ continuation. return $pre if $pre ne ""; next; } next if $line =~ /^\s*#/; $line =~ s/\s*[\r\n]+$//; # be forgiving $line =~ s/\s+#.+$//; warn("!".__x("Invoerregel {lno} bevat onzichtbare tekens na de backslash", lno => $.)."\n") # can't happen? if $line =~ /\\\s+$/; if ( $line =~ /(^.*)\\$/ ) { $line = $1; $line =~ s/\s+$/ /; $pre .= $line; next; } return $pre.$line; } } sub attach_file { my ($self, $file) = @_; push( @{ $self->{inputstack} }, [ $self->{readline} ] ); $self->{readline} = sub { shift->readline_file(sub { <$file> }) }; } sub attach_lines { my ($self, $lines) = @_; push( @{ $self->{inputstack} }, [ $self->{readline} ] ); my @lines = @$lines; $self->{readline} = sub { shift->readline_file(sub { shift(@lines); }) }; } sub readline_command { my ($self, $prompt) = @_; return undef unless @ARGV; return shift(@ARGV) if @ARGV == 1; my $line = ""; while ( @ARGV ) { my $word = shift(@ARGV); $word =~ s/('|\\)/\\$1/g; $line .= " " if $line ne ""; $line .= "'" . $word . "'"; } return $line; } sub readline { my ($self, $prompt) = @_; my $ret; while ( !defined($ret = $self->{readline}->($self, $prompt)) ) { return unless @{$self->{inputstack}}; ( $self->{readline} ) = @{pop(@{$self->{inputstack}})}; } # Command parsing gets stuck on leading blanks. $ret =~ s/^\s+//; $ret =~ s/\s+$//; return $ret; } 1; EekBoek-2.030.1/lib/EB/user/0000755000400000040000000000000013151742350012773 5ustar jvjvEekBoek-2.030.1/lib/EB/user/css/0000755000400000040000000000000013151742350013563 5ustar jvjvEekBoek-2.030.1/lib/EB/user/css/crdrept.css0000644000400000040000000000002612725476601015747 0ustar jvjv@import "debcrd.css"; EekBoek-2.030.1/lib/EB/user/css/debcrd.css0000644000400000040000000000377312725476602015544 0ustar jvjv/* $Id */ /* CSS for Debiteuren/Crediteuren reports */ @import eekboek.css; .title { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 100%; font-weight: bold; margin-top: 0pt; margin-bottom: 0pt; } .subtitle { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 100%; font-weight: bold; margin-top: 0pt; } .footer { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 80%; font-weight: normal; } body { font-family: Verdana, Arial, Helvetica, sans-serif; line-height: 150%; color: #000000; table-width: 100%; } /* Table and borders */ table { border: thin solid #000000; border-collapse: collapse; } table td { border-left: thin solid #000000; border-right: thin solid #000000; } table th { border-left: thin solid #000000; border-right: thin solid #000000; border-bottom: thin solid #000000; } /* By default, align rows at top */ th { vertical-align: top; } tr { vertical-align: top; } /* Row styles */ .r_total { padding-bottom: 10pt; font-weight: bold; border-bottom: thin solid #000000; } .r_bsk, .r_h1, .r_grand { font-weight: bold; } /* Column styles */ .c_debcrd, .h_debcrd { padding-left: 10pt; padding-right: 10pt; text-align: left; } .c_date, .h_date { padding-left: 10pt; padding-right: 10pt; text-align: left; } .c_desc, .h_desc { padding-left: 10pt; padding-right: 10pt; text-align: left; } .c_amount, .h_amount { padding-left: 10pt; padding-right: 10pt; text-align: right; } .c_open, .h_open { padding-left: 10pt; padding-right: 10pt; text-align: right; } .c_paid, .h_paid { padding-left: 10pt; padding-right: 10pt; text-align: right; } .c_bsknr, .h_bsknr { padding-left: 10pt; padding-right: 10pt; text-align: left; } /* Special style */ .r_paid .c_desc { text-indent: 1em; } .r_bskprv .c_date { color: #0000FF; } .r_bskprv .c_bsknr { color: #0000FF; } EekBoek-2.030.1/lib/EB/user/css/journaal.css0000644000400000040000000000410312725476602016120 0ustar jvjv/* $Id */ @import eekboek.css; .title { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 100%; font-weight: bold; margin-top: 0pt; margin-bottom: 0pt; } .subtitle { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 100%; font-weight: bold; margin-top: 0pt; } .footer { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 80%; font-weight: normal; } body { font-family: Verdana, Arial, Helvetica, sans-serif; line-height: 150%; color: #000000; table-width: 100%; } table { border: thin solid #000000; border-collapse: collapse; } table td { border-left: thin solid #000000; border-right: thin solid #000000; } table th { border-left: thin solid #000000; border-right: thin solid #000000; border-bottom: thin solid #000000; } th { vertical-align: top } tr { vertical-align: top } .r_head { color: #0000FF; border-top: thin solid #000000; } .r_chead { color: #0000FF; border-top: thin solid #000000; } .r_dhead { color: #0000FF; border-top: thin solid #000000; } .r_total { color: #FF0000; border-top: thin solid #000000; } .c_acct, .h_acct { padding-left: 10pt; padding-right: 10pt; text-align: left; } .c_date, .h_date { padding-left: 10pt; padding-right: 10pt; text-align: left; } .c_bsk, .h_bsk { padding-left: 10pt; padding-right: 10pt; text-align: left; } .c_desc, .h_desc { padding-left: 10pt; padding-right: 10pt; text-align: left; } .r_data .c_desc, .r_data .c_bsk { padding-left: 20pt; } .r_cdata .c_desc, .r_cdata .c_bsk { padding-left: 20pt; } .r_ddata .c_desc, .r_ddata .c_bsk { padding-left: 20pt; } .c_bsk, .h_bsk { padding-left: 10pt; padding-right: 10pt; text-align: left; } .c_rel, .h_rel { padding-left: 10pt; padding-right: 10pt; text-align: left; } .c_deb, .h_deb { padding-left: 10pt; padding-right: 10pt; text-align: right; } .c_crd, .h_crd { padding-left: 10pt; padding-right: 10pt; text-align: right; } EekBoek-2.030.1/lib/EB/user/css/openstaand.css0000644000400000040000000000341612725476601016446 0ustar jvjv/* $Id */ @import eekboek.css; .title { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 100%; font-weight: bold; margin-top: 0pt; margin-bottom: 0pt; } .subtitle { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 100%; font-weight: bold; margin-top: 0pt; } .footer { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 80%; font-weight: normal; } body { font-family: Verdana, Arial, Helvetica, sans-serif; line-height: 150%; color: #000000; table-width: 100%; } table { border: thin solid #000000; border-collapse: collapse; } table td { border-left: thin solid #000000; border-right: thin solid #000000; } table th { border-left: thin solid #000000; border-right: thin solid #000000; border-bottom: thin solid #000000; } th { vertical-align: top } tr { vertical-align: top } .r_trelatie { font-weight: bold; } .r_tdebcrd { border-top: thin solid #000000; color: #FF0000; border-bottom: thin solid #000000; } .c_date, .h_date { padding-left: 10pt; padding-right: 10pt; text-align: left; } .c_bsk, .h_bsk { padding-left: 10pt; padding-right: 10pt; text-align: left; } .c_desc, .h_desc { padding-left: 10pt; padding-right: 10pt; text-align: left; } .c_rel, .h_rel { padding-left: 10pt; padding-right: 10pt; text-align: left; } .c_amt, .h_amt { padding-left: 10pt; padding-right: 10pt; text-align: right; } .r_trelatie .c_desc { border-bottom: thin solid #000000; } .r_trelatie .c_bsk { border-bottom: thin solid #000000; } .r_trelatie .c_amt { border-bottom: thin solid #000000; } .r_prevdata .c_date { color: #0000FF; } .r_prevdata .c_bsk { color: #0000FF; } EekBoek-2.030.1/lib/EB/user/css/btwaangifte.css0000644000400000040000000000257212725476602016610 0ustar jvjv/* btwaangifte.css -- stylesheet for BTW aangifte report * Author : Johan Vromans * Created On : Sat Oct 8 14:45:33 2005 * Last Modified By: Johan Vromans * Last Modified On: Mon Jun 14 22:06:06 2010 * Update Count : 12 * Status : Unknown, Use with caution! */ @import eekboek.css; .title { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 100%; font-weight: bold; margin-top: 0pt; margin-bottom: 0pt; } .subtitle { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 100%; font-weight: bold; margin-top: 0pt; } .footer { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 80%; font-weight: normal; } body { font-family: Verdana, Arial, Helvetica, sans-serif; line-height: 150%; color: #000000; table-width: 100%; } table { border-collapse: collapse; } th { vertical-align: top } tr { vertical-align: top } .heading { font-size: 120%; font-weight: bold; } .subheading { font-weight: bold; } .c_num { padding-left: 10pt; padding-right: 6pt; } .c_desc { padding-right: 10pt; } .c_col1 { padding-left: 10pt; padding-right: 10pt; text-align: right; } .c_col2 { padding-left: 10pt; padding-right: 10pt; text-align: right; } .notice { font-size: 100%; font-weight: bold; color: #ff0000; } EekBoek-2.030.1/lib/EB/user/css/result.css0000644000400000040000000000002612725476602015623 0ustar jvjv@import "balres.css"; EekBoek-2.030.1/lib/EB/user/css/balans.css0000644000400000040000000000002612725476601015544 0ustar jvjv@import "balres.css"; EekBoek-2.030.1/lib/EB/user/css/balres.css0000644000400000040000000000313312725476602015557 0ustar jvjv/* $Id */ @import eekboek.css; .title { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 100%; font-weight: bold; margin-top: 0pt; margin-bottom: 0pt; } .subtitle { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 100%; font-weight: bold; margin-top: 0pt; } .footer { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 80%; font-weight: normal; } body { font-family: Verdana, Arial, Helvetica, sans-serif; line-height: 150%; color: #000000; table-width: 100%; } table { border: thin solid #000000; border-collapse: collapse; } table td { border-left: thin solid #000000; border-right: thin solid #000000; } table th { border-left: thin solid #000000; border-right: thin solid #000000; border-bottom: thin solid #000000; } th { vertical-align: top } tr { vertical-align: top } .r_h1 { color: #0000FF; border-top: thin solid #000000; } .r_h2 { color: #0000FF; } .r_v { color: #FF0000; border-top: thin solid #000000; } .r_grand { border-top: thin solid #000000; } .c_acct, .h_acct { padding-left: 10pt; padding-right: 10pt; text-align: left; } .c_desc, .h_desc { padding-left: 10pt; padding-right: 10pt; text-align: left; } .c_deb, .h_deb { padding-left: 10pt; padding-right: 10pt; text-align: right; } .c_crd, .h_crd { padding-left: 10pt; padding-right: 10pt; text-align: right; } .r_h2 .c_desc { padding-left: 20pt; } .r_t2 .c_desc { padding-left: 20pt; } .r_d2 .c_desc { padding-left: 30pt; } EekBoek-2.030.1/lib/EB/user/css/debrept.css0000644000400000040000000000002612725476602015732 0ustar jvjv@import "debcrd.css"; EekBoek-2.030.1/lib/EB/user/css/grootboek.css0000644000400000040000000000415412725476602016306 0ustar jvjv/* $Id */ @import eekboek.css; .title { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 100%; font-weight: bold; margin-bottom: 0pt; } .subtitle { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 100%; font-weight: bold; margin-top: 0pt; } .footer { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 80%; font-weight: normal; } body { font-family: Verdana, Arial, Helvetica, sans-serif; line-height: 150%; color: #000000; table-width: 100%; } table { border: thin solid #000000; border-collapse: collapse; } table td { border-left: thin solid #000000; border-right: thin solid #000000; } table th { border-left: thin solid #000000; border-right: thin solid #000000; border-bottom: thin solid #000000; } th { vertical-align: top } tr { vertical-align: top } .r_hd { color: #0000FF; border-top: thin solid #000000; } .r_tm, .r_mut { border-top: thin solid #000000; } .r_h1 { color: #0000FF; border-top: thin solid #000000; } .r_tg { color: #FF0000; border-top: thin solid #000000; } .c_acct, .h_acct { padding-left: 10pt; padding-right: 10pt; text-align: left; } .c_date, .h_date { padding-left: 10pt; padding-right: 10pt; text-align: left; } .c_bsk, .h_bsk { padding-left: 10pt; padding-right: 10pt; text-align: left; } .c_desc, .h_desc { padding-left: 10pt; padding-right: 10pt; text-align: left; } .r_d .c_desc { padding-left: 30pt; padding-right: 10pt; text-align: left; } .r_h2 .c_desc { padding-left: 20pt; padding-right: 10pt; text-align: left; } .r_t2 .c_desc { padding-left: 20pt; padding-right: 10pt; text-align: left; } .c_bsr, .h_bsr { padding-left: 10pt; padding-right: 10pt; text-align: left; } .c_rel, .h_rel { padding-left: 10pt; padding-right: 10pt; text-align: left; } .c_deb, .h_deb { padding-left: 10pt; padding-right: 10pt; text-align: right; } .c_crd, .h_crd { padding-left: 10pt; padding-right: 10pt; text-align: right; } EekBoek-2.030.1/lib/EB/user/css/eekboek.css0000644000400000040000000000114712725476602015717 0ustar jvjv/* eekboek.css -- common stylesheet for reports * Author : Johan Vromans * Created On : Sat Oct 8 14:45:33 2005 * Last Modified By: Johan Vromans * Last Modified On: Sat Mar 19 22:24:43 2011 * Update Count : 12 * Status : Unknown, Use with caution! */ body { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 12px; } th { vertical-align: top } tr { vertical-align: top } tr:nth-child(2n) { background-color: #ddd; } .i_row { } .i_cell { padding-left: 10pt; padding-right: 10pt; text-align: left; padding-top: 6px; padding-bottom: 6px; } EekBoek-2.030.1/lib/EB/user/css/proef.css0000644000400000040000000000032212725476602015417 0ustar jvjv@import "balres.css"; .c_sdeb, .h_sdeb { padding-left: 10pt; padding-right: 10pt; text-align: right; } .c_scrd, .h_scrd { padding-left: 10pt; padding-right: 10pt; text-align: right; } EekBoek-2.030.1/lib/EB/CPAN/0000755000400000040000000000000013151742350012536 5ustar jvjvEekBoek-2.030.1/lib/EB/CPAN/Term/0000755000400000040000000000000013151742350013445 5ustar jvjvEekBoek-2.030.1/lib/EB/CPAN/Term/ReadLine/0000755000400000040000000000000013151742350015130 5ustar jvjvEekBoek-2.030.1/lib/EB/CPAN/Term/ReadLine/readline.pm0000755000400000040000000040456412725476602017303 0ustar jvjv## ## Perl Readline -- The Quick Help ## (see the manual for complete info) ## ## Once this package is included (require'd), you can then call ## $text = &readline'readline($input); ## to get lines of input from the user. ## ## Normally, it reads ~/.inputrc when loaded... to suppress this, set ## $readline'rl_NoInitFromFile = 1; ## before requiring the package. ## ## Call rl_bind to add your own key bindings, as in ## &readline'rl_bind('C-L', 'possible-completions'); ## ## Call rl_set to set mode variables yourself, as in ## &readline'rl_set('TcshCompleteMode', 'On'); ## ## To change the input mode (emacs or vi) use ~/.inputrc or call ## &readline::rl_set('EditingMode', 'vi'); ## or &readline::rl_set('EditingMode', 'emacs'); ## ## Call rl_basic_commands to set your own command completion, as in ## &readline'rl_basic_commands('print', 'list', 'quit', 'run', 'status'); ## ## # Wrap the code below (initially Perl4, now partially Perl4) into a fake # Perl5 pseudo-module; mismatch of package and file name is intentional # to make is harder to abuse this (very fragile) code... package readline; my $autoload_broken = 1; # currently: defined does not work with a-l my $useioctl = 1; my $usestty = 1; my $max_include_depth = 10; # follow $include's in init files this deep BEGIN { # Some old systems have ioctl "unsupported" *ioctl = sub ($$$) { eval { ioctl $_[0], $_[1], $_[2] } }; } ## ## BLURB: ## A pretty full-function package similar to GNU's readline. ## Includes support for EUC-encoded Japanese text. ## ## Written by Jeffrey Friedl, Omron Corporation (jfriedl@omron.co.jp) ## ## Comments, corrections welcome. ## ## Thanks to the people at FSF for readline (and the code I referenced ## while writing this), and for Roland Schemers whose line_edit.pl I used ## as an early basis for this. ## $VERSION = $VERSION = '1.0303'; ## - Changes from Slaven Rezic (slaven@rezic.de): ## * reverted the usage of $ENV{EDITOR} to set startup mode ## only ~/.inputrc or an explicit call to rl_set should ## be used to set startup mode ## # 1011109.011 - Changes from Russ Southern (russ@dvns.com): ## * Added $rl_vi_replace_default_on_insert # 1000510.010 - Changes from Joe Petolino (petolino@eng.sun.com), requested ## by Ilya: ## ## * Make it compatible with perl 5.003. ## * Rename getc() to getc_with_pending(). ## * Change unshift(@Pending) to push(@Pending). ## ## 991109.009 - Changes from Joe Petolino (petolino@eng.sun.com): ## Added vi mode. Also added a way to set the keymap default ## action for multi-character keymaps, so that a 2-character ## sequence (e.g. A) can be treated as two one-character ## commands (, then A) if the sequence is not explicitly ## mapped. ## ## Changed subs: ## ## * preinit(): Initialize new keymaps and other data structures. ## Use $ENV{EDITOR} to set startup mode. ## ## * init(): Sets the global *KeyMap, since &F_ReReadInitFile ## may have changed the key map. ## ## * InitKeymap(): $KeyMap{default} is now optional - don't ## set it if $_[1] eq ''; ## ## * actually_do_binding(): Set $KeyMap{default} for '\*' key; ## warning if double-defined. ## ## * rl_bind(): Implement \* to set the keymap default. Also fix ## some existing regex bugs that I happened to notice. ## ## * readline(): No longer takes input from $pending before ## calling &$rl_getc(); instead, it calls getc_with_pending(), ## which takes input from the new array @Pending ## before calling &$rl_getc(). Sets the global ## *KeyMap after do_command(), since do_command() ## may change the keymap now. Does some cursor ## manipulation after do_command() when at the end ## of the line in vi command mode, to match the ## behavior of vi. ## ## * rl_getc(): Added a my declaration for $key, which was ## apparently omitted by the author. rl_getc() is ## no longer called directly; instead, getc_with_pending() calls ## it only after exhausting any requeued characters ## in @Pending. @Pending is used to implement the ## vi '.' command, as well as the emacs DoSearch ## functionality. ## ## * do_command(): Now defaults the command to 'F_Ding' if ## $KeyMap{default} is undefined. This is part ## of the new \* feature. ## ## * savestate()/getstate(): Now use an anonymous array instead ## of packing the fields into a string. ## ## * F_AcceptLine(): Code moved to new sub add_line_to_history(), ## so that it may be called by F_SaveLine() ## as well as by F_AcceptLine(). ## ## * F_QuotedInsert(): Calls getc_with_pending() instead of &$rl_getc(). ## ## * F_UnixWordRubout(): Fixed bug: changed 'my' declaration of ## global $rl_basic_word_break_characters to 'local'. ## ## * DoSearch(): Calls getc_with_pending() instead of &$rl_getc(). Ungets ## character onto @Pending instead of $pending. ## ## * F_EmacsEditingMode(): Resets global $Vi_mode; ## ## * F_ToggleEditingMode(): Deleted. We use F_ViInput() and ## F_EmacsEditingMode() instead. ## ## * F_PrefixMeta(): Calls getc_with_pending() instead of &$rl_getc(). ## ## * F_DigitArgument(): Calls getc_with_pending() instead of &$rl_getc(). ## ## * F_Ding(): Returns undef, for testing by vi commands. ## ## * F_Complete(): Returns true if a completion was done, false ## otherwise, so vi completion routines can test it. ## ## * complete_internal(): Returns true if a completion was done, ## false otherwise, so vi completion routines can ## test it. Does a little cursor massaging in vi ## mode, to match the behavior of ksh vi mode. ## ## Disclaimer: the original code dates from the perl 4 days, and ## isn't very pretty by today's standards (for example, ## extensive use of typeglobs and localized globals). In the ## interests of not breaking anything, I've tried to preserve ## the old code as much as possible, and I've avoided making ## major stylistic changes. Since I'm not a regular emacs user, ## I haven't done much testing to see that all the emacs-mode ## features still work. ## ## 940817.008 - Added $var_CompleteAddsuffix. ## Now recognizes window-change signals (at least on BSD). ## Various typos and bug fixes. ## Changes from Chris Arthur (csa@halcyon.com): ## Added a few new keybindings. ## Various typos and bug fixes. ## Support for use from a dumb terminal. ## Pretty-printing of filename-completion matches. ## ## 930306.007 - Added rl_start_default_at_beginning. ## Added optional message arg to &redisplay. ## Added explicit numeric argument var to functions that use it. ## Redid many commands to simplify. ## Added TransposeChars, UpcaseWord, CapitalizeWord, DownCaseWord. ## Redid key binding specs to better match GNU.. added ## undocumented "new-style" bindings.... can now bind ## arrow keys and other arbitrairly long key sequences. ## Added if/else/then to .inputrc. ## ## 930305.006 - optional "default" added (from mmuegel@cssmp.corp.mot.com). ## ## 930211.005 - fixed strange problem with eval while keybinding ## ## ## Ilya: ## ## Added support for ReadKey, ## ## Added customization variable $minlength ## to denote minimal lenth of a string to be put into history buffer. ## ## Added support for a bug in debugger: preinit cannot be a subroutine ?!!! ## (See immendiately below) ## ## Added support for WINCH hooks. The subroutine references should be put into ## @winchhooks. ## ## Added F_ToggleInsertMode, F_HistorySearchBackward, ## F_HistorySearchForward, PC keyboard bindings. ## 0.93: Updates to Operate, couple of keybindings added. ## $rl_completer_terminator_character, $rl_correct_sw added. ## Reload-init-file moved to C-x C-x. ## C-x ? and C-x * list/insert possible completions. $rl_getc = \&rl_getc; &preinit; &init; # # # # use strict 'vars'; # # # # # Separation into my and vars needs some thought... # # # # use vars qw(@KeyMap %KeyMap $rl_screen_width $rl_start_default_at_beginning # # # # $rl_completion_function $rl_basic_word_break_characters # # # # $rl_completer_word_break_characters $rl_special_prefixes # # # # $rl_readline_name @rl_History $rl_MaxHistorySize # # # # $rl_max_numeric_arg $rl_OperateCount # # # # $KillBuffer $dumb_term $stdin_not_tty $InsertMode # # # # $rl_NoInitFromFile); # # # # my ($InputLocMsg, $term_OUT, $term_IN); # # # # my ($winsz_t, $TIOCGWINSZ, $winsz, $rl_margin, $hooj, $force_redraw); # # # # my ($hook, %var_HorizontalScrollMode, %var_EditingMode, %var_OutputMeta); # # # # my ($var_HorizontalScrollMode, $var_EditingMode, $var_OutputMeta); # # # # my (%var_ConvertMeta, $var_ConvertMeta, %var_MarkModifiedLines, $var_MarkModifiedLines); # # # # my ($term_readkey, $inDOS); # # # # my (%var_PreferVisibleBell, $var_PreferVisibleBell); # # # # my (%var_TcshCompleteMode, $var_TcshCompleteMode); # # # # my (%var_CompleteAddsuffix, $var_CompleteAddsuffix); # # # # my ($minlength, @winchhooks); # # # # my ($BRKINT, $ECHO, $FIONREAD, $ICANON, $ICRNL, $IGNBRK, $IGNCR, $INLCR, # # # # $ISIG, $ISTRIP, $NCCS, $OPOST, $RAW, $TCGETS, $TCOON, $TCSETS, $TCXONC, # # # # $TERMIOS_CFLAG, $TERMIOS_IFLAG, $TERMIOS_LFLAG, $TERMIOS_NORMAL_IOFF, # # # # $TERMIOS_NORMAL_ION, $TERMIOS_NORMAL_LOFF, $TERMIOS_NORMAL_LON, # # # # $TERMIOS_NORMAL_OOFF, $TERMIOS_NORMAL_OON, $TERMIOS_OFLAG, # # # # $TERMIOS_READLINE_IOFF, $TERMIOS_READLINE_ION, $TERMIOS_READLINE_LOFF, # # # # $TERMIOS_READLINE_LON, $TERMIOS_READLINE_OOFF, $TERMIOS_READLINE_OON, # # # # $TERMIOS_VMIN, $TERMIOS_VTIME, $TIOCGETP, $TIOCGWINSZ, $TIOCSETP, # # # # $fion, $fionread_t, $mode, $sgttyb_t, # # # # $termios, $termios_t, $winsz, $winsz_t); # # # # my ($line, $initialized, $term_readkey); # # # # # Global variables added for vi mode (I'm leaving them all commented # # # # # out, like the declarations above, until SelfLoader issues # # # # # are resolved). # # # # # True when we're in one of the vi modes. # # # # my $Vi_mode; # # # # # Array refs: saves keystrokes for '.' command. Undefined when we're # # # # # not doing a '.'-able command. # # # # my $Dot_buf; # Working buffer # # # # my $Last_vi_command; # Gets $Dot_buf when a command is parsed # # # # # These hold state for vi 'u' and 'U'. # # # # my($Dot_state, $Vi_undo_state, $Vi_undo_all_state); # # # # # Refs to hashes used for cursor movement # # # # my($Vi_delete_patterns, $Vi_move_patterns, # # # # $Vi_change_patterns, $Vi_yank_patterns); # # # # # Array ref: holds parameters from the last [fFtT] command, for ';' # # # # # and ','. # # # # my $Last_findchar; # # # # # Globals for history search commands (/, ?, n, N) # # # # my $Vi_search_re; # Regular expression (compiled by qr{}) # # # # my $Vi_search_reverse; # True for '?' search, false for '/' ## ## What's Cool ## ---------------------------------------------------------------------- ## * hey, it's in perl. ## * Pretty full GNU readline like library... ## * support for ~/.inputrc ## * horizontal scrolling ## * command/file completion ## * rebinding ## * history (with search) ## * undo ## * numeric prefixes ## * supports multi-byte characters (at least for the Japanese I use). ## * Has a tcsh-like completion-function mode. ## call &readline'rl_set('tcsh-complete-mode', 'On') to turn on. ## ## ## What's not Cool ## ---------------------------------------------------------------------- ## Can you say HUGE? ## I can't spell, so comments riddled with misspellings. ## Written by someone that has never really used readline. ## History mechanism is slightly different than GNU... may get fixed ## someday, but I like it as it is now... ## Killbuffer not a ring.. just one level. ## Obviously not well tested yet. ## Written by someone that doesn't have a bell on his terminal, so ## proper readline use of the bell may not be here. ## ## ## Functions beginning with F_ are functions that are mapped to keys. ## Variables and functions beginning rl_ may be accessed/set/called/read ## from outside the package. Other things are internal. ## ## Some notable internal-only variables of global proportions: ## $prompt -- line prompt (passed from user) ## $line -- the line being input ## $D -- ``Dot'' -- index into $line of the cursor's location. ## $InsertMode -- usually true. False means overwrite mode. ## $InputLocMsg -- string for error messages, such as "[~/.inputrc line 2]" ## *emacs_keymap -- keymap for emacs-mode bindings: ## @emacs_keymap - bindings indexed by ASCII ordinal ## $emacs_keymap{'name'} = "emacs_keymap" ## $emacs_keymap{'default'} = "SelfInsert" (default binding) ## *vi_keymap -- keymap for vi input mode bindings ## *vicmd_keymap -- keymap for vi command mode bindings ## *vipos_keymap -- keymap for vi positioning command bindings ## *visearch_keymap -- keymap for vi search pattern input mode bindings ## *KeyMap -- current keymap in effect. ## $LastCommandKilledText -- needed so that subsequent kills accumulate ## $lastcommand -- name of command previously run ## $lastredisplay -- text placed upon screen during previous &redisplay ## $si -- ``screen index''; index into $line of leftmost char &redisplay'ed ## $force_redraw -- if set to true, causes &redisplay to be verbose. ## $AcceptLine -- when set, its value is returned from &readline. ## $ReturnEOF -- unless this also set, in which case undef is returned. ## @Pending -- characters to be used as input. ## @undo -- array holding all states of current line, for undoing. ## $KillBuffer -- top of kill ring (well, don't have a kill ring yet) ## @tcsh_complete_selections -- for tcsh mode, possible selections ## ## Some internal variables modified by &rl_set (see comment at &rl_set for ## info about how these set'able variables work) ## $var_EditingMode -- a keymap typeglob like *emacs_keymap or *vi_keymap ## $var_TcshCompleteMode -- if true, the completion function works like ## in tcsh. That is, the first time you try to complete something, ## the common prefix is completed for you. Subsequent completion tries ## (without other commands in between) cycles the command line through ## the various possibilities. If/when you get the one you want, just ## continue typing. ## Other $var_ things not supported yet. ## ## Some variables used internally, but may be accessed from outside... ## $VERSION -- just for good looks. ## $rl_readline_name = name of program -- for .initrc if/endif stuff. ## $rl_NoInitFromFile -- if defined when package is require'd, ~/.inputrc ## will not be read. ## @rl_History -- array of previous lines input ## $rl_HistoryIndex -- history pointer (for moving about history array) ## $rl_completion_function -- see "How Command Completion Works" (way) below. ## $rl_basic_word_break_characters -- string of characters that can cause ## a word break for forward-word, etc. ## $rl_start_default_at_beginning -- ## Normally, the user's cursor starts at the end of any default text ## passed to readline. If this variable is true, it starts at the ## beginning. ## $rl_completer_word_break_characters -- ## like $rl_basic_word_break_characters (and in fact defaults to it), ## but for the completion function. ## $rl_completer_terminator_character -- what to insert to separate ## a completed token from the rest. Reset at beginning of ## completion to ' ' so completion function can change it. ## $rl_special_prefixes -- characters that are part of this string as well ## as of $rl_completer_word_break_characters cause a word break for the ## completer function, but remain part of the word. An example: consider ## when the input might be perl code, and one wants to be able to ## complete on variable and function names, yet still have the '$', ## '&', '@',etc. part of the $text to be completed. Then set this var ## to '&@$%' and make sure each of these characters is in ## $rl_completer_word_break_characters as well.... ## $rl_MaxHistorySize -- maximum size that the history array may grow. ## $rl_screen_width -- width readline thinks it can use on the screen. ## $rl_correct_sw -- is substructed from the real width of the terminal ## $rl_margin -- scroll by moving to within this far from a margin. ## $rl_CLEAR -- what to output to clear the screen. ## $rl_max_numeric_arg -- maximum numeric arg allowed. ## $rl_vi_replace_default_on_insert ## Normally, the text you enter is added to any default text passed to ## readline. If this variable is true, default text will start out ## highlighted (if supported by your terminal) and text entered while the ## default is highlighted (during the _first_ insert mode only) will ## replace the entire default line. Once you have left insert mode (hit ## escape), everything works as normal. ## - This is similar to many GUI controls' behavior, which select the ## default text so that new text replaces the old. ## - Use with $rl_start_default_at_beginning for normal-looking behavior ## (though it works just fine without it). ## Notes/Bugs: ## - Control characters (like C-w) do not actually terminate this replace ## mode, for the same reason it does not work in emacs mode. ## - Spine-crawlingly scary subroutine redefinitions ## $rl_mark - start of the region ## $line_rl_mark - the line on which $rl_mark is active ## $_rl_japanese_mb - For character movement suppose Japanese (which?!) ## multi-byte encoding. (How to make a sane default?) ## sub get_window_size { my $sig = shift; local($., $@, $!, $^E, $?); # Preserve $! etc; the rest for hooks my ($num_cols,$num_rows); if (defined $term_readkey) { ($num_cols,$num_rows) = Term::ReadKey::GetTerminalSize($term_OUT); $rl_screen_width = $num_cols - $rl_correct_sw if defined($num_cols) && $num_cols; } elsif (defined $TIOCGWINSZ and &ioctl($term_IN,$TIOCGWINSZ,$winsz)) { ($num_rows,$num_cols) = unpack($winsz_t,$winsz); $rl_screen_width = $num_cols - $rl_correct_sw if defined($num_cols) && $num_cols; } $rl_margin = int($rl_screen_width/3); if (defined $sig) { $force_redraw = 1; &redisplay(); } for $hook (@winchhooks) { eval {&$hook()}; warn $@ if $@ and $^W; } local $^W = 0; # WINCH may be illegal... $SIG{'WINCH'} = "readline::get_window_size"; } # Fix: case-sensitivity of inputrc on/off keywords in # `set' commands. readline lib doesn't care about case. # changed case of keys 'On' and 'Off' to 'on' and 'off' # &rl_set changed so that it converts the value to # lower case before hash lookup. sub preinit { ## Set up the input and output handles $term_IN = \*STDIN unless defined $term_IN; $term_OUT = \*STDOUT unless defined $term_OUT; ## not yet supported... always on. $var_HorizontalScrollMode = 1; $var_HorizontalScrollMode{'On'} = 1; $var_HorizontalScrollMode{'Off'} = 0; $var_EditingMode{'emacs'} = *emacs_keymap; $var_EditingMode{'vi'} = *vi_keymap; $var_EditingMode{'vicmd'} = *vicmd_keymap; $var_EditingMode{'vipos'} = *vipos_keymap; $var_EditingMode{'visearch'} = *visearch_keymap; ## this is an addition. Very nice. $var_TcshCompleteMode = 0; $var_TcshCompleteMode{'On'} = 1; $var_TcshCompleteMode{'Off'} = 0; $var_CompleteAddsuffix = 1; $var_CompleteAddsuffix{'On'} = 1; $var_CompleteAddsuffix{'Off'} = 0; $var_DeleteSelection = $var_DeleteSelection{'On'} = 1; $var_DeleteSelection{'Off'} = 0; *rl_delete_selection = \$var_DeleteSelection; # Alias ## not yet supported... always on for ('InputMeta', 'OutputMeta') { ${"var_$_"} = 1; ${"var_$_"}{'Off'} = 0; ${"var_$_"}{'On'} = 1; } ## not yet supported... always off for ('ConvertMeta', 'MetaFlag', 'MarkModifiedLines', 'PreferVisibleBell', 'BlinkMatchingParen', 'VisibleStats', 'ShowAllIfAmbiguous', 'PrintCompletionsHorizontally', 'MarkDirectories', 'ExpandTilde', 'EnableKeypad', 'DisableCompletion', 'CompletionIgnoreCase') { ${"var_$_"} = 0; ${"var_$_"}{'Off'} = 0; ${"var_$_"}{'On'} = 1; } # To conform to interface $minlength = 1 unless defined $minlength; # WINCH hooks @winchhooks = (); $inDOS = $^O eq 'os2' || defined $ENV{OS2_SHELL} unless defined $inDOS; eval { require Term::ReadKey; $term_readkey++; } unless defined $ENV{PERL_RL_USE_TRK} and not $ENV{PERL_RL_USE_TRK}; unless ($term_readkey) { eval {require "ioctl.pl"}; ## try to get, don't die if not found. eval {require "sys/ioctl.ph"}; ## try to get, don't die if not found. eval {require "sgtty.ph"}; ## try to get, don't die if not found. if ($inDOS and !defined $TIOCGWINSZ) { $TIOCGWINSZ=0; $TIOCGETP=1; $TIOCSETP=2; $sgttyb_t="I5 C8"; $winsz_t=""; $RAW=0xf002; $ECHO=0x0008; } $TIOCGETP = &TIOCGETP if defined(&TIOCGETP); $TIOCSETP = &TIOCSETP if defined(&TIOCSETP); $TIOCGWINSZ = &TIOCGWINSZ if defined(&TIOCGWINSZ); $FIONREAD = &FIONREAD if defined(&FIONREAD); $TCGETS = &TCGETS if defined(&TCGETS); $TCSETS = &TCSETS if defined(&TCSETS); $TCXONC = &TCXONC if defined(&TCXONC); $TIOCGETP = 0x40067408 if !defined($TIOCGETP); $TIOCSETP = 0x80067409 if !defined($TIOCSETP); $TIOCGWINSZ = 0x40087468 if !defined($TIOCGWINSZ); $FIONREAD = 0x4004667f if !defined($FIONREAD); $TCGETS = 0x40245408 if !defined($TCGETS); $TCSETS = 0x80245409 if !defined($TCSETS); $TCXONC = 0x20005406 if !defined($TCXONC); ## TTY modes $ECHO = &ECHO if defined(&ECHO); $RAW = &RAW if defined(&RAW); $RAW = 040 if !defined($RAW); $ECHO = 010 if !defined($ECHO); #$CBREAK = 002 if !defined($CBREAK); $mode = $RAW; ## could choose CBREAK for testing.... $IGNBRK = 1 if !defined($IGNBRK); $BRKINT = 2 if !defined($BRKINT); $ISTRIP = 040 if !defined($ISTRIP); $INLCR = 0100 if !defined($INLCR); $IGNCR = 0200 if !defined($IGNCR); $ICRNL = 0400 if !defined($ICRNL); $OPOST = 1 if !defined($OPOST); $ISIG = 1 if !defined($ISIG); $ICANON = 2 if !defined($ICANON); $TCOON = 1 if !defined($TCOON); $TERMIOS_READLINE_ION = $BRKINT; $TERMIOS_READLINE_IOFF = $IGNBRK | $ISTRIP | $INLCR | $IGNCR | $ICRNL; $TERMIOS_READLINE_OON = 0; $TERMIOS_READLINE_OOFF = $OPOST; $TERMIOS_READLINE_LON = 0; $TERMIOS_READLINE_LOFF = $ISIG | $ICANON | $ECHO; $TERMIOS_NORMAL_ION = $BRKINT; $TERMIOS_NORMAL_IOFF = $IGNBRK; $TERMIOS_NORMAL_OON = $OPOST; $TERMIOS_NORMAL_OOFF = 0; $TERMIOS_NORMAL_LON = $ISIG | $ICANON | $ECHO; $TERMIOS_NORMAL_LOFF = 0; #$sgttyb_t = 'C4 S'; #$winsz_t = "S S S S"; # rows,cols, xpixel, ypixel $sgttyb_t = 'C4 S' if !defined($sgttyb_t); $winsz_t = "S S S S" if !defined($winsz_t); # rows,cols, xpixel, ypixel $winsz = pack($winsz_t,0,0,0,0); $fionread_t = "L"; $fion = pack($fionread_t, 0); $NCCS = 17; $termios_t = "LLLLc" . ("c" x $NCCS); # true for SunOS 4.1.3, at least... $termios = ''; ## just to shut up "perl -w". $termios = pack($termios, 0); # who cares, just make it long enough $TERMIOS_IFLAG = 0; $TERMIOS_OFLAG = 1; $TERMIOS_CFLAG = 2; $TERMIOS_LFLAG = 3; $TERMIOS_VMIN = 5 + 4; $TERMIOS_VTIME = 5 + 5; } $rl_delete_selection = 1; $rl_correct_sw = ($inDOS ? 1 : 0); $rl_scroll_nextline = 1 unless defined $rl_scroll_nextline; $rl_last_pos_can_backspace = ($inDOS ? 0 : 1) # Can backspace when the unless defined $rl_last_pos_can_backspace; # whole line is filled? $rl_start_default_at_beginning = 0; $rl_vi_replace_default_on_insert = 0; $rl_screen_width = 79; ## default $rl_completion_function = "rl_filename_list" unless defined($rl_completion_function); $rl_basic_word_break_characters = "\\\t\n' \"`\@\$><=;|&{("; $rl_completer_word_break_characters = $rl_basic_word_break_characters; $rl_special_prefixes = ''; ($rl_readline_name = $0) =~ s#.*[/\\]## if !defined($rl_readline_name); @rl_History=() if !(@rl_History); $rl_MaxHistorySize = 100 if !defined($rl_MaxHistorySize); $rl_max_numeric_arg = 200 if !defined($rl_max_numeric_arg); $rl_OperateCount = 0 if !defined($rl_OperateCount); $rl_term_set = \@Term::ReadLine::TermCap::rl_term_set; @$rl_term_set or $rl_term_set = ["","","",""]; $InsertMode=1; $KillBuffer=''; $line=''; $D = 0; $InputLocMsg = ' [initialization]'; &InitKeymap(*emacs_keymap, 'SelfInsert', 'emacs_keymap', ($inDOS ? () : ('C-@', 'SetMark') ), 'C-a', 'BeginningOfLine', 'C-b', 'BackwardChar', 'C-c', 'Interrupt', 'C-d', 'DeleteChar', 'C-e', 'EndOfLine', 'C-f', 'ForwardChar', 'C-g', 'Abort', 'M-C-g', 'Abort', 'C-h', 'BackwardDeleteChar', "TAB" , 'Complete', "C-j" , 'AcceptLine', 'C-k', 'KillLine', 'C-l', 'ClearScreen', "C-m" , 'AcceptLine', 'C-n', 'NextHistory', 'C-o', 'OperateAndGetNext', 'C-p', 'PreviousHistory', 'C-q', 'QuotedInsert', 'C-r', 'ReverseSearchHistory', 'C-s', 'ForwardSearchHistory', 'C-t', 'TransposeChars', 'C-u', 'UnixLineDiscard', ##'C-v', 'QuotedInsert', 'C-v', 'HistorySearchForward', 'C-w', 'UnixWordRubout', qq/"\cX\cX"/, 'ExchangePointAndMark', qq/"\cX\cR"/, 'ReReadInitFile', qq/"\cX?"/, 'PossibleCompletions', qq/"\cX*"/, 'InsertPossibleCompletions', qq/"\cX\cU"/, 'Undo', qq/"\cXu"/, 'Undo', qq/"\cX\cW"/, 'KillRegion', qq/"\cXw"/, 'CopyRegionAsKill', qq/"\cX\ec\\*"/, 'DoControlVersion', qq/"\cX\ec\0"/, 'SetMark', qq/"\cX\ec\@"/, 'SetMark', qq/"\cX\ec "/, 'SetMark', qq/"\cX\em\\*"/, 'DoMetaVersion', qq/"\cX\@c\\*"/, 'DoControlVersion', qq/"\cX\@c\0"/, 'SetMark', qq/"\cX\@c\@"/, 'SetMark', qq/"\cX\@c "/, 'SetMark', qq/"\cX\@m\\*"/, 'DoMetaVersion', 'C-y', 'Yank', 'C-z', 'Suspend', 'C-\\', 'Ding', 'C-^', 'Ding', 'C-_', 'Undo', 'DEL', ($inDOS ? 'BackwardKillWord' : # + 'BackwardDeleteChar' ), 'M-<', 'BeginningOfHistory', 'M->', 'EndOfHistory', 'M-DEL', 'BackwardKillWord', 'M-C-h', 'BackwardKillWord', 'M-C-j', 'ViInput', 'M-C-v', 'QuotedInsert', 'M-b', 'BackwardWord', 'M-c', 'CapitalizeWord', 'M-d', 'KillWord', 'M-f', 'ForwardWord', 'M-h', 'PrintHistory', 'M-l', 'DownCaseWord', 'M-r', 'RevertLine', 'M-t', 'TransposeWords', 'M-u', 'UpcaseWord', 'M-v', 'HistorySearchBackward', 'M-y', 'YankPop', "M-?", 'PossibleCompletions', "M-TAB", 'TabInsert', 'M-#', 'SaveLine', qq/"\e[A"/, 'previous-history', qq/"\e[B"/, 'next-history', qq/"\e[C"/, 'forward-char', qq/"\e[D"/, 'backward-char', qq/"\eOA"/, 'previous-history', qq/"\eOB"/, 'next-history', qq/"\eOC"/, 'forward-char', qq/"\eOD"/, 'backward-char', qq/"\eOy"/, 'HistorySearchBackward', # vt: PageUp qq/"\eOs"/, 'HistorySearchForward', # vt: PageDown qq/"\e[[A"/, 'previous-history', qq/"\e[[B"/, 'next-history', qq/"\e[[C"/, 'forward-char', qq/"\e[[D"/, 'backward-char', qq/"\e[2~"/, 'ToggleInsertMode', # X: # Mods: 1 + bitmask: 1 Shift, 2 Alt, 4 Control, 8 (sometimes) Meta qq/"\e[2;2~"/, 'YankClipboard', # + qq/"\e[3;2~"/, 'KillRegionClipboard', # + #qq/"\0\16"/, 'Undo', # + qq/"\eO5D"/, 'BackwardWord', # + qq/"\eO5C"/, 'ForwardWord', # + qq/"\e[5D"/, 'BackwardWord', # + qq/"\e[5C"/, 'ForwardWord', # + qq/"\eO5F"/, 'KillLine', # + qq/"\e[5F"/, 'KillLine', # + qq/"\e[4;5~"/, 'KillLine', # + qq/"\eO5s"/, 'EndOfHistory', # + qq/"\e[6;5~"/, 'EndOfHistory', # + qq/"\e[5H"/, 'BackwardKillLine', # + qq/"\eO5H"/, 'BackwardKillLine', # + qq/"\e[1;5~"/, 'BackwardKillLine', # + qq/"\eO5y"/, 'BeginningOfHistory', # + qq/"\e[5;5y"/, 'BeginningOfHistory', # + qq/"\e[2;5~"/, 'CopyRegionAsKillClipboard', # + qq/"\e[3;5~"/, 'KillWord', # + # XTerm mouse editing (f202/f203 not in mainstream yet): # Paste may be: move f200 STRING f201 # or f202 move f200 STRING f201 f203; # and Cut may be f202 move delete f203 qq/"\e[200~"/, 'BeginPasteGroup', # Pre-paste qq/"\e[201~"/, 'EndPasteGroup', # Post-paste qq/"\e[202~"/, 'BeginEditGroup', # Pre-edit qq/"\e[203~"/, 'EndEditGroup', # Post-edit # OSX xterm: # OSX xterm: home \eOH end \eOF delete \e[3~ help \e[28~ f13 \e[25~ # gray- \eOm gray+ \eOk gray-enter \eOM gray* \eOj gray/ \eOo gray= \eO # grayClear \e\e. qq/"\eOH"/, 'BeginningOfLine', # home qq/"\eOF"/, 'EndOfLine', # end # HP xterm #qq/"\e[A"/, 'PreviousHistory', # up arrow #qq/"\e[B"/, 'NextHistory', # down arrow #qq/"\e[C"/, 'ForwardChar', # right arrow #qq/"\e[D"/, 'BackwardChar', # left arrow qq/"\e[H"/, 'BeginningOfLine', # home #'C-k', 'KillLine', # clear display qq/"\e[5~"/, 'HistorySearchBackward', # prev qq/"\e[6~"/, 'HistorySearchForward', # next qq/"\e[\0"/, 'BeginningOfLine', # home # These contradict: ($^O =~ /^hp\W?ux/i ? ( qq/"\e[1~"/, 'HistorySearchForward', # find qq/"\e[3~"/, 'ToggleInsertMode', # insert char qq/"\e[4~"/, 'ToggleInsertMode', # select ) : ( # "Normal" xterm qq/"\e[1~"/, 'BeginningOfLine', # home qq/"\e[3~"/, 'DeleteChar', # delete qq/"\e[4~"/, 'EndOfLine', # end )), # hpterm (($ENV{'TERM'} and $ENV{'TERM'} eq 'hpterm') ? ( qq/"\eA"/, 'PreviousHistory', # up arrow qq/"\eB"/, 'NextHistory', # down arrow qq/"\eC"/, 'ForwardChar', # right arrow qq/"\eD"/, 'BackwardChar', # left arrow qq/"\eS"/, 'BeginningOfHistory', # shift up arrow qq/"\eT"/, 'EndOfHistory', # shift down arrow qq/"\e&r1R"/, 'EndOfLine', # shift right arrow qq/"\e&r1L"/, 'BeginningOfLine', # shift left arrow qq/"\eJ"/, 'ClearScreen', # clear display qq/"\eM"/, 'UnixLineDiscard', # delete line qq/"\eK"/, 'KillLine', # clear line qq/"\eG\eK"/, 'BackwardKillLine', # shift clear line qq/"\eP"/, 'DeleteChar', # delete char qq/"\eL"/, 'Yank', # insert line qq/"\eQ"/, 'ToggleInsertMode', # insert char qq/"\eV"/, 'HistorySearchBackward',# prev qq/"\eU"/, 'HistorySearchForward',# next qq/"\eh"/, 'BeginningOfLine', # home qq/"\eF"/, 'EndOfLine', # shift home qq/"\ei"/, 'Suspend', # shift tab ) : () ), ($inDOS ? ( qq/"\0\2"/, 'SetMark', # 2: + qq/"\0\3"/, 'SetMark', # 3: +<@> qq/"\0\4"/, 'YankClipboard', # 4: + qq/"\0\5"/, 'KillRegionClipboard', # 5: + qq/"\0\16"/, 'Undo', # 14: + # qq/"\0\23"/, 'RevertLine', # 19: + # qq/"\0\24"/, 'TransposeWords', # 20: + # qq/"\0\25"/, 'YankPop', # 21: + # qq/"\0\26"/, 'UpcaseWord', # 22: + # qq/"\0\31"/, 'ReverseSearchHistory', # 25: +

# qq/"\0\40"/, 'KillWord', # 32: + # qq/"\0\41"/, 'ForwardWord', # 33: + # qq/"\0\46"/, 'DownCaseWord', # 38: + #qq/"\0\51"/, 'TildeExpand', # 41: +<\'> # qq/"\0\56"/, 'CapitalizeWord', # 46: + # qq/"\0\60"/, 'BackwardWord', # 48: + # qq/"\0\61"/, 'ForwardSearchHistory', # 49: + #qq/"\0\64"/, 'YankLastArg', # 52: +<.> qq/"\0\65"/, 'PossibleCompletions', # 53: + qq/"\0\107"/, 'BeginningOfLine', # 71: qq/"\0\110"/, 'previous-history', # 72: qq/"\0\111"/, 'HistorySearchBackward', # 73: qq/"\0\113"/, 'backward-char', # 75: qq/"\0\115"/, 'forward-char', # 77: qq/"\0\117"/, 'EndOfLine', # 79: qq/"\0\120"/, 'next-history', # 80: qq/"\0\121"/, 'HistorySearchForward', # 81: qq/"\0\122"/, 'ToggleInsertMode', # 82: qq/"\0\123"/, 'DeleteChar', # 83: qq/"\0\163"/, 'BackwardWord', # 115: + qq/"\0\164"/, 'ForwardWord', # 116: + qq/"\0\165"/, 'KillLine', # 117: + qq/"\0\166"/, 'EndOfHistory', # 118: + qq/"\0\167"/, 'BackwardKillLine', # 119: + qq/"\0\204"/, 'BeginningOfHistory', # 132: + qq/"\0\x92"/, 'CopyRegionAsKillClipboard', # 146: + qq/"\0\223"/, 'KillWord', # 147: + qq/"\0#"/, 'PrintHistory', # Alt-H ) : ( 'C-@', 'Ding') ) ); *KeyMap = *emacs_keymap; my @add_bindings = (); foreach ('-', '0' .. '9') { push(@add_bindings, "M-$_", 'DigitArgument'); } foreach ("A" .. "Z") { next if # defined($KeyMap[27]) && defined (%{"$KeyMap{name}_27"}) && defined $ {"$KeyMap{name}_27"}[ord $_]; push(@add_bindings, "M-$_", 'DoLowercaseVersion'); } if ($inDOS) { # Default translation of Alt-char $ {"$KeyMap{name}_0"}{'Esc'} = *{"$KeyMap{name}_27"}; $ {"$KeyMap{name}_0"}{'default'} = 'F_DoEscVersion'; } &rl_bind(@add_bindings); # Vi input mode. &InitKeymap(*vi_keymap, 'SelfInsert', 'vi_keymap', "\e", 'ViEndInsert', 'C-c', 'Interrupt', 'C-h', 'BackwardDeleteChar', 'C-w', 'UnixWordRubout', 'C-u', 'UnixLineDiscard', 'C-v', 'QuotedInsert', 'DEL', 'BackwardDeleteChar', "\n", 'ViAcceptInsert', "\r", 'ViAcceptInsert', ); # Vi command mode. &InitKeymap(*vicmd_keymap, 'Ding', 'vicmd_keymap', 'C-c', 'Interrupt', 'C-e', 'EmacsEditingMode', 'C-h', 'ViMoveCursor', 'C-l', 'ClearScreen', "\n", 'ViAcceptLine', "\r", 'ViAcceptLine', ' ', 'ViMoveCursor', '#', 'SaveLine', '$', 'ViMoveCursor', '%', 'ViMoveCursor', '*', 'ViInsertPossibleCompletions', '+', 'NextHistory', ',', 'ViMoveCursor', '-', 'PreviousHistory', '.', 'ViRepeatLastCommand', '/', 'ViSearch', '0', 'ViMoveCursor', '1', 'ViDigit', '2', 'ViDigit', '3', 'ViDigit', '4', 'ViDigit', '5', 'ViDigit', '6', 'ViDigit', '7', 'ViDigit', '8', 'ViDigit', '9', 'ViDigit', ';', 'ViMoveCursor', '=', 'ViPossibleCompletions', '?', 'ViSearch', 'A', 'ViAppendLine', 'B', 'ViMoveCursor', 'C', 'ViChangeLine', 'D', 'ViDeleteLine', 'E', 'ViMoveCursor', 'F', 'ViMoveCursor', 'G', 'ViHistoryLine', 'H', 'PrintHistory', 'I', 'ViBeginInput', 'N', 'ViRepeatSearch', 'P', 'ViPutBefore', 'R', 'ViReplaceMode', 'S', 'ViChangeEntireLine', 'T', 'ViMoveCursor', 'U', 'ViUndoAll', 'W', 'ViMoveCursor', 'X', 'ViBackwardDeleteChar', 'Y', 'ViYankLine', '\\', 'ViComplete', '^', 'ViMoveCursor', 'a', 'ViAppend', 'b', 'ViMoveCursor', 'c', 'ViChange', 'd', 'ViDelete', 'e', 'ViMoveCursor', 'f', 'ViMoveCursorFind', 'h', 'ViMoveCursor', 'i', 'ViInput', 'j', 'NextHistory', 'k', 'PreviousHistory', 'l', 'ViMoveCursor', 'n', 'ViRepeatSearch', 'p', 'ViPut', 'r', 'ViReplaceChar', 's', 'ViChangeChar', 't', 'ViMoveCursorTo', 'u', 'ViUndo', 'w', 'ViMoveCursor', 'x', 'ViDeleteChar', 'y', 'ViYank', '|', 'ViMoveCursor', '~', 'ViToggleCase', (($inDOS and (not $ENV{'TERM'} or $ENV{'TERM'} !~ /^(vt|xterm)/i)) ? ( qq/"\0\110"/, 'PreviousHistory', # 72: qq/"\0\120"/, 'NextHistory', # 80: qq/"\0\113"/, 'BackwardChar', # 75: qq/"\0\115"/, 'ForwardChar', # 77: "\e", 'ViCommandMode', ) : (('M-C-j','EmacsEditingMode'), # Conflicts with \e otherwise (($ENV{'TERM'} and $ENV{'TERM'} eq 'hpterm') ? ( qq/"\eA"/, 'PreviousHistory', # up arrow qq/"\eB"/, 'NextHistory', # down arrow qq/"\eC"/, 'ForwardChar', # right arrow qq/"\eD"/, 'BackwardChar', # left arrow qq/"\e\\*"/, 'ViAfterEsc', ) : # Default ( qq/"\e[A"/, 'PreviousHistory', # up arrow qq/"\e[B"/, 'NextHistory', # down arrow qq/"\e[C"/, 'ForwardChar', # right arrow qq/"\e[D"/, 'BackwardChar', # left arrow qq/"\e\\*"/, 'ViAfterEsc', qq/"\e[\\*"/, 'ViAfterEsc', ) ))), ); # Vi positioning commands (suffixed to vi commands like 'd'). &InitKeymap(*vipos_keymap, 'ViNonPosition', 'vipos_keymap', '^', 'ViFirstWord', '0', 'BeginningOfLine', '1', 'ViDigit', '2', 'ViDigit', '3', 'ViDigit', '4', 'ViDigit', '5', 'ViDigit', '6', 'ViDigit', '7', 'ViDigit', '8', 'ViDigit', '9', 'ViDigit', '$', 'EndOfLine', 'h', 'BackwardChar', 'l', 'ForwardChar', ' ', 'ForwardChar', 'C-h', 'BackwardChar', 'f', 'ViForwardFindChar', 'F', 'ViBackwardFindChar', 't', 'ViForwardToChar', 'T', 'ViBackwardToChar', ';', 'ViRepeatFindChar', ',', 'ViInverseRepeatFindChar', '%', 'ViFindMatchingParens', '|', 'ViMoveToColumn', # Arrow keys ($inDOS ? ( qq/"\0\115"/, 'ForwardChar', # 77: qq/"\0\113"/, 'BackwardChar', # 75: "\e", 'ViPositionEsc', ) : ($ENV{'TERM'} and $ENV{'TERM'} eq 'hpterm') ? ( qq/"\eC"/, 'ForwardChar', # right arrow qq/"\eD"/, 'BackwardChar', # left arrow qq/"\e\\*"/, 'ViPositionEsc', ) : # Default ( qq/"\e[C"/, 'ForwardChar', # right arrow qq/"\e[D"/, 'BackwardChar', # left arrow qq/"\e\\*"/, 'ViPositionEsc', qq/"\e[\\*"/, 'ViPositionEsc', ) ), ); # Vi search string input mode for '/' and '?'. &InitKeymap(*visearch_keymap, 'SelfInsert', 'visearch_keymap', "\e", 'Ding', 'C-c', 'Interrupt', 'C-h', 'ViSearchBackwardDeleteChar', 'C-w', 'UnixWordRubout', 'C-u', 'UnixLineDiscard', 'C-v', 'QuotedInsert', 'DEL', 'ViSearchBackwardDeleteChar', "\n", 'ViEndSearch', "\r", 'ViEndSearch', ); # These constant hashes hold the arguments to &forward_scan() or # &backward_scan() for vi positioning commands, which all # behave a little differently for delete, move, change, and yank. # # Note: I originally coded these as qr{}, but changed them to q{} for # compatibility with older perls at the expense of some performance. # # Note: Some of the more obscure key combinations behave slightly # differently in different vi implementation. This module matches # the behavior of /usr/ucb/vi, which is different from the # behavior of vim, nvi, and the ksh command line. One example is # the command '2de', when applied to the string ('^' represents the # cursor, not a character of the string): # # ^5.6 7...88888888 # # With /usr/ucb/vi and with this module, the result is # # ^...88888888 # # but with the other three vi implementations, the result is # # ^ 7...88888888 $Vi_delete_patterns = { ord('w') => q{(?:\w+|[^\w\s]+|)\s*}, ord('W') => q{\S*\s*}, ord('b') => q{\w+\s*|[^\w\s]+\s*|^\s+}, ord('B') => q{\S+\s*|^\s+}, ord('e') => q{.\s*\w+|.\s*[^\w\s]+|.\s*$}, ord('E') => q{.\s*\S+|.\s*$}, }; $Vi_move_patterns = { ord('w') => q{(?:\w+|[^\w\s]+|)\s*}, ord('W') => q{\S*\s*}, ord('b') => q{\w+\s*|[^\w\s]+\s*|^\s+}, ord('B') => q{\S+\s*|^\s+}, ord('e') => q{.\s*\w*(?=\w)|.\s*[^\w\s]*(?=[^\w\s])|.?\s*(?=\s$)}, ord('E') => q{.\s*\S*(?=\S)|.?\s*(?=\s$)}, }; $Vi_change_patterns = { ord('w') => q{\w+|[^\w\s]+|\s}, ord('W') => q{\S+|\s}, ord('b') => q{\w+\s*|[^\w\s]+\s*|^\s+}, ord('B') => q{\S+\s*|^\s+}, ord('e') => q{.\s*\w+|.\s*[^\w\s]+|.\s*$}, ord('E') => q{.\s*\S+|.\s*$}, }; $Vi_yank_patterns = { ord('w') => q{(?:\w+|[^\w\s]+|)\s*}, ord('W') => q{\S*\s*}, ord('b') => q{\w+\s*|[^\w\s]+\s*|^\s+}, ord('B') => q{\S+\s*|^\s+}, ord('e') => q{.\s*\w*(?=\w)|.\s*[^\w\s]*(?=[^\w\s])|.?\s*(?=\s$)}, ord('E') => q{.\s*\S*(?=\S)|.?\s*(?=\s$)}, }; my $default_mode = 'emacs'; *KeyMap = $var_EditingMode = $var_EditingMode{$default_mode}; ## my $name; ## for $name ( keys %{'readline::'} ) { ## # Create aliases accessible via tied interface ## *{"rl_$1"} = \$ {"var_$1"} if $name =~ /$var_(.*)/; ## } 1; # Returning a glob causes a bug in db5.001m } sub init { if ($ENV{'TERM'} and ($ENV{'TERM'} eq 'emacs' || $ENV{'TERM'} eq 'dumb')) { $dumb_term = 1; } elsif (! -c $term_IN && $term_IN eq \*STDIN) { # Believe if it is given $stdin_not_tty = 1; } else { &get_window_size; &F_ReReadInitFile if !defined($rl_NoInitFromFile); $InputLocMsg = ''; *KeyMap = $var_EditingMode; } $initialized = 1; } ## ## InitKeymap(*keymap, 'default', 'name', bindings.....) ## sub InitKeymap { local(*KeyMap) = shift(@_); my $default = shift(@_); my $name = $KeyMap{'name'} = shift(@_); # 'default' is now optional - if '', &do_command() defaults it to # 'F_Ding'. Meta-maps now don't set a default - this lets # us detect multiple '\*' default declarations. JP if ($default ne '') { my $func = $KeyMap{'default'} = "F_$default"; ### Temporarily disabled die qq/Bad default function [$func] for keymap "$name"/ if !$autoload_broken and !defined(&$func); } &rl_bind if @_ > 0; ## The rest of @_ gets passed silently. } ## ## Accepts an array as pairs ($keyspec, $function, [$keyspec, $function]...). ## and maps the associated bindings to the current KeyMap. ## ## keyspec should be the name of key sequence in one of two forms: ## ## Old (GNU readline documented) form: ## M-x to indicate Meta-x ## C-x to indicate Ctrl-x ## M-C-x to indicate Meta-Ctrl-x ## x simple char x ## where 'x' above can be a single character, or the special: ## special means ## -------- ----- ## space space ( ) ## spc space ( ) ## tab tab (\t) ## del delete (0x7f) ## rubout delete (0x7f) ## newline newline (\n) ## lfd newline (\n) ## ret return (\r) ## return return (\r) ## escape escape (\e) ## esc escape (\e) ## ## New form: ## "chars" (note the required double-quotes) ## where each char in the list represents a character in the sequence, except ## for the special sequences: ## \\C-x Ctrl-x ## \\M-x Meta-x ## \\M-C-x Meta-Ctrl-x ## \\e escape. ## \\x x (if not one of the above) ## ## ## FUNCTION should be in the form 'BeginningOfLine' or 'beginning-of-line'. ## It is an error for the function to not be known.... ## ## As an example, the following lines in .inputrc will bind one's xterm ## arrow keys: ## "\e[[A": previous-history ## "\e[[B": next-history ## "\e[[C": forward-char ## "\e[[D": backward-char ## sub filler_Pending ($) { my $keys = shift; sub { my $c = shift; push @Pending, map chr, @$keys; return if not @$keys or $c == 1 or not defined(my $in = &getc_with_pending); # provide the numeric argument local(*KeyMap) = $var_EditingMode; $doingNumArg = 1; # Allow NumArg inside NumArg &do_command(*KeyMap, $c, ord $in); return; } } sub _unescape ($) { my($key, @keys) = shift; ## New-style bindings are enclosed in double-quotes. ## Characters are taken verbatim except the special cases: ## \C-x Control x (for any x) ## \M-x Meta x (for any x) ## \e Escape ## \* Set the keymap default (JP: added this) ## (must be the last character of the sequence) ## ## \x x (unless it fits the above pattern) ## ## Look for special case of "\C-\M-x", which should be treated ## like "\M-\C-x". while (length($key) > 0) { # JP: fixed regex bugs below: changed all 's#' to 's#^' if ($key =~ s#^\\C-\\M-(.)##) { push(@keys, ord("\e"), &ctrl(ord($1))); } elsif ($key =~ s#^\\(M-|e)##) { push(@keys, ord("\e")); } elsif ($key =~ s#^\\C-(.)##) { push(@keys, &ctrl(ord($1))); } elsif ($key =~ s#^\\x([0-9a-fA-F]{2})##) { push(@keys, eval('0x'.$1)); } elsif ($key =~ s#^\\([0-7]{3})##) { push(@keys, eval('0'.$1)); } elsif ($key =~ s#^\\\*$##) { # JP: added push(@keys, 'default'); } elsif ($key =~ s#^\\([afnrtv])##) { push(@keys, ord(eval(qq("\\$1")))); } elsif ($key =~ s#^\\d##) { push(@keys, 4); # C-d } elsif ($key =~ s#^\\b##) { push(@keys, 0x7f); # Backspace } elsif ($key =~ s#^\\(.)##) { push(@keys, ord($1)); } else { push(@keys, ord($key)); substr($key,0,1) = ''; } } @keys } sub RL_func ($) { my $name_or_macro = shift; if ($name_or_macro =~ /^"((?:\\.|[^\\\"])*)"|^'((?:\\.|[^\\\'])*)'/s) { filler_Pending [_unescape "$+"]; } else { "F_$name_or_macro"; } } sub actually_do_binding { ## ## actually_do_binding($function1, \@sequence1, ...) ## ## Actually inserts the binding for @sequence to $function into the ## current map. @sequence is an array of character ordinals. ## ## If @sequence is more than one element long, all but the last will ## cause meta maps to be created. ## ## $Function will have an implicit "F_" prepended to it. ## while (@_) { my $func = shift; my ($key, @keys) = @{shift()}; $key += 0; local(*KeyMap) = *KeyMap; my $map; while (@keys) { if (defined($KeyMap[$key]) && ($KeyMap[$key] ne 'F_PrefixMeta')) { warn "Warning$InputLocMsg: ". "Re-binding char #$key from [$KeyMap[$key]] to meta for [@keys] => $func.\n" if $^W; } $KeyMap[$key] = 'F_PrefixMeta'; $map = "$KeyMap{'name'}_$key"; InitKeymap(*$map, '', $map) if !(%$map); *KeyMap = *$map; $key = shift @keys; #&actually_do_binding($func, \@keys); } my $name = $KeyMap{'name'}; if ($key eq 'default') { # JP: added warn "Warning$InputLocMsg: ". " changing default action to $func in $name key map\n" if $^W && defined $KeyMap{'default'}; $KeyMap{'default'} = RL_func $func; } else { if (defined($KeyMap[$key]) && $KeyMap[$key] eq 'F_PrefixMeta' && $func ne 'PrefixMeta') { warn "Warning$InputLocMsg: ". " Re-binding char #$key to non-meta ($func) in $name key map\n" if $^W; } $KeyMap[$key] = RL_func $func; } } } sub rl_bind { my (@keys, $key, $func, $ord, @arr); while (defined($key = shift(@_)) && defined($func = shift(@_))) { ## ## Change the function name from something like ## backward-kill-line ## to ## BackwardKillLine ## if not already there. ## unless ($func =~ /^[\"\']/) { $func = "\u$func"; $func =~ s/-(.)/\u$1/g; # Temporary disabled if (!$autoload_broken and !defined($ {'readline::'}{"F_$func"})) { warn "Warning$InputLocMsg: bad bind function [$func]\n" if $^W; next; } } ## print "sequence [$key] func [$func]\n"; ##DEBUG @keys = (); ## See if it's a new-style binding. if ($key =~ m/"((?:\\.|[^\\])*)"/s) { @keys = _unescape "$1"; } else { ## ol-dstyle binding... only one key (or Meta+key) my ($isctrl, $orig) = (0, $key); $isctrl = $key =~ s/\b(C|Control|CTRL)-//i; push(@keys, ord("\e")) if $key =~ s/\b(M|Meta)-//i; ## is meta? ## Isolate key part. This matches GNU's implementation. ## If the key is '-', be careful not to delete it! $key =~ s/.*-(.)/$1/; if ($key =~ /^(space|spc)$/i) { $key = ' '; } elsif ($key =~ /^(rubout|del)$/i) { $key = "\x7f"; } elsif ($key =~ /^tab$/i) { $key = "\t"; } elsif ($key =~ /^(return|ret)$/i) { $key = "\r"; } elsif ($key =~ /^(newline|lfd)$/i) { $key = "\n"; } elsif ($key =~ /^(escape|esc)$/i) { $key = "\e"; } elsif (length($key) > 1) { warn "Warning$InputLocMsg: strange binding [$orig]\n" if $^W; } $key = ord($key); $key = &ctrl($key) if $isctrl; push(@keys, $key); } # ## Now do the mapping of the sequence represented in @keys # # print "&actually_do_binding($func, @keys)\n"; ##DEBUG push @arr, $func, [@keys]; #&actually_do_binding($func, \@keys); } &actually_do_binding(@arr); } sub read_an_init_file { my $file = shift; my $include_depth = shift; local *RC; $file =~ s/^~([\\\/])/$ENV{HOME}$1/ if not -f $file and exists $ENV{HOME}; return unless open RC, "< $file"; my (@action) = ('exec'); ## exec, skip, ignore (until appropriate endif) my (@level) = (); ## if, else local $/ = "\n"; while () { s/^\s+//; next if m/^\s*(#|$)/; $InputLocMsg = " [$file line $.]"; if (/^\$if\s+(.*)/) { my($test) = $1; push(@level, 'if'); if ($action[$#action] ne 'exec') { ## We're supposed to be skipping or ignoring this level, ## so for subsequent levels we really ignore completely. push(@action, 'ignore'); } else { ## We're executing this IF... do the test. ## The test is either "term=xxxx", or just a string that ## we compare to $rl_readline_name; if ($test =~ /term=([a-z0-9]+)/) { $test = ($ENV{'TERM'} && $1 eq $ENV{'TERM'}); } else { $test = $test =~ /^(perl|$rl_readline_name)\s*$/i; } push(@action, $test ? 'exec' : 'skip'); } next; } elsif (/^\$endif\b/) { die qq/\rWarning$InputLocMsg: unmatched endif\n/ if @level == 0; pop(@level); pop(@action); next; } elsif (/^\$else\b/) { die qq/\rWarning$InputLocMsg: unmatched else\n/ if @level == 0 || $level[$#level] ne 'if'; $level[$#level] = 'else'; ## an IF turns into an ELSE if ($action[$#action] eq 'skip') { $action[$#action] = 'exec'; ## if were SKIPing, now EXEC } else { $action[$#action] = 'ignore'; ## otherwise, just IGNORE. } next; } elsif (/^\$include\s+(\S+)/) { if ($include_depth > $max_include_depth) { warn "Deep recursion in \$include directives in $file.\n"; } else { read_an_init_file($1, $include_depth + 1); } } elsif ($action[$#action] ne 'exec') { ## skipping this one.... # readline permits trailing comments in inputrc # this seems to solve the warnings caused by trailing comments in the # default /etc/inputrc on Mandrake Linux boxes. } elsif (m/\s*set\s+(\S+)\s+(\S*)/) { # Allow trailing comment &rl_set($1, $2, $file); } elsif (m/^\s*(\S+):\s+("(?:\\.|[^\\\"])*"|'(\\.|[^\\\'])*')/) { # Allow trailing comment &rl_bind($1, $2); } elsif (m/^\s*(\S+|"[^\"]+"):\s+(\S+)/) { # Allow trailing comment &rl_bind($1, $2); } else { chomp; warn "\rWarning$InputLocMsg: Bad line [$_]\n" if $^W; } } close(RC); } sub F_ReReadInitFile { my ($file) = $ENV{'TRP_INPUTRC'}; $file = $ENV{'INPUTRC'} unless defined $file; unless (defined $file) { return unless defined $ENV{'HOME'}; $file = "$ENV{'HOME'}/.inputrc"; } read_an_init_file($file, 0); } sub get_ornaments_selected { return if @$rl_term_set >= 6; local $^W=0; my $Orig = $Term::ReadLine::Perl::term->ornaments(); eval { # Term::ReadLine does not expose its $terminal, so make another require Term::Cap; my $terminal = Tgetent Term::Cap ({OSPEED=>9600}); # and be sure the terminal supports highlighting $terminal->Trequire('mr'); }; if (!$@ and $Orig ne ',,,'){ my @set = @$rl_term_set; $Term::ReadLine::Perl::term->ornaments (join(',', (split(/,/, $Orig))[0,1]) . ',mr,me') ; @set[4,5] = @$rl_term_set[2,3]; $Term::ReadLine::Perl::term->ornaments($Orig); @$rl_term_set = @set; } else { @$rl_term_set[4,5] = @$rl_term_set[2,3]; } } sub readline_dumb { local $\ = ''; print $term_OUT $prompt; local $/ = "\n"; return undef if !defined($line = $Term::ReadLine::Perl::term->get_line); chomp($line); $| = $oldbar; select $old; return $line; } ## ## This is it. Called as &readline'readline($prompt, $default), ## (DEFAULT can be omitted) the next input line is returned (undef on EOF). ## sub readline { $Term::ReadLine::Perl::term->register_Tk if not $Term::ReadLine::registered and $Term::ReadLine::toloop and defined &Tk::DoOneEvent; if ($stdin_not_tty) { local $/ = "\n"; return undef if !defined($line = <$term_IN>); chomp($line); return $line; } $old = select $term_OUT; $oldbar = $|; local($|) = 1; local($input); ## prompt should be given to us.... $prompt = defined($_[0]) ? $_[0] : 'INPUT> '; # Try to move cursor to the beginning of the next line if this line # contains anything. # On DOSish 80-wide console # perl -we "print 1 x shift, qq(\b2\r3); sleep 2" 79 # prints 3 on the same line, # perl -we "print 1 x shift, qq(\b2\r3); sleep 2" 80 # on the next; $rl_screen_width is 79. # on XTerm one needs to increase the number by 1. print $term_OUT ' ' x ($rl_screen_width - !$rl_last_pos_can_backspace) . "\b \r" if $rl_scroll_nextline; if ($dumb_term) { return readline_dumb; } # test if we resume an 'Operate' command if ($rl_OperateCount > 0 && (!defined $_[1] || $_[1] eq '')) { ## it's from a valid previous 'Operate' command and ## user didn't give a default line ## we leave $rl_HistoryIndex untouched $line = $rl_History[$rl_HistoryIndex]; } else { ## set history pointer at the end of history $rl_HistoryIndex = $#rl_History + 1; $rl_OperateCount = 0; $line = defined $_[1] ? $_[1] : ''; } $rl_OperateCount-- if $rl_OperateCount > 0; $line_for_revert = $line; # I don't think we need to do this, actually... # while (&ioctl(STDIN,$FIONREAD,$fion)) # { # local($n_chars_available) = unpack ($fionread_t, $fion); # ## print "n_chars = $n_chars_available\n"; # last if $n_chars_available == 0; # $line .= getc_with_pending; # should we prepend if $rl_start_default_at_beginning? # } $D = $rl_start_default_at_beginning ? 0 : length($line); ## set dot. $LastCommandKilledText = 0; ## heck, was no last command. $lastcommand = ''; ## Well, there you go. $line_rl_mark = -1; ## ## some stuff for &redisplay. ## $lastredisplay = ''; ## Was no last redisplay for this time. $lastlen = length($lastredisplay); $lastpromptlen = 0; $lastdelta = 0; ## Cursor was nowhere $si = 0; ## Want line to start left-justified $force_redraw = 1; ## Want to display with brute force. if (!eval {SetTTY()}) { ## Put into raw mode. warn $@ if $@; $dumb_term = 1; return readline_dumb; } *KeyMap = $var_EditingMode; undef($AcceptLine); ## When set, will return its value. undef($ReturnEOF); ## ...unless this on, then return undef. @Pending = (); ## Contains characters to use as input. @undo = (); ## Undo history starts empty for each line. @undoGroupS = (); ## Undo groups start empty for each line. undef $memorizedArg; ## No digitArgument memorized undef $memorizedPos; ## No position memorized undef $Vi_undo_state; undef $Vi_undo_all_state; # We need to do some additional initialization for vi mode. # RS: bug reports/platform issues are welcome: russ@dvns.com if ($KeyMap{'name'} eq 'vi_keymap'){ &F_ViInput(); if ($rl_vi_replace_default_on_insert){ local $^W=0; my $Orig = $Term::ReadLine::Perl::term->ornaments(); eval { # Term::ReadLine does not expose its $terminal, so make another require Term::Cap; my $terminal = Tgetent Term::Cap ({OSPEED=>9600}); # and be sure the terminal supports highlighting $terminal->Trequire('mr'); }; if (!$@ and $Orig ne ',,,'){ $Term::ReadLine::Perl::term->ornaments (join(',', (split(/,/, $Orig))[0,1]) . ',mr,me') } my $F_SelfInsert_Real = \&F_SelfInsert; *F_SelfInsert = sub { $Term::ReadLine::Perl::term->ornaments($Orig); &F_ViChangeEntireLine; local $^W=0; *F_SelfInsert = $F_SelfInsert_Real; &F_SelfInsert; }; my $F_ViEndInsert_Real = \&F_ViEndInsert; *F_ViEndInsert = sub { $Term::ReadLine::Perl::term->ornaments($Orig); local $^W=0; *F_SelfInsert = $F_SelfInsert_Real; *F_ViEndInsert = $F_ViEndInsert_Real; &F_ViEndInsert; $force_redraw = 1; redisplay(); }; } } if ($rl_default_selected) { redisplay_high(); } else { &redisplay(); ## Show the line (prompt+default at this point). } # pretend input if we 'Operate' on more than one line &F_OperateAndGetNext($rl_OperateCount) if $rl_OperateCount > 0; $rl_first_char = 1; while (!defined($AcceptLine)) { ## get a character of input $input = &getc_with_pending(); # bug in debugger, returns 42. - No more! unless (defined $input) { # XXX What to do??? Until this is clear, just pretend we got EOF $AcceptLine = $ReturnEOF = 1; last; } preserve_state(); $ThisCommandKilledText = 0; ##print "\n\rline is @$D:[$line]\n\r"; ##DEBUG my $cmd = get_command($var_EditingMode, ord($input)); if ( $rl_first_char && $cmd =~ /^F_(SelfInsert$|Yank)/ && length $line && $rl_default_selected ) { # (Backward)?DeleteChar specialcased in the code $line = ''; $D = 0; $cmd = 'F_BackwardDeleteChar' if $cmd eq 'F_DeleteChar'; } undef $doingNumArg; &$cmd(1, ord($input)); ## actually execute input $rl_first_char = 0; $lastcommand = $cmd; *KeyMap = $var_EditingMode; # JP: added # In Vi command mode, don't position the cursor beyond the last # character of the line buffer. &F_BackwardChar(1) if $Vi_mode and $line ne '' and &at_end_of_line and $KeyMap{'name'} eq 'vicmd_keymap'; &redisplay(); $LastCommandKilledText = $ThisCommandKilledText; } undef @undo; ## Release the memory. undef @undoGroupS; ## Release the memory. &ResetTTY; ## Restore the tty state. $| = $oldbar; select $old; return undef if defined($ReturnEOF); #print STDOUT "|al=`$AcceptLine'"; $AcceptLine; ## return the line accepted. } ## ctrl(ord('a')) will return the ordinal for Ctrl-A. sub ctrl { $_[0] ^ (($_[0]>=ord('a') && $_[0]<=ord('z')) ? 0x60 : 0x40); } sub SetTTY { return if $dumb_term || $stdin_not_tty; #return system 'stty raw -echo' if defined &DB::DB; if (defined $term_readkey) { Term::ReadKey::ReadMode(4, $term_IN); if ($^O eq 'MSWin32') { # If we reached this, Perl isn't cygwin; Enter sends \r; thus we need binmode # XXXX Do we need to undo??? $term_IN is most probably private now... binmode $term_IN; } return 1; } # system 'stty raw -echo'; $sgttyb = ''; ## just to quiet "perl -w"; if ($useioctl && $^O ne 'solaris' && defined $TIOCGETP && &ioctl($term_IN,$TIOCGETP,$sgttyb)) { @tty_buf = unpack($sgttyb_t,$sgttyb); if (defined $ENV{OS2_SHELL}) { $tty_buf[3] &= ~$mode; $tty_buf[3] &= ~$ECHO; } else { $tty_buf[4] |= $mode; $tty_buf[4] &= ~$ECHO; } $sgttyb = pack($sgttyb_t,@tty_buf); &ioctl($term_IN,$TIOCSETP,$sgttyb) || die "Can't ioctl TIOCSETP: $!"; } elsif (!$usestty) { return 0; } else { warn < cygwin # The symptoms: now Enter sends \r; thus we need binmode # XXXX Do we need to undo??? $term_IN is most probably private now... binmode $term_IN; } } return 1; } sub ResetTTY { return if $dumb_term || $stdin_not_tty; #return system 'stty -raw echo' if defined &DB::DB; if (defined $term_readkey) { return Term::ReadKey::ReadMode(0, $term_IN); } # system 'stty -raw echo'; if ($useioctl) { &ioctl($term_IN,$TIOCGETP,$sgttyb) || die "Can't ioctl TIOCGETP: $!"; @tty_buf = unpack($sgttyb_t,$sgttyb); if (defined $ENV{OS2_SHELL}) { $tty_buf[3] |= $mode; $tty_buf[3] |= $ECHO; } else { $tty_buf[4] &= ~$mode; $tty_buf[4] |= $ECHO; } $sgttyb = pack($sgttyb_t,@tty_buf); &ioctl($term_IN,$TIOCSETP,$sgttyb) || die "Can't ioctl TIOCSETP: $!"; } elsif ($usestty) { system 'stty -raw echo' and die "Cannot call `stty': $!"; } } # Substr_with_props: gives the substr of prompt+string with embedded # face-change commands sub substr_with_props { my ($p, $s, $from, $len, $ket, $bsel, $esel) = @_; my $lp = length $p; defined $from or $from = 0; defined $len or $len = length($p) + length($s) - $from; unless (defined $ket) { warn 'bug in Term::ReadLine::Perl, please report to its author cpan@ilyaz.org'; $ket = ''; } # We may draw over to put cursor in a correct position: $ket = '' if $len < length($p) + length($s) - $from; # Not redrawn if ($from >= $lp) { $p = ''; $s = substr $s, $from - $lp; $lp = 0; } else { $p = substr $p, $from; $lp -= $from; $from = 0; } $s = substr $s, 0, $len - $lp; $p =~ s/^(\s*)//; my $bs = $1; $p =~ s/(\s*)$//; my $as = $1; $p = $rl_term_set->[0] . $p . $rl_term_set->[1] if length $p; $p = "$bs$p$as"; $ket = chop $s if $ket; if (defined $bsel and $bsel != $esel) { $bsel = $len if $bsel > $len; $esel = $len if $esel > $len; } if (defined $bsel and $bsel != $esel) { get_ornaments_selected; $bsel -= $lp; $esel -= $lp; my ($pre, $sel, $post) = (substr($s, 0, $bsel), substr($s, $bsel, $esel-$bsel), substr($s, $esel)); $pre = $rl_term_set->[2] . $pre . $rl_term_set->[3] if length $pre; $sel = $rl_term_set->[4] . $sel . $rl_term_set->[5] if length $sel; $post = $rl_term_set->[2] . $post . $rl_term_set->[3] if length $post; $s = "$pre$sel$post" } else { $s = $rl_term_set->[2] . $s . $rl_term_set->[3] if length $s; } if (!$lp) { # Should not happen... return $s; } elsif (!length $s) { # Should not happen return $p; } else { # Do not underline spaces in the prompt return "$p$s" . (length $ket ? ($rl_term_set->[0] . $ket . $rl_term_set->[1]) : ''); } } sub redisplay_high { get_ornaments_selected(); @$rl_term_set[2,3,4,5] = @$rl_term_set[4,5,2,3]; &redisplay(); ## Show the line, default inverted. @$rl_term_set[2,3,4,5] = @$rl_term_set[4,5,2,3]; $force_redraw = 1; } ## ## redisplay() ## ## Updates the screen to reflect the current $line. ## ## For the purposes of this routine, we prepend the prompt to a local copy of ## $line so that we display the prompt as well. We then modify it to reflect ## that some characters have different sizes (i.e. control-C is represented ## as ^C, tabs are expanded, etc.) ## ## This routine is somewhat complicated by two-byte characters.... must ## make sure never to try do display just half of one. ## ## NOTE: If an argument is given, it is used instead of the prompt. ## ## This is some nasty code. ## sub redisplay { ## local $line has prompt also; take that into account with $D. local($prompt) = defined($_[0]) ? $_[0] : $prompt; my ($thislen, $have_bra); my($dline) = $prompt . $line; local($D) = $D + length($prompt); my ($bsel, $esel); if (defined pos $line) { $bsel = (pos $line) + length $prompt; } my ($have_ket) = ''; ## ## If the line contains anything that might require special processing ## for displaying (such as tabs, control characters, etc.), we will ## take care of that now.... ## if ($dline =~ m/[^\x20-\x7e]/) { local($new, $Dinc, $c) = ('', 0); ## Look at each character of $dline in turn..... for ($i = 0; $i < length($dline); $i++) { $c = substr($dline, $i, 1); ## A tab to expand... if ($c eq "\t") { $c = ' ' x (8 - (($i-length($prompt)) % 8)); ## A control character.... } elsif ($c =~ tr/\000-\037//) { $c = sprintf("^%c", ord($c)+ord('@')); ## the delete character.... } elsif (ord($c) == 127) { $c = '^?'; } $new .= $c; ## Bump over $D if this char is expanded and left of $D. $Dinc += length($c) - 1 if (length($c) > 1 && $i < $D); ## Bump over $bsel if this char is expanded and left of $bsel. $bsel += length($c) - 1 if (defined $bsel && length($c) > 1 && $i < $bsel); } $dline = $new; $D += $Dinc; } ## ## Now $dline is what we'd like to display (with a prepended prompt) ## $D is the position of the cursor on it. ## ## If it's too long to fit on the line, we must decide what we can fit. ## ## If we end up moving the screen index ($si) [index of the leftmost ## character on the screen], to some place other than the front of the ## the line, we'll have to make sure that it's not on the first byte of ## a 2-byte character, 'cause we'll be placing a '<' marker there, and ## that would screw up the 2-byte character. ## ## $si is preserved between several displays (if possible). ## ## Similarly, if the line needs chopped off, we make sure that the ## placement of the tailing '>' won't screw up any 2-byte character in ## the vicinity. # Now $si keeps the value from previous display if ($D == length($prompt) # If prompts fits exactly, show only if need not show trailing '>' and length($prompt) < $rl_screen_width - (0 != length $dline)) { $si = 0; ## prefer displaying the whole prompt } elsif ($si >= $D) { # point to the left of what was displayed $si = &max(0, $D - $rl_margin); $si-- if $si > 0 && $si != length($prompt) && !&OnSecondByte($si); } elsif ($si + $rl_screen_width <= $D) { # Point to the right of ... $si = &min(length($dline), ($D - $rl_screen_width) + $rl_margin); $si-- if $si > 0 && $si != length($prompt) && !&OnSecondByte($si); } elsif (length($dline) - $si < $rl_screen_width - $rl_margin and $si) { # Too little of the line shown $si = &max(0, length($dline) - $rl_screen_width + 3); $si-- if $si > 0 && $si != length($prompt) && !&OnSecondByte($si); } else { ## Fine as-is.... don't need to change $si. } $have_bra = 1 if $si != 0; # Need the "chopped-off" marker $thislen = &min(length($dline) - $si, $rl_screen_width); if ($si + $thislen < length($dline)) { ## need to place a '>'... make sure to place on first byte. $thislen-- if &OnSecondByte($si+$thislen-1); substr($dline, $si+$thislen-1,1) = '>'; $have_ket = 1; } ## ## Now know what to display. ## Must get substr($dline, $si, $thislen) on the screen, ## with the cursor at $D-$si characters from the left edge. ## $dline = substr($dline, $si, $thislen); $delta = $D - $si; ## delta is cursor distance from beginning of $dline. if (defined $bsel) { # Highlight the selected part $bsel -= $si; $esel = $delta; ($bsel, $esel) = ($esel, $bsel) if $bsel > $esel; $bsel = 0 if $bsel < 0; if ($have_ket) { $esel = $thislen - 1 if $esel > $thislen - 1; } else { $esel = $thislen if $esel > $thislen; } } if ($si >= length($prompt)) { # Keep $dline for $lastredisplay... $prompt = ($have_bra ? "<" : ""); $dline = substr $dline, 1; # After prompt $bsel = 1 if defined $bsel and $bsel == 0; } else { $dline = substr($dline, (length $prompt) - $si); $prompt = substr($prompt,$si); substr($prompt, 0, 1) = '<' if $si > 0; } # Now $dline is the part after the prompt... ## ## Now must output $dline, with cursor $delta spaces from left of TTY ## local ($\, $,) = ('',''); ## ## If $force_redraw is not set, we can attempt to optimize the redisplay ## However, if we don't happen to find an easy way to optimize, we just ## fall through to the brute-force method of re-drawing the whole line. ## if (not $force_redraw and not defined $bsel) { ## can try to optimize here a bit. ## For when we only need to move the cursor if ($lastredisplay eq $dline and $lastpromptlen == length $prompt) { ## If we need to move forward, just overwrite as far as we need. if ($lastdelta < $delta) { print $term_OUT substr_with_props($prompt, $dline, $lastdelta, $delta-$lastdelta, $have_ket); ## Need to move back. } elsif($lastdelta > $delta) { ## Two ways to move back... use the fastest. One is to just ## backspace the proper amount. The other is to jump to the ## the beginning of the line and overwrite from there.... my $out = substr_with_props($prompt, $dline, 0, $delta, $have_ket); if ($lastdelta - $delta <= length $out) { print $term_OUT "\b" x ($lastdelta - $delta); } else { print $term_OUT "\r", $out; } } ($lastlen, $lastredisplay, $lastdelta, $lastpromptlen) = ($thislen, $dline, $delta, length $prompt); # print $term_OUT "\a"; # Debugging return; } ## for when we've just added stuff to the end if ($thislen > $lastlen && $lastdelta == $lastlen && $delta == $thislen && $lastpromptlen == length($prompt) && substr($dline, 0, $lastlen - $lastpromptlen) eq $lastredisplay) { print $term_OUT substr_with_props($prompt, $dline, $lastdelta, undef, $have_ket); # print $term_OUT "\a"; # Debugging ($lastlen, $lastredisplay, $lastdelta, $lastpromptlen) = ($thislen, $dline, $delta, length $prompt); return; } ## There is much more opportunity for optimizing..... ## something to work on later..... } ## ## Brute force method of redisplaying... redraw the whole thing. ## print $term_OUT "\r", substr_with_props($prompt, $dline, 0, undef, $have_ket, $bsel, $esel); my $back = length ($dline) + length ($prompt) - $delta; $back += $lastlen - $thislen, print $term_OUT ' ' x ($lastlen - $thislen) if $lastlen > $thislen; if ($back) { my $out = substr_with_props($prompt, $dline, 0, $delta, $have_ket, $bsel, $esel); if ($back <= length $out and not defined $bsel) { print $term_OUT "\b" x $back; } else { print $term_OUT "\r", $out; } } ($lastlen, $lastredisplay, $lastdelta, $lastpromptlen) = ($thislen, $dline, $delta, length $prompt); $force_redraw = 0; } sub min { $_[0] < $_[1] ? $_[0] : $_[1]; } sub getc_with_pending { my $key = @Pending ? shift(@Pending) : &$rl_getc; # Save keystrokes for vi '.' command push(@$Dot_buf, $key) if $Dot_buf; $key; } sub rl_getc { my $key; # JP: Added missing declaration if (defined $term_readkey) { # XXXX ??? $Term::ReadLine::Perl::term->Tk_loop if $Term::ReadLine::toloop && defined &Tk::DoOneEvent; $key = Term::ReadKey::ReadKey(0, $term_IN); } else { $key = $Term::ReadLine::Perl::term->get_c; } } ## ## get_command(keymap, ord_command_char) ## ## If the KEYMAP has an entry for COMMAND, it is returned. ## Otherwise, the default command is returned. ## sub get_command { local *KeyMap = shift; my ($key) = @_; my $cmd = defined($KeyMap[$key]) ? $KeyMap[$key] : ($KeyMap{'default'} || 'F_Ding'); if (!defined($cmd) || $cmd eq ''){ warn "internal error (key=$key)"; $cmd = 'F_Ding'; } $cmd } ## ## do_command(keymap, numericarg, command) ## ## If the KEYMAP has an entry for COMMAND, it is executed. ## Otherwise, the default command for the keymap is executed. ## sub do_command { my ($keymap, $count, $key) = @_; my $cmd = get_command($keymap, $key); local *KeyMap = $keymap; # &$cmd may expect it... &$cmd($count, $key); $lastcommand = $cmd; } ## ## Save whatever state we wish to save as an anonymous array. ## The only other function that needs to know about its encoding is getstate/preserve_state. ## sub savestate { [$D, $si, $LastCommandKilledText, $KillBuffer, $line, @_]; } # consolidate only-movement changes together... sub preserve_state { return if $Vi_mode; push(@undo, savestate()), return unless @undo; my $last = $undo[-1]; my @only_movement; if ( #$last->[1] == $si and $last->[2] eq $LastCommandKilledText # and $last->[3] eq $KillBuffer and $last->[4] eq $line ) { # Only position changed; remove old only-position-changed records pop @undo if $undo[-1]->[5]; @only_movement = 1; } push(@undo, savestate(@only_movement)); } ## ## $_[1] is an ASCII ordinal; inserts as per $count. ## sub F_SelfInsert { remove_selection(); my ($count, $ord) = @_; my $text2add = pack('C', $ord) x $count; if ($InsertMode) { substr($line,$D,0) .= $text2add; } else { ## note: this can screw up with 2-byte characters. substr($line,$D,length($text2add)) = $text2add; } $D += length($text2add); } ## ## Return the line as-is to the user. ## sub F_AcceptLine { &add_line_to_history; $AcceptLine = $line; local $\ = ''; print $term_OUT "\r\n"; $force_redraw = 0; (pos $line) = undef; # Another way to force redraw... } sub add_line_to_history { ## Insert into history list if: ## * bigger than the minimal length ## * not same as last entry ## if (length($line) >= $minlength && (!@rl_History || $rl_History[$#rl_History] ne $line) ) { ## if the history list is full, shift out an old one first.... while (@rl_History >= $rl_MaxHistorySize) { shift(@rl_History); $rl_HistoryIndex--; } push(@rl_History, $line); ## tack new one on the end } } sub remove_selection { if ( $rl_first_char && length $line && $rl_default_selected ) { $line = ''; $D = 0; return 1; } if ($rl_delete_selection and defined pos $line and $D != pos $line) { kill_text(pos $line, $D); return 1; } return; } #sub F_ReReadInitFile; #sub rl_getc; sub F_ForwardChar; sub F_BackwardChar; sub F_BeginningOfLine; sub F_EndOfLine; sub F_ForwardWord; sub F_BackwardWord; sub F_RedrawCurrentLine; sub F_ClearScreen; # sub F_SelfInsert; sub F_QuotedInsert; sub F_TabInsert; #sub F_AcceptLine; sub F_OperateAndGetNext; sub F_BackwardDeleteChar; sub F_DeleteChar; sub F_UnixWordRubout; sub F_UnixLineDiscard; sub F_UpcaseWord; sub F_DownCaseWord; sub F_CapitalizeWord; sub F_TransposeWords; sub F_TransposeChars; sub F_PreviousHistory; sub F_NextHistory; sub F_BeginningOfHistory; sub F_EndOfHistory; sub F_ReverseSearchHistory; sub F_ForwardSearchHistory; sub F_HistorySearchBackward; sub F_HistorySearchForward; sub F_KillLine; sub F_BackwardKillLine; sub F_Yank; sub F_YankPop; sub F_YankNthArg; sub F_KillWord; sub F_BackwardKillWord; sub F_Abort; sub F_DoLowercaseVersion; sub F_DoMetaVersion; sub F_DoControlVersion; sub F_Undo; sub F_RevertLine; sub F_EmacsEditingMode; sub F_Interrupt; sub F_PrefixMeta; sub F_UniversalArgument; sub F_DigitArgument; sub F_OverwriteMode; sub F_InsertMode; sub F_ToggleInsertMode; sub F_Suspend; sub F_Ding; sub F_PossibleCompletions; sub F_Complete; sub F_YankClipboard; sub F_CopyRegionAsKillClipboard; sub F_KillRegionClipboard; sub clipboard_set; sub F_BeginUndoGroup; sub F_EndUndoGroup; sub F_DoNothing; sub F_ForceMemorizeDigitArgument; sub F_MemorizeDigitArgument; sub F_UnmemorizeDigitArgument; sub F_ResetDigitArgument; sub F_MergeInserts; sub F_MemorizePos; sub F_BeginPasteGroup; sub F_EndPasteGroup; sub F_BeginEditGroup; sub F_EndEditGroup; # Comment next line and __DATA__ line below to disable the selfloader. #use SelfLoader; 1; #__DATA__ # From here on anything may be autoloaded sub max { $_[0] > $_[1] ? $_[0] : $_[1]; } sub isupper { ord($_[0]) >= ord('A') && ord($_[0]) <= ord('Z'); } sub islower { ord($_[0]) >= ord('a') && ord($_[0]) <= ord('z'); } sub toupper { &islower ? pack('c', ord($_[0])-ord('a')+ord('A')) : $_[0];} sub tolower { &isupper ? pack('c', ord($_[0])-ord('A')+ord('a')) : $_[0];} ## ## rl_set(var_name, value_string) ## ## Sets the named variable as per the given value, if both are appropriate. ## Allows the user of the package to set such things as HorizontalScrollMode ## and EditingMode. Value_string may be of the form ## HorizontalScrollMode ## horizontal-scroll-mode ## ## Also called during the parsing of ~/.inputrc for "set var value" lines. ## ## The previous value is returned, or undef on error. ########################################################################### ## Consider the following example for how to add additional variables ## accessible via rl_set (and hence via ~/.inputrc). ## ## Want: ## We want an external variable called "FooTime" (or "foo-time"). ## It may have values "January", "Monday", or "Noon". ## Internally, we'll want those values to translate to 1, 2, and 12. ## ## How: ## Have an internal variable $var_FooTime that will represent the current ## internal value, and initialize it to the default value. ## Make an array %var_FooTime whose keys and values are are the external ## (January, Monday, Noon) and internal (1, 2, 12) values: ## ## $var_FooTime = $var_FooTime{'January'} = 1; #default ## $var_FooTime{'Monday'} = 2; ## $var_FooTime{'Noon'} = 12; ## sub rl_set { local($var, $val) = @_; # &preinit's keys are all Capitalized $val = ucfirst lc $val if $val =~ /^(on|off)$/i; $var = 'CompleteAddsuffix' if $var eq 'visible-stats'; ## if the variable is in the form "some-name", change to "SomeName" local($_) = "\u$var"; local($return) = undef; s/-(.)/\u$1/g; # Skip unknown variables: return unless defined $ {'readline::'}{"var_$_"}; local(*V); # avoid warning { local $^W; *V = $ {'readline::'}{"var_$_"}; } if (!defined($V)) { # XXX Duplicate check? warn("Warning$InputLocMsg:\n". " Invalid variable `$var'\n") if $^W; } elsif (!defined($V{$val})) { local(@selections) = keys(%V); warn("Warning$InputLocMsg:\n". " Invalid value `$val' for variable `$var'.\n". " Choose from [@selections].\n") if $^W; } else { $return = $V; $V = $V{$val}; ## make the setting } $return; } ## ## OnSecondByte($index) ## ## Returns true if the byte at $index into $line is the second byte ## of a two-byte character. ## sub OnSecondByte { return 0 if !$_rl_japanese_mb || $_[0] == 0 || $_[0] == length($line); die 'internal error' if $_[0] > length($line); ## ## must start looking from the beginning of the line .... can ## have one- and two-byte characters interspersed, so can't tell ## without starting from some know location..... ## local($i); for ($i = 0; $i < $_[0]; $i++) { next if ord(substr($line, $i, 1)) < 0x80; ## We have the first byte... must bump up $i to skip past the 2nd. ## If that one we're skipping past is the index, it should be changed ## to point to the first byte of the pair (therefore, decremented). return 1 if ++$i == $_[0]; } 0; ## seemed to be OK. } ## ## CharSize(index) ## ## Returns the size of the character at the given INDEX in the ## current line. Most characters are just one byte in length, ## but if the byte at the index and the one after has the high ## bit set those two bytes are one character of size=2. ## ## Assumes that index points to the first of a 2-byte char if not ## pointing to a 2-byte char. ## sub CharSize { return 2 if $_rl_japanese_mb && ord(substr($line, $_[0], 1)) >= 0x80 && ord(substr($line, $_[0]+1, 1)) >= 0x80; 1; } sub GetTTY { $base_termios = $termios; # make it long enough &ioctl($term_IN,$TCGETS,$base_termios) || die "Can't ioctl TCGETS: $!"; } sub XonTTY { # I don't know which of these I actually need to do this to, so we'll # just cover all bases. &ioctl($term_IN,$TCXONC,$TCOON); # || die "Can't ioctl TCXONC STDIN: $!"; &ioctl($term_OUT,$TCXONC,$TCOON); # || die "Can't ioctl TCXONC STDOUT: $!"; } sub ___SetTTY { # print "before SetTTY\n\r"; # system 'stty -a'; &XonTTY; &GetTTY if !defined($base_termios); @termios = unpack($termios_t,$base_termios); $termios[$TERMIOS_IFLAG] |= $TERMIOS_READLINE_ION; $termios[$TERMIOS_IFLAG] &= ~$TERMIOS_READLINE_IOFF; $termios[$TERMIOS_OFLAG] |= $TERMIOS_READLINE_OON; $termios[$TERMIOS_OFLAG] &= ~$TERMIOS_READLINE_OOFF; $termios[$TERMIOS_LFLAG] |= $TERMIOS_READLINE_LON; $termios[$TERMIOS_LFLAG] &= ~$TERMIOS_READLINE_LOFF; $termios[$TERMIOS_VMIN] = 1; $termios[$TERMIOS_VTIME] = 0; $termios = pack($termios_t,@termios); &ioctl($term_IN,$TCSETS,$termios) || die "Can't ioctl TCSETS: $!"; # print "after SetTTY\n\r"; # system 'stty -a'; } sub normal_tty_mode { return if $stdin_not_tty || $dumb_term || !$initialized; &XonTTY; &GetTTY if !defined($base_termios); &ResetTTY; } sub ___ResetTTY { # print "before ResetTTY\n\r"; # system 'stty -a'; @termios = unpack($termios_t,$base_termios); $termios[$TERMIOS_IFLAG] |= $TERMIOS_NORMAL_ION; $termios[$TERMIOS_IFLAG] &= ~$TERMIOS_NORMAL_IOFF; $termios[$TERMIOS_OFLAG] |= $TERMIOS_NORMAL_OON; $termios[$TERMIOS_OFLAG] &= ~$TERMIOS_NORMAL_OOFF; $termios[$TERMIOS_LFLAG] |= $TERMIOS_NORMAL_LON; $termios[$TERMIOS_LFLAG] &= ~$TERMIOS_NORMAL_LOFF; $termios = pack($termios_t,@termios); &ioctl($term_IN,$TCSETS,$termios) || die "Can't ioctl TCSETS: $!"; # print "after ResetTTY\n\r"; # system 'stty -a'; } ## ## WordBreak(index) ## ## Returns true if the character at INDEX into $line is a basic word break ## character, false otherwise. ## sub WordBreak { index($rl_basic_word_break_characters, substr($line,$_[0],1)) != -1; } sub getstate { ($D, $si, $LastCommandKilledText, $KillBuffer, $line) = @{$_[0]}; $ThisCommandKilledText = $LastCommandKilledText; } ## ## kills from D=$_[0] to $_[1] (to the killbuffer if $_[2] is true) ## sub kill_text { my($from, $to, $save) = (&min($_[0], $_[1]), &max($_[0], $_[1]), $_[2]); my $len = $to - $from; if ($save) { $KillBuffer = '' if !$LastCommandKilledText; if ($from < $LastCommandKilledText - 1) { $KillBuffer = substr($line, $from, $len) . $KillBuffer; } else { $KillBuffer .= substr($line, $from, $len); } $ThisCommandKilledText = 1 + $from; } substr($line, $from, $len) = ''; ## adjust $D if ($D > $from) { $D -= $len; $D = $from if $D < $from; } } ########################################################################### ## Bindable functions... pretty much in the same order as in readline.c ### ########################################################################### ## ## Returns true if $D at the end of the line. ## sub at_end_of_line { ($D + &CharSize($D)) == (length($line) + 1); } ## ## Move forward (right) $count characters. ## sub F_ForwardChar { my $count = shift; return &F_BackwardChar(-$count) if $count < 0; while (!&at_end_of_line && $count-- > 0) { $D += &CharSize($D); } } ## ## Move backward (left) $count characters. ## sub F_BackwardChar { my $count = shift; return &F_ForwardChar(-$count) if $count < 0; while (($D > 0) && ($count-- > 0)) { $D--; ## Move back one regardless, $D-- if &OnSecondByte($D); ## another if over a big char. } } ## ## Go to beginning of line. ## sub F_BeginningOfLine { $D = 0; } ## ## Move to the end of the line. ## sub F_EndOfLine { &F_ForwardChar(100) while !&at_end_of_line; } ## ## Move to the end of this/next word. ## Done as many times as $count says. ## sub F_ForwardWord { my $count = shift; return &F_BackwardWord(-$count) if $count < 0; while (!&at_end_of_line && $count-- > 0) { ## skip forward to the next word (if not already on one) &F_ForwardChar(1) while !&at_end_of_line && &WordBreak($D); ## skip forward to end of word &F_ForwardChar(1) while !&at_end_of_line && !&WordBreak($D); } } ## ## ## Move to the beginning of this/next word. ## Done as many times as $count says. ## sub F_BackwardWord { my $count = shift; return &F_ForwardWord(-$count) if $count < 0; while ($D > 0 && $count-- > 0) { ## skip backward to the next word (if not already on one) &F_BackwardChar(1) while (($D > 0) && &WordBreak($D-1)); ## skip backward to start of word &F_BackwardChar(1) while (($D > 0) && !&WordBreak($D-1)); } } ## ## Refresh the input line. ## sub F_RedrawCurrentLine { $force_redraw = 1; } ## ## Clear the screen and refresh the line. ## If given a numeric arg other than 1, simply refreshes the line. ## sub F_ClearScreen { my $count = shift; return &F_RedrawCurrentLine if $count != 1; $rl_CLEAR = `clear` if !defined($rl_CLEAR); local $\ = ''; print $term_OUT $rl_CLEAR; $force_redraw = 1; } ## ## Insert the next character read verbatim. ## sub F_QuotedInsert { my $count = shift; &F_SelfInsert($count, ord(&getc_with_pending)); } ## ## Insert a tab. ## sub F_TabInsert { my $count = shift; &F_SelfInsert($count, ord("\t")); } ## Operate - accept the current line and fetch from the ## history the next line relative to current line for default. sub F_OperateAndGetNext { my $count = shift; &F_AcceptLine; my $remainingEntries = $#rl_History - $rl_HistoryIndex; if ($count > 0 && $remainingEntries >= 0) { # there is something to repeat if ($remainingEntries > 0) { # if we are not on last line $rl_HistoryIndex++; # fetch next one $count = $remainingEntries if $count > $remainingEntries; } $rl_OperateCount = $count; } } ## ## Removes $count chars to left of cursor (if not at beginning of line). ## If $count > 1, deleted chars saved to kill buffer. ## sub F_BackwardDeleteChar { return if remove_selection(); my $count = shift; return F_DeleteChar(-$count) if $count < 0; my $oldD = $D; &F_BackwardChar($count); return if $D == $oldD; &kill_text($oldD, $D, $count > 1); } ## ## Removes the $count chars from under the cursor. ## If there is no line and the last command was different, tells ## readline to return EOF. ## If there is a line, and the cursor is at the end of it, and we're in ## tcsh completion mode, then list possible completions. ## If $count > 1, deleted chars saved to kill buffer. ## sub F_DeleteChar { return if remove_selection(); my $count = shift; return F_DeleteBackwardChar(-$count) if $count < 0; if (length($line) == 0) { # EOF sent (probably OK in DOS too) $AcceptLine = $ReturnEOF = 1 if $lastcommand ne 'F_DeleteChar'; return; } if ($D == length ($line)) { &complete_internal('?') if $var_TcshCompleteMode; return; } my $oldD = $D; &F_ForwardChar($count); return if $D == $oldD; &kill_text($oldD, $D, $count > 1); } ## ## Kill to previous whitespace. ## sub F_UnixWordRubout { return &F_Ding if $D == 0; (my $oldD, local $rl_basic_word_break_characters) = ($D, "\t "); # JP: Fixed a bug here - both were 'my' F_BackwardWord(1); kill_text($D, $oldD, 1); } ## ## Kill line from cursor to beginning of line. ## sub F_UnixLineDiscard { return &F_Ding if $D == 0; kill_text(0, $D, 1); } sub F_UpcaseWord { &changecase($_[0], 'up'); } sub F_DownCaseWord { &changecase($_[0], 'down'); } sub F_CapitalizeWord { &changecase($_[0], 'cap'); } ## ## Translated from GNUs readline.c ## One arg is 'up' to upcase $_[0] words, ## 'down' to downcase them, ## or something else to capitolize them. ## If $_[0] is negative, the dot is not moved. ## sub changecase { my $op = $_[1]; my ($start, $state, $c, $olddot) = ($D, 0); if ($_[0] < 0) { $olddot = $D; $_[0] = -$_[0]; } &F_ForwardWord; ## goes forward $_[0] words. while ($start < $D) { $c = substr($line, $start, 1); if ($op eq 'up') { $c = &toupper($c); } elsif ($op eq 'down') { $c = &tolower($c); } else { ## must be 'cap' if ($state == 1) { $c = &tolower($c); } else { $c = &toupper($c); $state = 1; } $state = 0 if $c !~ tr/a-zA-Z//; } substr($line, $start, 1) = $c; $start++; } $D = $olddot if defined($olddot); } sub F_TransposeWords { my $c = shift; return F_Ding() unless $c; # Find "this" word F_BackwardWord(1); my $p0 = $D; F_ForwardWord(1); my $p1 = $D; return F_Ding() if $p1 == $p0; my ($p2, $p3) = ($p0, $p1); if ($c > 0) { F_ForwardWord($c); $p3 = $D; F_BackwardWord(1); $p2 = $D; } else { F_BackwardWord(1 - $c); $p0 = $D; F_ForwardWord(1); $p1 = $D; } return F_Ding() if $p3 == $p2 or $p2 < $p1; my $r = substr $line, $p2, $p3 - $p2; substr($line, $p2, $p3 - $p2) = substr $line, $p0, $p1 - $p0; substr($line, $p0, $p1 - $p0) = $r; $D = $c > 0 ? $p3 : $p0 + $p3 - $p2; # End of "this" word after edit return 1; ## Exchange words: C-Left, C-right, C-right, C-left. If positions do ## not overlap, we get two things to transpose. Repeat count? } ## ## Switch char at dot with char before it. ## If at the end of the line, switch the previous two... ## (NOTE: this could screw up multibyte characters.. should do correctly) sub F_TransposeChars { if ($D == length($line) && $D >= 2) { substr($line,$D-2,2) = substr($line,$D-1,1).substr($line,$D-2,1); } elsif ($D >= 1) { substr($line,$D-1,2) = substr($line,$D,1) .substr($line,$D-1,1); } else { &F_Ding; } } sub F_PreviousHistory { &get_line_from_history($rl_HistoryIndex - shift); } sub F_NextHistory { &get_line_from_history($rl_HistoryIndex + shift); } sub F_BeginningOfHistory { &get_line_from_history(0); } sub F_EndOfHistory { &get_line_from_history(@rl_History); } sub F_ReverseSearchHistory { &DoSearch($_[0] >= 0 ? 1 : 0); } sub F_ForwardSearchHistory { &DoSearch($_[0] >= 0 ? 0 : 1); } sub F_HistorySearchBackward { &DoSearchStart(($_[0] >= 0 ? 1 : 0),substr($line,0,$D)); } sub F_HistorySearchForward { &DoSearchStart(($_[0] >= 0 ? 0 : 1),substr($line,0,$D)); } ## returns a new $i or -1 if not found. sub search { my ($i, $str) = @_; return -1 if $i < 0 || $i > $#rl_History; ## for safety while (1) { return $i if rindex($rl_History[$i], $str) >= 0; if ($reverse) { return -1 if $i-- == 0; } else { return -1 if $i++ == $#rl_History; } } } sub DoSearch { local $reverse = shift; # Used in search() my $oldline = $line; my $oldD = $D; my $searchstr = ''; ## string we're searching for my $I = -1; ## which history line $si = 0; while (1) { if ($I != -1) { $line = $rl_History[$I]; $D += index($rl_History[$I], $searchstr); } &redisplay( '('.($reverse?'reverse-':'') ."i-search) `$searchstr': "); $c = &getc_with_pending; if (($KeyMap[ord($c)] || 0) eq 'F_ReverseSearchHistory') { if ($reverse && $I != -1) { if ($tmp = &search($I-1,$searchstr), $tmp >= 0) { $I = $tmp; } else { &F_Ding; } } $reverse = 1; } elsif (($KeyMap[ord($c)] || 0) eq 'F_ForwardSearchHistory') { if (!$reverse && $I != -1) { if ($tmp = &search($I+1,$searchstr), $tmp >= 0) { $I = $tmp; } else { &F_Ding; } } $reverse = 0; } elsif ($c eq "\007") { ## abort search... restore line and return $line = $oldline; $D = $oldD; return; } elsif (ord($c) < 32 || ord($c) > 126) { push(@Pending, $c) if $c ne "\e"; if ($I < 0) { ## just restore $line = $oldline; $D = $oldD; } else { #chose this line $line = $rl_History[$I]; $D = index($rl_History[$I], $searchstr); } &redisplay(); last; } else { ## Add this character to the end of the search string and ## see if that'll match anything. $tmp = &search($I < 0 ? $rl_HistoryIndex-$reverse: $I, $searchstr.$c); if ($tmp == -1) { &F_Ding; } else { $searchstr .= $c; $I = $tmp; } } } } ## returns a new $i or -1 if not found. sub searchStart { my ($i, $reverse, $str) = @_; $i += $reverse ? - 1: +1; return -1 if $i < 0 || $i > $#rl_History; ## for safety while (1) { return $i if index($rl_History[$i], $str) == 0; if ($reverse) { return -1 if $i-- == 0; } else { return -1 if $i++ == $#rl_History; } } } sub DoSearchStart { my ($reverse,$what) = @_; my $i = searchStart($rl_HistoryIndex, $reverse, $what); return if $i == -1; $rl_HistoryIndex = $i; ($D, $line) = (0, $rl_History[$rl_HistoryIndex]); F_BeginningOfLine(); F_ForwardChar(length($what)); } ########################################################################### ########################################################################### ## ## Kill from cursor to end of line. ## sub F_KillLine { my $count = shift; return F_BackwardKillLine(-$count) if $count < 0; kill_text($D, length($line), 1); } ## ## Delete from cursor to beginning of line. ## sub F_BackwardKillLine { my $count = shift; return F_KillLine(-$count) if $count < 0; return F_Ding if $D == 0; kill_text(0, $D, 1); } ## ## TextInsert(count, string) ## sub TextInsert { my $count = shift; my $text2add = shift(@_) x $count; if ($InsertMode) { substr($line,$D,0) .= $text2add; } else { substr($line,$D,length($text2add)) = $text2add; } $D += length($text2add); } sub F_Yank { remove_selection(); &TextInsert($_[0], $KillBuffer); } sub F_YankPop { 1; ## not implemented yet } sub F_YankNthArg { 1; ## not implemented yet } ## ## Kill to the end of the current word. If not on a word, kill to ## the end of the next word. ## sub F_KillWord { my $count = shift; return &F_BackwardKillWord(-$count) if $count < 0; my $oldD = $D; &F_ForwardWord($count); ## moves forward $count words. kill_text($oldD, $D, 1); } ## ## Kill backward to the start of the current word, or, if currently ## not on a word (or just at the start of a word), to the start of the ## previous word. ## sub F_BackwardKillWord { my $count = shift; return F_KillWord(-$count) if $count < 0; my $oldD = $D; &F_BackwardWord($count); ## moves backward $count words. kill_text($D, $oldD, 1); } ########################################################################### ########################################################################### ## ## Abort the current input. ## sub F_Abort { &F_Ding; } ## ## If the character that got us here is upper case, ## do the lower-case equiv... ## sub F_DoLowercaseVersion { if ($_[1] >= ord('A') && $_[1] <= ord('Z')) { &do_command(*KeyMap, $_[0], $_[1] - ord('A') + ord('a')); } else { &F_Ding; } } ## ## do the equiv with control key... ## sub F_DoControlVersion { local *KeyMap = $var_EditingMode; my $key = $_[1]; if ($key == ord('?')) { $key = 0x7F; } else { $key &= ~(0x80 | 0x60); } &do_command(*KeyMap, $_[0], $key); } ## ## do the equiv with meta key... ## sub F_DoMetaVersion { local *KeyMap = $var_EditingMode; unshift @Pending, chr $_[1]; &do_command(*KeyMap, $_[0], ord "\e"); } ## ## If the character that got us here is Alt-Char, ## do the Esc Char equiv... ## sub F_DoEscVersion { my ($ord, $t) = $_[1]; &F_Ding unless $KeyMap{'Esc'}; for $t (([ord 'w', '`1234567890-='], [ord ',', 'zxcvbnm,./\\'], [16, 'qwertyuiop[]'], [ord(' ') - 2, 'asdfghjkl;\''])) { next unless $ord >= $t->[0] and $ord < $t->[0] + length($t->[1]); $ord = ord substr $t->[1], $ord - $t->[0], 1; return &do_command($KeyMap{'Esc'}, $_[0], $ord); } &F_Ding; } ## ## Undo one level. ## sub F_Undo { pop(@undo); # unless $undo[-1]->[5]; ## get rid of the state we just put on, so we can go back one. if (@undo) { &getstate(pop(@undo)); } else { &F_Ding; } } ## ## Replace the current line to some "before" state. ## sub F_RevertLine { if ($rl_HistoryIndex >= $#rl_History+1) { $line = $line_for_revert; } else { $line = $rl_History[$rl_HistoryIndex]; } $D = length($line); } sub F_EmacsEditingMode { $var_EditingMode = $var_EditingMode{'emacs'}; $Vi_mode = 0; } ########################################################################### ########################################################################### ## ## (Attempt to) interrupt the current program. ## sub F_Interrupt { local $\ = ''; print $term_OUT "\r\n"; &ResetTTY; kill ("INT", 0); ## We're back.... must not have died. $force_redraw = 1; } ## ## Execute the next character input as a command in a meta keymap. ## sub F_PrefixMeta { my($count, $keymap) = ($_[0], "$KeyMap{'name'}_$_[1]"); ##print "F_PrefixMeta [$keymap]\n\r"; die "" unless %$keymap; do_command(*$keymap, $count, ord(&getc_with_pending)); } sub F_UniversalArgument { &F_DigitArgument; } ## ## For typing a numeric prefix to a command.... ## sub F_DigitArgument { my $in = chr $_[1]; my ($NumericArg, $sawDigit) = (1, 0); my ($increment, $ord); ($NumericArg, $sawDigit) = ($_[0], $_[0] !~ /e0$/i) if $doingNumArg; # XXX What if Esc-- 1 ? do { $ord = ord $in; if (defined($KeyMap[$ord]) && $KeyMap[$ord] eq 'F_UniversalArgument') { $NumericArg *= 4; } elsif ($ord == ord('-') && !$sawDigit) { $NumericArg = -$NumericArg; } elsif ($ord >= ord('0') && $ord <= ord('9')) { $increment = ($ord - ord('0')) * ($NumericArg < 0 ? -1 : 1); if ($sawDigit) { $NumericArg = $NumericArg * 10 + $increment; } else { $NumericArg = $increment; $sawDigit = 1; } } else { local(*KeyMap) = $var_EditingMode; &redisplay(); $doingNumArg = 1; # Allow NumArg inside NumArg &do_command(*KeyMap, $NumericArg . ($sawDigit ? '': 'e0'), $ord); return; } ## make sure it's not toooo big. if ($NumericArg > $rl_max_numeric_arg) { $NumericArg = $rl_max_numeric_arg; } elsif ($NumericArg < -$rl_max_numeric_arg) { $NumericArg = -$rl_max_numeric_arg; } &redisplay(sprintf("(arg %d) ", $NumericArg)); } while defined($in = &getc_with_pending); } sub F_OverwriteMode { $InsertMode = 0; } sub F_InsertMode { $InsertMode = 1; } sub F_ToggleInsertMode { $InsertMode = !$InsertMode; } ## ## (Attempt to) suspend the program. ## sub F_Suspend { if ($inDOS && length($line)==0) { # EOF sent $AcceptLine = $ReturnEOF = 1 if $lastcommand ne 'F_DeleteChar'; return; } local $\ = ''; print $term_OUT "\r\n"; &ResetTTY; eval { kill ("TSTP", 0) }; ## We're back.... &SetTTY; $force_redraw = 1; } ## ## Ring the bell. ## Should do something with $var_PreferVisibleBell here, but what? ## sub F_Ding { local $\ = ''; print $term_OUT "\007"; return; # Undefined return value } ########################################################################## #### command/file completion ############################################ ########################################################################## ## ## How Command Completion Works ## ## When asked to do a completion operation, readline isolates the word ## to the immediate left of the cursor (i.e. what's just been typed). ## This information is then passed to some function (which may be supplied ## by the user of this package) which will return an array of possible ## completions. ## ## If there is just one, that one is used. Otherwise, they are listed ## in some way (depends upon $var_TcshCompleteMode). ## ## The default is to do filename completion. The function that performs ## this task is readline'rl_filename_list. ## ## A minimal-trouble way to have command-completion is to call ## readline'rl_basic_commands with an array of command names, such as ## &readline'rl_basic_commands('quit', 'run', 'set', 'list') ## Those command names will then be used for completion if the word being ## completed begins the line. Otherwise, completion is disallowed. ## ## The way to have the most power is to provide a function to readline ## which will accept information about a partial word that needs completed, ## and will return the appropriate list of possibilities. ## This is done by setting $readline'rl_completion_function to the name of ## the function to run. ## ## That function will be called with three args ($text, $line, $start). ## TEXT is the partial word that should be completed. LINE is the entire ## input line as it stands, and START is the index of the TEXT in LINE ## (i.e. zero if TEXT is at the beginning of LINE). ## ## A cool completion function will look at LINE and START and give context- ## sensitive completion lists. Consider something that will do completion ## for two commands ## cat FILENAME ## finger USERNAME ## status [this|that|other] ## ## It (untested) might look like: ## ## $readline'rl_completion_function = "main'complete"; ## sub complete { local($text, $_, $start) = @_; ## ## return commands which may match if at the beginning.... ## return grep(/^$text/, 'cat', 'finger') if $start == 0; ## return &rl_filename_list($text) if /^cat\b/; ## return &my_namelist($text) if /^finger\b/; ## return grep(/^text/, 'this', 'that','other') if /^status\b/; ## (); ## } ## Of course, a real completion function would be more robust, but you ## get the idea (I hope). ## ## ## List possible completions ## sub F_PossibleCompletions { &complete_internal('?'); } ## ## List possible completions ## sub F_InsertPossibleCompletions { &complete_internal('*'); } ## ## Do a completion operation. ## If the last thing we did was a completion operation, we'll ## now list the options available (under normal emacs mode). ## ## Under TcshCompleteMode, each contiguous subsequent completion operation ## lists another of the possible options. ## ## Returns true if a completion was done, false otherwise, so vi completion ## routines can test it. ## sub F_Complete { if ($lastcommand eq 'F_Complete') { if ($var_TcshCompleteMode && @tcsh_complete_selections > 0) { substr($line, $tcsh_complete_start, $tcsh_complete_len) = $tcsh_complete_selections[0]; $D -= $tcsh_complete_len; $tcsh_complete_len = length($tcsh_complete_selections[0]); $D += $tcsh_complete_len; push(@tcsh_complete_selections, shift(@tcsh_complete_selections)); } else { &complete_internal('?') or return; } } else { @tcsh_complete_selections = (); &complete_internal("\t") or return; } 1; } ## ## The meat of command completion. Patterned closely after GNU's. ## ## The supposedly partial word at the cursor is "completed" as per the ## single argument: ## "\t" complete as much of the word as is unambiguous ## "?" list possibilities. ## "*" replace word with all possibilities. (who would use this?) ## ## A few notable variables used: ## $rl_completer_word_break_characters ## -- characters in this string break a word. ## $rl_special_prefixes ## -- but if in this string as well, remain part of that word. ## ## Returns true if a completion was done, false otherwise, so vi completion ## routines can test it. ## sub complete_internal { my $what_to_do = shift; my ($point, $end) = ($D, $D); # In vi mode, complete if the cursor is at the *end* of a word, not # after it. ($point++, $end++) if $Vi_mode; if ($point) { ## Not at the beginning of the line; Isolate the word to be completed. 1 while (--$point && (-1 == index($rl_completer_word_break_characters, substr($line, $point, 1)))); # Either at beginning of line or at a word break. # If at a word break (that we don't want to save), skip it. $point++ if ( (index($rl_completer_word_break_characters, substr($line, $point, 1)) != -1) && (index($rl_special_prefixes, substr($line, $point, 1)) == -1) ); } my $text = substr($line, $point, $end - $point); $rl_completer_terminator_character = ' '; @matches = &completion_matches($rl_completion_function,$text,$line,$point); if (@matches == 0) { return &F_Ding; } elsif ($what_to_do eq "\t") { my $replacement = shift(@matches); $replacement .= $rl_completer_terminator_character if @matches == 1; &F_Ding if @matches != 1; if ($var_TcshCompleteMode) { @tcsh_complete_selections = (@matches, $text); $tcsh_complete_start = $point; $tcsh_complete_len = length($replacement); } if ($replacement ne '') { substr($line, $point, $end-$point) = $replacement; $D = $D - ($end - $point) + length($replacement); } } elsif ($what_to_do eq '?') { shift(@matches); ## remove prepended common prefix local $\ = ''; print $term_OUT "\n\r"; # print "@matches\n\r"; &pretty_print_list (@matches); $force_redraw = 1; } elsif ($what_to_do eq '*') { shift(@matches); ## remove common prefix. local $" = $rl_completer_terminator_character; my $replacement = "@matches$rl_completer_terminator_character"; substr($line, $point, $end-$point) = $replacement; ## insert all. $D = $D - ($end - $point) + length($replacement); } else { warn "\r\n[Internal error]"; return &F_Ding; } 1; } ## ## completion_matches(func, text, line, start) ## ## FUNC is a function to call as FUNC(TEXT, LINE, START) ## where TEXT is the item to be completed ## LINE is the whole command line, and ## START is the starting index of TEXT in LINE. ## The FUNC should return a list of items that might match. ## ## completion_matches will return that list, with the longest common ## prefix prepended as the first item of the list. Therefor, the list ## will either be of zero length (meaning no matches) or of 2 or more..... ## ## Works with &rl_basic_commands. Return items from @rl_basic_commands ## that start with the pattern in $text. sub use_basic_commands { my ($text, $line, $start) = @_; return () if $start != 0; grep(/^$text/, @rl_basic_commands); } sub completion_matches { my ($func, $text, $line, $start) = @_; ## get the raw list my @matches; #print qq/\r\neval("\@matches = &$func(\$text, \$line, \$start)\n\r/;#DEBUG #eval("\@matches = &$func(\$text, \$line, \$start);1") || warn "$@ "; @matches = &$func($text, $line, $start); ## if anything returned , find the common prefix among them if (@matches) { my $prefix = $matches[0]; my $len = length($prefix); for ($i = 1; $i < @matches; $i++) { next if substr($matches[$i], 0, $len) eq $prefix; $prefix = substr($prefix, 0, --$len); last if $len == 0; $i--; ## retry this one to see if the shorter one matches. } unshift(@matches, $prefix); ## make common prefix the first thing. } @matches; } ## ## For use in passing to completion_matches(), returns a list of ## filenames that begin with the given pattern. The user of this package ## can set $rl_completion_function to 'rl_filename_list' to restore the ## default of filename matching if they'd changed it earlier, either ## directly or via &rl_basic_commands. ## sub rl_filename_list { my $pattern = $_[0]; my @files = (<$pattern*>); if ($var_CompleteAddsuffix) { foreach (@files) { if (-l $_) { $_ .= '@'; } elsif (-d _) { $_ .= '/'; } elsif (-x _) { $_ .= '*'; } elsif (-S _ || -p _) { $_ .= '='; } } } return @files; } ## ## For use by the user of the package. Called with a list of possible ## commands, will allow command completion on those commands, but only ## for the first word on a line. ## For example: &rl_basic_commands('set', 'quit', 'type', 'run'); ## ## This is for people that want quick and simple command completion. ## A more thoughtful implementation would set $rl_completion_function ## to a routine that would look at the context of the word being completed ## and return the appropriate possibilities. ## sub rl_basic_commands { @rl_basic_commands = @_; $rl_completion_function = 'use_basic_commands'; } ## ## Print an array in columns like ls -C. Originally based on stuff ## (lsC2.pl) by utashiro@sran230.sra.co.jp (Kazumasa Utashiro). ## sub pretty_print_list { my @list = @_; return unless @list; my ($lines, $columns, $mark, $index); ## find width of widest entry my $maxwidth = 0; grep(length > $maxwidth && ($maxwidth = length), @list); $maxwidth++; $columns = $maxwidth >= $rl_screen_width ? 1 : int($rl_screen_width / $maxwidth); ## if there's enough margin to interspurse among the columns, do so. $maxwidth += int(($rl_screen_width % $maxwidth) / $columns); $lines = int((@list + $columns - 1) / $columns); $columns-- while ((($lines * $columns) - @list + 1) > $lines); $mark = $#list - $lines; local $\ = ''; for ($l = 0; $l < $lines; $l++) { for ($index = $l; $index <= $mark; $index += $lines) { printf("%-$ {maxwidth}s", $list[$index]); } print $term_OUT $list[$index] if $index <= $#list; print $term_OUT "\n\r"; } } ##----------------- Vi Routines -------------------------------- sub F_ViAcceptLine { &F_AcceptLine(); &F_ViInput(); } # Repeat the most recent one of these vi commands: # # a A c C d D i I p P r R s S x X ~ # sub F_ViRepeatLastCommand { my($count) = @_; return &F_Ding if !$Last_vi_command; my @lastcmd = @$Last_vi_command; # Multiply @lastcmd's numeric arg by $count. unless ($count == 1) { my $n = ''; while (@lastcmd and $lastcmd[0] =~ /^\d$/) { $n *= 10; $n += shift(@lastcmd); } $count *= $n unless $n eq ''; unshift(@lastcmd, split(//, $count)); } push(@Pending, @lastcmd); } sub F_ViMoveCursor { my($count, $ord) = @_; my $new_cursor = &get_position($count, $ord, undef, $Vi_move_patterns); return &F_Ding if !defined $new_cursor; $D = $new_cursor; } sub F_ViFindMatchingParens { # Move to the first parens at or after $D my $old_d = $D; &forward_scan(1, q/[^[\](){}]*/); my $parens = substr($line, $D, 1); my $mate_direction = { '(' => [ ')', 1 ], '[' => [ ']', 1 ], '{' => [ '}', 1 ], ')' => [ '(', -1 ], ']' => [ '[', -1 ], '}' => [ '{', -1 ], }->{$parens}; return &F_Ding() unless $mate_direction; my($mate, $direction) = @$mate_direction; my $lvl = 1; while ($lvl) { last if !$D && ($direction < 0); &F_ForwardChar($direction); last if &at_end_of_line; my $c = substr($line, $D, 1); if ($c eq $parens) { $lvl++; } elsif ($c eq $mate) { $lvl--; } } if ($lvl) { # We didn't find a match $D = $old_d; return &F_Ding(); } } sub F_ViForwardFindChar { &do_findchar(1, 1, @_); } sub F_ViBackwardFindChar { &do_findchar(-1, 0, @_); } sub F_ViForwardToChar { &do_findchar(1, 0, @_); } sub F_ViBackwardToChar { &do_findchar(-1, 1, @_); } sub F_ViMoveCursorTo { &do_findchar(1, -1, @_); } sub F_ViMoveCursorFind { &do_findchar(1, 0, @_); } sub F_ViRepeatFindChar { my($n) = @_; return &F_Ding if !defined $Last_findchar; &findchar(@$Last_findchar, $n); } sub F_ViInverseRepeatFindChar { my($n) = @_; return &F_Ding if !defined $Last_findchar; my($c, $direction, $offset) = @$Last_findchar; &findchar($c, -$direction, $offset, $n); } sub do_findchar { my($direction, $offset, $n) = @_; my $c = &getc_with_pending; $c = &getc_with_pending if $c eq "\cV"; return &F_ViCommandMode if $c eq "\e"; $Last_findchar = [$c, $direction, $offset]; &findchar($c, $direction, $offset, $n); } sub findchar { my($c, $direction, $offset, $n) = @_; my $old_d = $D; while ($n) { last if !$D && ($direction < 0); &F_ForwardChar($direction); last if &at_end_of_line; my $char = substr($line, $D, 1); $n-- if substr($line, $D, 1) eq $c; } if ($n) { # Not found $D = $old_d; return &F_Ding; } &F_ForwardChar($offset); } sub F_ViMoveToColumn { my($n) = @_; $D = 0; my $col = 1; while (!&at_end_of_line and $col < $n) { my $c = substr($line, $D, 1); if ($c eq "\t") { $col += 7; $col -= ($col % 8) - 1; } else { $col++; } $D += &CharSize($D); } } sub start_dot_buf { my($count, $ord) = @_; $Dot_buf = [pack('c', $ord)]; unshift(@$Dot_buf, split(//, $count)) if $count > 1; $Dot_state = savestate(); } sub end_dot_buf { # We've recognized an editing command # Save the command keystrokes for use by '.' $Last_vi_command = $Dot_buf; undef $Dot_buf; # Save the pre-command state for use by 'u' and 'U'; $Vi_undo_state = $Dot_state; $Vi_undo_all_state = $Dot_state if !$Vi_undo_all_state; # Make sure the current line is treated as new line for history purposes. $rl_HistoryIndex = $#rl_History + 1; } sub save_dot_buf { &start_dot_buf(@_); &end_dot_buf; } sub F_ViUndo { return &F_Ding unless defined $Vi_undo_state; my $state = savestate(); &getstate($Vi_undo_state); $Vi_undo_state = $state; } sub F_ViUndoAll { $Vi_undo_state = $Vi_undo_all_state; &F_ViUndo; } sub F_ViChange { my($count, $ord) = @_; &start_dot_buf(@_); &do_delete($count, $ord, $Vi_change_patterns) || return(); &vi_input_mode; } sub F_ViDelete { my($count, $ord) = @_; &start_dot_buf(@_); &do_delete($count, $ord, $Vi_delete_patterns); &end_dot_buf; } sub do_delete { my($count, $ord, $poshash) = @_; my $other_end = &get_position($count, undef, $ord, $poshash); return &F_Ding if !defined $other_end; if ($other_end < 0) { # dd - delete entire line &kill_text(0, length($line), 1); } else { &kill_text($D, $other_end, 1); } 1; # True return value } sub F_ViDeleteChar { my($count) = @_; &save_dot_buf(@_); my $other_end = $D + $count; $other_end = length($line) if $other_end > length($line); &kill_text($D, $other_end, 1); } sub F_ViBackwardDeleteChar { my($count) = @_; &save_dot_buf(@_); my $other_end = $D - $count; $other_end = 0 if $other_end < 0; &kill_text($other_end, $D, 1); $D = $other_end; } ## ## Prepend line with '#', add to history, and clear the input buffer ## (this feature was borrowed from ksh). ## sub F_SaveLine { local $\ = ''; $line = '#'.$line; &redisplay(); print $term_OUT "\r\n"; &add_line_to_history; $line_for_revert = ''; &get_line_from_history(scalar @rl_History); &F_ViInput() if $Vi_mode; } # # Come here if we see a non-positioning keystroke when a positioning # keystroke is expected. # sub F_ViNonPosition { # Not a positioning command - undefine the cursor to indicate the error # to get_position(). undef $D; } # # Come here if we see , but *not* an arrow key or other # mapped sequence, when a positioning keystroke is expected. # sub F_ViPositionEsc { my($count, $ord) = @_; # We got in vipos mode. Put back onto the # input stream and terminate the positioning command. unshift(@Pending, pack('c', $ord)); &F_ViNonPosition; } # Interpret vi positioning commands sub get_position { my ($count, $ord, $fullline_ord, $poshash) = @_; # Manipulate a copy of the cursor, not the real thing local $D = $D; # $ord (first character of positioning command) is an optional argument. $ord = ord(&getc_with_pending) if !defined $ord; # Detect double character (for full-line operation, e.g. dd) return -1 if defined $fullline_ord and $ord == $fullline_ord; my $re = $poshash->{$ord}; if ($re) { my $c = pack('c', $ord); if (lc($c) eq 'b') { &backward_scan($count, $re); } else { &forward_scan($count, $re); } } else { # Move the local copy of the cursor &do_command($var_EditingMode{'vipos'}, $count, $ord); } # Return the new cursor (undef if illegal command) $D; } ## ## Go to first non-space character of line. ## sub F_ViFirstWord { $D = 0; &forward_scan(1, q{\s+}); } sub forward_scan { my($count, $re) = @_; while ($count--) { last unless substr($line, $D) =~ m{^($re)}; $D += length($1); } } sub backward_scan { my($count, $re) = @_; while ($count--) { last unless substr($line, 0, $D) =~ m{($re)$}; $D -= length($1); } } # Note: like the emacs case transforms, this doesn't work for # two-byte characters. sub F_ViToggleCase { my($count) = @_; &save_dot_buf(@_); while ($count-- > 0) { substr($line, $D, 1) =~ tr/A-Za-z/a-zA-Z/; &F_ForwardChar(1); if (&at_end_of_line) { &F_BackwardChar(1); last; } } } # Go to the numbered history line, as listed by the 'H' command, i.e. the # current $line is line 1, the youngest line in @rl_History is 2, etc. sub F_ViHistoryLine { my($n) = @_; &get_line_from_history(@rl_History - $n + 1); } sub get_line_from_history { my($n) = @_; return &F_Ding if $n < 0 or $n > @rl_History; return if $n == $rl_HistoryIndex; # If we're moving from the currently-edited line, save it for later. $line_for_revert = $line if $rl_HistoryIndex == @rl_History; # Get line from history buffer (or from saved edit line). $line = ($n == @rl_History) ? $line_for_revert : $rl_History[$n]; $D = $Vi_mode ? 0 : length $line; # Subsequent 'U' will bring us back to this point. $Vi_undo_all_state = savestate() if $Vi_mode; $rl_HistoryIndex = $n; } sub F_PrintHistory { my($count) = @_; $count = 20 if $count == 1; # Default - assume 'H', not '1H' my $end = $rl_HistoryIndex + $count/2; $end = @rl_History if $end > @rl_History; my $start = $end - $count + 1; $start = 0 if $start < 0; my $lmh = length $rl_MaxHistorySize; my $lspace = ' ' x ($lmh+3); my $hdr = "$lspace-----"; $hdr .= " (Use ESC UP to retrieve command ) -----" unless $Vi_mode; $hdr .= " (Use 'G' to retrieve command ) -----" if $Vi_mode; local ($\, $,) = ('',''); print "\n$hdr\n"; print $lspace, ". . .\n" if $start > 0; my $i; my $shift = ($Vi_mode != 0); for $i ($start .. $end) { print + ($i == $rl_HistoryIndex) ? '>' : ' ', sprintf("%${lmh}d: ", @rl_History - $i + $shift), ($i < @rl_History) ? $rl_History[$i] : ($i == $rl_HistoryIndex) ? $line : $line_for_revert, "\n"; } print $lspace, ". . .\n" if $end < @rl_History; print "$hdr\n"; &force_redisplay(); &F_ViInput() if $line eq '' && $Vi_mode; } # Redisplay the line, without attempting any optimization sub force_redisplay { local $force_redraw = 1; &redisplay(@_); } # Search history for matching string. As with vi in nomagic mode, the # ^, $, \<, and \> positional assertions, the \* quantifier, the \. # character class, and the \[ character class delimiter all have special # meaning here. sub F_ViSearch { my($n, $ord) = @_; my $c = pack('c', $ord); my $str = &get_vi_search_str($c); if (!defined $str) { # Search aborted by deleting the '/' at the beginning of the line return &F_ViInput() if $line eq ''; return(); } # Null string repeats last search if ($str eq '') { return &F_Ding unless defined $Vi_search_re; } else { # Convert to a regular expression. Interpret $str Like vi in nomagic # mode: '^', '$', '\<', and '\>' positional assertions, '\*' # quantifier, '\.' and '\[]' character classes. my @chars = ($str =~ m{(\\?.)}g); my(@re, @tail); unshift(@re, shift(@chars)) if @chars and $chars[0] eq '^'; push (@tail, pop(@chars)) if @chars and $chars[-1] eq '$'; my $in_chclass; my %chmap = ( '\<' => '\b(?=\w)', '\>' => '(?<=\w)\b', '\*' => '*', '\[' => '[', '\.' => '.', ); my $ch; foreach $ch (@chars) { if ($in_chclass) { # Any backslashes in vi char classes are literal push(@re, "\\") if length($ch) > 1; push(@re, $ch); $in_chclass = 0 if $ch =~ /\]$/; } else { push(@re, (length $ch == 2) ? ($chmap{$ch} || $ch) : ($ch =~ /^\w$/) ? $ch : ("\\", $ch)); $in_chclass = 1 if $ch eq '\['; } } my $re = join('', @re, @tail); $Vi_search_re = q{$re}; } local $reverse = $Vi_search_reverse = ($c eq '/') ? 1 : 0; &do_vi_search(); } sub F_ViRepeatSearch { my($n, $ord) = @_; my $c = pack('c', $ord); return &F_Ding unless defined $Vi_search_re; local $reverse = $Vi_search_reverse; $reverse ^= 1 if $c eq 'N'; &do_vi_search(); } ## returns a new $i or -1 if not found. sub vi_search { my ($i) = @_; return -1 if $i < 0 || $i > $#rl_History; ## for safety while (1) { return $i if $rl_History[$i] =~ /$Vi_search_re/; if ($reverse) { return -1 if $i-- == 0; } else { return -1 if $i++ == $#rl_History; } } } sub do_vi_search { my $incr = $reverse ? -1 : 1; my $i = &vi_search($rl_HistoryIndex + $incr); return &F_Ding if $i < 0; # Not found. $rl_HistoryIndex = $i; ($D, $line) = (0, $rl_History[$rl_HistoryIndex]); } # Using local $line, $D, and $prompt, get and return the string to search for. sub get_vi_search_str { my($c) = @_; local $prompt = $prompt . $c; local ($line, $D) = ('', 0); &redisplay(); # Gather a search string in our local $line. while ($lastcommand ne 'F_ViEndSearch') { &do_command($var_EditingMode{'visearch'}, 1, ord(&getc_with_pending)); &redisplay(); # We've backspaced past beginning of line return undef if !defined $line; } $line; } sub F_ViEndSearch {} sub F_ViSearchBackwardDeleteChar { if ($line eq '') { # Backspaced past beginning of line - terminate search mode undef $line; } else { &F_BackwardDeleteChar(@_); } } ## ## Kill entire line and enter input mode ## sub F_ViChangeEntireLine { &start_dot_buf(@_); kill_text(0, length($line), 1); &vi_input_mode; } ## ## Kill characters and enter input mode ## sub F_ViChangeChar { &start_dot_buf(@_); &F_DeleteChar(@_); &vi_input_mode; } sub F_ViReplaceChar { &start_dot_buf(@_); my $c = &getc_with_pending; $c = &getc_with_pending if $c eq "\cV"; # ctrl-V return &F_ViCommandMode if $c eq "\e"; &end_dot_buf; local $InsertMode = 0; local $D = $D; # Preserve cursor position &F_SelfInsert(1, ord($c)); } ## ## Kill from cursor to end of line and enter input mode ## sub F_ViChangeLine { &start_dot_buf(@_); &F_KillLine(@_); &vi_input_mode; } sub F_ViDeleteLine { &save_dot_buf(@_); &F_KillLine(@_); } sub F_ViPut { my($count) = @_; &save_dot_buf(@_); my $text2add = $KillBuffer x $count; my $ll = length($line); $D++; $D = $ll if $D > $ll; substr($line, $D, 0) = $KillBuffer x $count; $D += length($text2add) - 1; } sub F_ViPutBefore { &save_dot_buf(@_); &TextInsert($_[0], $KillBuffer); } sub F_ViYank { my($count, $ord) = @_; my $pos = &get_position($count, undef, $ord, $Vi_yank_patterns); &F_Ding if !defined $pos; if ($pos < 0) { # yy &F_ViYankLine; } else { my($from, $to) = ($pos > $D) ? ($D, $pos) : ($pos, $D); $KillBuffer = substr($line, $from, $to-$from); } } sub F_ViYankLine { $KillBuffer = $line; } sub F_ViInput { @_ = (1, ord('i')) if !@_; &start_dot_buf(@_); &vi_input_mode; } sub F_ViBeginInput { &start_dot_buf(@_); &F_BeginningOfLine; &vi_input_mode; } sub F_ViReplaceMode { &start_dot_buf(@_); $InsertMode = 0; $var_EditingMode = $var_EditingMode{'vi'}; $Vi_mode = 1; } sub vi_input_mode { $InsertMode = 1; $var_EditingMode = $var_EditingMode{'vi'}; $Vi_mode = 1; } # The previous keystroke was an escape, but the sequence was not recognized # as a mapped sequence (like an arrow key). Enter vi comand mode and # process this keystroke. sub F_ViAfterEsc { my($n, $ord) = @_; &F_ViCommandMode; &do_command($var_EditingMode, 1, $ord); } sub F_ViAppend { &start_dot_buf(@_); &vi_input_mode; &F_ForwardChar; } sub F_ViAppendLine { &start_dot_buf(@_); &vi_input_mode; &F_EndOfLine; } sub F_ViCommandMode { $var_EditingMode = $var_EditingMode{'vicmd'}; $Vi_mode = 1; } sub F_ViAcceptInsert { local $in_accept_line = 1; &F_ViEndInsert; &F_ViAcceptLine; } sub F_ViEndInsert { if ($Dot_buf) { if ($line eq '' and $Dot_buf->[0] eq 'i') { # We inserted nothing into an empty $line - assume it was a # &F_ViInput() call with no arguments, and don't save command. undef $Dot_buf; } else { # Regardless of which keystroke actually terminated this insert # command, replace it with an in the dot buffer. @{$Dot_buf}[-1] = "\e"; &end_dot_buf; } } &F_ViCommandMode; # Move cursor back to the last inserted character, but not when # we're about to accept a line of input &F_BackwardChar(1) unless $in_accept_line; } sub F_ViDigit { my($count, $ord) = @_; my $n = 0; my $ord0 = ord('0'); while (1) { $n *= 10; $n += $ord - $ord0; my $c = &getc_with_pending; return unless defined $c; $ord = ord($c); last unless $c =~ /^\d$/; } $n *= $count; # So 2d3w deletes six words $n = $rl_max_numeric_arg if $n > $rl_max_numeric_arg; &do_command($var_EditingMode, $n, $ord); } sub F_ViComplete { my($n, $ord) = @_; $Dot_state = savestate(); # Completion is undo-able undef $Dot_buf; # but not redo-able my $ch; while (1) { &F_Complete() or return; # Vi likes the cursor one character right of where emacs like it. &F_ForwardChar(1); &force_redisplay(); # Look ahead to the next input keystroke. $ch = &getc_with_pending(); last unless ord($ch) == $ord; # Not a '\' - quit. # Another '\' was typed - put the cursor back where &F_Complete left # it, and try again. &F_BackwardChar(1); $lastcommand = 'F_Complete'; # Play along with &F_Complete's kludge } unshift(@Pending, $ch); # Unget the lookahead keystroke # Successful completion - enter input mode with cursor beyond end of word. &vi_input_mode; } sub F_ViInsertPossibleCompletions { $Dot_state = savestate(); # Completion is undo-able undef $Dot_buf; # but not redo-able &complete_internal('*') or return; # Successful completion - enter input mode with cursor beyond end of word. &F_ForwardChar(1); &vi_input_mode; } sub F_ViPossibleCompletions { # List possible completions &complete_internal('?'); # Enter input mode with cursor where we left off. &F_ForwardChar(1); &vi_input_mode; } sub F_SetMark { $rl_mark = $D; pos $line = $rl_mark; $line_rl_mark = $rl_HistoryIndex; $force_redraw = 1; } sub F_ExchangePointAndMark { return F_Ding unless $line_rl_mark == $rl_HistoryIndex; ($rl_mark, $D) = ($D, $rl_mark); pos $line = $rl_mark; $D = length $line if $D > length $line; $force_redraw = 1; } sub F_KillRegion { return F_Ding unless $line_rl_mark == $rl_HistoryIndex; $rl_mark = length $line if $rl_mark > length $line; kill_text($rl_mark, $D, 1); $line_rl_mark = -1; # Disable mark } sub F_CopyRegionAsKill { return F_Ding unless $line_rl_mark == $rl_HistoryIndex; $rl_mark = length $line if $rl_mark > length $line; my ($s, $e) = ($rl_mark, $D); ($s, $e) = ($e, $s) if $s > $e; $ThisCommandKilledText = 1 + $s; $KillBuffer = '' if !$LastCommandKilledText; $KillBuffer .= substr($line, $s, $e - $s); } sub clipboard_set { my $in = shift; if ($^O eq 'os2') { eval { require OS2::Process; OS2::Process::ClipbrdText_set($in); # Do not disable \r\n-conversion 1 } and return; } elsif ($^O eq 'MSWin32') { eval { require Win32::Clipboard; Win32::Clipboard::Set($in); 1 } and return; } my $mess; if ($ENV{RL_CLCOPY_CMD}) { $mess = "Writing to pipe `$ENV{RL_CLCOPY_CMD}'"; open COPY, "| $ENV{RL_CLCOPY_CMD}" or warn("$mess: $!"), return; } elsif (defined $ENV{HOME}) { $mess = "Writing to file `$ENV{HOME}/.rl_cutandpaste'"; open COPY, "> $ENV{HOME}/.rl_cutandpaste" or warn("$mess: $!"), return; } else { return; } print COPY $in; close COPY or warn("$mess: closing $!"); } sub F_CopyRegionAsKillClipboard { return clipboard_set($line) unless $line_rl_mark == $rl_HistoryIndex; &F_CopyRegionAsKill; clipboard_set($KillBuffer); } sub F_KillRegionClipboard { &F_KillRegion; clipboard_set($KillBuffer); } sub F_YankClipboard { remove_selection(); my $in; if ($^O eq 'os2') { eval { require OS2::Process; $in = OS2::Process::ClipbrdText(); $in =~ s/\r\n/\n/g; # With old versions, or what? } } elsif ($^O eq 'MSWin32') { eval { require Win32::Clipboard; $in = Win32::Clipboard::GetText(); $in =~ s/\r\n/\n/g; # is this needed? } } else { my $mess; if ($ENV{RL_PASTE_CMD}) { $mess = "Reading from pipe `$ENV{RL_PASTE_CMD}'"; open PASTE, "$ENV{RL_PASTE_CMD} |" or warn("$mess: $!"), return; } elsif (defined $ENV{HOME}) { $mess = "Reading from file `$ENV{HOME}/.rl_cutandpaste'"; open PASTE, "< $ENV{HOME}/.rl_cutandpaste" or warn("$mess: $!"), return; } if ($mess) { local $/; $in = ; close PASTE or warn("$mess, closing: $!"); } } if (defined $in) { $in =~ s/\n+$//; return &TextInsert($_[0], $in); } &TextInsert($_[0], $KillBuffer); } sub F_BeginUndoGroup { push @undoGroupS, $#undo; } sub F_EndUndoGroup { return F_Ding unless @undoGroupS; my $last = pop @undoGroupS; return unless $#undo > $last + 1; my $now = pop @undo; $#undo = $last; push @undo, $now; } sub F_DoNothing { # E.g., reset digit-argument 1; } sub F_ForceMemorizeDigitArgument { $memorizedArg = shift; } sub F_MemorizeDigitArgument { return if defined $memorizedArg; $memorizedArg = shift; } sub F_UnmemorizeDigitArgument { $memorizedArg = undef; } sub F_MemorizePos { $memorizedPos = $D; } # It is assumed that F_MemorizePos was called, then something was inserted, # then F_MergeInserts is called with a prefix argument to multiply # insertion by sub F_MergeInserts { my $n = shift; return F_Ding unless defined $memorizedPos and $n > 0; my ($b, $e) = ($memorizedPos, $D); ($b, $e) = ($e, $b) if $e < $b; if ($n) { substr($line, $e, 0) = substr($line, $b, $e - $b) x ($n - 1); } else { substr($line, $b, $e - $b) = ''; } $D = $b + ($e - $b) * $n; } sub F_ResetDigitArgument { return F_Ding unless defined $memorizedArg; my $in = &getc_with_pending; return unless defined $in; my $ord = ord $in; local(*KeyMap) = $var_EditingMode; &do_command(*KeyMap, $memorizedArg, $ord); } sub F_BeginPasteGroup { my $c = shift; $memorizedArg = $c unless defined $memorizedArg; F_BeginUndoGroup(1); $memorizedPos = $D; } sub F_EndPasteGroup { my $c = $memorizedArg; undef $memorizedArg; $c = 1 unless defined $c; F_MergeInserts($c); F_EndUndoGroup(1); } sub F_BeginEditGroup { $memorizedArg = shift; F_BeginUndoGroup(1); } sub F_EndEditGroup { undef $memorizedArg; F_EndUndoGroup(1); } 1; __END__ EekBoek-2.030.1/lib/EB/CPAN/Term/ReadLine/Perl.pm0000755000400000040000000001002512725476601016402 0ustar jvjvpackage Term::ReadLine::Perl; use Carp; @ISA = qw(Term::ReadLine::Stub Term::ReadLine::Compa Term::ReadLine::Perl::AU); #require 'readline.pl'; $VERSION = $VERSION = 1.0303; sub readline { shift; #my $in = &readline::readline(@_); #$loaded = defined &Term::ReadKey::ReadKey; #print STDOUT "\nrl=`$in', loaded = `$loaded'\n"; #if (ref \$in eq 'GLOB') { # Bug under debugger # ($in = "$in") =~ s/^\*(\w+::)+//; #} #print STDOUT "rl=`$in'\n"; #$in; } #sub addhistory {} *addhistory = \&AddHistory; #$term; $readline::minlength = 1; # To peacify -w $readline::rl_readline_name = undef; # To peacify -w $readline::rl_basic_word_break_characters = undef; # To peacify -w sub new { if (defined $term) { warn "Cannot create second readline interface, falling back to dumb.\n"; return Term::ReadLine::Stub::new(@_); } shift; # Package if (@_) { if ($term) { warn "Ignoring name of second readline interface.\n" if defined $term; shift; } else { $readline::rl_readline_name = shift; # Name } } if (!@_) { if (!defined $term) { ($IN,$OUT) = Term::ReadLine->findConsole(); # Old Term::ReadLine did not have a workaround for a bug in Win devdriver $IN = 'CONIN$' if $^O eq 'MSWin32' and "\U$IN" eq 'CON'; open IN, # A workaround for another bug in Win device driver (($IN eq 'CONIN$' and $^O eq 'MSWin32') ? "+< $IN" : "< $IN") or croak "Cannot open $IN for read"; open(OUT,">$OUT") || croak "Cannot open $OUT for write"; $readline::term_IN = \*IN; $readline::term_OUT = \*OUT; } } else { if (defined $term and ($term->IN ne $_[0] or $term->OUT ne $_[1]) ) { croak "Request for a second readline interface with different terminal"; } $readline::term_IN = shift; $readline::term_OUT = shift; } eval {require Term::ReadLine::readline}; die $@ if $@; # The following is here since it is mostly used for perl input: # $readline::rl_basic_word_break_characters .= '-:+/*,[])}'; $term = bless [$readline::term_IN,$readline::term_OUT]; unless ($ENV{PERL_RL} and $ENV{PERL_RL} =~ /\bo\w*=0/) { local $Term::ReadLine::termcap_nowarn = 1; # With newer Perls local $SIG{__WARN__} = sub {}; # With older Perls $term->ornaments(1); } return $term; } sub newTTY { my ($self, $in, $out) = @_; $readline::term_IN = $self->[0] = $in; $readline::term_OUT = $self->[1] = $out; my $sel = select($out); $| = 1; # for DB::OUT select($sel); } sub ReadLine {'Term::ReadLine::Perl'} sub MinLine { my $old = $readline::minlength; $readline::minlength = $_[1] if @_ == 2; return $old; } sub SetHistory { shift; @readline::rl_History = @_; $readline::rl_HistoryIndex = @readline::rl_History; } sub GetHistory { @readline::rl_History; } sub AddHistory { shift; push @readline::rl_History, @_; $readline::rl_HistoryIndex = @readline::rl_History + @_; } %features = (appname => 1, minline => 1, autohistory => 1, getHistory => 1, setHistory => 1, addHistory => 1, preput => 1, attribs => 1, 'newTTY' => 1, tkRunning => Term::ReadLine::Stub->Features->{'tkRunning'}, ornaments => Term::ReadLine::Stub->Features->{'ornaments'}, ); sub Features { \%features; } # my %attribs; tie %attribs, 'Term::ReadLine::Perl::Tie' or die ; sub Attribs { \%attribs; } sub DESTROY {} package Term::ReadLine::Perl::AU; sub AUTOLOAD { { $AUTOLOAD =~ s/.*:://; } # preserve match data my $name = "readline::rl_$AUTOLOAD"; die "Unknown method `$AUTOLOAD' in Term::ReadLine::Perl" unless exists $readline::{"rl_$AUTOLOAD"}; *$AUTOLOAD = sub { shift; &$name }; goto &$AUTOLOAD; } package Term::ReadLine::Perl::Tie; sub TIEHASH { bless {} } sub DESTROY {} sub STORE { my ($self, $name) = (shift, shift); $ {'readline::rl_' . $name} = shift; } sub FETCH { my ($self, $name) = (shift, shift); $ {'readline::rl_' . $name}; } package Term::ReadLine::Compa; sub get_c { my $self = shift; getc($self->[0]); } sub get_line { my $self = shift; my $fh = $self->[0]; scalar <$fh>; } 1; EekBoek-2.030.1/lib/EB/CPAN/App/0000755000400000040000000000000013151742350013256 5ustar jvjvEekBoek-2.030.1/lib/EB/CPAN/App/Packager.pm0000644000400000040000000000256413044346163015343 0ustar jvjv#! perl package App::Packager; use strict; use warnings; use Carp; # Implementation agnostic packager support. our $VERSION = "1.420"; our $PACKAGED = 0 ; sub import { # PAR::Packer. if ( $ENV{PAR_0} ) { require PAR; $VERSION = $PAR::VERSION; $PACKAGED = 1; *IsPackaged = sub { 1 }; *GetScriptCommand = sub { $ENV{PAR_PROGNAME} }; *GetAppRoot = sub { $ENV{PAR_TEMP} }; *GetResourcePath = sub { $ENV{PAR_TEMP} . "/inc/res" }; *GetResource = sub { $ENV{PAR_TEMP} . "/inc/res/" . $_[0] }; *Packager = sub { "PAR" }; *Version = sub { "$PAR::VERSION" }; return; } if ( $Cava::Packager::PACKAGED ) { $VERSION = $Cava::Packager::VERSION; *Packager = sub { "Cava Packager" }; *Version = sub { "$VERSION" }; *IsPackaged = sub { 1 }; } else { *Packager = sub { return }; *Version = sub { "N/A" }; *IsPackaged = sub { return }; } } # Cava::Packager provides packaged and non-packaged functions. our $AUTOLOAD; sub AUTOLOAD { my $sub = $AUTOLOAD; $sub =~ s/^App\:\:Packager\:\://; eval { require Cava::Packager } unless $Cava::Packager::PACKAGED; my $can = Cava::Packager->can($sub); unless ( $can ) { require Carp; Carp::croak("Undefined subroutine \&$AUTOLOAD called"); } no strict 'refs'; *{'App::Packager::'.$sub} = $can; goto &$AUTOLOAD; } 1; EekBoek-2.030.1/lib/EB/DB/0000755000400000040000000000000013151742350012302 5ustar jvjvEekBoek-2.030.1/lib/EB/DB/Sqlite.pm0000644000400000040000000002441113044346163014106 0ustar jvjv#! perl # Sqlite.pm -- EekBoek driver for SQLite database # Author : Johan Vromans # Created On : Sat Oct 7 10:10:36 2006 # Last Modified By: Johan Vromans # Last Modified On: Tue Oct 13 16:32:32 2015 # Update Count : 186 # Status : Unknown, Use with caution! package main; our $cfg; package EB::DB::Sqlite; use strict; use warnings; use EB; use DBI; use File::Spec; my $CONCURRENT; sub CONCURRENT() { return $CONCURRENT if defined $CONCURRENT; $CONCURRENT = $cfg->val(__PACKAGE__, "concurrent", 1); } my $dbh; # singleton my $sdb; # singleton, DB for sequences my $dataset; my $trace = $cfg->val(__PACKAGE__, "trace", 0); # API: type type of driver sub type { "SQLite" } sub _dbname { my ($dbname) = @_; $dbname = File::Spec->catfile( $cfg->val(qw(database path)), $dbname ) if $cfg->val(qw(database path), undef); $dbname =~ s;(^|.*[/\\])(ebsqlite_|eekboek_)?([^/\\]+)$;${1}ebsqlite_$3;; return $dbname; } sub _dsn { my $dsn = "dbi:SQLite:dbname=" . shift; } # API: create a new, empty database. sub create { my ($self, $dbname) = @_; $dbname = _dbname($dbname); # Create (empty) db file. open(my $db, '>', $dbname); close($db); unlink("$dbname-journal") and warn("%".__x("Database journal voor {db} verwijderd", db => $dbname)."\n"); unlink("$dbname-seq") and warn("%".__x("Database sequences voor {db} verwijderd", db => $dbname)."\n"); } # API: connect to an existing database. sub connect { my ($self, $dbname) = @_; croak("?INTERNAL ERROR: connect db without dataset name") unless $dbname; if ( $dataset && $dbh && $dbname eq $dataset ) { return $dbh; } $self->disconnect; $dbname = _dbname($dbname); $cfg->newval(qw(database fullname), $dbname); unless ( -e $dbname ) { die("?".__x("Geen database met naam {name} gevonden", name => $dbname)."\n"); } $dbh = DBI::->connect(_dsn($dbname)) or die("?".__x("Database verbindingsprobleem: {err}", err => $DBI::errstr)."\n"); $dataset = $dbname; if ( CONCURRENT ) { $sdb = DBI::->connect(_dsn($dbname)."-seq") or die("?".__x("Database verbindingsprobleem: {err}", err => $DBI::errstr)."\n"); $sdb->{RaiseError} = 1; $sdb->{AutoCommit} = 0; } else { $sdb = $dbh; } # Our database is UTF8, so deal with it properly. if ( $DBD::SQLite::VERSION ge "1.26_06" ) { $dbh->{sqlite_unicode} = 1; } else { $dbh->{unicode} = 1; } # Create some missing functions. register_functions(); return $dbh; } # API: Disconnect from a database. sub disconnect { my ($self) = @_; return unless $dbh; $dbh->disconnect; $sdb->disconnect if CONCURRENT; undef $dbh; undef $sdb; undef $dataset; } # API: Clear database contents, including tables and such. sub clear { my ($self) = @_; croak("?INTERNAL ERROR: clear db while not connected") unless $dbh; croak("?INTERNAL ERROR: clear db not supperted by this driver"); my $ds = $dataset; $self->disconnect; $self->create($ds); $self->connect($ds); } # API: Setup whatever is needed. sub setup { # setup will be called after the connection to the database has # been established. # Create table for sequences. unless ( $sdb->selectrow_arrayref("SELECT name". " FROM sqlite_master". " WHERE name = 'eb_seq'". " AND type = 'table'") ) { $sdb->do("CREATE TABLE eb_seq". " (name TEXT PRIMARY KEY,". " value INT)"); $sdb->commit if CONCURRENT; } # Clone Accounts table into TAccounts. # This table has the purpose of copying the data from Accounts, so that # data from already completed financial years can be corrected when # creating overviews, such as Balance statements and Result accounts. # This way no backdated calculations need to be made when transitions # to previous financial years are involved. unless ( $dbh->selectrow_arrayref("SELECT name". " FROM sqlite_master". " WHERE name like 'taccounts'". " AND type = 'table'") ) { my $sql = $dbh->selectrow_arrayref("SELECT sql". " FROM sqlite_master". " WHERE name like 'accounts'". " AND type = 'table'")->[0]; $sql =~ s/TABLE Accounts/TABLE TAccounts/; $dbh->do($sql); } # Caller will commit. } # API: Get a array ref with table names (lowcased). sub get_tables { my $self = shift; my @t; foreach ( $dbh->tables ) { # SQLite returns table names with quotes. # Our tables all start with an uppercase letter. next unless /^"(?:main"\.")?([[:upper:]].+)"$/i; push(@t, lc($1)); } \@t; } # API: List available data sources. sub list { [] } ################ Sequences ################ # Currently non-atomic, restricting to single user mode. sub _create_sequence { my ($sn, $value) = (@_, 1); $sdb->do("INSERT INTO eb_seq (name, value) VALUES (?, ?)", {}, $sn, $value); $sdb->commit if CONCURRENT; $value; } sub _get_sequence { my ($seq) = @_; # Get the current (=next) value. my $rr = $sdb->selectrow_arrayref("SELECT value". " FROM eb_seq". " WHERE name = ?", {}, $seq); $rr ? $rr->[0] : undef; } sub _set_sequence { my ($seq, $value) = @_; $sdb->do("UPDATE eb_seq SET value = ? WHERE name = ?", {}, $value, $seq); $sdb->commit if CONCURRENT; return; } # API: Get the next value for a sequence, incrementing it. sub get_sequence { my ($self, $seq) = @_; if ( my $v = _get_sequence($seq) ) { _set_sequence($seq, $v+1); return $v; } _create_sequence($seq, 2); 1; } # API: Set the next value for a sequence. sub set_sequence { my ($self, $seq, $value) = @_; _get_sequence($seq) ? _set_sequence($seq, $value) : _create_sequence($seq, $value); return; } ################ Attachments ################ # SQLite stores the data into files, next to the database. use Fcntl; #### TODO: (re)factor the slurp/blurp code. sub get_attachment { my ( $self, $id ) = @_; my $rr = $dbh->selectrow_arrayref("SELECT att_name,att_encoding". " FROM Attachments". " WHERE att_id = ?", {}, $id ); my ( $name, $enc, $data ) = @{ $rr }; if ( $enc == ATTENCODING_URI ) { return { name => $name, encoding => $enc, content => \$name }; } my $path = $cfg->val(qw(database path), "."); my $file = File::Spec->catfile( $path, sprintf("%08d_%s", $id, $name) ); my $fail; sysopen( my $fd, $file, O_RDONLY ) or $fail = $!; my $cnt = 1; my $offset = 0; $data = ""; while ( !$fail && $cnt > 0 ) { $cnt = sysread( $fd, $data, 20480, $offset ); $fail = $! if $cnt < 0; $offset += $cnt; } close($fd); if ( $fail ) { die(__x("Intern probleem met bijlage {id} ({name}): {err}", id => $id, name => $name, err => $fail)."\n"); } return { name => $name, encoding => $enc, content => \$data }; } sub store_attachment { my ( $self, $atts ) = @_; my @fields = qw( id name size encoding ); $dbh->do("INSERT INTO Attachments" . " (" . join(",", map { +"att_$_" } @fields ) . ") ". " VALUES (" . join(",", ("?") x @fields) . ")", {}, $atts->{id}, $atts->{name}, $atts->{size}, $atts->{encoding} ); return if $atts->{encoding} == ATTENCODING_URI; my $path = $cfg->val(qw(database path), "."); my $file = File::Spec->catfile( $path, sprintf("%08d_%s", $atts->{id}, $atts->{name}) ); my $fail; sysopen( my $fd, $file, O_WRONLY|O_CREAT, 0600 ) or $fail = $!; my $data = $atts->{content}; my $cnt = length($$data); my $offset = 0; while ( !$fail && $cnt > 0 ) { my $w = syswrite( $fd, $$data, 20480, $offset ); $fail = $! if $cnt < 0; $offset += $w; $cnt -= $w; } unless ( $fail ) { close($fd) or $fail = $!; } if ( $fail ) { die(__x("Intern probleem met bijlage {id} ({name}): {err}", id => $atts->{id}, name => $atts->{name}, err => $fail)."\n"); } } sub drop_attachment { my ( $self, $id ) = @_; my $rr = $dbh->selectrow_arrayref("SELECT att_name,att_encoding". " FROM Attachments". " WHERE att_id = ?", {}, $id ); my ( $name, $enc ) = @{ $rr }; $dbh->do("DELETE FROM Attachments WHERE att_id = ?", {}, $id ); return if $enc == ATTENCODING_URI; my $path = $cfg->val(qw(database path), "."); my $file = File::Spec->catfile( $path, sprintf("%08d_%s", $id, $name) ); unless ( unlink($file) ) { die(__x("Intern probleem met bijlage {id} ({name}): {err}", id => $id, name => $name, err => $!)."\n"); } } ################ Interactive SQL ################ # API: Interactive SQL. sub isql { my ($self, @args) = @_; my $dbname = $cfg->val(qw(database fullname)); my $cmd = "sqlite3"; my @cmd = ( $cmd ); push(@cmd, $dbname); if ( @args ) { push(@cmd, "@args"); } my $res = system { $cmd } @cmd; # warn(sprintf("=> ret = %02x", $res)."\n") if $res; } ################ PostgreSQL Compatibility ################ # API: feature Can we? sub feature { my ($self, $feat) = @_; $feat = lc($feat); # Known features: # # pgcopy F PostgreSQL fast input copying # prepcache T Statement handles may be cached # filter C SQL filter routine # # Unknown/unsupported features may be ignored. return \&sqlfilter if $feat eq "filter"; return 1 if $feat eq "prepcache"; return 0 if $feat eq "import"; # Return false for all others. return; } sub sqlfilter { local $_ = shift; my (@args) = @_; # No sequences. return if /^(?:create|drop|alter)\s+sequence\b/i; # Constraints are ignored in table defs, but an # explicit alter needs to be skipped. return if /^alter\s+table\b.*\b(add|drop)\s+constraint\b/i; # UNSOLVED: No insert into temp tables. return if /^select\s+\*\s+into\s+temp\b/i; # Fortunately, LIKE behaves mostly like ILIKE. s/\bilike\b/like/gi; return $_; } sub register_functions { $dbh->func("now", 0, \&iso8601date, "create_function"); $dbh->func("sign", 1, sub { defined $_[0] ? $_[0] <=> 0 : 0 }, "create_function"); $dbh->func("int2", 1, sub { 0+$_[0] }, "create_function"); } ################ End PostgreSQL Compatibility ################ 1; EekBoek-2.030.1/lib/EB/DB/Postgres.pm0000644000400000040000000002152513044346163014456 0ustar jvjv#! perl # Postgres.pm -- EekBoek driver for PostgreSQL database # Author : Johan Vromans # Created On : Tue Jan 24 10:43:00 2006 # Last Modified By: Johan Vromans # Last Modified On: Tue Oct 13 15:42:37 2015 # Update Count : 243 # Status : Unknown, Use with caution! package main; our $cfg; package EB::DB::Postgres; use strict; use warnings; use EB; use DBI; use DBD::Pg; my $dbh; # singleton my $dataset; my $trace = $cfg->val(__PACKAGE__, "trace", 0) if $cfg; # API: type type of driver sub type { "PostgreSQL" } sub _dsn { my $dsn = "dbi:Pg:dbname=" . shift; my $t; $dsn .= ";host=" . $t if $t = $cfg->val(qw(database host), undef); $dsn .= ";port=" . $t if $t = $cfg->val(qw(database port), undef); wantarray ? ( $dsn, $cfg->val("database", "user", undef), $cfg->val("database", "password", undef)) : $dsn; } # API: create a new database, reuse an existing one if possible. sub create { my ($self, $dbname) = @_; if ( $dbh && !$dbname ) { # use current DB. $dbh->{RaiseError} = 0; $dbh->{PrintError} = 0; $dbh->{AutoCommit} = 1; $self->clear; $dbh->{RaiseError} = 1; $dbh->{PrintError} = 1; # $dbh->{AutoCommit} = 0; return; } croak("?INTERNAL ERROR: create db while connected") if $dbh; eval { { local($SIG{__WARN__}) = sub {}; $self->connect($dbname); } $dbh->{RaiseError} = 0; $dbh->{PrintError} = 0; $dbh->{AutoCommit} = 1; $self->clear; $self->disconnect; }; return unless $@; die($@) if $@ =~ /UNICODE/; $dbname =~ s/^(?!=eekboek_)/eekboek_/; # Normally, sql treats names as lowcased. By using " " we can # maintain the case of the database name. my $sql = "CREATE DATABASE \"$dbname\""; $sql .= " ENCODING 'UNICODE'"; for ( $cfg->val("database", "user", undef) ) { next unless $_; $sql .= " OWNER $_"; } my $dbh = DBI->connect(_dsn("template1")); my $errstr = $DBI::errstr; if ( $dbh ) { warn("+ $sql\n") if $trace; $dbh->do($sql); $errstr = $DBI::errstr; $dbh->disconnect; return unless $errstr; } die("?".__x("Database probleem: {err}", err => $errstr)."\n"); } # API: connect to an existing database. sub connect { my ($self, $dbname) = @_; croak("?INTERNAL ERROR: connect db without dataset name") unless $dbname; if ( $dataset && $dbh && $dbname eq $dataset ) { return $dbh; } $self->disconnect; $dbname = "eekboek_".$dbname unless $dbname =~ /^eekboek_/; $cfg->newval(qw(database fullname), $dbname); $dbh = DBI::->connect(_dsn($dbname)) or die("?".__x("Database verbindingsprobleem: {err}", err => $DBI::errstr)."\n"); $dataset = $dbname; my $enc = $dbh->selectall_arrayref("SHOW CLIENT_ENCODING")->[0]->[0]; if ( $enc !~ /^unicode|utf8$/i ) { warn("!".__x("Database {name} is niet in UTF-8 maar {enc}", name => $_[1], enc => $enc)."\n"); } $dbh->do("SET CLIENT_ENCODING TO 'UNICODE'"); $dbh->{pg_enable_utf8} = 1; return $dbh; } # API: Disconnect from a database. sub disconnect { my ($self) = @_; return unless $dbh; $dbh->disconnect; undef $dbh; undef $dataset; } # API: Setup whatever is needed. sub setup { } sub clear { my ($self) = @_; croak("?INTERNAL ERROR: clear db while not connected") unless $dbh; for my $tbl ( qw(Boekstukregels Journal Boekjaarbalans Metadata Standaardrekeningen Relaties Boekstukken Dagboeken Boekjaren Constants Accounts Btwtabel Verdichtingen Taccounts Attachments ) ) { warn("+ DROP TABLE $tbl\n") if $trace; eval { $dbh->do("DROP TABLE $tbl") }; } eval { my $rr = $dbh->selectall_arrayref("SELECT relname". " FROM pg_class". " WHERE relkind = 'S'". ' AND relname LIKE \'%bsk_%_seq\''); foreach my $seq ( @$rr ) { warn("+ DROP SEQUENCE $seq->[0]\n") if $trace; eval { $dbh->do("DROP SEQUENCE $seq->[0]") }; } }; $dbh->commit unless $dbh->{AutoCommit}; } # API: Test db connection. sub test { my $self = shift; my $db = shift; $db = $db ? "eekboek_$db" : "template1"; my $opts = shift || {}; my $d; my $dsn = "dbi:Pg:dbname=$db"; my $t; $dsn .= ";host=" . $t if $t = $opts->{host}; $dsn .= ";port=" . $t if $t = $opts->{port}; eval { $d = DBI->connect( $dsn, $opts->{user} || undef, $opts->{password} || undef, ); }; return $@ if $@; return DBI->errstr unless $d; $d->{RaiseError} = 1; unless ( $db eq "template1" ) { # Check if we really can access the db. eval { $d->do("SELECT * FROM Metadata"); }; return $@ if $@; return DBI->errstr unless $d; } eval { $d->disconnect; }; return; } # API: List available data sources. sub list { my @ds; my $t; local $ENV{PGHOST} = $t if $t = $cfg->val(qw(database host), undef); local $ENV{PGPORT} = $t if $t = $cfg->val(qw(database port), undef); local $ENV{DBI_USER} = $t if $t = $cfg->val("database", "user", undef); local $ENV{DBI_PASS} = $t if $t = $cfg->val("database", "password", undef); eval { @ds = DBI->data_sources("Pg"); }; # If the list cannot be established, @ds will be (undef). return [] unless defined($ds[0]); my $d = []; foreach ( @ds ) { next unless s/^.*?dbname=eekboek_(.+)//; push( @$d, $1 ); } return $d; } # API: Get a array ref with table names (lowcased). sub get_tables { my $self = shift; my @t; foreach ( $dbh->tables ) { next unless /^public\.(.+)/i; push(@t, lc($1)); } \@t; } ################ Sequences ################ # API: Get the next value for a sequence, incrementing it. sub get_sequence { my ($self, $seq) = @_; croak("?INTERNAL ERROR: get sequence while not connected") unless $dbh; my $rr = $dbh->selectall_arrayref("SELECT nextval('$seq')"); return ($rr && defined($rr->[0]) && defined($rr->[0]->[0])? $rr->[0]->[0] : undef); } # API: Set the next value for a sequence. sub set_sequence { my ($self, $seq, $value) = @_; croak("?INTERNAL ERROR: set sequence while not connected") unless $dbh; # Init a sequence to value. # The next call to get_sequence will return this value. $dbh->do("SELECT setval('$seq', $value, false)"); $value; } ################ Attachments ################ # PostgreSQL stores the data into the database, base64 encoded. use MIME::Base64 (); sub get_attachment { my ( $self, $id ) = @_; my $rr = $dbh->selectrow_arrayref("SELECT att_name,att_encoding,att_content". " FROM Attachments". " WHERE att_id = ?", {}, $id ); my ( $name, $enc, $data ) = @{ $rr }; $data = MIME::Base64::decode_base64($data) if $enc == ATTENCODING_BASE64; return { name => $name, encoding => $enc, content => \$data }; } sub store_attachment { my ( $self, $atts ) = @_; my @fields = qw( id name size encoding content ); my $enc = defined $atts->{encoding} ? $atts->{encoding} : ATTENCODING_BASE64; $dbh->do("INSERT INTO Attachments" . " (" . join(",", map { +"att_$_" } @fields ) . ") ". " VALUES (" . join(",", ("?") x @fields) . ")", {}, $atts->{id}, $atts->{name}, $atts->{size}, $enc, $enc == ATTENCODING_BASE64 ? MIME::Base64::encode( ${ $atts->{content} }, "" ) : ${ $atts->{content} }, ); } sub drop_attachment { my ( $self, $id ) = @_; $dbh->do("DELETE FROM Attachments WHERE att_id = ?", {}, $id ); } ################ Interactive SQL ################ # API: Interactive SQL. sub isql { my ($self, @args) = @_; my $dbname = $cfg->val(qw(database fullname)); my $cmd = "psql"; my @cmd = ( $cmd ); for ( $cfg->val("database", "user", undef) ) { next unless $_; push(@cmd, "-U", $_); } for ( $cfg->val("database", "host", undef) ) { next unless $_; push(@cmd, "-h", $_); } for ( $cfg->val("database", "port", undef) ) { next unless $_; push(@cmd, "-p", $_); } push(@cmd, "-d", $dbname); if ( @args ) { push(@cmd, "-c", "@args"); } my $res = system { $cmd } @cmd; # warn(sprintf("=> ret = %02x", $res)."\n") if $res; } ################ PostgreSQL Compatibility ################ # API: feature Can we? sub feature { my $self = shift; my $feat = lc(shift); # Known features: # # pgcopy F PostgreSQL fast input copying # prepcache T Statement handles may be cached # filter C SQL filter routine # # Unknown/unsupported features may be ignored. if ( $feat eq "pgcopy" ) { return 1 if ($DBD::Pg::VERSION||"0") ge "1.41"; warn("%"."Not using PostgreSQL fast load. DBD::Pg::VERSION = ", ($DBD::Pg::VERSION||"0"), ", needs 1.41 or later\n"); return; } return 1 if $feat eq "prepcache"; return 1 if $feat eq "import"; return 1 if $feat eq "test"; return 1 if $feat eq "blob"; # Return false for all others. return; } ################ End PostgreSQL Compatibility ################ 1; EekBoek-2.030.1/lib/EB/Import.pm0000644000400000040000000001273313151741114013630 0ustar jvjv#! perl -- -*- coding: utf-8 -*- use utf8; # Import.pm -- Import EekBoek administratie # Author : Johan Vromans # Created On : Tue Feb 7 11:56:50 2006 # Last Modified By: Johan Vromans # Last Modified On: Thu Aug 31 10:01:16 2017 # Update Count : 139 # Status : Unknown, Use with caution! package main; our $cfg; our $dbh; package EB::Import; use strict; use warnings; use EB; use EB::Format; # needs to be setup before we can use Schema use EB::Tools::Attachments; my $ident; sub do_import { my ($self, $cmdobj, $opts) = @_; require EB::Tools::Schema; my $dir = $opts->{dir}; if ( defined $dir ) { my $fail; $fail++, warn("?".__x("Directory {dir} bestaat niet", dir => $dir)."\n") unless -d $dir; $fail++, warn("?".__x("Geen toegang tot directory {dir}", dir => $dir)."\n") unless -r _ || -x _; -r "$dir/schema.dat" or $fail++, warn("?".__x("Bestand \"{file}\" ontbreekt ({err})", file => "schema.dat", err => $!)."\n"); # Do not open these with :encoding(utf-8) -- we'll do it ourselves. open(my $relaties, "<", "$dir/relaties.eb") or $fail++, warn("?".__x("Bestand \"{file}\" ontbreekt ({err})", file => "relaties.eb", err => $!)."\n"); open(my $opening, "<", "$dir/opening.eb") or $fail++, warn("?".__x("Bestand \"{file}\" ontbreekt ({err})", file => "opening.eb", err => $!)."\n"); open(my $mutaties, "<", "$dir/mutaties.eb") or $fail++, warn("?".__x("Bestand \"{file}\" ontbreekt ({err})", file => "mutaties.eb", err => $!)."\n"); if ( $fail ) { die("?"._T("DE IMPORT IS NIET UITGEVOERD")."\n"); } # To temporary suspend journaling. my $jnl_state = $cfg->val(qw(preferences journal), undef); # Delete daybook-associated shell functions. $cmdobj->_forget_cmds; # Create DB. $dbh->cleardb if $opts->{clean}; # Schema. EB::Tools::Schema->create("$dir/schema.dat"); $dbh->setup; # Add daybook-associated shell functions. $cmdobj->_plug_cmds; # Relaties, Opening, Mutaties. # Remember: These are executed in LIFO. $cmdobj->attach_lines(["journal --quiet $jnl_state"]) if $jnl_state; $cmdobj->attach_file($mutaties); $cmdobj->attach_file($opening); $cmdobj->attach_file($relaties); $cmdobj->attach_lines(["journal --quiet 0"]) if $jnl_state; my $att = EB::Tools::Attachments->new; my @atts = sort glob("$dir/[0-9]???????_*"); my $max_id = -1; foreach my $file ( @atts ) { my ($id, $name) = substr($file, length($dir)+1) =~ m;^(\d+)_(.+);; $att->{id} = 0+$id; $max_id = $id if $id > $max_id; $att->{name} = $name; $att->store_from_file($file); } $dbh->set_sequence( "attachments_id_seq", $max_id+1 ) if $max_id > 0; return; } my $inp = $opts->{file}; if ( defined $inp ) { eval { require Archive::Zip } or die("?"._T("Module Archive::Zip, nodig voor import van file, is niet beschikbaar")."\n"); open(my $zipf, "<", $inp) or die("?".__x("Bestand \"{file}\" is niet beschikbaar ({err})", file => $inp, err => $!)."\n"); binmode($zipf); my $zip = Archive::Zip->new; my $status = $zip->read($zipf); die("?".__x("Fout {code} tijdens het lezen van {file}", code => $status, file => $inp)."\n") if $status; my $c = $zip->zipfileComment; if ( $c ) { warn("$inp: $c\n"); } my $fail; my $d_schema = $zip->contents("schema.dat"); unless ( $d_schema ) { warn("?".__x("Het schema ontbreekt in bestand {file}", file => $inp)."\n"); $fail++; } my $d_relaties = $zip->contents("relaties.eb"); unless ( $d_relaties ) { warn("?".__x("De relatiegegevens ontbreken in bestand {file}", file => $inp)."\n"); $fail++; } my $d_opening = $zip->contents("opening.eb"); unless ( $d_opening ) { warn("?".__x("De openingsgegevens ontbreken in bestand {file}", file => $inp)."\n"); $fail++; } my $d_mutaties = $zip->contents("mutaties.eb"); unless ( $d_mutaties ) { warn("?".__x("De mutatiegegevens ontbreken in bestand {file}", file => $inp)."\n"); $fail++; } if ( $fail ) { close($zipf); die("?"._T("DE IMPORT IS NIET UITGEVOERD")."\n"); } foreach ( $d_mutaties, $d_relaties, $d_opening, $d_schema ) { # Do not recode, the input loop will do that for us. $_ = [ map { "$_\n" } split(/[\n\r]+/, $_) ]; } # To temporary suspend journaling. my $jnl_state = $cfg->val(qw(preferences journal), undef); # Delete daybook-associated shell functions. $cmdobj->_forget_cmds; # Create DB. $dbh->cleardb if $opts->{clean}; # Schema. my @s = @$d_schema; # copy for 2nd pass EB::Tools::Schema->_create1(sub { shift(@$d_schema) }); EB::Tools::Schema->_create2(sub { shift(@s) }); $dbh->setup; # Add daybook-associated shell functions. $cmdobj->_plug_cmds; # Relaties, Opening, Mutaties. In reverse order. $cmdobj->attach_lines(["journal --quiet $jnl_state"]) if $jnl_state; $cmdobj->attach_lines($d_mutaties); $cmdobj->attach_lines($d_opening ); $cmdobj->attach_lines($d_relaties); $cmdobj->attach_lines(["journal --quiet 0"]) if $jnl_state; my @att = $zip->membersMatching( '^\d+_.+' ); my $att = EB::Tools::Attachments->new; my $max_id = -1; foreach my $mem ( @att ) { my ($id, $name) = $mem->fileName =~ m;^(\d+)_(.+);; $att->{id} = 0+$id; $max_id = $id if $id > $max_id; $att->{name} = $name; my $d = $mem->contents; $att->{content} = \$d; $att->store; } close($zipf); $dbh->set_sequence( "attachments_id_seq", $max_id+1 ) if $max_id > 0; return; } die("?ASSERT ERROR: missing --dir / --file in Import\n"); } 1; EekBoek-2.030.1/lib/EB/Export.pm0000644000400000040000000002652613044346163013652 0ustar jvjv#! perl -- -*- coding: utf-8 -*- use utf8; # Export.pm -- Export EekBoek administratie # Author : Johan Vromans # Created On : Mon Jan 16 20:47:38 2006 # Last Modified By: Johan Vromans # Last Modified On: Mon Mar 7 08:38:34 2016 # Update Count : 263 # Status : Unknown, Use with caution! package main; our $dbh; our $cfg; package EB::Export; use strict; use warnings; use EB; use EB::Format; use Encode; use Fcntl qw( O_WRONLY O_CREAT ); use EB::Tools::Attachments; my $ident; sub export { my ($self, $opts) = @_; my $dir = $opts->{dir}; if ( defined $dir ) { mkdir($dir, 0777) unless -d $dir; die("?".__x("Fout bij aanmaken directory {dir}: {err}", dir => $dir, err => $!)."\n") unless -d $dir; die("?".__x("Geen toegang tot directory {dir}", dir => $dir)."\n") unless -w $dir; $self->_write("$dir/schema.dat", sub { $self->_schema(shift) }); $self->_write("$dir/relaties.eb", sub { print { shift } $self->_relaties }); $self->_write("$dir/opening.eb", sub { print { shift } $self->_opening }); $self->_write("$dir/mutaties.eb", sub { print { shift } $self->_mutaties($opts) }); my $att = EB::Tools::Attachments->new; foreach my $rr ( @{ $att->attachments } ) { next if $rr->{encoding} == ATTENCODING_URI; my $file = sprintf( "$dir/%08d_%s", $rr->{id}, $rr->{name} ); $att->save_to_file( $file, $rr->{id} ); } return; } my $out = $opts->{file}; if ( defined $out ) { eval { require Archive::Zip } or die("?"._T("Module Archive::Zip, nodig voor export naar file, is niet beschikbaar")."\n"); my $zip = Archive::Zip->new(); my $comment = __x("Export van dataset {db} aangemaakt door {id} op {date}", id => $EB::ident, db => $cfg->val(qw(database name)), date => datefmt_full(iso8601date())); $comment .= "\n".__x("Omschrijving: {desc}", desc => $opts->{desc}) if $opts->{desc}; $zip->zipfileComment($comment); my $m; # For the schema, we need a temp file. my ($fh, $tmpname) = Archive::Zip::tempFile(); binmode($fh, ":encoding(utf8)"); $self->_schema($fh); $fh->close; $m = $zip->addFile($tmpname, "schema.dat"); $m->desiredCompressionMethod(8); # The others can be added directly. # Note that the encoding needs to be fixed since there's no IO involved. $m = $zip->addString(_enc($self->_relaties), "relaties.eb"); $m->desiredCompressionMethod(8); $m = $zip->addString(_enc($self->_opening), "opening.eb"); $m->desiredCompressionMethod(8); $m = $zip->addString(_enc($self->_mutaties($opts)), "mutaties.eb"); $m->desiredCompressionMethod(8); # Attachments. my $att = EB::Tools::Attachments->new; foreach my $rr ( @{ $att->attachments } ) { next if $rr->{encoding} == ATTENCODING_URI; my $file = sprintf( "%08d_%s", $rr->{id}, $rr->{name} ); $att->save_to_zip( $zip, $file, $rr->{id} ); } my $status = $zip->writeToFileNamed($out); unlink($tmpname); die("?", __x("Fout {status} tijdens het aanmaken van exportbestand {name}", status => $status, name => $out)."\n") if $status; return; } die("?ASSERT ERROR: missing --dir / --file in Export\n"); } sub _enc { my $t; eval { $t = encode( 'utf8', "".$_[0], 1 ); }; if ( $@ ) { warn("?".__x("Geen geldige UTF-8 tekens for ZIP element", ). "\n".$_[0]."\n"); return; } $t; } sub _write { my ($self, $file, $producer) = @_; my $fh; open($fh, ">:encoding(utf-8)", $file) or die("?".__x("Fout bij aanmaken bestand {file}: {err}", file => $file, err => $!)."\n"); $producer->($fh) or die("?".__x("Fout bij schrijven bestand {file}: {err}", file => $file, err => $!)."\n"); close($fh) or die("?".__x("Fout bij afsluiten bestand {file}: {err}", file => $file, err => $!)."\n"); } sub _schema { my ($self, $fh) = @_; use EB::Tools::Schema; EB::Tools::Schema->dump_schema($fh); } sub _quote { my ($t) = @_; $t =~ s/(\\")/\\$1/g; '"'.$t.'"'; } sub _relaties { my ($self) = @_; my $sth = $dbh->sql_exec("SELECT rel_code, rel_desc, rel_debcrd,". " rel_btw_status, dbk_desc, rel_acc_id". " FROM Relaties, Dagboeken". " WHERE rel_ledger = dbk_id". " ORDER BY rel_ledger, rel_btw_status, rel_code"); my $cur_dbk = ""; my $cur_btw = -1; my $out = "# " . __x("{what} voor administratie {adm}", what => _T("Relaties"), adm => $dbh->adm("name")) . "\n" . "# " . __x("Aangemaakt door {id} op {date}", id => $EB::ident, date => datefmt_full(iso8601date())) . "\n" . "# Content-Type: text/plain; charset = UTF-8"; while ( my $rr = $sth->fetchrow_arrayref ) { my ($code, $desc, $debcrd, $btw, $dbk, $acct) = @$rr; if ( $cur_btw != $btw || $cur_dbk ne $dbk ) { $cur_btw = $btw; $cur_dbk = $dbk; $dbk =~ s/[^[:alnum:]]/_/g; $out .= "\n\n" if $out; $out .= _xt("cmd:relatie")." --".__xt("cmo:relatie:dagboek")."=".lc($dbk); $out .= " --".__xt("cmo:relatie:btw")."=".lc(BTWTYPES->[$btw]) unless $btw == BTWTYPE_NORMAAL; } $out .= " \\\n "; $out .= sprintf("%-12s %-40s %d", _quote($code), _quote($desc), $acct); } $out .= "\n\n# " . __x("Einde {what}", what => _T("Relaties")) . "\n"; } sub _opening { my ($self) = @_; require EB::Booking::Decode; my $sth; my $out = "# " . __x("{what} voor administratie {adm}", what => _T("Openingsgegevens"), adm => $dbh->adm("name")) . "\n" . "# " . __x("Aangemaakt door {id} op {date}", id => $EB::ident, date => datefmt_full(iso8601date())) . "\n" . "# Content-Type: text/plain; charset = UTF-8\n\n"; $out .= _xt("cmd:adm_naam") . " " . _quote($dbh->adm("name")) . "\n"; my $begin = $dbh->do("SELECT min(bky_begin)". " FROM Boekjaren". " WHERE bky_begin > ( SELECT bky_end FROM Boekjaren WHERE bky_code = ? )", BKY_PREVIOUS); $begin = $begin->[0]; $out .= _xt("cmd:adm_begindatum") . " " . substr($begin, 0, 4) . "\n"; $out .= _xt("cmd:adm_boekjaarcode") . " " . _quote($dbh->lookup($begin, qw(Boekjaren bky_begin bky_code))) . "\n"; $out .= _xt("cmd:adm_btwperiode") . " " . _T(qw(geen jaar x x kwartaal x x x x x x x maand)[$dbh->lookup($begin, qw(Boekjaren bky_begin bky_btwperiod))]). "\n" if $dbh->does_btw; $out .= "\n# " . _T("Openingsbalans") . "\n"; $sth = $dbh->sql_exec("SELECT acc_id, acc_desc, acc_ibalance, acc_debcrd". " FROM Accounts". " WHERE acc_balres". " AND acc_ibalance <> 0". " ORDER BY acc_debcrd DESC, acc_id"); my ($dt, $ct) = (0, 0); my $debcrd; while ( my $rr = $sth->fetchrow_arrayref ) { my ($acc_id, $acc_desc, $acc_balance, $acc_debcrd) = @$rr; next unless $acc_balance; # Export boekhoudkundig saldo (zie EB::Tools::Opening). if ( $acc_balance >= 0 ) { $dt += $acc_balance; } else { $ct -= $acc_balance; } $acc_balance = 0 - $acc_balance unless $acc_debcrd; if ( !defined($debcrd) || $acc_debcrd != $debcrd ) { $out .= "\n# " . ($acc_debcrd ? _T("Debet") : _T("Credit")) . "\n"; } $out .= sprintf("%s %-5s %10s # %s\n", _xt("cmd:adm_balans"), $acc_id, numfmt_plain($acc_balance), $acc_desc); $debcrd = $acc_debcrd; } die("?".__x("Internal error -- unbalance {arg1} <> {arg2}", arg1 => numfmt_plain($dt), arg2 => numfmt_plain($ct))."\n") unless $dt == $ct; $out .= "\n# " . _T("Totaal") . "\n" . _xt("cmd:adm_balanstotaal") . " " . numfmt_plain($dt) . "\n"; $sth = $dbh->sql_exec("SELECT bsk_id". " FROM Boekstukken". " WHERE bsk_date <= ( SELECT bky_end FROM Boekjaren WHERE bky_code = ? )". " ORDER BY bsk_dbk_id, bsk_nr, bsk_date", BKY_PREVIOUS); my $rr = $sth->fetchrow_arrayref; if ( $rr ) { $out .= "\n# "._T("Openstaande posten")."\n\n"; } while ( $rr ) { my ($bsk_id) = @$rr; $out .= "adm_relatie " . EB::Booking::Decode->decode ($bsk_id, { trail => 1, single => 0, btw => 0, bsknr => 1, bky => 1, total => 0, noivbskdesc => 1, debcrd => 0 }) . "\n"; $rr = $sth->fetchrow_arrayref; } $out .= "\n# "._T("Openen van de administratie")."\n\n"._xt("cmd:adm_open")."\n"; $out .= "\n# " . __x("Einde {what}", what => _T("Openingsgegevens")) . "\n"; $out; } sub _mutaties { my ($self, $opts) = @_; my $out = "# " . __x("{what} voor administratie {adm}", what => _T("Boekingen"), adm => $dbh->adm("name")) . "\n" . "# " . __x("Aangemaakt door {id} op {date}", id => $EB::ident, date => datefmt_full(iso8601date())) . "\n" . "# Content-Type: text/plain; charset = UTF-8\n\n"; my @bky; my $sth = $dbh->sql_exec("SELECT bky_code". " FROM Boekjaren". " WHERE bky_begin > ( SELECT bky_end FROM Boekjaren WHERE bky_code = ? )". " ORDER BY bky_code", BKY_PREVIOUS); while ( my $rr = $sth->fetchrow_arrayref ) { push(@bky, $rr->[0]); } my $check_je = sub { my ($bky) = @_; if ( $dbh->lookup($bky, qw(Boekjaren bky_code bky_closed)) ) { $out .= _xt("cmd:jaareinde") . " --" . __xt("cmo:jaareinde:boekjaar") . "=" . _quote($bky) . " --" . __xt("cmo:jaareinde:definitief") . "\n"; } else { $sth = $dbh->sql_exec("SELECT COUNT(*)". " FROM Boekjaarbalans". " WHERE bkb_bky = ?", $bky); my $rr; if ( ($rr = $sth->fetchrow_arrayref) && $rr->[0] ) { $out .= _xt("cmd:jaareinde") . " --" . __xt("cmo:jaareinde:boekjaar") . "=" . _quote($bky) . "\n"; } $sth->finish; } if ( $dbh->does_btw ) { my $bb = $dbh->adm("btwbegin"); my $bke = $dbh->lookup($bky, qw(Boekjaren bky_code bky_end)); my $bkb = $dbh->lookup($bky, qw(Boekjaren bky_code bky_begin)); if ( $bb gt $bkb ) { $bke = parse_date($bb, undef, -1) if $bb le $bke; $out .= _xt("cmd:btwaangifte"). " --" . __xt("cmo:btwaangifte:periode") . "=". datefmt_full($bkb)."-".datefmt_full($bke) . " --" . __xt("cmo:btwaangifte:definitief") . " --" . __xt("cmo:btwaangifte:noreport") . "\n"; } } }; my $cur_bky = $bky[0]; foreach my $bky ( @bky ) { next if $bky eq BKY_PREVIOUS; if ( $cur_bky ne $bky ) { $check_je->($cur_bky); my $bp = $dbh->lookup($bky, qw(Boekjaren bky_code bky_btwperiod)); $out .= "\n# ". _T("Openen nieuw boekjaar") . "\n\n"; $out .= _xt("cmd:adm_boekjaarcode") . " " . _quote($bky) . "\n"; $out .= _xt("cmd:adm_btwperiode") . " " . lc(BTWPERIODES->[$bp]) . "\n" if $bp; $out .= _xt("cmd:adm_open") . "\n"; $cur_bky = $bky; } $out .= _xt("cmd:boekjaar") . " " . _quote($bky) . "\n"; $sth = $dbh->sql_exec("SELECT bsk_id, dbk_id". " FROM Boekstukken, Dagboeken". " WHERE bsk_dbk_id = dbk_id". " AND bsk_bky = ?". " ORDER BY dbk_type, bsk_dbk_id, bsk_nr", $bky); my $cur_dbk = ""; while ( my $rr = $sth->fetchrow_arrayref ) { my ($bsk_id, $dbk_id) = @$rr; if ( $cur_dbk ne $dbk_id ) { $out .= "\n"; $cur_dbk = $dbk_id; } $out .= EB::Booking::Decode->decode ($bsk_id, { trail => 1, d_boekjaar => $bky, bsknr => defined($opts->{bsknr}) ? $opts->{bsknr} : 1, single => $opts->{single} || 0, btw => $opts->{explicit} || 0, total => defined($opts->{totals}) ? $opts->{totals} : 1, debcrd => 0 }) . "\n"; } $out .= "\n"; } $check_je->($cur_bky); $out .= "# " . __x("Einde {what}", what => _T("Boekingen")) . "\n"; $out; } sub _xt { # scm:btw -> scm:vat -> vat my $t = _T(shift); $t =~ s/^.*://; $t; } 1; EekBoek-2.030.1/META.json0000644000400000040000000000333313151742350012404 0ustar jvjv{ "abstract" : "Bookkeeping software for small and medium-size businesses", "author" : [ "Johan Vromans (jvromans@squirrel.nl)" ], "dynamic_config" : 1, "generated_by" : "ExtUtils::MakeMaker version 7.24, CPAN::Meta::Converter version 2.150005", "license" : [ "unknown", "perl_5" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : "2" }, "name" : "EekBoek", "no_index" : { "directory" : [ "t", "inc", "lib/EB" ] }, "prereqs" : { "build" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "configure" : { "requires" : { "ExtUtils::MakeMaker" : "6.5503" } }, "runtime" : { "recommends" : { "DBD::Pg" : "1.41", "Getopt::Long" : "2.32", "HTML::Entities" : "1.35" }, "requires" : { "Archive::Zip" : "1.16", "DBD::SQLite" : "1.13", "DBI" : "1.40", "Getopt::Long" : "2.13", "Term::ReadLine" : "0", "Term::ReadLine::Gnu" : "0", "perl" : "5.008006" } }, "test" : { "requires" : { "IPC::Run3" : "0.034", "Test::More" : "0" } } }, "provides" : { "EekBoek" : { "file" : "lib/EekBoek.pm", "version" : "v2.30.1" } }, "release_status" : "stable", "resources" : { "homepage" : "https://www.eekboek.nl", "license" : [ "https://dev.perl.org/licenses/" ] }, "version" : "v2.030.1", "x_serialization_backend" : "JSON::PP version 2.27400" } EekBoek-2.030.1/META.yml0000644000400000040000000000176313151742350012241 0ustar jvjv--- abstract: 'Bookkeeping software for small and medium-size businesses' author: - 'Johan Vromans (jvromans@squirrel.nl)' build_requires: ExtUtils::MakeMaker: '0' IPC::Run3: '0.034' Test::More: '0' configure_requires: ExtUtils::MakeMaker: '6.5503' dynamic_config: 1 generated_by: 'ExtUtils::MakeMaker version 7.24, CPAN::Meta::Converter version 2.150005' license: unknown meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: EekBoek no_index: directory: - t - inc - lib/EB provides: EekBoek: file: lib/EekBoek.pm version: v2.30.1 recommends: DBD::Pg: '1.41' Getopt::Long: '2.32' HTML::Entities: '1.35' requires: Archive::Zip: '1.16' DBD::SQLite: '1.13' DBI: '1.40' Getopt::Long: '2.13' Term::ReadLine: '0' Term::ReadLine::Gnu: '0' perl: '5.008006' resources: homepage: https://www.eekboek.nl license: https://dev.perl.org/licenses/ version: v2.030.1 x_serialization_backend: 'CPAN::Meta::YAML version 0.018' EekBoek-2.030.1/MANIFEST0000644000400000040000000001124513151742350012115 0ustar jvjvCHANGES INSTALL MANIFEST Makefile.PL README README.emacs README.gui README.postgres contrib/API/example1.pl contrib/API/example2.pl contrib/API/example3.pl contrib/API/example4.pl contrib/afschrijvingen/afschr-gewoon.dat contrib/afschrijvingen/afschr-group.dat contrib/afschrijvingen/afschr.pl ebwxshell.desktop emacs/eekboek-mode.el emacs/eekboek-site-start.el lib/EB.pm lib/EB/Booking.pm lib/EB/Booking/BKM.pm lib/EB/Booking/Decode.pm lib/EB/Booking/Delete.pm lib/EB/Booking/IV.pm lib/EB/CPAN/App/Packager.pm lib/EB/CPAN/Term/ReadLine/Perl.pm lib/EB/CPAN/Term/ReadLine/readline.pm lib/EB/Config.pm lib/EB/Config/Data.pm lib/EB/DB.pm lib/EB/DB/Postgres.pm lib/EB/DB/Sqlite.pm lib/EB/Export.pm lib/EB/Export/XAF.pm lib/EB/Format.pm lib/EB/Globals.pm lib/EB/Import.pm lib/EB/IniWiz.pm lib/EB/Main.pm lib/EB/Relation.pm lib/EB/Report.pm lib/EB/Report/BTWAangifte.pm lib/EB/Report/BTWAangifte/Wxhtml.pm lib/EB/Report/Balres.pm lib/EB/Report/Balres/Wxhtml.pm lib/EB/Report/Debcrd.pm lib/EB/Report/Debcrd/Wxhtml.pm lib/EB/Report/GenBase.pm lib/EB/Report/Grootboek.pm lib/EB/Report/Grootboek/Wxhtml.pm lib/EB/Report/Journal.pm lib/EB/Report/Journal/Wxhtml.pm lib/EB/Report/Open.pm lib/EB/Report/Open/Wxhtml.pm lib/EB/Report/Proof.pm lib/EB/Report/Proof/Wxhtml.pm lib/EB/Report/Reporter.pm lib/EB/Report/Reporter/Csv.pm lib/EB/Report/Reporter/Html.pm lib/EB/Report/Reporter/Text.pm lib/EB/Report/Reporter/WxHtml.pm lib/EB/Shell.pm lib/EB/Shell/Base.pm lib/EB/Shell/DeLuxe.pm lib/EB/Tools/Attachments.pm lib/EB/Tools/Einde.pm lib/EB/Tools/MiniAdm.pm lib/EB/Tools/Opening.pm lib/EB/Tools/SQLEngine.pm lib/EB/Tools/Schema.pm lib/EB/Utils.pm lib/EB/Version.pm lib/EB/Wx/FakeApp.pm lib/EB/Wx/Help.pm lib/EB/Wx/IniWiz.pm lib/EB/Wx/IniWiz/OpenDialog.pm lib/EB/Wx/Shell/EditDialog.pm lib/EB/Wx/Shell/HtmlViewer.pm lib/EB/Wx/Shell/Main.pm lib/EB/Wx/Shell/MainFrame.pm lib/EB/Wx/Shell/PreferencesDialog.pm lib/EB/Wx/Shell/Window.pm lib/EB/examples/Kasverkoop.pm lib/EB/examples/README lib/EB/examples/Userdefs.pm lib/EB/examples/eekboek.conf lib/EB/examples/nl/bvnv.dat lib/EB/examples/nl/eenmanszaak.dat lib/EB/examples/nl/mutaties.eb lib/EB/examples/nl/ondernemer.dat lib/EB/examples/nl/opening.eb lib/EB/examples/nl/relaties.eb lib/EB/examples/nl/schema.dat lib/EB/examples/nl/vereniging.dat lib/EB/res/Wx/icons/button_ok.png lib/EB/res/Wx/icons/eb.icns lib/EB/res/Wx/icons/eb.ico lib/EB/res/Wx/icons/eb.jpg lib/EB/res/Wx/icons/ebicon.png lib/EB/res/Wx/icons/ebwiz.jpg lib/EB/res/Wx/icons/edit.png lib/EB/res/help/nl/docs.htb lib/EB/res/migrate/001000008001000009.pl lib/EB/res/migrate/001000009001000010.sql lib/EB/res/migrate/001000010001000011.sql lib/EB/res/migrate/001000011001000012.sql lib/EB/res/migrate/001000012001000013.sql lib/EB/res/migrate/001000013001000014.sql lib/EB/res/migrate/001000014001000015.sql lib/EB/res/migrate/001000015001000016.sql lib/EB/res/migrate/001000016001000017.sql lib/EB/res/schema/eekboek.sql lib/EB/res/templates/nl/bvnv.ebz lib/EB/res/templates/nl/eenmanszaak.ebz lib/EB/res/templates/nl/ondernemer.ebz lib/EB/res/templates/nl/sampledb.ebz lib/EB/res/templates/nl/templates.txt lib/EB/res/templates/nl/vereniging.ebz lib/EB/res/templates/sample.conf lib/EB/user/css/balans.css lib/EB/user/css/balres.css lib/EB/user/css/btwaangifte.css lib/EB/user/css/crdrept.css lib/EB/user/css/debcrd.css lib/EB/user/css/debrept.css lib/EB/user/css/eekboek.css lib/EB/user/css/grootboek.css lib/EB/user/css/journaal.css lib/EB/user/css/openstaand.css lib/EB/user/css/proef.css lib/EB/user/css/result.css lib/EekBoek.pm script/ebpp.PL script/ebshell.pl script/ebwxshell.pl t/10_basic.t t/20_dates.t t/30_amounts.t t/31_expr.t t/80_db_postgresql.t t/81_db_sqlite.t t/90_ivp_common.pl t/91_ivp_sqlite.t t/92_ivp_postgres.t t/ivp/ivp.conf t/ivp/ref/balans.html t/ivp/ref/balans.txt t/ivp/ref/balans0.txt t/ivp/ref/balans1.txt t/ivp/ref/balans2.csv t/ivp/ref/balans2.html t/ivp/ref/balans2.txt t/ivp/ref/balans2xxx.html t/ivp/ref/balans2xxx.html t/ivp/ref/btw.html t/ivp/ref/btw.txt t/ivp/ref/btw7.txt t/ivp/ref/btwk2.txt t/ivp/ref/crdrept.txt t/ivp/ref/debrept.txt t/ivp/ref/export.xaf t/ivp/ref/grootboek.txt t/ivp/ref/grootboek0.txt t/ivp/ref/grootboek1.txt t/ivp/ref/grootboek2.txt t/ivp/ref/grootboek_2.txt t/ivp/ref/grootboek_23.txt t/ivp/ref/grootboek_2320.txt t/ivp/ref/grootboek_23_22.txt t/ivp/ref/journaal-postbank.txt t/ivp/ref/journaal-postbank24.txt t/ivp/ref/journaal.txt t/ivp/ref/obalans.txt t/ivp/ref/proef.txt t/ivp/ref/proef0.txt t/ivp/ref/proef1.txt t/ivp/ref/proef2.txt t/ivp/ref/result.txt t/ivp/ref/result0.txt t/ivp/ref/result1.txt t/ivp/ref/result2.txt t/ivp/reports.eb META.yml Module YAML meta-data (added by MakeMaker) META.json Module JSON meta-data (added by MakeMaker) EekBoek-2.030.1/README.emacs0000644000400000040000000000110112725476602012733 0ustar jvjvThe EekBoek kit contains two files to be used with GNU Emacs. eekboek-mode.el defines the 'eekboek' major mode for editing EekBoek data files. It is nothing fancy yet. eekboek-site-init.el contains the necessary autoload settings and type associations for EekBoek files. Place these files according to how your distribution configures GNU Emacs. For Fedora systems: /usr/share/emacs/site-lisp/site-start.d/eekboek.el /usr/share/emacs/site-lisp/eekboek-mode.el For Debian systems: /etc/emacs/site-start.d/50eekboek.el /usr/share/emacs/site-lisp/eekboek-mode.el EekBoek-2.030.1/Makefile.PL0000755000400000040000000001070013151274217012736 0ustar jvjv# Makefile.PL -- Build file for EekBoek # Author : Johan Vromans # Created On : Fri Sep 2 14:25:11 2005 # Last Modified By: Johan Vromans # Last Modified On: Tue Aug 29 16:22:07 2017 # Update Count : 119 # Status : Unknown, Use with caution! # Ease the life of the CPAN testers. exit 0 if $ENV{AUTOMATED_TESTING} && $] < 5.008006; use 5.008006; use strict; # EU::MM 6.5503 is the first version to understand *_REQUIRES. use ExtUtils::MakeMaker 6.5503; my $distname = 'EekBoek'; my $version = MM->parse_version('lib/EB/Version.pm'); my @bins = qw( ebshell ebwxshell ); # Warn on non-standard install locations. checkbin(< $distname, AUTHOR => 'Johan Vromans (jvromans@squirrel.nl)', ABSTRACT_FROM => 'lib/EekBoek.pm', PL_FILES => {'script/ebpp.PL' => [ map { "script/$_" } @bins ]}, INSTALLDIRS => 'site', DISTNAME => $distname, EXE_FILES => [ map { "script/$_" } @bins ], VERSION => $version, MIN_PERL_VERSION => 5.008006, PREREQ_PM => { 'Getopt::Long' => '2.13', 'Term::ReadLine' => 0, $^O eq "linux" ? ('Term::ReadLine::Gnu' => 0) : (), 'DBI' => '1.40', 'Archive::Zip' => '1.16', 'DBD::SQLite' => '1.13', }, CONFIGURE_REQUIRES => { 'ExtUtils::MakeMaker' => 6.5503, }, # BUILD_REQUIRES => { # }, TEST_REQUIRES => { 'Test::More' => 0, 'IPC::Run3' => 0.034, }, PM => filelist("lib", '$(INST_LIBDIR)/'), META_MERGE => { license => "perl", resources => { license => "https://dev.perl.org/licenses/", homepage => "https://www.eekboek.nl", repository => { web => "https://sourceforge.net/p/eekboek/code/", url => "git://git.code.sf.net/p/eekboek/code", type => "git", }, }, recommends => { 'DBD::Pg' => 1.41, 'Getopt::Long' => 2.32, 'HTML::Entities' => 1.35, }, provides => { 'EekBoek' => { file => "lib/EekBoek.pm", version => $version }, }, no_index => { directory => [ "lib/EB", ], }, }, ); # Write .spec file, Debian control, ... ProcessTemplates($distname, $version); ################ Subroutines ################ use Config; sub checkbin { my ($msg) = @_; my $installscript = $Config{installscript}; return if $installscript eq "/usr/bin"; print STDERR < ) { chomp; next unless /$dirp(.*)/; $pm->{$_} = $pfx ? $pfx . $1 : $_; } close($mf); $pm; } sub ProcessTemplates { my $name = shift; my $version = shift; my ($mv) = $version =~ /^\d+\.(\d+)/; my %vars = ( PkgName => $name, pkgname => lc($name), version => $version, stable => $mv % 2 ? "-unstable" : "\%nil", stability => $mv % 2 ? "unstable" : "stable", ); vcopy( _tag => "XAF ref file", _dst => "t/ivp/ref/export.xaf", %vars); =begin Fedora vcopy( _tag => "RPM spec file", _dst => "$name.spec", %vars); =cut =begin Debian vcopy( _tag => "Debian control file", _dst => "debian/control", %vars); vcopy( _tag => "Debian rules file", _dst => "debian/rules", %vars); ); chmod((((stat("debian/rules"))[2] & 0777) | 0111), "debian/rules"); vcopy( _tag => "Debian changelog file", _dst => "debian/changelog", %vars); =end =cut } sub vcopy { my (%ctrl) = @_; $ctrl{_src} ||= $ctrl{_dst} . ".in"; return unless open(my $fh, "<", $ctrl{_src}); print("Writing ", $ctrl{_tag}, "...\n") if $ctrl{_tag}; my $newfh; open ($newfh, ">", $ctrl{_dst}) or die($ctrl{_dst}, ": $!\n"); my $pat = "("; foreach ( grep { ! /^_/ } keys(%ctrl) ) { $pat .= quotemeta($_) . "|"; } chop($pat); $pat .= ")"; $pat = qr/\[\%\s+$pat\s+\%\]/; while ( <$fh> ) { s/$pat/$ctrl{$1}/ge; print { $newfh } $_; } close($newfh); } 1; EekBoek-2.030.1/CHANGES0000644000400000040000000015437613151742245011777 0ustar jvjv2.030.1 Aug 31, 2017 * File::Glob fix for Perls older than 5.16. Not really an emergency. 2.03 Aug 29, 2017 * Boekingen kunnen een bijlage krijgen, b.v. een PDF van de faktuur. * Fix IVP tests to use bsd_glob instead of glob. This is necessary for Perl 5.26 and above. * Fix Build.PL for no_index. * Actualiseren URLs in documentatie etc.. * Check relatiecodes voor geldigheid: max. 10 tekens, niet beginnend met NN- ivm parseproblemen. * Build procedure verloopt weer via ExtUtils::MakeMaker (Makefile.PL) aangezien Module::Build (Build.PL) obsoleet is. * Fix problemen met het verwijderen van '.' in @INC (perl 5.26). * Fix probleem dat maart 2013 loopt van 2013-03-01 t/m 2013-03-30. Oorzaak is de zomertijd die op 30 maart 2013 inging. * Rond bedragen niet af in de melding "Er is een verschil...". * Taalinstellingen zijn niet langer mogelijk. Deze veroorzaakten teveel problemen en misverstanden. * (contrib/API/example1.pl) Waarschuwing inzake SQL op de database. * (example schemas) Aanpassen beschrijving van het :dc attribuut. * Onderdruk de INTERNAL ERROR op open transacties tenzij gevraagd via de config settings. * Sta :btw=prive toe in het schema. * Automatisch toevoegen van BTW 0 als deze in het schema ontbreekt. * Aanpassen examples aan moderne BTW codes. * Op sommige systemen crashte de GUI shell wanneer bij het bekijken van een rapport window op de [Opslaan] button wordt gedrukt. * Op Windows systemen werkten de pijltjestoetsen niet in command line mode. * Aangezien de volledige documentatie beschikbaar is in de EekBoek hulp browser wordt deze niet meer apart meegeleverd. * Diverse kleine bugfixes en optimalisaties. 2.02.00 2012-09-18 14:37 * Update documentation, site, help documents. * Update relnotes-2.02 document. * Update README.201210 document. * Aanpassen spec file t.b.v. rpm bouwers. 2.01.06 2012-08-31 22:24 * Eerste beta voor 2.02. * Openen van een nieuw boekjaar is nu mogelijk vanaf juli. * Kleine bugfixes in de nieuwe BTW tariefcodes en afhandeling daarvan. 2.01.05 2012-08-30 11:30 * Voeg de README.201210 toe aan de kit :) 2.01.04 2012-08-29 21:50 * Verschillende wijzigingen in het definiëren en gebruiken van BTW tariefcodes in verband met de invoering van een nieuw BTW tarief per 1 oktober 2012. Zie het bestand README.201210 voor alle details. * Er is nu ook een engelstalige IVP (installatie-verificatie procedure) * Config setting voor errexit waarmee het effect van de command line optie --errexit permanent kan worden afgedwongen voor alle niet-interactieve EekBoek verwerkingen. [shell] errexit = 1 * Elimineer de undefined warning als er geen LANG environment variabele is gezet. * Script om het EekBoek versienummer uit de git repo te halen. 2.01.03 2012-08-01 20:55 * (Bootstrap) Seriële make afdwingen. * Voor het afletteren wordt de boekingsdatum gebruikt, en niet langer de boekingsvolgorde. * Term::ReadLine: Fallback naar T::R::Perl (meegeleverd) met command history en completion. * Er wordt een waarschuwing gegeven wanneer in een boeking '@H' en/of '@L' wordt gebruikt en er meerdere BTW tarieven corresponderen met '@H' of '@L'. * In het grootboek commando kunnen nu ook (hoofd)verdichtingen worden opgegeven. * Voer een rollback uit wanneer een mislukte opdracht dat vergeet te doen. Dit is een tijdelijke stoplap totdat alle opdrachten zich keurig aan de regels voor database transacties houden. * Deprecieer het plaatsen van een D of C na het rekeningnummer bij de specificatie van relaties. * Fix bug 3510006. * Fix bug 3499522. * Many translation / localisation changes for the on-going translatability project. * Several small updates to work with wxWidgets 2.9.x. * Eliminated using Wx :allclasses and :everything. This solves some problems with Cava packager and Wx 2.9.x. * Fix typo in messages (Issue #3477452). * Fix --help handling. * Fix bug #2624283 Dagboeken met whitespace erin worden intern van een underscore voorzien. Dus de opdrachten "Post Bank" "post bank" en post_bank en POST_bank zijn gelijkwaardig. Voor de export wordt de lowercase met underscores naam gehanteerd (zoals al het geval was). * Fix bug #2209529 Dagboeknamen die overlappen met ingebouwde commando's worden niet meer toegestaan. 2.01.02 2011-07-28 21:31 * (ebshell, ebwxshell) Forceer locale naar nl_NL totdat de engelse vertaling klaar is. * (ebshell) Verwijder de Term::ReadLine::Gnu fallback hack zodat de workaround met PERL_RL weer bruikbaar is. * (ebshell) Accepteer commando's weer case-insenstive. 2.01.01 2011-07-25 08:11 * Alle programmacomponenten zijn nu in het Nederlands. Er is nog één enkele vertaling, namelijk die van Nederlands naar Engels. 2.01.00 2011-07-21 22:04 >>> Nieuwe database versie; auto-migratie beschikbaar <<< * Interne cleanups en rework voor de EekBoek API. * Localisatie cleanup. Alle componenten gedragen zich nu gelocaliseerd. De locale instelling wordt initieel overgenomen van de omgeving. De wizards nemen de locale op in de gegenereerde config file. Locale switching op run time is mogelijk. * Verbetering wizards om aan bestaande databases (op server) te kunnen connecten. * Introductie resource- en user-dir. Resources en user info kunnen locale-dependent zijn. * Packaging met Cava Packager en Windows installer met InnoSetup. * Fix bug #3374176. BELANGRIJK: Administraties die last hebben van deze bug moeten opnieuw worden aangemaakt. 2.00.03 2011-03-22 20:42 * (schema) Fix probleem dat het gebruik van een ongedefinieerde BTW tariefgroep onopgemerkt bleef wanneer er wel een groep was gedefinieerd met een afwijkende exclusiviteit. 2.00.02 2010-05-06 * (ebwxshell, linux) Workaround voor het HTML rendering probleem met wxPerl versies 0.95 en 0.95. Dit probleem treft met name Ubuntu 10.4 LTS. * (ebshell) Meer flexibele invoer. Accepteer newlines en returns als regeleinde. Negeer trailing whitespace. Dit elimineert het probleem van spaties achter de laatste backslash. * (eekboek-mode.el) Kleine, niet strict noodzakelijke verbetering. * (ebshell, errexit) Invoerverwerking afbreken indien er een foutboodschap is gegeven. * INSTALL: Refereer naar de wiki. 2.00.01.01 * Packaging for Windows: (build_common.pl) use PL_files to avoid .pl files to be processed. 2.00.01 2010-03-28 20:42 * Fix probleem met Term::ReadLine::Perl. Gebruik in plaats daarvan Term::ReadLine::Gnu. Meest relevant voor Windows en MacOSX. * Elimineer File::HomeDir. Relevant voor MacOSX, omdat de benodigde Mac::Files daar problematisch is en enkel in 32bit beschikbaar. * Nieuwe packaging. Default is cli, gui is optioneel, contrib verhuist naar de wiki. 2.00.00 2010-03-23 20:59 * Release 2.00.00 2.00.00.RC03 2010-03-22 14:04 * Fix probleem dat een overbodige dialoog vraagt om een eekboek.conf. 2.00.00.RC02 2010-03-17 13:40 * Tweede release candidate 2.00. * Diverse fixes voor Windows. * Fix probleem met niet eenduidige interpretatie van getallen. In expressies als "5*0.005" werd 0.005 als 5 gezien i.p.v. 0,005. * Kleine verbeteringen in de wizards. 2.00.RC01 2010-03-12 23:13 * Eerste release candidate 2.00. * (iniwiz) Fix dubbele foutmelding. * Kleine, maar belangrijke aanpassingen t.b.v. Microsoft Windows. * Onderhoud vertalingen toegevoegd aan de kit. 1.05.20 2010-02-19 23:26 * Documentatie aanpassingen. * (iniwiz) Fix probleem met crash na db selectie. * Fix probleem met \ op laatste regel. (wbwxshell) Fix probleem met de result rapporten. 1.05.19 2010-01-27 10:25 * (ebshell) Fix unicode probleem in help strings. * (ebshell) Fix unicode probleem in wizard waardoor administratie namen/codes geen non-ascii tekens konden bevatten. 1.05.18 2010-01-26 10:56 * (ebwxshell) Fix unicode issues. * (ebwxshell) Filter duplicaten uit de history en beperk het aantal teruggeschreven regels tot een instelbaar maximum (default 200). * Upgrade Wx::Perl::ProcessStream to 0.24. 1.05.17 2010-01-22 13:10 * Nieuw command: schema. Hiermee kunnen interactief (vooralsnog alleen) grootboekrekeningen worden aangemaakt. Onderhoud van het schema. Deze opdracht kent sub-opdrachten: schema [ ] Aanmaken grootboekrekening schema gbk [ ] de gewenste grootboekrekening D/C voor Debet / Credit K/O/N voor Kosten / Omzet / Neutraal Eventueel gevolgd door ! als deze balansrekening vast staat aan één kant De omschrijving van deze grootboekrekening De verdichting waaronder deze rekening valt Wanneer enkel een nummer wordt opgegeven dan worden de gegevens van de betreffende grootboekrekening getoond. * Fix probleem met completion van rekeningnummers. * Upgrade Module::Build to 0.32 to have decent prereq support. 1.05.16 2010-01-17 00:14 * (ebshell) Non-zero exit status indien fouten zijn opgetreden. Dit kan consequenties hebben als ebshell wordt toegepast in makefiles. * (ebshell) Verwijderen opties --createsampleconfig en --createsampledb (vervangen door de wizard). * (ebshell, wizard) Gebruik eigen code (recursief) om --init uit te voeren. * (ebshell, shell) Grote opruiming. * (migration) Fix: DB automigratie van SQLite zat PostgreSQL in de weg. 1.05.15 2010-01-16 16:32 * Small changes for the packaging. 1.05.14 2010-01-13 11:12 * (ebwxshell) Icon buttons i.p.v. [Edit] en [Send]. Conform to Gnome Human Interface Guide. * (ebwxshell, editdialoog) Resizable, onthoudt size/pos. * (ebwxshell) Meer rapporten in het menu. * (ebwxshell) EditDialog meeleveren :) * Eerste herziening van de documentatie. * Fix test probleem op een virgo install. * Fix probleem met het verwerken van het schema (privé werd niet herkend). * Kleine aanpassingen om het opstartgedrag van ebshell en ebwxshell consistent te maken. 1.05.13 2010-01-06 21:21 1.05.12 2010-01-06 20:09 === EXPERIMENTAL === * De configuratie file mag nu ook "eekboek.conf" heten. Sterker nog, "eekboek.conf" wordt geprefereerd boven ".eekboek.conf". Dus wanneer beide er zijn wordt alleen "eekboek.conf" gebruikt. Wanneer nieuwe files worden aangemaakt wordt alleen "eekboek.conf" aangemaakt. Wanneer er alleen ".eekboek.conf" bestanden zijn moet het gedrag ongewijzigd zijn gebleven. 1.05.11 2010-01-06 13:56 * (ebwxshell, wizard) Verplicht unieke administratie naam en code. * (ebshell) Wizard om administraties aan te maken. * (ebwxshell) Mogelijkheid om de input regel uitgebreid te editen, inclusief multi-line support. 1.05.10 2009-12-23 22:32 * (ebwxshell) Persistent window size/positions. * (MS-Windows) Consequent gebruik van de registry. HKCU\Software\Squirrel Consultancy\EekBoek\ebwxshell * (Config) Gebruik HOMEDRIVE/HOMEPATH voor Windows. 1.05.09 2009-12-23 13:18 * (ebwxshell) Drill-down. In de rapportage windows kun je klikken op (de meeste) grootboeknummers, journaalposten en relatiecodes om daarmee het bijbehorende overzicht op te roepen. Voor het beste resultaat verdient het aanbeveling de preference "Rapporten in hetzelfde venster" uit te zetten. 1.05.08 2009-12-22 23:00 * Configuratie files: [locale] lang werkt nu (weer). [database] - fullname is vervallen. - name prefix "eekboek_" wordt niet langer gestript. - driver = sqlite is nu default. * (ebwxshell) Fix preferences save/restore. * examples/eekboek.conf bijgewerkt. * Meer vertaald. 1.05.07 2009-12-22 14:00 * (ebwxshell) Preferences voor error/warning/info popup windows. * (ebwxshell) Icon. * (ebwxshell) Altijd wizard/sel opstarten, ook als er een .eekboek.conf is. 1.05.06 2009-12-20 13:18 * Fix probleem dat ebshell niet langer create{database|sampleconfig} kon doen. * Missend icon toevoegen. * ebwxshell installeren ipv. ebgui. * Nieuwe settings toegevoegd aan examples/eekboek.conf. 1.05.05 2009-12-19 15:23 * Integratie met EB WxShell. * Verwijder (tijdelijk) GUI voor ombouw tot browser. * (Wizard) Config 'admdir' in sectie '[general]' kan worden gebruikt om te bepalen waar de administraties (moeten komen te) staan. * (Wizard) Voorkom dat de verkeerde ebshell wordt opgestart. * (Wizard) Gebruik de voorbeeldadministratie als default. * Bugfix (regressie) BTW werd niet afgeboekt in de volgjaren van een meerjarige boekhouding. * Bugfix: meervoudige definitie van 'min' in EB/Tools/Einde.pm. * Bugfix: ebgui kende --[no]wizard niet. * (Wizard): Defaults voor adm code en database naam. 1.05.04 2009-10-28 23:47 * Many internal changes for GUI integration. * Consistent gedrag gui/wizard. 1.05.03 2009-10-27 16:15 * !!! SNAPSHOT !!! SNAPSHOT !!! SNAPSHOT !!! * (GUI) Bugfix: Dagboeken -> Inkoop/Verkoop hadden geen title. * (Wizard) Toon alle beschkbare database drivers. * (Wizard) Fix vertaling buttons. * (Wizard) Ingave database folder. * (Wizard) Automatisch vormen van database naam uit de naam van de administratie. * (GUI) Aanmaken van en kiezen uit administraties die in een folder zijn ondergebracht. --admdir command line optie. 1.05.02 2009-10-19 11:47 * !!! SNAPSHOT !!! SNAPSHOT !!! SNAPSHOT !!! * (GUI) Verhelpen probleem van opstarten GUI vanuit Wizard. * Verhelpen probleem met de voorbeeldadmin (mutaties waren nog niet omgezet naar UTF-8). 1.05.01 2009-10-18 22:46 * !!! SNAPSHOT !!! SNAPSHOT !!! SNAPSHOT !!! * (GUI) Templates voor de setup wizard. * Discontinueer ondersteuning voor latin1 bestanden. Alles is nu UTF-8. * Export ondersteunt --titel (omschrijving van de export kit). Vooralsnog alleen relevant voor export naar ebz file. * (GUI) Export/EekBoek: Omschrijving kan worden opgegeven. * (GUI) IniWiz: Gebruik omschrijving in de templates lijst. * (SQLite) Config database::path bepaalt waar de databases worden neergezet. * Andere processing van de configuratiefiles. Mag geen zichtbare gevolgen hebben. * Andere processing van numerieke expressies in bedragen. Mag geen zichtbare gevolgen hebben. * Bedragen mogen nu ook worden ingegeven met duizendtalscheidingstekens, dus b.v. 1.234,56 of 1,234.56 . * (IVP) Verbetering opzet en afhandeling. * (Config) format:amount vervangt locale:decimalpt, locale:thousandsep en text:numwidth. 1234.56 -> dpt = "." 1234,56 -> dpt = "," 1.234,56 -> dpt = ",", sep = "." 1,234.56 -> dpt = ".", sep = "," 1.234.567,89 -> dpt = ",", sep = ".", width = 12 De width wordt alleen aangepast als het format breder is dan 9 tekens. 1.05.00 2009-10-09 17:50 * !!! SNAPSHOT !!! SNAPSHOT !!! SNAPSHOT !!! * (GUI) Admin setup wizard. * Strafbankje voor balansrekeningen. * Fix problem dat 'privé' niet wordt gematched als content-type = utf8 en $cfg->unicode. 1.04.04 2009-06-10 12:13 * Bugfix voor --createsampleconfig . * Bugfix voor --createsampledb . 1.04.03 2009-04-03 12:18 * Consolidatie. Geen wijzigingen. 1.04.02 2009-01-25 21:20 * Nieuwe voorbeeldmodule voor userdefs: examples/Kasveroop.pm . * bkm_multi: Fix probleem dat de intern aangemaakte boekingen worden geformatteerd volgens thousandsep, wat ongeldige invoer kan opleveren. * Fix bug 2172095. 1.04.01 2008-09-04 * Fix probleem met Windows Vista. 1.04 2008-08-30 10:53 * Versienummer aangepast. 1.03.93 2008-08-24 18:52 * Revisie en actualisatie on-line documentatie. 1.03.92 2008-08-10 21:18 * Kleine verbeteringen XAF export. Fix --boekjaar voor --xaf export. * Verwijder --boekjaar optie voor gewone export. 1.03.91 2008-08-02 15:06 (CPAN only) * Bugfix headerinderdrukking van de BTW-aangifte. 1.03.90 2008-07-19 18:58 * Alle rapporten in HTML kunnen een expliciete titel meekrijgen: balans --title="Voorlopige balans 2009" --out=x.html * Bugfix: Meer dan één -D / --define op de command line mogelijk. * Kleine wijzigingen in het verwerken van de config files. De ".eekboek.conf" in de huidige directory wordt niet langer meegenomen indien ebshell wordt opgestart met een "-f" optie. 1.03.13 2008-04-13 16:09 * Voorkom warnings indien bij de BTWaangifte er geen voorheffingen hebben plaatsgevonden in de periode waarover aangifte wordt gedaan. * (EB::Report::Genbase) Geen backends laden indien AUTOMATED_TESTING. Hiermee worden test failures vermeden indien er achterhaalde EekBoek installaties rondzwerven. * Oplossen installatieprobleem met RPM. * Uitbreidingen contrib/afschr.pl . 1.03.12 10-04-2008 13:47 * BKM deb/crd boeking gebruikt altijd de standaardrekeningen voor deb/crd i.p.v. de aan het dagboek gekoppelde rekening. * Kleine wijzigingen in de BTW rapportage. * Debian kit is now also 'unstable'. 1.03.11 22-032008 17:07 * BTW tariefgroepen Privé en Anders. In schema: 5 BTW Privé :tariefgroep=privé :perc=12,00 :exclusief 6 BTW Anders :tariefgroep=anders :perc=14,50 :exclusief Als deze taeriefgroepen worden opgevoerd dan moeten de betreffende koppelingen ook worden opgegeven: 4240 D BTW Inkoop Anders :koppeling=btw_ia 4250 C BTW Verkoop Anders :koppeling=btw_va Etc. BTW 'Privé' komt in de BTW aangifte in groep 1d, BTW 'Anders' komt in groep 1e. Deze groepen worden niet op het aangifteformulier vermeld als de betreffende tariefgroep ontbreekt. * BTW Aangifte: Uitgebreidere signalering discrepanties in BTW posten. * Kleine wijzigingen in de BTW rapportage. * EekBoek shell opdrachten zijn nu case-insensitive. * contrib/afschr.pl: tooltje om afschrijvingen te berekenen. * Fix regressie in debiteuren/crediteuren overzichten. * CPAN testing: Skip silently if perl < 5.8.3. 1.03.10 27-02-2008 11:55 * CPAN testing: Skip PostgreSQL tests if no database access. * CPAN testing: Encode reference data to UTF-8 if running in an Unicode environment. * Fix issue 1901436. 1.03.09 25-02-2008 13:01 * Update PPD met 5.10 info. * --config (-f) accepteert nu ook de naam van een directory, en probeert dan eekboek.conf en .eekboek.conf. * Commando's 'journal', 'trace' en 'confirm' kennen nu een'--quiet' optie, waardoor de opdrachten stil worden uitgevoerd. * Journaalposten worden niet meer gerapporteerd tijdens import en init. * Nieuw, actueel, eenvoudiger en beter schema voor de example database. * Verified to work with Perl 5.10.0 and DBD::Pg 2.0.0. * CPAN testing: Fix problems that cause the wrong perl to be used. * CPAN testing:Fix problems that cause the wrong sample files to be used. * Elimineer warnings bij export van administraties die niet alle standaardkoppelingen hebben. * Fix issue 1871576. 1.03.08 15-02-2008 21:08 * Boekingen in een periode waarover BTW aangifte is gedaan kunnen toch worden gewijzigd als deze boeken geen betrekking heeft op de BTW (m.a.w., BTW type Neutraal). * Fix problem met #! in ebshell script bij CPAN build. * Kleine aanpassingen t.b.v. de GUI. 1.03.07 06-02-2008 18:12 * Fix bug waardoor een adm_relatie met datum 31-12 niet werd geaccepteerd wanneer er al eerdere boekingen in dat jaar waren. * Fix bug waardoor openstaande posten uit voorgaande jaren XXXX leidden tot de melding "Boekjaar XXXX nog niet afgesloten". * Fix auto-migratie bug. 1.03.06 05-02-2008 11:57 * Enkele aanpassingen in het strategy:bkm_multi gebeuren. Omdat het zoekproces enige tijd in beslag kan nemen (enkele minuten bij 25 openstaande posten) is een begrenzing ingebouwd. Config: strategy:bkm_multi_max (default = 15). * Bij een inkoop/verkoop boeking kun je een willekeurige (moet tenminste één niet-cijfer bevatten) string opgeven als referentie: inkoop 25-12 CREDITEUR "Diversen" --ref="P24XyzBla!" 100 Een geschikte kandidaat is b.v. het faktuurnummer van de klant, of een ordernummer. Deze referentie kun je later gebruiken bij de betaling: postbank 25-12 Afschrijving \ crd 25-12 "CREDITEUR:P24XyzBla!" -100 Dus net zoals: postbank 25-12 Afschrijving \ crd 25-12 inkoop:54 -100 Overigens met dezelfde functionaliteit: er wordt niet gekeken of de boeking open staat. Je kunt dus op deze manier ook op voorhand boeken. De combinatie relatiecode - referentie moet per boekjaar uniek zijn. * De journaal-rapporten laten nu ook de relatiecodes zien bij inkoop- en verkoopboekingen. * Bij de rapportage openstaande posten kan nu ook worden geselecteerd dat alleen de debiteuren, crediteuren, of een enkele relatie wordt weergegeven. * Bij de crediteuren/debiteurenrapportages kan nu ook worden aangegeven dat alleen de openstaande posten moeten worden weergegeven. Let op: Openstaande posten van voorgaande boekjaren worden NIET vernmeld. * Fix enkele problemen met SQLite en Unicode. * Makefile.PL toegevoegd. * Nieuwe configuratie setting: [preferences] journal = 1 Hiermee wordt na elke boeking automatisch de betreffende journaalpost getoond. Deze preference setting vervangt de command line optie "--journaal". * Command line optie "--init". Hiermee wordt een nieuwe administratie opgezet in de huidige directory. Equivalent met "--import --dir=.". * Command line opties "--database" (en de verkorte vorm, "--db") en "--journaal" komen binnenkort te vervallen. * LET OP: EekBoek met SQLite ondersteunt niet de opdracht "import". Importeren uitsluitend met de command line versie ebshell --import ... * Database structuur is gewijzigd, auto-migratie is beschikbaar. Let op: automigratie voor SQLite geeft een foutmelding: !De database wordt aangepast aan de nieuwere versie DBD::SQLite::st execute failed: database schema has changed(1) ... DBD::SQLite::st execute failed: database schema has changed(1) ... De migratie is echter ok. Daarna kun je opnieuw opstarten. 1.03.05 28-10-2007 20:57 IV Boekingen: Config optie strategy:iv_vc. Bij het boeken in een Inkoop- of Verkoopdagboek wordt BTW berekend per boekstukregel. Sommige leveranciers berekenen echter de BTW over het totaal van de boekstukregels. Daardoor kunnen afrondingsverschillen ontstaan met als gevolg een boekstuktotaal dat niet klopt met de opgegeven waarde. De boeking zal dan worden geweigerd. EekBoek zal proberen zo'n boeking te corrigeren door de BTW te herberekenen over het totaal. Er wordt dan een melding gegeven, en een correctieboekstukregel aangemaakt. Dit gedrag kan worden afgezet door de strategy optie iv_vc de waarde 0 te geven. 1.03.04 18-07-2007 19:15 WAARSCHUWING: Hoewel de database niet is gewijzigd moeten bestaande administraties worden geëxporteerd en weer geïmporteerd. Dit kan met de nieuwe versie van EekBoek, dus na de upgrade. BTW Aangifte: Toon ook het onafgeronde totaal en de afronding. BTW Aangifte: Optie --noround voor een onafgerond rapport. BTW Aangifte: Fix probleem met relaties die zowel debiteur als crediteur zijn. BKM Boekingen: Config optie strategy:bkm_multi. Indien gezet en niet nul (kortom, true) dan wordt in geval een boeking niet kan worden gematched tegen een openstaande post geprobeerd of deze boeking wellicht voor meerdere openstaande posten tegelijk bedoeld is. Klant-specifieke wijzigingen in de (niet ondersteunde) DaviAccount import module. 1.03.03 27-06-2007 12:39 BKM Boekingen: Toon bedrag en relatie indien geen openstaande post kan worden gevonden. Shell: Optie --errexit: Verwerking van invoer breekt direct af na geconstateerde fouten. Shell: Optie --[no]interactive om interactief gedrag te forceren ook al komt de invoer niet van een terminal. Niet bedoeld voor uitwendig gebruik. Redesign en implementatie van de reporter backends. eekboek-mode.el: Emacs major mode voor EekBoek data. Kleine bugfixes. 1.03.02 04-02-2007 21:29 Fix probleem met foutieve export van adm_btwperiode in multi-jaar admin (issue 1628783). HTML reports: Use normal comments /* */ instead of for included styles. Voorbeeldschema's verplaatst van lib/EB/schema naar lib/EB/example. Voorbeelden verplaatst van lib/EB/example naar lib/EB/examples. Nieuw voorbeeldschema voor een vereniging, met dank aan Edwin Hakkennes. Fix probleem met UTF-8 data in Latin1 files in export zip. 1.03.01 27-12-2006 15:48 *** DATABASE STRUCTUUR IS GEWIJZIGD *** Export de data voor de upgrade! Database migratie werkt alleen met PostgreSQL. Optie: --createsampledb. Geen gezeur meer over de plaats van de demo data, of gecompresste data files. Debiteuren en crediteuren kunnen nu per dagboek verschillend worden opgegeven. Fix probleem met jaareinde van BTW-loze administratie. Fix probleem met rapportbreedte jaareinde. Fix probleem met SQLite en opdrachten die direct na een createdb/schema worden uitgevoerd, zoals b.v.: $ cat relaties.eb opening.eb | ebshell --createdb --schema=schema Fix probleem met het opruimen van de directories na (rpm) uninstall. 1.03.00 13-12-2006 21:55 Expliciete controle of een nieuw boekstuknummer nog vrij is, ter voorkoming van een onvriendelijke "dup key" melding. Fix bug met strings in de export die " en \ bevatten. Expliciete(re) sorteervolgorde voor alle uitvoer. Afronding mogelijk via 'bankers rounding'. 1.02.01 Config::IniFiles is nu onderdeel van EekBoek en hoeft niet langer apart te worden geïnstalleerd. Fix migratieprobleem 1.0.9 -> 1.0.10 voor PostgreSQL 7.x of zo. 1.02.00 2006-10-23 12:15 Release 1.02.00. 1.01.03 -> 1.02.00 Elimineer setting van environment variabelen in de lees-loop. Foute opdrachten als "foo=bar" werden daardoor niet gezien. 1.01.02 2006-10-16 22:36 Fix bug in export van :dc property voor dagboeken. Foutmelding "geen schema" is nu "geen database schema" om onderscheid te maken met het rekening schema. Kleine workarounds i.v.m. het INIT block probleem van PAR. Multi-user implementatie van sequences voor SQLite. Deze database zou daarom nu ook volledig multi-user moeten kunnen worden gebruikt. 1.01.01 2006-10-13 15:59 Fix migratieprobleem 1.0.9 -> 1.0.10. 1.01.00 2006-10-13 14:34 Retrofit: Hernoem de rpm's naar EekBoek-unstable. 1.01.00 2006-10-11 15:15 Support voor SQLite database. Inclusief IVP test. Eliminatie PostgreSQL afhankelijkheden. Stabiele sorteervolgorde voor Journaal. IVP voor een database wordt overgeslagen wanneer geen driver voor die database beschikbaar is. IVP gebruikt nu de bestanden uit de example directory. Database versie 1.0.10; migratie beschikbaar. WAARSCHUWING: Bij teruggaan naar 1.0.9 moet de database eerst fysiek worden verwijderd! 1.00.04 2006-10-11 14:59 Trace messages voor SET/GET SEQUENCE. Update EekBoek.spec[.in] met goede URLs en zo. 1.00.03 2006-10-06 15:05 Fix bug met TAccounts tabel bij interactief commando import. Fix bug in --ident display. 1.00.02 2006-09-30 13:54 Forceer UNICODE onder Windows, tenzij locale:unicode dit overruled. Fix een bug in de inputafhandeling waar regels die met whitespace geheel worden genegeerd. Fix bug in het opstarten van het (ongedocumenteerde) sql commando. 1.00.01 2006-09-28 15:43 Fix een bug waardoor de TAccounts tabel niet werd aangemaakt in geval van --import. Over het algemeen onschadelijk, tenzij de mutaties.eb een opdracht bevat die TAccounts nodig heeft, zoals een jaareinde. Fix detectie van Windows. 1.00 2006-08-27 21:15 Op de kop af 18 maanden nadat ik de eerste regels intoetste tot wat nu EekBoek geworden is is het zover: de stabiliteit, functionaliteit, degelijkheid, veelzijdigheid en gebruiksgemak zijn naar tevredenheid van de gebruikers (en van mij!). Hier is hij dan: Versie 1.00! * http://www.eekboek.nl/dl/EekBoek-1.00-1.noarch.rpm * http://www.eekboek.nl/dl/EekBoek-1.00-1.src.rpm * http://www.eekboek.nl/dl/EekBoek-1.00.tar.gz * http://www.eekboek.nl/dl/EekBoek.ppd Alle kits zijn voorzien van een aparte digitale handtekening. De key ervan vind je op http://www.eekboek.nl/fedora/RPM-PGP-KEY-EekBoek. YUM liefhebbers kunnen een (experimentele) repository toevoegen door het installeren van http://www.eekboek.nl/fedora/EekBoek-yum-1.0-1.noarch.rpm. Zie voor meer informatie http://www.eekboek.nl/fedora/repodata . De aanbevolen manier van installeren is door middel van de RPM. Belangrijkste wijzigingen: * Deze versie is identiek aan 0.93, met alleen het versienummer aangepast. 1.0RC3 2006-08-05 14:45 EekBoek heeft nu een eigen web site: http://www.eekboek.nl . EekBoek 1.0 Release Candidate 3 is daar nu beschikbaar: * http://www.eekboek.nl/dl/EekBoek-0.93-1.noarch.rpm * http://www.eekboek.nl/dl/EekBoek-0.93-1.src.rpm * http://www.eekboek.nl/dl/EekBoek-0.93.tar.gz * http://www.eekboek.nl/dl/EekBoek.ppd Alle kits zijn voorzien van een aparte digitale handtekening. De key ervan vind je op http://www.eekboek.nl/fedora/RPM-PGP-KEY-EekBoek. YUM liefhebbers kunnen een (experimentele) repository toevoegen door het installeren van http://www.eekboek.nl/fedora/EekBoek-yum-1.0-1.noarch.rpm. Zie voor meer informatie http://www.eekboek.nl/fedora/repodata . De aanbevolen manier van installeren is door middel van de RPM. Belangrijkste wijzigingen: * Deze versie is identiek aan 0.92, met uitsluitend de gewijzigde web site in sources en documentatie. 1.0RC2 2006-07-20 15:11 * Deze versie is identiek aan 0.63. 0.63 2006-07-12 19:02 * Herstel ernstige fout in het hernieuwde saldoberekeningsmechanisme. VERSIE 0.62 NIET GEBRUIKEN. RESTORE DE PRE-0.62 DATABASE! * Controleer bij het verwijderen van een boeking of het boekjaar of de BTW periode niet is afgesloten. 0.62 XXXXXXXXXXXXXXXX * Bank- en kasboekingen kunnen ook een --beginsaldo meekrijgen. Saldobepaling gaat op volgorde van boekstuknummer (was: invoervolgorde). Het beginsaldo moet overeenkoment met het eindsaldo van het eraan voorafgaande boekstuk (indien aanwezig). Het eindsaldo moet overeenkoment met het beginsaldo van het erop volgende boekstuk (indien aanwezig). Dit lost tevens een im/exportprobleem op met boekstukken die worden verwijderd en later opnieuw ingevoerd. * Export van boekstukken gaat nu per dagboek, op volgorde van boekstuknummer. * Database structuur is gewijzigd -- automigratie is beschikbaar. * Boekingen laten geen informatie meer zien tenzij de optie --verbose wordt meegegeven. (Is dit een goed idee?) 0.91 2006-07-03 14:37 1.0 Release Candidate 1 * UNICODE is nu default, de ebshell 'banner' toont nu in voorkomende gevallen (Latin1) in plaats van (UNICODE). * De tekensetaanduiding in bestanden is gewijzigd van # Content-Type: text; charset = ... in # Content-Type: text/plain; charset = ... De oude vorm blijft vooralsnog herkend. * De automigratie-bestanden zijn verwijderd. 0.61 2006-06-20 22:04 * Import naar en Export van files. $ ebshell --export --file data.ebx $ ebshell --import --file data.ebx Dit vereist het beschikbaar zijn van de module Archive::Zip. * Voor inkoop- en verkoopboekingen mag de boekstukomschrijving of de boekstukregelomschrijving (maar niet beide) leeg zijn. De waarde van de andere omschrijving wordt dan overgenomen. Dit is met name handig voor simpele inkoop-/verkoopboekingen waarbij normaalgesproken beide beschrijvingen toch hetzelfde zouden zijn: inkopen 10-10 "Internetkosten" XS4ALL "" 10,00 * Fix een (overigens onschuldige) "undefined" warning bij verwijderen van een partiële boeking. 0.60 2006-06-09 15:08 * Lokatie van de 'example' directory: - In geval van Build install: /EB/example - In geval van RPM install: /EekBoek-x.xx/example - In geval van PPM install: /EB/example * Het sample database script is vervallen. Met de nieuwe import functionaliteit kan de sample database eenvoudig worden opgezet met $ ebshell --db=sample --import --dir= waarin de 'example' directory is. 0.59 2006-06-05 21:48 * Het main programma ebshell is nu een triviale wrapper rondom module EB::Shell. (Dat is nu zo'n wijziging waar niemand iets van zou moeten kunnen merken, maar je weet maar nooit.) * Er is nu een command line import en export commando. $ ebshell --export --dir=foo Equivalent met: $ ebshell -c export --dir=foo $ ebshell --import --dir=foo Equivalent met: $ ebshell --createdb -c import --dir=foo * Bijkomende wijzigingen voor CSS handling (zie 0.58). * Fix probleem met verwijderen script dir van geïnstalleerde rpm. * Fix 1 januari-probleem met openingsbalans. 0.58 2006-06-01 18:04 * CSS stylesheet afhandeling in HTML rapporten Er is nu een config setting `cssdir' in sectie `html' waar de directory kan worden opgegeven waar de CSS stylesheets zijn te vinden. Het uiteindelijke resultaat hangt af van deze `cssdir', en de voor het rapport opgegeven `style' optie. Style Cssdir Resultaat -------------------------------- - - De EekBoek standaard style voor dit type rapport wordt opgenomen in het rapport. naam - De EekBoek standaard style `naam' wordt opgenomen in het rapport. - dir Stylesheet link naar dir/std.css, waarin std de naam is van de EekBoek standaard style voor dit type rapport. naam dir Stylesheet link naar dir/naam.css bestandsnaam n.v.t. Stylesheet link naar bestandsnaam Zonder wijzigingen betekent het dat de standaard stylesheet nu in de rapporten wordt opgenomen, zodat deze direct toonbaar zijn. Om hetzelfde resultaat te bereiken als tot nu toe het geval is, moet de config setting [html] cssdir = css worden opgegeven. 0.57 25-05-2006 20:54 * Probeerdatabase Na afloop van de installatieverificatietests is er een probeerdatabase "sample" beschikbaar. Deze wordt nu ook in de vorm van een SQL file in de example directory meegeleverd. Dit is met name van belang indien er wordt geïnstalleerd vanuit een RPM, want dan is de probeerdatabase niet aangemaakt. De probeerdatabase kan te allen tijde worden (her)aangemaakt met: $ dropdb eekboek_sample $ psql template1 < example/sampledb.sql Na een RPM installatie is de example directory te vinden in de zogenaamde 'doc' dir, meestal /usr/share/doc/eekboek-X.XX'. * Controle op numeriek zijn van het boekstuknummer. * "--opening" optie voor "balans". Hiermee wordt de openingsbalans opnieuw getoond. In geval van meervoudige boekjaren dienen de voorgaande boekjaren te zijn afgesloten, anders is deze openingsbalans gelijk aan de eindbalans van het voorgaande boekjaar. 0.56 05-05-2006 21:53 * (Enigszins experimenteel) Betere Unicode transparantie. Alle door EekBoek te verwerken bestanden kunnen middels een Content-Type aanduiding aangeven of de inhoud Latin1 dan wel UTF-8 is. Dit geldt voor: - schema - invoer via redirectie en de 'include' opdracht. Bij het schrijven van export-bestanden wordt standaard een Content-Type toegevoegd. De Content-Type aanduiding is: # Content-Type: text; charset = XXX XXX = Latin1, Latin9, ISO-8859.1 of ISO-8859.15 (voor Latin1 invoer) XXX = UTF-8 (voor Unicode UTF-8 invoer) Zonder Content-Type aanduiding worden de invoerbestanden verondersteld overeen te komen met de omgeving, dus UTF-8 in een Unicode omgeving, en anders Latin1. De meegeleverde bestanden (schema's) zijn nu in UTF-8, en hebben een overeenkomstige Content-Type aanduiding. De restrictie dat in een Unicode omgeving een database ook Unicode moet zijn is (voorlopig) (weer) vervallen. * Onder MS Windows wordt default een Unicode omgeving verondersteld. * Keuze uit afrondingsalgoritmen. In de config file: [strategy] round = XXX Op dit moment zijn er twee mogelijkheden: "ieee", de huidige methode, en "posix", een over het algemeen iets betere afrondingsmethode. Suggesties (plus implementatie, zie EB::Format) voor meer afrondingsalgoritmen zijn welkom. * Fix probleem met trailing backslash in non-file invoer. 0.55 04-04-2006 15:22 * Instelbaar datumformaat. In de config file: [format] date = yyyy-mm-dd Mogelijke formaten zijn: YYYY-MM-DD (default), DD-MM-YYY en DD-MM. In het laatste geval wordt, waar nodig, het formaat aangevuld tot DD-MM-YYYY. 0.54 04-04-2006 12:01 * Aanvullende fixes voor UNICODE. Bestanden worden gecontroleerd op valide UNICODE tekens. Non-UNICODE databases worden geweigerd indien UNICODE is geactiveerd. Een database kan gemakkelijk worden geconverteerd met: $ pg_dump eekboek_XXX > xx $ dropdb eekboek_XXX $ createdb -E unicode eekboek_XXX $ psql eekboek_XXX < xx Let op: De standaardbestanden (schema's en zo) zijn nog steeds Latin1. * De HTML uitvoer kan gebruik maken van de module HTML::Entities, indien deze is geïnstalleerd. 0.53 29-03-2005 20:35 * UNICODE support. ****EXPERIMENTEEL**** Aanzetten met de EekBoek locale in de config file: [locale] unicode = 1 of [locale] lang = nl_NL.utf8 Elke suffix anders dan utf8 (of utf-8) wordt als latin1 geïnterpreteerd. ("unicode" heeft prioriteit over "lang"). Semantiek: - Alle geproduceerde uitvoer (scherm, maar ook rapporten, exports, etc) wordt in UTF-8 weggeschreven. - Alle invoerbestanden (schema, opening.eb, imports, etc) moeten UTF-8 zijn. Geen databasewijzigingen. Echter, alle met 0,53 aangemaakte databases zijn niet te verwerken met pre-0.53 versies. Zonder het aanzetten van UNICODE moet alles zijn zoals het was. Zoals gezegd, is e.e.a. nog een beetje experimenteel. Testresultaten en feedback wordt op prijs gesteld. Let op: De standaardbestanden (schema's en zo) zijn nog steeds Latin1. 0.52 27-03-2006 15:21 * Wijzigingen in packaging t.b.v. RPM-build en CPAN. * Database-tests kunnen worden uitgevoerd met een RPM-build: $ rpmbuild ... --with dbtests ... * De source-RPM is getekend met mijn GPG key. Om de source-RPM te verifiëren moet je mijn GPG key in het rpm systeem importeren, bijvoorbeeld: $ wget http://www.squirrel.nl/people/jvromans/pubkey.asc $ sudo rpm --import pubkey.asc * Fix probleem met aanmaken database op remote database server. Hierdoor faalt de IVP indien de database nog niet bestaat. 0.51 24-02-2006 15:03 * Bouwen en installeren gaat nu middels het Module::Build framework. $ perl Build.PL $ ./Build $ ./Build test $ su # ./Build install * Het Module::Build framework wordt (vooralsnog) meegeleverd. * Een compatibility-mode Makefile.PL is meegeleverd. * De installatie-verificatieprocedure is nu geïntegreerd in de build tests. * De build, test en installatie kan nu ook onder ActiveState Perl onder Windows. * Fix probleem met ophalen database naam op remote database server. 0.50 17-03-2006 19:34 * Bugfixes m.b.t. de boekhoudkundige/rekenkundige berekening van balanstotaal. 0.49 16-03-2006 * De oorspronkelijke, boekhoudkundige berekening van het balanstotaal voor de openingsbalans wordt nu ook weer geaccepteerd, evenals de in de vorige versie geïntroduceerde rekenkundige berekening. Zie de documentatie. * Kleine bugfixes. 0.48 13-03-2006 20:54 * Negatieve getallen in de openingsbalans blijven gehandhaafd. In vorige versies werd (foutief!) de D/C status gewisseld. B.v., oude situatie: adm_balans 100 adm_balans -10 adm_balans 90 adm_balanstotaal 100 Nieuwe situatie: adm_balans 100 adm_balans -10 adm_balans 90 adm_balanstotaal 90 Dit is een incompatibele wijziging, doch enkel indien er negatieve bedragen in de openingsbalans voorkomen (wat doorgaans niet het geval zal zijn). In dat geval moet het balanstotaal even worden aangepast. * Fix BTW afsluiting na export/import indien BTW periode != jaar. 0.47 10-03-2006 13:54 * Additionele fixes voor duizendpuntjes in jaarafsluiting. * Fix BTW afsluiting na export/import indien BTW periode != jaar. 0.46 07-03-2006 10:06 * Duizendpuntjes worden niet worden toegepast in geëporteerde gegevens omdat die anders niet meer kunnen worden ingelezen. 0.45 06-03-2006 17:23 * Kolombreedte van bedragen in tekstuele rapportages is instelbaar. Configuratievariabele 'numwidth' in sectie 'text' kan hiervoor worden gebruikt: [text] numwidth = 10 numwidth = +1 numwidth = 111% Elk van deze settings vergroot de standaardwaarde van 9 naar 10. * Duizendpuntjes. Configuratievariabele 'thousandsep' in sectie 'locale' kan hiervoor worden gebruikt: [locale] decimalpt = , thousandsep = . De kolombreedte in tekstuele rapportages wordt automatisch vergroot bij het gebruik van duizendpuntjes. * Windows install kit voor de ActiveState Perl Package Manager. Zie README.WINDOWS. 0.44 05-03-2006 22:26 * Inkoop/Verkoopdagboeken mogen ook een :rekening specificatie krijgen in het schema. Indien deze ontbreekt wordt de koppeling "crd" resp "deb" gebruikt. * Koppelingen voor "deb" en "crd" mogen ontbreken in het schema mits er geen dagboeken zijn die er gebruik van maken. * De BTW tabel mag ontbreken in het schema. Er wordt dan geen BTW toegepast. Bijvoorbeeld voor organisaties die niet BTW-plichtig zijn. (Experimenteel) * Alle koppelingen voor BTW (btw_ih, btw_vl, etc...) mogen ontbreken in een BTW-vrije administratie. * Configuratie-setting "userdefs" in sectie "shell" om een userdefs module te selecteren. Pas op: als de module niet succesvol laadt is dit een fatale fout. 0.43 03-03-2006 23:01 * Nieuw aangemaakte administraties (aangemaakt met 0.43 of later) kunnen bedragen groter dan 21.474.836,47 aan. De huidige limiet ligt op 92.233.720.368.547.758,07. Bestaande databases worden ge-automigreerd. * Diverse aanpassingen in de toepassing van BTW voor minder-triviale boekingen. * Export/import verbeteringen, waarondr behoud van BTW aangifteperiode. * Mogelijkheid tot draaien zonder Term::ReadLine::Gnu. Niet dat je het leuk zult vinden... 0.42 20-02-2006 22:59 * Toepassen van BTW is nu volledig gedreven door de kosten/omzet classificatie van de grootboekrekeningen. * Meer flexibele BTW codering in schema: naast hoog/laag kan ook kosten/omzet en incl/excl worden opgegeven. * BTW koppeling met balansrekening in schema is weer mogelijk, daarbij moet dan een kosten/omzet classificatie worden opgegeven. * Naast kosten (code K) en omzet (code O) kan een grootboekrekening in het schema ook als neutraal (code N) worden opgegeven. Op een neutrale rekening kan nooit BTW worden geboekt. * Meer flexibele BTW codering in boekingsbedragen: naast H/L is ook K/O mogelijk (en soms verplicht). BTW exclusief kan worden opgegeven met een "-". * Herziene en aanvullende documentatie inzake het toepassen van BTW. 0.41 09-02-2006 18:47 * BTW koppeling met balansrekening in schema niet langer toegestaan. * Config variabelen op command line: --define database:name=foo 0.40 07-02-2006 12:55 * Opdrachten "import" en "include" (experimenteel). Met "import" kan een eerder geëxporteerde administratie in één klap weer worden gereconstrueerd. De huidige inhoud van de database wordt daarbij volledig overschreven. Opdracht "include" neemt een bestandsnaam en voert alle opdrachten uit dit bestand uit. * Schema-naam (ebshell --schema=naam) mag nu ook een bestand zijn in plaats van een naam (alleen letters, cijfers en _). In het geval van een bestand wordt geen zoekstrategie toegepast. 0.39 06-02-2006 19:22 * Kleine bugfixjes. 0.38 04-02-2006 20:41 * BTW Aangifteformulier aangepast aan de moderne tijd. Kleineondernemenrsregeling verwerkt in formulier. * Betere foutdetectie op verkeerde commando-invoer. * Herziening alle hulpteksten. * Bug fix: RPM bouwprobleem met Config::IniFiles. 0.37 02-02-2006 15:08 In batch mode wordt backslash-continuering ook beëindigd door een lege regel. 0.36 24-01-2006 18:16 Wijzigen rapportopmaak d.m.v. de configuratiefiles (Experimenteel). Fix periode-einde balans/resultaat. Fix enkele warnings voor "missing configs". Eerste aanzet afscheiden database-specifieke code. 0.35 23-01-2006 11:31 Better checks on user input for bookings. Fix problem with null object if no configs. 0.34 22-01-2006 21:38 Config files. Uitfasering environment variabelen. Fix .eb generatie door jaareinde. Export jaareinde. Kleine fixes. 0.33 20-01-2006 09:38 Emergency fix. Please do not use 0.32. 0.32 18-01-2006 22:47 INCOMPATIBELE WIJZIGING ======================= Openstaande posten ingevoerd bij het openen van het boekjaar door middel van de vorm "adm_relatie ..." hebben de omschrijving en relatiecode omgewisseld. Dat betekent dat de opdracht ter invoering van de openstaande boeking nu identiek is aan de oorspronkelijke boekingsopdracht, voorafgegaan door het woord "adm_relatie". ======================= Database structuur is gewijzigd, auto-migratie is beschikbaar. 0.31 17-01-2006 22:19 Export functionaliteit. Tegenrekening voor Memoriaal. Verbetering PostgreSQL tests. 0.30 14-01-2006 22:37 Afronden documentatie. Extra build test op database. IVP: Verificatie Crediteuren/Debiteurenoverzicht. IVP: Verificatie HTML en CSV generatie. Issue 1404053: Grootboekrekeningen als '0005' toestaan. Openstaande posten: FQbsknr voor openstaande posten vorig boekjaar. Aparte style / kleurtje voor openstaande posten vorig boekjaar. Fix Issue 1404051: Fout bij TABs in Schema. 0.29 12-01-2006 22:44 Issue 1395916. Openstaande posten ondersteunt --per en --boekjaar. Debiteuren/Crediteurenboekingen ondersteunen --boekjaar. Issue 1403886. Debiteuren/Crediteurenboekingen tonen openstaande betalingen nu correct. Geen waarschuwing meer als de einddatum van een periode in de toekomst ligt. Fix HTML generatiefout (stylesheet spec ontbrak tenzij expliciet meegegeven). 0.28 11-01-2006 23:03 :btw= in schema. Lay-out fix Balans/Resultaatrekening. Fix openstaande posten rapportage bij jaareinde. Documentatie-updates. 0.27 09-01-2005 18:48 Uitgebreider rapport over Openstaande posten. Jaareinde kan nu ook de openingsopdrachten voor het komende boekjaar aanmaken. Stylesheet fixes voor Proef- en Saldibalans. 0.26 08-01-2005 19:56 Aanpassingen voor BTW aangifte met --periode en --boekjaar. Alle rapporten kennen nu ook een CSV variant. Debiteuren: Fix voor openstaande inkoopfacturen. adm_naam niet langer toegestaan bij openen boekjaar. CSS Style sheet voor openstaande posten. 0.25 05-01-2006 10:24 Toepassen regeling Kleine Ondernemers. Nieuwe reporter backend. Alle rapporten kennen nu ook een HTML variant. Kleine bugfixes. Enkele documentatie updates. 0.24 28-12-2005 23:26 Overzichten voor Debiteuren en Crediteuren. Environment variabelen EB_DB_USER, EB_DB_PASSWORD, EB_DB_HOST en EB_DB_PORT voor database access. 0.23 23-12-2005 11:41 Kleine bugfixes. Enkele documentatie updates. Boekstuknummers in Grootboek overzicht nu ook in Dagboek:Volgnummer vorm. 0.22 14-12-2005 17:25 Packaging t.b.v. CPAN. 0.21 13-12-2005 20:20 *** EERSTE PUBLIEKE BETA RELEASE *** Meer dan 9 hoofdverdichtingen en meer dan 89 verdichtingen mogelijk. Twee voorbeeld-schema's: eenmanszaak en bvnv. adm_relatie neemt nu een fully-qualified boekstuknummer: adm_relatie inkopen:1998:1245 1998-12-31 "Consultancy" SCS 1877.09 0.20 12-12-2005 11:55 Aanzet documentatie op web site. Opdracht "relaties" kan meerdere relaties tegelijk aanmaken. BTW intracomm. in aangifte. Bugfixes jaareinde. ebshell command line opties --boekjaar, --db (alias voor --dataset) en --journaal (preferred voor --journal). Waarschuwing voor relaties met BTW intra en BTW verlegd (nog niet (geheel)) ondersteund. Dagboek-ids kunnen nu alfanumeriek (max. 4 tekens) zijn. Invoeren syntax Dagboek:BoekjaarCode:VolgNummer voor boekstukken. *** INCOMPATIBLE DATABASE CHANGES *** GEEN MIGRATIE *** 0.19 30-11-2005 21:45 sample renamed naar ivp. example aangemaakt. spec file generatie in tarball. Uitfasering van dubbele vlaggetjes in schema. Temporary disable Build.PL building. 0.18 21-11-2005 17:04 Emergency fix voor PostgreSQL temp tables probleem. PATH fix in sample/setup.csh. 0.17 19-11-2005 23:18 HTML uitvoer-plugins voor Balans en Resultaat. HTML uitvoer-plugin voor Journaal. HTML uitvoer-plugin voor Grootboek. 0.16 16-11-2005 15:25 Aanvang invoering universele uitvoer-plugins voor rapporten. Meer help: "help periodes" en "help rapporten". btwaangifte heeft nu een --definitief optie. Is netter. Openstaande posten worden gegroepeerd per dagboek. Openstaande posten per einddatum. Relatiecodes worden nu case-insensitive herkend. Meerdere boekjaren per administratie (experimenteel). 0.15 08-10-2005 18:20 BTW aangifte nu ook naar bestand (optie --output=...) en in HTML formaat (optie --html). Lange boekstukomschrijvingen worden in het journaal en grootboek over meerdere regels afgedrukt. Wijziging boekstuknummer in numeriek. Bugfix: BTW aangifte gebruikte harde nummers voor BTW rekeningen. 0.14 03-10-2005 23:09 Automatische migratie van database naar een nieuwe versie. (EB::Tools::SQLEngine): Afvangen transactionele commandos. (Shell) Correct completions after "help". (EB::Booking::*) Partiële boekingen. 0.13 30-09-2005 18:40 (EB::Report::Open) Overzicht openstaande posten. (Shell) Niewe opdracht: "openstaand". (Utils) Meer ISO-achtige periodeformaten: YYYY-MM-DD/YYY-MM-DD, YYYY-MM-DD/MM-DD en YYYY-MM-DD/DD. (Shell) Experimentele invoer-completion op debiteur/crediteurcodes en grootboekrekeningen. 0.12 29-09-2005 22:05 (Shell) Periode-selectie (--periode=XXX) voor (sommige) commando's. (Grootboek) Periode-selectie. (Journaal) Periode-selectie. (Relatie) Dagboek-selectie met --dagboek. Periode-aanduidingen zijn erg flexibel. B.v. als 2003 het huidige boekjaar is, dan zijn de volgende aanduidingen equivalent: 2003-01-01 - 2003-03-31 01-01-2003 - 31-03-2003 01-01 - 31-03 januari - maart jan - mrt (korte namen) m1 - m3 (maandnummers) k1 (eerste kwartaal) Eveneens: 2003-02-01 - 2003-02-28 01-02-2003 - 28-02-2003 01-02 - 28-02 februari feb m2 Verder is toegestaan: jaar (01-01 - 31-12) Een subset hiervan is ook bruikbaar voor b.v. btw aangifte. 0.11 28-09-2005 22:59 (BKM.IV) Datumcontrole op boekingen. Boekingen moeten in het huidige boekjaar vallen. (BTWAangfite) Als er definitief BTW aangifte is gedaan kan er niet meer worden geboekt in die periode. Een BTW aangifte wordt definitief door toevoeging van het woord "definitief" aan de opdracht, b.v.: btwaangifte augustus definitief Introductie database migratie. Om te migreren van database versie 1.0.0 (EekBoek 0.10) naar 1.0.1 (EekBoek 0.11) kan het script migrate/1_0_0_to_1_0_1.sql worden gebruikt: pg_dump -c $EB_DB_NAME > backup.sql psql $EB_DB_NAME < migrate/1_0_0_to_1_0_1.sql (Wordt later wsl. geautomatiseerd) (EB::Tools::Schema,EB::Tools::SQLEngine) Afsplitsen SQL engine. 0.10 27-09-2005 23:09 (IV, BKM) Her-invoering van de mogelijkheid om BTW te boeken op 'std' boekingen. Zie de beschrijving in samples/mutaties.eb. BTW tariefcodewijzigingen kunnen nu ook zijn "@H" en "@L" voor hoog resp. laagtarief. Correctie van de dependencies in Makefile.PL. 0.09 26-09-2005 22:34 Belangrijkste wijziging: Uitfaseren van de rol van de D/C setting van grootboekrekeningen tijdens het boekingsproces. Tot nu toe werd de richting van een boeking bepaald door het dagboek en de Debet/Credit setting van de betreffende grootboekrekening. Dit werd door enkele testers als contra-intuïtief ervaren en daarom heb ik in overleg een nieuwe manier geïmplementeerd. Consequenties voor bestaande mutatie-bestanden: - Inkoop / Verkoop boekingen: geen consequenties. - Bank / Kas / Memoriaal: - 'deb' boekingen: geen - 'crd' boekingen: het bedrag moet nu negatief worden opgegeven (het saldo vermindert immers) - 'std' boekingen: Boekingen met BTW zijn niet langer toegestaan. Deze zijn boekhoudtechnisch nl. vrijwel altijd incorrect, en doorgaans illegaal. Als je perse een 'std' boeking met BTW wilt, dan kun je die met de hand uitsplitsen. Zie de beschrijving in samples/mutaties.eb. 0.08 22-09-2005 15:45 (BKM) BKM boekingen kunnen nu een datum per boekstukregel krijgen. (Grootboek) Opdracht 'grootboek' kan selectief worden uitgevoerd op een of meer rekeningen. (EB::Utils) Nieuw: Utility functies. 0.07 21-09-2005 12:25 (IV,BKM) Datum ook als DD-MM-JJJJ en DD-MM. (IV,BKM) --totaal optie. (IV,BKM) Melding over balansrekening vervalt. (IV,BKM) Melding over D/C conflict niet langer fataal. (EB::Locale) Alles onder I18n (gettext). Alle tools printen een banner. (EB): Nieuwe, algemene module. Handelt Globals en Locale af. (EB::Booking::Delete) Verwijderen boekstukken. (EB::Booking::Decode) Decoderen boekstukken. (EB::Shell) Nieuwe opdracht: "verwijder". (EB::Shell) Nieuwe opdracht: "toon". 0.06 02-09-2005 19:15 (EB::Tools::Schema) Schema handling. (ebshell) Schema initialisatie. (Makefile.PL, build_common.inc) Installer Introductie EB library (@INC/EB). 0.05 30-08-2005 10:50 (Shell) Alle shell spul van Shell:: -> EB::Shell:: (EB::Shell::Base) Opvangen ontbreken van Term::Size. (Term::Size): Verwijderd. (opening, schema) tools -> EB::Tools (ebshell.pl) Integratie nieuwe stijl opening (dvimport, newdb, ...) Nieuwe stijl opening 0.04 28-08-2005 16:34 (Schema) Tabel BTWTariefgroepen afgeschaft. (Database) Geen pgplsql (CREATE LANGUAGE) meer nodig. (Schema) CHECK constraints toegevoegd. (sample/setup.sh) Opvangen ontbreken van PERL5LIB (sample/setup.csh) Opvangen ontbreken van PERL5LIB (sample/newdb.sh) Creëer database met Latin1 encoding. (Term::Size) Stub voor mogelijk ontbrekende module. 0.03 15-08-2005 22:42 (schema) Volledige database setup uitgaande van schema.dat. EekBoek-2.030.1/README.postgres0000644000400000040000000000013712725476602013521 0ustar jvjvEekBoek database driver voor PostgreSQL. Alle documentatie van EekBoek vindt u onder EekBoek. EekBoek-2.030.1/t/0000755000400000040000000000000013151742350011224 5ustar jvjvEekBoek-2.030.1/t/81_db_sqlite.t0000644000400000040000000000207612725476601013705 0ustar jvjv# 81_db_sqlite.t -- Basic SQLite access # Author : Johan Vromans # Created On : Tue Oct 10 18:46:26 2006 # Last Modified By: Johan Vromans # Last Modified On: Mon Jun 14 22:16:28 2010 # Update Count : 12 use strict; use warnings; use Test::More tests => 4; # Some basic tests. BEGIN { use_ok("DBI"); } SKIP: { eval { require DBD::SQLite }; skip("DBI SQLite driver (DBD::SQLite) not installed", 3) if $@; # Check minimal interface version. my $minpg = 1.12; ok($DBD::SQLite::VERSION >= $minpg, "DBD::SQLite version = $DBD::SQLite::VERSION,". " should be at least $minpg"); my $tmpdb = "tmp$$.db"; SKIP: { skip("Database tests skipped on request", 2) if $ENV{EB_SKIPDBTESTS}; # Check whether we can contact the database. open(my $db, ">", $tmpdb); close($db); my $dbh; eval { $dbh = DBI->connect("dbi:SQLite:dbname=$tmpdb"); ok(!$DBI::errstr, "Database Connect"); diag("Connect error:\n\t" . ($DBI::errstr||"")) if $DBI::errstr; }; ok($dbh, "Check databases"); } unlink($tmpdb); } EekBoek-2.030.1/t/30_amounts.t0000644000400000040000000000214412725476601013413 0ustar jvjv#! perl # $Id: 30_amounts.t,v 1.4 2010/03/17 10:51:33 jv Exp $ use strict; use warnings; use EB; use EB::Format; EB->app_init( { app => "Test", nostdconf => 1 } ); my @tests; BEGIN { @tests = ( # Integral '12345' => '1234500', # Fraction, EU + US '12345,66' => '1234566', '12345.66' => '1234566', # Too many fractional digits '12345,667' => '', '12345.667' => '', # Groups, EU + US '1.234.456' => '123445600', '1,234,456' => '123445600', # Illegal groups '1234.456' => '', '1234,456' => '', # Group + Fraction, EU + US '1.234,56' => '123456', '1,234.56' => '123456', # Illegal group/fract. '1.234.56' => '', '1.3' => '', '1,6' => '', ); } use Test::More tests => @tests/2; # Test numers (amount) parsing. while ( @tests ) { my $amt = shift(@tests); my $exp = shift(@tests); my $res = amount($amt); $res = '' unless defined $res; is($res, $exp, "amount $amt"); } EekBoek-2.030.1/t/91_ivp_sqlite.t0000644000400000040000000000042713131642770014107 0ustar jvjv#! perl # $Id: 91_ivp_sqlite.t,v 1.10 2009/10/15 16:27:04 jv Exp $ -*-perl-*- use strict; use warnings; our $dbdriver = "sqlite"; if ( !$dbdriver && $0 =~ /\d+_ivp_(.+).t/ ) { $dbdriver = $1; } chdir("t") if -d "t"; $ENV{LANG} = "nl_NL"; require "./90_ivp_common.pl"; EekBoek-2.030.1/t/90_ivp_common.pl0000644000400000040000000002045013151741146014242 0ustar jvjv#! perl # 90_ivp_common.pl -- Common code for IVPs # Author : Johan Vromans # Created On : Thu Oct 15 16:27:04 2009 # Last Modified By: Johan Vromans # Last Modified On: Thu Aug 31 10:01:42 2017 # Update Count : 134 use strict; use warnings; # The actual number of database tests, as executed by report_tests. use constant NUMTESTS => 38; # There are 9 initial tests. # report_tests requires 1 more for the setup, and 1 for the export # (all but the last). my $remaining; use Test::More $ENV{EB_SKIPDBTESTS} ? (skip_all => "Database tests skipped on request") : (tests => ( $remaining = 3*(NUMTESTS+2)-1+10 )); use warnings; BEGIN { use_ok('IPC::Run3') } BEGIN { use_ok('EB::Config') } BEGIN { use_ok('EB') } BEGIN { use_ok('File::Copy') } EB->app_init( { app => "ivp" } ); ok( $::cfg, "Got config"); $remaining -= 5; our $dbdriver; my $dbddrv; $dbdriver = "postgres" unless $dbdriver; if ( $dbdriver eq "postgres" ) { $dbddrv = "DBD::Pg"; } elsif ( $dbdriver eq "sqlite" ) { $dbddrv = "DBD::SQLite"; } BAIL_OUT("Unsupported database driver: $dbdriver") unless $dbddrv; my $l = $ENV{LANG}; $l =~ s/_.*//; for ( "ivp_".$ENV{LANG}, "ivp_$l", "ivp" ) { chdir($_), last if -d $_; } SKIP: { diag("This test is not yet implemented -- SKIPPED") unless -d "ref"; skip("This test is not yet implemented", $remaining) unless -d "ref"; my $f; for ( qw(opening.eb relaties.eb mutaties.eb schema.dat) ) { ok(1, $_), next if -s $_; if ( $f = findlib($_, "examples") and -s $f ) { copy($f, $_); } ok(-s $_, $_); } $remaining -= 4; for ( qw(ivp.conf opening.eb relaties.eb mutaties.eb reports.eb schema.dat ) ) { die("=== IVP configuratiefout: $_ ===\n") unless -s $_; } mkdir("out") unless -d "out"; ok( -w "out" && -d "out", "writable output dir" ); $remaining--; eval "require $dbddrv"; skip("DBI $dbdriver driver ($dbddrv) not installed", $remaining) if $@; # Cleanup old logs and reports. unlink( glob("out/*.log") ); unlink( glob("out/*.txt") ); unlink( glob("out/*.html") ); unlink( glob("out/*.csv") ); # Results from export. unlink( glob("out/*.dat") ); unlink( glob("out/*.eb") ); unlink( glob("out/*.ebz") ); unlink( glob("out/0???????_*") ); # SQLite databases. unlink( glob("ebsqlite_sample*") ); # Attachments unlink( glob("0???????_*") ); my @ebcmd = qw(-MEB::Main -e EB::Main->run -- -X -f ivp.conf --echo); push(@ebcmd, "-D", "database:driver=$dbdriver") if $dbdriver; unshift(@ebcmd, map { ("-I", "../../$_" ) } grep { /^\w\w/ } reverse @INC); unshift(@ebcmd, $^X); # Check whether we can contact the database. eval { if ( $dbdriver eq "postgres" ) { my @ds = DBI->data_sources("Pg"); diag("Connect error:\n\t" . ($DBI::errstr||"")) if $DBI::errstr; skip("No access to database", $remaining) if $DBI::errstr; # && $DBI::errstr =~ /FATAL:\s*(user|role) .* does not exist/; } }; #### PASS 1: Construct from distributed files. for my $log ( "out/init.log" ) { ok(syscmd([@ebcmd, qw(--init)], undef, $log), "init"); checkerr($log); } report_tests(@ebcmd); for my $log ( "out/export1.log" ) { ok(syscmd([@ebcmd, qw(--export --dir=out)], undef, $log), "export1"); checkerr($log); } #### PASS 2: Construct from exported files. for my $log ( "out/import1.log" ) { ok(syscmd([@ebcmd, qw(--import --dir=out)], undef, $log), "import1"); checkerr($log); } report_tests(@ebcmd); for my $log ( "out/export2.log" ) { ok(syscmd([@ebcmd, qw(--export --file=out/export2.ebz)], undef, $log), "export2"); checkerr($log); } #### PASS 3: Construct from exported .ebz . for my $log ( "out/import2.log" ) { ok(syscmd([@ebcmd, qw(--import --file=out/export2.ebz)], undef, $log), "import2"); checkerr($log); } report_tests(@ebcmd); } # end SKIP ################ subroutines ################ sub report_tests { my @ebcmd = @_; for my $log ( "out/reports.log" ) { ok(syscmd(\@ebcmd, "reports.eb", $log), "reports"); checkerr($log); $remaining--; } # Verify: balans in varianten. vfy([@ebcmd, qw(-c balans) ], "balans.txt" ); vfy([@ebcmd, qw(-c balans --detail=0)], "balans0.txt"); vfy([@ebcmd, qw(-c balans --detail=1)], "balans1.txt"); vfy([@ebcmd, qw(-c balans --detail=2)], "balans2.txt"); vfy([@ebcmd, qw(-c balans --verdicht)], "balans2.txt"); vfy([@ebcmd, qw(-c balans --opening) ], "obalans.txt"); # Verify: verlies/winst in varianten. vfy([@ebcmd, qw(-c result) ], "result.txt" ); vfy([@ebcmd, qw(-c result --detail=0)], "result0.txt"); vfy([@ebcmd, qw(-c result --detail=1)], "result1.txt"); vfy([@ebcmd, qw(-c result --detail=2)], "result2.txt"); vfy([@ebcmd, qw(-c result --verdicht)], "result2.txt"); # Verify: Journaal. vfy([@ebcmd, qw(-c journaal) ], "journaal.txt"); # Verify: Journaal van dagboek. vfy([@ebcmd, qw(-c journaal postbank) ], "journaal-postbank.txt"); # Verify: Journaal van boekstuk. vfy([@ebcmd, qw(-c journaal postbank:24)], "journaal-postbank24.txt"); # Verify: Proef- en Saldibalans in varianten. vfy([@ebcmd, qw(-c proefensaldibalans) ], "proef.txt"); vfy([@ebcmd, qw(-c proefensaldibalans --detail=0)], "proef0.txt"); vfy([@ebcmd, qw(-c proefensaldibalans --detail=1)], "proef1.txt"); vfy([@ebcmd, qw(-c proefensaldibalans --detail=2)], "proef2.txt"); vfy([@ebcmd, qw(-c proefensaldibalans --verdicht)], "proef2.txt"); # Verify: Grootboek in varianten. vfy([@ebcmd, qw(-c grootboek) ], "grootboek.txt" ); vfy([@ebcmd, qw(-c grootboek --detail=0)], "grootboek0.txt" ); vfy([@ebcmd, qw(-c grootboek --detail=1)], "grootboek1.txt" ); vfy([@ebcmd, qw(-c grootboek --detail=2)], "grootboek2.txt" ); vfy([@ebcmd, qw(-c grootboek 2) ], "grootboek_2.txt" ); vfy([@ebcmd, qw(-c grootboek 23) ], "grootboek_23.txt" ); vfy([@ebcmd, qw(-c grootboek 23 22) ], "grootboek_23_22.txt"); vfy([@ebcmd, qw(-c grootboek 2320) ], "grootboek_2320.txt" ); # Verify: Crediteuren/Debiteuren. vfy([@ebcmd, qw(-c crediteuren) ], "crdrept.txt"); vfy([@ebcmd, qw(-c debiteuren) ], "debrept.txt"); # Verify: BTW aangifte. vfy([@ebcmd, qw(-c btwaangifte j) ], "btw.txt" ); vfy([@ebcmd, qw(-c btwaangifte k2) ], "btwk2.txt"); vfy([@ebcmd, qw(-c btwaangifte 7) ], "btw7.txt" ); # Verify: HTML generatie. vfy([@ebcmd, qw(-c balans --detail=2 --gen-html) ], "balans2.html"); vfy([@ebcmd, qw(-c balans --detail=2 --gen-html --style=xxx)], "balans2xxx.html"); vfy([@ebcmd, qw(-c btwaangifte j)], "btw.html"); # Verify: CSV generatie. vfy([@ebcmd, qw(-c balans --detail=2 --gen-csv)], "balans2.csv"); # Verify: XAF generatie. vfy([@ebcmd, qw(-c export --xaf=out/export.xaf)], "export.xaf"); } sub vfy { my ($cmd, $ref) = @_; my @c = @$cmd; while ( shift(@c) ne "-c" ) { } if ( $ref =~ /\.xaf$/ ) { push( @c, "--xaf=$ref" ); } else { push( @c, "--output=$ref" ); } ok(!diff($ref), $ref); } sub vfyxx { my ($cmd, $ref) = @_; syscmd($cmd, undef, $ref); ok(!diff($ref), $ref); } sub diff { my ($file1, $file2) = @_; $file2 = "ref/$file1" unless $file2; $file1 = "out/$file1"; my ($str1, $str2); local($/); open(my $fd1, "<:encoding(utf-8)", $file1) or die("$file1: $!\n"); $str1 = <$fd1>; close($fd1); open(my $fd2, "<:encoding(utf-8)", $file2) or die("$file2: $!\n"); $str2 = <$fd2>; close($fd2); $str1 =~ s/^EekBoek \d.*Squirrel Consultancy\n//; $str1 =~ s/[\n\r]+/\n/; $str2 =~ s/[\n\r]+/\n/; return 0 if $str1 eq $str2; 1; } sub syscmd { my ($cmd, $in, $out, $err) = @_; $in = \undef unless defined($in); $err = $out if @_ < 4; #warn("+ @$cmd\n"); run3($cmd, $in, $out, $err); printf STDERR ("Exit status 0x%x\n", $?) if $?; $? == 0; } sub checkerr { my $fail; unless ( -s $_[0] ) { warn("$_[0]: Bestand ontbreekt, of is leeg\n"); $fail++; } open(my $fd, "<", $_[0]) or die("$_[0]: $!\n"); while ( <$fd> ) { next unless /(^\?|^ERROR| at .* line \d+)/; warn($_); $fail++; } close($fd); die("=== IVP afgebroken ===\n") if $fail; } 1; EekBoek-2.030.1/t/20_dates.t0000644000400000040000000000524112725476601013025 0ustar jvjv#! perl # $Id: 20_dates.t,v 1.5 2009/10/28 22:43:05 jv Exp $ use strict; use warnings; use EB; my @tests1; my @tests2; BEGIN { @tests1 = ( "01-02" => "2004-02-01", "01-02-2003" => "2003-02-01", "2003-02-01" => "2003-02-01", "2011-09-01+3d" => "2011-09-04", "2011-09-01+30d" => "2011-10-01", "2011-09-01+30d+1m" => "2011-10-31", "2011-09-01+30d-1m" => "2011-08-31", "2011-12-31+1d" => "2012-01-01", map { sprintf("2012-10-%02d", $_) => sprintf("2012-10-%02d", $_) } 1..31, ); @tests2 = ( "jaar" => "2004-01-01 - 2004-12-31", "2003-03-04 - 2003-05-06" => "2003-03-04 - 2003-05-06", "2003-03-04 / 2003-05-06" => "2003-03-04 - 2003-05-06", "2003-03-04 / 05-06" => "2003-03-04 - 2003-05-06", "2003-03-04 / 06" => "2003-03-04 - 2003-03-06", "03-04-2003 - 05-06-2003" => "2003-04-03 - 2003-06-05", "03-04 - 25-06" => "2004-04-03 - 2004-06-25", "3 april - 25 jun" => "2004-04-03 - 2004-06-25", "3 april - 25 jun 2003" => "2003-04-03 - 2003-06-25", "3 april 2003 - 25 jun 2003" => "2003-04-03 - 2003-06-25", "april - jun" => "2004-04-01 - 2004-06-30", "april - jun 2003" => "2003-04-01 - 2003-06-30", "k2" => "2004-04-01 - 2004-06-30", "k2 2003" => "2003-04-01 - 2003-06-30", "jaar" => "2004-01-01 - 2004-12-31", "apr" => "2004-04-01 - 2004-04-30", "april" => "2004-04-01 - 2004-04-30", "m4" => "2004-04-01 - 2004-04-30", "m04" => "2004-04-01 - 2004-04-30", "apr 2003" => "2003-04-01 - 2003-04-30", "m04 2003" => "2003-04-01 - 2003-04-30", "2003" => "2003-01-01 - 2003-12-31", "maart 2013" => "2013-03-01 - 2013-03-31", ); } use Test::More tests => @tests1 + @tests2/2; EB->app_init( { app => "Test", nostdconf => 1 } ); # Test date parsing. while ( @tests1 ) { my $date = shift(@tests1); my $exp = shift(@tests1); my ($dy, $dm, $dd); $dy = $1 if $date =~ s/([-+]\d+)y//; $dm = $1 if $date =~ s/([-+]\d+)m//; $dd = $1 if $date =~ s/([-+]\d+)d//; my $res = parse_date($date, 2004, $dd, $dm, $dy); #ok(1, "$date -> undef"), next unless $exp || $res; is($res, $exp, "date $date"); my @res = parse_date($date, 2004, $dd, $dm, $dy); $res = sprintf("%04d-%02d-%02d", @res); is($res, $exp, "date $date"); } # Test range parsing. while ( @tests2 ) { my $range = shift(@tests2); my $exp = shift(@tests2); my $res = parse_date_range($range, 2004); #ok(1, "$range -> undef"), next unless $exp || $res; $res = defined($res) ? join(" - ", @$res) : ""; is($res, $exp, "range $range"); } EekBoek-2.030.1/t/31_expr.t0000644000400000040000000000163712725476602012713 0ustar jvjv#! perl # $Id: 31_expr.t,v 1.4 2010/03/17 10:51:33 jv Exp $ use strict; use warnings; use EB; use EB::Format; EB->app_init( { app => "Test", nostdconf => 1 } ); my @tests; BEGIN { @tests = ( '12345+98765' => '11111000', '3*2' => '600', '4.12+5,25' => '937', '+123+123' => '24600', '-123+123' => '0', '123.45*0.1253' => '1547', # 0.005 should not be treated as 0005, but as 0005. '25.50*1.19+0.005' => '3035', # Mix . and , '25,50*1.19+0.005+0,05' => '3040', # Disallow anything fancy '7.123,45*0.12' => '' ); } use Test::More tests => @tests/2; # Test numers (amount) parsing. while ( @tests ) { my $amt = shift(@tests); my $exp = shift(@tests); my $res = eval { amount($amt) }; $res = '' unless defined $res; diag($@) if $@; is($res, $exp, "amount $amt"); } EekBoek-2.030.1/t/80_db_postgresql.t0000644000400000040000000000221212725476602014577 0ustar jvjv# 80_db_postgresql.t -- Basic test PosgreSQL access # Author : Johan Vromans # Created On : Mon Jan 16 11:07:02 2006 # Last Modified By: Johan Vromans # Last Modified On: Mon Jun 14 22:15:34 2010 # Update Count : 1 use strict; use warnings; use Test::More tests => 4; # Some basic tests. BEGIN { use_ok("DBI"); } SKIP: { eval { require DBD::Pg }; skip("DBI PostgreSQL driver (DBD::Pg) not installed", 3) if $@; # Check minimal Pg interface version. my $minpg = 1.31; ok($DBD::Pg::VERSION >= $minpg, "DBD::PG version = $DBD::Pg::VERSION, should be at east $minpg"); SKIP: { skip("Database tests skipped on request", 2) if $ENV{EB_SKIPDBTESTS}; # Check whether we can contact the database. my @ds; eval { @ds = DBI->data_sources("Pg"); diag("Connect error:\n\t" . ($DBI::errstr||"")) if $DBI::errstr; skip("No access to database", 2) if $DBI::errstr;# && $DBI::errstr =~ /FATAL:\s*(user|role) .* does not exist/; diag("Connect error:\n\t" . ($DBI::errstr||"")) if $DBI::errstr; ok(!$DBI::errstr, "Database Connect"); }; ok(@ds > 1, "Check databases"); } } EekBoek-2.030.1/t/10_basic.t0000644000400000040000000000113712725476601013005 0ustar jvjv#! perl use strict; use Test::More tests => 11; # Some basic tests. BEGIN { $ENV{LANG} = "nl_NL"; use_ok("EB"); EB->app_init( { app => "Test", nostdconf => 1 } ); ok( $::cfg, "Got config" ); use_ok("EB::Format"); use_ok("EB::Booking::IV"); use_ok("EB::Booking::BKM"); } # Check some data files. foreach ( qw(eekboek.sql) ) { my $t = findlib("schema/$_"); ok(-s $t, $t); } foreach ( qw(schema.dat bvnv.dat) ) { my $t = findlib($_, "examples"); ok(-s $t, $t); } foreach ( qw(eekboek balans balres) ) { my $t = findlib("css/$_.css"); ok(-s $t, $t); } EekBoek-2.030.1/t/92_ivp_postgres.t0000644000400000040000000000043313131642777014461 0ustar jvjv#! perl # $Id: 92_ivp_postgres.t,v 1.1 2009/10/15 16:27:04 jv Exp $ -*-perl-*- use strict; use warnings; our $dbdriver = "postgres"; if ( !$dbdriver && $0 =~ /\d+_ivp_(.+).t/ ) { $dbdriver = $1; } chdir("t") if -d "t"; $ENV{LANG} = "nl_NL"; require "./90_ivp_common.pl"; EekBoek-2.030.1/t/ivp/0000755000400000040000000000000013151742350012022 5ustar jvjvEekBoek-2.030.1/t/ivp/ivp.conf0000644000400000040000000000030113044346163013464 0ustar jvjv; Settings voor EekBoek Installatie-Verificatie Procedure. [locale] lang = nl_NL decimalpt = , [database] name = sample [internal] now = 2013-12-31 [csv] separator = , [html] cssdir = css EekBoek-2.030.1/t/ivp/reports.eb0000644000400000040000000000422012725476602014040 0ustar jvjv# Verify: balans in varianten. balans --output=out/balans.txt balans --detail=0 --output=out/balans0.txt balans --detail=1 --output=out/balans1.txt balans --detail=2 --output=out/balans2.txt balans --verdicht --output=out/balans2.txt balans --opening --output=out/obalans.txt # Verify: verlies/winst in varianten. result --output=out/result.txt result --detail=0 --output=out/result0.txt result --detail=1 --output=out/result1.txt result --verdicht --output=out/result2.txt result --periode=apr --output=out/result-apr.txt result --periode=mei --output=out/result-mei.txt # Verify: Journaal. journaal --output=out/journaal.txt # Verify: Journaal van dagboek. journaal postbank --output=out/journaal-postbank.txt # Verify: Journaal van boekstuk. journaal postbank:24 --output=out/journaal-postbank24.txt # Verify: Proef- en Saldibalans in varianten. proefensaldibalans --output=out/proef.txt proefensaldibalans --detail=0 --output=out/proef0.txt proefensaldibalans --detail=1 --output=out/proef1.txt proefensaldibalans --detail=2 --output=out/proef2.txt proefensaldibalans --verdicht --output=out/proef2.txt # Verify: Grootboek in varianten. grootboek --output=out/grootboek.txt grootboek --detail=0 --output=out/grootboek0.txt grootboek --detail=1 --output=out/grootboek1.txt grootboek --detail=2 --output=out/grootboek2.txt grootboek 2 --output=out/grootboek_2.txt grootboek 23 --output=out/grootboek_23.txt grootboek 23 22 --output=out/grootboek_23_22.txt grootboek 2320 --output=out/grootboek_2320.txt # Verify: Crediteuren/Debiteuren. crediteuren --output=out/crdrept.txt debiteuren --output=out/debrept.txt # Verify: BTW aangifte. btwaangifte j --output=out/btw.txt btwaangifte k2 --output=out/btwk2.txt btwaangifte 7 --output=out/btw7.txt # Verify: HTML generatie. balans --detail=2 --gen-html --output=out/balans2.html balans --detail=2 --gen-html --style=xxx --output=out/balans2xxx.html btwaangifte j --output=out/btw.html # Verify: CSV generatie. balans --detail=2 --gen-csv --output=out/balans2.csv # Verify: XAF generatie. export --xaf=out/export.xaf EekBoek-2.030.1/t/ivp/ref/0000755000400000040000000000000013151742350012576 5ustar jvjvEekBoek-2.030.1/t/ivp/ref/journaal-postbank.txt0000644000400000040000000002100613044346163016773 0ustar jvjv Journaal Periode: 2013-01-01 t/m 2013-12-31 EekBoek Demo Administratie EekBoek, 2013-12-31 Datum Boekstuk/Grootboek Rek Debet Credit BTW % Tarief Boekstuk/regel Relatie ------------------------------------------------------------------------------------------------------------------------------------------ 2013-01-31 Postbank:1 Afschrift 1 2013-01-31 Crediteuren 4100 104,65 *ADSL + Telefoon KPN 2013-01-19 Crediteuren 4100 22,80 *Internet XS4ALL 2013-01-06 Bankkosten 6980 2,70 0,00 Nul Girotel 2013-01-31 Postbank 2320 130,15 Afschrift 1 2013-02-28 Postbank:2 Afschrift 2 2013-02-23 Crediteuren 4100 22,80 *Internet XS4ALL 2013-02-10 Bankkosten 6980 2,70 0,00 Nul Girotel 2013-02-28 Postbank 2320 25,50 Afschrift 2 2013-03-31 Postbank:3 Afschrift 3 2013-03-31 Postbank 2320 3442,98 Afschrift 3 2013-03-31 Crediteuren 4100 101,52 *Telefoonkosten KPN 2013-03-31 Crediteuren 4100 22,80 *Internet XS4ALL 2013-03-09 Bankkosten 6980 2,70 0,00 Nul Girotel 2013-03-18 Debiteuren 2200 3570,00 *Perl Cursus ACME 2013-04-30 Postbank:4 Afschrift 4 2013-04-30 Postbank 2320 3544,50 Afschrift 4 2013-04-06 Crediteuren 4100 22,80 *Internet XS4ALL 2013-04-06 Bankkosten 6980 2,70 0,00 Nul Girotel 2013-04-12 Debiteuren 2200 3570,00 *Perl Cursus ACME 2013-05-31 Postbank:5 Afschrift 5 2013-05-31 Postbank 2320 472,28 Afschrift 5 2013-05-31 Crediteuren 4100 102,22 *Telefoonkosten KPN 2013-05-31 Crediteuren 4100 22,80 *Internet XS4ALL 2013-05-11 Bankkosten 6980 2,70 0,00 Nul Girotel 2013-05-31 Debiteuren 2200 600,00 *Perl Cursus ACME 2013-06-30 Postbank:6 Afschrift 6 2013-06-12 Debiteuren 2200 5,00 *Perl Cursus ACME 2013-06-30 Postbank 2320 683,50 Afschrift 6 2013-06-21 Crediteuren 4100 22,80 *Internet XS4ALL 2013-06-08 Bankkosten 6980 2,70 0,00 Nul Girotel 2013-06-08 Debiteuren 2200 714,00 *Ondersteuning ACME 2013-07-31 Postbank:7 Afschrift 7 2013-07-31 Crediteuren 4100 104,66 *Telefoonkosten KPN 2013-07-30 Crediteuren 4100 22,80 *Internet XS4ALL 2013-07-06 Bankkosten 6980 2,70 0,00 Nul Girotel 2013-07-31 Postbank 2320 130,16 Afschrift 7 2013-08-31 Postbank:8 Afschrift 8 2013-08-31 Postbank 2320 1688,50 Afschrift 8 2013-08-10 Crediteuren 4100 22,80 *Internet XS4ALL 2013-08-10 Bankkosten 6980 2,70 0,00 Nul Girotel 2013-08-10 Debiteuren 2200 714,00 *Ondersteuning ACME 2013-08-19 Debiteuren 2200 1000,00 *Pocket Reference ORA 2013-09-30 Postbank:9 Afschrift 9 2013-09-30 Crediteuren 4100 108,72 *Telefoonkosten KPN 2013-09-30 Crediteuren 4100 22,80 *Internet XS4ALL 2013-09-17 Bankkosten 6980 2,70 0,00 Nul Girotel 2013-09-30 Postbank 2320 134,22 Afschrift 9 2013-10-31 Postbank:10 Afschrift 10 2013-10-13 Crediteuren 4100 22,80 *Internet XS4ALL 2013-10-12 Bankkosten 6980 2,70 0,00 Nul Girotel 2013-10-31 Postbank 2320 25,50 Afschrift 10 2013-11-30 Postbank:11 Afschrift 11 2013-11-30 Crediteuren 4100 109,67 *Telefoonkosten KPN 2013-11-30 Crediteuren 4100 22,80 *Internet XS4ALL 2013-11-08 Bankkosten 6980 2,70 0,00 Nul Girotel 2013-11-30 Postbank 2320 135,17 Afschrift 11 2013-12-07 Postbank:12 Afschrift 12 2013-12-07 Crediteuren 4100 22,80 *Internet XS4ALL 2013-12-06 Bankkosten 6980 2,70 0,00 Nul Girotel 2013-12-07 Postbank 2320 25,50 Afschrift 12 2013-12-09 Postbank:13 Eerste deel ADSL 2013-12-09 Crediteuren 4100 10,00 *Internet XS4ALL 2013-12-09 Postbank 2320 10,00 Eerste deel ADSL 2013-12-10 Postbank:14 Tweede deel ADSL 2013-12-10 Crediteuren 4100 12,80 *Internet XS4ALL 2013-12-10 Postbank 2320 12,80 Tweede deel ADSL ------------------------------------------------------------------------------------------------------------------------------------------ Totaal Dagboek Postbank 10797,00 10797,00 EekBoek-2.030.1/t/ivp/ref/grootboek_23_22.txt0000644000400000040000000000662313044346163016153 0ustar jvjv Grootboek Periode: 2013-01-01 t/m 2013-12-31 EekBoek Demo Administratie EekBoek, 2013-12-31 GrBk Grootboek/Boekstuk Datum Debet Credit BoekstukNr Relatie --------------------------------------------------------------------------------------------------- 2200 Debiteuren Beginsaldo 0,00 0,00 Perl Cursus 2013-02-18 3570,00 0,00 Verkoop:1 Perl Cursus 2013-03-18 3570,00 0,00 Verkoop:2 *Perl Cursus 2013-03-18 0,00 3570,00 Postbank:3 ACME *Perl Cursus 2013-04-12 0,00 3570,00 Postbank:4 ACME Perl Cursus 2013-04-18 600,00 0,00 Verkoop:3 Perl Cursus 2013-05-12 0,00 5,00 Verkoop:4 Ondersteuning 2013-05-14 714,00 0,00 Verkoop:5 *Perl Cursus 2013-05-31 0,00 600,00 Postbank:5 ACME *Ondersteuning 2013-06-08 0,00 714,00 Postbank:6 ACME *Perl Cursus 2013-06-12 5,00 0,00 Postbank:6 ACME Ondersteuning 2013-07-16 714,00 0,00 Verkoop:6 *Ondersteuning 2013-08-10 0,00 714,00 Postbank:8 ACME Pocket Reference 2013-08-19 1000,00 0,00 Verkoop:7 *Pocket Reference 2013-08-19 0,00 1000,00 Postbank:8 ORA Totaal mutaties 0,00 2200 Totaal Debiteuren 0,00 2320 Postbank Beginsaldo 1131,92 0,00 Afschrift 1 2013-01-31 0,00 130,15 Postbank:1 Afschrift 2 2013-02-28 0,00 25,50 Postbank:2 Afschrift 3 2013-03-31 3442,98 0,00 Postbank:3 Afschrift 4 2013-04-30 3544,50 0,00 Postbank:4 Afschrift 5 2013-05-31 472,28 0,00 Postbank:5 Afschrift 6 2013-06-30 683,50 0,00 Postbank:6 Afschrift 7 2013-07-31 0,00 130,16 Postbank:7 Afschrift 8 2013-08-31 1688,50 0,00 Postbank:8 Afschrift 9 2013-09-30 0,00 134,22 Postbank:9 Afschrift 10 2013-10-31 0,00 25,50 Postbank:10 Afschrift 11 2013-11-30 0,00 135,17 Postbank:11 Afschrift 12 2013-12-07 0,00 25,50 Postbank:12 Eerste deel ADSL 2013-12-09 0,00 10,00 Postbank:13 Tweede deel ADSL 2013-12-10 0,00 12,80 Postbank:14 Totaal mutaties 9202,76 2320 Totaal Postbank 10334,68 Totaal mutaties 9202,76 0,00 --------------------------------------------------------------------------------------------------- Totaal 10334,68 0,00 EekBoek-2.030.1/t/ivp/ref/result.txt0000644000400000040000000000175613044346163014671 0ustar jvjv Verlies/Winst Periode: 2013-01-01 t/m 2013-12-31 EekBoek Demo Administratie EekBoek, 2013-12-31 RekNr Grootboekrekening Debet Credit ---------------------------------------------------------------------- 6800 Afschr. kosten inv. & inr. 411,26 6810 Afschr. kosten computers 396,82 6900 Telefoon- en faxkosten 501,86 6905 Internetkosten 264,92 6980 Bankkosten 32,40 8100 Omzet advisering 1180,16 8300 Omzet editing 1000,00 8400 Omzet cursussen 6392,56 << Winst >> 6965,46 ---------------------------------------------------------------------- TOTAAL Resultaten 8572,72 8572,72 EekBoek-2.030.1/t/ivp/ref/journaal.txt0000644000400000040000000005212413044346163015161 0ustar jvjv Journaal Periode: 2013-01-01 t/m 2013-12-31 EekBoek Demo Administratie EekBoek, 2013-12-31 Datum Boekstuk/Grootboek Rek Debet Credit BTW % Tarief Boekstuk/regel Relatie ------------------------------------------------------------------------------------------------------------------------------------------ 2013-01-05 Inkoop:1 Internet XS4ALL 2013-01-05 BTW Inkoop Hoog 4220 3,96 BTW ADSL 2013-01-05 Internetkosten 6905 18,84 21,00 Hoog ADSL 2013-01-05 Crediteuren 4100 22,80 Internet 2013-01-15 Inkoop:2 ADSL + Telefoon KPN 2013-01-15 BTW Inkoop Hoog 4220 13,96 BTW Telefoonkosten 2013-01-15 BTW Inkoop Hoog 4220 4,20 BTW ADSL 2013-01-15 Telefoon- en faxkosten 6900 66,49 21,00 Hoog Telefoonkosten 2013-01-15 Internetkosten 6905 20,00 21,00 Hoog ADSL 2013-01-15 Crediteuren 4100 104,65 ADSL + Telefoon 2013-01-31 Postbank:1 Afschrift 1 2013-01-31 Crediteuren 4100 104,65 *ADSL + Telefoon KPN 2013-01-19 Crediteuren 4100 22,80 *Internet XS4ALL 2013-01-06 Bankkosten 6980 2,70 0,00 Nul Girotel 2013-01-31 Postbank 2320 130,15 Afschrift 1 2013-02-09 Inkoop:3 Internet XS4ALL 2013-02-09 BTW Inkoop Hoog 4220 3,96 BTW ADSL 2013-02-09 Internetkosten 6905 18,84 21,00 Hoog ADSL 2013-02-09 Crediteuren 4100 22,80 Internet 2013-02-18 Verkoop:1 Perl Cursus ACME 2013-02-18 Debiteuren 2200 3570,00 Perl Cursus 2013-02-18 BTW Verkoop Hoog 4200 619,59 BTW Perl Cursus 1e bet. 2013-02-18 Omzet cursussen 8400 2950,41 21,00 Hoog Perl Cursus 1e bet. 2013-02-28 Postbank:2 Afschrift 2 2013-02-23 Crediteuren 4100 22,80 *Internet XS4ALL 2013-02-10 Bankkosten 6980 2,70 0,00 Nul Girotel 2013-02-28 Postbank 2320 25,50 Afschrift 2 2013-03-08 Inkoop:4 Internet XS4ALL 2013-03-08 BTW Inkoop Hoog 4220 3,96 BTW ADSL 2013-03-08 Internetkosten 6905 18,84 21,00 Hoog ADSL 2013-03-08 Crediteuren 4100 22,80 Internet 2013-03-18 Inkoop:5 Telefoonkosten KPN 2013-03-18 BTW Inkoop Hoog 4220 17,62 BTW ADSL + Telefoon 2013-03-18 Telefoon- en faxkosten 6900 83,90 21,00 Hoog ADSL + Telefoon 2013-03-18 Crediteuren 4100 101,52 Telefoonkosten 2013-03-18 Verkoop:2 Perl Cursus ACME 2013-03-18 Debiteuren 2200 3570,00 Perl Cursus 2013-03-18 BTW Verkoop Hoog 4200 619,59 BTW Perl Cursus 2e bet. 2013-03-18 Omzet cursussen 8400 2950,41 21,00 Hoog Perl Cursus 2e bet. 2013-03-31 Postbank:3 Afschrift 3 2013-03-31 Postbank 2320 3442,98 Afschrift 3 2013-03-31 Crediteuren 4100 101,52 *Telefoonkosten KPN 2013-03-31 Crediteuren 4100 22,80 *Internet XS4ALL 2013-03-09 Bankkosten 6980 2,70 0,00 Nul Girotel 2013-03-18 Debiteuren 2200 3570,00 *Perl Cursus ACME 2013-04-05 Inkoop:6 Internet XS4ALL 2013-04-05 BTW Inkoop Hoog 4220 3,96 BTW ADSL 2013-04-05 Internetkosten 6905 18,84 21,00 Hoog ADSL 2013-04-05 Crediteuren 4100 22,80 Internet 2013-04-18 Verkoop:3 Perl Cursus ACME 2013-04-18 Debiteuren 2200 600,00 Perl Cursus 2013-04-18 BTW Verkoop Hoog 4200 104,13 BTW Perl Cursus rest 2013-04-18 Omzet cursussen 8400 495,87 21,00 Hoog Perl Cursus rest 2013-04-30 Postbank:4 Afschrift 4 2013-04-30 Postbank 2320 3544,50 Afschrift 4 2013-04-06 Crediteuren 4100 22,80 *Internet XS4ALL 2013-04-06 Bankkosten 6980 2,70 0,00 Nul Girotel 2013-04-12 Debiteuren 2200 3570,00 *Perl Cursus ACME 2013-05-10 Inkoop:7 Internet XS4ALL 2013-05-10 BTW Inkoop Hoog 4220 3,96 BTW ADSL 2013-05-10 Internetkosten 6905 18,84 21,00 Hoog ADSL 2013-05-10 Crediteuren 4100 22,80 Internet 2013-05-12 Verkoop:4 Perl Cursus ACME 2013-05-12 BTW Verkoop Hoog 4200 0,87 BTW Perl Cursus rest 2013-05-12 Omzet cursussen 8400 4,13 21,00 Hoog Perl Cursus rest 2013-05-12 Debiteuren 2200 5,00 Perl Cursus 2013-05-14 Verkoop:5 Ondersteuning ACME 2013-05-14 Debiteuren 2200 714,00 Ondersteuning 2013-05-14 BTW Verkoop Hoog 4200 123,92 BTW Consultancy 2013-05-14 Omzet advisering 8100 590,08 21,00 Hoog Consultancy 2013-05-20 Inkoop:8 Telefoonkosten KPN 2013-05-20 BTW Inkoop Hoog 4220 17,74 BTW ADSL + Telefoon 2013-05-20 Telefoon- en faxkosten 6900 84,48 21,00 Hoog ADSL + Telefoon 2013-05-20 Crediteuren 4100 102,22 Telefoonkosten 2013-05-31 Postbank:5 Afschrift 5 2013-05-31 Postbank 2320 472,28 Afschrift 5 2013-05-31 Crediteuren 4100 102,22 *Telefoonkosten KPN 2013-05-31 Crediteuren 4100 22,80 *Internet XS4ALL 2013-05-11 Bankkosten 6980 2,70 0,00 Nul Girotel 2013-05-31 Debiteuren 2200 600,00 *Perl Cursus ACME 2013-06-07 Inkoop:9 Internet XS4ALL 2013-06-07 BTW Inkoop Hoog 4220 3,96 BTW ADSL 2013-06-07 Internetkosten 6905 18,84 21,00 Hoog ADSL 2013-06-07 Crediteuren 4100 22,80 Internet 2013-06-30 Postbank:6 Afschrift 6 2013-06-12 Debiteuren 2200 5,00 *Perl Cursus ACME 2013-06-30 Postbank 2320 683,50 Afschrift 6 2013-06-21 Crediteuren 4100 22,80 *Internet XS4ALL 2013-06-08 Bankkosten 6980 2,70 0,00 Nul Girotel 2013-06-08 Debiteuren 2200 714,00 *Ondersteuning ACME 2013-07-05 Inkoop:10 Internet XS4ALL 2013-07-05 BTW Inkoop Hoog 4220 3,96 BTW ADSL 2013-07-05 Internetkosten 6905 18,84 21,00 Hoog ADSL 2013-07-05 Crediteuren 4100 22,80 Internet 2013-07-15 Inkoop:11 Telefoonkosten KPN 2013-07-15 BTW Inkoop Hoog 4220 18,16 BTW ADSL + Telefoon 2013-07-15 Telefoon- en faxkosten 6900 86,50 21,00 Hoog ADSL + Telefoon 2013-07-15 Crediteuren 4100 104,66 Telefoonkosten 2013-07-16 Verkoop:6 Ondersteuning ACME 2013-07-16 Debiteuren 2200 714,00 Ondersteuning 2013-07-16 BTW Verkoop Hoog 4200 123,92 BTW Consultancy 2013-07-16 Omzet advisering 8100 590,08 21,00 Hoog Consultancy 2013-07-31 Postbank:7 Afschrift 7 2013-07-31 Crediteuren 4100 104,66 *Telefoonkosten KPN 2013-07-30 Crediteuren 4100 22,80 *Internet XS4ALL 2013-07-06 Bankkosten 6980 2,70 0,00 Nul Girotel 2013-07-31 Postbank 2320 130,16 Afschrift 7 2013-08-09 Inkoop:12 Internet XS4ALL 2013-08-09 BTW Inkoop Hoog 4220 3,96 BTW ADSL 2013-08-09 Internetkosten 6905 18,84 21,00 Hoog ADSL 2013-08-09 Crediteuren 4100 22,80 Internet 2013-08-19 Verkoop:7 Pocket Reference ORA 2013-08-19 Debiteuren 2200 1000,00 Pocket Reference 2013-08-19 Omzet editing 8300 1000,00 21,00 Hoog Produktie boek 2013-08-31 Postbank:8 Afschrift 8 2013-08-31 Postbank 2320 1688,50 Afschrift 8 2013-08-10 Crediteuren 4100 22,80 *Internet XS4ALL 2013-08-10 Bankkosten 6980 2,70 0,00 Nul Girotel 2013-08-10 Debiteuren 2200 714,00 *Ondersteuning ACME 2013-08-19 Debiteuren 2200 1000,00 *Pocket Reference ORA 2013-09-06 Inkoop:13 Internet XS4ALL 2013-09-06 BTW Inkoop Hoog 4220 3,96 BTW ADSL 2013-09-06 Internetkosten 6905 18,84 21,00 Hoog ADSL 2013-09-06 Crediteuren 4100 22,80 Internet 2013-09-16 Inkoop:14 Telefoonkosten KPN 2013-09-16 BTW Inkoop Hoog 4220 18,87 BTW ADSL + Telefoon 2013-09-16 Telefoon- en faxkosten 6900 89,85 21,00 Hoog ADSL + Telefoon 2013-09-16 Crediteuren 4100 108,72 Telefoonkosten 2013-09-30 Postbank:9 Afschrift 9 2013-09-30 Crediteuren 4100 108,72 *Telefoonkosten KPN 2013-09-30 Crediteuren 4100 22,80 *Internet XS4ALL 2013-09-17 Bankkosten 6980 2,70 0,00 Nul Girotel 2013-09-30 Postbank 2320 134,22 Afschrift 9 2013-10-11 Inkoop:15 Internet XS4ALL 2013-10-11 BTW Inkoop Hoog 4220 3,96 BTW ADSL 2013-10-11 Internetkosten 6905 18,84 21,00 Hoog ADSL 2013-10-11 Crediteuren 4100 22,80 Internet 2013-10-31 Postbank:10 Afschrift 10 2013-10-13 Crediteuren 4100 22,80 *Internet XS4ALL 2013-10-12 Bankkosten 6980 2,70 0,00 Nul Girotel 2013-10-31 Postbank 2320 25,50 Afschrift 10 2013-11-07 Inkoop:16 Internet XS4ALL 2013-11-07 BTW Inkoop Hoog 4220 3,96 BTW ADSL 2013-11-07 Internetkosten 6905 18,84 21,00 Hoog ADSL 2013-11-07 Crediteuren 4100 22,80 Internet 2013-11-17 Inkoop:17 Telefoonkosten KPN 2013-11-17 BTW Inkoop Hoog 4220 19,03 BTW ADSL + Telefoon 2013-11-17 Telefoon- en faxkosten 6900 90,64 21,00 Hoog ADSL + Telefoon 2013-11-17 Crediteuren 4100 109,67 Telefoonkosten 2013-11-30 Postbank:11 Afschrift 11 2013-11-30 Crediteuren 4100 109,67 *Telefoonkosten KPN 2013-11-30 Crediteuren 4100 22,80 *Internet XS4ALL 2013-11-08 Bankkosten 6980 2,70 0,00 Nul Girotel 2013-11-30 Postbank 2320 135,17 Afschrift 11 2013-12-06 Inkoop:18 Internet XS4ALL 2013-12-06 BTW Inkoop Hoog 4220 3,96 BTW ÁDSL 2013-12-06 Internetkosten 6905 18,84 21,00 Hoog ÁDSL 2013-12-06 Crediteuren 4100 22,80 Internet 2013-12-07 Inkoop:20 Internet XS4ALL 2013-12-07 BTW Inkoop Hoog 4220 3,96 BTW ADSL 2013-12-07 Internetkosten 6905 18,84 21,00 Hoog ADSL 2013-12-07 Crediteuren 4100 22,80 Internet 2013-12-07 Postbank:12 Afschrift 12 2013-12-07 Crediteuren 4100 22,80 *Internet XS4ALL 2013-12-06 Bankkosten 6980 2,70 0,00 Nul Girotel 2013-12-07 Postbank 2320 25,50 Afschrift 12 2013-12-09 Postbank:13 Eerste deel ADSL 2013-12-09 Crediteuren 4100 10,00 *Internet XS4ALL 2013-12-09 Postbank 2320 10,00 Eerste deel ADSL 2013-12-10 Postbank:14 Tweede deel ADSL 2013-12-10 Crediteuren 4100 12,80 *Internet XS4ALL 2013-12-10 Postbank 2320 12,80 Tweede deel ADSL 2013-12-31 Memoriaal:1 Afschrijving inventaris 2013-12-31 Afschr. kosten inv. & inr. 6800 411,26 0,00 Nul Afschrijving 2013-12-31 Afschrijving inv. & inr. 1101 411,26 Afschrijving 2013-12-31 Memoriaal:2 Afschrijving computers 2013-12-31 Afschr. kosten computers 6810 396,82 0,00 Nul Afschrijving 2013-12-31 Afschrijving computers 1111 396,82 Afschrijving ------------------------------------------------------------------------------------------------------------------------------------------ Totaal 22705,92 22705,92 EekBoek-2.030.1/t/ivp/ref/grootboek1.txt0000644000400000040000000001131313044346163015415 0ustar jvjv Grootboek Periode: 2013-01-01 t/m 2013-12-31 EekBoek Demo Administratie EekBoek, 2013-12-31 GrBk Grootboek/Boekstuk Datum Debet Credit BoekstukNr Relatie --------------------------------------------------------------------------------------------------- 1100 Inventaris en inrichting Beginsaldo 1344,37 0,00 Totaal mutaties 0,00 1100 Totaal Inventaris en 1344,37 inrichting 1101 Afschrijving inv. & inr. Beginsaldo 0,00 1304,81 Totaal mutaties 411,26 1101 Totaal Afschrijving inv. & 1716,07 inr. 1110 Computers Beginsaldo 13378,48 0,00 Totaal mutaties 0,00 1110 Totaal Computers 13378,48 1111 Afschrijving computers Beginsaldo 0,00 12106,78 Totaal mutaties 396,82 1111 Totaal Afschrijving computers 12503,60 2200 Debiteuren Beginsaldo 0,00 0,00 Totaal mutaties 0,00 2200 Totaal Debiteuren 0,00 2320 Postbank Beginsaldo 1131,92 0,00 Totaal mutaties 9202,76 2320 Totaal Postbank 10334,68 3100 Kapitaal de heer/mevrouw Beginsaldo 0,00 2443,18 Totaal mutaties 0,00 3100 Totaal Kapitaal de 2443,18 heer/mevrouw 4100 Crediteuren Beginsaldo 0,00 0,00 Totaal mutaties 0,00 4100 Totaal Crediteuren 0,00 4200 BTW Verkoop Hoog Beginsaldo 0,00 0,00 Totaal mutaties 1590,28 4200 Totaal BTW Verkoop Hoog 1590,28 4220 BTW Inkoop Hoog Beginsaldo 0,00 0,00 Totaal mutaties 161,06 4220 Totaal BTW Inkoop Hoog 161,06 6800 Afschr. kosten inv. & inr. Beginsaldo 0,00 0,00 Totaal mutaties 411,26 6800 Totaal Afschr. kosten inv. & 411,26 inr. 6810 Afschr. kosten computers Beginsaldo 0,00 0,00 Totaal mutaties 396,82 6810 Totaal Afschr. kosten 396,82 computers 6900 Telefoon- en faxkosten Beginsaldo 0,00 0,00 Totaal mutaties 501,86 6900 Totaal Telefoon- en faxkosten 501,86 6905 Internetkosten Beginsaldo 0,00 0,00 Totaal mutaties 264,92 6905 Totaal Internetkosten 264,92 6980 Bankkosten Beginsaldo 0,00 0,00 Totaal mutaties 32,40 6980 Totaal Bankkosten 32,40 8100 Omzet advisering Beginsaldo 0,00 0,00 Totaal mutaties 1180,16 8100 Totaal Omzet advisering 1180,16 8300 Omzet editing Beginsaldo 0,00 0,00 Totaal mutaties 1000,00 8300 Totaal Omzet editing 1000,00 8400 Omzet cursussen Beginsaldo 0,00 0,00 Totaal mutaties 6392,56 8400 Totaal Omzet cursussen 6392,56 Totaal mutaties 10971,08 10971,08 --------------------------------------------------------------------------------------------------- Totaal 26825,85 26825,85 EekBoek-2.030.1/t/ivp/ref/proef.txt0000644000400000040000000000403613044346163014460 0ustar jvjv Proef- en Saldibalans Periode: t/m 2013-12-31 EekBoek Demo Administratie EekBoek, 2013-12-31 RekNr Grootboekrekening Debet Credit Saldo Db Saldo Cr -------------------------------------------------------------------------------------------- 1100 Inventaris en inrichting 1344,37 0,00 1344,37 1101 Afschrijving inv. & inr. 0,00 1716,07 1716,07 1110 Computers 13378,48 0,00 13378,48 1111 Afschrijving computers 0,00 12503,60 12503,60 2200 Debiteuren 10173,00 10173,00 2320 Postbank 10963,68 629,00 10334,68 3100 Kapitaal de heer/mevrouw 0,00 2443,18 2443,18 4100 Crediteuren 927,84 927,84 4200 BTW Verkoop Hoog 0,87 1591,15 1590,28 4220 BTW Inkoop Hoog 161,06 0,00 161,06 6800 Afschr. kosten inv. & inr. 411,26 0,00 411,26 6810 Afschr. kosten computers 396,82 0,00 396,82 6900 Telefoon- en faxkosten 501,86 0,00 501,86 6905 Internetkosten 264,92 0,00 264,92 6980 Bankkosten 32,40 0,00 32,40 8100 Omzet advisering 0,00 1180,16 1180,16 8300 Omzet editing 0,00 1000,00 1000,00 8400 Omzet cursussen 4,13 6396,69 6392,56 -------------------------------------------------------------------------------------------- TOTAAL 38560,69 38560,69 26825,85 26825,85 EekBoek-2.030.1/t/ivp/ref/debrept.txt0000644000400000040000000000422213044346163014767 0ustar jvjv Debiteurenadministratie Periode: 2013-01-01 t/m 2013-12-31 EekBoek Demo Administratie EekBoek, 2013-12-31 Debiteur Datum Omschrijving Bedrag Open Betaald Boekstuk ------------------------------------------------------------------------------------------------------ ACME 2013-02-18 Perl Cursus 3570,00 0,00 Verkoop:1 2013-03-18 *Perl Cursus 3570,00 Postbank:3 2013-03-18 Perl Cursus 3570,00 0,00 Verkoop:2 2013-04-12 *Perl Cursus 3570,00 Postbank:4 2013-04-18 Perl Cursus 600,00 0,00 Verkoop:3 2013-05-31 *Perl Cursus 600,00 Postbank:5 2013-05-12 Perl Cursus -5,00 0,00 Verkoop:4 2013-06-12 *Perl Cursus -5,00 Postbank:6 2013-05-14 Ondersteuning 714,00 0,00 Verkoop:5 2013-06-08 *Ondersteuning 714,00 Postbank:6 2013-07-16 Ondersteuning 714,00 0,00 Verkoop:6 2013-08-10 *Ondersteuning 714,00 Postbank:8 --------- --------- ACME Totaal 9163,00 0,00 ORA 2013-08-19 Pocket Reference 1000,00 0,00 Verkoop:7 2013-08-19 *Pocket Reference 1000,00 Postbank:8 --------- --------- ORA Totaal 1000,00 0,00 ------------------------------------------------------------------------------------------------------ Totaal 10163,00 0,00 EekBoek-2.030.1/t/ivp/ref/result2.txt0000644000400000040000000000315413044346163014745 0ustar jvjv Verlies/Winst Periode: 2013-01-01 t/m 2013-12-31 EekBoek Demo Administratie EekBoek, 2013-12-31 RekNr Verdichting/Grootboekrekening Debet Credit ---------------------------------------------------------------------- 6 Kosten 68 Afschrijvingen 6800 Afschr. kosten inv. & inr. 411,26 6810 Afschr. kosten computers 396,82 68 Totaal Afschrijvingen 808,08 69 Algemene kosten 6900 Telefoon- en faxkosten 501,86 6905 Internetkosten 264,92 6980 Bankkosten 32,40 69 Totaal Algemene kosten 799,18 6 Totaal Kosten 1607,26 8 Bedrijfsopbrengsten 81 Omzet Consultancy 8100 Omzet advisering 1180,16 81 Totaal Omzet Consultancy 1180,16 83 Omzet Editing 8300 Omzet editing 1000,00 83 Totaal Omzet Editing 1000,00 84 Omzet Cursussen 8400 Omzet cursussen 6392,56 84 Totaal Omzet Cursussen 6392,56 8 Totaal Bedrijfsopbrengsten 8572,72 << Winst >> 6965,46 ---------------------------------------------------------------------- TOTAAL Resultaten 8572,72 8572,72 EekBoek-2.030.1/t/ivp/ref/grootboek_2320.txt0000644000400000040000000000375013044346163016010 0ustar jvjv Grootboek Periode: 2013-01-01 t/m 2013-12-31 EekBoek Demo Administratie EekBoek, 2013-12-31 GrBk Grootboek/Boekstuk Datum Debet Credit BoekstukNr Relatie --------------------------------------------------------------------------------------------------- 2320 Postbank Beginsaldo 1131,92 0,00 Afschrift 1 2013-01-31 0,00 130,15 Postbank:1 Afschrift 2 2013-02-28 0,00 25,50 Postbank:2 Afschrift 3 2013-03-31 3442,98 0,00 Postbank:3 Afschrift 4 2013-04-30 3544,50 0,00 Postbank:4 Afschrift 5 2013-05-31 472,28 0,00 Postbank:5 Afschrift 6 2013-06-30 683,50 0,00 Postbank:6 Afschrift 7 2013-07-31 0,00 130,16 Postbank:7 Afschrift 8 2013-08-31 1688,50 0,00 Postbank:8 Afschrift 9 2013-09-30 0,00 134,22 Postbank:9 Afschrift 10 2013-10-31 0,00 25,50 Postbank:10 Afschrift 11 2013-11-30 0,00 135,17 Postbank:11 Afschrift 12 2013-12-07 0,00 25,50 Postbank:12 Eerste deel ADSL 2013-12-09 0,00 10,00 Postbank:13 Tweede deel ADSL 2013-12-10 0,00 12,80 Postbank:14 Totaal mutaties 9202,76 2320 Totaal Postbank 10334,68 Totaal mutaties 9202,76 0,00 --------------------------------------------------------------------------------------------------- Totaal 10334,68 0,00 EekBoek-2.030.1/t/ivp/ref/proef0.txt0000644000400000040000000000206013044346163014533 0ustar jvjv Proef- en Saldibalans Periode: t/m 2013-12-31 EekBoek Demo Administratie EekBoek, 2013-12-31 RekNr Verdichting/Grootboekrekening Debet Credit Saldo Db Saldo Cr -------------------------------------------------------------------------------------------- 1 Totaal Vaste Activa 14722,85 14219,67 503,18 2 Totaal Vlottende activa 21136,68 10802,00 10334,68 3 Totaal Eigen vermogen 2443,18 2443,18 4 Totaal Vreemd vermogen 1089,77 2518,99 1429,22 6 Totaal Kosten 1607,26 1607,26 8 Totaal Bedrijfsopbrengsten 4,13 8576,85 8572,72 -------------------------------------------------------------------------------------------- TOTAAL 38560,69 38560,69 12445,12 12445,12 EekBoek-2.030.1/t/ivp/ref/balans2.html0000644000400000040000000001100413044346163015005 0ustar jvjv Balans

Balans

Periode: t/m 2013-12-31
EekBoek Demo Administratie

{name}, "\">", $_->{title} ? $html->($_->{title}) : " '", "
RekNr Verdichting/Grootboekrekening Debet Credit
1 Vaste Activa    
11 Materiële vaste activa    
1100 Inventaris en inrichting 1344,37  
1101 Afschrijving inv. & inr.   1716,07
1110 Computers 13378,48  
1111 Afschrijving computers   12503,60
11 Totaal Materiële vaste activa 503,18  
1 Totaal Vaste Activa 503,18  
2 Vlottende activa    
23 Liquide middelen    
2320 Postbank 10334,68  
23 Totaal Liquide middelen 10334,68  
2 Totaal Vlottende activa 10334,68  
3 Eigen vermogen    
31 Kapitaal    
3100 Kapitaal de heer/mevrouw   2443,18
31 Totaal Kapitaal   2443,18
3 Totaal Eigen vermogen   2443,18
4 Vreemd vermogen    
42 Belastingen & soc. lasten    
4200 BTW Verkoop Hoog   1590,28
4220 BTW Inkoop Hoog 161,06  
42 Totaal Belastingen & soc. lasten   1429,22
4 Totaal Vreemd vermogen   1429,22
  << Winst >>   6965,46
  TOTAAL Balans 10837,86 10837,86
EekBoek-2.030.1/t/ivp/ref/grootboek_23.txt0000644000400000040000000000375013044346163015646 0ustar jvjv Grootboek Periode: 2013-01-01 t/m 2013-12-31 EekBoek Demo Administratie EekBoek, 2013-12-31 GrBk Grootboek/Boekstuk Datum Debet Credit BoekstukNr Relatie --------------------------------------------------------------------------------------------------- 2320 Postbank Beginsaldo 1131,92 0,00 Afschrift 1 2013-01-31 0,00 130,15 Postbank:1 Afschrift 2 2013-02-28 0,00 25,50 Postbank:2 Afschrift 3 2013-03-31 3442,98 0,00 Postbank:3 Afschrift 4 2013-04-30 3544,50 0,00 Postbank:4 Afschrift 5 2013-05-31 472,28 0,00 Postbank:5 Afschrift 6 2013-06-30 683,50 0,00 Postbank:6 Afschrift 7 2013-07-31 0,00 130,16 Postbank:7 Afschrift 8 2013-08-31 1688,50 0,00 Postbank:8 Afschrift 9 2013-09-30 0,00 134,22 Postbank:9 Afschrift 10 2013-10-31 0,00 25,50 Postbank:10 Afschrift 11 2013-11-30 0,00 135,17 Postbank:11 Afschrift 12 2013-12-07 0,00 25,50 Postbank:12 Eerste deel ADSL 2013-12-09 0,00 10,00 Postbank:13 Tweede deel ADSL 2013-12-10 0,00 12,80 Postbank:14 Totaal mutaties 9202,76 2320 Totaal Postbank 10334,68 Totaal mutaties 9202,76 0,00 --------------------------------------------------------------------------------------------------- Totaal 10334,68 0,00 EekBoek-2.030.1/t/ivp/ref/btw.html0000644000400000040000000000670613044346163014274 0ustar jvjv BTW Aangifte

BTW Aangifte

Periode: 2013
EekBoek Demo Administratie

Binnenland    
1. Door mij verrichte leveringen/diensten    
1a Belast met hoog tarief 7572 1590
1b Belast met laag tarief 0 0
1e Belast met 0% / verlegd 0  
Buitenland    
3. Door mij verrichte leveringen    
3a Buiten de EU 1000  
3b Binnen de EU 0  
4. Aan mij verrichte leveringen    
4a Van buiten de EU 0 0
4b Verwervingen van goederen uit de EU 0 0
Berekening    
5. Berekening totaal    
5a Subtotaal   1590
5b Voorbelasting   162
5c Subtotaal   1428
5d Vermindering kleineondernemersregeling   1138
5g Totaal te betalen   290
  Totaal te betalen (onafgerond) 1429,22  
  Afrondingsverschil 1,22  
EekBoek-2.030.1/t/ivp/ref/balans2xxx.html0000644000400000040000000001100113044346163015552 0ustar jvjv Balans

Balans

Periode: t/m 2013-12-31
EekBoek Demo Administratie

RekNr Verdichting/Grootboekrekening Debet Credit
1 Vaste Activa    
11 Materiële vaste activa    
1100 Inventaris en inrichting 1344,37  
1101 Afschrijving inv. & inr.   1716,07
1110 Computers 13378,48  
1111 Afschrijving computers   12503,60
11 Totaal Materiële vaste activa 503,18  
1 Totaal Vaste Activa 503,18  
2 Vlottende activa    
23 Liquide middelen    
2320 Postbank 10334,68  
23 Totaal Liquide middelen 10334,68  
2 Totaal Vlottende activa 10334,68  
3 Eigen vermogen    
31 Kapitaal    
3100 Kapitaal de heer/mevrouw   2443,18
31 Totaal Kapitaal   2443,18
3 Totaal Eigen vermogen   2443,18
4 Vreemd vermogen    
42 Belastingen & soc. lasten    
4200 BTW Verkoop Hoog   1590,28
4220 BTW Inkoop Hoog 161,06  
42 Totaal Belastingen & soc. lasten   1429,22
4 Totaal Vreemd vermogen   1429,22
  << Winst >>   6965,46
  TOTAAL Balans 10837,86 10837,86
EekBoek-2.030.1/t/ivp/ref/balans.txt0000644000400000040000000000176613044346163014614 0ustar jvjv Balans Periode: t/m 2013-12-31 EekBoek Demo Administratie EekBoek, 2013-12-31 RekNr Grootboekrekening Debet Credit ---------------------------------------------------------------------- 1100 Inventaris en inrichting 1344,37 1101 Afschrijving inv. & inr. 1716,07 1110 Computers 13378,48 1111 Afschrijving computers 12503,60 2320 Postbank 10334,68 3100 Kapitaal de heer/mevrouw 2443,18 4200 BTW Verkoop Hoog 1590,28 4220 BTW Inkoop Hoog 161,06 << Winst >> 6965,46 ---------------------------------------------------------------------- TOTAAL Balans 25218,59 25218,59 EekBoek-2.030.1/t/ivp/ref/balans2.txt0000644000400000040000000000333013044346163014663 0ustar jvjv Balans Periode: t/m 2013-12-31 EekBoek Demo Administratie EekBoek, 2013-12-31 RekNr Verdichting/Grootboekrekening Debet Credit ---------------------------------------------------------------------- 1 Vaste Activa 11 Materiële vaste activa 1100 Inventaris en inrichting 1344,37 1101 Afschrijving inv. & inr. 1716,07 1110 Computers 13378,48 1111 Afschrijving computers 12503,60 11 Totaal Materiële vaste activa 503,18 1 Totaal Vaste Activa 503,18 2 Vlottende activa 23 Liquide middelen 2320 Postbank 10334,68 23 Totaal Liquide middelen 10334,68 2 Totaal Vlottende activa 10334,68 3 Eigen vermogen 31 Kapitaal 3100 Kapitaal de heer/mevrouw 2443,18 31 Totaal Kapitaal 2443,18 3 Totaal Eigen vermogen 2443,18 4 Vreemd vermogen 42 Belastingen & soc. lasten 4200 BTW Verkoop Hoog 1590,28 4220 BTW Inkoop Hoog 161,06 42 Totaal Belastingen & soc. lasten 1429,22 4 Totaal Vreemd vermogen 1429,22 << Winst >> 6965,46 ---------------------------------------------------------------------- TOTAAL Balans 10837,86 10837,86 EekBoek-2.030.1/t/ivp/ref/result0.txt0000644000400000040000000000116013044346163014736 0ustar jvjv Verlies/Winst Periode: 2013-01-01 t/m 2013-12-31 EekBoek Demo Administratie EekBoek, 2013-12-31 RekNr Verdichting/Grootboekrekening Debet Credit ---------------------------------------------------------------------- 6 Kosten 1607,26 8 Bedrijfsopbrengsten 8572,72 << Winst >> 6965,46 ---------------------------------------------------------------------- TOTAAL Resultaten 8572,72 8572,72 EekBoek-2.030.1/t/ivp/ref/grootboek.txt0000644000400000040000000004006013044346163015335 0ustar jvjv Grootboek Periode: 2013-01-01 t/m 2013-12-31 EekBoek Demo Administratie EekBoek, 2013-12-31 GrBk Grootboek/Boekstuk Datum Debet Credit BoekstukNr Relatie --------------------------------------------------------------------------------------------------- 1100 Inventaris en inrichting Beginsaldo 1344,37 0,00 Totaal mutaties 0,00 1100 Totaal Inventaris en 1344,37 inrichting 1101 Afschrijving inv. & inr. Beginsaldo 0,00 1304,81 Afschrijving 2013-12-31 0,00 411,26 Memoriaal:1 Totaal mutaties 411,26 1101 Totaal Afschrijving inv. & 1716,07 inr. 1110 Computers Beginsaldo 13378,48 0,00 Totaal mutaties 0,00 1110 Totaal Computers 13378,48 1111 Afschrijving computers Beginsaldo 0,00 12106,78 Afschrijving 2013-12-31 0,00 396,82 Memoriaal:2 Totaal mutaties 396,82 1111 Totaal Afschrijving computers 12503,60 2200 Debiteuren Beginsaldo 0,00 0,00 Perl Cursus 2013-02-18 3570,00 0,00 Verkoop:1 Perl Cursus 2013-03-18 3570,00 0,00 Verkoop:2 *Perl Cursus 2013-03-18 0,00 3570,00 Postbank:3 ACME *Perl Cursus 2013-04-12 0,00 3570,00 Postbank:4 ACME Perl Cursus 2013-04-18 600,00 0,00 Verkoop:3 Perl Cursus 2013-05-12 0,00 5,00 Verkoop:4 Ondersteuning 2013-05-14 714,00 0,00 Verkoop:5 *Perl Cursus 2013-05-31 0,00 600,00 Postbank:5 ACME *Ondersteuning 2013-06-08 0,00 714,00 Postbank:6 ACME *Perl Cursus 2013-06-12 5,00 0,00 Postbank:6 ACME Ondersteuning 2013-07-16 714,00 0,00 Verkoop:6 *Ondersteuning 2013-08-10 0,00 714,00 Postbank:8 ACME Pocket Reference 2013-08-19 1000,00 0,00 Verkoop:7 *Pocket Reference 2013-08-19 0,00 1000,00 Postbank:8 ORA Totaal mutaties 0,00 2200 Totaal Debiteuren 0,00 2320 Postbank Beginsaldo 1131,92 0,00 Afschrift 1 2013-01-31 0,00 130,15 Postbank:1 Afschrift 2 2013-02-28 0,00 25,50 Postbank:2 Afschrift 3 2013-03-31 3442,98 0,00 Postbank:3 Afschrift 4 2013-04-30 3544,50 0,00 Postbank:4 Afschrift 5 2013-05-31 472,28 0,00 Postbank:5 Afschrift 6 2013-06-30 683,50 0,00 Postbank:6 Afschrift 7 2013-07-31 0,00 130,16 Postbank:7 Afschrift 8 2013-08-31 1688,50 0,00 Postbank:8 Afschrift 9 2013-09-30 0,00 134,22 Postbank:9 Afschrift 10 2013-10-31 0,00 25,50 Postbank:10 Afschrift 11 2013-11-30 0,00 135,17 Postbank:11 Afschrift 12 2013-12-07 0,00 25,50 Postbank:12 Eerste deel ADSL 2013-12-09 0,00 10,00 Postbank:13 Tweede deel ADSL 2013-12-10 0,00 12,80 Postbank:14 Totaal mutaties 9202,76 2320 Totaal Postbank 10334,68 3100 Kapitaal de heer/mevrouw Beginsaldo 0,00 2443,18 Totaal mutaties 0,00 3100 Totaal Kapitaal de 2443,18 heer/mevrouw 4100 Crediteuren Beginsaldo 0,00 0,00 Internet 2013-01-05 0,00 22,80 Inkoop:1 ADSL + Telefoon 2013-01-15 0,00 104,65 Inkoop:2 *Internet 2013-01-19 22,80 0,00 Postbank:1 XS4ALL *ADSL + Telefoon 2013-01-31 104,65 0,00 Postbank:1 KPN Internet 2013-02-09 0,00 22,80 Inkoop:3 *Internet 2013-02-23 22,80 0,00 Postbank:2 XS4ALL Internet 2013-03-08 0,00 22,80 Inkoop:4 Telefoonkosten 2013-03-18 0,00 101,52 Inkoop:5 *Internet 2013-03-31 22,80 0,00 Postbank:3 XS4ALL *Telefoonkosten 2013-03-31 101,52 0,00 Postbank:3 KPN Internet 2013-04-05 0,00 22,80 Inkoop:6 *Internet 2013-04-06 22,80 0,00 Postbank:4 XS4ALL Internet 2013-05-10 0,00 22,80 Inkoop:7 Telefoonkosten 2013-05-20 0,00 102,22 Inkoop:8 *Internet 2013-05-31 22,80 0,00 Postbank:5 XS4ALL *Telefoonkosten 2013-05-31 102,22 0,00 Postbank:5 KPN Internet 2013-06-07 0,00 22,80 Inkoop:9 *Internet 2013-06-21 22,80 0,00 Postbank:6 XS4ALL Internet 2013-07-05 0,00 22,80 Inkoop:10 Telefoonkosten 2013-07-15 0,00 104,66 Inkoop:11 *Internet 2013-07-30 22,80 0,00 Postbank:7 XS4ALL *Telefoonkosten 2013-07-31 104,66 0,00 Postbank:7 KPN Internet 2013-08-09 0,00 22,80 Inkoop:12 *Internet 2013-08-10 22,80 0,00 Postbank:8 XS4ALL Internet 2013-09-06 0,00 22,80 Inkoop:13 Telefoonkosten 2013-09-16 0,00 108,72 Inkoop:14 *Internet 2013-09-30 22,80 0,00 Postbank:9 XS4ALL *Telefoonkosten 2013-09-30 108,72 0,00 Postbank:9 KPN Internet 2013-10-11 0,00 22,80 Inkoop:15 *Internet 2013-10-13 22,80 0,00 Postbank:10 XS4ALL Internet 2013-11-07 0,00 22,80 Inkoop:16 Telefoonkosten 2013-11-17 0,00 109,67 Inkoop:17 *Internet 2013-11-30 22,80 0,00 Postbank:11 XS4ALL *Telefoonkosten 2013-11-30 109,67 0,00 Postbank:11 KPN Internet 2013-12-06 0,00 22,80 Inkoop:18 Internet 2013-12-07 0,00 22,80 Inkoop:20 *Internet 2013-12-07 22,80 0,00 Postbank:12 XS4ALL *Internet 2013-12-09 10,00 0,00 Postbank:13 XS4ALL *Internet 2013-12-10 12,80 0,00 Postbank:14 XS4ALL Totaal mutaties 0,00 4100 Totaal Crediteuren 0,00 4200 BTW Verkoop Hoog Beginsaldo 0,00 0,00 BTW Perl Cursus 1e bet. 2013-02-18 0,00 619,59 Verkoop:1 BTW Perl Cursus 2e bet. 2013-03-18 0,00 619,59 Verkoop:2 BTW Perl Cursus rest 2013-04-18 0,00 104,13 Verkoop:3 BTW Perl Cursus rest 2013-05-12 0,87 0,00 Verkoop:4 BTW Consultancy 2013-05-14 0,00 123,92 Verkoop:5 BTW Consultancy 2013-07-16 0,00 123,92 Verkoop:6 Totaal mutaties 1590,28 4200 Totaal BTW Verkoop Hoog 1590,28 4220 BTW Inkoop Hoog Beginsaldo 0,00 0,00 BTW ADSL 2013-01-05 3,96 0,00 Inkoop:1 BTW ADSL 2013-01-15 4,20 0,00 Inkoop:2 BTW Telefoonkosten 2013-01-15 13,96 0,00 Inkoop:2 BTW ADSL 2013-02-09 3,96 0,00 Inkoop:3 BTW ADSL 2013-03-08 3,96 0,00 Inkoop:4 BTW ADSL + Telefoon 2013-03-18 17,62 0,00 Inkoop:5 BTW ADSL 2013-04-05 3,96 0,00 Inkoop:6 BTW ADSL 2013-05-10 3,96 0,00 Inkoop:7 BTW ADSL + Telefoon 2013-05-20 17,74 0,00 Inkoop:8 BTW ADSL 2013-06-07 3,96 0,00 Inkoop:9 BTW ADSL 2013-07-05 3,96 0,00 Inkoop:10 BTW ADSL + Telefoon 2013-07-15 18,16 0,00 Inkoop:11 BTW ADSL 2013-08-09 3,96 0,00 Inkoop:12 BTW ADSL 2013-09-06 3,96 0,00 Inkoop:13 BTW ADSL + Telefoon 2013-09-16 18,87 0,00 Inkoop:14 BTW ADSL 2013-10-11 3,96 0,00 Inkoop:15 BTW ADSL 2013-11-07 3,96 0,00 Inkoop:16 BTW ADSL + Telefoon 2013-11-17 19,03 0,00 Inkoop:17 BTW ÁDSL 2013-12-06 3,96 0,00 Inkoop:18 BTW ADSL 2013-12-07 3,96 0,00 Inkoop:20 Totaal mutaties 161,06 4220 Totaal BTW Inkoop Hoog 161,06 6800 Afschr. kosten inv. & inr. Beginsaldo 0,00 0,00 Afschrijving 2013-12-31 411,26 0,00 Memoriaal:1 Totaal mutaties 411,26 6800 Totaal Afschr. kosten inv. & 411,26 inr. 6810 Afschr. kosten computers Beginsaldo 0,00 0,00 Afschrijving 2013-12-31 396,82 0,00 Memoriaal:2 Totaal mutaties 396,82 6810 Totaal Afschr. kosten 396,82 computers 6900 Telefoon- en faxkosten Beginsaldo 0,00 0,00 Telefoonkosten 2013-01-15 66,49 0,00 Inkoop:2 ADSL + Telefoon 2013-03-18 83,90 0,00 Inkoop:5 ADSL + Telefoon 2013-05-20 84,48 0,00 Inkoop:8 ADSL + Telefoon 2013-07-15 86,50 0,00 Inkoop:11 ADSL + Telefoon 2013-09-16 89,85 0,00 Inkoop:14 ADSL + Telefoon 2013-11-17 90,64 0,00 Inkoop:17 Totaal mutaties 501,86 6900 Totaal Telefoon- en faxkosten 501,86 6905 Internetkosten Beginsaldo 0,00 0,00 ADSL 2013-01-05 18,84 0,00 Inkoop:1 ADSL 2013-01-15 20,00 0,00 Inkoop:2 ADSL 2013-02-09 18,84 0,00 Inkoop:3 ADSL 2013-03-08 18,84 0,00 Inkoop:4 ADSL 2013-04-05 18,84 0,00 Inkoop:6 ADSL 2013-05-10 18,84 0,00 Inkoop:7 ADSL 2013-06-07 18,84 0,00 Inkoop:9 ADSL 2013-07-05 18,84 0,00 Inkoop:10 ADSL 2013-08-09 18,84 0,00 Inkoop:12 ADSL 2013-09-06 18,84 0,00 Inkoop:13 ADSL 2013-10-11 18,84 0,00 Inkoop:15 ADSL 2013-11-07 18,84 0,00 Inkoop:16 ÁDSL 2013-12-06 18,84 0,00 Inkoop:18 ADSL 2013-12-07 18,84 0,00 Inkoop:20 Totaal mutaties 264,92 6905 Totaal Internetkosten 264,92 6980 Bankkosten Beginsaldo 0,00 0,00 Girotel 2013-01-06 2,70 0,00 Postbank:1 Girotel 2013-02-10 2,70 0,00 Postbank:2 Girotel 2013-03-09 2,70 0,00 Postbank:3 Girotel 2013-04-06 2,70 0,00 Postbank:4 Girotel 2013-05-11 2,70 0,00 Postbank:5 Girotel 2013-06-08 2,70 0,00 Postbank:6 Girotel 2013-07-06 2,70 0,00 Postbank:7 Girotel 2013-08-10 2,70 0,00 Postbank:8 Girotel 2013-09-17 2,70 0,00 Postbank:9 Girotel 2013-10-12 2,70 0,00 Postbank:10 Girotel 2013-11-08 2,70 0,00 Postbank:11 Girotel 2013-12-06 2,70 0,00 Postbank:12 Totaal mutaties 32,40 6980 Totaal Bankkosten 32,40 8100 Omzet advisering Beginsaldo 0,00 0,00 Consultancy 2013-05-14 0,00 590,08 Verkoop:5 Consultancy 2013-07-16 0,00 590,08 Verkoop:6 Totaal mutaties 1180,16 8100 Totaal Omzet advisering 1180,16 8300 Omzet editing Beginsaldo 0,00 0,00 Produktie boek 2013-08-19 0,00 1000,00 Verkoop:7 Totaal mutaties 1000,00 8300 Totaal Omzet editing 1000,00 8400 Omzet cursussen Beginsaldo 0,00 0,00 Perl Cursus 1e bet. 2013-02-18 0,00 2950,41 Verkoop:1 Perl Cursus 2e bet. 2013-03-18 0,00 2950,41 Verkoop:2 Perl Cursus rest 2013-04-18 0,00 495,87 Verkoop:3 Perl Cursus rest 2013-05-12 4,13 0,00 Verkoop:4 Totaal mutaties 6392,56 8400 Totaal Omzet cursussen 6392,56 Totaal mutaties 10971,08 10971,08 --------------------------------------------------------------------------------------------------- Totaal 26825,85 26825,85 EekBoek-2.030.1/t/ivp/ref/balans0.txt0000644000400000040000000000136013044346163014662 0ustar jvjv Balans Periode: t/m 2013-12-31 EekBoek Demo Administratie EekBoek, 2013-12-31 RekNr Verdichting/Grootboekrekening Debet Credit ---------------------------------------------------------------------- 1 Vaste Activa 503,18 2 Vlottende activa 10334,68 3 Eigen vermogen 2443,18 4 Vreemd vermogen 1429,22 << Winst >> 6965,46 ---------------------------------------------------------------------- TOTAAL Balans 10837,86 10837,86 EekBoek-2.030.1/t/ivp/ref/btwk2.txt0000644000400000040000000000223213044346163014372 0ustar jvjv BTW Aangifte Periode: 2e kwartaal 2013 EekBoek Demo Administratie EekBoek, 2013-12-31 ----------------------------------------------------------------- Binnenland 1. Door mij verrichte leveringen/diensten 1a Belast met hoog tarief 1081 227 1b Belast met laag tarief 0 0 1e Belast met 0% / verlegd 0 Buitenland 3. Door mij verrichte leveringen 3a Buiten de EU 0 3b Binnen de EU 0 4. Aan mij verrichte leveringen 4a Van buiten de EU 0 0 4b Verwervingen van goederen uit de EU 0 0 Berekening 5. Berekening totaal 5a Subtotaal 227 5b Voorbelasting 30 5c Subtotaal 197 5g Totaal te betalen 197 Totaal te betalen (onafgerond) 197,56 Afrondingsverschil 0,56 EekBoek-2.030.1/t/ivp/ref/balans1.txt0000644000400000040000000000213013044346163014657 0ustar jvjv Balans Periode: t/m 2013-12-31 EekBoek Demo Administratie EekBoek, 2013-12-31 RekNr Verdichting/Grootboekrekening Debet Credit ---------------------------------------------------------------------- 1 Vaste Activa 11 Materiële vaste activa 503,18 1 Totaal Vaste Activa 503,18 2 Vlottende activa 23 Liquide middelen 10334,68 2 Totaal Vlottende activa 10334,68 3 Eigen vermogen 31 Kapitaal 2443,18 3 Totaal Eigen vermogen 2443,18 4 Vreemd vermogen 42 Belastingen & soc. lasten 1429,22 4 Totaal Vreemd vermogen 1429,22 << Winst >> 6965,46 ---------------------------------------------------------------------- TOTAAL Balans 10837,86 10837,86 EekBoek-2.030.1/t/ivp/ref/proef2.txt0000644000400000040000000000761413044346163014547 0ustar jvjv Proef- en Saldibalans Periode: t/m 2013-12-31 EekBoek Demo Administratie EekBoek, 2013-12-31 RekNr Verdichting/Grootboekrekening Debet Credit Saldo Db Saldo Cr -------------------------------------------------------------------------------------------- 1 Vaste Activa 11 Materiële vaste activa 1100 Inventaris en inrichting 1344,37 0,00 1344,37 1101 Afschrijving inv. & inr. 0,00 1716,07 1716,07 1110 Computers 13378,48 0,00 13378,48 1111 Afschrijving computers 0,00 12503,60 12503,60 11 Totaal Materiële vaste activa 14722,85 14219,67 503,18 1 Totaal Vaste Activa 14722,85 14219,67 503,18 2 Vlottende activa 22 Vorderingen 2200 Debiteuren 10173,00 10173,00 22 Totaal Vorderingen 10173,00 10173,00 23 Liquide middelen 2320 Postbank 10963,68 629,00 10334,68 23 Totaal Liquide middelen 10963,68 629,00 10334,68 2 Totaal Vlottende activa 21136,68 10802,00 10334,68 3 Eigen vermogen 31 Kapitaal 3100 Kapitaal de heer/mevrouw 0,00 2443,18 2443,18 31 Totaal Kapitaal 2443,18 2443,18 3 Totaal Eigen vermogen 2443,18 2443,18 4 Vreemd vermogen 41 Leveranciers kredieten 4100 Crediteuren 927,84 927,84 41 Totaal Leveranciers kredieten 927,84 927,84 42 Belastingen & soc. lasten 4200 BTW Verkoop Hoog 0,87 1591,15 1590,28 4220 BTW Inkoop Hoog 161,06 0,00 161,06 42 Totaal Belastingen & soc. lasten 161,93 1591,15 1429,22 4 Totaal Vreemd vermogen 1089,77 2518,99 1429,22 6 Kosten 68 Afschrijvingen 6800 Afschr. kosten inv. & inr. 411,26 0,00 411,26 6810 Afschr. kosten computers 396,82 0,00 396,82 68 Totaal Afschrijvingen 808,08 808,08 69 Algemene kosten 6900 Telefoon- en faxkosten 501,86 0,00 501,86 6905 Internetkosten 264,92 0,00 264,92 6980 Bankkosten 32,40 0,00 32,40 69 Totaal Algemene kosten 799,18 799,18 6 Totaal Kosten 1607,26 1607,26 8 Bedrijfsopbrengsten 81 Omzet Consultancy 8100 Omzet advisering 0,00 1180,16 1180,16 81 Totaal Omzet Consultancy 1180,16 1180,16 83 Omzet Editing 8300 Omzet editing 0,00 1000,00 1000,00 83 Totaal Omzet Editing 1000,00 1000,00 84 Omzet Cursussen 8400 Omzet cursussen 4,13 6396,69 6392,56 84 Totaal Omzet Cursussen 4,13 6396,69 6392,56 8 Totaal Bedrijfsopbrengsten 4,13 8576,85 8572,72 -------------------------------------------------------------------------------------------- TOTAAL 38560,69 38560,69 12445,12 12445,12 EekBoek-2.030.1/t/ivp/ref/btw7.txt0000644000400000040000000000222313044346163014224 0ustar jvjv BTW Aangifte Periode: Juli 2013 EekBoek Demo Administratie EekBoek, 2013-12-31 ----------------------------------------------------------------- Binnenland 1. Door mij verrichte leveringen/diensten 1a Belast met hoog tarief 590 123 1b Belast met laag tarief 0 0 1e Belast met 0% / verlegd 0 Buitenland 3. Door mij verrichte leveringen 3a Buiten de EU 0 3b Binnen de EU 0 4. Aan mij verrichte leveringen 4a Van buiten de EU 0 0 4b Verwervingen van goederen uit de EU 0 0 Berekening 5. Berekening totaal 5a Subtotaal 123 5b Voorbelasting 23 5c Subtotaal 100 5g Totaal te betalen 100 Totaal te betalen (onafgerond) 101,80 Afrondingsverschil 1,80 EekBoek-2.030.1/t/ivp/ref/btw.txt0000644000400000040000000000232013044346163014133 0ustar jvjv BTW Aangifte Periode: 2013 EekBoek Demo Administratie EekBoek, 2013-12-31 ----------------------------------------------------------------- Binnenland 1. Door mij verrichte leveringen/diensten 1a Belast met hoog tarief 7572 1590 1b Belast met laag tarief 0 0 1e Belast met 0% / verlegd 0 Buitenland 3. Door mij verrichte leveringen 3a Buiten de EU 1000 3b Binnen de EU 0 4. Aan mij verrichte leveringen 4a Van buiten de EU 0 0 4b Verwervingen van goederen uit de EU 0 0 Berekening 5. Berekening totaal 5a Subtotaal 1590 5b Voorbelasting 162 5c Subtotaal 1428 5d Vermindering kleineondernemersregeling 1138 5g Totaal te betalen 290 Totaal te betalen (onafgerond) 1429,22 Afrondingsverschil 1,22 EekBoek-2.030.1/t/ivp/ref/crdrept.txt0000644000400000040000000001071513044346163015011 0ustar jvjv Crediteurenadministratie Periode: 2013-01-01 t/m 2013-12-31 EekBoek Demo Administratie EekBoek, 2013-12-31 Crediteur Datum Omschrijving Bedrag Open Betaald Boekstuk ------------------------------------------------------------------------------------------------------ KPN 2013-01-15 ADSL + Telefoon 104,65 0,00 Inkoop:2 2013-01-31 *ADSL + Telefoon 104,65 Postbank:1 2013-03-18 Telefoonkosten 101,52 0,00 Inkoop:5 2013-03-31 *Telefoonkosten 101,52 Postbank:3 2013-05-20 Telefoonkosten 102,22 0,00 Inkoop:8 2013-05-31 *Telefoonkosten 102,22 Postbank:5 2013-07-15 Telefoonkosten 104,66 0,00 Inkoop:11 2013-07-31 *Telefoonkosten 104,66 Postbank:7 2013-09-16 Telefoonkosten 108,72 0,00 Inkoop:14 2013-09-30 *Telefoonkosten 108,72 Postbank:9 2013-11-17 Telefoonkosten 109,67 0,00 Inkoop:17 2013-11-30 *Telefoonkosten 109,67 Postbank:11 --------- --------- KPN Totaal 631,44 0,00 XS4ALL 2013-01-05 Internet 22,80 0,00 Inkoop:1 2013-01-19 *Internet 22,80 Postbank:1 2013-02-09 Internet 22,80 0,00 Inkoop:3 2013-02-23 *Internet 22,80 Postbank:2 2013-03-08 Internet 22,80 0,00 Inkoop:4 2013-03-31 *Internet 22,80 Postbank:3 2013-04-05 Internet 22,80 0,00 Inkoop:6 2013-04-06 *Internet 22,80 Postbank:4 2013-05-10 Internet 22,80 0,00 Inkoop:7 2013-05-31 *Internet 22,80 Postbank:5 2013-06-07 Internet 22,80 0,00 Inkoop:9 2013-06-21 *Internet 22,80 Postbank:6 2013-07-05 Internet 22,80 0,00 Inkoop:10 2013-07-30 *Internet 22,80 Postbank:7 2013-08-09 Internet 22,80 0,00 Inkoop:12 2013-08-10 *Internet 22,80 Postbank:8 2013-09-06 Internet 22,80 0,00 Inkoop:13 2013-09-30 *Internet 22,80 Postbank:9 2013-10-11 Internet 22,80 0,00 Inkoop:15 2013-10-13 *Internet 22,80 Postbank:10 2013-11-07 Internet 22,80 0,00 Inkoop:16 2013-11-30 *Internet 22,80 Postbank:11 2013-12-06 Internet 22,80 0,00 Inkoop:18 2013-12-07 *Internet 22,80 Postbank:12 2013-12-07 Internet 22,80 0,00 Inkoop:20 2013-12-09 *Internet 10,00 Postbank:13 2013-12-10 *Internet 12,80 Postbank:14 --------- --------- XS4ALL Totaal 296,40 0,00 ------------------------------------------------------------------------------------------------------ Totaal 927,84 0,00 EekBoek-2.030.1/t/ivp/ref/grootboek2.txt0000644000400000040000000004006013044346163015417 0ustar jvjv Grootboek Periode: 2013-01-01 t/m 2013-12-31 EekBoek Demo Administratie EekBoek, 2013-12-31 GrBk Grootboek/Boekstuk Datum Debet Credit BoekstukNr Relatie --------------------------------------------------------------------------------------------------- 1100 Inventaris en inrichting Beginsaldo 1344,37 0,00 Totaal mutaties 0,00 1100 Totaal Inventaris en 1344,37 inrichting 1101 Afschrijving inv. & inr. Beginsaldo 0,00 1304,81 Afschrijving 2013-12-31 0,00 411,26 Memoriaal:1 Totaal mutaties 411,26 1101 Totaal Afschrijving inv. & 1716,07 inr. 1110 Computers Beginsaldo 13378,48 0,00 Totaal mutaties 0,00 1110 Totaal Computers 13378,48 1111 Afschrijving computers Beginsaldo 0,00 12106,78 Afschrijving 2013-12-31 0,00 396,82 Memoriaal:2 Totaal mutaties 396,82 1111 Totaal Afschrijving computers 12503,60 2200 Debiteuren Beginsaldo 0,00 0,00 Perl Cursus 2013-02-18 3570,00 0,00 Verkoop:1 Perl Cursus 2013-03-18 3570,00 0,00 Verkoop:2 *Perl Cursus 2013-03-18 0,00 3570,00 Postbank:3 ACME *Perl Cursus 2013-04-12 0,00 3570,00 Postbank:4 ACME Perl Cursus 2013-04-18 600,00 0,00 Verkoop:3 Perl Cursus 2013-05-12 0,00 5,00 Verkoop:4 Ondersteuning 2013-05-14 714,00 0,00 Verkoop:5 *Perl Cursus 2013-05-31 0,00 600,00 Postbank:5 ACME *Ondersteuning 2013-06-08 0,00 714,00 Postbank:6 ACME *Perl Cursus 2013-06-12 5,00 0,00 Postbank:6 ACME Ondersteuning 2013-07-16 714,00 0,00 Verkoop:6 *Ondersteuning 2013-08-10 0,00 714,00 Postbank:8 ACME Pocket Reference 2013-08-19 1000,00 0,00 Verkoop:7 *Pocket Reference 2013-08-19 0,00 1000,00 Postbank:8 ORA Totaal mutaties 0,00 2200 Totaal Debiteuren 0,00 2320 Postbank Beginsaldo 1131,92 0,00 Afschrift 1 2013-01-31 0,00 130,15 Postbank:1 Afschrift 2 2013-02-28 0,00 25,50 Postbank:2 Afschrift 3 2013-03-31 3442,98 0,00 Postbank:3 Afschrift 4 2013-04-30 3544,50 0,00 Postbank:4 Afschrift 5 2013-05-31 472,28 0,00 Postbank:5 Afschrift 6 2013-06-30 683,50 0,00 Postbank:6 Afschrift 7 2013-07-31 0,00 130,16 Postbank:7 Afschrift 8 2013-08-31 1688,50 0,00 Postbank:8 Afschrift 9 2013-09-30 0,00 134,22 Postbank:9 Afschrift 10 2013-10-31 0,00 25,50 Postbank:10 Afschrift 11 2013-11-30 0,00 135,17 Postbank:11 Afschrift 12 2013-12-07 0,00 25,50 Postbank:12 Eerste deel ADSL 2013-12-09 0,00 10,00 Postbank:13 Tweede deel ADSL 2013-12-10 0,00 12,80 Postbank:14 Totaal mutaties 9202,76 2320 Totaal Postbank 10334,68 3100 Kapitaal de heer/mevrouw Beginsaldo 0,00 2443,18 Totaal mutaties 0,00 3100 Totaal Kapitaal de 2443,18 heer/mevrouw 4100 Crediteuren Beginsaldo 0,00 0,00 Internet 2013-01-05 0,00 22,80 Inkoop:1 ADSL + Telefoon 2013-01-15 0,00 104,65 Inkoop:2 *Internet 2013-01-19 22,80 0,00 Postbank:1 XS4ALL *ADSL + Telefoon 2013-01-31 104,65 0,00 Postbank:1 KPN Internet 2013-02-09 0,00 22,80 Inkoop:3 *Internet 2013-02-23 22,80 0,00 Postbank:2 XS4ALL Internet 2013-03-08 0,00 22,80 Inkoop:4 Telefoonkosten 2013-03-18 0,00 101,52 Inkoop:5 *Internet 2013-03-31 22,80 0,00 Postbank:3 XS4ALL *Telefoonkosten 2013-03-31 101,52 0,00 Postbank:3 KPN Internet 2013-04-05 0,00 22,80 Inkoop:6 *Internet 2013-04-06 22,80 0,00 Postbank:4 XS4ALL Internet 2013-05-10 0,00 22,80 Inkoop:7 Telefoonkosten 2013-05-20 0,00 102,22 Inkoop:8 *Internet 2013-05-31 22,80 0,00 Postbank:5 XS4ALL *Telefoonkosten 2013-05-31 102,22 0,00 Postbank:5 KPN Internet 2013-06-07 0,00 22,80 Inkoop:9 *Internet 2013-06-21 22,80 0,00 Postbank:6 XS4ALL Internet 2013-07-05 0,00 22,80 Inkoop:10 Telefoonkosten 2013-07-15 0,00 104,66 Inkoop:11 *Internet 2013-07-30 22,80 0,00 Postbank:7 XS4ALL *Telefoonkosten 2013-07-31 104,66 0,00 Postbank:7 KPN Internet 2013-08-09 0,00 22,80 Inkoop:12 *Internet 2013-08-10 22,80 0,00 Postbank:8 XS4ALL Internet 2013-09-06 0,00 22,80 Inkoop:13 Telefoonkosten 2013-09-16 0,00 108,72 Inkoop:14 *Internet 2013-09-30 22,80 0,00 Postbank:9 XS4ALL *Telefoonkosten 2013-09-30 108,72 0,00 Postbank:9 KPN Internet 2013-10-11 0,00 22,80 Inkoop:15 *Internet 2013-10-13 22,80 0,00 Postbank:10 XS4ALL Internet 2013-11-07 0,00 22,80 Inkoop:16 Telefoonkosten 2013-11-17 0,00 109,67 Inkoop:17 *Internet 2013-11-30 22,80 0,00 Postbank:11 XS4ALL *Telefoonkosten 2013-11-30 109,67 0,00 Postbank:11 KPN Internet 2013-12-06 0,00 22,80 Inkoop:18 Internet 2013-12-07 0,00 22,80 Inkoop:20 *Internet 2013-12-07 22,80 0,00 Postbank:12 XS4ALL *Internet 2013-12-09 10,00 0,00 Postbank:13 XS4ALL *Internet 2013-12-10 12,80 0,00 Postbank:14 XS4ALL Totaal mutaties 0,00 4100 Totaal Crediteuren 0,00 4200 BTW Verkoop Hoog Beginsaldo 0,00 0,00 BTW Perl Cursus 1e bet. 2013-02-18 0,00 619,59 Verkoop:1 BTW Perl Cursus 2e bet. 2013-03-18 0,00 619,59 Verkoop:2 BTW Perl Cursus rest 2013-04-18 0,00 104,13 Verkoop:3 BTW Perl Cursus rest 2013-05-12 0,87 0,00 Verkoop:4 BTW Consultancy 2013-05-14 0,00 123,92 Verkoop:5 BTW Consultancy 2013-07-16 0,00 123,92 Verkoop:6 Totaal mutaties 1590,28 4200 Totaal BTW Verkoop Hoog 1590,28 4220 BTW Inkoop Hoog Beginsaldo 0,00 0,00 BTW ADSL 2013-01-05 3,96 0,00 Inkoop:1 BTW ADSL 2013-01-15 4,20 0,00 Inkoop:2 BTW Telefoonkosten 2013-01-15 13,96 0,00 Inkoop:2 BTW ADSL 2013-02-09 3,96 0,00 Inkoop:3 BTW ADSL 2013-03-08 3,96 0,00 Inkoop:4 BTW ADSL + Telefoon 2013-03-18 17,62 0,00 Inkoop:5 BTW ADSL 2013-04-05 3,96 0,00 Inkoop:6 BTW ADSL 2013-05-10 3,96 0,00 Inkoop:7 BTW ADSL + Telefoon 2013-05-20 17,74 0,00 Inkoop:8 BTW ADSL 2013-06-07 3,96 0,00 Inkoop:9 BTW ADSL 2013-07-05 3,96 0,00 Inkoop:10 BTW ADSL + Telefoon 2013-07-15 18,16 0,00 Inkoop:11 BTW ADSL 2013-08-09 3,96 0,00 Inkoop:12 BTW ADSL 2013-09-06 3,96 0,00 Inkoop:13 BTW ADSL + Telefoon 2013-09-16 18,87 0,00 Inkoop:14 BTW ADSL 2013-10-11 3,96 0,00 Inkoop:15 BTW ADSL 2013-11-07 3,96 0,00 Inkoop:16 BTW ADSL + Telefoon 2013-11-17 19,03 0,00 Inkoop:17 BTW ÁDSL 2013-12-06 3,96 0,00 Inkoop:18 BTW ADSL 2013-12-07 3,96 0,00 Inkoop:20 Totaal mutaties 161,06 4220 Totaal BTW Inkoop Hoog 161,06 6800 Afschr. kosten inv. & inr. Beginsaldo 0,00 0,00 Afschrijving 2013-12-31 411,26 0,00 Memoriaal:1 Totaal mutaties 411,26 6800 Totaal Afschr. kosten inv. & 411,26 inr. 6810 Afschr. kosten computers Beginsaldo 0,00 0,00 Afschrijving 2013-12-31 396,82 0,00 Memoriaal:2 Totaal mutaties 396,82 6810 Totaal Afschr. kosten 396,82 computers 6900 Telefoon- en faxkosten Beginsaldo 0,00 0,00 Telefoonkosten 2013-01-15 66,49 0,00 Inkoop:2 ADSL + Telefoon 2013-03-18 83,90 0,00 Inkoop:5 ADSL + Telefoon 2013-05-20 84,48 0,00 Inkoop:8 ADSL + Telefoon 2013-07-15 86,50 0,00 Inkoop:11 ADSL + Telefoon 2013-09-16 89,85 0,00 Inkoop:14 ADSL + Telefoon 2013-11-17 90,64 0,00 Inkoop:17 Totaal mutaties 501,86 6900 Totaal Telefoon- en faxkosten 501,86 6905 Internetkosten Beginsaldo 0,00 0,00 ADSL 2013-01-05 18,84 0,00 Inkoop:1 ADSL 2013-01-15 20,00 0,00 Inkoop:2 ADSL 2013-02-09 18,84 0,00 Inkoop:3 ADSL 2013-03-08 18,84 0,00 Inkoop:4 ADSL 2013-04-05 18,84 0,00 Inkoop:6 ADSL 2013-05-10 18,84 0,00 Inkoop:7 ADSL 2013-06-07 18,84 0,00 Inkoop:9 ADSL 2013-07-05 18,84 0,00 Inkoop:10 ADSL 2013-08-09 18,84 0,00 Inkoop:12 ADSL 2013-09-06 18,84 0,00 Inkoop:13 ADSL 2013-10-11 18,84 0,00 Inkoop:15 ADSL 2013-11-07 18,84 0,00 Inkoop:16 ÁDSL 2013-12-06 18,84 0,00 Inkoop:18 ADSL 2013-12-07 18,84 0,00 Inkoop:20 Totaal mutaties 264,92 6905 Totaal Internetkosten 264,92 6980 Bankkosten Beginsaldo 0,00 0,00 Girotel 2013-01-06 2,70 0,00 Postbank:1 Girotel 2013-02-10 2,70 0,00 Postbank:2 Girotel 2013-03-09 2,70 0,00 Postbank:3 Girotel 2013-04-06 2,70 0,00 Postbank:4 Girotel 2013-05-11 2,70 0,00 Postbank:5 Girotel 2013-06-08 2,70 0,00 Postbank:6 Girotel 2013-07-06 2,70 0,00 Postbank:7 Girotel 2013-08-10 2,70 0,00 Postbank:8 Girotel 2013-09-17 2,70 0,00 Postbank:9 Girotel 2013-10-12 2,70 0,00 Postbank:10 Girotel 2013-11-08 2,70 0,00 Postbank:11 Girotel 2013-12-06 2,70 0,00 Postbank:12 Totaal mutaties 32,40 6980 Totaal Bankkosten 32,40 8100 Omzet advisering Beginsaldo 0,00 0,00 Consultancy 2013-05-14 0,00 590,08 Verkoop:5 Consultancy 2013-07-16 0,00 590,08 Verkoop:6 Totaal mutaties 1180,16 8100 Totaal Omzet advisering 1180,16 8300 Omzet editing Beginsaldo 0,00 0,00 Produktie boek 2013-08-19 0,00 1000,00 Verkoop:7 Totaal mutaties 1000,00 8300 Totaal Omzet editing 1000,00 8400 Omzet cursussen Beginsaldo 0,00 0,00 Perl Cursus 1e bet. 2013-02-18 0,00 2950,41 Verkoop:1 Perl Cursus 2e bet. 2013-03-18 0,00 2950,41 Verkoop:2 Perl Cursus rest 2013-04-18 0,00 495,87 Verkoop:3 Perl Cursus rest 2013-05-12 4,13 0,00 Verkoop:4 Totaal mutaties 6392,56 8400 Totaal Omzet cursussen 6392,56 Totaal mutaties 10971,08 10971,08 --------------------------------------------------------------------------------------------------- Totaal 26825,85 26825,85 EekBoek-2.030.1/t/ivp/ref/balans2.csv0000644000400000040000000000163413044346163014644 0ustar jvjv"RekNr","Verdichting/Grootboekrekening","Debet","Credit" 1,"Vaste Activa",, 11,"Materiële vaste activa",, 1100,"Inventaris en inrichting","1344,37", 1101,"Afschrijving inv. & inr.",,"1716,07" 1110,"Computers","13378,48", 1111,"Afschrijving computers",,"12503,60" 11,"Totaal Materiële vaste activa","503,18", 1,"Totaal Vaste Activa","503,18", 2,"Vlottende activa",, 23,"Liquide middelen",, 2320,"Postbank","10334,68", 23,"Totaal Liquide middelen","10334,68", 2,"Totaal Vlottende activa","10334,68", 3,"Eigen vermogen",, 31,"Kapitaal",, 3100,"Kapitaal de heer/mevrouw",,"2443,18" 31,"Totaal Kapitaal",,"2443,18" 3,"Totaal Eigen vermogen",,"2443,18" 4,"Vreemd vermogen",, 42,"Belastingen & soc. lasten",, 4200,"BTW Verkoop Hoog",,"1590,28" 4220,"BTW Inkoop Hoog","161,06", 42,"Totaal Belastingen & soc. lasten",,"1429,22" 4,"Totaal Vreemd vermogen",,"1429,22" ,"<< Winst >>",,"6965,46" ,"TOTAAL Balans","10837,86","10837,86" EekBoek-2.030.1/t/ivp/ref/balans.html0000644000400000040000000000404612725476602014742 0ustar jvjv Balans

Balans

Periode: t/m 2007-12-31
EekBoek Demo Administratie

RekNr Grootboekrekening Debet Credit
1100 Inventaris en inrichting 1344,37  
1101 Afschrijving inv. & inr.   1716,07
1110 Computers 13378,48  
1111 Afschrijving computers   12503,60
2320 Postbank 10334,68  
3100 Kapitaal de heer/mevrouw   2443,18
4200 BTW Verkoop Hoog   1463,00
4220 BTW Inkoop Hoog 148,13  
  << Winst >>   7079,81
  TOTAAL Balans 25205,66 25205,66
EekBoek-2.030.1/t/ivp/ref/proef1.txt0000644000400000040000000000414513044346163014542 0ustar jvjv Proef- en Saldibalans Periode: t/m 2013-12-31 EekBoek Demo Administratie EekBoek, 2013-12-31 RekNr Verdichting/Grootboekrekening Debet Credit Saldo Db Saldo Cr -------------------------------------------------------------------------------------------- 1 Vaste Activa 11 Totaal Materiële vaste activa 14722,85 14219,67 503,18 1 Totaal Vaste Activa 14722,85 14219,67 503,18 2 Vlottende activa 22 Totaal Vorderingen 10173,00 10173,00 23 Totaal Liquide middelen 10963,68 629,00 10334,68 2 Totaal Vlottende activa 21136,68 10802,00 10334,68 3 Eigen vermogen 31 Totaal Kapitaal 2443,18 2443,18 3 Totaal Eigen vermogen 2443,18 2443,18 4 Vreemd vermogen 41 Totaal Leveranciers kredieten 927,84 927,84 42 Totaal Belastingen & soc. lasten 161,93 1591,15 1429,22 4 Totaal Vreemd vermogen 1089,77 2518,99 1429,22 6 Kosten 68 Totaal Afschrijvingen 808,08 808,08 69 Totaal Algemene kosten 799,18 799,18 6 Totaal Kosten 1607,26 1607,26 8 Bedrijfsopbrengsten 81 Totaal Omzet Consultancy 1180,16 1180,16 83 Totaal Omzet Editing 1000,00 1000,00 84 Totaal Omzet Cursussen 4,13 6396,69 6392,56 8 Totaal Bedrijfsopbrengsten 4,13 8576,85 8572,72 -------------------------------------------------------------------------------------------- TOTAAL 38560,69 38560,69 12445,12 12445,12 EekBoek-2.030.1/t/ivp/ref/grootboek0.txt0000644000400000040000000000353713044346163015425 0ustar jvjv Grootboek Periode: 2013-01-01 t/m 2013-12-31 EekBoek Demo Administratie EekBoek, 2013-12-31 GrBk Grootboek/Boekstuk Datum Debet Credit BoekstukNr Relatie --------------------------------------------------------------------------------------------------- 1100 Totaal Inventaris en 1344,37 inrichting 1101 Totaal Afschrijving inv. & 1716,07 inr. 1110 Totaal Computers 13378,48 1111 Totaal Afschrijving computers 12503,60 2200 Totaal Debiteuren 0,00 2320 Totaal Postbank 10334,68 3100 Totaal Kapitaal de 2443,18 heer/mevrouw 4100 Totaal Crediteuren 0,00 4200 Totaal BTW Verkoop Hoog 1590,28 4220 Totaal BTW Inkoop Hoog 161,06 6800 Totaal Afschr. kosten inv. & 411,26 inr. 6810 Totaal Afschr. kosten 396,82 computers 6900 Totaal Telefoon- en faxkosten 501,86 6905 Totaal Internetkosten 264,92 6980 Totaal Bankkosten 32,40 8100 Totaal Omzet advisering 1180,16 8300 Totaal Omzet editing 1000,00 8400 Totaal Omzet cursussen 6392,56 Totaal mutaties 10971,08 10971,08 --------------------------------------------------------------------------------------------------- Totaal 26825,85 26825,85 EekBoek-2.030.1/t/ivp/ref/grootboek_2.txt0000644000400000040000000000662313044346163015565 0ustar jvjv Grootboek Periode: 2013-01-01 t/m 2013-12-31 EekBoek Demo Administratie EekBoek, 2013-12-31 GrBk Grootboek/Boekstuk Datum Debet Credit BoekstukNr Relatie --------------------------------------------------------------------------------------------------- 2200 Debiteuren Beginsaldo 0,00 0,00 Perl Cursus 2013-02-18 3570,00 0,00 Verkoop:1 Perl Cursus 2013-03-18 3570,00 0,00 Verkoop:2 *Perl Cursus 2013-03-18 0,00 3570,00 Postbank:3 ACME *Perl Cursus 2013-04-12 0,00 3570,00 Postbank:4 ACME Perl Cursus 2013-04-18 600,00 0,00 Verkoop:3 Perl Cursus 2013-05-12 0,00 5,00 Verkoop:4 Ondersteuning 2013-05-14 714,00 0,00 Verkoop:5 *Perl Cursus 2013-05-31 0,00 600,00 Postbank:5 ACME *Ondersteuning 2013-06-08 0,00 714,00 Postbank:6 ACME *Perl Cursus 2013-06-12 5,00 0,00 Postbank:6 ACME Ondersteuning 2013-07-16 714,00 0,00 Verkoop:6 *Ondersteuning 2013-08-10 0,00 714,00 Postbank:8 ACME Pocket Reference 2013-08-19 1000,00 0,00 Verkoop:7 *Pocket Reference 2013-08-19 0,00 1000,00 Postbank:8 ORA Totaal mutaties 0,00 2200 Totaal Debiteuren 0,00 2320 Postbank Beginsaldo 1131,92 0,00 Afschrift 1 2013-01-31 0,00 130,15 Postbank:1 Afschrift 2 2013-02-28 0,00 25,50 Postbank:2 Afschrift 3 2013-03-31 3442,98 0,00 Postbank:3 Afschrift 4 2013-04-30 3544,50 0,00 Postbank:4 Afschrift 5 2013-05-31 472,28 0,00 Postbank:5 Afschrift 6 2013-06-30 683,50 0,00 Postbank:6 Afschrift 7 2013-07-31 0,00 130,16 Postbank:7 Afschrift 8 2013-08-31 1688,50 0,00 Postbank:8 Afschrift 9 2013-09-30 0,00 134,22 Postbank:9 Afschrift 10 2013-10-31 0,00 25,50 Postbank:10 Afschrift 11 2013-11-30 0,00 135,17 Postbank:11 Afschrift 12 2013-12-07 0,00 25,50 Postbank:12 Eerste deel ADSL 2013-12-09 0,00 10,00 Postbank:13 Tweede deel ADSL 2013-12-10 0,00 12,80 Postbank:14 Totaal mutaties 9202,76 2320 Totaal Postbank 10334,68 Totaal mutaties 9202,76 0,00 --------------------------------------------------------------------------------------------------- Totaal 10334,68 0,00 EekBoek-2.030.1/t/ivp/ref/obalans.txt0000644000400000040000000000145213044346163014763 0ustar jvjv Openingsbalans Datum: 2013-01-01 EekBoek Demo Administratie EekBoek, 2013-12-31 RekNr Grootboekrekening Debet Credit ---------------------------------------------------------------------- 1100 Inventaris en inrichting 1344,37 1101 Afschrijving inv. & inr. 1304,81 1110 Computers 13378,48 1111 Afschrijving computers 12106,78 2320 Postbank 1131,92 3100 Kapitaal de heer/mevrouw 2443,18 ---------------------------------------------------------------------- TOTAAL Balans 15854,77 15854,77 EekBoek-2.030.1/t/ivp/ref/result1.txt0000644000400000040000000000175213044346163014746 0ustar jvjv Verlies/Winst Periode: 2013-01-01 t/m 2013-12-31 EekBoek Demo Administratie EekBoek, 2013-12-31 RekNr Verdichting/Grootboekrekening Debet Credit ---------------------------------------------------------------------- 6 Kosten 68 Afschrijvingen 808,08 69 Algemene kosten 799,18 6 Totaal Kosten 1607,26 8 Bedrijfsopbrengsten 81 Omzet Consultancy 1180,16 83 Omzet Editing 1000,00 84 Omzet Cursussen 6392,56 8 Totaal Bedrijfsopbrengsten 8572,72 << Winst >> 6965,46 ---------------------------------------------------------------------- TOTAAL Resultaten 8572,72 8572,72 EekBoek-2.030.1/t/ivp/ref/export.xaf0000644000400000040000000017317613151742310014632 0ustar jvjv
CLAIR2.00.00 x 1 Squirrel Here There 1234AA 2013 2013-01-01 2013-12-31 EUR 2013-12-31 EekBoek 2.030.1
geen 1100 Inventaris en inrichting B 1100 1101 Afschrijving inv. & inr. B 1101 1110 Computers B 1110 1111 Afschrijving computers B 1111 1120 Wagenpark B 1120 1121 Afschrijving Wagenpark B 1121 2100 Voorraad B 2100 2200 Debiteuren B 2200 2300 Kas B 2300 2320 Postbank B 2320 2330 Postbank Inbedrijf B 2330 2390 Kruisposten B 2390 3100 Kapitaal de heer/mevrouw B 3100 3110 Privé stortingen B 3110 3120 Privé opnamen B 3120 4100 Crediteuren B 4100 4150 Nog te ontvangen fakturen B 4150 4200 BTW Verkoop Hoog B 4200 4210 BTW Verkoop Laag B 4210 4212 BTW Verkoop Privé B 4212 4220 BTW Inkoop Hoog B 4220 4230 BTW Inkoop Laag B 4230 4232 BTW Inkoop Privé B 4232 4240 BTW Autokostenvergoeding B 4240 4290 Omzetbelasting betaald B 4290 6100 Reis- en verblijfkosten P 6100 6110 Sponsoring P 6110 6200 Verzekeringen P 6200 6310 Kamer van Koophandel P 6310 6320 Vakbond P 6320 6330 Branche-organisatiekosten P 6330 6600 Leasekosten auto P 6600 6610 Brandstof auto P 6610 6620 Onderhoud auto P 6620 6630 Verzekering auto P 6630 6640 Kilometervergoedingen P 6640 6650 Huur auto P 6650 6660 Motorrijtuigenbelasting P 6660 6670 Boetes P 6670 6671 Boetes 0% aftrekbaar P 6671 6680 BTW privégebruik auto P 6680 6690 Overige autokosten P 6690 6700 Contributies & abonnementen P 6700 6710 Contr. & abonn. BTW 0% P 6710 6800 Afschr. kosten inv. & inr. P 6800 6810 Afschr. kosten computers P 6810 6820 Afschr. kosten wagenpark P 6820 6900 Telefoon- en faxkosten P 6900 6905 Internetkosten P 6905 6920 Kantoorartikelen P 6920 6921 Computerbenodigdheden P 6921 6930 Vakliteratuur P 6930 6940 Administratiekosten P 6940 6950 Drukwerk & papier P 6950 6970 Postzegels P 6970 6971 Verzending portikosten P 6971 6980 Bankkosten P 6980 6981 Kasverschillen P 6981 6982 Afrondingen P 6982 6990 Overige algemene kosten P 6990 8100 Omzet advisering P 8100 8110 Omzet advisering BTW vrij P 8110 8200 Omzet royalties BTW vrij P 8200 8300 Omzet editing P 8300 8400 Omzet cursussen P 8400 8410 Omzet cursuslicenties P 8410 8500 Omzet projekten P 8500 8900 Omzet diversen BTW hoog P 8900 8910 Omzet diversen BTW laag P 8910 8920 Omzet diversen BTW vrij P 8920 9120 Rente bate Postbank P 9120 9130 Rente bate Postbank Inbedrijf P 9130 9190 Rente bate overige P 9190 9220 Rente last Postbank P 9220 9230 Rente last Postbank Inbedrijf P 9230 9290 Rente last overige P 9290 9380 Bijtelling privégebruik auto P 9380 9390 Kleine ondernemersregeling P 9390 ACME Acme Corp.
onbekend
ONBEKEND 0000 XX Nederland
KPN KPN
onbekend
ONBEKEND 0000 XX Nederland
ORA O'Reilly & Associates
onbekend
ONBEKEND 0000 XX Nederland
XS4ALL XS4All Internet B.V.
onbekend
ONBEKEND 0000 XX Nederland
142 38560.69 38560.69 I Inkoop 1 1 01 2013-01-05 1 6905 XS4ALL 1 ADSL 18.84 2 4220 XS4ALL 1 BTW ADSL 3.96 3 4100 XS4ALL 1 Internet 22.80 2 01 2013-01-15 1 6905 KPN 2 ADSL 20.00 2 4220 KPN 2 BTW ADSL 4.20 3 6900 KPN 2 Telefoonkosten 66.49 4 4220 KPN 2 BTW Telefoonkosten 13.96 5 4100 KPN 2 ADSL + Telefoon 104.65 3 02 2013-02-09 1 6905 XS4ALL 3 ADSL 18.84 2 4220 XS4ALL 3 BTW ADSL 3.96 3 4100 XS4ALL 3 Internet 22.80 4 03 2013-03-08 1 6905 XS4ALL 4 ADSL 18.84 2 4220 XS4ALL 4 BTW ADSL 3.96 3 4100 XS4ALL 4 Internet 22.80 5 03 2013-03-18 1 6900 KPN 5 ADSL + Telefoon 83.90 2 4220 KPN 5 BTW ADSL + Telefoon 17.62 3 4100 KPN 5 Telefoonkosten 101.52 6 04 2013-04-05 1 6905 XS4ALL 6 ADSL 18.84 2 4220 XS4ALL 6 BTW ADSL 3.96 3 4100 XS4ALL 6 Internet 22.80 7 05 2013-05-10 1 6905 XS4ALL 7 ADSL 18.84 2 4220 XS4ALL 7 BTW ADSL 3.96 3 4100 XS4ALL 7 Internet 22.80 8 05 2013-05-20 1 6900 KPN 8 ADSL + Telefoon 84.48 2 4220 KPN 8 BTW ADSL + Telefoon 17.74 3 4100 KPN 8 Telefoonkosten 102.22 9 06 2013-06-07 1 6905 XS4ALL 9 ADSL 18.84 2 4220 XS4ALL 9 BTW ADSL 3.96 3 4100 XS4ALL 9 Internet 22.80 10 07 2013-07-05 1 6905 XS4ALL 10 ADSL 18.84 2 4220 XS4ALL 10 BTW ADSL 3.96 3 4100 XS4ALL 10 Internet 22.80 11 07 2013-07-15 1 6900 KPN 11 ADSL + Telefoon 86.50 2 4220 KPN 11 BTW ADSL + Telefoon 18.16 3 4100 KPN 11 Telefoonkosten 104.66 12 08 2013-08-09 1 6905 XS4ALL 12 ADSL 18.84 2 4220 XS4ALL 12 BTW ADSL 3.96 3 4100 XS4ALL 12 Internet 22.80 13 09 2013-09-06 1 6905 XS4ALL 13 ADSL 18.84 2 4220 XS4ALL 13 BTW ADSL 3.96 3 4100 XS4ALL 13 Internet 22.80 14 09 2013-09-16 1 6900 KPN 14 ADSL + Telefoon 89.85 2 4220 KPN 14 BTW ADSL + Telefoon 18.87 3 4100 KPN 14 Telefoonkosten 108.72 15 10 2013-10-11 1 6905 XS4ALL 15 ADSL 18.84 2 4220 XS4ALL 15 BTW ADSL 3.96 3 4100 XS4ALL 15 Internet 22.80 16 11 2013-11-07 1 6905 XS4ALL 16 ADSL 18.84 2 4220 XS4ALL 16 BTW ADSL 3.96 3 4100 XS4ALL 16 Internet 22.80 17 11 2013-11-17 1 6900 KPN 17 ADSL + Telefoon 90.64 2 4220 KPN 17 BTW ADSL + Telefoon 19.03 3 4100 KPN 17 Telefoonkosten 109.67 18 12 2013-12-06 1 6905 XS4ALL 18 ÁDSL 18.84 2 4220 XS4ALL 18 BTW ÁDSL 3.96 3 4100 XS4ALL 18 Internet 22.80 20 12 2013-12-07 1 6905 XS4ALL 20 ADSL 18.84 2 4220 XS4ALL 20 BTW ADSL 3.96 3 4100 XS4ALL 20 Internet 22.80 K Kas 4 M Memoriaal 5 0 0 2013-01-01 1 1100 0 opening 1344.37 2 1101 0 opening 1304.81 3 1110 0 opening 13378.48 4 1111 0 opening 12106.78 5 2320 0 opening 1131.92 6 3100 0 opening 2443.18 1 12 2013-12-31 1 6800 1 Afschrijving 411.26 2 1101 1 Afschrijving 411.26 2 12 2013-12-31 1 6810 2 Afschrijving 396.82 2 1111 2 Afschrijving 396.82 P Postbank 3 1 01 2013-01-31 1 6980 1 Girotel 2.70 2 4100 1 *Internet 22.80 3 4100 1 *ADSL + Telefoon 104.65 4 2320 1 Afschrift 1 130.15 2 02 2013-02-28 1 6980 2 Girotel 2.70 2 4100 2 *Internet 22.80 3 2320 2 Afschrift 2 25.50 3 03 2013-03-31 1 6980 3 Girotel 2.70 2 2200 3 *Perl Cursus 3570.00 3 4100 3 *Internet 22.80 4 4100 3 *Telefoonkosten 101.52 5 2320 3 Afschrift 3 3442.98 4 04 2013-04-30 1 6980 4 Girotel 2.70 2 4100 4 *Internet 22.80 3 2200 4 *Perl Cursus 3570.00 4 2320 4 Afschrift 4 3544.50 5 05 2013-05-31 1 6980 5 Girotel 2.70 2 4100 5 *Internet 22.80 3 2200 5 *Perl Cursus 600.00 4 4100 5 *Telefoonkosten 102.22 5 2320 5 Afschrift 5 472.28 6 06 2013-06-30 1 6980 6 Girotel 2.70 2 2200 6 *Ondersteuning 714.00 3 2200 6 *Perl Cursus 5.00 4 4100 6 *Internet 22.80 5 2320 6 Afschrift 6 683.50 7 07 2013-07-31 1 6980 7 Girotel 2.70 2 4100 7 *Internet 22.80 3 4100 7 *Telefoonkosten 104.66 4 2320 7 Afschrift 7 130.16 8 08 2013-08-31 1 6980 8 Girotel 2.70 2 2200 8 *Ondersteuning 714.00 3 4100 8 *Internet 22.80 4 2200 8 *Pocket Reference 1000.00 5 2320 8 Afschrift 8 1688.50 9 09 2013-09-30 1 6980 9 Girotel 2.70 2 4100 9 *Internet 22.80 3 4100 9 *Telefoonkosten 108.72 4 2320 9 Afschrift 9 134.22 10 10 2013-10-31 1 6980 10 Girotel 2.70 2 4100 10 *Internet 22.80 3 2320 10 Afschrift 10 25.50 11 11 2013-11-30 1 6980 11 Girotel 2.70 2 4100 11 *Internet 22.80 3 4100 11 *Telefoonkosten 109.67 4 2320 11 Afschrift 11 135.17 12 12 2013-12-07 1 6980 12 Girotel 2.70 2 4100 12 *Internet 22.80 3 2320 12 Afschrift 12 25.50 13 12 2013-12-09 1 4100 13 *Internet 10.00 2 2320 13 Eerste deel ADSL 10.00 14 12 2013-12-10 1 4100 14 *Internet 12.80 2 2320 14 Tweede deel ADSL 12.80 R Inbedrijf 3 V Verkoop 2 1 02 2013-02-18 1 8400 ACME 1 Perl Cursus 1e bet. 2950.41 2 4200 ACME 1 BTW Perl Cursus 1e bet. 619.59 3 2200 ACME 1 Perl Cursus 3570.00 2 03 2013-03-18 1 8400 ACME 2 Perl Cursus 2e bet. 2950.41 2 4200 ACME 2 BTW Perl Cursus 2e bet. 619.59 3 2200 ACME 2 Perl Cursus 3570.00 3 04 2013-04-18 1 8400 ACME 3 Perl Cursus rest 495.87 2 4200 ACME 3 BTW Perl Cursus rest 104.13 3 2200 ACME 3 Perl Cursus 600.00 4 05 2013-05-12 1 8400 ACME 4 Perl Cursus rest 4.13 2 4200 ACME 4 BTW Perl Cursus rest 0.87 3 2200 ACME 4 Perl Cursus 5.00 5 05 2013-05-14 1 8100 ACME 5 Consultancy 590.08 2 4200 ACME 5 BTW Consultancy 123.92 3 2200 ACME 5 Ondersteuning 714.00 6 07 2013-07-16 1 8100 ACME 6 Consultancy 590.08 2 4200 ACME 6 BTW Consultancy 123.92 3 2200 ACME 6 Ondersteuning 714.00 7 08 2013-08-19 1 8300 ORA 7 Produktie boek 1000.00 2 2200 ORA 7 Pocket Reference 1000.00
EekBoek-2.030.1/t/ivp/ref/journaal-postbank24.txt0000644000400000040000000000133713044346163017146 0ustar jvjv Journaal Periode: 2013-01-01 t/m 2013-12-31 EekBoek Demo Administratie EekBoek, 2013-12-31 Datum Boekstuk/Grootboek Rek Debet Credit BTW % Tarief Boekstuk/regel Relatie ------------------------------------------------------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------------------------------------------------------ Totaal Boekstuk Postbank:24 0,00 0,00 EekBoek-2.030.1/README0000644000400000040000000000324213151236120011633 0ustar jvjvEekboek Boekhoudpakket ====================== EekBoek is een boekhoudprogramma bedoeld voor het midden- en kleinbedrijf. EekBoek is niet zomaar een conventioneel boekhoudprogramma. EekBoek is ontstaan uit de gedachte die iedere wat meer technisch onderlegde bedrijfsvoerder wel eens heeft gehad: "Boekhouden, da's toch gewoon wat getalletjes organiseren? Dat moet toch gemakkelijk kunnen met wat slimme scriptjes." Velen hebben pogingen daartoe gedaan, maar de meesten faalden omdat het toch iets complexer bleek te zijn. De goedbedoelde 'slimme scriptjes' werden weer afgedankt, en men nam noodgedwongen een commercieel, meestal op Microsoft Windows gebaseerd boekhoudpakket. EekBoek is wel geslaagd in deze opzet. De 'slimme scriptjes' zijn weliswaar uitgegroeid tot een stevige applicatie, maar het geheel vertoont nog steeds alle kenmerken die zo belangrijk waren: eenvoudig in gebruik, command line gedreven, en een programmeerbare API. EekBoek slaat alle data op in een relationele database, wat het geheel robuust en betrouwbaar maakt. De structuur van de administratie en de boekingsopdrachten kunnen worden onderhouden in twee eenvoudige tekstbestanden. Voor de andersdenkenden is een grafische user interface in ontwikkeling die op dezelfde database werkt, Een export-faciliteit kan van alles wat met de GUI is uitgevoerd weer tekstbestandjes maken. Op deze wijze blijft het geheel overzichtelijk. Voor meer informatie: https://www.eekboek.nl/ . * Documentatie: https://www.eekboek.nl/docs/ * Wiki: https://wiki.eekboek.nl Voor het uitwisselen van ervaringen, vragen om ondersteuning en zo is er een mailing list: * https://lists.sourceforge.net/lists/listinfo/eekboek-users . EekBoek-2.030.1/README.gui0000644000400000040000000000013512725476602012435 0ustar jvjvwxWidgets (GUI) extensie voor EekBoek. Alle documentatie van EekBoek vindt u onder EekBoek. EekBoek-2.030.1/INSTALL0000644000400000040000000000113213151255733012013 0ustar jvjvInstallatie Eekboek Boekhoudpakket ================================== Als u dit leest dan heeft u met succes de EekBoek source kit gedownload en uitgepakt. Voor verschillende platforms bestaan kant-en-klare installatiekits. Ook wordt EekBoek standaard meegeleverd met een aantal linux distributies waaronder Fedora, Debian en Ubuntu. Voor Miscrosoft Windows is EekBoek beschikbaar via de ActiveState repository. Al deze informatie is echter al achterhaald nog voor u de source kit kon downloaden... Actuele informatie kunt u te allen tijde vinden op de EekBoek wiki: https://wiki.eekboek.nl/ EekBoek-2.030.1/emacs/0000755000400000040000000000000013151742350012051 5ustar jvjvEekBoek-2.030.1/emacs/eekboek-mode.el0000644000400000040000000000332212725476602014734 0ustar jvjv;;; eekboek-mode.el --- major mode for EekBoek data files ;; Copyright (C) 2007 by Johan Vromans ;; Author: Johan Vromans ;; Keywords: languages ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program; if not, write to the Free Software ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ;;; Commentary: ;; Major mode for editing EekBoek data files. Mainly text-mode, but ;; without filling and wrapping, and no tabs in the written data. ;; ;; To add to your Emacs, copy this file to your lisp library and add ;; the following lines to your .emacs: ;; ;; (setq auto-mode-alist ;; (append ;; '(("\\.eb$" . eekboek-mode) ;; ("\\.ebz$" . archive-mode)) ;; auto-mode-alist)) ;;; Code: (define-derived-mode eekboek-mode text-mode "EekBoek" "Major mode for EekBoek data files. \\{eekboek-mode-map}" (auto-fill-mode 0) (add-hook 'write-contents-hooks 'eekboek-detab) ) (define-key eekboek-mode-map "\t" 'tab-to-tab-stop) (defun eekboek-detab () "Untabify the whole buffer." (untabify (point-min) (point-max)) ;; Write hooks must return nil for the writing to continue. nil) ;;; eekboek-mode.el ends here EekBoek-2.030.1/emacs/eekboek-site-start.el0000644000400000040000000000067412725476601016115 0ustar jvjv;; Use eekboek-mode for .eb files. Treat .ebz files as (zip) archives. (autoload 'eekboek-mode "eekboek-mode" "Major mode for editing EekBoek data." t) (add-to-list 'auto-mode-alist '("\\.eb\\'" . eekboek-mode)) (add-to-list 'auto-mode-alist '("\\.ebz\\'" . archive-mode)) (if (boundp 'auto-coding-alist) ;; no such variable in xemacs21 (add-to-list 'auto-coding-alist '("\\.ebz\\'" . no-conversion))) ;;; eekboek-site-start.el ends here EekBoek-2.030.1/script/0000755000400000040000000000000013151742350012265 5ustar jvjvEekBoek-2.030.1/script/ebwxshell.pl0000755000400000040000000001143413044366443014633 0ustar jvjv#! perl # ebwxshell -- Main script for EekBoek GUI shell # Author : Johan Vromans # Created On : Fri Dec 18 21:54:24 2009 # Last Modified By: Johan Vromans # Last Modified On: Wed Feb 1 15:13:55 2017 # Update Count : 119 # Status : Unknown, Use with caution! use strict; use utf8; # use lib qw(EekBoekLibrary); package main; use strict; use warnings; use File::Spec; use File::Basename; use Wx qw[ wxDefaultPosition wxICON_ERROR wxICON_EXCLAMATION wxICON_INFORMATION wxOK ]; # If we get here, we have Wx :) use FindBin; our $bin = $FindBin::Bin; # Common case when run from unpacked dist. my $lib = File::Spec->catfile( dirname($bin), "lib" ); if ( -s File::Spec->catfile( $lib, "EekBoek.pm" ) ) { # Need abs paths since we're going to chdir later. unshift( @INC, File::Spec->rel2abs($lib) ); my $sep = $ENV{PATH} =~ m?;??q:;::q;:;;;; # just for fun $ENV{PATH} = File::Spec->rel2abs($lib) . $sep . $ENV{PATH}; } check_install( "EekBoek", "EekBoek.pm", "EB.pm", "EB/res/schema/eekboek.sql" ); require EekBoek; check_version( "EekBoek", $EekBoek::VERSION, "2.01.00" ); check_install( "De EekBoek WxShell", "EB/Wx/Shell/Main.pm", "EB/Wx/IniWiz.pm" ); # Some more version checking. Wx 0.74 is somewhat arbitrary. check_version( "Wx", $Wx::VERSION, "0.74" ); # Versions 0.95 and 0.96 have issues with wxHTML rendering. # Workaround courtesy of Mark Dootson. if ( ( $Wx::VERSION =~ /^0[.,]9[56]$/ ) && ( not exists($ENV{PAR_0}) ) && !$App::Packager::PACKAGED ) { no warnings; *Wx::load_dll = sub { use warnings; return if $^O =~ /^darwin/i; Wx::_load_dll( @_ ); }; } # We currently support wxWidgets 2.8 and 2.9. check_version( "wxWidgets", $Wx::wxVERSION, "2.008" ); require EB::Wx::Shell::Main; EB::Wx::Shell::Main->run; ################ Subroutines ################ sub findfile { my ( $file ) = @_; return if $App::Packager::PACKAGED; foreach ( @INC ) { my $f = File::Spec->catfile( $_, $file ); return $f if -s $f; } return; } sub check_install { # Trust packager. return 1 if $App::Packager::PACKAGED; my ( $what, @checks ) = @_; foreach ( @checks ) { next if findfile( $_ ); error( <new ( undef, $msg, $caption, $style, wxDefaultPosition ); $d->ShowModal; $d->Destroy; } sub info { push( @_, wxICON_INFORMATION ); goto &_msg; } sub error { push( @_, wxICON_ERROR ); &_msg; exit(1); } sub warning { push( @_, wxICON_EXCLAMATION ); goto &_msg; } 1; =head1 NAME EekBoek - Bookkeeping software for small and medium-size businesses =head1 SYNOPSIS The graphical EekBoek shell: ebwxshell The standalone documentation browser: ebwxshell --showhelp EekBoek is a bookkeeping package for small and medium-size businesses. Unlike other accounting software, EekBoek has both a command-line interface (CLI) and a graphical user-interface (GUI). Furthermore, it has a complete Perl API to create your own custom applications. EekBoek is designed for the Dutch/European market and currently available in Dutch only. An English translation is in the works (help appreciated). =head1 DESCRIPTION For a description how to use the program, see L. =head1 BUGS AND PROBLEMS Please use the eekboek-users mailing list at SourceForge. =head1 AUTHOR AND CREDITS Johan Vromans (jvromans@squirrel.nl) wrote this package. Web site: L. =head1 COPYRIGHT AND DISCLAIMER This program is Copyright 2005-2017 by Squirrel Consultancy. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of either: a) the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version, or b) the "Artistic License" which comes with Perl. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See either the GNU General Public License or the Artistic License for more details. =cut EekBoek-2.030.1/script/ebshell.pl0000755000400000040000000000715413151302402014240 0ustar jvjv#! perl # ebshell -- Main script for EekBoek CLI shell # Author : Johan Vromans # Created On : Thu Jul 14 12:54:08 2005 # Last Modified By: Johan Vromans # Last Modified On: Thu Jan 26 20:18:24 2017 # Update Count : 120 # Status : Unknown, Use with caution! package main; use strict; use warnings; use utf8; # use lib qw(EekBoekLibrary); use File::Spec; use File::Basename; use Encode; binmode( STDERR, ':encoding(utf-8)' ); use FindBin; our $bin = $FindBin::Bin; # Common case when run from unpacked dist. my $lib = File::Spec->catfile( dirname($bin), "lib" ); if ( -s File::Spec->catfile( $lib, "EekBoek.pm" ) ) { # Need abs paths since we're going to chdir later. unshift( @INC, File::Spec->rel2abs($lib) ); my $sep = $ENV{PATH} =~ m?;??q:;::q;:;;;; # just for fun $ENV{PATH} = File::Spec->rel2abs($lib) . $sep . $ENV{PATH}; } check_install( "EekBoek", "EekBoek.pm", "EB.pm", "EB/res/schema/eekboek.sql" ); require EekBoek; check_version( "EekBoek", $EekBoek::VERSION, "2.01.00" ); require EB::Main; exit EB::Main->run; ################ Subroutines ################ sub findfile { my ( $file ) = @_; return if $App::Packager::PACKAGED; foreach ( @INC ) { my $f = File::Spec->catfile( $_, $file ); return $f if -s $f; } return; } sub check_install { # Trust packager. return 1 if $App::Packager::PACKAGED; my ( $what, @checks ) = @_; foreach ( @checks ) { next if findfile( $_ ); error( <. =head1 BUGS AND PROBLEMS Please use the eekboek-users mailing list at SourceForge. =head1 AUTHOR AND CREDITS Johan Vromans (jvromans@squirrel.nl) wrote this package. Web site: L. =head1 COPYRIGHT AND DISCLAIMER This program is Copyright 2005-2010 by Squirrel Consultancy. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of either: a) the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version, or b) the "Artistic License" which comes with Perl. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See either the GNU General Public License or the Artistic License for more details. =cut EekBoek-2.030.1/script/ebpp.PL0000644000400000040000000000017113151270266013451 0ustar jvjv#! perl my $src = shift; open( my $fd, ">", $src); open( my $fi, "<", "$src.pl" ); print { $fd } ( <$fi> ); close($fd); EekBoek-2.030.1/contrib/0000755000400000040000000000000013151742350012421 5ustar jvjvEekBoek-2.030.1/contrib/afschrijvingen/0000755000400000040000000000000013151742350015421 5ustar jvjvEekBoek-2.030.1/contrib/afschrijvingen/afschr.pl0000644000400000040000000002410611654007441017230 0ustar jvjv#!/usr/bin/perl my $RCS_Id = '$Id: skel.pl,v 1.7 1998-02-06 11:41:12+01 jv Exp $ '; # Author : Johan Vromans # Created On : Tue Sep 15 15:59:04 1998 # Last Modified By: Johan Vromans # Last Modified On: Sat May 10 19:03:19 2008 # Update Count : 215 # Status : Unknown, Use with caution! ################ Common stuff ################ use strict; use warnings; use locale; # Package name. my $my_package = 'EekBoek'; # Program name and version. my ($my_name, $my_version) = $RCS_Id =~ /: (.+).pl,v ([\d.]+)/; $my_name = 'Afschrijvingen'; # Tack '*' if it is not checked in into RCS. $my_version .= '*' if length('$Locker: $ ') > 12; ################ Command line parameters ################ use Getopt::Long 2.13; sub app_options(); my $eb; # EekBoek boekingen my $gr; # only group totals my $oy; # order by year my $html; # produce HTML my $adm; # admin name app_options(); ################ The Process ################ $^L = "\n"; use Time::Local; sub min { $_[0] < $_[1] ? $_[1] : $_[0] } my @data; my @grdata; my %grdesc; my $ythis = 1900 + (localtime())[6]; while ( <> ) { # Skip comments and empty lines. next if /^#/; next unless /\S/; # Detect group identifiers if (/^(\d+)\s+(\d+)\s*=\s*(\S.*?)\s*$/) { $grdesc{"${1}:${2}"} = $3; next; } # Split up. my ( $date, $amt, $rest, $n, @desc ) = split; # Check for account numbers. my ($bal, $res); ($bal, $res) = splice(@desc, 0, 2) if @desc > 2 && $desc[0] =~ /^\d+$/ && $desc[1] =~ /^\d+$/; my $desc = "@desc"; my @aux = ($desc, $date, $amt, $rest, $n, $bal, $res); my ( $year, $month, $day ); if ( $date =~ /^(\d\d\d\d)-?(\d\d)-?(\d\d)$/ ) { ( $year, $month, $day ) = ( $1, $2, $3); } elsif ( $date =~ /^(\d\d\d\d)$/ ) { ( $year, $month, $day ) = ( $1, 1, 1 ); } # Beginwaarde. my $val = $amt; # Tijdstip van aanschaf. my $t1 = timelocal (0, 0, 0, $day, $month-1, $year); # Zolang er meer is dan de restwaarde. while ( $val > $rest ) { # Eind van het boekjaar. my $t2 = timelocal (0, 0, 0, 1, 0, $year+1); # Tijdspanne. my $d1 = $t2 - $t1; # Gedeelte in dit jaar. my $d2 = $t2 - timelocal (0, 0, 0, 1, 0, $year); # Afschrijving, my $decr = ($amt - $rest) / $n * $d1 / $d2; $decr = $val-$rest if $val -$decr < $rest; # Waardevermindering. $val -= $decr; # Sla op. push (@data, [$year, $decr, min($rest,$val), @aux]); push_group (\@grdata, \%grdesc, [$year, $decr, min($rest,$val), @aux]); # Naar volgend jaar. $year++; $t1 = $t2; } } my ($year, $af, $v, $desc, $date, $amt, $rest, $n, $bal, $res); if ( $gr ) { @data = @grdata; $~ = 'GROUP'; $^ = 'GROUP_TOP'; } if ( !defined($eb) || !$eb ) { my $this = ""; if ( defined($oy) ) { do_template(join("", )) if $html; foreach ( sort { $a->[0] <=> $b->[0] or $a->[3] cmp $b->[3] } @data ) { ($year, $af, $v, $desc, $date, $amt, $rest, $n, $bal, $res) = @$_; if ( $this ne $year ) { $this = $year; $- = 0; } next if $oy && $year != $oy; do_write(); } if ( $html ) { do_template(< EOD } } } if ( !defined($eb) || $eb ) { my $fmt = " std 31-12 %-34s %9.2f %4d"; foreach ( sort {$a->[0] <=> $b->[0] or $a->[3] cmp $b->[3] } @data ) { my ($year, $af, $v, $desc, $date, $amt, $rest, $n, $bal, $res) = @$_; next unless defined($bal) && defined($res); $desc = "\"Afschrijving $desc\""; printf STDOUT ("# Afschrijving %4d %s, balanswaarde = %.2f -> %.2f\n". "memoriaal 31-12 %s \\\n". "$fmt \\\n". "$fmt\n\n", $year, $_->[3], $v+$af, $v, $desc, $desc, $af, $bal, $desc, -$af, $res); } } ################ Subroutines ################ sub app_ident; sub app_usage($); sub app_options() { my $help = 0; # handled locally my $ident = 0; # handled locally # Process options, if any. # Make sure defaults are set before returning! return unless @ARGV > 0; if ( !GetOptions( 'adm=s' => \$adm, 'eb|eekboek!' => \$eb, 'groups' => \$gr, 'oy|order-year:i' => \$oy, 'html' => \$html, 'ident' => \$ident, 'help|?' => \$help, ) or $help ) { app_usage(2); } app_ident if $ident; $oy = 0 if defined($oy) && $oy <= 1900; if ( $html ) { die("--html requires --oy=YYYY\n") if $oy <= 1900; die("--html requires --adm=XXX\n") unless $adm; die("--html cannot (yet) be used with --groups\n") if $gr; $eb = 0; } } sub app_ident { print STDERR ("This is $my_package [$my_name $my_version]\n"); } sub app_usage($) { my ($exit) = @_; app_ident; print STDERR </>/g; $t =~ s/ "Afschrijfstaat", bky => $oy, adm => html($adm), ); my $pat = "("; foreach ( grep { ! /^_/ } keys(%ctrl) ) { $pat .= quotemeta($_) . "|"; } chop($pat); $pat .= ")"; $pat = qr/\[\%\s+$pat\s+\%\]/; $t =~ s/$pat/$ctrl{$1}/ge; print($t); } sub do_write { if ( $date =~ /(\d\d\d\d)-?(\d\d)-?(\d\d)/ ) { $date = "$3-$2-$1"; } else { $date = $html ? "Boekwaarde $date" : "Boekw $date"; } if ( !$html ) { write; return; } print < @{[html($desc)]} $date @{[numfmt($amt)]} $n @{[numfmt($rest)]} @{[numfmt($v+$af)]} @{[numfmt($af)]} @{[numfmt($v)]} EOD } sub push_group { my ($grdata, $grdesc, $elem) = @_; my ($year, $af, $v, $desc, $date, $amt, $rest, $n, $bal, $res) = @$elem; foreach (@$grdata) { if ($$_[0] == $year and $$_[8] == $bal and $$_[9] == $res) { $$_[1] += $af; $$_[2] += $v; return; } } my $d = $$grdesc{"${bal}:${res}"}; $$elem[3] = $d ? $d : "Group-${bal}-${res}"; push(@$grdata, $elem); } format STDOUT_TOP = @>>> @<<<<<<<<<<<<<<<<<<< @<<<<<<<<< @>>>>>>> @> @>>>>>>> @>>>>>>> @>>>>>>> @>>>>>>> "Jaar", "Omchrijving", "Aanschaf", "Waarde", "N", "Rest", "Begin", "Afschr.", "Eind" ---- -------------------- ---------- -------- -- -------- -------- -------- -------- . format STDOUT = @>>> @<<<<<<<<<<<<<<<<<<< @<<<<<<<<< @>>>>>>> @> @>>>>>>> @>>>>>>> @>>>>>>> @>>>>>>> $year, $desc, $date, sprintf("%.2f",$amt), $n, sprintf("%.2f",$rest), sprintf("%.2f",$v+$af), sprintf("%.2f",$af), sprintf("%.2f",$v) . format GROUP_TOP = @>>> @<<<<<<<<<<<<<<<<<<< @>>>>>>> @>>>>>>> @>>>>>>> "Jaar", "Omchrijving", "Begin", "Afschr.", "Eind" ---- -------------------- -------- -------- -------- . format GROUP = @>>> @<<<<<<<<<<<<<<<<<<< @>>>>>>> @>>>>>>> @>>>>>>> $year, $desc, sprintf("%.2f",$v+$af), sprintf("%.2f",$af), sprintf("%.2f",$v) . __END__ [% title %]

[% title %]

Periode: [% bky %]-01-01 t/m [% bky %]-12-31
[% adm %]

EekBoek-2.030.1/contrib/afschrijvingen/afschr-group.dat0000644000400000040000000000053711654007441020521 0ustar jvjv1100 6100 = Computers 1200 6200 = Auto's # Aanschaf Bedrag Restw #jr Bal Res Omschrijving 2006-07-01 2500.00 0 5 1100 6100 Computer A 2007-07-01 1000.00 0 5 1100 6100 Computer B 2007-01-01 28500.00 3500 5 1200 6200 Auto A 2007-07-01 5000.00 0 4 1200 6200 Auto B EekBoek-2.030.1/contrib/afschrijvingen/afschr-gewoon.dat0000644000400000040000000000025511654007441020660 0ustar jvjv# Aanschaf Bedrag Restw #jr Bal Res Omschrijving 2007-02-12 1225.00 0 5 1111 6810 Computer V 2007-10-06 27285.93 3500 5 1121 6820 Auto 53-XD-SR EekBoek-2.030.1/contrib/API/0000755000400000040000000000000013151742350013032 5ustar jvjvEekBoek-2.030.1/contrib/API/example1.pl0000644000400000040000000000316113044346163015107 0ustar jvjv#!/usr/bin/perl -w # Example of an EekBoek application. # Author : Johan Vromans # Created On : Sun Apr 13 17:25:07 2008 # Last Modified By: Johan Vromans # Last Modified On: Wed Jan 23 13:31:52 2013 # Update Count : 97 # Status : Unknown, Use with caution! ################ Common stuff ################ use strict; use warnings; # EekBoek modules. use EekBoek; # optional (but we'll use $PACKAGE) use EB; # common ################ Presets ################ binmode( STDOUT, ':encoding(utf-8)' ); ################ The Process ################ #### W A R N I N G #### W A R N I N G #### W A R N I N G ##### # # Querying the database may give unexpected results except for # trivial things like names of customers, grootboekrekeningen. # ################ ################ ################ ########### # Initialise. # The app name passed will be used for the config files, # e.g., Foo -> /etc/foo.conf, ~/.foo/foo.conf, ./.foo.conf # By using $EekBoek::PACKAGE we'll use the standard EekBoek # config files. my $eb = EB->app_init( { app => $EekBoek::PACKAGE, config => "eekboek.conf", # local } ); # Connect to the data base. # Returns the database handle. # NOTE: This is not a DBI object! my $dbh = $eb->connect_db; # SQL query. my $sql = "SELECT acc_id, acc_desc, acc_balres". " FROM Accounts". " ORDER BY acc_id"; # Parse SQL and execute. my $sth = $dbh->sql_exec($sql); # Bind result columns. $sth->bind_columns(\my($acc_id, $acc_desc, $acc_balans)); # Fetch results. while ( $sth->fetch ) { # Print balansrekeningen. printf("%5d %s\n", $acc_id, $acc_desc) if $acc_balans; } EekBoek-2.030.1/contrib/API/example2.pl0000644000400000040000000000211011654007441015077 0ustar jvjv#!/usr/bin/perl -w # Example of an EekBoek application. # Author : Johan Vromans # Created On : Sun Apr 13 17:25:07 2008 # Last Modified By: Johan Vromans # Last Modified On: Wed Mar 9 22:03:05 2011 # Update Count : 96 # Status : Unknown, Use with caution! ################ Common stuff ################ use strict; use warnings; # EekBoek modules. use EekBoek; # optional (but we'll use PACKAGE) use EB; # common ################ Presets ################ binmode( STDOUT, ':encoding(utf-8)' ); ################ The Process ################ # Initialise. # The app name passed will be used for the config files, # e.g., Foo -> /etc/foo.conf, ~/.foo/foo.conf, ./.foo.conf # By using $EekBoek::PACKAGE we'll use the standard EekBoek # config files. my $eb = EB->app_init( { app => $EekBoek::PACKAGE, config => "eekboek.conf", # local } ); # Connect to the data base. $eb->connect_db; # Generate some reports. use EB::Report::Balres; my $opts = { verdicht => 1 }; EB::Report::Balres->new->balans($opts); EB::Report::Balres->new->result($opts); EekBoek-2.030.1/contrib/API/example4.pl0000644000400000040000000000220311654007441015104 0ustar jvjv#!/usr/bin/perl -w # Example of an EekBoek application. # Author : Johan Vromans # Created On : Sun Apr 13 17:25:07 2008 # Last Modified By: Johan Vromans # Last Modified On: Wed Mar 9 22:22:07 2011 # Update Count : 108 # Status : Unknown, Use with caution! ################ Common stuff ################ use strict; use warnings; # EekBoek modules. use EekBoek; # optional (but we'll use PACKAGE) use EB; # common use EB::Globals; # globals ################ Presets ################ binmode( STDOUT, ':encoding(utf-8)' ); ################ The Process ################ # Initialise. # The app name passed will be used for the config files, # e.g., Foo -> /etc/foo.conf, ~/.foo/foo.conf, ./.foo.conf # By using $EekBoek::PACKAGE we'll use the standard EekBoek # config files. my $eb = EB->app_init( { app => $EekBoek::PACKAGE, config => "eekboek.conf", # local } ); # Connect to the data base. $eb->connect_db; # Perform a booking. require EB::Shell; my $bsk = EB::Shell->new->do_inkoop( "09-02", "Internet", "XS4ALL", "ADSL", "22,80" ); print("Geboekt: $bsk\n"); EekBoek-2.030.1/contrib/API/example3.pl0000644000400000040000000000252411654007441015111 0ustar jvjv#!/usr/bin/perl -w # Example of an EekBoek application. # Author : Johan Vromans # Created On : Sun Apr 13 17:25:07 2008 # Last Modified By: Johan Vromans # Last Modified On: Wed Mar 9 22:19:58 2011 # Update Count : 106 # Status : Unknown, Use with caution! ################ Common stuff ################ use strict; use warnings; # EekBoek modules. use EekBoek; # optional (but we'll use PACKAGE) use EB; # common use EB::Globals; # globals ################ Presets ################ binmode( STDOUT, ':encoding(utf-8)' ); ################ The Process ################ # Initialise. # The app name passed will be used for the config files, # e.g., Foo -> /etc/foo.conf, ~/.foo/foo.conf, ./.foo.conf # By using $EekBoek::PACKAGE we'll use the standard EekBoek # config files. my $eb = EB->app_init( { app => $EekBoek::PACKAGE, config => "eekboek.conf", # local } ); # Connect to the data base. $eb->connect_db; # Perform a booking. require EB::Booking::IV; my $opts = { dagboek => "I", dagboek_type => DBKTYPE_INKOOP, journal => 1, }; my $args = [ "09-02", # date "Internet", # booking description "XS4ALL", # relation "ADLS", # booking details "22,80", # amount ]; my $bsk = EB::Booking::IV->new->perform($args, $opts); print("Geboekt: $bsk\n"); EekBoek-2.030.1/ebwxshell.desktop0000644000400000040000000000053612725476602014367 0ustar jvjv[Desktop Entry] Version=1.0 Type=Application Exec=ebwxshell Icon=ebicon StartupNotify=true Terminal=false Categories=Office;Finance; Name=EekBoek Comment=Bookkeeping program for small to medium sized companies GenericName=Bookkeeping Name[nl]=EekBoek Comment[nl]=Eigenzinnig boekhouden voor kleine en middelgrote bedrijven GenericName[nl]=Boekhouden
  Aanschaf Afschrijving Periode
Omschrijving Datum Waarde Jr Restant Begin Afschr. Eind