Merge branch 'f-bundled-perl-modules'
authorMoritz Bunkus <m.bunkus@linet-services.de>
Fri, 5 Apr 2019 09:21:33 +0000 (11:21 +0200)
committerMoritz Bunkus <m.bunkus@linet-services.de>
Fri, 5 Apr 2019 09:21:33 +0000 (11:21 +0200)
83 files changed:
Devel/REPL/Plugin/AutoloadModules.pm [new file with mode: 0644]
Devel/REPL/Plugin/PermanentHistory.pm [new file with mode: 0644]
SL/Auth/SessionValue.pm
SL/BackgroundJob/CsvImport.pm
SL/BackgroundJob/SelfTest/Transactions.pm
SL/Controller/Draft.pm
SL/Controller/Order.pm
SL/DB.pm
SL/DB/BackgroundJob.pm
SL/DB/Helper/ActsAsList.pm
SL/DB/Helper/Cache.pm [new file with mode: 0644]
SL/DB/Helper/Metadata.pm
SL/DB/Object/Hooks.pm
SL/DO.pm
SL/Form.pm
SL/IC.pm
SL/InstallationCheck.pm
SL/LXDebug.pm
SL/Menu.pm
SL/MoreCommon.pm
SL/OE.pm
SL/X.pm
SL/X/Base.pm [new file with mode: 0644]
SL/YAML.pm [new file with mode: 0644]
bin/mozilla/acctranscorrections.pl
bin/mozilla/do.pl
bin/mozilla/oe.pl
dispatcher.pl
doc/dokumentation.xml
doc/html/ch02s02.html
doc/html/ch02s06.html
doc/html/ch02s07.html
doc/html/ch02s13.html
doc/html/ch03s03.html
doc/html/ch03s07.html
doc/html/ch03s08.html
doc/html/ch03s09.html
doc/html/ch04.html
doc/html/index.html
doc/kivitendo-Dokumentation.pdf
doc/modules/LICENSE.CGI-Ajax [deleted file]
doc/modules/LICENSE.Email-Address [deleted file]
doc/modules/LICENSE.List-MoreUtils [deleted file]
doc/modules/LICENSE.List-UtilsBy [deleted file]
doc/modules/README.CGI-Ajax [deleted file]
doc/modules/README.File-Slurp [deleted file]
doc/modules/README.List-UtilsBy [deleted file]
doc/modules/README.PDF-Table
doc/modules/README.Sort-Naturally [deleted file]
doc/modules/README.YAML [deleted file]
modules/fallback/DateTime/Event/Cron.pm [deleted file]
modules/fallback/Exception/Lite.pm [deleted file]
modules/fallback/Exception/Lite.pod [deleted file]
modules/fallback/Set/Crontab.pm [deleted file]
modules/fallback/Sort/Naturally.pm [deleted file]
modules/override/Devel/REPL/Plugin/AutoloadModules.pm [deleted file]
modules/override/Devel/REPL/Plugin/PermanentHistory.pm [deleted file]
modules/override/PDF/Table.pm [changed mode: 0644->0755]
modules/override/Rose/DBx/Cache/Anywhere.pm [deleted file]
modules/override/YAML.pm [deleted file]
modules/override/YAML/Any.pm [deleted file]
modules/override/YAML/Dumper.pm [deleted file]
modules/override/YAML/Dumper/Base.pm [deleted file]
modules/override/YAML/Error.pm [deleted file]
modules/override/YAML/Loader.pm [deleted file]
modules/override/YAML/Loader/Base.pm [deleted file]
modules/override/YAML/Marshall.pm [deleted file]
modules/override/YAML/Mo.pm [deleted file]
modules/override/YAML/Node.pm [deleted file]
modules/override/YAML/Tag.pm [deleted file]
modules/override/YAML/Types.pm [deleted file]
scripts/dbconnect.pl
scripts/dbupgrade2_tool.pl
scripts/find-use.pl
scripts/installation_check.pl
scripts/locales.pl
scripts/rose_auto_create_model.pl
scripts/sync_files_from_backend.pl
scripts/task_server.pl
sql/Pg-upgrade2/convert_drafts_to_record_templates.pl
t/001compile.t
t/request/post_multipart.t
t/test.pl

diff --git a/Devel/REPL/Plugin/AutoloadModules.pm b/Devel/REPL/Plugin/AutoloadModules.pm
new file mode 100644 (file)
index 0000000..e36ee96
--- /dev/null
@@ -0,0 +1,29 @@
+package Devel::REPL::Plugin::AutoloadModules;
+
+use Moose::Role;
+use namespace::clean -except => [ 'meta' ];
+use Data::Dumper;
+
+has 'autoloaded' => ( is => 'rw', isa => 'HashRef', default => sub { {} } );
+
+my $re = qr/Runtime error: Can.t locate object method "\w+" via package "\w+" \(perhaps you forgot to load "(\w+)"\?\)/;
+around 'execute' => sub {
+  my $orig = shift;
+  my $self = shift;
+
+  my @re = $self->$orig(@_);                           # original call
+
+  return @re unless defined $re[0] && $re[0] =~ /$re/; # if there is no "perhaps you forgot" error, just return
+  my $module = $1;                                     # save the missing package name
+
+  return @re if $self->autoloaded->{$module};          # if we tried to load it before, give up and return the error
+
+  $self->autoloaded->{$module} = 1;                    # make sure we don't try this again
+  $self->eval("use SL::$module");                      # try to load the missing module
+
+  @re = $self->$orig(@_);                              # try again
+
+  return @re;
+};
+
+1;
diff --git a/Devel/REPL/Plugin/PermanentHistory.pm b/Devel/REPL/Plugin/PermanentHistory.pm
new file mode 100644 (file)
index 0000000..3a46b56
--- /dev/null
@@ -0,0 +1,39 @@
+package Devel::REPL::Plugin::PermanentHistory;
+
+use Moose::Role;
+use namespace::clean -except => [ 'meta' ];
+use File::Slurp;
+use Data::Dumper;
+
+has 'history_file' => ( is => 'rw' );
+
+sub load_history {
+  my $self = shift;
+  my $file = shift;
+
+  $self->history_file( $file );
+
+  return unless $self->history_file && -f $self->history_file;
+
+  my @history =
+    map { chomp; $_ }
+    read_file($self->history_file);
+#  print  Dumper(\@history);
+  $self->history( \@history );
+  $self->term->addhistory($_) for @history;
+}
+
+before 'DESTROY' => sub {
+  my $self = shift;
+
+  return unless $self->history_file;
+
+  write_file $self->history_file,
+    map { $_, $/ }
+    grep $_,
+    grep { !/^quit\b/ }
+    @{ $self->history };
+};
+
+1;
+
index cfaa624..3cc80bb 100644 (file)
@@ -7,9 +7,9 @@ use strict;
 use SL::Locale::String ();
 
 use Scalar::Util qw(weaken);
-use YAML;
 
 use SL::DBUtils;
+use SL::YAML;
 
 sub new {
   my ($class, %params) = @_;
@@ -39,7 +39,7 @@ sub get_dumped {
   my ($self) = @_;
   no warnings 'once';
   local $YAML::Stringify = 1;
-  return YAML::Dump($self->get);
+  return SL::YAML::Dump($self->get);
 }
 
 sub _fetch {
@@ -58,7 +58,7 @@ sub _fetch {
 sub _parse {
   my ($self) = @_;
 
-  $self->{value}  = YAML::Load($self->{value}) unless $self->{parsed};
+  $self->{value}  = SL::YAML::Load($self->{value}) unless $self->{parsed};
   $self->{parsed} = 1;
 
   return $self;
@@ -71,7 +71,7 @@ sub _load_value {
 
   my %params = ( simple => 1 );
   eval {
-    my $data = YAML::Load($value);
+    my $data = SL::YAML::Load($value);
 
     if (ref $data eq 'HASH') {
       map { $params{$_} = $data->{$_} } keys %{ $data };
index 1736721..00f76d5 100644 (file)
@@ -4,8 +4,8 @@ use strict;
 
 use parent qw(SL::BackgroundJob::Base);
 
-use YAML ();
 use SL::JSON;
+use SL::YAML;
 use SL::DB::CsvImportProfile;
 
 sub create_job {
@@ -23,7 +23,7 @@ sub create_job {
     type         => 'once',
     active       => 1,
     package_name => $package,
-    data         => YAML::Dump(\%data),
+    data         => SL::YAML::Dump(\%data),
   );
 
   return $job;
@@ -33,7 +33,7 @@ sub profile {
   my ($self) = @_;
 
   if (!$self->{profile}) {
-    my $data = YAML::Load($self->{db_obj}->data);
+    my $data = SL::YAML::Load($self->{db_obj}->data);
     $self->{profile} = SL::DB::Manager::CsvImportProfile->find_by(id => $data->{profile_id});
   }
 
index a30acc7..3fbc0d1 100644 (file)
@@ -697,7 +697,7 @@ sub check_orphaned_bank_transaction_acc_trans_links {
     $self->tester->ok(1, "Keine verwaisten Einträge in verknüpften Bankbewegungen (Richtung Bank).");
   }
   # check for deleted acc_trans_ids
-  my $query = qq|
+  $query = qq|
           SELECT purpose from bank_transactions
           WHERE id in
           (SELECT bank_transaction_id from bank_transaction_acc_trans
index ed2f602..02e74f5 100644 (file)
@@ -9,7 +9,7 @@ use SL::Locale::String qw(t8);
 use SL::Request;
 use SL::DB::Draft;
 use SL::DBUtils qw(selectall_hashref_query);
-use YAML;
+use SL::YAML;
 use List::Util qw(max);
 
 use Rose::Object::MakeMethods::Generic (
@@ -53,7 +53,7 @@ sub action_save {
     module      => $self->module,
     submodule   => $self->submodule,
     description => $description,
-    form        => YAML::Dump($form),
+    form        => SL::YAML::Dump($form),
     employee_id => SL::DB::Manager::Employee->current->id,
   );
 
@@ -83,7 +83,7 @@ sub action_load {
     require $allowed_modules{ $self->draft->module };
   }
   my $params = delete $::form->{form};
-  my $new_form = YAML::Load($self->draft->form);
+  my $new_form = SL::YAML::Load($self->draft->form);
   $::form->{$_} = $new_form->{$_} for keys %$new_form;
   $::form->{"draft_$_"} = $self->draft->$_ for qw(id description);
 
index c37dc1c..5a42a19 100644 (file)
@@ -11,6 +11,7 @@ use SL::PriceSource;
 use SL::Webdav;
 use SL::File;
 use SL::Util qw(trim);
+use SL::YAML;
 use SL::DB::Order;
 use SL::DB::Default;
 use SL::DB::Unit;
@@ -552,7 +553,7 @@ sub action_assign_periodic_invoices_config {
                  email_body                 => $::form->{email_body},
                };
 
-  my $periodic_invoices_config = YAML::Dump($config);
+  my $periodic_invoices_config = SL::YAML::Dump($config);
 
   my $status = $self->get_periodic_invoices_status($config);
 
@@ -1232,7 +1233,7 @@ sub make_order {
 
   $order->assign_attributes(%{$::form->{order}});
 
-  if (my $periodic_invoices_config_attrs = $form_periodic_invoices_config ? YAML::Load($form_periodic_invoices_config) : undef) {
+  if (my $periodic_invoices_config_attrs = $form_periodic_invoices_config ? SL::YAML::Load($form_periodic_invoices_config) : undef) {
     my $periodic_invoices_config = $order->periodic_invoices_config || $order->periodic_invoices_config(SL::DB::PeriodicInvoicesConfig->new);
     $periodic_invoices_config->assign_attributes(%$periodic_invoices_config_attrs);
   }
@@ -1723,7 +1724,7 @@ sub generate_pdf {
         },
       );
       1;
-    } || push @errors, ref($EVAL_ERROR) eq 'SL::X::FormError' ? $EVAL_ERROR->getMessage : $EVAL_ERROR;
+    } || push @errors, ref($EVAL_ERROR) eq 'SL::X::FormError' ? $EVAL_ERROR->error : $EVAL_ERROR;
   });
 
   return @errors;
@@ -1765,7 +1766,7 @@ sub make_periodic_invoices_config_from_yaml {
   my ($yaml_config) = @_;
 
   return if !$yaml_config;
-  my $attr = YAML::Load($yaml_config);
+  my $attr = SL::YAML::Load($yaml_config);
   return if 'HASH' ne ref $attr;
   return SL::DB::PeriodicInvoicesConfig->new(%$attr);
 }
index 79a251a..c678ed1 100644 (file)
--- a/SL/DB.pm
+++ b/SL/DB.pm
@@ -6,12 +6,12 @@ use Carp;
 use Data::Dumper;
 use English qw(-no_match_vars);
 use Rose::DB;
-use Rose::DBx::Cache::Anywhere;
+use SL::DB::Helper::Cache;
 use Scalar::Util qw(blessed);
 
 use base qw(Rose::DB);
 
-__PACKAGE__->db_cache_class('Rose::DBx::Cache::Anywhere');
+__PACKAGE__->db_cache_class('SL::DB::Helper::Cache');
 __PACKAGE__->use_private_registry;
 
 my (%_db_registered);
index 3e6c03d..1fc8d99 100644 (file)
@@ -11,6 +11,7 @@ use SL::DB::MetaSetup::BackgroundJob;
 use SL::DB::Manager::BackgroundJob;
 
 use SL::System::Process;
+use SL::YAML;
 
 __PACKAGE__->meta->initialize;
 
@@ -76,18 +77,18 @@ sub run {
 sub data_as_hash {
   my $self = shift;
 
-  $self->data(YAML::Dump($_[0])) if @_;
+  $self->data(SL::YAML::Dump($_[0])) if @_;
 
   return {}                        if !$self->data;
   return $self->data               if ref($self->{data}) eq 'HASH';
-  return YAML::Load($self->{data}) if !ref($self->{data});
+  return SL::YAML::Load($self->{data}) if !ref($self->{data});
   return {};
 }
 
 sub set_data {
   my ($self, %data) = @_;
 
-  $self->data(YAML::Dump({
+  $self->data(SL::YAML::Dump({
     %{ $self->data_as_hash },
     %data,
   }));
index abe11c0..7ca63a3 100644 (file)
@@ -143,10 +143,10 @@ sub reorder_list {
   my $column = column_name($self);
   my $result = $self->db->with_transaction(sub {
     my $query = qq|UPDATE | . $self->meta->table . qq| SET ${column} = ? WHERE id = ?|;
-    my $sth   = $self->db->dbh->prepare($query) || die $self->db->dbh->errstr;
+    my $sth   = $self->db->dbh->prepare($query) || SL::X::DBUtilsError->throw(msg => 'reorder_list error', db_error => $self->db->dbh->errstr);
 
     foreach my $new_position (1 .. scalar(@ids)) {
-      $sth->execute($new_position, $ids[$new_position - 1]) || die SL::X::DBUtilsError->new(error => $sth->errstr);
+      $sth->execute($new_position, $ids[$new_position - 1]) || SL::X::DBUtilsError->throw(msg => 'reorder_list error', db_error => $sth->errstr);
     }
 
     $sth->finish;
diff --git a/SL/DB/Helper/Cache.pm b/SL/DB/Helper/Cache.pm
new file mode 100644 (file)
index 0000000..e93b551
--- /dev/null
@@ -0,0 +1,44 @@
+package SL::DB::Helper::Cache;
+
+use strict;
+use warnings;
+
+use Carp;
+
+use parent qw(Rose::DB::Cache);
+
+sub prepare_db {
+  my ($self, $db, $entry) = @_;
+
+  if (!$entry->is_prepared) {
+    # if this a dummy kivitendo dbh, don't try to actually prepare this.
+    if ($db->type =~ /KIVITENDO_EMPTY/) {
+      return;
+    }
+
+    $entry->prepared(1);
+  }
+
+  if (!$db->dbh->ping) {
+    $db->dbh(undef);
+  }
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+SL::DB::Helper::Cache - database handle caching for kivitendo
+
+=head1 DESCRIPTION
+
+This class provides database cache handling for kivitendo running
+under FastCGI. It's based on Rose::DBx::Cache::Anywhere.
+
+=head1 METHODS
+
+=head2 prepare_db( I<rose_db>, I<entry> )
+
+Overrides default method to always ping() dbh.
index 4eaa106..c65bb28 100644 (file)
@@ -38,8 +38,8 @@ sub handle_error {
   # these are used as Rose internal canaries, don't wrap them
   die $object->error if UNIVERSAL::isa($object->error, 'Rose::DB::Object::Exception');
 
-  die SL::X::DBRoseError->new(
-    error      => $object->error,
+  SL::X::DBRoseError->throw(
+    db_error   => $object->error,
     class      => ref($object),
     metaobject => $self,
     object     => $object,
index 371e445..6a54869 100644 (file)
@@ -44,10 +44,10 @@ sub run_hooks {
 
   foreach my $sub (@{ ( $hooks{$when} || { })->{ ref($object) } || [ ] }) {
     my $result = ref($sub) eq 'CODE' ? $sub->($object, @args) : $object->call_sub($sub, @args);
-    die SL::X::DBHookError->new(when        => $when,
-                                hook        => (ref($sub) eq 'CODE' ? '<anonymous sub>' : $sub),
-                                object      => $object,
-                                object_type => ref($object))
+    SL::X::DBHookError->throw(when        => $when,
+                              hook        => (ref($sub) eq 'CODE' ? '<anonymous sub>' : $sub),
+                              object      => $object,
+                              object_type => ref($object))
       if !$result;
   }
 }
index 6a91953..54df47c 100644 (file)
--- a/SL/DO.pm
+++ b/SL/DO.pm
@@ -37,7 +37,6 @@ package DO;
 use Carp;
 use List::Util qw(max);
 use Text::ParseWords;
-use YAML;
 
 use SL::AM;
 use SL::Common;
@@ -52,6 +51,7 @@ use SL::IC;
 use SL::TransNumber;
 use SL::DB;
 use SL::Util qw(trim);
+use SL::YAML;
 
 use strict;
 
@@ -450,7 +450,7 @@ SQL
                   conv_i($sinfo->{bin_id}));
         $h_item_stock_id->finish();
         # write back the id to the form (important if only transfer was clicked (id fk for invoice)
-        $form->{"stock_${in_out}_$i"} = YAML::Dump($stock_info);
+        $form->{"stock_${in_out}_$i"} = SL::YAML::Dump($stock_info);
       }
       @values = ($form->{"delivery_order_items_id_$i"}, $sinfo->{qty}, $sinfo->{unit}, conv_i($sinfo->{warehouse_id}),
                  conv_i($sinfo->{bin_id}), $sinfo->{chargenumber}, conv_date($sinfo->{bestbefore}),
@@ -833,7 +833,7 @@ sub retrieve {
         push @{ $requests }, $ref;
       }
 
-      $doi->{"stock_${in_out}"} = YAML::Dump($requests);
+      $doi->{"stock_${in_out}"} = SL::YAML::Dump($requests);
     }
 
     $sth->finish();
@@ -1095,7 +1095,7 @@ sub unpack_stock_information {
 
   my $unpacked;
 
-  eval { $unpacked = $params{packed} ? YAML::Load($params{packed}) : []; };
+  eval { $unpacked = $params{packed} ? SL::YAML::Load($params{packed}) : []; };
 
   $unpacked = [] if (!$unpacked || ('ARRAY' ne ref $unpacked));
 
index 55ac633..59d69c3 100644 (file)
@@ -249,7 +249,7 @@ sub hide_form {
 
 sub throw_on_error {
   my ($self, $code) = @_;
-  local $self->{__ERROR_HANDLER} = sub { die SL::X::FormError->new($_[0]) };
+  local $self->{__ERROR_HANDLER} = sub { SL::X::FormError->throw(error => $_[0]) };
   $code->();
 }
 
@@ -311,9 +311,9 @@ sub numtextrows {
 sub dberror {
   my ($self, $msg) = @_;
 
-  die SL::X::DBError->new(
-    msg   => $msg,
-    error => $DBI::errstr,
+  SL::X::DBError->throw(
+    msg      => $msg,
+    db_error => $DBI::errstr,
   );
 }
 
index f62c676..a2a0a86 100644 (file)
--- a/SL/IC.pm
+++ b/SL/IC.pm
@@ -37,7 +37,6 @@ package IC;
 
 use Data::Dumper;
 use List::MoreUtils qw(all any uniq);
-use YAML;
 
 use SL::CVar;
 use SL::DBUtils;
index 9fdfb8f..81d5c91 100644 (file)
@@ -30,7 +30,7 @@ BEGIN {
   { name => "DBI",             version => '1.50',  url => "http://search.cpan.org/~timb/",      debian => 'libdbi-perl' },
   { name => "DBD::Pg",         version => '1.49',  url => "http://search.cpan.org/~dbdpg/",     debian => 'libdbd-pg-perl' },
   { name => "Digest::SHA",                         url => "http://search.cpan.org/~mshelor/",   debian => 'libdigest-sha-perl' },
-  { name => "Exception::Lite",                     url => "http://search.cpan.org/~elisheva/", }, # fallback latest version 2011
+  { name => "Exception::Class",                    url => "https://metacpan.org/pod/Exception::Class", debian => 'libexception-class-perl' },
   { name => "Email::Address",  version => '1.888', url => "http://search.cpan.org/~rjbs/",      debian => 'libemail-address-perl' },
   { name => "Email::MIME",                         url => "http://search.cpan.org/~rjbs/",      debian => 'libemail-mime-perl' },
   { name => "FCGI",            version => '0.72',  url => "http://search.cpan.org/~mstrout/",   debian => 'libfcgi-perl' },
@@ -55,11 +55,8 @@ BEGIN {
   { name => "Rose::DB",                            url => "http://search.cpan.org/~jsiracusa/", debian => 'librose-db-perl' },
   { name => "Rose::DB::Object", version => 0.788,  url => "http://search.cpan.org/~jsiracusa/", debian => 'librose-db-object-perl' },
   { name => "Set::Infinite",    version => '0.63', url => "http://search.cpan.org/~fglock/",    debian => 'libset-infinite-perl' },
-  { name => "Set::Crontab",     version => '1.03', url => "http://search.cpan.org/~ams/",       debian => 'libset-crontab-perl' },
   { name => "String::ShellQuote", version => 1.01, url => "http://search.cpan.org/~rosch/",     debian => 'libstring-shellquote-perl' },
   { name => "Sort::Naturally",                     url => "http://search.cpan.org/~sburke/",    debian => 'libsort-naturally-perl' },
-  # Test::Harness is core, so no Debian packages. Test::Harness 3.00 was first packaged in 5.10.1
-  { name => "Test::Harness",   version => '3.00',  url => "http://search.cpan.org/~petdance/",  },
   { name => "Template",        version => '2.18',  url => "http://search.cpan.org/~abw/",       debian => 'libtemplate-perl' },
   { name => "Text::CSV_XS",    version => '0.23',  url => "http://search.cpan.org/~hmbrand/",   debian => 'libtext-csv-xs-perl' },
   { name => "Text::Iconv",     version => '1.2',   url => "http://search.cpan.org/~mpiotr/",    debian => 'libtext-iconv-perl' },
@@ -75,6 +72,7 @@ BEGIN {
   # Net::SMTP is core since 5.7.3
   { name => "Net::SMTP::SSL",                      url => "http://search.cpan.org/~cwest/",     debian => 'libnet-smtp-ssl-perl' },
   { name => "Net::SSLGlue",                        url => "http://search.cpan.org/~sullr/",     debian => 'libnet-sslglue-perl' },
+  { name => "YAML::XS",                            url => "https://metacpan.org/pod/distribution/YAML-LibYAML/lib/YAML/LibYAML.pod", debian => 'libyaml-libyaml-perl' },
 );
 
 @developer_modules = (
index 7dddf2a..28a36bf 100644 (file)
@@ -22,8 +22,8 @@ use Data::Dumper;
 use POSIX qw(strftime getpid);
 use Scalar::Util qw(blessed refaddr weaken);
 use Time::HiRes qw(gettimeofday tv_interval);
-use YAML;
 use SL::Request ();
+use SL::YAML;
 
 use strict;
 use utf8;
@@ -213,7 +213,7 @@ sub dump {
 sub dump_yaml {
   my ($self, $level, $name, $variable) = @_;
 
-  $self->message($level, "dumping ${name}:\n" . YAML::Dump($variable));
+  $self->message($level, "dumping ${name}:\n" . SL::YAML::Dump($variable));
 }
 
 sub dump_sql_result {
@@ -252,7 +252,7 @@ sub show_diff {
     return;
   }
 
-  my @texts = map { ref $_ ? YAML::Dump($_) : $_ } ($item1, $item2);
+  my @texts = map { ref $_ ? SL::YAML::Dump($_) : $_ } ($item1, $item2);
 
   $self->message($level, Text::Diff::diff(\$texts[0], \$texts[1], \%params));
 }
index 42b08de..0c6df22 100644 (file)
@@ -3,14 +3,9 @@ package SL::Menu;
 use strict;
 
 use SL::Auth;
-use YAML ();
 use File::Spec;
 use SL::MoreCommon qw(uri_encode);
-
-our $yaml_xs;
-BEGIN {
-   $yaml_xs =  eval { require YAML::XS };
-}
+use SL::YAML;
 
 our %menu_cache;
 
@@ -29,11 +24,7 @@ sub new {
     for my $file (@files) {
       my $data;
       eval {
-        if ($yaml_xs) {
-          $data = YAML::XS::LoadFile(File::Spec->catfile($path, $file));
-        } else {
-          $data = YAML::LoadFile(File::Spec->catfile($path, $file));
-        }
+        $data = SL::YAML::LoadFile(File::Spec->catfile($path, $file));
         1;
       } or do {
         die "Error while parsing $file: $@";
index b1ea817..0aa84a7 100644 (file)
@@ -8,7 +8,7 @@ our @EXPORT_OK = qw(ary_union ary_intersect ary_diff listify ary_to_hash uri_enc
 
 use Encode ();
 use List::MoreUtils qw(zip);
-use YAML;
+use SL::YAML;
 
 use strict;
 
@@ -23,7 +23,7 @@ sub save_form {
     delete $main::form->{$key};
   }
 
-  my $old_form = YAML::Dump($main::form);
+  my $old_form = SL::YAML::Dump($main::form);
   $old_form =~ s|!|!:|g;
   $old_form =~ s|\n|!n|g;
   $old_form =~ s|\r|!r|g;
@@ -49,7 +49,7 @@ sub restore_form {
   $old_form =~ s|!n|\n|g;
   $old_form =~ s|![!:]|!|g;
 
-  my $new_form = YAML::Load($old_form);
+  my $new_form = SL::YAML::Load($old_form);
   map { $form->{$_} = $new_form->{$_} if (!$keep_vars_map{$_}) } keys %{ $new_form };
 
   $main::lxdebug->leave_sub();
index ef6f597..74c9ffd 100644 (file)
--- a/SL/OE.pm
+++ b/SL/OE.pm
@@ -36,7 +36,6 @@
 package OE;
 
 use List::Util qw(max first);
-use YAML;
 
 use SL::AM;
 use SL::Common;
@@ -53,6 +52,7 @@ use SL::IC;
 use SL::TransNumber;
 use SL::Util qw(trim);
 use SL::DB;
+use SL::YAML;
 use Text::ParseWords;
 
 use strict;
@@ -816,7 +816,7 @@ sub save_periodic_invoices_config {
 
   return if !$params{oe_id};
 
-  my $config = $params{config_yaml} ? YAML::Load($params{config_yaml}) : undef;
+  my $config = $params{config_yaml} ? SL::YAML::Load($params{config_yaml}) : undef;
   return if 'HASH' ne ref $config;
 
   my $obj  = SL::DB::Manager::PeriodicInvoicesConfig->find_by(oe_id => $params{oe_id})
@@ -836,7 +836,7 @@ sub load_periodic_invoice_config {
     if ($config_obj) {
       my $config = { map { $_ => $config_obj->$_ } qw(active terminated periodicity order_value_periodicity start_date_as_date end_date_as_date first_billing_date_as_date extend_automatically_by ar_chart_id
                                                       print printer_id copies direct_debit send_email email_recipient_contact_id email_recipient_address email_sender email_subject email_body) };
-      $form->{periodic_invoices_config} = YAML::Dump($config);
+      $form->{periodic_invoices_config} = SL::YAML::Dump($config);
     }
   }
 }
diff --git a/SL/X.pm b/SL/X.pm
index 4ecfc7d..756793b 100644 (file)
--- a/SL/X.pm
+++ b/SL/X.pm
@@ -1,13 +1,32 @@
 package SL::X;
 
 use strict;
+use warnings;
 
-use Exception::Lite qw(declareExceptionClass);
+use SL::X::Base;
 
-declareExceptionClass('SL::X::FormError');
-declareExceptionClass('SL::X::DBError',                        [ '%s %s', qw(error msg) ]);
-declareExceptionClass('SL::X::DBHookError',  'SL::X::DBError', [ '%s hook \'%s\' for object type \'%s\' failed', qw(when hook object_type object) ]);
-declareExceptionClass('SL::X::DBRoseError',  'SL::X::DBError', [ '\'%s\' in object of type \'%s\' occured', qw(error class) ]);
-declareExceptionClass('SL::X::DBUtilsError', 'SL::X::DBError', [ '%s: %s', qw(msg error) ]);
+use Exception::Class (
+  'SL::X::FormError'    => {
+    isa                 => 'SL::X::Base',
+  },
+  'SL::X::DBError'      => {
+    isa                 => 'SL::X::Base',
+    fields              => [ qw(msg db_error) ],
+    defaults            => { error_template => [ '%s: %s', qw(msg db_error) ] },
+  },
+  'SL::X::DBHookError'  => {
+    isa                 => 'SL::X::DBError',
+    fields              => [ qw(when hook object object_type) ],
+    defaults            => { error_template => [ '%s hook \'%s\' for object type \'%s\' failed', qw(when hook object_type object) ] },
+  },
+  'SL::X::DBRoseError'  => {
+    isa                 => 'SL::X::DBError',
+    fields              => [ qw(class metaobject object) ],
+    defaults            => { error_template => [ '\'%s\' in object of type \'%s\' occured', qw(db_error class) ] },
+  },
+  'SL::X::DBUtilsError' => {
+    isa                 => 'SL::X::DBError',
+  },
+);
 
 1;
diff --git a/SL/X/Base.pm b/SL/X/Base.pm
new file mode 100644 (file)
index 0000000..3e6d251
--- /dev/null
@@ -0,0 +1,26 @@
+package SL::X::Base;
+
+use strict;
+use warnings;
+
+use parent qw(Exception::Class::Base);
+
+sub _defaults { return () }
+
+sub message { goto &error }
+
+sub error {
+  my ($self, @params) = @_;
+
+  return $self->{message} if ($self->{message} // '') ne '';
+
+  return $self->SUPER::error(@params) if !$self->can('_defaults');
+
+  my %defaults = $self->_defaults;
+  return $self->SUPER::error(@params) if !$defaults{error_template};
+
+  my ($format, @fields) = @{ $defaults{error_template} };
+  return sprintf $format, map { $self->$_ } @fields;
+}
+
+1;
diff --git a/SL/YAML.pm b/SL/YAML.pm
new file mode 100644 (file)
index 0000000..bfccfba
--- /dev/null
@@ -0,0 +1,60 @@
+package SL::YAML;
+
+use strict;
+use warnings;
+
+sub _choose_yaml_module {
+  return 'YAML::XS' if $INC{'YAML/XS.pm'};
+  return 'YAML'     if $INC{'YAML.pm'};
+
+  my @err;
+
+  return 'YAML::XS' if eval { require YAML::XS; 1; };
+  push @err, "Error loading YAML::XS: $@";
+
+  return 'YAML' if eval { require YAML; 1; };
+  push @err, "Error loading YAML: $@";
+
+  die join("\n", "Couldn't load a YAML module:", @err);
+}
+
+BEGIN {
+  our $YAML_Class = _choose_yaml_module();
+  $YAML_Class->import(qw(Dump Load DumpFile LoadFile));
+}
+
+sub YAML { our $YAML_Class }
+
+1;
+
+__END__
+
+=pod
+
+=encoding utf8
+
+=head1 NAME
+
+SL::YAML - A thin wrapper around YAML::XS and YAML
+
+=head1 SYNOPSIS
+
+    use SL::YAML;
+
+    my $menu_data = SL::YAML::LoadFile("menus/user/00-erp.yml");
+
+=head1 OVERVIEW
+
+This is a thin wrapper around the YAML::XS and YAML modules. It'll
+prefer loading YAML::XS if that's found and will fallback to YAML
+otherwise. It only provides the four functions C<Dump>, C<Load>,
+C<DumpFile> and C<LoadFile> â€” just enough to get by for kivitendo.
+
+The functions are direct imports from the imported module. Please see
+the documentation for YAML::XS or YAML for details.
+
+=head1 AUTHOR
+
+Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>
+
+=cut
index c0e325e..18d237b 100644 (file)
@@ -3,7 +3,6 @@ use SL::Form;
 use SL::Locale::String qw(t8);
 use SL::User;
 use Data::Dumper;
-use YAML;
 
 require "bin/mozilla/common.pl";
 
index c356351..ff90217 100644 (file)
@@ -35,7 +35,6 @@ use Carp;
 use List::MoreUtils qw(uniq);
 use List::Util qw(max sum);
 use POSIX qw(strftime);
-use YAML;
 
 use SL::DB::DeliveryOrder;
 use SL::DO;
@@ -44,6 +43,7 @@ use SL::IS;
 use SL::MoreCommon qw(ary_diff restore_form save_form);
 use SL::ReportGenerator;
 use SL::WH;
+use SL::YAML;
 use Sort::Naturally ();
 require "bin/mozilla/common.pl";
 require "bin/mozilla/io.pl";
@@ -1390,7 +1390,7 @@ sub set_stock_in {
     push @{ $stock_info }, { map { $_ => $form->{"${_}_${i}"} } qw(delivery_order_items_stock_id warehouse_id bin_id chargenumber bestbefore qty unit) };
   }
 
-  $form->{stock} = YAML::Dump($stock_info);
+  $form->{stock} = SL::YAML::Dump($stock_info);
 
   _stock_in_out_set_qty_display($stock_info);
 
@@ -1485,7 +1485,7 @@ sub set_stock_out {
   my @errors     = DO->check_stock_availability('requests' => $stock_info,
                                                 'parts_id' => $form->{parts_id});
 
-  $form->{stock} = YAML::Dump($stock_info);
+  $form->{stock} = SL::YAML::Dump($stock_info);
 
   if (@errors) {
     $form->{ERRORS} = [];
@@ -1917,7 +1917,7 @@ sub transfer_in_out_default {
   foreach (@all_requests){
     $i++;
     next unless scalar(%{ $_ });
-    $form->{"stock_${prefix}_$i"} = YAML::Dump([$_]);
+    $form->{"stock_${prefix}_$i"} = SL::YAML::Dump([$_]);
   }
 
   save(no_redirect => 1); # Wir können auslagern, deshalb beleg speichern
index 1d358d9..b5f3eb6 100644 (file)
@@ -44,6 +44,7 @@ use SL::IR;
 use SL::IS;
 use SL::MoreCommon qw(ary_diff restore_form save_form);
 use SL::ReportGenerator;
+use SL::YAML;
 use List::MoreUtils qw(uniq any none);
 use List::Util qw(min max reduce sum);
 use Data::Dumper;
@@ -614,7 +615,7 @@ sub form_header {
       $form->{periodic_invoices_status} = $locale->text('not configured');
 
     } else {
-      my $config                        = YAML::Load($form->{periodic_invoices_config});
+      my $config                        = SL::YAML::Load($form->{periodic_invoices_config});
       $form->{periodic_invoices_status} = $config->{active} ? $locale->text('active') : $locale->text('inactive');
     }
   }
@@ -2171,7 +2172,7 @@ sub edit_periodic_invoices_config {
   check_oe_access();
 
   my $config;
-  $config = YAML::Load($::form->{periodic_invoices_config}) if $::form->{periodic_invoices_config};
+  $config = SL::YAML::Load($::form->{periodic_invoices_config}) if $::form->{periodic_invoices_config};
 
   if ('HASH' ne ref $config) {
     my $lang_id = $::form->{language_id};
@@ -2237,7 +2238,7 @@ sub save_periodic_invoices_config {
                  email_body                 => $::form->{email_body},
                };
 
-  $::form->{periodic_invoices_config} = YAML::Dump($config);
+  $::form->{periodic_invoices_config} = SL::YAML::Dump($config);
 
   $::form->{title} = $::locale->text('Edit the configuration for periodic invoices');
   $::form->header;
index e5621f6..a6364ab 100755 (executable)
@@ -7,7 +7,6 @@ BEGIN {
 
   unshift(@INC, $FindBin::Bin . '/modules/override'); # Use our own versions of various modules (e.g. YAML).
   push   (@INC, $FindBin::Bin);                       # '.' will be removed from @INC soon.
-  push   (@INC, $FindBin::Bin . '/modules/fallback'); # Only use our own versions of modules if there's no system version.
 }
 
 use SL::Dispatcher;
index b9b7e11..72c74ca 100644 (file)
             <para><literal>Email::MIME</literal></para>
           </listitem>
 
+          <listitem>
+            <para><literal>Exception::Class</literal></para>
+          </listitem>
+
           <listitem>
             <para><literal>FCGI</literal> (nicht Versionen 0.68 bis 0.71
             inklusive; siehe <xref
             <para><literal>Set::Infinite</literal></para>
           </listitem>
 
-          <listitem>
-            <para><literal>Set::Crontab</literal></para>
-          </listitem>
-
           <listitem>
             <para><literal>String::ShellQuote</literal></para>
           </listitem>
           </listitem>
 
           <listitem>
-            <para><literal>YAML</literal></para>
+            <para><literal>YAML::XS</literal> oder <literal>YAML</literal></para>
           </listitem>
         </itemizedlist>
 
+        <para>Seit Version größer v3.5.3 sind die folgenden Pakete hinzugekommen: <literal>Exception::Class</literal></para>
+
         <para>Seit Version größer v3.5.1 sind die folgenden Pakete hinzugekommen: <literal>Set::Infinite</literal>,
         <literal>List::UtilsBy</literal>, <literal>DateTime::Set</literal>, <literal>DateTime::Event::Cron</literal>
-        <literal>Daemon::Generic</literal> <literal>DateTime::Event::Cron</literal> <literal>File::Flock</literal>
-        <literal>File::Slurp</literal> <literal>Set::Crontab</literal> <literal>Exception::Lite</literal>. Für die letzten beiden Module
-        liefert kivitendo fallback-Module aus, da diese Ã¼berhaupt nicht in debian oder in der benötigten Version zu Verfügung stehen (Stand
-        Anfang 2019).</para>
+        <literal>Daemon::Generic</literal>, <literal>DateTime::Event::Cron</literal>, <literal>File::Flock</literal>,
+        <literal>File::Slurp</literal></para>
 
         <para>Seit Version größer v3.5.0 sind die folgenden Pakete
         hinzugekommen: <literal>Text::Unidecode</literal>,
   libparams-validate-perl libpdf-api2-perl librose-db-object-perl \
   librose-db-perl librose-object-perl libsort-naturally-perl \
   libstring-shellquote-perl libtemplate-perl libtext-csv-xs-perl \
-  libtext-iconv-perl liburi-perl libxml-writer-perl libyaml-perl \
+  libtext-iconv-perl liburi-perl libxml-writer-perl libyaml-libyaml-perl \
   libimage-info-perl libgd-gd2-perl libapache2-mod-fcgid \
   libfile-copy-recursive-perl postgresql libalgorithm-checkdigits-perl \
   libcrypt-pbkdf2-perl git libcgi-pm-perl libtext-unidecode-perl libwww-perl\
   postgresql-contrib aqbanking-tools poppler-utils libhtml-restrict-perl\
   libdatetime-set-perl libset-infinite-perl liblist-utilsby-perl\
   libdaemon-generic-perl libfile-flock-perl libfile-slurp-perl\
-  libfile-mimeinfo-perl libpbkdf2-tiny-perl libregexp-ipv6-perl
-
+  libfile-mimeinfo-perl libpbkdf2-tiny-perl libregexp-ipv6-perl \
+  libdatetime-event-perl libexception-class-perl
 </programlisting>
           <para>Ab Ubuntu Version 18.04 LTS, bzw. Debian Buster sind alle benötigten Pakete in der Distribution verfügbar.</para>
           <para>Für Ã¤ltere Ubuntu/Debians müßen einige Pakete per CPAN installiert werden.
@@ -471,7 +471,7 @@ cpan HTML::Restrict</programlisting>
   perl-Email-MIME perl-FastCGI perl-File-Copy-Recursive perl-File-Flock \
   perl-File-MimeInfo perl-File-Slurp perl-GD perl-Image-Info perl-JSON \
   perl-List-MoreUtils perl-List-UtilsBy perl-Net-SMTP-SSL perl-Net-SSLGlue \
-  perl-PDF-API2 perl-Params-Validate perl-Regexp-IPv6 perl-Set-Crontab \
+  perl-PDF-API2 perl-Params-Validate perl-Regexp-IPv6 \
   perl-Sort-Naturally perl-String-ShellQuote perl-Template-Toolkit \
   perl-Text-CSV_XS perl-Text-Iconv perl-Text-Unidecode perl-URI \
   perl-XML-Writer perl-YAML perl-libwww-perl
index a4fae67..2f4217c 100644 (file)
@@ -41,6 +41,8 @@
                      <code class="literal">Email::Address</code>
                   </p></li><li class="listitem"><p>
                      <code class="literal">Email::MIME</code>
+                  </p></li><li class="listitem"><p>
+                     <code class="literal">Exception::Class</code>
                   </p></li><li class="listitem"><p>
                      <code class="literal">FCGI</code> (nicht Versionen 0.68 bis 0.71
             inklusive; siehe <a class="xref" href="ch02s06.html#Apache-Konfiguration.FCGI.WebserverUndPlugin" title="2.6.2.3. Getestete Kombinationen aus Webservern und Plugin">Abschnitt&nbsp;2.6.2.3, â€žGetestete Kombinationen aus Webservern und Plugin“</a>)</p></li><li class="listitem"><p>
@@ -85,8 +87,6 @@
                      <code class="literal">Rose::DB::Object</code> Version 0.788 oder
             neuer</p></li><li class="listitem"><p>
                      <code class="literal">Set::Infinite</code>
-                  </p></li><li class="listitem"><p>
-                     <code class="literal">Set::Crontab</code>
                   </p></li><li class="listitem"><p>
                      <code class="literal">String::ShellQuote</code>
                   </p></li><li class="listitem"><p>
                   </p></li><li class="listitem"><p>
                      <code class="literal">XML::Writer</code>
                   </p></li><li class="listitem"><p>
-                     <code class="literal">YAML</code>
-                  </p></li></ul></div><p>Seit Version größer v3.5.1 sind die folgenden Pakete hinzugekommen: <code class="literal">Set::Infinite</code>,
+                     <code class="literal">YAML::XS</code> oder <code class="literal">YAML</code>
+                  </p></li></ul></div><p>Seit Version größer v3.5.3 sind die folgenden Pakete hinzugekommen: <code class="literal">Exception::Class</code>
+            </p><p>Seit Version größer v3.5.1 sind die folgenden Pakete hinzugekommen: <code class="literal">Set::Infinite</code>,
         <code class="literal">List::UtilsBy</code>, <code class="literal">DateTime::Set</code>, <code class="literal">DateTime::Event::Cron</code>
         
-               <code class="literal">Daemon::Generic</code> 
-               <code class="literal">DateTime::Event::Cron</code> 
-               <code class="literal">File::Flock</code>
-        
-               <code class="literal">File::Slurp</code> 
-               <code class="literal">Set::Crontab</code> 
-               <code class="literal">Exception::Lite</code>. Für die letzten beiden Module
-        liefert kivitendo fallback-Module aus, da diese Ã¼berhaupt nicht in debian oder in der benötigten Version zu Verfügung stehen (Stand
-        Anfang 2019).</p><p>Seit Version größer v3.5.0 sind die folgenden Pakete
+               <code class="literal">Daemon::Generic</code>, <code class="literal">DateTime::Event::Cron</code>, <code class="literal">File::Flock</code>,
+        <code class="literal">File::Slurp</code>
+            </p><p>Seit Version größer v3.5.0 sind die folgenden Pakete
         hinzugekommen: <code class="literal">Text::Unidecode</code>,
         <code class="literal">LWP::Authen::Digest</code>,
         <code class="literal">LWP::UserAgent</code>
         sind auch in 2.6.1 weiterhin mit ausgeliefert, wurden in einer
         zukünftigen Version aber aus dem Paket entfernt werden. Es wird
         empfohlen diese Module zusammen mit den anderen als Bibliotheken zu
-        installieren.</p><div class="sect3" title="2.2.2.1. Debian und Ubuntu"><div class="titlepage"><div><div><h4 class="title"><a name="d0e543"></a>2.2.2.1. Debian und Ubuntu</h4></div></div></div><p>Für Debian und Ubuntu stehen die meisten der benötigten
+        installieren.</p><div class="sect3" title="2.2.2.1. Debian und Ubuntu"><div class="titlepage"><div><div><h4 class="title"><a name="d0e545"></a>2.2.2.1. Debian und Ubuntu</h4></div></div></div><p>Für Debian und Ubuntu stehen die meisten der benötigten
           Pakete als Debian-Pakete zur Verfügung. Sie können mit
           folgendem Befehl installiert werden:</p><pre class="programlisting">apt install  apache2 libarchive-zip-perl libclone-perl \
   libconfig-std-perl libdatetime-perl libdbd-pg-perl libdbi-perl \
   libparams-validate-perl libpdf-api2-perl librose-db-object-perl \
   librose-db-perl librose-object-perl libsort-naturally-perl \
   libstring-shellquote-perl libtemplate-perl libtext-csv-xs-perl \
-  libtext-iconv-perl liburi-perl libxml-writer-perl libyaml-perl \
+  libtext-iconv-perl liburi-perl libxml-writer-perl libyaml-libyaml-perl \
   libimage-info-perl libgd-gd2-perl libapache2-mod-fcgid \
   libfile-copy-recursive-perl postgresql libalgorithm-checkdigits-perl \
   libcrypt-pbkdf2-perl git libcgi-pm-perl libtext-unidecode-perl libwww-perl\
   postgresql-contrib aqbanking-tools poppler-utils libhtml-restrict-perl\
   libdatetime-set-perl libset-infinite-perl liblist-utilsby-perl\
   libdaemon-generic-perl libfile-flock-perl libfile-slurp-perl\
-  libfile-mimeinfo-perl libpbkdf2-tiny-perl libregexp-ipv6-perl
-
+  libfile-mimeinfo-perl libpbkdf2-tiny-perl libregexp-ipv6-perl \
+  libdatetime-event-perl libexception-class-perl
 </pre><p>Ab Ubuntu Version 18.04 LTS, bzw. Debian Buster sind alle benötigten Pakete in der Distribution verfügbar.</p><p>Für Ã¤ltere Ubuntu/Debians müßen einige Pakete per CPAN installiert werden.
           Das geht bspw. für das benötige Paket HTML::Restrict mit:</p><pre class="programlisting">apt-get install build-essential
-cpan HTML::Restrict</pre></div><div class="sect3" title="2.2.2.2. Fedora"><div class="titlepage"><div><div><h4 class="title"><a name="d0e556"></a>2.2.2.2. Fedora</h4></div></div></div><p>Für Fedora stehen die meisten der benötigten Perl-Pakete als
+cpan HTML::Restrict</pre></div><div class="sect3" title="2.2.2.2. Fedora"><div class="titlepage"><div><div><h4 class="title"><a name="d0e558"></a>2.2.2.2. Fedora</h4></div></div></div><p>Für Fedora stehen die meisten der benötigten Perl-Pakete als
           RPM-Pakete zur Verfügung. Sie können mit folgendem Befehl
           installiert werden:</p><pre class="programlisting">dnf install httpd mod_fcgid postgresql-server postgresql-contrib\
   perl-Algorithm-CheckDigits perl-Archive-Zip perl-CPAN perl-Class-XSAccessor \
@@ -175,7 +170,7 @@ cpan HTML::Restrict</pre></div><div class="sect3" title="2.2.2.2. Fedora"><div c
   perl-Params-Validate perl-Regexp-IPv6 perl-Rose-DB perl-Rose-DB-Object \
   perl-Rose-Object perl-Sort-Naturally perl-String-ShellQuote \
   perl-Template-Toolkit perl-Text-CSV_XS perl-Text-Iconv perl-URI perl-XML-Writer \
-  perl-YAML perl-libwww-perl</pre></div><div class="sect3" title="2.2.2.3. openSUSE"><div class="titlepage"><div><div><h4 class="title"><a name="d0e563"></a>2.2.2.3. openSUSE</h4></div></div></div><p>Für openSUSE stehen die meisten der benötigten Perl-Pakete als
+  perl-YAML perl-libwww-perl</pre></div><div class="sect3" title="2.2.2.3. openSUSE"><div class="titlepage"><div><div><h4 class="title"><a name="d0e565"></a>2.2.2.3. openSUSE</h4></div></div></div><p>Für openSUSE stehen die meisten der benötigten Perl-Pakete als
           RPM-Pakete zur Verfügung. Sie können mit folgendem Befehl
           installiert werden:</p><pre class="programlisting">zypper install apache2 apache2-mod_fcgid postgresql-server postgresql-contrib\
   perl-Algorithm-CheckDigits perl-Archive-Zip perl-CGI perl-Class-XSAccessor \
@@ -184,13 +179,13 @@ cpan HTML::Restrict</pre></div><div class="sect3" title="2.2.2.2. Fedora"><div c
   perl-Email-MIME perl-FastCGI perl-File-Copy-Recursive perl-File-Flock \
   perl-File-MimeInfo perl-File-Slurp perl-GD perl-Image-Info perl-JSON \
   perl-List-MoreUtils perl-List-UtilsBy perl-Net-SMTP-SSL perl-Net-SSLGlue \
-  perl-PDF-API2 perl-Params-Validate perl-Regexp-IPv6 perl-Set-Crontab \
+  perl-PDF-API2 perl-Params-Validate perl-Regexp-IPv6 \
   perl-Sort-Naturally perl-String-ShellQuote perl-Template-Toolkit \
   perl-Text-CSV_XS perl-Text-Iconv perl-Text-Unidecode perl-URI \
   perl-XML-Writer perl-YAML perl-libwww-perl
           </pre><p>Zusätzlich müssen einige Pakete aus dem CPAN installiert
           werden. Dazu können Sie die folgenden Befehle nutzen:</p><pre class="programlisting">cpan DateTime::event::Cron DateTime::Set FCGI \
-  HTML::Restrict PBKDF2::Tiny Rose::Db::Object Set::Infinite</pre></div></div><div class="sect2" title="2.2.3. Andere Pakete installieren"><div class="titlepage"><div><div><h3 class="title"><a name="d0e574"></a>2.2.3. Andere Pakete installieren</h3></div></div></div><p>Seit Version v3.4.0 wird für den Bankimport optional das Paket
+  HTML::Restrict PBKDF2::Tiny Rose::Db::Object Set::Infinite</pre></div></div><div class="sect2" title="2.2.3. Andere Pakete installieren"><div class="titlepage"><div><div><h3 class="title"><a name="d0e576"></a>2.2.3. Andere Pakete installieren</h3></div></div></div><p>Seit Version v3.4.0 wird für den Bankimport optional das Paket
         'aqbanking-tools' benötigt.</p><p>Debian und Ubuntu: </p><pre class="programlisting">apt install aqbanking-tools
         </pre><p>
             </p><p>Fedora: </p><pre class="programlisting">dnf install aqbanking</pre><p>
index 7ca08d0..a2b0b30 100644 (file)
@@ -1,6 +1,6 @@
 <html><head>
       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-   <title>2.6. Webserver-Konfiguration</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.5.3: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch02.html" title="Kapitel 2. Installation und Grundkonfiguration"><link rel="prev" href="ch02s05.html" title="2.5. Anpassung der PostgreSQL-Konfiguration"><link rel="next" href="ch02s07.html" title="2.7. Der Task-Server"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">2.6. Webserver-Konfiguration</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02s05.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 2. Installation und Grundkonfiguration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02s07.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="2.6. Webserver-Konfiguration"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="Apache-Konfiguration"></a>2.6. Webserver-Konfiguration</h2></div></div></div><div class="sect2" title="2.6.1. Grundkonfiguration mittels CGI"><div class="titlepage"><div><div><h3 class="title"><a name="d0e1051"></a>2.6.1. Grundkonfiguration mittels CGI</h3></div></div></div><div class="note" title="Anmerkung" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Anmerkung]" src="system/docbook-xsl/images/note.png"></td><th align="left">Anmerkung</th></tr><tr><td align="left" valign="top"><p>Für einen deutlichen Performanceschub sorgt die Ausführung
+   <title>2.6. Webserver-Konfiguration</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.5.3: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch02.html" title="Kapitel 2. Installation und Grundkonfiguration"><link rel="prev" href="ch02s05.html" title="2.5. Anpassung der PostgreSQL-Konfiguration"><link rel="next" href="ch02s07.html" title="2.7. Der Task-Server"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">2.6. Webserver-Konfiguration</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02s05.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 2. Installation und Grundkonfiguration</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch02s07.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="2.6. Webserver-Konfiguration"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="Apache-Konfiguration"></a>2.6. Webserver-Konfiguration</h2></div></div></div><div class="sect2" title="2.6.1. Grundkonfiguration mittels CGI"><div class="titlepage"><div><div><h3 class="title"><a name="d0e1053"></a>2.6.1. Grundkonfiguration mittels CGI</h3></div></div></div><div class="note" title="Anmerkung" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Anmerkung]" src="system/docbook-xsl/images/note.png"></td><th align="left">Anmerkung</th></tr><tr><td align="left" valign="top"><p>Für einen deutlichen Performanceschub sorgt die Ausführung
           mittels FastCGI/FCGI. Die Einrichtung wird ausführlich im Abschnitt
           <a class="xref" href="ch02s06.html#Apache-Konfiguration.FCGI" title="2.6.2. Konfiguration für FastCGI/FCGI">Konfiguration für FastCGI/FCGI</a> beschrieben.</p></td></tr></table></div><p>Der Zugriff auf das Programmverzeichnis muss in der Apache
         Webserverkonfigurationsdatei <code class="literal">httpd.conf</code> eingestellt
@@ -106,13 +106,13 @@ AliasMatch ^/url/for/kivitendo-erp-fcgid/[^/]+\.pl /path/to/kivitendo-erp/dispat
 Alias       /url/for/kivitendo-erp-fcgid/          /path/to/kivitendo-erp/</pre><p>Dann ist unter <code class="filename">/url/for/kivitendo-erp/</code>
           die normale Version erreichbar, und unter
           <code class="constant">/url/for/kivitendo-erp-fcgid/</code> die
-          FastCGI-Version.</p></div></div><div class="sect2" title="2.6.3. Authentifizierung mittels HTTP Basic Authentication"><div class="titlepage"><div><div><h3 class="title"><a name="d0e1202"></a>2.6.3. Authentifizierung mittels HTTP Basic Authentication</h3></div></div></div><p>
+          FastCGI-Version.</p></div></div><div class="sect2" title="2.6.3. Authentifizierung mittels HTTP Basic Authentication"><div class="titlepage"><div><div><h3 class="title"><a name="d0e1204"></a>2.6.3. Authentifizierung mittels HTTP Basic Authentication</h3></div></div></div><p>
         Kivitendo unterstützt, dass Benutzerauthentifizierung Ã¼ber den Webserver mittels des Â»Basic«-HTTP-Authentifizierungs-Schema erfolgt
         (siehe <a class="ulink" href="https://tools.ietf.org/html/rfc7617" target="_top">RFC 7617</a>). Dazu ist es aber nötig, dass der dabei vom Client
         mitgeschickte Header <code class="constant">Authorization</code> vom Webserver an Kivitendo Ã¼ber die Umgebungsvariable
         <code class="constant">HTTP_AUTHORIZATION</code> weitergegeben wird, was standardmäßig nicht der Fall ist. Für Apache kann dies Ã¼ber die
         folgende Konfigurationsoption aktiviert werden:
-       </p><pre class="programlisting">SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1</pre></div><div class="sect2" title="2.6.4. Weitergehende Konfiguration"><div class="titlepage"><div><div><h3 class="title"><a name="d0e1218"></a>2.6.4. Weitergehende Konfiguration</h3></div></div></div><p>Für einen deutlichen Sicherheitsmehrwert sorgt die Ausführung
+       </p><pre class="programlisting">SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1</pre></div><div class="sect2" title="2.6.4. Weitergehende Konfiguration"><div class="titlepage"><div><div><h3 class="title"><a name="d0e1220"></a>2.6.4. Weitergehende Konfiguration</h3></div></div></div><p>Für einen deutlichen Sicherheitsmehrwert sorgt die Ausführung
         von kivitendo nur Ã¼ber https-verschlüsselten Verbindungen, sowie
         weiteren Zusatzmassnahmen, wie beispielsweise Basic Authenticate. Die
         Konfigurationsmöglichkeiten sprengen allerdings den Rahmen dieser
index 0dfca39..794d9c6 100644 (file)
@@ -39,7 +39,7 @@
         Links aus einem der Runlevel-Verzeichnisse heraus in den Boot-Prozess
         einzubinden. Da das bei neueren Linux-Distributionen aber nicht
         zwangsläufig funktioniert, werden auch Start-Scripte mitgeliefert, die
-        anstelle eines symbolischen Links verwendet werden können.</p><div class="sect3" title="2.7.3.1. SystemV-basierende Systeme (z.B. Ã¤ltere Debian, Ã¤ltere openSUSE, Ã¤ltere Fedora)"><div class="titlepage"><div><div><h4 class="title"><a name="d0e1292"></a>2.7.3.1. SystemV-basierende Systeme (z.B. Ã¤ltere Debian, Ã¤ltere
+        anstelle eines symbolischen Links verwendet werden können.</p><div class="sect3" title="2.7.3.1. SystemV-basierende Systeme (z.B. Ã¤ltere Debian, Ã¤ltere openSUSE, Ã¤ltere Fedora)"><div class="titlepage"><div><div><h4 class="title"><a name="d0e1294"></a>2.7.3.1. SystemV-basierende Systeme (z.B. Ã¤ltere Debian, Ã¤ltere
           openSUSE, Ã¤ltere Fedora)</h4></div></div></div><p>Kopieren Sie die Datei
           <code class="filename">scripts/boot/system-v/kivitendo-task-server</code>
           nach <code class="filename">/etc/init.d/kivitendo-task-server</code>. Passen
           <code class="literal">DAEMON=....</code>). Binden Sie das Script in den
           Boot-Prozess ein. Dies ist distributionsabhängig:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Debian-basierende Systeme:</p><pre class="programlisting">update-rc.d kivitendo-task-server defaults
 insserv kivitendo-task-server</pre></li><li class="listitem"><p>Ältere openSUSE und Ã¤ltere Fedora:</p><pre class="programlisting">chkconfig --add kivitendo-task-server</pre></li></ul></div><p>Danach kann der Task-Server mit dem folgenden Befehl gestartet
-          werden:</p><pre class="programlisting">/etc/init.d/kivitendo-task-server start</pre></div><div class="sect3" title="2.7.3.2. Upstart-basierende Systeme (z.B. Ubuntu bis 14.04)"><div class="titlepage"><div><div><h4 class="title"><a name="d0e1321"></a>2.7.3.2. Upstart-basierende Systeme (z.B. Ubuntu bis 14.04)</h4></div></div></div><p>Kopieren Sie die Datei
+          werden:</p><pre class="programlisting">/etc/init.d/kivitendo-task-server start</pre></div><div class="sect3" title="2.7.3.2. Upstart-basierende Systeme (z.B. Ubuntu bis 14.04)"><div class="titlepage"><div><div><h4 class="title"><a name="d0e1323"></a>2.7.3.2. Upstart-basierende Systeme (z.B. Ubuntu bis 14.04)</h4></div></div></div><p>Kopieren Sie die Datei
           <code class="filename">scripts/boot/upstart/kivitendo-task-server.conf</code>
           nach <code class="filename">/etc/init/kivitendo-task-server.conf</code>.
           Passen Sie in der kopierten Datei den Pfad zum Task-Server an (Zeile
           <code class="literal">exec ....</code>).</p><p>Danach kann der Task-Server mit dem folgenden Befehl gestartet
-          werden:</p><pre class="programlisting">service kivitendo-task-server start</pre></div><div class="sect3" title="2.7.3.3. systemd-basierende Systeme (z.B. neure openSUSE, neuere Fedora, neuere Ubuntu und neuere Debians)"><div class="titlepage"><div><div><h4 class="title"><a name="d0e1339"></a>2.7.3.3. systemd-basierende Systeme (z.B. neure openSUSE, neuere
+          werden:</p><pre class="programlisting">service kivitendo-task-server start</pre></div><div class="sect3" title="2.7.3.3. systemd-basierende Systeme (z.B. neure openSUSE, neuere Fedora, neuere Ubuntu und neuere Debians)"><div class="titlepage"><div><div><h4 class="title"><a name="d0e1341"></a>2.7.3.3. systemd-basierende Systeme (z.B. neure openSUSE, neuere
           Fedora, neuere Ubuntu und neuere Debians)</h4></div></div></div><p>Kopieren Sie die Datei
           <code class="filename">scripts/boot/systemd/kivitendo-task-server.service</code>
           nach <code class="filename">/etc/systemd/system/</code>. Passen Sie in der
index 026b043..de21abf 100644 (file)
       Verzeichnis umbenannt werden.</p><p>Dieses Verzeichnis, wie auch das komplette
       <code class="literal">users</code>-Verzeichnis, muss vom Webserver beschreibbar
       sein. Dieses wurde bereits erledigt (siehe <a class="xref" href="ch02s03.html" title="2.3. Manuelle Installation des Programmpaketes">Manuelle Installation des Programmpaketes</a>), kann aber erneut
-      Ã¼berprüft werden, wenn die Konvertierung nach PDF fehlschlägt.</p><div class="sect2" title="2.13.1. OpenDocument (odt) Druckvorlagen mit Makros"><div class="titlepage"><div><div><h3 class="title"><a name="d0e2383"></a>2.13.1. OpenDocument (odt) Druckvorlagen mit Makros</h3></div></div></div><p>OpenDocument Vorlagen können Makros enthalten, welche komplexere
+      Ã¼berprüft werden, wenn die Konvertierung nach PDF fehlschlägt.</p><div class="sect2" title="2.13.1. OpenDocument (odt) Druckvorlagen mit Makros"><div class="titlepage"><div><div><h3 class="title"><a name="d0e2385"></a>2.13.1. OpenDocument (odt) Druckvorlagen mit Makros</h3></div></div></div><p>OpenDocument Vorlagen können Makros enthalten, welche komplexere
         Aufgaben erfüllen.</p><p>Der Vorlagensatz "rev-odt" enthält solche Vorlagen mit <span class="bold"><strong>Schweizer Bank-Einzahlungsscheinen (BESR)</strong></span>.
         Diese Makros haben die Aufgabe, die in den Einzahlungsscheinen
         benötigte Referenznummer und Kodierzeile zu erzeugen. Hier eine kurze
         Beschreibung, wie die Makros aufgebaut sind, und was bei ihrer Nutzung
         zu beachten ist (<span class="bold"><strong>in fett sind nötige einmalige
-        Anpassungen aufgeführt</strong></span>):</p><div class="sect3" title="2.13.1.1. Bezeichnung der Vorlagen"><div class="titlepage"><div><div><h4 class="title"><a name="d0e2396"></a>2.13.1.1. Bezeichnung der Vorlagen</h4></div></div></div><p>Rechnung: invoice_besr.odt, Auftrag:
-          sales_order_besr.odt</p></div><div class="sect3" title="2.13.1.2. Vorbereitungen im Adminbereich"><div class="titlepage"><div><div><h4 class="title"><a name="d0e2401"></a>2.13.1.2. Vorbereitungen im Adminbereich</h4></div></div></div><p>Damit beim Erstellen von Rechnungen und Aufträgen neben der
+        Anpassungen aufgeführt</strong></span>):</p><div class="sect3" title="2.13.1.1. Bezeichnung der Vorlagen"><div class="titlepage"><div><div><h4 class="title"><a name="d0e2398"></a>2.13.1.1. Bezeichnung der Vorlagen</h4></div></div></div><p>Rechnung: invoice_besr.odt, Auftrag:
+          sales_order_besr.odt</p></div><div class="sect3" title="2.13.1.2. Vorbereitungen im Adminbereich"><div class="titlepage"><div><div><h4 class="title"><a name="d0e2403"></a>2.13.1.2. Vorbereitungen im Adminbereich</h4></div></div></div><p>Damit beim Erstellen von Rechnungen und Aufträgen neben der
           Standardvorlage ohne Einzahlungsschein weitere Vorlagen (z.B. mit
           Einzahlungsschein) auswählbar sind, muss für jedes Vorlagen-Suffix
           ein Drucker eingerichtet werden:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Druckeradministration â†’ Drucker hinzufügen</p></li><li class="listitem"><p>Mandant wählen</p></li><li class="listitem"><p>Druckerbeschreibung â†’ aussagekräftiger Text: wird in der
               Aufträgen oder Rechnungen als odt-Datei keine Bedeutung, darf
               aber nicht leer sein)</p></li><li class="listitem"><p>Vorlagenkürzel â†’ besr bzw. selbst gewähltes Vorlagensuffix
               (muss genau der Zeichenfolge entsprechen, die zwischen
-              "invoice_" bzw. "sales_order_" und ".odt" steht.)</p></li><li class="listitem"><p>speichern</p></li></ul></div></div><div class="sect3" title="2.13.1.3. Benutzereinstellungen"><div class="titlepage"><div><div><h4 class="title"><a name="d0e2425"></a>2.13.1.3. Benutzereinstellungen</h4></div></div></div><p>Wer den Ausdruck mit Einzahlungsschein als Standardeinstellung
+              "invoice_" bzw. "sales_order_" und ".odt" steht.)</p></li><li class="listitem"><p>speichern</p></li></ul></div></div><div class="sect3" title="2.13.1.3. Benutzereinstellungen"><div class="titlepage"><div><div><h4 class="title"><a name="d0e2427"></a>2.13.1.3. Benutzereinstellungen</h4></div></div></div><p>Wer den Ausdruck mit Einzahlungsschein als Standardeinstellung
           im Rechnungs- bzw. Auftragsformular angezeigt haben möchte, kann
           dies persönlich für sich bei den Benutzereinstellungen
           konfigurieren:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Programm â†’ Benutzereinstellungen â†’ Druckoptionen</p></li><li class="listitem"><p>Standardvorlagenformat â†’ OpenDocument/OASIS</p></li><li class="listitem"><p>Standardausgabekanal â†’ Bildschirm</p></li><li class="listitem"><p>Standarddrucker â†’ gewünschte Druckerbeschreibung auswählen
-              (z.B. mit Einzahlungsschein Bank xy)</p></li><li class="listitem"><p>Anzahl Kopien â†’ leer</p></li><li class="listitem"><p>speichern</p></li></ul></div></div><div class="sect3" title="2.13.1.4. Aufbau und nötige Anpassungen der Vorlagen"><div class="titlepage"><div><div><h4 class="title"><a name="d0e2449"></a>2.13.1.4. Aufbau und nötige Anpassungen der Vorlagen</h4></div></div></div><p>In der Vorlage sind als Modul "BESR" 4 Makros gespeichert, die
+              (z.B. mit Einzahlungsschein Bank xy)</p></li><li class="listitem"><p>Anzahl Kopien â†’ leer</p></li><li class="listitem"><p>speichern</p></li></ul></div></div><div class="sect3" title="2.13.1.4. Aufbau und nötige Anpassungen der Vorlagen"><div class="titlepage"><div><div><h4 class="title"><a name="d0e2451"></a>2.13.1.4. Aufbau und nötige Anpassungen der Vorlagen</h4></div></div></div><p>In der Vorlage sind als Modul "BESR" 4 Makros gespeichert, die
           aus dem von kivitendo erzeugten odt-Dokument die korrekte
           Referenznummer inklusive Prüfziffer sowie die Kodierzeile in
           OCRB-Schrift erzeugen und am richtigen Ort ins Dokument
               angepasst werden.</strong></span> Dabei ist darauf zu achten, dass
               sich die Positionen der Postkonto-Nummern der Bank, sowie der
               Zeichenfolgen dddfr, DDDREF1, DDDREF2, 609, DDDKODIERZEILE nicht
-              verschieben.</p></li></ul></div><div class="screenshot"><div class="mediaobject"><img src="images/Einzahlungsschein_Makro.png"></div></div></div><div class="sect3" title="2.13.1.5. Auswahl der Druckvorlage in kivitendo beim Erzeugen einer odt-Rechnung (analog bei Auftrag)"><div class="titlepage"><div><div><h4 class="title"><a name="d0e2513"></a>2.13.1.5. Auswahl der Druckvorlage in kivitendo beim Erzeugen einer
+              verschieben.</p></li></ul></div><div class="screenshot"><div class="mediaobject"><img src="images/Einzahlungsschein_Makro.png"></div></div></div><div class="sect3" title="2.13.1.5. Auswahl der Druckvorlage in kivitendo beim Erzeugen einer odt-Rechnung (analog bei Auftrag)"><div class="titlepage"><div><div><h4 class="title"><a name="d0e2515"></a>2.13.1.5. Auswahl der Druckvorlage in kivitendo beim Erzeugen einer
           odt-Rechnung (analog bei Auftrag)</h4></div></div></div><p>Im Fussbereich der Rechnungsmaske muss neben Rechnung,
           OpenDocument/OASIS und Bildschirm die im Adminbereich erstellte
           Druckerbeschreibung ausgewählt werden, falls diese nicht bereits bei
           den Benutzereinstellungen als persönlicher Standard gewählt
-          wurde.</p></div><div class="sect3" title="2.13.1.6. Makroeinstellungen in LibreOffice anpassen"><div class="titlepage"><div><div><h4 class="title"><a name="d0e2518"></a>2.13.1.6. Makroeinstellungen in LibreOffice anpassen</h4></div></div></div><p>Falls beim Ã–ffnen einer von kivitendo erzeugten odt-Rechnung
+          wurde.</p></div><div class="sect3" title="2.13.1.6. Makroeinstellungen in LibreOffice anpassen"><div class="titlepage"><div><div><h4 class="title"><a name="d0e2520"></a>2.13.1.6. Makroeinstellungen in LibreOffice anpassen</h4></div></div></div><p>Falls beim Ã–ffnen einer von kivitendo erzeugten odt-Rechnung
           die Meldung kommt, dass Makros aus Sicherheitsgründen nicht
           ausgeführt werden, so müssen folgende Einstellungen in LibreOffice
           angepasst werden:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Extras â†’ Optionen â†’ Sicherheit â†’ Makrosicherheit</p></li><li class="listitem"><p>Sicherheitslevel auf "Mittel" einstellen (Diese
index 628bc90..4f34a8b 100644 (file)
                         <code class="varname">invdate</code>
                      </span></dt><dd><p>Rechnungsdatum</p></dd><dt><span class="term">
                         <code class="varname">invnumber</code>
-                     </span></dt><dd><p>Rechnungsnummer</p></dd></dl></div></div></div><div class="sect2" title="3.3.10. Variablen in anderen Vorlagen"><div class="titlepage"><div><div><h3 class="title"><a name="dokumentenvorlagen-und-variablen.andere-vorlagen"></a>3.3.10. Variablen in anderen Vorlagen</h3></div></div></div><div class="sect3" title="3.3.10.1. Einführung"><div class="titlepage"><div><div><h4 class="title"><a name="d0e5785"></a>3.3.10.1. Einführung</h4></div></div></div><p>Die Variablen in anderen Vorlagen sind Ã¤hnlich wie in der
+                     </span></dt><dd><p>Rechnungsnummer</p></dd></dl></div></div></div><div class="sect2" title="3.3.10. Variablen in anderen Vorlagen"><div class="titlepage"><div><div><h3 class="title"><a name="dokumentenvorlagen-und-variablen.andere-vorlagen"></a>3.3.10. Variablen in anderen Vorlagen</h3></div></div></div><div class="sect3" title="3.3.10.1. Einführung"><div class="titlepage"><div><div><h4 class="title"><a name="d0e5787"></a>3.3.10.1. Einführung</h4></div></div></div><p>Die Variablen in anderen Vorlagen sind Ã¤hnlich wie in der
           Rechnung. Allerdings heißen die Variablen, die mit
           <code class="varname">inv</code> beginnen, jetzt anders. Bei den Angeboten
           fangen sie mit <code class="varname">quo</code> für "quotation" an:
index cebc533..f0c50a7 100644 (file)
@@ -1,15 +1,15 @@
 <html><head>
       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-   <title>3.7. Artikelklassifizierung</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.5.3: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch03.html" title="Kapitel 3. Features und Funktionen"><link rel="prev" href="ch03s06.html" title="3.6. Schweizer Kontenpläne"><link rel="next" href="ch03s08.html" title="3.8. Dateiverwaltung (Mini-DMS)"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">3.7. Artikelklassifizierung</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch03s06.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 3. Features und Funktionen</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch03s08.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="3.7. Artikelklassifizierung"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="features.part_classification"></a>3.7. Artikelklassifizierung</h2></div></div></div><div class="sect2" title="3.7.1. Ãœbersicht"><div class="titlepage"><div><div><h3 class="title"><a name="d0e6453"></a>3.7.1. Ãœbersicht</h3></div></div></div><p>Die Klassifizierung von Artikeln dient einer weiteren
+   <title>3.7. Artikelklassifizierung</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.5.3: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch03.html" title="Kapitel 3. Features und Funktionen"><link rel="prev" href="ch03s06.html" title="3.6. Schweizer Kontenpläne"><link rel="next" href="ch03s08.html" title="3.8. Dateiverwaltung (Mini-DMS)"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">3.7. Artikelklassifizierung</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch03s06.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 3. Features und Funktionen</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch03s08.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="3.7. Artikelklassifizierung"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="features.part_classification"></a>3.7. Artikelklassifizierung</h2></div></div></div><div class="sect2" title="3.7.1. Ãœbersicht"><div class="titlepage"><div><div><h3 class="title"><a name="d0e6455"></a>3.7.1. Ãœbersicht</h3></div></div></div><p>Die Klassifizierung von Artikeln dient einer weiteren
         Gliederung, um zum Beispiel den Einkauf vom Verkauf zu trennen,
         gekennzeichnet durch eine Beschreibung (z.B. "Einkauf") und ein Kürzel
         (z.B. "E"). Für jede Klassifizierung besteht eine Beschreibung und
         eine Abkürzung die normalerweise aus einem Zeichen besteht, kann aber
         auf mehrere Zeichen erweitert werden, falls zur Unterscheidung
-        notwendig. Sinnvoll sind jedoch nur maximal 2 Zeichen.</p></div><div class="sect2" title="3.7.2. Basisklassifizierung"><div class="titlepage"><div><div><h3 class="title"><a name="d0e6458"></a>3.7.2. Basisklassifizierung</h3></div></div></div><p>Als Basisklassifizierungen gibt es</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Einkauf</p></li><li class="listitem"><p>Verkauf</p></li><li class="listitem"><p>Handelsware</p></li><li class="listitem"><p>Produktion</p></li><li class="listitem"><p>- keine - (diese wird bei einer Aktualisierung für alle
+        notwendig. Sinnvoll sind jedoch nur maximal 2 Zeichen.</p></div><div class="sect2" title="3.7.2. Basisklassifizierung"><div class="titlepage"><div><div><h3 class="title"><a name="d0e6460"></a>3.7.2. Basisklassifizierung</h3></div></div></div><p>Als Basisklassifizierungen gibt es</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Einkauf</p></li><li class="listitem"><p>Verkauf</p></li><li class="listitem"><p>Handelsware</p></li><li class="listitem"><p>Produktion</p></li><li class="listitem"><p>- keine - (diese wird bei einer Aktualisierung für alle
             existierenden Artikel verwendet und ist gültig für Verkauf und
             Einkauf)</p></li></ul></div><p>Es können weitere Klassifizierungen angelegt werden. So kann es
-        z.B. für separat auszuweisende Artikel folgende Klassen geben:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Lieferung (Logistik, Transport) mit Kürzel L</p></li><li class="listitem"><p>Material (Verpackungsmaterial) mit Kürzel M</p></li></ul></div></div><div class="sect2" title="3.7.3. Attribute"><div class="titlepage"><div><div><h3 class="title"><a name="d0e6488"></a>3.7.3. Attribute</h3></div></div></div><p>Bisher haben die Klassifizierungen folgende Attribute, die auch
+        z.B. für separat auszuweisende Artikel folgende Klassen geben:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Lieferung (Logistik, Transport) mit Kürzel L</p></li><li class="listitem"><p>Material (Verpackungsmaterial) mit Kürzel M</p></li></ul></div></div><div class="sect2" title="3.7.3. Attribute"><div class="titlepage"><div><div><h3 class="title"><a name="d0e6490"></a>3.7.3. Attribute</h3></div></div></div><p>Bisher haben die Klassifizierungen folgende Attribute, die auch
         alle gleichzeitg gültig sein können</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>gültig für Verkauf - dieser Artikel kann im Verkauf genutzt
             werden</p></li><li class="listitem"><p>gültig für Einkauf - dieser Artikel kann im Einkauf genutzt
             werden</p></li><li class="listitem"><p>separat ausweisen - hierzu gibt es zur Dokumentengenerierung
@@ -19,7 +19,7 @@
         pro separat auszuweisenden Klassifizierungen die Variable<span class="bold"><strong>&lt; %separate_X_subtotal%&gt;</strong></span>, wobei X das
         Kürzel der Klassifizierung ist.</p><p>Im obigen Beispiel wäre das für Lieferkosten <span class="bold"><strong>&lt;%separate_L_subtotal%&gt;</strong></span> und für
         Verpackungsmaterial <span class="bold"><strong>
-        &lt;%separate_M_subtotal%&gt;</strong></span>.</p></div><div class="sect2" title="3.7.4. Zwei-Zeichen Abkürzung"><div class="titlepage"><div><div><h3 class="title"><a name="d0e6519"></a>3.7.4. Zwei-Zeichen Abkürzung</h3></div></div></div><p>Der Typ des Artikels und die Klassifizierung werden durch zwei
+        &lt;%separate_M_subtotal%&gt;</strong></span>.</p></div><div class="sect2" title="3.7.4. Zwei-Zeichen Abkürzung"><div class="titlepage"><div><div><h3 class="title"><a name="d0e6521"></a>3.7.4. Zwei-Zeichen Abkürzung</h3></div></div></div><p>Der Typ des Artikels und die Klassifizierung werden durch zwei
         Buchstaben dargestellt. Der erste Buchstabe ist eine Lokalisierung des
         Artikel-Typs ('P','A','S'), deutsch 'W', 'E', und 'D' für Ware
         Erzeugnis oder Dienstleistung und ggf. weiterer Typen.</p><p>Der zweite Buchstabe (und ggf. auch ein dritter, falls nötig)
index d3d3ecb..ed7a241 100644 (file)
@@ -1,10 +1,10 @@
 <html><head>
       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-   <title>3.8. Dateiverwaltung (Mini-DMS)</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.5.3: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch03.html" title="Kapitel 3. Features und Funktionen"><link rel="prev" href="ch03s07.html" title="3.7. Artikelklassifizierung"><link rel="next" href="ch03s09.html" title="3.9. Webshop-Api"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">3.8. Dateiverwaltung (Mini-DMS)</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch03s07.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 3. Features und Funktionen</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch03s09.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="3.8. Dateiverwaltung (Mini-DMS)"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="features.file_managment"></a>3.8. Dateiverwaltung (Mini-DMS)</h2></div></div></div><div class="sect2" title="3.8.1. Ãœbersicht"><div class="titlepage"><div><div><h3 class="title"><a name="d0e6531"></a>3.8.1. Ãœbersicht</h3></div></div></div><p>Parallel zum alten WebDAV gibt es ein Datei-Management-System,
+   <title>3.8. Dateiverwaltung (Mini-DMS)</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.5.3: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch03.html" title="Kapitel 3. Features und Funktionen"><link rel="prev" href="ch03s07.html" title="3.7. Artikelklassifizierung"><link rel="next" href="ch03s09.html" title="3.9. Webshop-Api"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">3.8. Dateiverwaltung (Mini-DMS)</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch03s07.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 3. Features und Funktionen</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch03s09.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="3.8. Dateiverwaltung (Mini-DMS)"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="features.file_managment"></a>3.8. Dateiverwaltung (Mini-DMS)</h2></div></div></div><div class="sect2" title="3.8.1. Ãœbersicht"><div class="titlepage"><div><div><h3 class="title"><a name="d0e6533"></a>3.8.1. Ãœbersicht</h3></div></div></div><p>Parallel zum alten WebDAV gibt es ein Datei-Management-System,
         das Dateien verschiedenen Typs verwaltet. Dies können</p><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem"><p>aus ERP-Daten per LaTeX Template erzeugte
             PDF-Dokumente,</p></li><li class="listitem"><p>zu bestimmten ERP-Daten gehörende Anhangdateien
             unterschiedlichen Formats,</p></li><li class="listitem"><p>per Scanner eingelesene PDF-Dateien,</p></li><li class="listitem"><p>per E-Mail empfangene Dateianhänge unterschiedlichen
-            Formats,</p></li><li class="listitem"><p>sowie speziel für Artikel hochgeladene Bilder sein.</p></li></ol></div><div class="screenshot"><div class="mediaobject"><img src="images/DMS-Overview.png"></div></div></div><div class="sect2" title="3.8.2. Struktur"><div class="titlepage"><div><div><h3 class="title"><a name="d0e6558"></a>3.8.2. Struktur</h3></div></div></div><p>Ãœber eine vom Speichermedium unabhängige Zwischenschicht werden
+            Formats,</p></li><li class="listitem"><p>sowie speziel für Artikel hochgeladene Bilder sein.</p></li></ol></div><div class="screenshot"><div class="mediaobject"><img src="images/DMS-Overview.png"></div></div></div><div class="sect2" title="3.8.2. Struktur"><div class="titlepage"><div><div><h3 class="title"><a name="d0e6560"></a>3.8.2. Struktur</h3></div></div></div><p>Ãœber eine vom Speichermedium unabhängige Zwischenschicht werden
         die Dateien und ihre Versionen in der Datenbank verwaltet. Darunter
         können verschiedene Implementierungen (Backends) gleichzeitig
         existieren:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Dateisystem</p></li><li class="listitem"><p>WebDAV</p></li><li class="listitem"><p>Schnittstelle zu externen
@@ -23,7 +23,7 @@
         für "attachment" und "image" nur die Quelle "uploaded". Für "document"
         gibt es auf jeden Fall die Quelle "created". Die Quellen "scanner" und
         "email" müssen derzeit in der Datenbank konfiguriert werden (siehe
-        <a class="xref" href="ch03s08.html#file_management.dbconfig" title="3.8.4.2. Datenbank-Konfigurierung">Datenbank-Konfigurierung</a>).</p></div><div class="sect2" title="3.8.3. Anwendung"><div class="titlepage"><div><div><h3 class="title"><a name="d0e6610"></a>3.8.3. Anwendung</h3></div></div></div><p>Die Daten werden bei den ERP-Objekten als extra Reiter
+        <a class="xref" href="ch03s08.html#file_management.dbconfig" title="3.8.4.2. Datenbank-Konfigurierung">Datenbank-Konfigurierung</a>).</p></div><div class="sect2" title="3.8.3. Anwendung"><div class="titlepage"><div><div><h3 class="title"><a name="d0e6612"></a>3.8.3. Anwendung</h3></div></div></div><p>Die Daten werden bei den ERP-Objekten als extra Reiter
         dargestellt. Eine Verkaufsrechnung z.B. hat die Reiter "Dokumente" und
         "Dateianhänge".</p><div class="screenshot"><div class="mediaobject"><img src="images/DMS-Anhaenge.png"></div></div><p>Bei den Dateianhängen wird immer nur die aktuelle Version einer
         Datei angezeigt. Wird eine Datei mit gleichem Namen hochgeladen, so
         so sind diese z.B. bei Einkaufsrechnungen sichtbar:</p><div class="screenshot"><div class="mediaobject"><img src="images/DMS-Dokumente-Scanner.png"></div></div><p>Statt des Löschens wird hier die Datei zurück zur Quelle
         verschoben. Somit kann die Datei anschließend an ein anderes
         ERP-Objekt angehängt werden.</p><p>Derzeit sind "Titel" und "Beschreibung" noch nicht genutzt. Sie
-        sind bisher nur bei Bildern relevant.</p></div><div class="sect2" title="3.8.4. Konfigurierung"><div class="titlepage"><div><div><h3 class="title"><a name="d0e6653"></a>3.8.4. Konfigurierung</h3></div></div></div><div class="sect3" title="3.8.4.1. Mandantenkonfiguration"><div class="titlepage"><div><div><h4 class="title"><a name="file_management.clientconfig"></a>3.8.4.1. Mandantenkonfiguration</h4></div></div></div><div class="sect4" title="3.8.4.1.1. Reiter &#34;Features&#34;"><div class="titlepage"><div><div><h5 class="title"><a name="d0e6659"></a>3.8.4.1.1. Reiter "Features"</h5></div></div></div><p>Unter dem Reiter <span class="bold"><strong>Features</strong></span>
+        sind bisher nur bei Bildern relevant.</p></div><div class="sect2" title="3.8.4. Konfigurierung"><div class="titlepage"><div><div><h3 class="title"><a name="d0e6655"></a>3.8.4. Konfigurierung</h3></div></div></div><div class="sect3" title="3.8.4.1. Mandantenkonfiguration"><div class="titlepage"><div><div><h4 class="title"><a name="file_management.clientconfig"></a>3.8.4.1. Mandantenkonfiguration</h4></div></div></div><div class="sect4" title="3.8.4.1.1. Reiter &#34;Features&#34;"><div class="titlepage"><div><div><h5 class="title"><a name="d0e6661"></a>3.8.4.1.1. Reiter "Features"</h5></div></div></div><p>Unter dem Reiter <span class="bold"><strong>Features</strong></span>
             im Abschnitt Dateimanagement ist neben dem "alten" WebDAV das
             Dateimangement generell zu- und abschaltbar, sowie die Zuordnung
             der Dateitypen zu Backends. Die Löschbarkeit von Dateien, sowie
             die maximale Uploadgröße sind Backend-unabhängig</p><div class="screenshot"><div class="mediaobject"><img src="images/DMS-ClientConfig.png"></div></div><p>Die einzelnen Backends sind einzeln einschaltbar.
             Spezifische Backend-Konfigurierungen sind hier noch
-            ergänzbar.</p></div><div class="sect4" title="3.8.4.1.2. Reiter &#34;Allgemeine Dokumentenanhänge&#34;"><div class="titlepage"><div><div><h5 class="title"><a name="d0e6675"></a>3.8.4.1.2. Reiter "Allgemeine Dokumentenanhänge"</h5></div></div></div><p>Unter dem Reiter <span class="bold"><strong>Allgemeine
+            ergänzbar.</p></div><div class="sect4" title="3.8.4.1.2. Reiter &#34;Allgemeine Dokumentenanhänge&#34;"><div class="titlepage"><div><div><h5 class="title"><a name="d0e6677"></a>3.8.4.1.2. Reiter "Allgemeine Dokumentenanhänge"</h5></div></div></div><p>Unter dem Reiter <span class="bold"><strong>Allgemeine
             Dokumentenanhänge</strong></span> kann für alle ERP-Dokumente (
             Angebote, Aufträge, Lieferscheine, Rechnungen im Verkauf und
             Einkauf ) allgemeingültige Anhänge hochgeladen werden.</p><div class="screenshot"><div class="mediaobject"><img src="images/DMS-Allgemeine-Dokumentenanhaenge.png"></div></div><p>Diese Anhänge werden beim Generieren von PDF-Dateien an die
index 612816b..a436ded 100644 (file)
@@ -1,13 +1,13 @@
 <html><head>
       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-   <title>3.9. Webshop-Api</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.5.3: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch03.html" title="Kapitel 3. Features und Funktionen"><link rel="prev" href="ch03s08.html" title="3.8. Dateiverwaltung (Mini-DMS)"><link rel="next" href="ch04.html" title="Kapitel 4. Entwicklerdokumentation"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">3.9. Webshop-Api</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch03s08.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 3. Features und Funktionen</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch04.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="3.9. Webshop-Api"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e6709"></a>3.9. Webshop-Api</h2></div></div></div><p>Das Shopmodul bietet die Möglichkeit Onlineshopartikel und
+   <title>3.9. Webshop-Api</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.5.3: Installation, Konfiguration, Entwicklung"><link rel="up" href="ch03.html" title="Kapitel 3. Features und Funktionen"><link rel="prev" href="ch03s08.html" title="3.8. Dateiverwaltung (Mini-DMS)"><link rel="next" href="ch04.html" title="Kapitel 4. Entwicklerdokumentation"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">3.9. Webshop-Api</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch03s08.html">Zurück</a>&nbsp;</td><th width="60%" align="center">Kapitel 3. Features und Funktionen</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch04.html">Weiter</a></td></tr></table><hr></div><div class="sect1" title="3.9. Webshop-Api"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e6711"></a>3.9. Webshop-Api</h2></div></div></div><p>Das Shopmodul bietet die Möglichkeit Onlineshopartikel und
       Onlineshopbestellungen zu verwalten und zu bearbeiten.</p><p>Es ist Multishopfähig, d.h. Artikel können mehreren oder
       unterschiedlichen Shops zugeordnet werden. Bestellungen können aus
       mehreren Shops geholt werden.</p><p>Zur Zeit bietet das Modul nur einen Connector zur REST-Api von
       Shopware. Weitere Connectoren können dazu programmiert und eingerichtet
-      werden.</p><div class="sect2" title="3.9.1. Rechte für die Webshopapi"><div class="titlepage"><div><div><h3 class="title"><a name="d0e6718"></a>3.9.1. Rechte für die Webshopapi</h3></div></div></div><p>In der Administration können folgende Rechte vergeben
-        werden</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Webshopartikel anlegen und bearbeiten</p></li><li class="listitem"><p>Shopbestellungen holen und bearbeiten</p></li><li class="listitem"><p>Shop anlegen und bearbeiten</p></li></ul></div></div><div class="sect2" title="3.9.2. Konfiguration"><div class="titlepage"><div><div><h3 class="title"><a name="d0e6733"></a>3.9.2. Konfiguration</h3></div></div></div><p>Unter System-&gt;Webshops können Shops angelegt und konfiguriert
-        werden</p><div class="mediaobject"><img src="images/Shop_Listing.png"></div></div><div class="sect2" title="3.9.3. Webshopartikel"><div class="titlepage"><div><div><h3 class="title"><a name="d0e6741"></a>3.9.3. Webshopartikel</h3></div></div></div><div class="sect3" title="3.9.3.1. Shopvariablenreiter in Artikelstammdaten"><div class="titlepage"><div><div><h4 class="title"><a name="d0e6744"></a>3.9.3.1. Shopvariablenreiter in Artikelstammdaten</h4></div></div></div><p>Mit dem Recht "Shopartikel anlegen und bearbeiten" und des
+      werden.</p><div class="sect2" title="3.9.1. Rechte für die Webshopapi"><div class="titlepage"><div><div><h3 class="title"><a name="d0e6720"></a>3.9.1. Rechte für die Webshopapi</h3></div></div></div><p>In der Administration können folgende Rechte vergeben
+        werden</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Webshopartikel anlegen und bearbeiten</p></li><li class="listitem"><p>Shopbestellungen holen und bearbeiten</p></li><li class="listitem"><p>Shop anlegen und bearbeiten</p></li></ul></div></div><div class="sect2" title="3.9.2. Konfiguration"><div class="titlepage"><div><div><h3 class="title"><a name="d0e6735"></a>3.9.2. Konfiguration</h3></div></div></div><p>Unter System-&gt;Webshops können Shops angelegt und konfiguriert
+        werden</p><div class="mediaobject"><img src="images/Shop_Listing.png"></div></div><div class="sect2" title="3.9.3. Webshopartikel"><div class="titlepage"><div><div><h3 class="title"><a name="d0e6743"></a>3.9.3. Webshopartikel</h3></div></div></div><div class="sect3" title="3.9.3.1. Shopvariablenreiter in Artikelstammdaten"><div class="titlepage"><div><div><h4 class="title"><a name="d0e6746"></a>3.9.3.1. Shopvariablenreiter in Artikelstammdaten</h4></div></div></div><p>Mit dem Recht "Shopartikel anlegen und bearbeiten" und des
           Markers <span class="bold"><strong>"Shopartikel" in den Basisdaten
           </strong></span>zeigt sich der Reiter "Shopvariablen" in den
           Artikelstammdaten. Hier können jetzt die Artikel mit
           Stelle können auch beliebig viele Bilder dem Shopartikel zugeordnet
           werden. Artikelbilder gelten für alle Shops.</p><div class="mediaobject"><img src="images/Shop_Artikel.png"></div><p>Die Artikelgruppen werden direkt vom Shopsystem geholt somit
           ist es möglich einen Artikel auch mehreren Gruppen
-          zuzuordenen</p></div><div class="sect3" title="3.9.3.2. Shopartikelliste"><div class="titlepage"><div><div><h4 class="title"><a name="d0e6757"></a>3.9.3.2. Shopartikelliste</h4></div></div></div><p>Unter dem Menu Webshop-&gt;Webshop Artikel hat man nochmal
+          zuzuordenen</p></div><div class="sect3" title="3.9.3.2. Shopartikelliste"><div class="titlepage"><div><div><h4 class="title"><a name="d0e6759"></a>3.9.3.2. Shopartikelliste</h4></div></div></div><p>Unter dem Menu Webshop-&gt;Webshop Artikel hat man nochmal
           eine Gesamtübersicht. Von hier aus ist es möglich Artikel im Stapel
           unter verschiedenen Kriterien &lt;alles&gt;&lt;nur Preis&gt;&lt;nur
           Bestand&gt;&lt;Preis und Bestand&gt; an die jeweiligen Shops
-          hochzuladen.</p><div class="mediaobject"><img src="images/Shop_Artikel_Listing.png"></div></div></div><div class="sect2" title="3.9.4. Bestellimport"><div class="titlepage"><div><div><h3 class="title"><a name="d0e6765"></a>3.9.4. Bestellimport</h3></div></div></div><p>Unter dem Menupunkt Webshop-&gt;Webshop Import Ã¶ffnet sich die
+          hochzuladen.</p><div class="mediaobject"><img src="images/Shop_Artikel_Listing.png"></div></div></div><div class="sect2" title="3.9.4. Bestellimport"><div class="titlepage"><div><div><h3 class="title"><a name="d0e6767"></a>3.9.4. Bestellimport</h3></div></div></div><p>Unter dem Menupunkt Webshop-&gt;Webshop Import Ã¶ffnet sich die
         Bestellimportsliste. Hier ist sind Möglichkeiten gegeben Neue
         Bestellungen vom Shop abzuholen, geholte Bestellungen im Stapel oder
         einzeln als Auftrag zu transferieren. Die Liste kann nach
@@ -52,7 +52,7 @@
             auch der Grund für die Auftragssperre sein.</p></li><li class="listitem"><p>Die Buttons "Auftrag erstellen" und "Kunde mit
             Rechnungsadresse Ã¼berschreiben" zeigen sich erst, wenn ein Kunde
             aus dem Listing ausgewählt ist.</p></li><li class="listitem"><p>Es ist aber möglich die Shopbestellung zu löschen.</p></li><li class="listitem"><p>Ist eine Bestellung schon Ã¼bernommen, zeigen sich an dieser
-            Stelle, die dazugehörigen Belegverknüpfungen.</p></li></ul></div></div><div class="sect2" title="3.9.5. Mapping der Daten"><div class="titlepage"><div><div><h3 class="title"><a name="d0e6818"></a>3.9.5. Mapping der Daten</h3></div></div></div><p>Das Mapping der kivitendo Daten mit den Shopdaten geschieht in
+            Stelle, die dazugehörigen Belegverknüpfungen.</p></li></ul></div></div><div class="sect2" title="3.9.5. Mapping der Daten"><div class="titlepage"><div><div><h3 class="title"><a name="d0e6820"></a>3.9.5. Mapping der Daten</h3></div></div></div><p>Das Mapping der kivitendo Daten mit den Shopdaten geschieht in
         der Datei SL/ShopConnector/&lt;SHOPCONNECTORNAME&gt;.pm
         z.B.:SL/ShopConnector/Shopware.pm</p><p>In dieser Datei gibt es einen Bereich wo die Bestellpostionen,
         die Bestellkopfdaten und die Artikeldaten gemapt werden. In dieser
index 8015de7..99cf2ee 100644 (file)
@@ -1,6 +1,6 @@
 <html><head>
       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-   <title>Kapitel 4. Entwicklerdokumentation</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.5.3: Installation, Konfiguration, Entwicklung"><link rel="up" href="index.html" title="kivitendo 3.5.3: Installation, Konfiguration, Entwicklung"><link rel="prev" href="ch03s09.html" title="3.9. Webshop-Api"><link rel="next" href="ch04s02.html" title="4.2. Entwicklung unter FastCGI"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Kapitel 4. Entwicklerdokumentation</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch03s09.html">Zurück</a>&nbsp;</td><th width="60%" align="center">&nbsp;</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch04s02.html">Weiter</a></td></tr></table><hr></div><div class="chapter" title="Kapitel 4. Entwicklerdokumentation"><div class="titlepage"><div><div><h2 class="title"><a name="d0e6828"></a>Kapitel 4. Entwicklerdokumentation</h2></div></div></div><div class="sect1" title="4.1. Globale Variablen"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="devel.globals"></a>4.1. Globale Variablen</h2></div></div></div><div class="sect2" title="4.1.1. Wie sehen globale Variablen in Perl aus?"><div class="titlepage"><div><div><h3 class="title"><a name="d0e6834"></a>4.1.1. Wie sehen globale Variablen in Perl aus?</h3></div></div></div><p>Globale Variablen liegen in einem speziellen namespace namens
+   <title>Kapitel 4. Entwicklerdokumentation</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.5.3: Installation, Konfiguration, Entwicklung"><link rel="up" href="index.html" title="kivitendo 3.5.3: Installation, Konfiguration, Entwicklung"><link rel="prev" href="ch03s09.html" title="3.9. Webshop-Api"><link rel="next" href="ch04s02.html" title="4.2. Entwicklung unter FastCGI"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Kapitel 4. Entwicklerdokumentation</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch03s09.html">Zurück</a>&nbsp;</td><th width="60%" align="center">&nbsp;</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch04s02.html">Weiter</a></td></tr></table><hr></div><div class="chapter" title="Kapitel 4. Entwicklerdokumentation"><div class="titlepage"><div><div><h2 class="title"><a name="d0e6830"></a>Kapitel 4. Entwicklerdokumentation</h2></div></div></div><div class="sect1" title="4.1. Globale Variablen"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="devel.globals"></a>4.1. Globale Variablen</h2></div></div></div><div class="sect2" title="4.1.1. Wie sehen globale Variablen in Perl aus?"><div class="titlepage"><div><div><h3 class="title"><a name="d0e6836"></a>4.1.1. Wie sehen globale Variablen in Perl aus?</h3></div></div></div><p>Globale Variablen liegen in einem speziellen namespace namens
         "main", der von Ã¼berall erreichbar ist. Darüber hinaus sind bareword
         globs global und die meisten speziellen Variablen sind...
         speziell.</p><p>Daraus ergeben sich folgende Formen:</p><div class="variablelist"><dl><dt><span class="term">
@@ -25,7 +25,7 @@
               <code class="varname">$PACKAGE::form</code>.</p></dd><dt><span class="term">
                      <code class="literal">local $form</code>
                   </span></dt><dd><p>Alle Ã„nderungen an <code class="varname">$form</code> werden am Ende
-              des scopes zurückgesetzt</p></dd></dl></div></div><div class="sect2" title="4.1.2. Warum sind globale Variablen ein Problem?"><div class="titlepage"><div><div><h3 class="title"><a name="d0e6935"></a>4.1.2. Warum sind globale Variablen ein Problem?</h3></div></div></div><p>Das erste Problem ist <span class="productname">FCGI</span>â„¢.</p><p>
+              des scopes zurückgesetzt</p></dd></dl></div></div><div class="sect2" title="4.1.2. Warum sind globale Variablen ein Problem?"><div class="titlepage"><div><div><h3 class="title"><a name="d0e6937"></a>4.1.2. Warum sind globale Variablen ein Problem?</h3></div></div></div><p>Das erste Problem ist <span class="productname">FCGI</span>â„¢.</p><p>
                <span class="productname">SQL-Ledger</span>â„¢ hat fast alles im globalen
         namespace abgelegt, und erwartet, dass es da auch wiederzufinden ist.
         Unter <span class="productname">FCGI</span>â„¢ müssen diese Sachen aber wieder
@@ -39,7 +39,7 @@
         dies hat, seit der Einführung, u.a. schon so manche langwierige
         Bug-Suche verkürzt. Da globale Variablen aber implizit mit Package
         angegeben werden, werden die nicht geprüft, und somit kann sich
-        schnell ein Tippfehler einschleichen.</p></div><div class="sect2" title="4.1.3. Kanonische globale Variablen"><div class="titlepage"><div><div><h3 class="title"><a name="d0e6968"></a>4.1.3. Kanonische globale Variablen</h3></div></div></div><p>Um dieses Problem im Griff zu halten gibt es einige wenige
+        schnell ein Tippfehler einschleichen.</p></div><div class="sect2" title="4.1.3. Kanonische globale Variablen"><div class="titlepage"><div><div><h3 class="title"><a name="d0e6970"></a>4.1.3. Kanonische globale Variablen</h3></div></div></div><p>Um dieses Problem im Griff zu halten gibt es einige wenige
         globale Variablen, die kanonisch sind, d.h. sie haben bestimmte
         vorgegebenen Eigenschaften, und alles andere sollte anderweitig
         umhergereicht werden.</p><p>Diese Variablen sind im Moment die folgenden neun:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>
@@ -62,7 +62,7 @@
                      <code class="varname">$::request</code>
                   </p></li></ul></div><p>Damit diese nicht erneut als Müllhalde missbraucht werden, im
         Folgenden eine kurze Erläuterung der bestimmten vorgegebenen
-        Eigenschaften (Konventionen):</p><div class="sect3" title="4.1.3.1. $::form"><div class="titlepage"><div><div><h4 class="title"><a name="d0e7032"></a>4.1.3.1. $::form</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Ist ein Objekt der Klasse
+        Eigenschaften (Konventionen):</p><div class="sect3" title="4.1.3.1. $::form"><div class="titlepage"><div><div><h4 class="title"><a name="d0e7034"></a>4.1.3.1. $::form</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Ist ein Objekt der Klasse
               "<code class="classname">Form</code>"</p></li><li class="listitem"><p>Wird nach jedem Request gelöscht</p></li><li class="listitem"><p>Muss auch in Tests und Konsolenscripts vorhanden
               sein.</p></li><li class="listitem"><p>Enthält am Anfang eines Requests die Requestparameter vom
               User</p></li><li class="listitem"><p>Kann zwar intern Ã¼ber Requestgrenzen ein Datenbankhandle
   push @{ $form-&gt;{TEMPLATE_ARRAYS}{number} },          $form-&gt;{"partnumber_$i"};
   push @{ $form-&gt;{TEMPLATE_ARRAYS}{description} },     $form-&gt;{"description_$i"};
   # ...
-}</pre></div><div class="sect3" title="4.1.3.2. %::myconfig"><div class="titlepage"><div><div><h4 class="title"><a name="d0e7116"></a>4.1.3.2. %::myconfig</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Das einzige Hash unter den globalen Variablen</p></li><li class="listitem"><p>Wird spätestens benötigt wenn auf die Datenbank
+}</pre></div><div class="sect3" title="4.1.3.2. %::myconfig"><div class="titlepage"><div><div><h4 class="title"><a name="d0e7118"></a>4.1.3.2. %::myconfig</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Das einzige Hash unter den globalen Variablen</p></li><li class="listitem"><p>Wird spätestens benötigt wenn auf die Datenbank
               zugegriffen wird</p></li><li class="listitem"><p>Wird bei jedem Request neu erstellt.</p></li><li class="listitem"><p>Enthält die Userdaten des aktuellen Logins</p></li><li class="listitem"><p>Sollte nicht ohne Filterung irgendwo gedumpt werden oder
               extern serialisiert werden, weil da auch der Datenbankzugriff
               für diesen user drinsteht.</p></li><li class="listitem"><p>Enthält unter anderem Datumsformat dateformat und
           Ã¼berwiegend die Daten, die sich unter <span class="guimenu">Programm</span>
           -&gt; <span class="guimenuitem">Einstellungen</span> befinden, bzw. die
           Informationen Ã¼ber den Benutzer die Ã¼ber die
-          Administrator-Schnittstelle eingegeben wurden.</p></div><div class="sect3" title="4.1.3.3. $::locale"><div class="titlepage"><div><div><h4 class="title"><a name="d0e7155"></a>4.1.3.3. $::locale</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Objekt der Klasse "Locale"</p></li><li class="listitem"><p>Wird pro Request erstellt</p></li><li class="listitem"><p>Muss auch für Tests und Scripte immer verfügbar
+          Administrator-Schnittstelle eingegeben wurden.</p></div><div class="sect3" title="4.1.3.3. $::locale"><div class="titlepage"><div><div><h4 class="title"><a name="d0e7157"></a>4.1.3.3. $::locale</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Objekt der Klasse "Locale"</p></li><li class="listitem"><p>Wird pro Request erstellt</p></li><li class="listitem"><p>Muss auch für Tests und Scripte immer verfügbar
               sein.</p></li><li class="listitem"><p>Cached intern Ã¼ber Requestgrenzen hinweg benutzte
               Locales</p></li></ul></div><p>Lokalisierung für den aktuellen User. Alle Ãœbersetzungen,
-          Zahlen- und Datumsformatierungen laufen Ã¼ber dieses Objekt.</p></div><div class="sect3" title="4.1.3.4. $::lxdebug"><div class="titlepage"><div><div><h4 class="title"><a name="d0e7173"></a>4.1.3.4. $::lxdebug</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Objekt der Klasse "LXDebug"</p></li><li class="listitem"><p>Wird global gecached</p></li><li class="listitem"><p>Muss immer verfügbar sein, in nahezu allen
+          Zahlen- und Datumsformatierungen laufen Ã¼ber dieses Objekt.</p></div><div class="sect3" title="4.1.3.4. $::lxdebug"><div class="titlepage"><div><div><h4 class="title"><a name="d0e7175"></a>4.1.3.4. $::lxdebug</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Objekt der Klasse "LXDebug"</p></li><li class="listitem"><p>Wird global gecached</p></li><li class="listitem"><p>Muss immer verfügbar sein, in nahezu allen
               Funktionen</p></li></ul></div><p>
                   <code class="varname">$::lxdebug</code> stellt Debuggingfunktionen
           bereit, wie "<code class="function">enter_sub</code>" und
           "<code class="function">message</code>" und "<code class="function">dump</code>" mit
           denen man flott Informationen ins Log (tmp/kivitendo-debug.log)
           packen kann.</p><p>Beispielsweise so:</p><pre class="programlisting">$main::lxdebug-&gt;message(0, 'Meine Konfig:' . Dumper (%::myconfig));
-$main::lxdebug-&gt;message(0, 'Wer bin ich? Kunde oder Lieferant:' . $form-&gt;{vc});</pre></div><div class="sect3" title="4.1.3.5. $::auth"><div class="titlepage"><div><div><h4 class="title"><a name="d0e7210"></a>4.1.3.5. $::auth</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Objekt der Klasse "SL::Auth"</p></li><li class="listitem"><p>Wird global gecached</p></li><li class="listitem"><p>Hat eine permanente DB Verbindung zur Authdatenbank</p></li><li class="listitem"><p>Wird nach jedem Request resettet.</p></li></ul></div><p>
+$main::lxdebug-&gt;message(0, 'Wer bin ich? Kunde oder Lieferant:' . $form-&gt;{vc});</pre></div><div class="sect3" title="4.1.3.5. $::auth"><div class="titlepage"><div><div><h4 class="title"><a name="d0e7212"></a>4.1.3.5. $::auth</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Objekt der Klasse "SL::Auth"</p></li><li class="listitem"><p>Wird global gecached</p></li><li class="listitem"><p>Hat eine permanente DB Verbindung zur Authdatenbank</p></li><li class="listitem"><p>Wird nach jedem Request resettet.</p></li></ul></div><p>
                   <code class="varname">$::auth</code> stellt Funktionen bereit um die
           Rechte des aktuellen Users abzufragen. Obwohl diese Informationen
           vom aktuellen User abhängen wird das Objekt aus
@@ -144,7 +144,7 @@ $main::lxdebug-&gt;message(0, 'Wer bin ich? Kunde oder Lieferant:' . $form-&gt;{
           Dessen Einstellungen können Ã¼ber
           <code class="literal">$::auth-&gt;client</code> abgefragt werden; Rückgabewert
           ist ein Hash mit den Werten aus der Tabelle
-          <code class="literal">auth.clients</code>.</p></div><div class="sect3" title="4.1.3.6. $::lx_office_conf"><div class="titlepage"><div><div><h4 class="title"><a name="d0e7239"></a>4.1.3.6. $::lx_office_conf</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Objekt der Klasse
+          <code class="literal">auth.clients</code>.</p></div><div class="sect3" title="4.1.3.6. $::lx_office_conf"><div class="titlepage"><div><div><h4 class="title"><a name="d0e7241"></a>4.1.3.6. $::lx_office_conf</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Objekt der Klasse
               "<code class="classname">SL::LxOfficeConf</code>"</p></li><li class="listitem"><p>Global gecached</p></li><li class="listitem"><p>Repräsentation der
               <code class="filename">config/kivitendo.conf[.default]</code>-Dateien</p></li></ul></div><p>Globale Konfiguration. Configdateien werden zum Start gelesen
           und danach nicht mehr angefasst. Es ist derzeit nicht geplant, dass
@@ -154,16 +154,16 @@ $main::lxdebug-&gt;message(0, 'Wer bin ich? Kunde oder Lieferant:' . $form-&gt;{
 file_name = /tmp/kivitendo-debug.log</pre><p>ist der Key <code class="varname">file</code> im Programm als
           <code class="varname">$::lx_office_conf-&gt;{debug}{file}</code>
           erreichbar.</p><div class="warning" title="Warnung" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Warning"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Warnung]" src="system/docbook-xsl/images/warning.png"></td><th align="left">Warnung</th></tr><tr><td align="left" valign="top"><p>Zugriff auf die Konfiguration erfolgt im Moment Ã¼ber
-            Hashkeys, sind also nicht gegen Tippfehler abgesichert.</p></td></tr></table></div></div><div class="sect3" title="4.1.3.7. $::instance_conf"><div class="titlepage"><div><div><h4 class="title"><a name="d0e7275"></a>4.1.3.7. $::instance_conf</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Objekt der Klasse
+            Hashkeys, sind also nicht gegen Tippfehler abgesichert.</p></td></tr></table></div></div><div class="sect3" title="4.1.3.7. $::instance_conf"><div class="titlepage"><div><div><h4 class="title"><a name="d0e7277"></a>4.1.3.7. $::instance_conf</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Objekt der Klasse
               "<code class="classname">SL::InstanceConfiguration</code>"</p></li><li class="listitem"><p>wird pro Request neu erstellt</p></li></ul></div><p>Funktioniert wie <code class="varname">$::lx_office_conf</code>,
           speichert aber Daten die von der Instanz abhängig sind. Eine Instanz
           ist hier eine Mandantendatenbank. Beispielsweise Ã¼berprüft
           </p><pre class="programlisting">$::instance_conf-&gt;get_inventory_system eq 'perpetual'</pre><p>
-          ob die berüchtigte Bestandsmethode zur Anwendung kommt.</p></div><div class="sect3" title="4.1.3.8. $::dispatcher"><div class="titlepage"><div><div><h4 class="title"><a name="d0e7296"></a>4.1.3.8. $::dispatcher</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Objekt der Klasse
+          ob die berüchtigte Bestandsmethode zur Anwendung kommt.</p></div><div class="sect3" title="4.1.3.8. $::dispatcher"><div class="titlepage"><div><div><h4 class="title"><a name="d0e7298"></a>4.1.3.8. $::dispatcher</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Objekt der Klasse
               "<code class="varname">SL::Dispatcher</code>"</p></li><li class="listitem"><p>wird pro Serverprozess erstellt.</p></li><li class="listitem"><p>enthält Informationen Ã¼ber die technische Verbindung zum
               Server</p></li></ul></div><p>Der dritte Punkt ist auch der einzige Grund warum das Objekt
           global gespeichert wird. Wird vermutlich irgendwann in einem anderen
-          Objekt untergebracht.</p></div><div class="sect3" title="4.1.3.9. $::request"><div class="titlepage"><div><div><h4 class="title"><a name="d0e7314"></a>4.1.3.9. $::request</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Hashref (evtl später Objekt)</p></li><li class="listitem"><p>Wird pro Request neu initialisiert.</p></li><li class="listitem"><p>Keine Unterstruktur garantiert.</p></li></ul></div><p>
+          Objekt untergebracht.</p></div><div class="sect3" title="4.1.3.9. $::request"><div class="titlepage"><div><div><h4 class="title"><a name="d0e7316"></a>4.1.3.9. $::request</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Hashref (evtl später Objekt)</p></li><li class="listitem"><p>Wird pro Request neu initialisiert.</p></li><li class="listitem"><p>Keine Unterstruktur garantiert.</p></li></ul></div><p>
                   <code class="varname">$::request</code> ist ein generischer Platz um
           Daten "für den aktuellen Request" abzulegen. Sollte nicht für action
           at a distance benutzt werden, sondern um lokales memoizing zu
@@ -176,20 +176,20 @@ file_name = /tmp/kivitendo-debug.log</pre><p>ist der Key <code class="varname">f
               <code class="varname">$::request</code>
                      </p></li><li class="listitem"><p>Muss ich von anderen Teilen des Programms lesend drauf
               zugreifen? Dann <code class="varname">$::request</code>, aber Zugriff Ã¼ber
-              Wrappermethode</p></li></ul></div></div></div><div class="sect2" title="4.1.4. Ehemalige globale Variablen"><div class="titlepage"><div><div><h3 class="title"><a name="d0e7356"></a>4.1.4. Ehemalige globale Variablen</h3></div></div></div><p>Die folgenden Variablen waren einmal im Programm, und wurden
-        entfernt.</p><div class="sect3" title="4.1.4.1. $::cgi"><div class="titlepage"><div><div><h4 class="title"><a name="d0e7361"></a>4.1.4.1. $::cgi</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>war nötig, weil cookie Methoden nicht als
+              Wrappermethode</p></li></ul></div></div></div><div class="sect2" title="4.1.4. Ehemalige globale Variablen"><div class="titlepage"><div><div><h3 class="title"><a name="d0e7358"></a>4.1.4. Ehemalige globale Variablen</h3></div></div></div><p>Die folgenden Variablen waren einmal im Programm, und wurden
+        entfernt.</p><div class="sect3" title="4.1.4.1. $::cgi"><div class="titlepage"><div><div><h4 class="title"><a name="d0e7363"></a>4.1.4.1. $::cgi</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>war nötig, weil cookie Methoden nicht als
               Klassenfunktionen funktionieren</p></li><li class="listitem"><p>Aufruf als Klasse erzeugt Dummyobjekt was im
               Klassennamespace gehalten wird und Ã¼ber Requestgrenzen
               leaked</p></li><li class="listitem"><p>liegt jetzt unter
               <code class="varname">$::request-&gt;{cgi}</code>
-                     </p></li></ul></div></div><div class="sect3" title="4.1.4.2. $::all_units"><div class="titlepage"><div><div><h4 class="title"><a name="d0e7377"></a>4.1.4.2. $::all_units</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>war nötig, weil einige Funktionen in Schleifen zum Teil
+                     </p></li></ul></div></div><div class="sect3" title="4.1.4.2. $::all_units"><div class="titlepage"><div><div><h4 class="title"><a name="d0e7379"></a>4.1.4.2. $::all_units</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>war nötig, weil einige Funktionen in Schleifen zum Teil
               ein paar hundert mal pro Request eine Liste der Einheiten
               brauchen, und de als Parameter durch einen Riesenstack von
               Funktionen geschleift werden müssten.</p></li><li class="listitem"><p>Liegt jetzt unter
               <code class="varname">$::request-&gt;{cache}{all_units}</code>
                      </p></li><li class="listitem"><p>Wird nur in
               <code class="function">AM-&gt;retrieve_all_units()</code> gesetzt oder
-              gelesen.</p></li></ul></div></div><div class="sect3" title="4.1.4.3. %::called_subs"><div class="titlepage"><div><div><h4 class="title"><a name="d0e7396"></a>4.1.4.3. %::called_subs</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>wurde benutzt um callsub deep recursions
+              gelesen.</p></li></ul></div></div><div class="sect3" title="4.1.4.3. %::called_subs"><div class="titlepage"><div><div><h4 class="title"><a name="d0e7398"></a>4.1.4.3. %::called_subs</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>wurde benutzt um callsub deep recursions
               abzufangen.</p></li><li class="listitem"><p>Wurde entfernt, weil callsub nur einen Bruchteil der
               möglichen Rekursioenen darstellt, und da nie welche
               auftreten.</p></li><li class="listitem"><p>komplette recursion protection wurde entfernt.</p></li></ul></div></div></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch03s09.html">Zurück</a>&nbsp;</td><td width="20%" align="center">&nbsp;</td><td width="40%" align="right">&nbsp;<a accesskey="n" href="ch04s02.html">Weiter</a></td></tr><tr><td width="40%" align="left" valign="top">3.9. Webshop-Api&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="index.html">Zum Anfang</a></td><td width="40%" align="right" valign="top">&nbsp;4.2. Entwicklung unter FastCGI</td></tr></table></div></body></html>
\ No newline at end of file
index e95b09d..8212b84 100644 (file)
@@ -2,8 +2,8 @@
       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>kivitendo 3.5.3: Installation, Konfiguration, Entwicklung</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.76.1-RC2"><link rel="home" href="index.html" title="kivitendo 3.5.3: Installation, Konfiguration, Entwicklung"><link rel="next" href="ch01.html" title="Kapitel 1. Aktuelle Hinweise"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">kivitendo 3.5.3: Installation, Konfiguration,
   Entwicklung</th></tr><tr><td width="20%" align="left">&nbsp;</td><th width="60%" align="center">&nbsp;</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch01.html">Weiter</a></td></tr></table><hr></div><div lang="de" class="book" title="kivitendo 3.5.3: Installation, Konfiguration, Entwicklung"><div class="titlepage"><div><div><h1 class="title"><a name="kivitendo-documentation"></a>kivitendo 3.5.3: Installation, Konfiguration,
-  Entwicklung</h1></div></div><hr></div><div class="toc"><p><b>Inhaltsverzeichnis</b></p><dl><dt><span class="chapter"><a href="ch01.html">1. Aktuelle Hinweise</a></span></dt><dt><span class="chapter"><a href="ch02.html">2. Installation und Grundkonfiguration</a></span></dt><dd><dl><dt><span class="sect1"><a href="ch02.html#Installation-%C3%9Cbersicht">2.1. Ãœbersicht</a></span></dt><dt><span class="sect1"><a href="ch02s02.html">2.2. Benötigte Software und Pakete</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s02.html#Betriebssystem">2.2.1. Betriebssystem</a></span></dt><dt><span class="sect2"><a href="ch02s02.html#Pakete">2.2.2. Benötigte Perl-Pakete installieren</a></span></dt><dt><span class="sect2"><a href="ch02s02.html#d0e574">2.2.3. Andere Pakete installieren</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s03.html">2.3. Manuelle Installation des Programmpaketes</a></span></dt><dt><span class="sect1"><a href="ch02s04.html">2.4. kivitendo-Konfigurationsdatei</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s04.html#config.config-file.introduction">2.4.1. Einführung</a></span></dt><dt><span class="sect2"><a href="ch02s04.html#config.config-file.sections-parameters">2.4.2. Abschnitte und Parameter</a></span></dt><dt><span class="sect2"><a href="ch02s04.html#config.config-file.prior-versions">2.4.3. Versionen vor 2.6.3</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s05.html">2.5. Anpassung der PostgreSQL-Konfiguration</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s05.html#Zeichens%C3%A4tze-die-Verwendung-von-UTF-8">2.5.1. Zeichensätze/die Verwendung von Unicode/UTF-8</a></span></dt><dt><span class="sect2"><a href="ch02s05.html#%C3%84nderungen-an-Konfigurationsdateien">2.5.2. Ã„nderungen an Konfigurationsdateien</a></span></dt><dt><span class="sect2"><a href="ch02s05.html#Erweiterung-f%C3%BCr-servergespeicherte-Prozeduren">2.5.3. Erweiterung für servergespeicherte Prozeduren</a></span></dt><dt><span class="sect2"><a href="ch02s05.html#Erweiterung-f%C3%BCr-trigram">2.5.4. Erweiterung für Trigram Prozeduren</a></span></dt><dt><span class="sect2"><a href="ch02s05.html#Datenbankbenutzer-anlegen">2.5.5. Datenbankbenutzer anlegen</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s06.html">2.6. Webserver-Konfiguration</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s06.html#d0e1051">2.6.1. Grundkonfiguration mittels CGI</a></span></dt><dt><span class="sect2"><a href="ch02s06.html#Apache-Konfiguration.FCGI">2.6.2. Konfiguration für FastCGI/FCGI</a></span></dt><dt><span class="sect2"><a href="ch02s06.html#d0e1202">2.6.3. Authentifizierung mittels HTTP Basic Authentication</a></span></dt><dt><span class="sect2"><a href="ch02s06.html#d0e1218">2.6.4. Weitergehende Konfiguration</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s07.html">2.7. Der Task-Server</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s07.html#Konfiguration-des-Task-Servers">2.7.1. Verfügbare und notwendige Konfigurationsoptionen</a></span></dt><dt><span class="sect2"><a href="ch02s07.html#Konfiguration-der-Mandanten-fuer-den-Task-Servers">2.7.2. Konfiguration der Mandanten für den Task-Server</a></span></dt><dt><span class="sect2"><a href="ch02s07.html#Einbinden-in-den-Boot-Prozess">2.7.3. Automatisches Starten des Task-Servers beim Booten</a></span></dt><dt><span class="sect2"><a href="ch02s07.html#Prozesskontrolle">2.7.4. Wie der Task-Server gestartet und beendet wird</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s08.html">2.8. Benutzerauthentifizierung und Administratorpasswort</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s08.html#Grundlagen-zur-Benutzerauthentifizierung">2.8.1. Grundlagen zur Benutzerauthentifizierung</a></span></dt><dt><span class="sect2"><a href="ch02s08.html#Administratorpasswort">2.8.2. Administratorpasswort</a></span></dt><dt><span class="sect2"><a href="ch02s08.html#Authentifizierungsdatenbank">2.8.3. Authentifizierungsdatenbank</a></span></dt><dt><span class="sect2"><a href="ch02s08.html#Passwort%C3%BCberpr%C3%BCfung">2.8.4. Passwortüberprüfung</a></span></dt><dt><span class="sect2"><a href="ch02s08.html#Name-des-Session-Cookies">2.8.5. Name des Session-Cookies</a></span></dt><dt><span class="sect2"><a href="ch02s08.html#Anlegen-der-Authentifizierungsdatenbank">2.8.6. Anlegen der Authentifizierungsdatenbank</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s09.html">2.9. Mandanten-, Benutzer- und Gruppenverwaltung</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s09.html#Zusammenh%C3%A4nge">2.9.1. Zusammenhänge</a></span></dt><dt><span class="sect2"><a href="ch02s09.html#Mandanten-Benutzer-Gruppen">2.9.2. Mandanten, Benutzer und Gruppen</a></span></dt><dt><span class="sect2"><a href="ch02s09.html#Datenbanken-anlegen">2.9.3. Datenbanken anlegen</a></span></dt><dt><span class="sect2"><a href="ch02s09.html#Gruppen-anlegen">2.9.4. Gruppen anlegen</a></span></dt><dt><span class="sect2"><a href="ch02s09.html#Benutzer-anlegen">2.9.5. Benutzer anlegen</a></span></dt><dt><span class="sect2"><a href="ch02s09.html#Mandanten-anlegen">2.9.6. Mandanten anlegen</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s10.html">2.10. Drucker- und Systemverwaltung</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s10.html#Druckeradministration">2.10.1. Druckeradministration</a></span></dt><dt><span class="sect2"><a href="ch02s10.html#System">2.10.2. System sperren / entsperren</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s11.html">2.11. E-Mail-Versand aus kivitendo heraus</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s11.html#config.sending-email.sendmail">2.11.1. Versand Ã¼ber lokalen E-Mail-Server</a></span></dt><dt><span class="sect2"><a href="ch02s11.html#config.sending-email.smtp">2.11.2. Versand Ã¼ber einen SMTP-Server</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s12.html">2.12. Drucken mit kivitendo</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s12.html#Vorlagenverzeichnis-anlegen">2.12.1. Vorlagenverzeichnis anlegen</a></span></dt><dt><span class="sect2"><a href="ch02s12.html#Vorlagen-RB">2.12.2. Der Druckvorlagensatz RB</a></span></dt><dt><span class="sect2"><a href="ch02s12.html#f-tex">2.12.3. f-tex</a></span></dt><dt><span class="sect2"><a href="ch02s12.html#Vorlagen-rev-odt">2.12.4. Der Druckvorlagensatz rev-odt</a></span></dt><dt><span class="sect2"><a href="ch02s12.html#allgemeine-hinweise-zu-latex">2.12.5. Allgemeine Hinweise zu LaTeX Vorlagen</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s13.html">2.13. OpenDocument-Vorlagen</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s13.html#d0e2383">2.13.1. OpenDocument (odt) Druckvorlagen mit Makros</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s14.html">2.14. Nomenklatur</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s14.html#booking.dates">2.14.1. Datum bei Buchungen</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s15.html">2.15. Konfiguration zur Einnahmenüberschussrechnung/Bilanzierung:
+  Entwicklung</h1></div></div><hr></div><div class="toc"><p><b>Inhaltsverzeichnis</b></p><dl><dt><span class="chapter"><a href="ch01.html">1. Aktuelle Hinweise</a></span></dt><dt><span class="chapter"><a href="ch02.html">2. Installation und Grundkonfiguration</a></span></dt><dd><dl><dt><span class="sect1"><a href="ch02.html#Installation-%C3%9Cbersicht">2.1. Ãœbersicht</a></span></dt><dt><span class="sect1"><a href="ch02s02.html">2.2. Benötigte Software und Pakete</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s02.html#Betriebssystem">2.2.1. Betriebssystem</a></span></dt><dt><span class="sect2"><a href="ch02s02.html#Pakete">2.2.2. Benötigte Perl-Pakete installieren</a></span></dt><dt><span class="sect2"><a href="ch02s02.html#d0e576">2.2.3. Andere Pakete installieren</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s03.html">2.3. Manuelle Installation des Programmpaketes</a></span></dt><dt><span class="sect1"><a href="ch02s04.html">2.4. kivitendo-Konfigurationsdatei</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s04.html#config.config-file.introduction">2.4.1. Einführung</a></span></dt><dt><span class="sect2"><a href="ch02s04.html#config.config-file.sections-parameters">2.4.2. Abschnitte und Parameter</a></span></dt><dt><span class="sect2"><a href="ch02s04.html#config.config-file.prior-versions">2.4.3. Versionen vor 2.6.3</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s05.html">2.5. Anpassung der PostgreSQL-Konfiguration</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s05.html#Zeichens%C3%A4tze-die-Verwendung-von-UTF-8">2.5.1. Zeichensätze/die Verwendung von Unicode/UTF-8</a></span></dt><dt><span class="sect2"><a href="ch02s05.html#%C3%84nderungen-an-Konfigurationsdateien">2.5.2. Ã„nderungen an Konfigurationsdateien</a></span></dt><dt><span class="sect2"><a href="ch02s05.html#Erweiterung-f%C3%BCr-servergespeicherte-Prozeduren">2.5.3. Erweiterung für servergespeicherte Prozeduren</a></span></dt><dt><span class="sect2"><a href="ch02s05.html#Erweiterung-f%C3%BCr-trigram">2.5.4. Erweiterung für Trigram Prozeduren</a></span></dt><dt><span class="sect2"><a href="ch02s05.html#Datenbankbenutzer-anlegen">2.5.5. Datenbankbenutzer anlegen</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s06.html">2.6. Webserver-Konfiguration</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s06.html#d0e1053">2.6.1. Grundkonfiguration mittels CGI</a></span></dt><dt><span class="sect2"><a href="ch02s06.html#Apache-Konfiguration.FCGI">2.6.2. Konfiguration für FastCGI/FCGI</a></span></dt><dt><span class="sect2"><a href="ch02s06.html#d0e1204">2.6.3. Authentifizierung mittels HTTP Basic Authentication</a></span></dt><dt><span class="sect2"><a href="ch02s06.html#d0e1220">2.6.4. Weitergehende Konfiguration</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s07.html">2.7. Der Task-Server</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s07.html#Konfiguration-des-Task-Servers">2.7.1. Verfügbare und notwendige Konfigurationsoptionen</a></span></dt><dt><span class="sect2"><a href="ch02s07.html#Konfiguration-der-Mandanten-fuer-den-Task-Servers">2.7.2. Konfiguration der Mandanten für den Task-Server</a></span></dt><dt><span class="sect2"><a href="ch02s07.html#Einbinden-in-den-Boot-Prozess">2.7.3. Automatisches Starten des Task-Servers beim Booten</a></span></dt><dt><span class="sect2"><a href="ch02s07.html#Prozesskontrolle">2.7.4. Wie der Task-Server gestartet und beendet wird</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s08.html">2.8. Benutzerauthentifizierung und Administratorpasswort</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s08.html#Grundlagen-zur-Benutzerauthentifizierung">2.8.1. Grundlagen zur Benutzerauthentifizierung</a></span></dt><dt><span class="sect2"><a href="ch02s08.html#Administratorpasswort">2.8.2. Administratorpasswort</a></span></dt><dt><span class="sect2"><a href="ch02s08.html#Authentifizierungsdatenbank">2.8.3. Authentifizierungsdatenbank</a></span></dt><dt><span class="sect2"><a href="ch02s08.html#Passwort%C3%BCberpr%C3%BCfung">2.8.4. Passwortüberprüfung</a></span></dt><dt><span class="sect2"><a href="ch02s08.html#Name-des-Session-Cookies">2.8.5. Name des Session-Cookies</a></span></dt><dt><span class="sect2"><a href="ch02s08.html#Anlegen-der-Authentifizierungsdatenbank">2.8.6. Anlegen der Authentifizierungsdatenbank</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s09.html">2.9. Mandanten-, Benutzer- und Gruppenverwaltung</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s09.html#Zusammenh%C3%A4nge">2.9.1. Zusammenhänge</a></span></dt><dt><span class="sect2"><a href="ch02s09.html#Mandanten-Benutzer-Gruppen">2.9.2. Mandanten, Benutzer und Gruppen</a></span></dt><dt><span class="sect2"><a href="ch02s09.html#Datenbanken-anlegen">2.9.3. Datenbanken anlegen</a></span></dt><dt><span class="sect2"><a href="ch02s09.html#Gruppen-anlegen">2.9.4. Gruppen anlegen</a></span></dt><dt><span class="sect2"><a href="ch02s09.html#Benutzer-anlegen">2.9.5. Benutzer anlegen</a></span></dt><dt><span class="sect2"><a href="ch02s09.html#Mandanten-anlegen">2.9.6. Mandanten anlegen</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s10.html">2.10. Drucker- und Systemverwaltung</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s10.html#Druckeradministration">2.10.1. Druckeradministration</a></span></dt><dt><span class="sect2"><a href="ch02s10.html#System">2.10.2. System sperren / entsperren</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s11.html">2.11. E-Mail-Versand aus kivitendo heraus</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s11.html#config.sending-email.sendmail">2.11.1. Versand Ã¼ber lokalen E-Mail-Server</a></span></dt><dt><span class="sect2"><a href="ch02s11.html#config.sending-email.smtp">2.11.2. Versand Ã¼ber einen SMTP-Server</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s12.html">2.12. Drucken mit kivitendo</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s12.html#Vorlagenverzeichnis-anlegen">2.12.1. Vorlagenverzeichnis anlegen</a></span></dt><dt><span class="sect2"><a href="ch02s12.html#Vorlagen-RB">2.12.2. Der Druckvorlagensatz RB</a></span></dt><dt><span class="sect2"><a href="ch02s12.html#f-tex">2.12.3. f-tex</a></span></dt><dt><span class="sect2"><a href="ch02s12.html#Vorlagen-rev-odt">2.12.4. Der Druckvorlagensatz rev-odt</a></span></dt><dt><span class="sect2"><a href="ch02s12.html#allgemeine-hinweise-zu-latex">2.12.5. Allgemeine Hinweise zu LaTeX Vorlagen</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s13.html">2.13. OpenDocument-Vorlagen</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s13.html#d0e2385">2.13.1. OpenDocument (odt) Druckvorlagen mit Makros</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s14.html">2.14. Nomenklatur</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s14.html#booking.dates">2.14.1. Datum bei Buchungen</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s15.html">2.15. Konfiguration zur Einnahmenüberschussrechnung/Bilanzierung:
       EUR</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s15.html#config.eur.introduction">2.15.1. Einführung</a></span></dt><dt><span class="sect2"><a href="ch02s15.html#config.eur.parameters">2.15.2. Konfigurationsparameter</a></span></dt><dt><span class="sect2"><a href="ch02s15.html#config.eur.setting-parameters">2.15.3. Festlegen der Parameter</a></span></dt><dt><span class="sect2"><a href="ch02s15.html#config.eur.inventory-system-perpetual">2.15.4. Bemerkungen zur Bestandsmethode</a></span></dt><dt><span class="sect2"><a href="ch02s15.html#config.eur.knonw-issues">2.15.5. Bekannte Probleme</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s16.html">2.16. SKR04 19% Umstellung für innergemeinschaftlichen Erwerb</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch02s16.html#config.skr04-update-3804.introduction">2.16.1. Einführung</a></span></dt><dt><span class="sect2"><a href="ch02s16.html#config.skr04-update-3804.create-chart">2.16.2. Konto 3804 manuell anlegen</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch02s17.html">2.17. Verhalten des Bilanzberichts</a></span></dt><dt><span class="sect1"><a href="ch02s18.html">2.18. Erfolgsrechnung</a></span></dt><dt><span class="sect1"><a href="ch02s19.html">2.19. Rundung in Verkaufsbelegen</a></span></dt><dt><span class="sect1"><a href="ch02s20.html">2.20. Einstellungen pro Mandant</a></span></dt><dt><span class="sect1"><a href="ch02s21.html">2.21. kivitendo ERP verwenden</a></span></dt></dl></dd><dt><span class="chapter"><a href="ch03.html">3. Features und Funktionen</a></span></dt><dd><dl><dt><span class="sect1"><a href="ch03.html#features.periodic-invoices">3.1. Wiederkehrende Rechnungen</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch03.html#features.periodic-invoices.introduction">3.1.1. Einführung</a></span></dt><dt><span class="sect2"><a href="ch03.html#features.periodic-invoices.configuration">3.1.2. Konfiguration</a></span></dt><dt><span class="sect2"><a href="ch03.html#features.periodic-invoices.variables">3.1.3. Spezielle Variablen</a></span></dt><dt><span class="sect2"><a href="ch03.html#features.periodic-invoices.reports">3.1.4. Auflisten</a></span></dt><dt><span class="sect2"><a href="ch03.html#features.periodic-invoices.task-server">3.1.5. Erzeugung der eigentlichen Rechnungen</a></span></dt><dt><span class="sect2"><a href="ch03.html#features.periodic-invoices.create-for-current-month">3.1.6. Erste Rechnung für aktuellen Monat erstellen</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch03s02.html">3.2. Bankerweiterung</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch03s02.html#features.bank.introduction">3.2.1. Einführung</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch03s03.html">3.3. Dokumentenvorlagen und verfügbare Variablen</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch03s03.html#dokumentenvorlagen-und-variablen.einf%C3%BChrung">3.3.1. Einführung</a></span></dt><dt><span class="sect2"><a href="ch03s03.html#dokumentenvorlagen-und-variablen.variablen-ausgeben">3.3.2. Variablen ausgeben</a></span></dt><dt><span class="sect2"><a href="ch03s03.html#dokumentenvorlagen-und-variablen.verwendung-in-druckbefehlen">3.3.3. Verwendung in Druckbefehlen</a></span></dt><dt><span class="sect2"><a href="ch03s03.html#dokumentenvorlagen-und-variablen.tag-style">3.3.4. Anfang und Ende der Tags verändern</a></span></dt><dt><span class="sect2"><a href="ch03s03.html#dokumentenvorlagen-und-variablen.zuordnung-dateinamen">3.3.5. Zuordnung von den Dateinamen zu den Funktionen</a></span></dt><dt><span class="sect2"><a href="ch03s03.html#dokumentenvorlagen-und-variablen.dateinamen-erweitert">3.3.6. Sprache, Drucker und E-Mail</a></span></dt><dt><span class="sect2"><a href="ch03s03.html#dokumentenvorlagen-und-variablen.allgemeine-variablen">3.3.7. Allgemeine Variablen, die in allen Vorlagen vorhanden
         sind</a></span></dt><dt><span class="sect2"><a href="ch03s03.html#dokumentenvorlagen-und-variablen.invoice">3.3.8. Variablen in Rechnungen</a></span></dt><dt><span class="sect2"><a href="ch03s03.html#dokumentenvorlagen-und-variablen.dunning">3.3.9. Variablen in Mahnungen und Rechnungen Ã¼ber Mahngebühren</a></span></dt><dt><span class="sect2"><a href="ch03s03.html#dokumentenvorlagen-und-variablen.andere-vorlagen">3.3.10. Variablen in anderen Vorlagen</a></span></dt><dt><span class="sect2"><a href="ch03s03.html#dokumentenvorlagen-und-variablen.bloecke">3.3.11. Blöcke, bedingte Anweisungen und Schleifen</a></span></dt><dt><span class="sect2"><a href="ch03s03.html#dokumentenvorlagen-und-variablen.markup">3.3.12. Markup-Code zur Textformatierung innerhalb von
-        Formularen</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch03s04.html">3.4. Excel-Vorlagen</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch03s04.html#excel-templates.summary">3.4.1. Zusammenfassung</a></span></dt><dt><span class="sect2"><a href="ch03s04.html#excel-templates.usage">3.4.2. Bedienung</a></span></dt><dt><span class="sect2"><a href="ch03s04.html#excel-templates.syntax">3.4.3. Variablensyntax</a></span></dt><dt><span class="sect2"><a href="ch03s04.html#excel-templates.limitations">3.4.4. Einschränkungen</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch03s05.html">3.5. Mandantenkonfiguration Lager</a></span></dt><dt><span class="sect1"><a href="ch03s06.html">3.6. Schweizer Kontenpläne</a></span></dt><dt><span class="sect1"><a href="ch03s07.html">3.7. Artikelklassifizierung</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch03s07.html#d0e6453">3.7.1. Ãœbersicht</a></span></dt><dt><span class="sect2"><a href="ch03s07.html#d0e6458">3.7.2. Basisklassifizierung</a></span></dt><dt><span class="sect2"><a href="ch03s07.html#d0e6488">3.7.3. Attribute</a></span></dt><dt><span class="sect2"><a href="ch03s07.html#d0e6519">3.7.4. Zwei-Zeichen Abkürzung</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch03s08.html">3.8. Dateiverwaltung (Mini-DMS)</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch03s08.html#d0e6531">3.8.1. Ãœbersicht</a></span></dt><dt><span class="sect2"><a href="ch03s08.html#d0e6558">3.8.2. Struktur</a></span></dt><dt><span class="sect2"><a href="ch03s08.html#d0e6610">3.8.3. Anwendung</a></span></dt><dt><span class="sect2"><a href="ch03s08.html#d0e6653">3.8.4. Konfigurierung</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch03s09.html">3.9. Webshop-Api</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch03s09.html#d0e6718">3.9.1. Rechte für die Webshopapi</a></span></dt><dt><span class="sect2"><a href="ch03s09.html#d0e6733">3.9.2. Konfiguration</a></span></dt><dt><span class="sect2"><a href="ch03s09.html#d0e6741">3.9.3. Webshopartikel</a></span></dt><dt><span class="sect2"><a href="ch03s09.html#d0e6765">3.9.4. Bestellimport</a></span></dt><dt><span class="sect2"><a href="ch03s09.html#d0e6818">3.9.5. Mapping der Daten</a></span></dt></dl></dd></dl></dd><dt><span class="chapter"><a href="ch04.html">4. Entwicklerdokumentation</a></span></dt><dd><dl><dt><span class="sect1"><a href="ch04.html#devel.globals">4.1. Globale Variablen</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch04.html#d0e6834">4.1.1. Wie sehen globale Variablen in Perl aus?</a></span></dt><dt><span class="sect2"><a href="ch04.html#d0e6935">4.1.2. Warum sind globale Variablen ein Problem?</a></span></dt><dt><span class="sect2"><a href="ch04.html#d0e6968">4.1.3. Kanonische globale Variablen</a></span></dt><dt><span class="sect2"><a href="ch04.html#d0e7356">4.1.4. Ehemalige globale Variablen</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch04s02.html">4.2. Entwicklung unter FastCGI</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch04s02.html#devel.fcgi.general">4.2.1. Allgemeines</a></span></dt><dt><span class="sect2"><a href="ch04s02.html#devel.fcgi.exiting">4.2.2. Programmende und Ausnahmen</a></span></dt><dt><span class="sect2"><a href="ch04s02.html#devel.fcgi.globals">4.2.3. Globale Variablen</a></span></dt><dt><span class="sect2"><a href="ch04s02.html#devel.fcgi.performance">4.2.4. Performance und Statistiken</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch04s03.html">4.3. Programmatische API-Aufrufe</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch04s03.html#dev-programmatic-api-calls.introduction">4.3.1. Einführung</a></span></dt><dt><span class="sect2"><a href="ch04s03.html#dev-programmatic-api-calls.client_selection">4.3.2. Wahl des Mandanten</a></span></dt><dt><span class="sect2"><a href="ch04s03.html#dev-programmatic-api-calls.http_basic_authentication">4.3.3. HTTP-»Basic«-Authentifizierung</a></span></dt><dt><span class="sect2"><a href="ch04s03.html#dev-programmatic-api-calls.authentication_via_parameters">4.3.4. Authentifizierung mit Parametern</a></span></dt><dt><span class="sect2"><a href="ch04s03.html#dev-programmatic-api-calls.examples">4.3.5. Beispiele</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch04s04.html">4.4. SQL-Upgradedateien</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch04s04.html#db-upgrade-files.introduction">4.4.1. Einführung</a></span></dt><dt><span class="sect2"><a href="ch04s04.html#db-upgrade-files.format">4.4.2. Format der Kontrollinformationen</a></span></dt><dt><span class="sect2"><a href="ch04s04.html#db-upgrade-files.format-perl-files">4.4.3. Format von in Perl geschriebenen
+        Formularen</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch03s04.html">3.4. Excel-Vorlagen</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch03s04.html#excel-templates.summary">3.4.1. Zusammenfassung</a></span></dt><dt><span class="sect2"><a href="ch03s04.html#excel-templates.usage">3.4.2. Bedienung</a></span></dt><dt><span class="sect2"><a href="ch03s04.html#excel-templates.syntax">3.4.3. Variablensyntax</a></span></dt><dt><span class="sect2"><a href="ch03s04.html#excel-templates.limitations">3.4.4. Einschränkungen</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch03s05.html">3.5. Mandantenkonfiguration Lager</a></span></dt><dt><span class="sect1"><a href="ch03s06.html">3.6. Schweizer Kontenpläne</a></span></dt><dt><span class="sect1"><a href="ch03s07.html">3.7. Artikelklassifizierung</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch03s07.html#d0e6455">3.7.1. Ãœbersicht</a></span></dt><dt><span class="sect2"><a href="ch03s07.html#d0e6460">3.7.2. Basisklassifizierung</a></span></dt><dt><span class="sect2"><a href="ch03s07.html#d0e6490">3.7.3. Attribute</a></span></dt><dt><span class="sect2"><a href="ch03s07.html#d0e6521">3.7.4. Zwei-Zeichen Abkürzung</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch03s08.html">3.8. Dateiverwaltung (Mini-DMS)</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch03s08.html#d0e6533">3.8.1. Ãœbersicht</a></span></dt><dt><span class="sect2"><a href="ch03s08.html#d0e6560">3.8.2. Struktur</a></span></dt><dt><span class="sect2"><a href="ch03s08.html#d0e6612">3.8.3. Anwendung</a></span></dt><dt><span class="sect2"><a href="ch03s08.html#d0e6655">3.8.4. Konfigurierung</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch03s09.html">3.9. Webshop-Api</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch03s09.html#d0e6720">3.9.1. Rechte für die Webshopapi</a></span></dt><dt><span class="sect2"><a href="ch03s09.html#d0e6735">3.9.2. Konfiguration</a></span></dt><dt><span class="sect2"><a href="ch03s09.html#d0e6743">3.9.3. Webshopartikel</a></span></dt><dt><span class="sect2"><a href="ch03s09.html#d0e6767">3.9.4. Bestellimport</a></span></dt><dt><span class="sect2"><a href="ch03s09.html#d0e6820">3.9.5. Mapping der Daten</a></span></dt></dl></dd></dl></dd><dt><span class="chapter"><a href="ch04.html">4. Entwicklerdokumentation</a></span></dt><dd><dl><dt><span class="sect1"><a href="ch04.html#devel.globals">4.1. Globale Variablen</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch04.html#d0e6836">4.1.1. Wie sehen globale Variablen in Perl aus?</a></span></dt><dt><span class="sect2"><a href="ch04.html#d0e6937">4.1.2. Warum sind globale Variablen ein Problem?</a></span></dt><dt><span class="sect2"><a href="ch04.html#d0e6970">4.1.3. Kanonische globale Variablen</a></span></dt><dt><span class="sect2"><a href="ch04.html#d0e7358">4.1.4. Ehemalige globale Variablen</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch04s02.html">4.2. Entwicklung unter FastCGI</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch04s02.html#devel.fcgi.general">4.2.1. Allgemeines</a></span></dt><dt><span class="sect2"><a href="ch04s02.html#devel.fcgi.exiting">4.2.2. Programmende und Ausnahmen</a></span></dt><dt><span class="sect2"><a href="ch04s02.html#devel.fcgi.globals">4.2.3. Globale Variablen</a></span></dt><dt><span class="sect2"><a href="ch04s02.html#devel.fcgi.performance">4.2.4. Performance und Statistiken</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch04s03.html">4.3. Programmatische API-Aufrufe</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch04s03.html#dev-programmatic-api-calls.introduction">4.3.1. Einführung</a></span></dt><dt><span class="sect2"><a href="ch04s03.html#dev-programmatic-api-calls.client_selection">4.3.2. Wahl des Mandanten</a></span></dt><dt><span class="sect2"><a href="ch04s03.html#dev-programmatic-api-calls.http_basic_authentication">4.3.3. HTTP-»Basic«-Authentifizierung</a></span></dt><dt><span class="sect2"><a href="ch04s03.html#dev-programmatic-api-calls.authentication_via_parameters">4.3.4. Authentifizierung mit Parametern</a></span></dt><dt><span class="sect2"><a href="ch04s03.html#dev-programmatic-api-calls.examples">4.3.5. Beispiele</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch04s04.html">4.4. SQL-Upgradedateien</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch04s04.html#db-upgrade-files.introduction">4.4.1. Einführung</a></span></dt><dt><span class="sect2"><a href="ch04s04.html#db-upgrade-files.format">4.4.2. Format der Kontrollinformationen</a></span></dt><dt><span class="sect2"><a href="ch04s04.html#db-upgrade-files.format-perl-files">4.4.3. Format von in Perl geschriebenen
         Datenbankupgradescripten</a></span></dt><dt><span class="sect2"><a href="ch04s04.html#db-upgrade-files.dbupgrade-tool">4.4.4. Hilfsscript dbupgrade2_tool.pl</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch04s05.html">4.5. Translations and languages</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch04s05.html#translations-languages.introduction">4.5.1. Introduction</a></span></dt><dt><span class="sect2"><a href="ch04s05.html#translations-languages.character-set">4.5.2. Character set</a></span></dt><dt><span class="sect2"><a href="ch04s05.html#translations-languages.file-structure">4.5.3. File structure</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch04s06.html">4.6. Die kivitendo-Test-Suite</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch04s06.html#devel.testsuite.intro">4.6.1. Einführung</a></span></dt><dt><span class="sect2"><a href="ch04s06.html#devel.testsuite.prerequisites">4.6.2. Voraussetzungen</a></span></dt><dt><span class="sect2"><a href="ch04s06.html#devel.testsuite.execution">4.6.3. Existierende Tests ausführen</a></span></dt><dt><span class="sect2"><a href="ch04s06.html#devel.testsuite.meaning_of_scripts">4.6.4. Bedeutung der verschiedenen Test-Scripte</a></span></dt><dt><span class="sect2"><a href="ch04s06.html#devel.testsuite.create_new">4.6.5. Neue Test-Scripte erstellen</a></span></dt></dl></dd><dt><span class="sect1"><a href="ch04s07.html">4.7. Stil-Richtlinien</a></span></dt><dt><span class="sect1"><a href="ch04s08.html">4.8. Dokumentation erstellen</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch04s08.html#devel.build-doc.introduction">4.8.1. Einführung</a></span></dt><dt><span class="sect2"><a href="ch04s08.html#devel.build-doc.required-software">4.8.2. Benötigte Software</a></span></dt><dt><span class="sect2"><a href="ch04s08.html#devel.build-doc.build">4.8.3. PDFs und HTML-Seiten erstellen</a></span></dt><dt><span class="sect2"><a href="ch04s08.html#devel.build-doc.repository">4.8.4. Einchecken in das Git-Repository</a></span></dt></dl></dd></dl></dd></dl></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left">&nbsp;</td><td width="20%" align="center">&nbsp;</td><td width="40%" align="right">&nbsp;<a accesskey="n" href="ch01.html">Weiter</a></td></tr><tr><td width="40%" align="left" valign="top">&nbsp;</td><td width="20%" align="center">&nbsp;</td><td width="40%" align="right" valign="top">&nbsp;Kapitel 1. Aktuelle Hinweise</td></tr></table></div></body></html>
\ No newline at end of file
index 5d2864b..f14365a 100644 (file)
Binary files a/doc/kivitendo-Dokumentation.pdf and b/doc/kivitendo-Dokumentation.pdf differ
diff --git a/doc/modules/LICENSE.CGI-Ajax b/doc/modules/LICENSE.CGI-Ajax
deleted file mode 100644 (file)
index 9d0305b..0000000
+++ /dev/null
@@ -1,383 +0,0 @@
-Terms of Perl itself
-
-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"
-
----------------------------------------------------------------------------
-
-The General Public License (GPL)
-Version 2, June 1991
-
-Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave,
-Cambridge, MA 02139, USA. Everyone is permitted to copy and distribute
-verbatim copies of this license document, but changing it is not allowed.
-
-Preamble
-
-The licenses for most software are designed to take away your freedom to share
-and change it. By contrast, the GNU General Public License is intended to
-guarantee your freedom to share and change free software--to make sure the
-software is free for all its users. This General Public License applies to most of
-the Free Software Foundation's software and to any other program whose
-authors commit to using it. (Some other Free Software Foundation software is
-covered by the GNU Library General Public License instead.) You can apply it to
-your programs, too.
-
-When we speak of free software, we are referring to freedom, not price. Our
-General Public Licenses are designed to make sure that you have the freedom
-to distribute copies of free software (and charge for this service if you wish), that
-you receive source code or can get it if you want it, that you can change the
-software or use pieces of it in new free programs; and that you know you can do
-these things.
-
-To protect your rights, we need to make restrictions that forbid anyone to deny
-you these rights or to ask you to surrender the rights. These restrictions
-translate to certain responsibilities for you if you distribute copies of the
-software, or if you modify it.
-
-For example, if you distribute copies of such a program, whether gratis or for a
-fee, you must give the recipients all the rights that you have. You must make
-sure that they, too, receive or can get the source code. And you must show
-them these terms so they know their rights.
-
-We protect your rights with two steps: (1) copyright the software, and (2) offer
-you this license which gives you legal permission to copy, distribute and/or
-modify the software.
-
-Also, for each author's protection and ours, we want to make certain that
-everyone understands that there is no warranty for this free software. If the
-software is modified by someone else and passed on, we want its recipients to
-know that what they have is not the original, so that any problems introduced by
-others will not reflect on the original authors' reputations.
-
-Finally, any free program is threatened constantly by software patents. We wish
-to avoid the danger that redistributors of a free program will individually obtain
-patent licenses, in effect making the program proprietary. To prevent this, we
-have made it clear that any patent must be licensed for everyone's free use or
-not licensed at all.
-
-The precise terms and conditions for copying, distribution and modification
-follow.
-
-GNU GENERAL PUBLIC LICENSE
-TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND
-MODIFICATION
-
-0. This License applies to any program or other work which contains a notice
-placed by the copyright holder saying it may be distributed under the terms of
-this General Public License. The "Program", below, refers to any such program
-or work, and a "work based on the Program" means either the Program or any
-derivative work under copyright law: that is to say, a work containing the
-Program or a portion of it, either verbatim or with modifications and/or translated
-into another language. (Hereinafter, translation is included without limitation in
-the term "modification".) Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not covered by
-this License; they are outside its scope. The act of running the Program is not
-restricted, and the output from the Program is covered only if its contents
-constitute a work based on the Program (independent of having been made by
-running the Program). Whether that is true depends on what the Program does.
-
-1. You may copy and distribute verbatim copies of the Program's source code as
-you receive it, in any medium, provided that you conspicuously and appropriately
-publish on each copy an appropriate copyright notice and disclaimer of warranty;
-keep intact all the notices that refer to this License and to the absence of any
-warranty; and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and you may at
-your option offer warranty protection in exchange for a fee.
-
-2. You may modify your copy or copies of the Program or any portion of it, thus
-forming a work based on the Program, and copy and distribute such
-modifications or work under the terms of Section 1 above, provided that you also
-meet all of these conditions:
-
-a) You must cause the modified files to carry prominent notices stating that you
-changed the files and the date of any change.
-
-b) You must cause any work that you distribute or publish, that in whole or in
-part contains or is derived from the Program or any part thereof, to be licensed
-as a whole at no charge to all third parties under the terms of this License.
-
-c) If the modified program normally reads commands interactively when run, you
-must cause it, when started running for such interactive use in the most ordinary
-way, to print or display an announcement including an appropriate copyright
-notice and a notice that there is no warranty (or else, saying that you provide a
-warranty) and that users may redistribute the program under these conditions,
-and telling the user how to view a copy of this License. (Exception: if the
-Program itself is interactive but does not normally print such an announcement,
-your work based on the Program is not required to print an announcement.)
-
-These requirements apply to the modified work as a whole. If identifiable
-sections of that work are not derived from the Program, and can be reasonably
-considered independent and separate works in themselves, then this License,
-and its terms, do not apply to those sections when you distribute them as
-separate works. But when you distribute the same sections as part of a whole
-which is a work based on the Program, the distribution of the whole must be on
-the terms of this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest your rights to
-work written entirely by you; rather, the intent is to exercise the right to control
-the distribution of derivative or collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program with the
-Program (or with a work based on the Program) on a volume of a storage or
-distribution medium does not bring the other work under the scope of this
-License.
-
-3. You may copy and distribute the Program (or a work based on it, under
-Section 2) in object code or executable form under the terms of Sections 1 and 2
-above provided that you also do one of the following:
-
-a) Accompany it with the complete corresponding machine-readable source
-code, which must be distributed under the terms of Sections 1 and 2 above on a
-medium customarily used for software interchange; or,
-
-b) Accompany it with a written offer, valid for at least three years, to give any
-third party, for a charge no more than your cost of physically performing source
-distribution, a complete machine-readable copy of the corresponding source
-code, to be distributed under the terms of Sections 1 and 2 above on a medium
-customarily used for software interchange; or,
-
-c) Accompany it with the information you received as to the offer to distribute
-corresponding source code. (This alternative is allowed only for noncommercial
-distribution and only if you received the program in object code or executable
-form with such an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for making
-modifications to it. For an executable work, complete source code means all the
-source code for all modules it contains, plus any associated interface definition
-files, plus the scripts used to control compilation and installation of the
-executable. However, as a special exception, the source code distributed need
-not include anything that is normally distributed (in either source or binary form)
-with the major components (compiler, kernel, and so on) of the operating system
-on which the executable runs, unless that component itself accompanies the
-executable.
-
-If distribution of executable or object code is made by offering access to copy
-from a designated place, then offering equivalent access to copy the source
-code from the same place counts as distribution of the source code, even though
-third parties are not compelled to copy the source along with the object code.
-
-4. You may not copy, modify, sublicense, or distribute the Program except as
-expressly provided under this License. Any attempt otherwise to copy, modify,
-sublicense or distribute the Program is void, and will automatically terminate
-your rights under this License. However, parties who have received copies, or
-rights, from you under this License will not have their licenses terminated so long
-as such parties remain in full compliance.
-
-5. You are not required to accept this License, since you have not signed it.
-However, nothing else grants you permission to modify or distribute the Program
-or its derivative works. These actions are prohibited by law if you do not accept
-this License. Therefore, by modifying or distributing the Program (or any work
-based on the Program), you indicate your acceptance of this License to do so,
-and all its terms and conditions for copying, distributing or modifying the
-Program or works based on it.
-
-6. Each time you redistribute the Program (or any work based on the Program),
-the recipient automatically receives a license from the original licensor to copy,
-distribute or modify the Program subject to these terms and conditions. You
-may not impose any further restrictions on the recipients' exercise of the rights
-granted herein. You are not responsible for enforcing compliance by third parties
-to this License.
-
-7. If, as a consequence of a court judgment or allegation of patent infringement
-or for any other reason (not limited to patent issues), conditions are imposed on
-you (whether by court order, agreement or otherwise) that contradict the
-conditions of this License, they do not excuse you from the conditions of this
-License. If you cannot distribute so as to satisfy simultaneously your obligations
-under this License and any other pertinent obligations, then as a consequence
-you may not distribute the Program at all. For example, if a patent license would
-not permit royalty-free redistribution of the Program by all those who receive
-copies directly or indirectly through you, then the only way you could satisfy
-both it and this License would be to refrain entirely from distribution of the
-Program.
-
-If any portion of this section is held invalid or unenforceable under any particular
-circumstance, the balance of the section is intended to apply and the section as
-a whole is intended to apply in other circumstances.
-
-It is not the purpose of this section to induce you to infringe any patents or other
-property right claims or to contest validity of any such claims; this section has
-the sole purpose of protecting the integrity of the free software distribution
-system, which is implemented by public license practices. Many people have
-made generous contributions to the wide range of software distributed through
-that system in reliance on consistent application of that system; it is up to the
-author/donor to decide if he or she is willing to distribute software through any
-other system and a licensee cannot impose that choice.
-
-This section is intended to make thoroughly clear what is believed to be a
-consequence of the rest of this License.
-
-8. If the distribution and/or use of the Program is restricted in certain countries
-either by patents or by copyrighted interfaces, the original copyright holder who
-places the Program under this License may add an explicit geographical
-distribution limitation excluding those countries, so that distribution is permitted
-only in or among countries not thus excluded. In such case, this License
-incorporates the limitation as if written in the body of this License.
-
-9. The Free Software Foundation may publish revised and/or new versions of the
-General Public License from time to time. Such new versions will be similar in
-spirit to the present version, but may differ in detail to address new problems or
-concerns.
-
-Each version is given a distinguishing version number. If the Program specifies a
-version number of this License which applies to it and "any later version", you
-have the option of following the terms and conditions either of that version or of
-any later version published by the Free Software Foundation. If the Program does
-not specify a version number of this License, you may choose any version ever
-published by the Free Software Foundation.
-
-10. If you wish to incorporate parts of the Program into other free programs
-whose distribution conditions are different, write to the author to ask for
-permission. For software which is copyrighted by the Free Software Foundation,
-write to the Free Software Foundation; we sometimes make exceptions for this.
-Our decision will be guided by the two goals of preserving the free status of all
-derivatives of our free software and of promoting the sharing and reuse of
-software generally.
-
-NO WARRANTY
-
-11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS
-NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
-APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE
-COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM
-"AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR
-IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
-ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
-PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE,
-YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR
-CORRECTION.
-
-12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED
-TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY
-WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS
-PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
-GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES
-ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM
-(INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
-RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
-PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY
-OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS
-BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
-
-END OF TERMS AND CONDITIONS
-
-
----------------------------------------------------------------------------
-
-The Artistic License
-
-Preamble
-
-The intent of this document is to state the conditions under which a Package
-may be copied, such that the Copyright Holder maintains some semblance of
-artistic control over the development of the package, while giving the users of the
-package the right to use and distribute the Package in a more-or-less customary
-fashion, plus the right to make reasonable modifications.
-
-Definitions:
-
--    "Package" refers to the collection of files distributed by the Copyright
-     Holder, and derivatives of that collection of files created through textual
-     modification. 
--    "Standard Version" refers to such a Package if it has not been modified,
-     or has been modified in accordance with the wishes of the Copyright
-     Holder. 
--    "Copyright Holder" is whoever is named in the copyright or copyrights for
-     the package. 
--    "You" is you, if you're thinking about copying or distributing this Package.
--    "Reasonable copying fee" is whatever you can justify on the basis of
-     media cost, duplication charges, time of people involved, and so on. (You
-     will not be required to justify it to the Copyright Holder, but only to the
-     computing community at large as a market that must bear the fee.) 
--    "Freely Available" means that no fee is charged for the item itself, though
-     there may be fees involved in handling the item. It also means that
-     recipients of the item may redistribute it under the same conditions they
-     received it. 
-
-1. You may make and give away verbatim copies of the source form of the
-Standard Version of this Package without restriction, provided that you duplicate
-all of the original copyright notices and associated disclaimers.
-
-2. You may apply bug fixes, portability fixes and other modifications derived from
-the Public Domain or from the Copyright Holder. A Package modified in such a
-way shall still be considered the Standard Version.
-
-3. You may otherwise modify your copy of this Package in any way, provided
-that you insert a prominent notice in each changed file stating how and when
-you changed that file, and provided that you do at least ONE of the following:
-
-     a) place your modifications in the Public Domain or otherwise
-     make them Freely Available, such as by posting said modifications
-     to Usenet or an equivalent medium, or placing the modifications on
-     a major archive site such as ftp.uu.net, or by allowing the
-     Copyright Holder to include your modifications in the Standard
-     Version of the Package.
-
-     b) use the modified Package only within your corporation or
-     organization.
-
-     c) rename any non-standard executables so the names do not
-     conflict with standard executables, which must also be provided,
-     and provide a separate manual page for each non-standard
-     executable that clearly documents how it differs from the Standard
-     Version.
-
-     d) make other distribution arrangements with the Copyright Holder.
-
-4. You may distribute the programs of this Package in object code or executable
-form, provided that you do at least ONE of the following:
-
-     a) distribute a Standard Version of the executables and library
-     files, together with instructions (in the manual page or equivalent)
-     on where to get the Standard Version.
-
-     b) accompany the distribution with the machine-readable source of
-     the Package with your modifications.
-
-     c) accompany any non-standard executables with their
-     corresponding Standard Version executables, giving the
-     non-standard executables non-standard names, and clearly
-     documenting the differences in manual pages (or equivalent),
-     together with instructions on where to get the Standard Version.
-
-     d) make other distribution arrangements with the Copyright Holder.
-
-5. You may charge a reasonable copying fee for any distribution of this Package.
-You may charge any fee you choose for support of this Package. You may not
-charge a fee for this Package itself. However, you may distribute this Package in
-aggregate with other (possibly commercial) programs as part of a larger
-(possibly commercial) software distribution provided that you do not advertise
-this Package as a product of your own.
-
-6. The scripts and library files supplied as input to or produced as output from
-the programs of this Package do not automatically fall under the copyright of this
-Package, but belong to whomever generated them, and may be sold
-commercially, and may be aggregated with this Package.
-
-7. C or perl subroutines supplied by you and linked into this Package shall not
-be considered part of this Package.
-
-8. Aggregation of this Package with a commercial distribution is always permitted
-provided that the use of this Package is embedded; that is, when no overt attempt
-is made to make this Package's interfaces visible to the end user of the
-commercial distribution. Such use shall not be construed as a distribution of
-this Package.
-
-9. The name of the Copyright Holder may not be used to endorse or promote
-products derived from this software without specific prior written permission.
-
-10. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
-IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
-WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
-PURPOSE.
-
-The End
-
-
diff --git a/doc/modules/LICENSE.Email-Address b/doc/modules/LICENSE.Email-Address
deleted file mode 100644 (file)
index 8d38927..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-Copyright (c) 2004 Casey West.  All rights reserved.
-
-This module is free software; you can redistribute it and/or modify it
-under the same terms as Perl itself.
-
-Perl is distributed under your choice of the GNU General Public License or
-the Artistic License.
-
-The complete text of the GNU General Public License can be found in
-/usr/share/common-licenses/GPL and the Artistic Licence can be found
-in /usr/share/common-licenses/Artistic.
diff --git a/doc/modules/LICENSE.List-MoreUtils b/doc/modules/LICENSE.List-MoreUtils
deleted file mode 100644 (file)
index eb3a238..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-COPYRIGHT AND LICENSE
-
-Copyright (C) 2004-2006 by Tassilo von Parseval
-
-This library is free software; you can redistribute it and/or modify
-it under the same terms as Perl itself, either Perl version 5.8.4 or,
-at your option, any later version of Perl 5 you may have available.
diff --git a/doc/modules/LICENSE.List-UtilsBy b/doc/modules/LICENSE.List-UtilsBy
deleted file mode 100644 (file)
index 67ba0bf..0000000
+++ /dev/null
@@ -1,378 +0,0 @@
-This software is copyright (c) 2012 by Paul Evans <leonerd@leonerd.org.uk>.
-
-This is free software; you can redistribute it and/or modify it under
-the same terms as the Perl 5 programming language system itself.
-
-Terms of the Perl programming language system itself
-
-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"
-
---- The GNU General Public License, Version 1, February 1989 ---
-
-This software is Copyright (c) 2012 by Paul Evans <leonerd@leonerd.org.uk>.
-
-This is free software, licensed under:
-
-  The GNU General Public License, Version 1, February 1989
-
-                    GNU GENERAL PUBLIC LICENSE
-                     Version 1, February 1989
-
- Copyright (C) 1989 Free Software Foundation, Inc.
- 51 Franklin St, Suite 500, Boston, MA  02110-1335  USA
-
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-                            Preamble
-
-  The license agreements of most software companies try to keep users
-at the mercy of those companies.  By contrast, our General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users.  The
-General Public License applies to the Free Software Foundation's
-software and to any other program whose authors commit to using it.
-You can use it for your programs, too.
-
-  When we speak of free software, we are referring to freedom, not
-price.  Specifically, the General Public License is designed to make
-sure that you have the freedom to give away or sell copies of free
-software, that you receive source code or can get it if you want it,
-that you can change the software or use pieces of it in new free
-programs; and that you know you can do these things.
-
-  To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
-  For example, if you distribute copies of a such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have.  You must make sure that they, too, receive or can get the
-source code.  And you must tell them their rights.
-
-  We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
-  Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software.  If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
-  The precise terms and conditions for copying, distribution and
-modification follow.
-
-                    GNU GENERAL PUBLIC LICENSE
-   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
-  0. This License Agreement applies to any program or other work which
-contains a notice placed by the copyright holder saying it may be
-distributed under the terms of this General Public License.  The
-"Program", below, refers to any such program or work, and a "work based
-on the Program" means either the Program or any work containing the
-Program or a portion of it, either verbatim or with modifications.  Each
-licensee is addressed as "you".
-
-  1. You may copy and distribute verbatim copies of the Program's source
-code as you receive it, in any medium, provided that you conspicuously and
-appropriately publish on each copy an appropriate copyright notice and
-disclaimer of warranty; keep intact all the notices that refer to this
-General Public License and to the absence of any warranty; and give any
-other recipients of the Program a copy of this General Public License
-along with the Program.  You may charge a fee for the physical act of
-transferring a copy.
-
-  2. You may modify your copy or copies of the Program or any portion of
-it, and copy and distribute such modifications under the terms of Paragraph
-1 above, provided that you also do the following:
-
-    a) cause the modified files to carry prominent notices stating that
-    you changed the files and the date of any change; and
-
-    b) cause the whole of any work that you distribute or publish, that
-    in whole or in part contains the Program or any part thereof, either
-    with or without modifications, to be licensed at no charge to all
-    third parties under the terms of this General Public License (except
-    that you may choose to grant warranty protection to some or all
-    third parties, at your option).
-
-    c) If the modified program normally reads commands interactively when
-    run, you must cause it, when started running for such interactive use
-    in the simplest and most usual way, to print or display an
-    announcement including an appropriate copyright notice and a notice
-    that there is no warranty (or else, saying that you provide a
-    warranty) and that users may redistribute the program under these
-    conditions, and telling the user how to view a copy of this General
-    Public License.
-
-    d) You may charge a fee for the physical act of transferring a
-    copy, and you may at your option offer warranty protection in
-    exchange for a fee.
-
-Mere aggregation of another independent work with the Program (or its
-derivative) on a volume of a storage or distribution medium does not bring
-the other work under the scope of these terms.
-
-  3. You may copy and distribute the Program (or a portion or derivative of
-it, under Paragraph 2) in object code or executable form under the terms of
-Paragraphs 1 and 2 above provided that you also do one of the following:
-
-    a) accompany it with the complete corresponding machine-readable
-    source code, which must be distributed under the terms of
-    Paragraphs 1 and 2 above; or,
-
-    b) accompany it with a written offer, valid for at least three
-    years, to give any third party free (except for a nominal charge
-    for the cost of distribution) a complete machine-readable copy of the
-    corresponding source code, to be distributed under the terms of
-    Paragraphs 1 and 2 above; or,
-
-    c) accompany it with the information you received as to where the
-    corresponding source code may be obtained.  (This alternative is
-    allowed only for noncommercial distribution and only if you
-    received the program in object code or executable form alone.)
-
-Source code for a work means the preferred form of the work for making
-modifications to it.  For an executable file, complete source code means
-all the source code for all modules it contains; but, as a special
-exception, it need not include source code for modules which are standard
-libraries that accompany the operating system on which the executable
-file runs, or for standard header files or definitions files that
-accompany that operating system.
-
-  4. You may not copy, modify, sublicense, distribute or transfer the
-Program except as expressly provided under this General Public License.
-Any attempt otherwise to copy, modify, sublicense, distribute or transfer
-the Program is void, and will automatically terminate your rights to use
-the Program under this License.  However, parties who have received
-copies, or rights to use copies, from you under this General Public
-License will not have their licenses terminated so long as such parties
-remain in full compliance.
-
-  5. By copying, distributing or modifying the Program (or any work based
-on the Program) you indicate your acceptance of this license to do so,
-and all its terms and conditions.
-
-  6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the original
-licensor to copy, distribute or modify the Program subject to these
-terms and conditions.  You may not impose any further restrictions on the
-recipients' exercise of the rights granted herein.
-
-  7. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time.  Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number.  If the Program
-specifies a version number of the license which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation.  If the Program does not specify a version number of
-the license, you may choose any version ever published by the Free Software
-Foundation.
-
-  8. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission.  For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this.  Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
-                            NO WARRANTY
-
-  9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
-  10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
-                     END OF TERMS AND CONDITIONS
-
-        Appendix: How to Apply These Terms to Your New Programs
-
-  If you develop a new program, and you want it to be of the greatest
-possible use to humanity, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these
-terms.
-
-  To do so, attach the following notices to the program.  It is safest to
-attach them to the start of each source file to most effectively convey
-the exclusion of warranty; and each file should have at least the
-"copyright" line and a pointer to where the full notice is found.
-
-    <one line to give the program's name and a brief idea of what it does.>
-    Copyright (C) 19yy  <name of author>
-
-    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 1, or (at your option)
-    any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 USA
-
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
-    Gnomovision version 69, Copyright (C) 19xx name of author
-    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
-    This is free software, and you are welcome to redistribute it
-    under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the
-appropriate parts of the General Public License.  Of course, the
-commands you use may be called something other than `show w' and `show
-c'; they could even be mouse-clicks or menu items--whatever suits your
-program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary.  Here a sample; alter the names:
-
-  Yoyodyne, Inc., hereby disclaims all copyright interest in the
-  program `Gnomovision' (a program to direct compilers to make passes
-  at assemblers) written by James Hacker.
-
-  <signature of Ty Coon>, 1 April 1989
-  Ty Coon, President of Vice
-
-That's all there is to it!
-
-
---- The Artistic License 1.0 ---
-
-This software is Copyright (c) 2012 by Paul Evans <leonerd@leonerd.org.uk>.
-
-This is free software, licensed under:
-
-  The Artistic License 1.0
-
-The Artistic License
-
-Preamble
-
-The intent of this document is to state the conditions under which a Package
-may be copied, such that the Copyright Holder maintains some semblance of
-artistic control over the development of the package, while giving the users of
-the package the right to use and distribute the Package in a more-or-less
-customary fashion, plus the right to make reasonable modifications.
-
-Definitions:
-
-  - "Package" refers to the collection of files distributed by the Copyright
-    Holder, and derivatives of that collection of files created through
-    textual modification.
-  - "Standard Version" refers to such a Package if it has not been modified,
-    or has been modified in accordance with the wishes of the Copyright
-    Holder.
-  - "Copyright Holder" is whoever is named in the copyright or copyrights for
-    the package.
-  - "You" is you, if you're thinking about copying or distributing this Package.
-  - "Reasonable copying fee" is whatever you can justify on the basis of media
-    cost, duplication charges, time of people involved, and so on. (You will
-    not be required to justify it to the Copyright Holder, but only to the
-    computing community at large as a market that must bear the fee.)
-  - "Freely Available" means that no fee is charged for the item itself, though
-    there may be fees involved in handling the item. It also means that
-    recipients of the item may redistribute it under the same conditions they
-    received it.
-
-1. You may make and give away verbatim copies of the source form of the
-Standard Version of this Package without restriction, provided that you
-duplicate all of the original copyright notices and associated disclaimers.
-
-2. You may apply bug fixes, portability fixes and other modifications derived
-from the Public Domain or from the Copyright Holder. A Package modified in such
-a way shall still be considered the Standard Version.
-
-3. You may otherwise modify your copy of this Package in any way, provided that
-you insert a prominent notice in each changed file stating how and when you
-changed that file, and provided that you do at least ONE of the following:
-
-  a) place your modifications in the Public Domain or otherwise make them
-     Freely Available, such as by posting said modifications to Usenet or an
-     equivalent medium, or placing the modifications on a major archive site
-     such as ftp.uu.net, or by allowing the Copyright Holder to include your
-     modifications in the Standard Version of the Package.
-
-  b) use the modified Package only within your corporation or organization.
-
-  c) rename any non-standard executables so the names do not conflict with
-     standard executables, which must also be provided, and provide a separate
-     manual page for each non-standard executable that clearly documents how it
-     differs from the Standard Version.
-
-  d) make other distribution arrangements with the Copyright Holder.
-
-4. You may distribute the programs of this Package in object code or executable
-form, provided that you do at least ONE of the following:
-
-  a) distribute a Standard Version of the executables and library files,
-     together with instructions (in the manual page or equivalent) on where to
-     get the Standard Version.
-
-  b) accompany the distribution with the machine-readable source of the Package
-     with your modifications.
-
-  c) accompany any non-standard executables with their corresponding Standard
-     Version executables, giving the non-standard executables non-standard
-     names, and clearly documenting the differences in manual pages (or
-     equivalent), together with instructions on where to get the Standard
-     Version.
-
-  d) make other distribution arrangements with the Copyright Holder.
-
-5. You may charge a reasonable copying fee for any distribution of this
-Package.  You may charge any fee you choose for support of this Package. You
-may not charge a fee for this Package itself. However, you may distribute this
-Package in aggregate with other (possibly commercial) programs as part of a
-larger (possibly commercial) software distribution provided that you do not
-advertise this Package as a product of your own.
-
-6. The scripts and library files supplied as input to or produced as output
-from the programs of this Package do not automatically fall under the copyright
-of this Package, but belong to whomever generated them, and may be sold
-commercially, and may be aggregated with this Package.
-
-7. C or perl subroutines supplied by you and linked into this Package shall not
-be considered part of this Package.
-
-8. The name of the Copyright Holder may not be used to endorse or promote
-products derived from this software without specific prior written permission.
-
-9. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
-WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
-MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
-
-The End
diff --git a/doc/modules/README.CGI-Ajax b/doc/modules/README.CGI-Ajax
deleted file mode 100644 (file)
index 1af8860..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-pod2text CGI::Perljax.pm > README
-
-CGI::Perljax
-
-Perljax - a perl-specific system for writing AJAX- or
-DHTML-based web applications.
-
-
-Perljax provides a unique mechanism for using perl code
-asynchronously from javascript using AJAX to access user-written
-perl functions/methods. Perljax unburdens the user from having to
-write any javascript, except for having to associate an exported
-method with a document-defined event (such as onClick, onKeyUp,
-etc). Only in the more advanced implementations of a exported perl
-method would a user need to write custom javascript. Perljax supports
-methods that return single results, or multiple results to the web
-page. No other projects that we know of are like Perljax for the
-following reasons: 1. Perljax is targeted specifically for perl
-development. 2. Perljax shields the user from having to write any
-javascript at all (unless they want to).  3. The URL for the HTTP GET
-request is automatically generated based on HTML layout and events,
-and the page is then dynamically updated.  4. Perljax is not part
-of a Content Management System, or some other larger project.
-
-
-INSTALL
-
-perl Makefile.PL
-make
-make test
-make install
-
-*If you are on a windows box you should use 'nmake' rather than 'make'.
-
-Installation will place Perljax into the system perl @INC path, but it
-is important that you make sure mod_perl uses this path (which is
-mod_perl's default behavior, and also assuming you use mod_perl, and
-not just run perl as a CGI).
-
-Example scripts are provided in the source script directory, and can
-also be seen on the project's website, http://www.perljax.us.
diff --git a/doc/modules/README.File-Slurp b/doc/modules/README.File-Slurp
deleted file mode 100644 (file)
index 1a7a9d4..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-File::Slurp.pm version 0.04
-===========================
-
-This module provides subroutines to read or write entire files with a
-simple call.  It also has a subroutine for reading the list of filenames
-in a directory.
-
-In the extras/ directory you can read an article (slurp_article.pod)
-about file slurping and also run a benchmark (slurp_bench.pl) that
-compares many ways of slurping/spewing files.
-
-This module was first written and owned by David Muir Sharnoff (MUIR on
-CPAN).  I checked out his module and decided to write a new version
-which would be faster, and with many more features.  To that end, David
-graciously transfered the namespace to me.
-
-Since then, I discovered and fixed a bug in the original module's test
-script (which had only 7 tests), which is included now as t/original.t.
-This module now has 164 tests in 7 test scripts, and passes on Windows,
-Linux, Solaris and Mac OS X.
-
-There have been some comments about the somewhat unusual version number.
-The problem was that David used a future date (2004.0904) in his version
-number, and the only way I could get CPAN to index my new module was to
-make it have a version number higher than the old one, so I chose the
-9999 prefix and appended the real revision number to it.
-
-INSTALLATION
-
-To install this module type the following:
-
-   perl Makefile.PL
-   make
-   make test
-   make install
-
-COPYRIGHT AND LICENCE
-
-Copyright (C) 2003 Uri Guttman <uri@stemsystems.com>
-
-Licensed the same as Perl.
diff --git a/doc/modules/README.List-UtilsBy b/doc/modules/README.List-UtilsBy
deleted file mode 100644 (file)
index efdceb3..0000000
+++ /dev/null
@@ -1,238 +0,0 @@
-NAME
-    `List::UtilsBy' - higher-order list utility functions
-
-SYNOPSIS
-     use List::UtilsBy qw( nsort_by min_by );
-
-     use File::stat qw( stat );
-     my @files_by_age = nsort_by { stat($_)->mtime } @files;
-
-     my $shortest_name = min_by { length } @names;
-
-DESCRIPTION
-    This module provides a number of list utility functions, all of which
-    take an initial code block to control their behaviour. They are
-    variations on similar core perl or `List::Util' functions of similar
-    names, but which use the block to control their behaviour. For example,
-    the core Perl function `sort' takes a list of values and returns them,
-    sorted into order by their string value. The `sort_by' function sorts
-    them according to the string value returned by the extra function, when
-    given each value.
-
-     my @names_sorted = sort @names;
-
-     my @people_sorted = sort_by { $_->name } @people;
-
-FUNCTIONS
-  @vals = sort_by { KEYFUNC } @vals
-    Returns the list of values sorted according to the string values
-    returned by the `KEYFUNC' block or function. A typical use of this may
-    be to sort objects according to the string value of some accessor, such
-    as
-
-     sort_by { $_->name } @people
-
-    The key function is called in scalar context, being passed each value in
-    turn as both `$_' and the only argument in the parameters, `@_'. The
-    values are then sorted according to string comparisons on the values
-    returned.
-
-    This is equivalent to
-
-     sort { $a->name cmp $b->name } @people
-
-    except that it guarantees the `name' accessor will be executed only once
-    per value.
-
-    One interesting use-case is to sort strings which may have numbers
-    embedded in them "naturally", rather than lexically.
-
-     sort_by { s/(\d+)/sprintf "%09d", $1/eg; $_ } @strings
-
-    This sorts strings by generating sort keys which zero-pad the embedded
-    numbers to some level (9 digits in this case), helping to ensure the
-    lexical sort puts them in the correct order.
-
-  @vals = nsort_by { KEYFUNC } @vals
-    Similar to `sort_by' but compares its key values numerically.
-
-  @vals = rev_sort_by { KEYFUNC } @vals
-  @vals = rev_nsort_by { KEYFUNC } @vals
-    Similar to `sort_by' and `nsort_by' but returns the list in the reverse
-    order. Equivalent to
-
-     @vals = reverse sort_by { KEYFUNC } @vals
-
-    except that these functions are slightly more efficient because they
-    avoid the final `reverse' operation.
-
-  $optimal = max_by { KEYFUNC } @vals
-  @optimal = max_by { KEYFUNC } @vals
-    Returns the (first) value from `@vals' that gives the numerically
-    largest result from the key function.
-
-     my $tallest = max_by { $_->height } @people
-
-     use File::stat qw( stat );
-     my $newest = max_by { stat($_)->mtime } @files;
-
-    In scalar context, the first maximal value is returned. In list context,
-    a list of all the maximal values is returned. This may be used to obtain
-    positions other than the first, if order is significant.
-
-    If called on an empty list, an empty list is returned.
-
-    For symmetry with the `nsort_by' function, this is also provided under
-    the name `nmax_by' since it behaves numerically.
-
-  $optimal = min_by { KEYFUNC } @vals
-  @optimal = min_by { KEYFUNC } @vals
-    Similar to `max_by' but returns values which give the numerically
-    smallest result from the key function. Also provided as `nmin_by'
-
-  @vals = uniq_by { KEYFUNC } @vals
-    Returns a list of the subset of values for which the key function block
-    returns unique values. The first value yielding a particular key is
-    chosen, subsequent values are rejected.
-
-     my @some_fruit = uniq_by { $_->colour } @fruit;
-
-    To select instead the last value per key, reverse the input list. If the
-    order of the results is significant, don't forget to reverse the result
-    as well:
-
-     my @some_fruit = reverse uniq_by { $_->colour } reverse @fruit;
-
-  %parts = partition_by { KEYFUNC } @vals
-    Returns a key/value list of ARRAY refs containing all the original
-    values distributed according to the result of the key function block.
-    Each value will be an ARRAY ref containing all the values which returned
-    the string from the key function, in their original order.
-
-     my %balls_by_colour = partition_by { $_->colour } @balls;
-
-    Because the values returned by the key function are used as hash keys,
-    they ought to either be strings, or at least well-behaved as strings
-    (such as numbers, or object references which overload stringification in
-    a suitable manner).
-
-  %counts = count_by { KEYFUNC } @vals
-    Returns a key/value list of integers, giving the number of times the key
-    function block returned the key, for each value in the list.
-
-     my %count_of_balls = count_by { $_->colour } @balls;
-
-    Because the values returned by the key function are used as hash keys,
-    they ought to either be strings, or at least well-behaved as strings
-    (such as numbers, or object references which overload stringification in
-    a suitable manner).
-
-  @vals = zip_by { ITEMFUNC } \@arr0, \@arr1, \@arr2,...
-    Returns a list of each of the values returned by the function block,
-    when invoked with values from across each each of the given ARRAY
-    references. Each value in the returned list will be the result of the
-    function having been invoked with arguments at that position, from
-    across each of the arrays given.
-
-     my @transposition = zip_by { [ @_ ] } @matrix;
-
-     my @names = zip_by { "$_[1], $_[0]" } \@firstnames, \@surnames;
-
-     print zip_by { "$_[0] => $_[1]\n" } [ keys %hash ], [ values %hash ];
-
-    If some of the arrays are shorter than others, the function will behave
-    as if they had `undef' in the trailing positions. The following two
-    lines are equivalent:
-
-     zip_by { f(@_) } [ 1, 2, 3 ], [ "a", "b" ]
-     f( 1, "a" ), f( 2, "b" ), f( 3, undef )
-
-    The item function is called by `map', so if it returns a list, the
-    entire list is included in the result. This can be useful for example,
-    for generating a hash from two separate lists of keys and values
-
-     my %nums = zip_by { @_ } [qw( one two three )], [ 1, 2, 3 ];
-     # %nums = ( one => 1, two => 2, three => 3 )
-
-    (A function having this behaviour is sometimes called `zipWith', e.g. in
-    Haskell, but that name would not fit the naming scheme used by this
-    module).
-
-  $arr0, $arr1, $arr2, ... = unzip_by { ITEMFUNC } @vals
-    Returns a list of ARRAY references containing the values returned by the
-    function block, when invoked for each of the values given in the input
-    list. Each of the returned ARRAY references will contain the values
-    returned at that corresponding position by the function block. That is,
-    the first returned ARRAY reference will contain all the values returned
-    in the first position by the function block, the second will contain all
-    the values from the second position, and so on.
-
-     my ( $firstnames, $lastnames ) = unzip_by { m/^(.*?) (.*)$/ } @names;
-
-    If the function returns lists of differing lengths, the result will be
-    padded with `undef' in the missing elements.
-
-    This function is an inverse of `zip_by', if given a corresponding
-    inverse function.
-
-  @vals = extract_by { SELECTFUNC } @arr
-    Removes elements from the referenced array on which the selection
-    function returns true, and returns a list containing those elements.
-    This function is similar to `grep', except that it modifies the
-    referenced array to remove the selected values from it, leaving only the
-    unselected ones.
-
-     my @red_balls = extract_by { $_->color eq "red" } @balls;
-
-     # Now there are no red balls in the @balls array
-
-    This function modifies a real array, unlike most of the other functions
-    in this module. Because of this, it requires a real array, not just a
-    list.
-
-    This function is implemented by invoking `splice()' on the array, not by
-    constructing a new list and assigning it. One result of this is that
-    weak references will not be disturbed.
-
-     extract_by { !defined $_ } @refs;
-
-    will leave weak references weakened in the `@refs' array, whereas
-
-     @refs = grep { defined $_ } @refs;
-
-    will strengthen them all again.
-
-  @vals = weighted_shuffle_by { WEIGHTFUNC } @vals
-    Returns the list of values shuffled into a random order. The
-    randomisation is not uniform, but weighted by the value returned by the
-    `WEIGHTFUNC'. The probabilty of each item being returned first will be
-    distributed with the distribution of the weights, and so on recursively
-    for the remaining items.
-
-  @vals = bundle_by { BLOCKFUNC } $number, @vals
-    Similar to a regular `map' functional, returns a list of the values
-    returned by `BLOCKFUNC'. Values from the input list are given to the
-    block function in bundles of `$number'.
-
-    If given a list of values whose length does not evenly divide by
-    `$number', the final call will be passed fewer elements than the others.
-
-TODO
-    * XS implementations
-        These functions are currently all written in pure perl. Some at
-        least, may benefit from having XS implementations to speed up their
-        logic.
-
-    * Merge into List::Util or List::MoreUtils
-        This module shouldn't really exist. The functions should instead be
-        part of one of the existing modules that already contain many list
-        utility functions. Having Yet Another List Utilty Module just
-        worsens the problem.
-
-        I have attempted to contact the authors of both of the above
-        modules, to no avail; therefore I decided it best to write and
-        release this code here anyway so that it is at least on CPAN. Once
-        there, we can then see how best to merge it into an existing module.
-
-AUTHOR
-    Paul Evans <leonerd@leonerd.org.uk>
index c1cc623..31442a9 100644 (file)
@@ -1,39 +1,36 @@
-PDF-Table version 0.9.3
-=====================
-SOME NOTES
+# PDF::Table
 
-This module is intended for table generation using PDF::API2
-The current version is RC1 and I will apreciate any feedback.
-Developed and tested on i586 Linux SuSE 10.0 and perl, v5.8.7 built for i586-linux-thread-multi
+This module creates text blocks and tables into PDF documents using PDF::API2 Perl module.
 
-CHANGES
+The official repository for PDF::Table module collaboration:
+https://github.com/kamenov/PDF-Table.git
 
-Since version 0.02 there are many changes. 
-See the ChangeLog file or make a diff from the tools menu in CPAN
+Any patches, pull requests, issues and feedback are more than welcome.
 
-CONTACTS 
+## Installation
 
-See http://search.cpan.org/~omega/
+To install the module from CPAN, please type the following command:
 
-INSTALLATION
+```cpanm PDF::Table```
 
-To install this module type the following:
+To test or add features to this module, please type the following command:
 
-   perl Makefile.PL
-   make
-   make test
-   make install
+```cpanm .```
 
-DEPENDENCIES
+## Changes
+To see a list of changes, please do one or more of the following:
+- Read the [Changes](Changes) file
+- Review commits history on GitHub
+- Make a diff from the tools menu at CPAN
 
-This module requires these other modules and libraries:
+## Contacts 
+@deskata on Twitter 
 
-  PDF::API2
-
-COPYRIGHT AND LICENCE
-
-Put the correct copyright and licence information here.
+- Use the issue tracker on GitHub
+- See http://search.cpan.org/~omega/
+- See http://search.cpan.org/~jbazik/
 
+## License
 Copyright (C) 2006 by Daemmon Hughes
 
 Extended by Desislav Kamenov since version 0.02
@@ -41,5 +38,3 @@ Extended by Desislav Kamenov since version 0.02
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself, either Perl version 5.8.7 or,
 at your option, any later version of Perl 5 you may have available.
-
-
diff --git a/doc/modules/README.Sort-Naturally b/doc/modules/README.Sort-Naturally
deleted file mode 100644 (file)
index 4fa4f1e..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-README for Sort::Naturally
-                                        Time-stamp: "2001-05-25 21:17:33 MDT"
-
-                           Sort::Naturally
-
-[extracted from the Pod...]
-
-NAME
-     Sort::Naturally -- sort lexically, but sort numeral parts
-     numerically
-
-SYNOPSIS
-       @them = nsort(qw(
-        foo12a foo12z foo13a foo 14 9x foo12 fooa foolio Foolio Foo12a
-       ));
-       print join(' ', @them), "\n";
-
-     Prints:
-
-       9x 14 foo fooa foolio Foolio foo12 foo12a Foo12a foo12z foo13a
-
-     (Or "foo12a" + "Foo12a" and "foolio" + "Foolio" and might be
-     switched, depending on your locale.)
-
-DESCRIPTION
-     This module exports two functions, nsort and ncmp; they are
-     used in implementing my idea of a "natural sorting"
-     algorithm.  Under natural sorting, numeric substrings are
-     compared numerically, and other word-characters are compared
-     lexically.
-
-     This is the way I define natural sorting:
-
-     o    Non-numeric word-character substrings are sorted
-          lexically, case-insensitively: "Foo" comes between
-          "fish" and "fowl".
-
-     o    Numeric substrings are sorted numerically:  "100" comes
-          after "20", not before.
-
-     o    \W substrings (neither words-characters nor digits) are
-          ignored.
-
-     o    Our use of \w, \d, \D, and \W is locale-sensitive:
-          Sort::Naturally uses a use locale statement.
-
-     o    When comparing two strings, where a numeric substring
-          in one place is not up against a numeric substring in
-          another, the non-numeric always comes first.  This is
-          fudged by reading pretending that the lack of a number
-          substring has the value -1, like so:
-
-            foo       =>  "foo",  -1
-            foobar    =>  "foo",  -1,  "bar"
-            foo13     =>  "foo",  13,
-            foo13xyz  =>  "foo",  13,  "xyz"
-
-          That's so that "foo" will come before "foo13", which
-          will come before "foobar".
-
-     o    The start of a string is exceptional: leading non-\W
-          (non-word, non-digit) components are are ignored, and
-          numbers come before letters.
-
-     o    I define "numeric substring" just as sequences matching
-          m/\d+/ -- scientific notation, commas, decimals, etc.,
-          are not seen.  If your data has thousands separators in
-          numbers ("20,000 Leagues Under The Sea" or "20.000
-          lieues sous les mers"), consider stripping them before
-          feeding them to nsort or ncmp.
-
-[end Pod extract]
-
-
-INSTALLATION
-
-You install Sort::Naturally, as you would install any perl module
-library, by running these commands:
-
-   perl Makefile.PL
-   make
-   make test
-   make install
-
-If you want to install a private copy of Sort::Naturally in your home
-directory, then you should try to produce the initial Makefile with
-something like this command:
-
-  perl Makefile.PL LIB=~/perl
-
-See perldoc perlmodinstall for more information on installing modules.
-
-
-DOCUMENTATION
-
-POD-format documentation is included in Naturally.pm.  POD is readable
-with the 'perldoc' utility.  See ChangeLog for recent changes.
-
-
-SUPPORT
-
-Questions, bug reports, useful code bits, and suggestions for
-Sort::Naturally should just be sent to me at sburke@cpan.org
-
-
-AVAILABILITY
-
-The latest version of Sort::Naturally is available from the
-Comprehensive Perl Archive Network (CPAN).  Visit
-<http://www.perl.com/CPAN/> to find a CPAN site near you.
-
-
-COPYRIGHT
-
-Copyright 2001, Sean M. Burke <sburke@cpan.org>, all rights
-reserved.
-
-The programs and documentation in this dist are distributed in
-the hope that they will be useful, but without any warranty; without
-even the implied warranty of merchantability or fitness for a
-particular purpose.
-
-This library is free software; you can redistribute it and/or modify
-it under the same terms as Perl itself.
diff --git a/doc/modules/README.YAML b/doc/modules/README.YAML
deleted file mode 100644 (file)
index 0fbb2fd..0000000
+++ /dev/null
@@ -1,611 +0,0 @@
-NAME
-    YAML - YAML Ain't Markup Language (tm)
-
-SYNOPSIS
-        use YAML;
-    
-        # Load a YAML stream of 3 YAML documents into Perl data structures.
-        my ($hashref, $arrayref, $string) = Load(<<'...');
-        ---
-        name: ingy
-        age: old
-        weight: heavy
-        # I should comment that I also like pink, but don't tell anybody.
-        favorite colors:
-            - red
-            - green
-            - blue
-        ---
-        - Clark Evans
-        - Oren Ben-Kiki
-        - Ingy döt Net
-        --- >
-        You probably think YAML stands for "Yet Another Markup Language". It
-        ain't! YAML is really a data serialization language. But if you want
-        to think of it as a markup, that's OK with me. A lot of people try
-        to use XML as a serialization format.
-    
-        "YAML" is catchy and fun to say. Try it. "YAML, YAML, YAML!!!"
-        ...
-    
-        # Dump the Perl data structures back into YAML.
-        print Dump($string, $arrayref, $hashref); 
-    
-        # YAML::Dump is used the same way you'd use Data::Dumper::Dumper
-        use Data::Dumper;
-        print Dumper($string, $arrayref, $hashref); 
-
-DESCRIPTION
-    The YAML.pm module implements a YAML Loader and Dumper based on the YAML
-    1.0 specification. <http://www.yaml.org/spec/>
-
-    YAML is a generic data serialization language that is optimized for
-    human readability. It can be used to express the data structures of most
-    modern programming languages. (Including Perl!!!)
-
-    For information on the YAML syntax, please refer to the YAML
-    specification.
-
-WHY YAML IS COOL
-    YAML is readable for people.
-        It makes clear sense out of complex data structures. You should find
-        that YAML is an exceptional data dumping tool. Structure is shown
-        through indentation, YAML supports recursive data, and hash keys are
-        sorted by default. In addition, YAML supports several styles of
-        scalar formatting for different types of data.
-
-    YAML is editable.
-        YAML was designed from the ground up to be an excellent syntax for
-        configuration files. Almost all programs need configuration files,
-        so why invent a new syntax for each one? And why subject users to
-        the complexities of XML or native Perl code?
-
-    YAML is multilingual.
-        Yes, YAML supports Unicode. But I'm actually referring to
-        programming languages. YAML was designed to meet the serialization
-        needs of Perl, Python, Ruby, Tcl, PHP, Javascript and Java. It was
-        also designed to be interoperable between those languages. That
-        means YAML serializations produced by Perl can be processed by
-        Python.
-
-    YAML is taint safe.
-        Using modules like Data::Dumper for serialization is fine as long as
-        you can be sure that nobody can tamper with your data files or
-        transmissions. That's because you need to use Perl's "eval()"
-        built-in to deserialize the data. Somebody could add a snippet of
-        Perl to erase your files.
-
-        YAML's parser does not need to eval anything.
-
-    YAML is full featured.
-        YAML can accurately serialize all of the common Perl data structures
-        and deserialize them again without losing data relationships.
-        Although it is not 100% perfect (no serializer is or can be
-        perfect), it fares as well as the popular current modules:
-        Data::Dumper, Storable, XML::Dumper and Data::Denter.
-
-        YAML.pm also has the ability to handle code (subroutine) references
-        and typeglobs. (Still experimental) These features are not found in
-        Perl's other serialization modules.
-
-    YAML is extensible.
-        The YAML language has been designed to be flexible enough to solve
-        it's own problems. The markup itself has 3 basic construct which
-        resemble Perl's hash, array and scalar. By default, these map to
-        their Perl equivalents. But each YAML node also supports a tagging
-        mechanism (type system) which can cause that node to be interpreted
-        in a completely different manner. That's how YAML can support object
-        serialization and oddball structures like Perl's typeglob.
-
-YAML IMPLEMENTATIONS IN PERL
-    This module, YAML.pm, is really just the interface module for YAML
-    modules written in Perl. The basic interface for YAML consists of two
-    functions: "Dump" and "Load". The real work is done by the modules
-    YAML::Dumper and YAML::Loader.
-
-    Different YAML module distributions can be created by subclassing
-    YAML.pm and YAML::Loader and YAML::Dumper. For example, YAML-Simple
-    consists of YAML::Simple YAML::Dumper::Simple and YAML::Loader::Simple.
-
-    Why would there be more than one implementation of YAML? Well, despite
-    YAML's offering of being a simple data format, YAML is actually very
-    deep and complex. Implementing the entirety of the YAML specification is
-    a daunting task.
-
-    For this reason I am currently working on 3 different YAML
-    implementations.
-
-    YAML
-        The main YAML distribution will keeping evolving to support the
-        entire YAML specification in pure Perl. This may not be the fastest
-        or most stable module though. Currently, YAML.pm has lots of known
-        bugs. It is mostly a great tool for dumping Perl data structures to
-        a readable form.
-
-    YAML::Lite
-        The point of YAML::Lite is to strip YAML down to the 90% that people
-        use most and offer that in a small, fast, stable, pure Perl form.
-        YAML::Lite will simply die when it is asked to do something it
-        can't.
-
-    YAML::Syck
-        "libsyck" is the C based YAML processing library used by the Ruby
-        programming language (and also Python, PHP and Pugs). YAML::Syck is
-        the Perl binding to "libsyck". It should be very fast, but may have
-        problems of its own. It will also require C compilation.
-
-        NOTE: Audrey Tang has actually completed this module and it works
-        great and is 10 times faster than YAML.pm.
-
-    In the future, there will likely be even more YAML modules. Remember,
-    people other than Ingy are allowed to write YAML modules!
-
-FUNCTIONAL USAGE
-    YAML is completely OO under the hood. Still it exports a few useful top
-    level functions so that it is dead simple to use. These functions just
-    do the OO stuff for you. If you want direct access to the OO API see the
-    documentation for YAML::Dumper and YAML::Loader.
-
-  Exported Functions
-    The following functions are exported by YAML.pm by default. The reason
-    they are exported is so that YAML works much like Data::Dumper. If you
-    don't want functions to be imported, just use YAML with an empty import
-    list:
-
-        use YAML ();
-
-    Dump(list-of-Perl-data-structures)
-        Turn Perl data into YAML. This function works very much like
-        Data::Dumper::Dumper(). It takes a list of Perl data strucures and
-        dumps them into a serialized form. It returns a string containing
-        the YAML stream. The structures can be references or plain scalars.
-
-    Load(string-containing-a-YAML-stream)
-        Turn YAML into Perl data. This is the opposite of Dump. Just like
-        Storable's thaw() function or the eval() function in relation to
-        Data::Dumper. It parses a string containing a valid YAML stream into
-        a list of Perl data structures.
-
-  Exportable Functions
-    These functions are not exported by default but you can request them in
-    an import list like this:
-
-        use YAML qw'freeze thaw Bless';
-
-    freeze() and thaw()
-        Aliases to Dump() and Load() for Storable fans. This will also allow
-        YAML.pm to be plugged directly into modules like POE.pm, that use
-        the freeze/thaw API for internal serialization.
-
-    DumpFile(filepath, list)
-        Writes the YAML stream to a file instead of just returning a string.
-
-    LoadFile(filepath)
-        Reads the YAML stream from a file instead of a string.
-
-    Bless(perl-node, [yaml-node | class-name])
-        Associate a normal Perl node, with a yaml node. A yaml node is an
-        object tied to the YAML::Node class. The second argument is either a
-        yaml node that you've already created or a class (package) name that
-        supports a yaml_dump() function. A yaml_dump() function should take
-        a perl node and return a yaml node. If no second argument is
-        provided, Bless will create a yaml node. This node is not returned,
-        but can be retrieved with the Blessed() function.
-
-        Here's an example of how to use Bless. Say you have a hash
-        containing three keys, but you only want to dump two of them.
-        Furthermore the keys must be dumped in a certain order. Here's how
-        you do that:
-
-            use YAML qw(Dump Bless);
-            $hash = {apple => 'good', banana => 'bad', cauliflower => 'ugly'};
-            print Dump $hash;
-            Bless($hash)->keys(['banana', 'apple']);
-            print Dump $hash;
-
-        produces:
-
-            ---
-            apple: good
-            banana: bad
-            cauliflower: ugly
-            ---
-            banana: bad
-            apple: good
-
-        Bless returns the tied part of a yaml-node, so that you can call the
-        YAML::Node methods. This is the same thing that YAML::Node::ynode()
-        returns. So another way to do the above example is:
-
-            use YAML qw(Dump Bless);
-            use YAML::Node;
-            $hash = {apple => 'good', banana => 'bad', cauliflower => 'ugly'};
-            print Dump $hash;
-            Bless($hash);
-            $ynode = ynode(Blessed($hash));
-            $ynode->keys(['banana', 'apple']);
-            print Dump $hash;
-
-        Note that Blessing a Perl data structure does not change it anyway.
-        The extra information is stored separately and looked up by the
-        Blessed node's memory address.
-
-    Blessed(perl-node)
-        Returns the yaml node that a particular perl node is associated with
-        (see above). Returns undef if the node is not (YAML) Blessed.
-
-GLOBAL OPTIONS
-    YAML options are set using a group of global variables in the YAML
-    namespace. This is similar to how Data::Dumper works.
-
-    For example, to change the indentation width, do something like:
-
-        local $YAML::Indent = 3;
-
-    The current options are:
-
-    DumperClass
-        You can override which module/class YAML uses for Dumping data.
-
-    LoaderClass
-        You can override which module/class YAML uses for Loading data.
-
-    Indent
-        This is the number of space characters to use for each indentation
-        level when doing a Dump(). The default is 2.
-
-        By the way, YAML can use any number of characters for indentation at
-        any level. So if you are editing YAML by hand feel free to do it
-        anyway that looks pleasing to you; just be consistent for a given
-        level.
-
-    SortKeys
-        Default is 1. (true)
-
-        Tells YAML.pm whether or not to sort hash keys when storing a
-        document.
-
-        YAML::Node objects can have their own sort order, which is usually
-        what you want. To override the YAML::Node order and sort the keys
-        anyway, set SortKeys to 2.
-
-    Stringify
-        Default is 0. (false)
-
-        Objects with string overloading should honor the overloading and
-        dump the stringification of themselves, rather than the actual
-        object's guts.
-
-    UseHeader
-        Default is 1. (true)
-
-        This tells YAML.pm whether to use a separator string for a Dump
-        operation. This only applies to the first document in a stream.
-        Subsequent documents must have a YAML header by definition.
-
-    UseVersion
-        Default is 0. (false)
-
-        Tells YAML.pm whether to include the YAML version on the
-        separator/header.
-
-            --- %YAML:1.0
-
-    AnchorPrefix
-        Default is ''.
-
-        Anchor names are normally numeric. YAML.pm simply starts with '1'
-        and increases by one for each new anchor. This option allows you to
-        specify a string to be prepended to each anchor number.
-
-    UseCode
-        Setting the UseCode option is a shortcut to set both the DumpCode
-        and LoadCode options at once. Setting UseCode to '1' tells YAML.pm
-        to dump Perl code references as Perl (using B::Deparse) and to load
-        them back into memory using eval(). The reason this has to be an
-        option is that using eval() to parse untrusted code is, well,
-        untrustworthy.
-
-    DumpCode
-        Determines if and how YAML.pm should serialize Perl code references.
-        By default YAML.pm will dump code references as dummy placeholders
-        (much like Data::Dumper). If DumpCode is set to '1' or 'deparse',
-        code references will be dumped as actual Perl code.
-
-        DumpCode can also be set to a subroutine reference so that you can
-        write your own serializing routine. YAML.pm passes you the code ref.
-        You pass back the serialization (as a string) and a format
-        indicator. The format indicator is a simple string like: 'deparse'
-        or 'bytecode'.
-
-    LoadCode
-        LoadCode is the opposite of DumpCode. It tells YAML if and how to
-        deserialize code references. When set to '1' or 'deparse' it will
-        use "eval()". Since this is potentially risky, only use this option
-        if you know where your YAML has been.
-
-        LoadCode can also be set to a subroutine reference so that you can
-        write your own deserializing routine. YAML.pm passes the
-        serialization (as a string) and a format indicator. You pass back
-        the code reference.
-
-    UseBlock
-        YAML.pm uses heuristics to guess which scalar style is best for a
-        given node. Sometimes you'll want all multiline scalars to use the
-        'block' style. If so, set this option to 1.
-
-        NOTE: YAML's block style is akin to Perl's here-document.
-
-    UseFold
-        If you want to force YAML to use the 'folded' style for all
-        multiline scalars, then set $UseFold to 1.
-
-        NOTE: YAML's folded style is akin to the way HTML folds text, except
-        smarter.
-
-    UseAliases
-        YAML has an alias mechanism such that any given structure in memory
-        gets serialized once. Any other references to that structure are
-        serialized only as alias markers. This is how YAML can serialize
-        duplicate and recursive structures.
-
-        Sometimes, when you KNOW that your data is nonrecursive in nature,
-        you may want to serialize such that every node is expressed in full.
-        (ie as a copy of the original). Setting $YAML::UseAliases to 0 will
-        allow you to do this. This also may result in faster processing
-        because the lookup overhead is by bypassed.
-
-        THIS OPTION CAN BE DANGEROUS. *If* your data is recursive, this
-        option *will* cause Dump() to run in an endless loop, chewing up
-        your computers memory. You have been warned.
-
-    CompressSeries
-        Default is 1.
-
-        Compresses the formatting of arrays of hashes:
-
-            -
-              foo: bar
-            - 
-              bar: foo
-
-        becomes:
-
-            - foo: bar
-            - bar: foo
-
-        Since this output is usually more desirable, this option is turned
-        on by default.
-
-YAML TERMINOLOGY
-    YAML is a full featured data serialization language, and thus has its
-    own terminology.
-
-    It is important to remember that although YAML is heavily influenced by
-    Perl and Python, it is a language in its own right, not merely just a
-    representation of Perl structures.
-
-    YAML has three constructs that are conspicuously similar to Perl's hash,
-    array, and scalar. They are called mapping, sequence, and string
-    respectively. By default, they do what you would expect. But each
-    instance may have an explicit or implicit tag (type) that makes it
-    behave differently. In this manner, YAML can be extended to represent
-    Perl's Glob or Python's tuple, or Ruby's Bigint.
-
-    stream
-        A YAML stream is the full sequence of unicode characters that a YAML
-        parser would read or a YAML emitter would write. A stream may
-        contain one or more YAML documents separated by YAML headers.
-
-            ---
-            a: mapping
-            foo: bar
-            ---
-            - a
-            - sequence
-
-    document
-        A YAML document is an independent data structure representation
-        within a stream. It is a top level node. Each document in a YAML
-        stream must begin with a YAML header line. Actually the header is
-        optional on the first document.
-
-            ---
-            This: top level mapping
-            is:
-                - a
-                - YAML
-                - document
-
-    header
-        A YAML header is a line that begins a YAML document. It consists of
-        three dashes, possibly followed by more info. Another purpose of the
-        header line is that it serves as a place to put top level tag and
-        anchor information.
-
-            --- !recursive-sequence &001
-            - * 001
-            - * 001
-
-    node
-        A YAML node is the representation of a particular data stucture.
-        Nodes may contain other nodes. (In Perl terms, nodes are like
-        scalars. Strings, arrayrefs and hashrefs. But this refers to the
-        serialized format, not the in-memory structure.)
-
-    tag This is similar to a type. It indicates how a particular YAML node
-        serialization should be transferred into or out of memory. For
-        instance a Foo::Bar object would use the tag 'perl/Foo::Bar':
-
-            - !perl/Foo::Bar
-                foo: 42
-                bar: stool
-
-    collection
-        A collection is the generic term for a YAML data grouping. YAML has
-        two types of collections: mappings and sequences. (Similar to hashes
-        and arrays)
-
-    mapping
-        A mapping is a YAML collection defined by unordered key/value pairs
-        with unique keys. By default YAML mappings are loaded into Perl
-        hashes.
-
-            a mapping:
-                foo: bar
-                two: times two is 4
-
-    sequence
-        A sequence is a YAML collection defined by an ordered list of
-        elements. By default YAML sequences are loaded into Perl arrays.
-
-            a sequence:
-                - one bourbon
-                - one scotch
-                - one beer
-
-    scalar
-        A scalar is a YAML node that is a single value. By default YAML
-        scalars are loaded into Perl scalars.
-
-            a scalar key: a scalar value
-
-        YAML has many styles for representing scalars. This is important
-        because varying data will have varying formatting requirements to
-        retain the optimum human readability.
-
-    plain scalar
-        A plain sclar is unquoted. All plain scalars are automatic
-        candidates for "implicit tagging". This means that their tag may be
-        determined automatically by examination. The typical uses for this
-        are plain alpha strings, integers, real numbers, dates, times and
-        currency.
-
-            - a plain string
-            - -42
-            - 3.1415
-            - 12:34
-            - 123 this is an error
-
-    single quoted scalar
-        This is similar to Perl's use of single quotes. It means no escaping
-        except for single quotes which are escaped by using two adjacent
-        single quotes.
-
-            - 'When I say ''\n'' I mean "backslash en"'
-
-    double quoted scalar
-        This is similar to Perl's use of double quotes. Character escaping
-        can be used.
-
-            - "This scalar\nhas two lines, and a bell -->\a"
-
-    folded scalar
-        This is a multiline scalar which begins on the next line. It is
-        indicated by a single right angle bracket. It is unescaped like the
-        single quoted scalar. Line folding is also performed.
-
-            - > 
-             This is a multiline scalar which begins on
-             the next line. It is indicated by a single
-             carat. It is unescaped like the single
-             quoted scalar. Line folding is also
-             performed.
-
-    block scalar
-        This final multiline form is akin to Perl's here-document except
-        that (as in all YAML data) scope is indicated by indentation.
-        Therefore, no ending marker is required. The data is verbatim. No
-        line folding.
-
-            - |
-                QTY  DESC          PRICE  TOTAL
-                ---  ----          -----  -----
-                  1  Foo Fighters  $19.95 $19.95
-                  2  Bar Belles    $29.95 $59.90
-
-    parser
-        A YAML processor has four stages: parse, load, dump, emit.
-
-        A parser parses a YAML stream. YAML.pm's Load() function contains a
-        parser.
-
-    loader
-        The other half of the Load() function is a loader. This takes the
-        information from the parser and loads it into a Perl data structure.
-
-    dumper
-        The Dump() function consists of a dumper and an emitter. The dumper
-        walks through each Perl data structure and gives info to the
-        emitter.
-
-    emitter
-        The emitter takes info from the dumper and turns it into a YAML
-        stream.
-
-        NOTE: In YAML.pm the parser/loader and the dumper/emitter code are
-        currently very closely tied together. In the future they may be
-        broken into separate stages.
-
-    For more information please refer to the immensely helpful YAML
-    specification available at <http://www.yaml.org/spec/>.
-
-ysh - The YAML Shell
-    The YAML distribution ships with a script called 'ysh', the YAML shell.
-    ysh provides a simple, interactive way to play with YAML. If you type in
-    Perl code, it displays the result in YAML. If you type in YAML it turns
-    it into Perl code.
-
-    To run ysh, (assuming you installed it along with YAML.pm) simply type:
-
-        ysh [options]
-
-    Please read the "ysh" documentation for the full details. There are lots
-    of options.
-
-BUGS & DEFICIENCIES
-    If you find a bug in YAML, please try to recreate it in the YAML Shell
-    with logging turned on ('ysh -L'). When you have successfully reproduced
-    the bug, please mail the LOG file to the author (ingy@cpan.org).
-
-    WARNING: This is still *ALPHA* code. Well, most of this code has been
-    around for years...
-
-    BIGGER WARNING: YAML.pm has been slow in the making, but I am committed
-    to having top notch YAML tools in the Perl world. The YAML team is close
-    to finalizing the YAML 1.1 spec. This version of YAML.pm is based off of
-    a very old pre 1.0 spec. In actuality there isn't a ton of difference,
-    and this YAML.pm is still fairly useful. Things will get much better in
-    the future.
-
-RESOURCES
-    <http://lists.sourceforge.net/lists/listinfo/yaml-core> is the mailing
-    list. This is where the language is discussed and designed.
-
-    <http://www.yaml.org> is the official YAML website.
-
-    <http://www.yaml.org/spec/> is the YAML 1.0 specification.
-
-    <http://yaml.kwiki.org> is the official YAML wiki.
-
-SEE ALSO
-    See YAML::Syck. Fast!
-
-AUTHOR
-    Ingy döt Net <ingy@cpan.org>
-
-    is resonsible for YAML.pm.
-
-    The YAML serialization language is the result of years of collaboration
-    between Oren Ben-Kiki, Clark Evans and Ingy döt Net. Several others
-    have added help along the way.
-
-COPYRIGHT
-    Copyright (c) 2005, 2006. Ingy döt Net. All rights reserved. Copyright
-    (c) 2001, 2002, 2005. Brian Ingerson. All rights reserved.
-
-    This program is free software; you can redistribute it and/or modify it
-    under the same terms as Perl itself.
-
-    See <http://www.perl.com/perl/misc/Artistic.html>
-
diff --git a/modules/fallback/DateTime/Event/Cron.pm b/modules/fallback/DateTime/Event/Cron.pm
deleted file mode 100644 (file)
index a835aa7..0000000
+++ /dev/null
@@ -1,885 +0,0 @@
-package DateTime::Event::Cron;
-
-use 5.006;
-use strict;
-use warnings;
-use Carp;
-
-use vars qw($VERSION);
-
-$VERSION = '0.08';
-
-use constant DEBUG => 0;
-
-use DateTime;
-use DateTime::Set;
-use Set::Crontab;
-
-my %Object_Attributes;
-
-###
-
-sub from_cron {
-  # Return cron as DateTime::Set
-  my $class = shift;
-  my %sparms = @_ == 1 ? (cron => shift) : @_;
-  my %parms;
-  $parms{cron}      = delete $sparms{cron};
-  $parms{user_mode} = delete $sparms{user_mode};
-  $parms{cron} or croak "Cron string parameter required.\n";
-  my $dtc = $class->new(%parms);
-  $dtc->as_set(%sparms);
-}
-
-sub from_crontab {
-  # Return list of DateTime::Sets based on entries from
-  # a crontab file.
-  my $class = shift;
-  my %sparms = @_ == 1 ? (file => shift) : @_;
-  my $file = delete $sparms{file};
-  delete $sparms{cron};
-  my $fh = $class->_prepare_fh($file);
-  my @cronsets;
-  while (<$fh>) {
-    chomp;
-    my $set;
-    eval { $set = $class->from_cron(%sparms, cron => $_) };
-    push(@cronsets, $set) if ref $set && !$@;
-  }
-  @cronsets;
-}
-
-sub as_set {
-  # Return self as DateTime::Set
-  my $self = shift;
-  my %sparms = @_;
-  Carp::cluck "Recurrence callbacks overriden by ". ref $self . "\n"
-    if $sparms{next} || $sparms{recurrence} || $sparms{previous};
-  delete $sparms{next};
-  delete $sparms{previous};
-  delete $sparms{recurrence};
-  $sparms{next}     = sub { $self->next(@_) };
-  $sparms{previous} = sub { $self->previous(@_) };
-  DateTime::Set->from_recurrence(%sparms);
-}
-
-###
-
-sub new {
-  my $class = shift;
-  my $self = {};
-  bless $self, $class;
-  my %parms = @_ == 1 ? (cron => shift) : @_;
-  my $crontab = $self->_make_cronset(%parms);
-  $self->_cronset($crontab);
-  $self;
-}
-
-sub new_from_cron { new(@_) }
-
-sub new_from_crontab {
-  my $class = shift;
-  my %parms = @_ == 1 ? (file => shift()) : @_;
-  my $fh = $class->_prepare_fh($parms{file});
-  delete $parms{file};
-  my @dtcrons;
-  while (<$fh>) {
-    my $dtc;
-    eval { $dtc = $class->new(%parms, cron => $_) };
-    if (ref $dtc && !$@) {
-      push(@dtcrons, $dtc);
-      $parms{user_mode} = 1 if defined $dtc->user;
-    }
-  }
-  @dtcrons;
-}
-
-###
-
-sub _prepare_fh {
-  my $class = shift;
-  my $fh = shift;
-  if (! ref $fh) {
-    my $file = $fh;
-    local(*FH);
-    $fh = do { local *FH; *FH }; # doubled *FH avoids warning
-    open($fh, "<$file")
-      or croak "Error opening $file for reading\n";
-  }
-  $fh;
-}
-
-###
-
-sub valid {
-  # Is the given date valid according the current cron settings?
-  my($self, $date) = @_;
-  return if !$date || $date->second;
-  $self->minute->contains($date->minute)      &&
-  $self->hour->contains($date->hour)          &&
-  $self->days_contain($date->day, $date->dow) &&
-  $self->month->contains($date->month);
-}
-
-sub match {
-  # Does the given date match the cron spec?
-  my($self, $date) = @_;
-  $date = DateTime->now unless $date;
-  $self->minute->contains($date->minute)      &&
-  $self->hour->contains($date->hour)          &&
-  $self->days_contain($date->day, $date->dow) &&
-  $self->month->contains($date->month);
-}
-
-### Return adjacent dates without altering original date
-
-sub next {
-  my($self, $date) = @_;
-  $date = DateTime->now unless $date;
-  $self->increment($date->clone);
-}
-
-sub previous {
-  my($self, $date) = @_;
-  $date = DateTime->now unless $date;
-  $self->decrement($date->clone);
-}
-
-### Change given date to adjacent dates
-
-sub increment {
-  my($self, $date) = @_;
-  $date = DateTime->now unless $date;
-  return $date if $date->is_infinite;
-  do {
-    $self->_attempt_increment($date);
-  } until $self->valid($date);
-  $date;
-}
-
-sub decrement {
-  my($self, $date) = @_;
-  $date = DateTime->now unless $date;
-  return $date if $date->is_infinite;
-  do {
-    $self->_attempt_decrement($date);
-  } until $self->valid($date);
-  $date;
-}
-
-###
-
-sub _attempt_increment {
-  my($self, $date) = @_;
-  ref $date or croak "Reference to datetime object reqired\n";
-  $self->valid($date) ?
-    $self->_valid_incr($date) :
-    $self->_invalid_incr($date);
-}
-
-sub _attempt_decrement {
-  my($self, $date) = @_;
-  ref $date or croak "Reference to datetime object reqired\n";
-  $self->valid($date) ?
-    $self->_valid_decr($date) :
-    $self->_invalid_decr($date);
-}
-
-sub _valid_incr { shift->_minute_incr(@_) }
-
-sub _valid_decr { shift->_minute_decr(@_) }
-
-sub _invalid_incr {
-  # If provided date is valid, return it. Otherwise return
-  # nearest valid date after provided date.
-  my($self, $date) = @_;
-  ref $date or croak "Reference to datetime object reqired\n";
-
-  print STDERR "\nI GOT: ", $date->datetime, "\n" if DEBUG;
-
-  $date->truncate(to => 'minute')->add(minutes => 1)
-    if $date->second;
-
-  print STDERR "RND: ", $date->datetime, "\n" if DEBUG;
-
-  # Find our greatest invalid unit and clip
-  if (!$self->month->contains($date->month)) {
-    $date->truncate(to => 'month');
-  }
-  elsif (!$self->days_contain($date->day, $date->dow)) {
-    $date->truncate(to => 'day');
-  }
-  elsif (!$self->hour->contains($date->hour)) {
-    $date->truncate(to => 'hour');
-  }
-  else {
-    $date->truncate(to => 'minute');
-  }
-
-  print STDERR "BBT: ", $date->datetime, "\n" if DEBUG;
-
-  return $date if $self->valid($date);
-
-  print STDERR "ZZT: ", $date->datetime, "\n" if DEBUG;
-
-  # Extraneous durations clipped. Start searching.
-  while (!$self->valid($date)) {
-    $date->add(months => 1) until $self->month->contains($date->month);
-    print STDERR "MON: ", $date->datetime, "\n" if DEBUG;
-
-    my $day_orig = $date->day;
-    $date->add(days => 1) until $self->days_contain($date->day, $date->dow);
-    $date->truncate(to => 'month') && next if $date->day < $day_orig;
-    print STDERR "DAY: ", $date->datetime, "\n" if DEBUG;
-
-    my $hour_orig = $date->hour;
-    $date->add(hours => 1) until $self->hour->contains($date->hour);
-    $date->truncate(to => 'day') && next if $date->hour < $hour_orig;
-    print STDERR "HOR: ", $date->datetime, "\n" if DEBUG;
-
-    my $min_orig = $date->minute;
-    $date->add(minutes => 1) until $self->minute->contains($date->minute);
-    $date->truncate(to => 'hour') && next if $date->minute < $min_orig;
-    print STDERR "MIN: ", $date->datetime, "\n" if DEBUG;
-  }
-  print STDERR "SET: ", $date->datetime, "\n" if DEBUG;
-  $date;
-}
-
-sub _invalid_decr {
-  # If provided date is valid, return it. Otherwise
-  # return the nearest previous valid date.
-  my($self, $date) = @_;
-  ref $date or croak "Reference to datetime object reqired\n";
-
-  print STDERR "\nD GOT: ", $date->datetime, "\n" if DEBUG;
-
-  if (!$self->month->contains($date->month)) {
-    $date->truncate(to => 'month');
-  }
-  elsif (!$self->days_contain($date->day, $date->dow)) {
-    $date->truncate(to => 'day');
-  }
-  elsif (!$self->hour->contains($date->hour)) {
-    $date->truncate(to => 'hour');
-  }
-  else {
-    $date->truncate(to => 'minute');
-  }
-
-  print STDERR "BBT: ", $date->datetime, "\n" if DEBUG;
-
-  return $date if $self->valid($date);
-
-  print STDERR "ZZT: ", $date->datetime, "\n" if DEBUG;
-
-  # Extraneous durations clipped. Start searching.
-  while (!$self->valid($date)) {
-    if (!$self->month->contains($date->month)) {
-      $date->subtract(months => 1) until $self->month->contains($date->month);
-      $self->_unit_peak($date, 'month');
-      print STDERR "MON: ", $date->datetime, "\n" if DEBUG;
-    }
-    if (!$self->days_contain($date->day, $date->dow)) {
-      my $day_orig = $date->day;
-      $date->subtract(days => 1)
-        until $self->days_contain($date->day, $date->dow);
-      $self->_unit_peak($date, 'month') && next if ($date->day > $day_orig);
-      $self->_unit_peak($date, 'day');
-      print STDERR "DAY: ", $date->datetime, "\n" if DEBUG;
-    }
-    if (!$self->hour->contains($date->hour)) {
-      my $hour_orig = $date->hour;
-      $date->subtract(hours => 1) until $self->hour->contains($date->hour);
-      $self->_unit_peak($date, 'day') && next if ($date->hour > $hour_orig);
-      $self->_unit_peak($date, 'hour');
-      print STDERR "HOR: ", $date->datetime, "\n" if DEBUG;
-    }
-    if (!$self->minute->contains($date->minute)) {
-      my $min_orig = $date->minute;
-      $date->subtract(minutes => 1)
-        until $self->minute->contains($date->minute);
-      $self->_unit_peak($date, 'hour') && next if ($date->minute > $min_orig);
-      print STDERR "MIN: ", $date->datetime, "\n" if DEBUG;
-    }
-  }
-  print STDERR "SET: ", $date->datetime, "\n" if DEBUG;
-  $date;
-}
-
-###
-
-sub _unit_peak {
-  my($self, $date, $unit) = @_;
-  $date && $unit or croak "DateTime ref and unit required.\n";
-  $date->truncate(to => $unit)
-       ->add($unit . 's' => 1)
-       ->subtract(minutes => 1);
-}
-
-### Unit cascades
-
-sub _minute_incr {
-  my($self, $date) = @_;
-  croak "datetime object required\n" unless $date;
-  my $cur = $date->minute;
-  my $next = $self->minute->next($cur);
-  $date->set(minute => $next);
-  $next <= $cur ? $self->_hour_incr($date) : $date;
-}
-
-sub _hour_incr {
-  my($self, $date) = @_;
-  croak "datetime object required\n" unless $date;
-  my $cur = $date->hour;
-  my $next = $self->hour->next($cur);
-  $date->set(hour => $next);
-  $next <= $cur ? $self->_day_incr($date) : $date;
-}
-
-sub _day_incr {
-  my($self, $date) = @_;
-  croak "datetime object required\n" unless $date;
-  $date->add(days => 1);
-  $self->_invalid_incr($date);
-}
-
-sub _minute_decr {
-  my($self, $date) = @_;
-  croak "datetime object required\n" unless $date;
-  my $cur = $date->minute;
-  my $next = $self->minute->previous($cur);
-  $date->set(minute => $next);
-  $next >= $cur ? $self->_hour_decr($date) : $date;
-}
-
-sub _hour_decr {
-  my($self, $date) = @_;
-  croak "datetime object required\n" unless $date;
-  my $cur = $date->hour;
-  my $next = $self->hour->previous($cur);
-  $date->set(hour => $next);
-  $next >= $cur ? $self->_day_decr($date) : $date;
-}
-
-sub _day_decr {
-  my($self, $date) = @_;
-  croak "datetime object required\n" unless $date;
-  $date->subtract(days => 1);
-  $self->_invalid_decr($date);
-}
-
-### Factories
-
-sub _make_cronset { shift; DateTime::Event::Cron::IntegratedSet->new(@_) }
-
-### Shortcuts
-
-sub days_contain { shift->_cronset->days_contain(@_) }
-
-sub minute   { shift->_cronset->minute  }
-sub hour     { shift->_cronset->hour    }
-sub day      { shift->_cronset->day     }
-sub month    { shift->_cronset->month   }
-sub dow      { shift->_cronset->dow     }
-sub user     { shift->_cronset->user    }
-sub command  { shift->_cronset->command }
-sub original { shift->_cronset->original }
-
-### Static acessors/mutators
-
-sub _cronset { shift->_attr('cronset', @_) }
-
-sub _attr {
-  my $self = shift;
-  my $name = shift;
-  if (@_) {
-    $Object_Attributes{$self}{$name} = shift;
-  }
-  $Object_Attributes{$self}{$name};
-}
-
-### debugging
-
-sub _dump_sets {
-  my($self, $date) = @_;
-  foreach (qw(minute hour day month dow)) {
-    print STDERR "$_: ", join(',',$self->$_->list), "\n";
-  }
-  if (ref $date) {
-    $date = $date->clone;
-    my @mod;
-    my $mon = $date->month;
-    $date->truncate(to => 'month');
-    while ($date->month == $mon) {
-      push(@mod, $date->day) if $self->days_contain($date->day, $date->dow);
-      $date->add(days => 1);
-    }
-    print STDERR "mod for month($mon): ", join(',', @mod), "\n";
-  }
-  print STDERR "day_squelch: ", $self->_cronset->day_squelch, " ",
-               "dow_squelch: ", $self->_cronset->dow_squelch, "\n";
-  $self;
-}
-
-###
-
-sub DESTROY { delete $Object_Attributes{shift()} }
-
-##########
-
-{
-
-package DateTime::Event::Cron::IntegratedSet;
-
-# IntegratedSet manages the collection of field sets for
-# each cron entry, including sanity checks. Individual
-# field sets are accessed through their respective names,
-# i.e., minute hour day month dow.
-#
-# Also implements some merged field logic for day/dow
-# interactions.
-
-use strict;
-use Carp;
-
-my %Range = (
-  minute => [0..59],
-  hour   => [0..23],
-  day    => [1..31],
-  month  => [1..12],
-  dow    => [1..7],
-);
-
-my @Month_Max = qw( 31 29 31 30 31 30 31 31 30 31 30 31 );
-
-my %Object_Attributes;
-
-sub new {
-  my $self = [];
-  bless $self, shift;
-  $self->_range(\%Range);
-  $self->set_cron(@_);
-  $self;
-}
-
-sub set_cron {
-  # Initialize
-  my $self = shift;
-  my %parms = @_;
-  my $cron = $parms{cron};
-  my $user_mode = $parms{user_mode};
-  defined $cron or croak "Cron entry fields required\n";
-  $self->_attr('original', $cron);
-  my @line;
-  if (ref $cron) {
-    @line = grep(!/^\s*$/, @$cron);
-  }
-  else {
-    $cron =~ s/^\s+//;
-    $cron =~ s/\s+$//;
-    @line = split(/\s+/, $cron);
-  }
-  @line >= 5 or croak "At least five cron entry fields required.\n";
-  my @entry = splice(@line, 0, 5);
-  my($user, $command);
-  unless (defined $user_mode) {
-    # auto-detect
-    if (@line > 1 && $line[0] =~ /^\w+$/) {
-      $user_mode = 1;
-    }
-  }
-  $user = shift @line if $user_mode;
-  $command = join(' ', @line);
-  $self->_attr('command', $command);
-  $self->_attr('user', $user);
-  my $i = 0;
-  foreach my $name (qw( minute hour day month dow )) {
-    $self->_attr($name, $self->make_valid_set($name, $entry[$i]));
-    ++$i;
-  }
-  my @day_list  = $self->day->list;
-  my @dow_list  = $self->dow->list;
-  my $day_range = $self->range('day');
-  my $dow_range = $self->range('dow');
-  $self->day_squelch(scalar @day_list == scalar @$day_range &&
-                     scalar @dow_list != scalar @$dow_range ? 1 : 0);
-  $self->dow_squelch(scalar @dow_list == scalar @$dow_range &&
-                     scalar @day_list != scalar @$day_range ? 1 : 0);
-  unless ($self->day_squelch) {
-    my @days = $self->day->list;
-    my $pass = 0;
-    MONTH: foreach my $month ($self->month->list) {
-      foreach (@days) {
-        ++$pass && last MONTH if $_ <= $Month_Max[$month - 1];
-      }
-    }
-    croak "Impossible last day for provided months.\n" unless $pass;
-  }
-  $self;
-}
-
-# Field range queries
-sub range {
-  my($self, $name) = @_;
-  my $val = $self->_range->{$name} or croak "Unknown field '$name'\n";
-  $val;
-}
-
-# Perform sanity checks when setting up each field set.
-sub make_valid_set {
-  my($self, $name, $str) = @_;
-  my $range = $self->range($name);
-  my $set = $self->make_set($str, $range);
-  my @list = $set->list;
-  croak "Malformed cron field '$str'\n" unless @list;
-  croak "Field value ($list[-1]) out of range ($range->[0]-$range->[-1])\n"
-    if $list[-1] > $range->[-1];
-  if ($name eq 'dow' && $set->contains(0)) {
-    shift(@list);
-    push(@list, 7) unless $set->contains(7);
-    $set = $self->make_set(join(',',@list), $range);
-  }
-  croak "Field value ($list[0]) out of range ($range->[0]-$range->[-1])\n"
-    if $list[0] < $range->[0];
-  $set;
-}
-
-# No sanity checks
-sub make_set { shift; DateTime::Event::Cron::OrderedSet->new(@_) }
-
-# Flags for when day/dow are applied.
-sub day_squelch { shift->_attr('day_squelch', @_ ) }
-sub dow_squelch { shift->_attr('dow_squelch', @_ ) }
-
-# Merged logic for day/dow
-sub days_contain {
-  my($self, $day, $dow) = @_;
-  defined $day && defined $dow
-    or croak "Day of month and day of week required.\n";
-  my $day_c = $self->day->contains($day);
-  my $dow_c = $self->dow->contains($dow);
-  return $dow_c if $self->day_squelch;
-  return $day_c if $self->dow_squelch;
-  $day_c || $dow_c;
-}
-
-# Set Accessors
-sub minute   { shift->_attr('minute' ) }
-sub hour     { shift->_attr('hour'   ) }
-sub day      { shift->_attr('day'    ) }
-sub month    { shift->_attr('month'  ) }
-sub dow      { shift->_attr('dow'    ) }
-sub user     { shift->_attr('user'   ) }
-sub command  { shift->_attr('command') }
-sub original { shift->_attr('original') }
-
-# Accessors/mutators
-sub _range       { shift->_attr('range', @_) }
-
-sub _attr {
-  my $self = shift;
-  my $name = shift;
-  if (@_) {
-    $Object_Attributes{$self}{$name} = shift;
-  }
-  $Object_Attributes{$self}{$name};
-}
-
-sub DESTROY { delete $Object_Attributes{shift()} }
-
-}
-
-##########
-
-{
-
-package DateTime::Event::Cron::OrderedSet;
-
-# Extends Set::Crontab with some progression logic (next/prev)
-
-use strict;
-use Carp;
-use base 'Set::Crontab';
-
-my %Object_Attributes;
-
-sub new {
-  my $class = shift;
-  my($string, $range) = @_;
-  defined $string && ref $range
-    or croak "Cron field and range ref required.\n";
-  my $self = Set::Crontab->new($string, $range);
-  bless $self, $class;
-  my @list = $self->list;
-  my(%next, %prev);
-  foreach (0 .. $#list) {
-    $next{$list[$_]} = $list[($_+1)%@list];
-    $prev{$list[$_]} = $list[($_-1)%@list];
-  }
-  $self->_attr('next', \%next);
-  $self->_attr('previous', \%prev);
-  $self;
-}
-
-sub next {
-  my($self, $entry) = @_;
-  my $hash = $self->_attr('next');
-  croak "Missing entry($entry) in set\n" unless exists $hash->{$entry};
-  my $next = $hash->{$entry};
-  wantarray ? ($next, $next <= $entry) : $next;
-}
-
-sub previous {
-  my($self, $entry) = @_;
-  my $hash = $self->_attr('previous');
-  croak "Missing entry($entry) in set\n" unless exists $hash->{$entry};
-  my $prev = $hash->{$entry};
-  wantarray ? ($prev, $prev >= $entry) : $prev;
-}
-
-sub _attr {
-  my $self = shift;
-  my $name = shift;
-  if (@_) {
-    $Object_Attributes{$self}{$name} = shift;
-  }
-  $Object_Attributes{$self}{$name};
-}
-
-sub DESTROY { delete $Object_Attributes{shift()} }
-
-}
-
-###
-
-1;
-
-__END__
-
-=head1 NAME
-
-DateTime::Event::Cron - DateTime extension for generating recurrence
-sets from crontab lines and files.
-
-=head1 SYNOPSIS
-
-  use DateTime::Event::Cron;
-
-  # check if a date matches (defaults to current time)
-  my $c = DateTime::Event::Cron->new('* 2 * * *');
-  if ($c->match) {
-    # do stuff
-  }
-  if ($c->match($date)) {
-    # do something else for datetime $date
-  }
-
-  # DateTime::Set construction from crontab line
-  $crontab = '*/3 15 1-10 3,4,5 */2';
-  $set = DateTime::Event::Cron->from_cron($crontab);
-  $iter = $set->iterator(after => DateTime->now);
-  while (1) {
-    my $next = $iter->next;
-    my $now  = DateTime->now;
-    sleep(($next->subtract_datetime_absolute($now))->seconds);
-    # do stuff...
-  }
-
-  # List of DateTime::Set objects from crontab file
-  @sets = DateTime::Event::Cron->from_crontab(file => '/etc/crontab');
-  $now = DateTime->now;
-  print "Now: ", $now->datetime, "\n";
-  foreach (@sets) {
-    my $next = $_->next($now);
-    print $next->datetime, "\n";
-  }
-
-  # DateTime::Set parameters
-  $crontab = '* * * * *';
-
-  $now = DateTime->now;
-  %set_parms = ( after => $now );
-  $set = DateTime::Event::Cron->from_cron(cron => $crontab, %set_parms);
-  $dt = $set->next;
-  print "Now: ", $now->datetime, " and next: ", $dt->datetime, "\n";
-
-  # Spans for DateTime::Set
-  $crontab = '* * * * *';
-  $now = DateTime->now;
-  $now2 = $now->clone;
-  $span = DateTime::Span->from_datetimes(
-            start => $now->add(minutes => 1),
-           end   => $now2->add(hours => 1),
-         );
-  %parms = (cron => $crontab, span => $span);
-  $set = DateTime::Event::Cron->from_cron(%parms);
-  # ...do things with the DateTime::Set
-
-  # Every RTFCT relative to 12am Jan 1st this year
-  $crontab = '7-10 6,12-15 10-28/2 */3 3,4,5';
-  $date = DateTime->now->truncate(to => 'year');
-  $set = DateTime::Event::Cron->from_cron(cron => $crontab, after => $date);
-
-  # Rather than generating DateTime::Set objects, next/prev
-  # calculations can be made directly:
-
-  # Every day at 10am, 2pm, and 6pm. Reference date
-  # defaults to DateTime->now.
-  $crontab = '10,14,18 * * * *';
-  $dtc = DateTime::Event::Cron->new_from_cron(cron => $crontab);
-  $next_datetime = $dtc->next;
-  $last_datetime = $dtc->previous;
-  ...
-
-  # List of DateTime::Event::Cron objects from
-  # crontab file
-  @dtc = DateTime::Event::Cron->new_from_crontab(file => '/etc/crontab');
-
-  # Full cron lines with user, such as from /etc/crontab
-  # or files in /etc/cron.d, are supported and auto-detected:
-  $crontab = '* * * * * gump /bin/date';
-  $dtc = DateTime::Event::Cron->new(cron => $crontab);
-
-  # Auto-detection of users is disabled if you explicitly
-  # enable/disable via the user_mode parameter:
-  $dtc = DateTime::Event::Cron->new(cron => $crontab, user_mode => 1);
-  my $user = $dtc->user;
-  my $command = $dtc->command;
-
-  # Unparsed original cron entry
-  my $original = $dtc->original;
-
-=head1 DESCRIPTION
-
-DateTime::Event::Cron generated DateTime events or DateTime::Set objects
-based on crontab-style entries.
-
-=head1 METHODS
-
-The cron fields are typical crontab-style entries. For more information,
-see L<crontab(5)> and extensions described in L<Set::Crontab>. The
-fields can be passed as a single string or as a reference to an array
-containing each field. Only the first five fields are retained.
-
-=head2 DateTime::Set Factories
-
-See L<DateTime::Set> for methods provided by Set objects, such as
-C<next()> and C<previous()>.
-
-=over 4
-
-=item from_cron($cronline)
-
-=item from_cron(cron => $cronline, %parms, %set_parms)
-
-Generates a DateTime::Set recurrence for the cron line provided. See
-new() for details on %parms. Optionally takes parameters for
-DateTime::Set.
-
-=item from_crontab(file => $crontab_fh, %parms, %set_parms)
-
-Returns a list of DateTime::Set recurrences based on lines from a
-crontab file. C<$crontab_fh> can be either a filename or filehandle
-reference. See new() for details on %parm. Optionally takes parameters
-for DateTime::Set which will be passed along to each set for each line.
-
-=item as_set(%set_parms)
-
-Generates a DateTime::Set recurrence from an existing
-DateTime::Event::Cron object.
-
-=back
-
-=head2 Constructors
-
-=over 4
-
-=item new_from_cron(cron => $cronstring, %parms)
-
-Returns a DateTime::Event::Cron object based on the cron specification.
-Optional parameters include the boolean 'user_mode' which indicates that
-the crontab entry includes a username column before the command.
-
-=item new_from_crontab(file => $fh, %parms)
-
-Returns a list of DateTime::Event::Cron objects based on the lines of a
-crontab file. C<$fh> can be either a filename or a filehandle reference.
-Optional parameters include the boolean 'user_mode' as mentioned above.
-
-=back
-
-=head2 Other methods
-
-=over 4
-
-=item next()
-
-=item next($date)
-
-Returns the next valid datetime according to the cron specification.
-C<$date> defaults to DateTime->now unless provided.
-
-=item previous()
-
-=item previous($date)
-
-Returns the previous valid datetime according to the cron specification.
-C<$date> defaults to DateTime->now unless provided.
-
-=item increment($date)
-
-=item decrement($date)
-
-Same as C<next()> and C<previous()> except that the provided datetime is
-modified to the new datetime.
-
-=item match($date)
-
-Returns whether or not the given datetime (defaults to current time)
-matches the current cron specification. Dates are truncated to minute
-resolution.
-
-=item valid($date)
-
-A more strict version of match(). Returns whether the given datetime is
-valid under the current cron specification. Cron dates are only accurate
-to the minute -- datetimes with seconds greater than 0 are invalid by
-default. (note: never fear, all methods accepting dates will accept
-invalid dates -- they will simply be rounded to the next nearest valid
-date in all cases except this particular method)
-
-=item command()
-
-Returns the command string, if any, from the original crontab entry.
-Currently no expansion is performed such as resolving environment
-variables, etc.
-
-=item user()
-
-Returns the username under which this cron command was to be executed,
-assuming such a field was present in the original cron entry.
-
-=item original()
-
-Returns the original, unparsed cron string including any user or
-command fields.
-
-=back
-
-=head1 AUTHOR
-
-Matthew P. Sisk E<lt>sisk@mojotoad.comE<gt>
-
-=head1 COPYRIGHT
-
-Copyright (c) 2003 Matthew P. Sisk. All rights reserved. All wrongs
-revenged. This program is free software; you can distribute it and/or
-modify it under the same terms as Perl itself.
-
-=head1 SEE ALSO
-
-DateTime(3), DateTime::Set(3), DateTime::Event::Recurrence(3),
-DateTime::Event::ICal(3), DateTime::Span(3), Set::Crontab(3), crontab(5)
-
-=cut
diff --git a/modules/fallback/Exception/Lite.pm b/modules/fallback/Exception/Lite.pm
deleted file mode 100644 (file)
index 5f467e6..0000000
+++ /dev/null
@@ -1,527 +0,0 @@
-# Copyright (c) 2010 Elizabeth Grace Frank-Backman.
-# All rights reserved.
-# Liscenced under the "Artistic Liscence"
-# (see http://dev.perl.org/licenses/artistic.html)
-
-use 5.8.8;
-use strict;
-use warnings;
-use overload;
-
-package Exception::Lite;
-our @ISA = qw(Exporter);
-our @EXPORT_OK=qw(declareExceptionClass isException isChainable
-                  onDie onWarn);
-our %EXPORT_TAGS
-  =( common => [qw(declareExceptionClass isException isChainable)]
-     , all => [@EXPORT_OK]
-   );
-my $CLASS='Exception::Lite';
-
-#------------------------------------------------------------------
-
-our $STRINGIFY=3;
-our $FILTER=1;
-our $UNDEF='<undef>';
-our $TAB=3;
-our $LINE_LENGTH=120;
-
-# provide command line control over amount and layout of debugging
-# information, e.g. perl -mException::Lite=STRINGIFY=4
-
-sub import {
-  Exception::Lite->export_to_level(1, grep {
-    if (/^(\w+)=(.*)$/) {
-      my $k = $1;
-      my $v = $2;
-      if ($k eq 'STRINGIFY')        { $STRINGIFY=$v;
-      } elsif ($k eq 'FILTER')      { $FILTER=$v;
-      } elsif ($k eq 'LINE_LENGTH') { $LINE_LENGTH=$v;
-      } elsif ($k eq 'TAB')         { $TAB=$v;
-      }
-      0;
-    } else {
-      1;
-    }
-  } @_);
-}
-
-#------------------------------------------------------------------
-# Note to source code divers: DO NOT USE THIS. This is intended for
-# internal use but must be declared with "our" because we need to
-# localize it.  This is an implementation detail and cannot be relied
-# on for future releases.
-
-our $STACK_OFFSET=0;
-
-#------------------------------------------------------------------
-
-use Scalar::Util ();
-use constant EVAL => '(eval)';
-
-#==================================================================
-# EXPORTABLE FUNCTIONS
-#==================================================================
-
-sub declareExceptionClass {
-  my ($sClass, $sSuperClass, $xFormatRule, $bCustomizeSubclass) = @_;
-  my $sPath = $sClass; $sPath =~ s/::/\//g; $sPath .= '.pm';
-  if ($INC{$sPath}) {
-    # we want to start with the caller's frame, not ours
-    local $STACK_OFFSET = $STACK_OFFSET + 1;
-    die 'Exception::Lite::Any'->new("declareExceptionClass failed: "
-                                    . "$sClass is already defined!");
-    return undef;
-  }
-
-  my $sRef=ref($sSuperClass);
-  if ($sRef) {
-    $bCustomizeSubclass = $xFormatRule;
-    $xFormatRule = $sSuperClass;
-    $sSuperClass=undef;
-  } else {
-    $sRef = ref($xFormatRule);
-    if (!$sRef && defined($xFormatRule)) {
-      $bCustomizeSubclass = $xFormatRule;
-      $xFormatRule = undef;
-    }
-  }
-
-  # set up things dependent on whether or not the class has a
-  # format string or expects a message for each instance
-
-  my ($sLeadingParams, $sAddOrOmit, $sRethrowMsg, $sMakeMsg);
-  my $sReplaceMsg='';
-
-  if ($sRef) {
-    $sLeadingParams='my $e; $e=shift if ref($_[0]);';
-    $sAddOrOmit='added an unnecessary message or format';
-    $sRethrowMsg='';
-
-    #generate format rule
-    $xFormatRule=$xFormatRule->($sClass) if ($sRef eq 'CODE');
-
-    my $sFormat= 'q{' . $xFormatRule->[0] . '}';
-    if (scalar($xFormatRule) == 1) {
-      $sMakeMsg='my $msg='.$sFormat;
-    } else {
-      my $sSprintf = 'Exception::Lite::_sprintf(' . $sFormat
-        . ', map {defined($_)?$_:\''. $UNDEF .'\'} @$h{qw('
-        . join(' ', @$xFormatRule[1..$#$xFormatRule]) . ')});';
-      $sMakeMsg='my $msg='.$sSprintf;
-      $sReplaceMsg='$_[0]->[0]='.$sSprintf;
-    }
-
-  } else {
-    $sLeadingParams = 'my $e=shift; my $msg;'.
-      'if(ref($e)) { $msg=shift; $msg=$e->[0] if !defined($msg);}'.
-      'else { $msg=$e;$e=undef; }';
-    $sAddOrOmit='omitted a required message';
-    $sRethrowMsg='my $msg=shift; $_[0]->[0]=$msg if defined($msg);';
-    $sMakeMsg='';
-  }
-
-  # put this in an eval so that it doesn't cause parse errors at
-  # compile time in no-threads versions of Perl
-
-  my $sTid = eval q{defined(&threads::tid)?'threads->tid':'undef'};
-
-  my $sDeclare = "package $sClass;".
-    'sub new { my $cl=shift;'.  $sLeadingParams .
-      'my $st=Exception::Lite::_cacheStackTrace($e);'.
-      'my $h= Exception::Lite::_shiftProperties($cl' .
-         ',$st,"'.$sAddOrOmit.'",@_);' . $sMakeMsg .
-      'my $self=bless([$msg,$h,$st,$$,'.$sTid.',$e,[]],$cl);';
-
-  # the remainder depends on the type of subclassing
-
-  if ($bCustomizeSubclass) {
-    $sDeclare .= '$self->[7]={}; $self->_new(); return $self; }'
-      . 'sub _p_getSubclassData { $_[0]->[7]; }';
-  } else {
-    $sDeclare .= 'return $self;}'.
-    'sub replaceProperties {'.
-       'my $h={%{$_[0]->[1]},%{$_[1]}}; $_[0]->[1]=$h;'.$sReplaceMsg.
-    '}'.
-    'sub rethrow {' .
-      'my $self=shift;' . $sRethrowMsg .
-      'Exception::Lite::_rethrow($self,"'.$sAddOrOmit.'",@_)' .
-    '}';
-
-    unless (isExceptionClass($sSuperClass)) {
-      $sDeclare .=
-        'sub _getInterface { \'Exception::Lite\' }' .
-        'sub getMessage { $_[0]->[0] };' .
-        'sub getProperty { $_[0]->[1]->{$_[1]} }' .
-        'sub isProperty { exists($_[0]->[1]->{$_[1]})?1:0 }' .
-        'sub getStackTrace { $_[0]->[2] }' .
-        'sub getFrameCount { scalar(@{$_[0]->[2]}); }' .
-        'sub getFile { $_[0]->[2]->[ $_[1]?$_[1]:0 ]->[0] };' .
-        'sub getLine { $_[0]->[2]->[ $_[1]?$_[1]:0 ]->[1] };' .
-        'sub getSubroutine { $_[0]->[2]->[ $_[1]?$_[1]:0 ]->[2] };' .
-        'sub getArgs { $_[0]->[2]->[ $_[1]?$_[1]:0 ]->[3] };' .
-        'sub getPackage {$_[0]->[2]->[-1]->[2] =~ /(\w+)>$/;$1}'.
-        'sub getPid { $_[0]->[3] }' .
-        'sub getTid { $_[0]->[4] }' .
-        'sub getChained { $_[0]->[5] }' .
-        'sub getPropagation { $_[0]->[6]; }' .
-        'use overload '.
-           'q{""} => \&Exception::Lite::_dumpMessage ' .
-           ', q{0+} => \&Exception::Lite::_refaddr, fallback=>1;' .
-        'sub PROPAGATE { push @{$_[0]->[6]},[$_[1],$_[2]]; $_[0]}';
-    }
-  }
-  $sDeclare .= 'return 1;';
-
-  local $SIG{__WARN__} = sub {
-    my ($p,$f,$l) = caller(2);
-    my $s=$_[0]; $s =~ s/at \(eval \d+\)\s+line\s+\d+\.//m;
-    print STDERR "$s in declareExceptionClass($sClass,...) "
-      ."in file $f, line $l\n";
-  };
-
-  eval $sDeclare or do {
-    my ($p,$f,$l) = caller(1);
-    print STDERR "Can't create class $sClass at file $f, line $l\n";
-    if ($sClass =~ /\w:\w/) {
-      print STDERR "Bad class name: "
-        ."At least one ':' is not doubled\n";
-    } elsif ($sClass !~ /^\w+(?:::\w+)*$/) {
-      print STDERR "Bad class name: $sClass\n";
-    } else {
-      $sDeclare=~s/(sub |use )/\n$1/g; print STDERR "$sDeclare\n";
-    }
-  };
-
-  # this needs to be separate from the eval, otherwise it never
-  # ends up in @INC or @ISA, at least in Perl 5.8.8
-  $INC{$sPath} = __FILE__;
-  eval "\@${sClass}::ISA=qw($sSuperClass);" if $sSuperClass;
-
-  return $sClass;
-}
-
-#------------------------------------------------------------------
-
-sub isChainable { return ref($_[0])?1:0; }
-
-#------------------------------------------------------------------
-
-sub isException {
-  my ($e, $sClass) = @_;
-  my $sRef=ref($e);
-  return !defined($sClass)
-    ? ($sRef ? isExceptionClass($sRef) : 0)
-    : $sClass eq ''
-       ? ($sRef eq '' ? 1 : 0)
-       : ($sRef eq '')
-            ? 0
-            : $sRef->isa($sClass)
-               ?1:0;
-}
-
-#------------------------------------------------------------------
-
-sub isExceptionClass {
-  return defined($_[0]) && $_[0]->can('_getInterface')
-    && ($_[0]->_getInterface() eq __PACKAGE__) ? 1 : 0;
-}
-
-#------------------------------------------------------------------
-
-sub onDie {
-  my $iStringify = $_[0];
-  $SIG{__DIE__} = sub {
-    $Exception::Lite::STRINGIFY=$iStringify;
-    warn 'Exception::Lite::Any'->new('Unexpected death:'.$_[0])
-      unless $^S || isException($_[0]);
-  };
-}
-
-#------------------------------------------------------------------
-
-sub onWarn {
-  my $iStringify = $_[0];
-  $SIG{__WARN__} = sub {
-    $Exception::Lite::STRINGIFY=$iStringify;
-    print STDERR 'Exception::Lite::Any'->new("Warning: $_[0]");
-  };
-}
-
-#==================================================================
-# PRIVATE SUBROUTINES
-#==================================================================
-
-#------------------------------------------------------------------
-
-sub _cacheCall {
-  my $iFrame = $_[0];
-
-  my @aCaller;
-  my $aArgs;
-
-  # caller populates @DB::args if called within DB package
-  eval {
-    # this 2 line wierdness is needed to prevent Module::Build from finding
-    # this and adding it to the provides list.
-    package
-      DB;
-
-    #get rid of eval and call to _cacheCall
-    @aCaller = caller($iFrame+2);
-
-    # mark leading undefined elements as maybe shifted away
-    my $iDefined;
-    if ($#aCaller < 0) {
-      @DB::args=@ARGV;
-    }
-    $aArgs = [  map {
-      defined($_)
-        ? do {$iDefined=1;
-              "'$_'" . (overload::Method($_,'""')
-                        ? ' ('.overload::StrVal($_).')':'')}
-          : 'undef' . (defined($iDefined)
-                       ? '':'  (maybe shifted away?)')
-        } @DB::args];
-  };
-
-  return $#aCaller < 0 ? \$aArgs : [ @aCaller[0..3], $aArgs ];
-}
-
-#------------------------------------------------------------------
-
-sub _cacheStackTrace {
-  my $e=$_[0]; my $st=[];
-
-  # set up initial frame
-  my $iFrame= $STACK_OFFSET + 1; # call to new
-  my $aCall = _cacheCall($iFrame++);
-  my ($sPackage, $iFile, $iLine, $sSub, $sArgs) = @$aCall;
-  my $iLineFrame=$iFrame;
-
-  $aCall =  _cacheCall($iFrame++);  #context of call to new
-  while (ref($aCall) ne 'REF') {
-    $sSub  = $aCall->[3];  # subroutine containing file,line
-    $sArgs = $aCall->[4];  # args used to call $sSub
-
-    #print STDERR "debug-2: package=$sPackage file=$iFile line=$iLine"
-    #  ." sub=$sSub, args=@$sArgs\n";
-
-    # in evals we want the line number within the eval, but the
-    # name of the sub in which the eval was located. To get this
-    # we wait to push on the stack until we get an actual sub name
-    # and we avoid overwriting the location information, hence 'ne'
-
-    if (!$FILTER || ($sSub ne EVAL)) {
-      my $aFrame=[ $iFile, $iLine, $sSub, $sArgs ];
-      ($sPackage, $iFile, $iLine) = @$aCall;
-      $iLineFrame=$iFrame;
-
-      my $sRef=ref($FILTER);
-      if ($sRef eq 'CODE') {
-        my $x = $FILTER->(@$aFrame, $iFrame, $iLineFrame);
-        if (ref($x) eq 'ARRAY') {
-          $aFrame=$x;
-        } elsif (!$x) {
-          $aFrame=undef;
-        }
-      } elsif (($sRef eq 'ARRAY') && ! _isIgnored($sSub, $FILTER)) {
-        $aFrame=undef;
-      } elsif (($sRef eq 'Regexp') && !_isIgnored($sSub, [$FILTER])) {
-        $aFrame=undef;
-      }
-      push(@$st, $aFrame) if $aFrame;
-    }
-
-    $aCall = _cacheCall($iFrame++);
-  }
-
-  push @$st, [ $iFile, $iLine, "<package: $sPackage>", $$aCall ];
-  if ($e) { my $n=$#{$e->[2]}-$#$st;$e->[2]=[@{$e->[2]}[0..$n]]};
-  return $st;
-}
-
-#-----------------------------
-
-sub _isIgnored {
-  my ($sSub, $aIgnore) = @_;
-  foreach my $re (@$aIgnore) { return 1 if $sSub =~ $re; }
-  return 0;
-}
-
-#------------------------------------------------------------------
-
-sub _dumpMessage {
-  my ($e, $iDepth) = @_;
-
-  my $sMsg = $e->getMessage();
-  return $sMsg unless $STRINGIFY;
-  if (ref($STRINGIFY) eq 'CODE') {
-    return $STRINGIFY->($sMsg);
-  }
-
-  $iDepth = 0 unless defined($iDepth);
-  my $sIndent = ' ' x ($TAB*$iDepth);
-  $sMsg = "\n${sIndent}Exception! $sMsg";
-  return $sMsg if $STRINGIFY == 0;
-
-  my ($sThrow, $sReach);
-  my $sTab = ' ' x $TAB;
-
-  $sIndent.= $sTab;
-  if ($STRINGIFY > 2) {
-    my $aPropagation = $e->getPropagation();
-    for (my $i=$#$aPropagation; $i >= 0; $i--) {
-      my ($f,$l) = @{$aPropagation->[$i]};
-      $sMsg .= "\n${sIndent}rethrown at file $f, line $l";
-    }
-    $sMsg .= "\n";
-    $sThrow='thrown  ';
-    $sReach='reached ';
-  } else {
-    $sThrow='';
-    $sReach='';
-  }
-
-  my $st=$e->getStackTrace();
-  my $iTop = scalar @$st;
-
-  for (my $iFrame=0; $iFrame<$iTop; $iFrame++) {
-    my ($f,$l,$s,$aArgs) = @{$st->[$iFrame]};
-
-    if ($iFrame) {
-      #2nd and following stack frame
-      my $sVia="${sIndent}${sReach}via file $f, line $l";
-      my $sLine="$sVia in $s";
-      $sMsg .= (length($sLine)>$LINE_LENGTH
-                ? "\n$sVia\n$sIndent${sTab}in $s" : "\n$sLine");
-    } else {
-      # first stack frame
-      my $tid=$e->getTid();
-      my $sAt="${sIndent}${sThrow}at  file $f, line $l";
-      my $sLine="$sAt in $s";
-      $sMsg .= (length($sLine)>$LINE_LENGTH
-                ? "\n$sAt\n$sIndent${sTab}in $s" : "\n$sLine")
-        . ", pid=" . $e->getPid() . (defined($tid)?", tid=$tid":'');
-
-      return "$sMsg\n" if $STRINGIFY == 1;
-    }
-
-    if ($STRINGIFY > 3) {
-      my $bTop = ($iFrame+1) == $iTop;
-      my $sVar= ($bTop && !$iDepth) ? '@ARGV' : '@_';
-      my $bMaybeEatenByGetOpt = $bTop && !scalar(@$aArgs)
-        && exists($INC{'Getopt/Long.pm'});
-
-      my $sVarIndent = "\n${sIndent}" . (' ' x $TAB);
-      my $sArgPrefix = "${sVarIndent}".(' ' x length($sVar)).' ';
-      if ($bMaybeEatenByGetOpt) {
-        $sMsg .= $sArgPrefix . $sVar
-          . '()    # maybe eaten by Getopt::Long?';
-      } else {
-        my $sArgs = join($sArgPrefix.',', @$aArgs);
-        $sMsg .= "${sVarIndent}$sVar=($sArgs";
-        $sMsg .= $sArgs ? "$sArgPrefix)" : ')';
-      }
-    }
-  }
-  $sMsg.="\n";
-  return $sMsg if $STRINGIFY == 2;
-
-  my $eChained = $e->getChained();
-  if (defined($eChained)) {
-    my $sTrigger = isException($eChained)
-      ? _dumpMessage($eChained, $iDepth+1)
-      : "\n${sIndent}$eChained\n";
-    $sMsg .= "\n${sIndent}Triggered by...$sTrigger";
-  }
-  return $sMsg;
-}
-
-#------------------------------------------------------------------
-
-# refaddr has a prototype($) so we can't use it directly as an
-# overload operator: it complains about being passed 3 parameters
-# instead of 1.
-sub _refaddr { Scalar::Util::refaddr($_[0]) };
-
-#------------------------------------------------------------------
-
-sub _rethrow {
-  my $self = shift; my $sAddOrOmit = shift;
-  my ($p,$f,$l)=caller(1);
-  $self->PROPAGATE($f,$l);
-
-  if (@_%2) {
-    warn sprintf('bad parameter list to %s->rethrow(...)'
-      .'at file %d, line %d: odd number of elements in property-value '
-      .'list, property value has no property name and will be '
-      ."discarded (common causes: you have %s string)\n"
-      ,$f, $l, $sAddOrOmit);
-    shift @_;
-  }
-  $self->replaceProperties({@_}) if (@_);
-  return $self;
-}
-
-#------------------------------------------------------------------
-# Traps warnings and reworks them so that they tell the user how
-# to fix the problem rather than obscurely complain about an
-# invisible sprintf with uninitialized values that seem to come from
-# no where (and make Exception::Lite look like it is broken)
-
-sub _sprintf {
-  my $sMsg;
-  my $sWarn;
-
-  {
-    local $SIG{__WARN__} = sub { $sWarn=$_[0] if !defined($sWarn) };
-
-    # sprintf has prototype ($@)
-    my $sFormat = shift;
-    $sMsg = sprintf($sFormat, @_);
-  }
-
-  if (defined($sWarn)) {
-    my $sReason='';
-    my ($f, $l, $s) = (caller(1))[1,2,3];
-    $s =~ s/::(\w+)\z/->$1/;
-    $sWarn =~ s/sprintf/$s/;
-    $sWarn =~ s/\s+at\s+[\w\/\.]+\s+line\s+\d+\.\s+\z//;
-    if ($sWarn
-        =~ m{^Use of uninitialized value in|^Missing argument}) {
-      my $p=$s; $p =~ s/->\w+\z//;
-      $sReason ="\n     Most likely cause: "
-        . "Either you are missing property-value pairs needed to"
-        . "build the message or your exception class's format"
-        . "definition mistakenly has too many placeholders "
-        . "(e.g. %s,%d,etc)\n";
-    }
-    warn "$sWarn called at file $f, line $l$sReason\n";
-  }
-  return $sMsg;
-}
-
-#------------------------------------------------------------------
-
-sub _shiftProperties {
-  my $cl= shift;  my $st=shift;  my $sAddOrOmit = shift;
-  if (@_%2) {
-    $"='|';
-    warn sprintf('bad parameter list to %s->new(...) at '
-      .'file %s, line %d: odd number of elements in property-value '
-      .'list, property value has no property name and will be '
-      .'discarded (common causes: you have %s string -or- you are '
-      ."using a string as a chained exception)\n"
-      ,$cl,$st->[0]->[0],$st->[0]->[1], $sAddOrOmit);
-    shift @_;
-  }
-  return {@_};
-}
-
-#==================================================================
-# MODULE INITIALIZATION
-#==================================================================
-
-declareExceptionClass(__PACKAGE__ .'::Any');
-1;
diff --git a/modules/fallback/Exception/Lite.pod b/modules/fallback/Exception/Lite.pod
deleted file mode 100644 (file)
index cea165f..0000000
+++ /dev/null
@@ -1,2314 +0,0 @@
-=head1 NAME
-
-Exception::Lite - light weight exception handling class with smart
-stack tracing, chaining, and localization support.
-
-=head1 SYNOPSIS
-
-   # --------------------------------------------------------
-   # making this module available to your code
-   # --------------------------------------------------------
-
-   #Note: there are NO automatic exports
-
-   use Exception::Lite qw(declareExceptionClass
-                          isException
-                          isChainable
-                          onDie
-                          onWarn);
-
-   # imports only: declareExceptionClass isException isChainable
-   use Exception::Lite qw(:common);
-
-   # imports all exportable methods listed above
-   use Exception::Lite qw(:all);
-
-
-   # --------------------------------------------------------
-   # declare an exception class
-   # --------------------------------------------------------
-
-   # no format rule
-   declareExceptionClass($sClass);
-   declareExceptionClass($sClass, $sSuperClass);
-
-   # with format rule
-   declareExceptionClass($sClass, $aFormatRule);
-   declareExceptionClass($sClass, $sSuperClass, $aFormatRule);
-
-   # with customized subclass
-   declareExceptionClass($sClass, $sSuperClass, 1);
-   declareExceptionClass($sClass, $aFormatRule, 1);
-   declareExceptionClass($sClass, $sSuperClass, $aFormatRule, 1);
-
-   # --------------------------------------------------------
-   # throw an exception
-   # --------------------------------------------------------
-
-   die $sClass->new($sMsg, $prop1 => $val1, ...);  #no format rule
-   die $sClass->new($prop1 => $val1, ...);         #has format rule
-
-   #-or-
-
-   $e = $sClass->new($sMsg, $prop1 => $val1, ...); #no format rule
-   $e = $sClass->new($prop1 => $val1, ...);        #has format rule
-
-   die $e;
-
-   # --------------------------------------------------------
-   # catch and test an exception
-   # --------------------------------------------------------
-
-   # Note: for an explanation of why we don't use if ($@)... here,
-   # see Catching and Rethrowing exceptions below
-
-   eval {
-     .... some code that may die here ...
-     return 1;
-   } or do {
-     my $e=$@;
-
-     if (isException($e, 'Class1')) {
-       ... do something ...
-     } elsif (isExcption($e, 'Class2')) {
-        ... do something else ...
-     }
-   };
-
-   isException($e);        # does $e have the above exception methods?
-   isException($e,$sClass) # does $e belong to $sClass or a subclass?
-
-   # --------------------------------------------------------
-   # getting information about an exception object
-   # --------------------------------------------------------
-
-   $e->getMessage();
-   $e->getProperty($sName);
-   $e->isProperty($sName);
-   $e->replaceProperties($hOverride);
-
-   $e->getPid();
-   $e->getPackage();
-   $e->getTid();
-
-   $e->getStackTrace();
-   $e->getFrameCount();
-   $e->getFile($i);
-   $e->getLine($i);
-   $e->getSubroutine($i);
-   $e->getArgs($i);
-
-   $e->getPropagation();
-   $e->getChained();
-
-
-   # --------------------------------------------------------
-   # rethrowing exceptions
-   # --------------------------------------------------------
-
-   # using original properties and message
-
-   $@=$e; die;         # pure Perl way (reset $@ in case wiped out)
-
-   die $e->rethrow();  # same thing, but a little less cryptic
-
-
-   # overriding original message/properties
-
-   die $e->rethrow(path=>$altpath, user=>$nameReplacingId);
-
-
-   # --------------------------------------------------------
-   # creation of chained exceptions (one triggered by another)
-   # (new exception with "memory" of what caused it and stack
-   # trace from point of cause to point of capture)
-   # --------------------------------------------------------
-
-   isChainable($e);        # can $e be used as a chained exception?
-
-   die $sClass->new($e, $sMsg, $prop1 => $val1, ...);#no format rule
-   die $sClass->new($e, $prop1 => $val1, ...);       #has format rule
-
-   # --------------------------------------------------------
-   # print out full message from an exception
-   # --------------------------------------------------------
-
-   print $e                         # print works
-   warn $e                          # warn works
-   print "$e\n";                    # double quotes work
-   my $sMsg=$e."\n"; print $sMsg;   # . operator works
-
-
-   # --------------------------------------------------------
-   # global control variables (maybe set on the command line)
-   # --------------------------------------------------------
-
-   $Exception::Lite::STRINGIFY   #set rule for stringifying messages
-
-      = 1;        # message and file/line where it occured
-      = 2;        # 1 + what called what (simplified stack trace)
-      = 3;        # 2 + plus any chained exceptions and where message
-                  # was caught, if propagated and rethrown
-      = 4;        # 3 + arguments given to each call in stack trace
-      = coderef   # custom formatting routine
-
-   $Exception::Lite::TAB   # set indentation for stringified
-                           # messages, particularly indentation for
-                           # call parameters and chained exceptions
-
-   $Exception::Lite::FILTER
-     = 0         # see stack exactly as Perl does
-     = 1         # remove frames added by eval blocks
-     = coderef   # custom filter - see getStackTrace for details
-
-   # --------------------------------------------------------
-   # controlling the stack trace from the command line
-   # --------------------------------------------------------
-
-   perl -mException::Lite=STRINGIFY=1,FILTER=0,TAB=4
-   perl -m'Exception::Lite qw(STRINGIFY=1 FILTER=0 TAB=4)'
-
-   # --------------------------------------------------------
-   # built in exception classes
-   # --------------------------------------------------------
-
-   # generic wrapper for converting exception strings and other
-   # non-Exception::Lite exceptions into exception objects
-
-   Exception::Class::Any->new($sMessageText);
-
-To assist in debugging and testing, this package also includes
-two methods that set handlers for die and warn. These methods
-should I<only> be used temporarily during active debugging. They
-should not be used in production software, least they interfere
-with the way other programmers using your module wish to do their
-debugging and testing.
-
-   # --------------------------------------------------------
-   # force all exceptions/warnings to use Exception::Lite to
-   # print out messages and stack traces
-   # --------------------------------------------------------
-
-   # $stringify is the value for EXCEPTION::Lite::STRINGIFY
-   # that you want to use locally to print out messages. It
-   # will have no effect outside of the die handler
-
-   Exception::Lite::onDie($stringify);
-   Exception::Lite::onWarn($stringify);
-
-=head1 DESCRIPTION
-
-The C<Exception::Lite> class provides an easy and very light weight
-way to generate context aware exceptions.  It was developed because
-the exception modules on CPAN as of December,2010 were heavy on
-features I didn't care for and did not have the features I most
-needed to test and debug code efficiently.
-
-=head2 Features
-
-This module provides a light weight but powerful exception class
-that
-
-=over 
-
-=item *
-
-provides an uncluttered stack trace that clearly shows what
-called what and what exception triggered what other exception.
-It significantly improves on the readability of the stack trace
-dumps provided by C<carp> and other exception modules on
-CPAN (as of 12/2010).  For further discussion and a sample, see
-L</More intelligent stack trace>.
-
-=item *
-
-gives the user full control over the amount of debugging
-information displayed when exceptions are thrown.
-
-=item *
-
-permits global changes to the amount of debugging information
-displayed via the command line.
-
-=item *
-
-closely integrates exception classes, messages, and properties
-so that they never get out of sync with one another.  This in
-turn eliminates redundant coding and helps reduce the cost of
-writing,validating and maintaining a set of exceptions.
-
-=item *
-
-is easy to retrofit with native language support, even if this
-need appears late in the development process.This makes it
-suitable for use with agile development strategies.
-
-=item *
-
-act like strings in string context but are in fact objects with
-a class hierarchy and properties.They can be thrown and rethrown
-with standard Perl syntax. Like any object, they can be uniquely
-identified in numeric context where they equal their reference
-address (the value returned by C<Scalar::Util::refaddr()>.
-
-=item *
-
-does not interfere with signal handlers or the normal Perl syntax
-and the assumptions of Perl operators.
-
-=item *
-
-can be easily extended and subclassed
-
-=back
-
-=head2 Lightweight how?
-
-Despite these features C<Exception::Lite> maintains its "lite"
-status by
-
-=over
-
-=item *
-
-using only core modules
-
-=item *
-
-generating tiny exception classes (30-45LOC per class).
-
-=item *
-
-eliminating excess baggage by customizing generated classes to
-  reflect the actual needs of exception message generation.  For
-  instance an exception wrapped around a fixed string message would
-  omit code for message/property integration and would be little
-  more than a string tied to a stack trace and property hash.
-
-=item *
-
-storing only the minimum amount of stack trace data needed to
-  generate exception messages and avoiding holding onto references
-  from dead stack frames.  (Note: some CPAN modules hold onto
-  actual variables from each frame, possibly interfering with
-  garbage collection).
-
-=item *
-
-doing all its work, including class generation and utilities in
-  a single file that is less than half the size of the next smallest
-  similarly featured all-core exception class on CPAN (support for
-  both properties and a class heirarchy).  C<Exception::Lite>
-  contains about 400 lines when developer comments are excluded). The
-  next smallest all core module is L<Exception::Base|Exception::Base>
-  which clocks in at just over 1000 lines after pod and developer
-  comments are excluded).
-
-=item *
-
-avoiding a heavy-weight base class.  Code shared by
-  C<Exception::Lite> classes are stored in function calls that total
-  230 or so lines of code relying on nothing but core modules. This
-  is significantly less code than is needed by the two CPAN packages
-  with comparable features.  The all core
-  L<Exception::Base|Exception::Base> class contains 700+ lines of
-  code.  The base class of L<Exception::Class|Exception::Class> has
-  200 lines of its own but drags in two rather large non-core
-  modules as dependencies:  L<Devel::StackTrace|Devel::StackTrace>
-  L<Class::Data::Inheritable|Class::Data::Inheritable>.
-
-=back
-
-C<Exception::Lite> has more features (chaining, message/property
-integration) but less code due to the following factors:
-
-=over
-
-=item *
-
-working with Perl syntax rather than trying to replace it.
-
-=item *
-
-using a light approach to OOP - exception classes have just enough
-and no more OO features than are needed to be categorized by a
-class, participate in a class heirarchy and to have properties.
-
-=item *
-
-respecting separation of concerns. C<Exception::Lite> focuses
-on the core responsibility of an exception and leaves the bulk of
-syntax creation (e.g. Try/Catch) to specialist modules like
-L<Try::Tiny|Try::Tiny>.  Other modules try to double as
-comprehensive providers of exception related syntactic sugar.
-
-=item *
-
-not trying to be the only kind of exception that an application
-uses.
-
-=back
-
-=head1 USAGE
-
-=head2 Defining Exception Classes
-
-C<Exception::Lite> provides two different ways to define messages.
-The first way, without a format rule, lets you compose a freeform
-message for each exception.  The second way, with a format rule,
-lets you closely integrate messages and properties and facilitates
-localization of messages for any packages using your software.
-
-=head3 Defining freeform messages
-
-If you want to compose a free form message for each and every
-exception, the class declaration is very simple:
-
-   declareExceptionClass($sClass);
-   declareExceptionClass($sClass, $sSuperClass);
-
-   # with customized subclass
-   declareExceptionClass($sClass, $sSuperClass, 1);
-
-C<$sClass> is the name of the exception class.
-
-C<$sSuperClass> is the name of the superclass, if there is one.
-The superclass can be any class created by C<Exception::Lite>. It
-can also be any role class, i.e. a class that has methods but no
-object data of its own.
-
-The downside of this simple exception class is that there is
-absolutely no integration of your messages and any properties that
-you assign to the exception.  If you would like to see your property
-values included in the message string,consider using a formatted
-message instead.
-
-=head3 Defining formatted messages
-
-If you wish to include property values in your messages, you need
-to declare a formatted message class. To do this, you define a
-format rule and pass it to the constructor:
-
-   $aFormatRule = ['Cannot copy %s to %s', qw(from to) ];
-
-   declareExceptionClass($sClass, $aFormatRule);
-   declareExceptionClass($sClass, $sSuperClass, $aFormatRule);
-
-   # with customized subclass
-   declareExceptionClass($sClass, $aFormatRule, 1);
-   declareExceptionClass($sClass, $sSuperClass, $aFormatRule, 1);
-
-Format rules are nothing more than a sprintf message string
-followed by a list of properties in the same order as the
-placeholders in the message string.  Later on when an exception
-is generated, the values of the properties will replace the
-property names.  Some more examples of format rules:
-
-
-   $aFormatRule = ['Illegal argument <%s>: %s', qw(arg reason)];
-   declareExceptionClass('BadArg', $aFormatRule);
-
-   $aFormatRule = ['Cannot open file <%s>> %s', qw(file reason)];
-   declareExceptionClass('OpenFailed', $aFormatRule);
-
-   $sFormatRule = ['Too few %s,  must be at least %s', qw(item min)];
-   declareExceptionClass('TooFewWidgets', $aFormatRule);
-
-
-Later on when you throw an exception you can forget about the message
-and set the properties, the class will do the rest of the work:
-
-    die BadArg->new(arg=>$sPassword, reason=>'Too few characters');
-
-
-    open(my $fh, '>', $sFile)
-      or die OpenFailed->new(file=>$sFile, reason=>$!);
-
-And still later when you catch the exception, you have two kinds
-of information for the price of one:
-
-    # if you catch BadArg
-
-    $e->getProperty('arg')      # mine
-    $e->getProperty('reason')   # too few characters
-    $e->getMessage()   # Illegal argument <mine>: too few characters
-
-
-    # if you catch OpenFailed
-
-    $e->getProperty('file')     # foo.txt
-    $e->getProperty('reason')   # path not found
-    $e->getMessage()   # Cannot open <foo.txt>: path not found
-
-
-=head2 Creating and throwing exceptions
-
-When it comes times to create an exception, you create and
-throw it like this (C<$sClass> is a placeholder for the name of
-your exception class);
-
-
-   die $sClass->new($sMsg, prop1 => $val1, ...);  #no format rule
-   die $sClass->new(prop1 => $val1, ...);         #has format rule
-
-   #-or-
-
-   $e = $sClass->new($sMsg, prop1 => $val1, ...); #no format rule
-   $e = $sClass->new(prop1 => $val1, ...);        #has format rule
-
-   die $e;
-
-
-For example:
-
-   # Freeform exceptions (caller composes message, has message
-   # parameter ($sMsg) before the list of properties)
-
-   close $fh or die UnexpectedException
-     ->new("Couldn't close file handle (huh?): $!");
-
-   die PropertySettingError("Couldn't set property"
-     , prop=>foo, value=>bar);
-
-   # Formatted exceptions (no $sMsg parameter)
-
-   if (length($sPassword) < 8) {
-      die BadArg->new(arg=>$sPassword, reason=>'Too few characters');
-   }
-
-   open(my $fh, '>', $sFile)
-      or die OpenFailed->new(file=>$sFile, reason=>$!);
-
-In the above examples the order of the properties does not matter.
-C<Exception::Lite> is using the property names, not the order of
-the properties to find the right value to plug into the message
-format string.
-
-=head2 Catching and testing exceptions
-
-In Perl there are two basic ways to work with exceptions:
-
-* native Perl syntax
-
-* Java like syntax (requires non-core modules)
-
-=head3 Catching exceptions the Java way
-
-Java uses the following idiom to catch exceptions:
-
-   try {
-     .... some code here ...
-  } catch (SomeExceptionClass e) {
-    ... error handling code here ...
-  } catch (SomeOtherExceptionClass e) {
-    ... error handling code here ...
-  } finally {
-    ... cleanup code here ...
-  }
-
-There are several CPAN modules that provide some sort of syntactic
-sugar so that you can emulate java syntax. The one recommended
-for C<Exception::Lite> users is L<Try::Tiny|Try::Tiny>.
-L<Try::Tiny|Try::Tiny> is an elegant class that concerns itself
-only with making it possible to use java-like syntax.  It can be
-used with any sort of exception.
-
-Some of the other CPAN modules that provide java syntax also
-require that you use their exception classes because the java like
-syntax is part of the class definition rather than a pure
-manipulation of Perl syntax.
-
-
-=head3 Catching exceptions the Perl way
-
-The most reliable and fastest way to catch an exception is to use
-C< eval/do >:
-
-   eval {
-     ...
-     return 1;
-   } or do {
-     # save $@ before using it - it can easily be clobbered
-     my $e=$@;
-
-     ... do something with the exception ...
-
-     warn $e;                 #use $e as a string
-     warn $e->getMessage();   # use $e as an object
-   }
-
-
-The C<eval> block ends with C<return 1;> to insure that successful
-completion of the eval block never results in an undefined value.
-In certain cases C<undef> is a valid return value for a statement,
-We don't want to enter the C<do> block for any reason other than
-a thrown exception.
-
-C< eval/do > is both faster and more reliable than the C< eval/if>
-which is commonly promoted in Perl programming tutorials:
-
-  # eval ... if
-
-  eval {...};
-  if ($@) {....}
-
-It is faster because the C<do> block is executed if and only
-if the eval fails. By contrast the C<if> must be evaluated both
-in cases of succes and failure.
-
-C< eval/do > is more reliable because the C<do> block is guaranteed
-to be triggered by any die, even one that accidentally throws undef
-or '' as the "exception". If an exception is thrown within the C<eval>
-block, it will always evaluate to C<undef> therefore triggering the
-C<do> block.
-
-On the other hand we can't guarentee that C<$@> will be defined
-even if an exception is thrown. If C<$@> is C<0>, C<undef>, or an
-empty string, the C<if> block will never be entered.  This happens
-more often then many programmers realize.  When eval exits the
-C< eval > block, it calls destructors of any C<my> variables. If
-any of those has an C< eval > statement, then the value of C<$@> is
-wiped clean or reset to the exception generated by the destructor.
-
-Within the C<do> block, it is a good idea to save C<$@> immediately
-into a variable before doing any additional work.  Any subroutine
-you call might also clobber it.  Even built-in commands that don't
-normally set C<$@> can because Perl lets a programmer override
-built-ins with user defined routines and those user define routines
-might set C<$@> even if the built-in does not.
-
-=head3 Testing exceptions
-
-Often when we catch an exception we want to ignore some, rethrow
-others, and in still other cases, fix the problem. Thus we need a
-way to tell what kind of exception we've caught.  C<Exception::Lite>
-provides the C<isException> method for this purpose.  It can be
-passed any exception, including scalar exceptions:
-
-   # true if this exception was generated by Exception::Line
-   isException($e);
-
-
-   # true if this exception belongs to $sClass. It may be a member
-   # of the class or a subclass.  C<$sClass> may be any class, not
-   # just an Exception::Lite generated class. You can even use this
-   # method to test for string (scalar) exceptions:
-
-   isException($e,$sClass);
-
-   isException($e,'Excption::Class');
-   isException($e, 'BadArg');
-   isException($e, '');
-
-And here is an example in action. It converts an exception to a
-warning and determines how to do it by checing the class.
-
-
-   eval {
-     ...
-     return 1;
-   } or do {
-     my $e=$@;
-     if (Exception::Lite::isException($e)) {
-
-        # get message w/o stack trace, "$e" would produce trace
-        warn $e->getMessage();
-
-     } elsif (Exception::Lite::isException('Exception::Class') {
-
-        # get message w/o stack trace, "$e" would produce trace
-        warn $e->message();
-
-     } elsif (Exception::Lite::isException($e,'')) {
-
-        warn $e;
-     }
-   }
-
-=head2 Rethrowing exceptions
-
-Perl doesn't have a C<rethrow> statement.  To reliably rethrow an
-exception, you must set C<$@> to the original exception (in case it
-has been clobbered during the error handling process) and then call
-C<die> without any arguments.
-
-   eval {
-     ...
-     return 1;
-   } or do {
-     my $e=$@;
-
-     # do some stuff
-
-     # rethrow $e
-     $@=$e; die;
-   }
-
-The above code will cause the exception's C<PROPAGATE> method to
-record the file and line number where the exception is rethrown.
-See C<getLine>, C<getFile>, and C<getPropagation> in the class
-reference below for more information.
-
-As this Perl syntax is not exactly screaming "I'm a rethrow", 
-C<Exception::Lite> provides an alternative and hopefully more
-intuitive way of propagating an exception. There is no magic here,
-it just does what perl would do had you used the normal syntax,
-i.e. call the exception's C<PROPAGATE> method.
-
-   eval {
-     ...
-     return 1;
-   } or do {
-     my $e=$@;
-
-     # rethrow $e
-     die $e->rethrow();
-   }
-
-=head2 Chaining Messages
-
-As an exception moves up the stack, its meaning may change. For
-example, suppose a subroutine throws the message "File not open".
-The immediate caller might be able to use that to try and open
-a different file.  On the other hand, if the message gets thrown
-up the stack, the fact that a file failed to open might not
-have any meaning at all.  That higher level code only cares that
-the data it needed wasn't available. When it notifies the user,
-it isn't going to say "File not found", but "Can't run market
-report: missing data feed.".
-
-When the meaning of the exception changes, it is normal to throw
-a new exception with a class and message that captures the new
-meaning. However, if this is all we do, we lose the original
-source of the problem.
-
-Enter chaining.  Chaining is the process of making one exception
-"know" what other exception caused it.  You can create a new
-exception without losing track of the original source of the
-problem.
-
-To chain exceptions is simple: just create a new exception and
-pass the caught exception as the first parameter to C<new>. So
-long as the exception is a non-scalar, it will be interpreted
-as a chained exception and not a property name or message text
-(the normal first parameter of C<new>).
-
-Chaining is efficient, especially if the chained exception is
-another C<Exception::Lite> exception. It does not replicate
-the stack trace.  Rather the original stack trace is shorted to
-include only the those fromes frome the time it was created to
-the time it was chained.
-
-Any non-scalar exception can be chained.  To test whether or not
-a caught exception is chainable, you can use the method
-C<isChainable>.  This method is really nothing more than
-a check to see if the exception is a non-scalar, but it helps
-to make your code more self documenting if you use that method
-rather than C<if (ref($e))>.
-
-If an exception isn't chainable, and you still want to chain
-it, you can wrap the exception in an exception class. You
-can use the built-in C<Exception::Class::Any> or any class of
-your own choosing.
-
-   #-----------------------------------------------------
-   # define some classes
-   #-----------------------------------------------------
-
-   # no format rule
-   declareExceptionClass('HouseholdDisaster');
-
-   # format rule
-   declareExceptionClass('ProjectDelay'
-     , ['The project was delayed % days', qw(days)]);
-
-   #-----------------------------------------------------
-   # chain some exceptins
-   #-----------------------------------------------------
-
-   eval {
-     .... some code here ...
-     return 1;
-  } or do {
-    my $e=$@;
-    if (Exception::Lite::isChainable($e)) {
-      if (Exception::Lite::isException($e, 'FooErr') {
-        die 'SomeNoFormatException'->new($e, "Caught a foo");
-      } else {
-        die 'SomeFormattedException'->new($e, when => 'today');
-      }
-    } elsif ($e =~ /fire/) {
-       die 'Exception::Lite::Any'->new($e);
-       die 'SomeFormattedException'->new($e, when => 'today');
-    } else {
-      # rethrow it since we can't chain it
-      $@=$e; die;
-    }
-  }
-
-=head2 Reading Stack Traces
-
-At its fullest level of detail, a stack trace looks something
-like this:
-
- Exception! Mayhem! and then ...
-
-    thrown  at  file Exception/Lite.t, line 307
-    in main::weKnowBetterThanYou, pid=24986, tid=1
-       @_=('ARRAY(0x83a8a90)'
-          ,'rot, rot, rot'
-          ,'Wikerson brothers'
-          ,'triculous tripe'
-          ,'There will be no more talking to hoos who are not!'
-          ,'black bottom birdie'
-          ,'from the three billionth flower'
-          ,'Mrs Tucanella returns with uncles and cousins'
-          ,'sound off! sound off! come make yourself known!'
-          ,'Apartment 12J'
-          ,'Jo Jo the young lad'
-          ,'the whole world was saved by the smallest of all'
-          )
-    reached via file Exception/Lite.t, line 281
-    in main::notAWhatButAWho
-       @_=()
-    reached via file Exception/Lite.t, line 334 in main::__ANON__
-       @_=()
-    reached via file Exception/Lite.t, line 335 in <package: main>
-       @ARGV=()
-
-    Triggered by...
-    Exception! Horton hears a hoo!
-       rethrown at file Exception/Lite.t, line 315
-
-       thrown  at  file Exception/Lite.t, line 316
-       in main::horton, pid=24986, tid=1
-          @_=('15th of May'
-             ,'Jungle of Nool'
-             ,'a small speck of dust on a small clover'
-             ,'a person's a person no matter how small'
-             )
-       reached via file Exception/Lite.t, line 310 in main::hoo
-          @_=('Dr Hoovey'
-             ,'hoo-hoo scope'
-             ,'Mrs Tucanella'
-             ,'Uncle Nate'
-             )
-       reached via file Exception/Lite.t, line 303
-       in main::weKnowBetterThanYou
-          @_=('ARRAY(0x83a8a90)'
-             ,'rot, rot, rot'
-             ,'Wikerson brothers'
-             ,'triculous tripe'
-             ,'There will be no more talking to hoos who are not!'
-             ,'black bottom birdie'
-             ,'from the three billionth flower'
-             ,'Mrs Tucanella returns with uncles and cousins'
-             ,'sound off! sound off! come make yourself known!'
-             ,'Apartment 12J'
-             ,'Jo Jo the young lad'
-             ,'the whole world was saved by the smallest of all'
-             )
-
-
-=over
-
-=item *
-
-lines begining with "thrown" indicate a line where a new exception
-was thrown. If an exception was chained, there might be multiple
-such lines.
-
-=item *
-
-lines beginning with "reached via" indicate the path travelled
-I<down> to the point where the exception was thrown. This is the
-code that was excuted before the exception was triggered.
-
-=item *
-
-lines beginning with "rethrown at" indicate the path travelled
-I<up> the stack by the exception I<after> it was geenerated. Each
-line indicates a place where the exception was caught and rethrown.
-
-=item *
-
-lines introduced with "Triggered by" are exceptions that were
-chained together. The original exception is the last of the
-triggered exceptions.  The original line is the "thrown" line
-for the original exception.
-
-=item *
-
-C<@_> and <C@ARGV> below a line indicates what is left of the
-parameters passed to a method, function or entry point routine.
-In ideal circumstances they are the parameters passed to the
-subroutine mentioned in the line immediately above C<@_>. In
-reality, they can be overwritten or shifted away between the
-point when the subroutine started and the line was reached.
-
-Note: if you use L<Getopt::Long> to process C<@ARGV>, C<@ARGV>
-will be empty reduced to an empty array. If this bothers you, you
-can localize <@ARGV> before calling C<GetOptions>, like this:
-
-  my %hARGV;
-  {
-    local @ARGV = @ARGV;
-    GetOptions(\%hARGV,...);
-  }
-
-=item *
-
-pid is the process id where the code was running
-
-=item *
-
-tid is the thread id where the code was running
-
-=back
-
-=head1 SPECIAL TOPICS
-
-=head2 Localization of error messages
-
-Rather than treat the error message and properties as entirely
-separate entities, it gives you the option to define a format string
-that will take your property values and insert them automatically
-into your message.  Thus when you generate an exception, you can
-specify only the properties and have your message automatically
-generated without any need to repeat the property values in messy
-C<sprintf>'s that clutter up your program.
-
-One can localize from the very beginning when one declares the
-class or later on after the fact if you are dealing with legacy
-software or developing on an agile module and only implementing
-what you need now.
-
-To localize from the get-go:
-
-   # myLookupSub returns the arguments to declareException
-   # e.g.  ('CopyError', [ 'On ne peut pas copier de %s a %s'
-                           , qw(from to)])
-
-   declareExceptionClass( myLookupSub('CopyError', $ENV{LANG}) );
-
-
-   # .... later on, exception generation code doesn't need to
-   # know or care about the language. it just sets the properties
-
-
-    # error message depends on locale:
-    #   en_US:  'Cannot copy A.txt to B.txt'
-    #   fr_FR:  'On ne peut pas copier de A.txt a B.txt'
-    #   de_DE:  'Kann nicht kopieren von A.txt nach B.txt'
-
-    die 'CopyError'->new(from => 'A.txt', to => 'B.txt');
-
-
-Another alternative if you wish to localize from the get-go is
-to pass a code reference instead of a format rule array. In this
-case, C<Exception::Lite> will automatically pass the class name
-to the subroutine and retrieve the value returned.
-
-
-   # anothherLookupSub has parameters ($sClass) and returns
-   # a format array, for example:
-   #
-   # %LOCALE_FORMAT_HASH = (
-   #    CopyError => {
-   #        en_US => ['Cannot copy %s to %s', qw(from to)]
-   #       ,fr_FR => ['On ne peut pas copier de %s a %s', qw(from to)]
-   #       ,de_DE => ['Kann nicht kopieren von %s nach %s''
-   #                   , qw(from to)]
-   #
-   #    AddError => ...
-   # );
-   #
-   # sub anotherLookupSub {
-   #    my ($sClass) = @_;
-   #    my $sLocale = $ENV{LANG}
-   #    return $LOCALE_FORMAT_HASH{$sClass}{$sLocale};
-   # }
-   #
-
-   declareExceptionClass('CopyError', &anotherLookupSub);
-   declareExceptionClass('AddError', &anotherLookupSub);
-
-
-    # error message depends on locale:
-    #   en_US:  'Cannot copy A.txt to B.txt'
-    #   fr_FR:  'On ne peut pas copier de A.txt a B.txt'
-    #   de_DE:  'Kann nicht kopieren von A.txt nach B.txt'
-
-    die CopyError->new(from => 'A.txt', to => 'B.txt');
-    die AddError->new(path => 'C.txt');
-
-
-If you need to put in localization after the fact, perhaps for a
-new user interface you are developing, the design pattern might
-look like this:
-
-   # in the code module you are retrofitting would be an exception
-   # that lived in a single language world. 
-
-   declareExceptionClass('CopyError'
-     ['Cannot copy %s to %s', [qw(from to)]);
-
-
-   # in your user interface application.
-
-   if (isException($e, 'CopyError') && isLocale('fr_FR')) {
-     my $sFrom = $e->getProperty('from');
-     my $sTo = $e->getProperty('to');
-     warn sprintf('On ne peut pas copier de %s a %s', $sFrom,$sTo);
-   }
-
-=head2 Controlling verbosity and stack tracing
-
-You don't need to print out the fully verbose stack trace and in
-fact, by default you won't.  The default setting, prints out
-only what called what. To make it easier to see what called what,
-it leaves out all of the dumps of C<@_> and C<@ARGV>.
-
-If you want more or less verbosity or even an entirely different
-trace, C<Exception::Lite> is at your sevice.  It provides a variety
-of options for controlling the output of the exception:
-
-* Adjusting the level of debugging information when an exception is
-  thrown by setting C<$Exception::Lite::STRINGIFY>
-  in the program or C<-mException::Lite=STRINGIFY=level> on the
-  command line. This can be set to either a verbosity level or to
-  an exception stringification routine of your own choosing.
-
-* Control which stack frames are displayed by setting
-  C<$Exception::Lite::FILTER>. By default, only calls within named
-  and anonymous subroutines are displayed in the stack trace. Perl
-  sometimes creates frames for blocks of code within a subroutine.
-  These are omitted by default. If you want to see them, you can
-  turn filterin off. Alternatively you can set up an entirely
-  custon stack filtering rule by assigning a code reference to
-  C<$Exception::Lite::FILTER>.
-
-* By default, exceptions store and print a subset of the data
-  available for each stack frame. If you would like to display
-  richer per-frame information, you can do that too. See below
-  for details.
-
-=head3 Verbosity level
-
-The built-in rules for displaying exceptions as strings offer five
-levels of detail.
-
-* 0: Just the error message
-
-* 1: the error message and the file/line number where it occured
-     along with pid and tid.
-
-* 2: the error message and the calling sequence from the point where
-  the exception was generated to the package or script entry point
-  The calling sequence shows only file, line number and the name
-  of the subroutine where the exception was generated. It is not
-  cluttered with parameters, making it easy to scan.
-
-* 3: similar to 2, except that propagation and chained exceptions
-  are also displayed.
-
-* 4: same as 3, except that the state of C<@_> or C<@ARGV> at the
-  time the exception was thrown is also displayed.  usually this
-  is the parameters that were passed in, but it may include several
-  leading C<undef> if C<shift> was used to process the parameter
-  list.
-
-Here are some samples illustrating different level of debugging
-information and what happens when the filter is turned off
-
- #---------------------------------------------------
- #Sample exception STRINGIFY=0 running on thread 5
- #---------------------------------------------------
-
- Exception! Mayhem! and then ...
-
- #---------------------------------------------------
- #Sample exception STRINGIFY=1 running on thread 5
- #---------------------------------------------------
-
- Exception! Mayhem! and then ...
-    at  file Exception/Lite.t, line 307 in main::weKnowBetterThanYou, pid=24986, tid=5
-
- #---------------------------------------------------
- #Sample exception STRINGIFY=2 running on thread 4
- #---------------------------------------------------
-
- Exception! Mayhem! and then ...
-    at  file Exception/Lite.t, line 307 in main::weKnowBetterThanYou, pid=24986, tid=4
-    via file Exception/Lite.t, line 281 in main::notAWhatButAWho
-    via file Exception/Lite.t, line 373 in main::__ANON__
-    via file Exception/Lite.t, line 374 in <package: main>
-
- #---------------------------------------------------
- #Sample exception STRINGIFY=3 running on thread 3
- #---------------------------------------------------
-
- Exception! Mayhem! and then ...
-
-    thrown  at  file Exception/Lite.t, line 307 in main::weKnowBetterThanYou, pid=24986, tid=3
-    reached via file Exception/Lite.t, line 281 in main::notAWhatButAWho
-    reached via file Exception/Lite.t, line 362 in main::__ANON__
-    reached via file Exception/Lite.t, line 363 in <package: main>
-
-    Triggered by...
-    Exception! Horton hears a hoo!
-       rethrown at file Exception/Lite.t, line 315
-
-       thrown  at  file Exception/Lite.t, line 316 in main::horton, pid=24986, tid=3
-       reached via file Exception/Lite.t, line 310 in main::hoo
-       reached via file Exception/Lite.t, line 303 in main::weKnowBetterThanYou
-
- #---------------------------------------------------
- #Sample exception STRINGIFY=3 running on thread 2
- #FILTER=OFF (see hidden eval frames)
- #---------------------------------------------------
-
- Exception! Mayhem! and then ...
-
-    thrown  at  file Exception/Lite.t, line 307 in main::weKnowBetterThanYou, pid=24986, tid=2
-    reached via file Exception/Lite.t, line 281 in main::notAWhatButAWho
-    reached via file Exception/Lite.t, line 348 in (eval)
-    reached via file Exception/Lite.t, line 348 in main::__ANON__
-    reached via file Exception/Lite.t, line 350 in (eval)
-    reached via file Exception/Lite.t, line 350 in <package: main>
-
-    Triggered by...
-    Exception! Horton hears a hoo!
-       rethrown at file Exception/Lite.t, line 315
-
-       thrown  at  file Exception/Lite.t, line 316 in main::horton, pid=24986, tid=2
-       reached via file Exception/Lite.t, line 310 in (eval)
-       reached via file Exception/Lite.t, line 315 in main::hoo
-       reached via file Exception/Lite.t, line 303 in (eval)
-       reached via file Exception/Lite.t, line 305 in main::weKnowBetterThanYou
-
- #---------------------------------------------------
- #Sample exception STRINGIFY=4 running on thread 1
- #FILTER=ON
- #---------------------------------------------------
-
- Exception! Mayhem! and then ...
-
-    thrown  at  file Exception/Lite.t, line 307 in main::weKnowBetterThanYou, pid=24986, tid=1
-       @_=('ARRAY(0x83a8a90)'
-          ,'rot, rot, rot'
-          ,'Wikerson brothers'
-          ,'triculous tripe'
-          ,'There will be no more talking to hoos who are not!'
-          ,'black bottom birdie'
-          ,'from the three billionth flower'
-          ,'Mrs Tucanella returns with Wikerson uncles and cousins'
-          ,'sound off! sound off! come make yourself known!'
-          ,'Apartment 12J'
-          ,'Jo Jo the young lad'
-          ,'the whole world was saved by the tiny Yopp! of the smallest of all'
-          )
-    reached via file Exception/Lite.t, line 281 in main::notAWhatButAWho
-       @_=()
-    reached via file Exception/Lite.t, line 334 in main::__ANON__
-       @_=()
-    reached via file Exception/Lite.t, line 335 in <package: main>
-       @ARGV=()
-
-    Triggered by...
-    Exception! Horton hears a hoo!
-       rethrown at file Exception/Lite.t, line 315
-
-       thrown  at  file Exception/Lite.t, line 316 in main::horton, pid=24986, tid=1
-          @_=('15th of May'
-             ,'Jungle of Nool'
-             ,'a small speck of dust on a small clover'
-             ,'a person's a person no matter how small'
-             )
-       reached via file Exception/Lite.t, line 310 in main::hoo
-          @_=('Dr Hoovey'
-             ,'hoo-hoo scope'
-             ,'Mrs Tucanella'
-             ,'Uncle Nate'
-             )
-       reached via file Exception/Lite.t, line 303 in main::weKnowBetterThanYou
-          @_=('ARRAY(0x83a8a90)'
-              ,'rot, rot, rot'
-              ,'Wikerson brothers'
-              ,'triculous tripe'
-              ,'There will be no more talking to hoos who are not!'
-              ,'black bottom birdie'
-              ,'from the three billionth flower'
-              ,'Mrs Tucanella returns with Wikerson uncles and cousins'
-              ,'sound off! sound off! come make yourself known!'
-              ,'Apartment 12J'
-              ,'Jo Jo the young lad'
-              ,'the whole world was saved by the tiny Yopp! of the smallest of all'
-                )
-
-
-=head3 Custom stringification subroutines
-
-The custom stringification subroutine expects one parameter, the
-exception to be stringified. It returns the stringified form of
-the exception. Here is an example of a fairly silly custom
-stringification routine that just prints out the chained messages
-without any stack trace:
-
-   $Exception::Lite::STRINGIFY = sub {
-      my $e=$_[0];    # exception is sole input parameter
-      my $sMsg='';
-      while ($e) {
-        $sMsg .= $e->getMessage() . "\n";
-        $e= $e->getChained();
-      }
-      return $sMsg;   # return string repreentation of message
-  };
-
-=head3 Adding information to the stack trace
-
-By default, each frame of the stack trace contains only the file,
-line, containing subroutine, and the state of C<@_> at the time
-C<$sFile>,C<$iLine> was reached.
-
-If your custom subroutine needs more information about the stack
-than C<Exception::Lite> normally provides, you can change the
-contents of the stack trace by assigning a custom filter routine
-to C<$Exception::Lite::FILTER>.
-
-The arguments to this subroutine are:
-
-
-   ($iFrame, $sFile, $iLine $sSub, $aArgs, $iSubFrame, $iLineFrame)
-
-where
-
-* C<$sFile> is the file of the current line in that frame
-
-* C<$iLine> is the line number of current line in that frame
-
-* C<$sSub> is the name of the subroutine that contains C<$sFile> and
-  C<$iLine>
-
-* C<$aArgs> is an array that holds the stringified value of each
-  member of @_ at the time the line at C<$sFile>, C<$sLine> was
-  called.  Usually, this is the parameters passed into C<$sSub>,
-  but may not be.
-
-* C<$iSubFrame> is the stack frame that provided the name of the sub
-  and the contents of $aArgs.
-
-* C<$iLineFrame> is the stack frame that provided the file and line
-  number for the frame.
-
-Please be aware that each line of the stack trace passed into the
-filter subroutine is a composite drawn from two different frames of
-the Perl stack trace, C<$iSubFrame> and C<$iLineFrame>.   This
-composition is necessary because the Perl stack trace contains the
-subroutine that was called at C<$sFile>, C<$iLine> rather than the
-subroutine that I<contains> C<$sFile>,C<$iLine>.
-
-The subroutine returns 0 or any other false value if the stack frame
-should be omitted. It returns to 1 accept the default stack frame as
-is.  If it accepts the stack frame but wants to insert extra data
-in the frame, it returns
-C<[$sFile,$iLine,$sSub,$aArgs, $extra1, $extra2, ...]>
-
-The extra data is always placed at the end after the C<$aArgs>
-member.
-
-=head3 Stack trace filtering
-
-To avoid noise, by default, intermediate frames that are associated
-with a block of code within a subroutine other than an anonymous
-sub (e.g. the frame created by C<eval {...} or do {...} >) are
-omitted from the stack trace.
-
-These omissions add to readability for most debugging purposes.
-In most cases one just wants to see which subroutine called which
-other subroutine.  Frames created by eval blocks don't provide
-useful information for that purpose and simply clutter up the
-debugging output.
-
-However, there are situations where one either wants more or less
-stack trace filtering.  Stack filtering can turned on or off or
-customized by setting C<$Exception::Lite::FILTER> to any of the
-following values:
-
-Normally the filtering rule is set at the start of the program or
-via the command line.   It can also be set anywhere in code, with one
-caveat: an error handling block.
-
-=over
-
-=item 0
-
-Turns all filtering off so that you see each and every frame
-in the stack trace.
-
-=item 1
-
-Turns on filtering of eval frames only (default)
-
-=item C<[ regex1, regex2, ... ]>
-
-A list of regexes. If the fully qualified subroutine name matches
-any one of these regular expressions it will be omitted from the
-stack trace.
-
-=item C<$regex>
-
-A single regular expression.  If the fully qualified subroutine name
-matches this regular expression, it will be omitted from the stack
-trace.
-
-=item C<$codeReference>
-
-The address of a named or anonymous routine that returns a boolean
-value: true if the frame should be includeed, false if it should be
-omitted. For parameters and return value of this subroutine see
-L</Adding information to the stack trace>.
-
-
-=back
-
-If filtering strategies change and an exception is chained, some of
-its stack frames might be lost during the chaining process if the
-filtering strategy that was in effect when the exception was
-generated changes before it is chained to another exception.
-
-
-=head2 Subclassing
-
-To declare a subclass with custom data and methods, use a three step
-process:
-
-=over
-
-=item *
-
-choose an exception superclass.  The choice of superclass follows
-the rule, "like gives birth to like".  Exception superclasses that
-have formats must have a superclass that also takes a format.
-Exception subclasses that have no format, must use an exception.
-
-=item *
-
-call C<declareExceptionClass> with its C<$bCustom> parameter set
-to 1
-
-=item *
-
-define a C<_new(...)> method (note the leading underscore _) and
-subclass specific methods in a  block that sets the package to
-the subclass package.
-
-=back
-
-
-When the C<$bCustom> flag is set to true, it might be best to think
-of C<declareExceptionClass> as something like C<use base> or
-C<use parent> except that there is no implicit BEGIN block. Like
-both these methods it handles all of the setup details for the
-class so that you can focus on defining methods and functionality.
-
-Wnen C<Exception::Lite> sees the C<$bCustom> flag set to true, it
-assumes you plan on customizing the class. It will set up inhertance,
-and generate all the usual method definition for an C<Exception::Lite>
-class. However, on account of C<$bCustom> being true, it will add a
-few extra things so that and your custom code can play nicely
-together:
-
-=over
-
-=item *
-
-a special hash reserved for your subclsses data. You can get
-access to this hash by calling C<_p_getSubclassData()>. You are
-free to add, change, or remove entries in the hash as needed.
-
-=item *
-
-at the end of its C<new()> method, it calls
-C<< $sClass->_new($self) >>. This is why you must define a C<_new()>
-method in your subclass package block. The C<_new> method is
-responsible for doing additional setup of exception data. Since
-this method is called last it can count on all of the normally
-expected methods and data having been set up, including the
-stack trace and the message generated by the classes format rule
-(if there is one).
-
-=back
-
-For example, suppose we want to define a subclass that accepts
-formats:
-
-  #define a superclass that accepts formats
-
-  declareExceptionClass('AnyError'
-    , ['Unexpected exception: %s','exception']);
-
-
-  # declare Exception subclass
-
-  declareExceptionClass('TimedException', 'AnyError', $aFormatData,1);
-  {
-     package TimedException;
-
-     sub _new {
-       my $self = $_[0];  #exception object created by Exception::Lite
-
-       # do additional setup of properties here
-       my $timestamp=time();
-       my $hMyData = $self->_p_getSubclassData();
-       $hMyData->{when} = time();
-    }
-
-    sub getWhen {
-       my $self=$_[0];
-       return $self->_p_getSubclassData()->{when};
-    }
-  }
-
-
-Now suppose we wish to extend our custom class further.  There is
-no difference in the way we do things just because it is a subclass
-of a customized C<Exception::Lite> class:
-
-  # extend TimedException further so that it
-  #
-  # - adds two additional bits of data - the effective gid and uid
-  #   at the time the exception was thrown
-  # - overrides getMessage() to include the time, egid, and euid
-
-  declareExceptionClass('SecureException', 'TimedException'
-                       , $aFormatData,1);
-  {
-     package TimedException;
-
-     sub _new {
-       my $self = $_[0];  #exception object created by Exception::Lite
-
-       # do additional setup of properties here
-       my $timestamp=time();
-       my $hMyData = $self->_p_getSubclassData();
-       $hMyData->{euid} = $>;
-       $hMyData->{egid} = $);
-    }
-
-    sub getEuid {
-       my $self=$_[0];
-       return $self->_p_getSubclassData()->{euid};
-    }
-    sub getEgid {
-       my $self=$_[0];
-       return $self->_p_getSubclassData()->{egid};
-    }
-    sub getMessage {
-       my $self=$_[0];
-       my $sMsg = $self->SUPER::getMessage();
-       return sprintf("%s at %s, euid=%s, guid=%s", $sMsg
-           , $self->getWhen(), $self->getEuid(), $self->getGuid());
-    }
-  }
-
-=head2 Converting other exceptions into Exception::Lite exceptions
-
-If you decide that you prefer the stack traces of this package, you
-can temporarily force all exceptions to use the C<Exception::Lite>
-stack trace, even those not generated by your own code.
-
-There are two ways to do this:
-
-* production code:  chaining/wrapping
-
-* active debugging: die/warn handlers
-
-
-=head3 Wrapping and chaining
-
-The preferred solution for production code is wrapping and/or
-chaining the exception.  Any non-string exception, even one
-of a class not created by C<Exception::Lite> can be chained
-to an C<Exception::Lite> exception.
-
-To chain a string exception, you first need to wrap it in
-an exception class.  For this purpose you can create a special
-purpose class or use the generic exception class provided by
-the C<Exception::Lite> module: C<Exception::Lite::Any>.
-
-If you don't want to chain the exception, you can also just
-rethrow the wrapped exception, as is.  Some examples:
-
-   #-----------------------------------------------------
-   # define some classes
-   #-----------------------------------------------------
-
-   # no format rule
-   declareExceptionClass('HouseholdRepairNeeded');
-
-   # format rule
-   declareExceptionClass('ProjectDelay'
-     , ['The project was delayed % days', qw(days)]);
-
-   #-----------------------------------------------------
-   # chain and/or wrap some exceptins
-   #-----------------------------------------------------
-
-   eval {
-     .... some code here ...
-     return 1;
-  } or do {
-
-    my $e=$@;
-    if (Exception::Lite::isChainable($e)) {
-      if ("$e" =~ /project/) {
-
-         # chain formatted message
-         die 'ProjectDelay'->new($e, days => 3);
-
-      } elsif ("$e" =~ /water pipe exploded/) {
-
-         # chain unformatted message
-         die 'HouseholdRepairNeeded'->new($e, 'Call the plumber');
-
-      }
-    } elsif ($e =~ 'repairman') {   #exception is a string
-
-       # wrapping a scalar exception so it has the stack trace
-       # up to this point, but _no_ chaining
-       #
-       # since the exception is a scalar, the constructor
-       # of a no-format exception class will treat the first
-       # parameter as a message rather than a chained exception
-
-       die 'HouseholdRepairNeeded'->new($e);
-
-    } else {
-
-       # if we do want to chain a string exception, we need to
-       # wrap it first in an exception class:
-
-       my $eWrapped = Exception::Lite::Any->new($e);
-       die 'HouseholdRepairNeeded'
-         ->new($eWrapped, "Call the repair guy");
-    }
-  }
-
-=head3 Die/Warn Handlers
-
-Die/Warn handlers provide a quick and dirty way to at Exception::Lite
-style stack traces to all warnings and exceptions.  However,
-it should ONLY BE USED DURING ACTIVE DEBUGGING.  They should never
-be used in production code. Setting these handlers
-can interfere with the debugging style and techiniques of other
-programmers and that is not nice.
-
-However, so long as you are actiely debugging, setting a die or
-warn handler can be quite useful, especially if a third party module
-is generating an exception or warning and you have no idea where it
-is coming from.
-
-To set a die handler, you pass your desired stringify level or
-code reference to C<onDie>:
-
-    Exception::Lite::onDie(4);
-
-This is roughly equivalent to:
-
-   $SIG{__DIE__} = sub {
-     $Exception::Lite::STRINGIFY=4;
-     warn 'Exception::Lite::Any'->new('Unexpected death:'.$_[0])
-       unless ($^S || Exception::Lite::isException($_[0]));
-   };
-
-To set a warning handler, you pass your desired stringify level or
-code reference to C<onWarn>:
-
-    Exception::Lite::onWarn(4);
-
-This is roughly equivalent to:
-
-  $SIG{__WARN__} = sub {
-    $Exception::Lite::STRINGIFY=4;
-    print STDERR 'Exception::Lite::Any'->new("Warning: $_[0]");
-  };
-
-Typically these handlers are placed at the top of a test script
-like this:
-
-  use strict;
-  use warnings;
-  use Test::More tests => 25;
-
-  use Exception::Lite;
-  Exception::Lite::onDie(4);
-  Exception::Lite::onWarn(3);
-
-  ... actual testing code here ...
-
-
-
-=head1 WHY A NEW EXCEPTION CLASS
-
-Aren't there enough already? Well, no.  This class differs from
-existing classes in several significant ways beyond "lite"-ness.
-
-=head2 Simplified integration of properties and messages
-
-C<Exception::Lite> simplifies the creation of exceptions by
-minimizing the amount of metadata that needs to be declared for
-each exception and by closely integrating exception properties
-and error messages.  Though there are many exception modules
-that let you define message and properties for exceptions, in
-those other modules you have to manually maintain any connection
-between the two either in your code or in a custom subclass.
-
-In L<Exception::Class|Exception::Class>, for example, you have to
-do something like this:
-
-     #... at the start of your code ...
-     # notice how exception definition and message format
-     # string constant are in two different places and need
-     # to be manually coordinated by the programmer.
-
-     use Exception::Class {
-       'Exception::Copy::Mine' {
-           fields => [qw(from to)];
-        }
-        # ... lots of other exceptions here ...
-     }
-     my $MSG_COPY='Could not copy A.txt to B.txt";
-
-     ... later on when you throw the exception ...
-
-     # notice the repetition in the use of exception
-     # properties; the repetition is error prone and adds
-     # unnecessary extra typing     
-
-     my $sMsg = sprintf($MSG_COPY, 'A.txt', 'B.txt');
-     Exception::Copy::Mine->throw(error => $sMsg
-                                  , from => 'A.txt'
-                                  , to => 'B.txt');
-
-
-C<Exception::Lite> provides a succinct and easy to maintain
-method of declaring those same exceptions
-
-    # the declaration puts the message format string and the
-    # class declaration together for the programmer, thus
-    # resulting in less maintenence work
-
-    declareExceptionClass("Exception::Mine::Copy"
-       , ["Could not copy %s to %s", qw(from, to) ]);
-
-
-    .... some where else in your code ...
-
-
-    # there is no need to explicitly call sprintf or
-    # repetitively type variable names, nor even remember
-    # the order of parameters in the format string or check
-    # for undefined values. Both of these will produce
-    # the same error message:
-    #   "Could not copy A.txt to B.txt"
-
-    die "Exception::Mine:Copy"->new(from =>'A.txt', to=>'B.txt');
-    die "Exception::Mine:Copy"->new(to =>'B.txt', from=>'A.txt');
-
-     # and this will politely fill in 'undef' for the
-     # property you leave out:
-     #    "Could not copy A.txt to <undef>"
-
-     die "Exception::Mine::Copy"->new(from=>'A.txt');
-
-
-=head2 More intelligent stack trace
-
-The vast majority, if not all, of the exception modules on CPAN
-essentially reproduce Carp's presentation of the stack trace. They
-sometimes provide parameters to control the level of detail, but
-make only minimal efforts, if any, to improve on the quality of
-debugging information.
-
-C<Exception::Lite> improves on the traditional Perl stack trace
-provided by Carp in a number of ways.
-
-=over
-
-=item *
-
-Error messages are shown in full and never truncated (a problem with
-  C<Carp::croak>.
-
-=item *
-
-The ability to see a list of what called what without the clutter
-  of subroutine parameters.
-
-=item *
-
-The ability to see the context of a line that fails rather than
-a pinhole snapshot of the line itself. Thus one sees
-"at file Foo.pm, line 13 in sub doTheFunkyFunk" rather
-  than the  contextless stack trace line displayed by nearly every,
-  if not all Perl stacktraces, including C<Carp::croak>:
-  "called foobar(...) at line 13 in Foo.pm".
-  When context rather than line snapshots
-  are provided, it is often enough simply to scan the list of what
-  called what to see where the error occurred.
-
-=item *
-
-Automatic filtering of stack frames that do not show the actual
-Flow from call to call.  Perl internally creates stack frames for
-each eval block.  Seeing these in the stack trace make it harder
-to scan the stack trace and see what called what.
-
-=item *
-
-The automatic filtering can be turned off or, alternatively
-customized to include/exclude arbitrary stack frames.
-
-=item *
-
-One can chain together exceptions and then print out what exception
-triggered what other exception.  Sometimes what a low level module
-considers important about an exception is not what a higher level
-module considers important. When that happens, the programmer can
-create a new exception with a more relevant error message that
-"remembers" the exception that inspired it. If need be, one can
-see the entire history from origin to destination.
-
-=back
-
-The "traditional" stack trace smushes together all parameters into
-a single long line that is very hard to read.  C<Exception::Lite>
-provides a much more readable parametr listing:
-
-=over
-
-=item *
-
-They are displayed one per line so that they can be easily read
-  and distinguished one from another
-
-=item *
-
-The string value <i>and</i> the normal object representation is
-  shown when an object's string conversion is overloaded. That way
-  there can be no confusion about whether the actual object or a
-  string was passed in as a parameter.
-
-=item *
-
-It doesn't pretend that these are the parameters passed to the
-  subroutine.  It is impossible to recreate the actual values in
-  the parameter list because the parameter list for any sub is
-  just C<@_> and that can be modified when a programmer uses shift
-  to process command line arguments. The most Perl can give (through
-  its DB module) is the way C<@_> looked at the time the next frame
-  in the stack was set up.  Instead of positioning the parameters
-  as if they were being passed to the subroutine, they are listed
-  below the stacktrace line saying "thrown at in line X in
-  subroutine Y".  In reality, the "parameters" are the value of
-  @_ passed to subroutine Y (or @ARGV if this is the entry point),
-  or what was left of it when we got to line X.
-
-=item
-
-A visual hint that leading C<undef>s in C<@_> or C<@ARGV> may be
-  the result of shifts rather than a heap of C<undef>s passed into
-  the subroutine.  This lets the programmer focus on the code, not
-  on remembering the quirks of Perl stack tracing.
-
-=back
-
-=head1 CLASS REFERENCE
-
-=head2 Class factory methods
-
-=head3 C<declareExceptionClass>
-
-   declareExceptionClass($sClass);
-   declareExceptionClass($sClass, $sSuperclass);
-   declareExceptionClass($sClass, $sSuperclass, $bCustom);
-
-   declareExceptionClass($sClass, $aFormatRule);
-   declareExceptionClass($sClass, $sSuperclass, $aFormatRule);
-   declareExceptionClass($sClass, $sSuperclass, $aFormatRule
-      , $bCustom);
-
-Generates a lightweight class definition for an exception class. It
-returns the name of the created class, i.e. $sClass.
-
-=over
-
-=item C<$sClass>
-
-The name of the class (package) to be created.  Required.
-
-Any legal Perl package name may be used, so long as it hasn't
-already been used to define an exception or any other class.
-
-=item C<$sSuperclass>
-
-The name of the superclass of C<$sClass>.  Optional.
-
-If missing or undefed, C<$sClass> will be be a base class
-whose only superclass is C<UNIVERSAL>, the root class of all Perl
-classes.  There is no special "Exception::Base" class that all
-exceptions have to descend from, unless you want it that way
-and choose to define your set of exception classes that way.
-
-=item C<$aFormatRule>
-
-An array reference describing how to use properties to construct
-a message. Optional.
-
-If provided, the format rule is essential the same parameters as
-used by sprintf with one major exception: instead of using actual
-values as arguments, you use property names, like this:
-
-    # insert value of 'from' property in place of first %s
-    # insert value of 'to' property in place of first %s
-
-    [ 'Cannot copy from %s to %s, 'from', 'to' ]
-
-When a format rule is provided, C<Exception::Lite> will auto-generate
-the message from the properties whenever the properties are set or
-changed. Regeneration is a lightweight process that selects property
-values from the hash and sends them to C<sprintf> for formatting.
-
-Later on, when you are creating exceptions, you simply pass in the
-property values. They can be listed in any order and extra properties
-that do not appear in the message string can also be provided. If
-for some reason the value of a property is unknown, you can assign it
-C<undef> and C<Exception::Lite> will politely insert a placeholder
-for the missing value.  All of the following are valid:
-
-
-    # These all generate "Cannot copy A.txt to B.txt"
-
-    $sClass->new(from => 'A.txt', to => 'B.txt');
-    $sClass->new(to => 'B.txt', from => 'A.txt');
-    $sClass->new(to => 'B.txt', from => 'A.txt'
-                 , reason => 'source doesn't exist'
-                 , seriousness => 4
-                );
-    $sClass->new(reason => 'source doesn't exist'
-                 , seriousness => 4
-                 , to => 'B.txt', from => 'A.txt'
-                );
-
-    # These generate "Cannot copy A.txt to <undef>"
-
-    $sClass->new(from => 'A.txt');
-    $sClass->new(from => 'A.txt', to => 'B.txt');
-
-=item C<$bCustom>
-
-True if the caller intends to add custom methods and/or a custom
-constructor to the newly declared class.  This will force the
-L<Excepton::Lite> to generate some extra methods and data so
-that the subclass can have its own private data area in the class.
-See L</Subclassing> for more information.
-
-
-=back
-
-=head2 Object construction methods
-
-=head3 C<new>
-
-    # class configured for no generation from properties
-
-    $sClass->new($sMsg);
-    $sClass->new($sMsg,$prop1 => $val1, ....);
-    $sClass->new($e);
-    $sClass->new($e, $sMsg);
-    $sClass->new($e, $sMsg,$prop1 => $val1, ....);
-
-    # class configured to generate messages from properties
-    # using a per-class format string
-
-    $sClass->new($prop1 => $val1, ....);
-    $sClass->new($e, $prop1 => $val1, ....);
-
-
-Creates a new instance of exception class C<$sClass>. The exception
-may be independent or chained to the exception that triggered it.
-
-=over
-
-=item $e
-
-The exception that logically triggered this new exception.
-May be omitted or left undefined.  If defined, the new exception is
-considered chained to C<$e>.
-
-=item $sMsg
-
-The message text, for classes with no autogeneration from properties,
-that is, classes declared like
-
-   declareExceptionClass($sClass);
-   declareExceptionClass($sClass, $sSuperclass);
-
-In the constructor, C< $sClass->new($e) >>, the message defaults to
-the message of C<$e>. Otherwise the message is required for any
-class that id declared in the above two ways.
-
-=item $prop1 => $val1
-
-The first property name and its associated value. There can be
-as many repetitions of this as there are properties.  All types
-of exception classes may have property lists.
-
-=back
-
-If you have chosen to have the message be completely independent
-of properties:
-
-   declareExceptionClass('A');
-
-   # unchained exception - print output "Hello"
-
-   my $e1 = A->new("Hello", importance => 'small', risk => 'large');
-   print "$e1\n";
-
-   # chained exception - print output "Hello"
-
-   my $e2 = A->new($e1,'Goodbye');
-
-   $e2->getChained();                      # returns $e1
-   print $e1->getMessage();                # outputs "Goodbye"
-   print $e1;                              # outputs "Goodbye"
-   print $e2->getChained()->getMessage();  # outputs "Hello"
-
-
-If you have chosen to have the message autogenerated from properties
-your call to C<new> will look like this:
-
-   $sFormat ='the importance is %s, but the risk is %s';
-   declareExceptionClass('B', [ $sFormat, qw(importance risk)]);
-
-
-   # unchained exception
-
-   my $e1 = B->new(importance=>'small', risk=>'large');
-
-   $e1->getChained();   # returns undef
-   print "$e1\n";       # outputs "The importance is small, but the
-                        #   risk is large"
-
-   # chained exception
-
-   $e2 = B->new($e1, importance=>'yink', risk=>'hooboy');
-   $e2->getChained();   # returns $e1
-   "$e2"                # evaluates to "The importance is yink, but
-                        # the risk is hooboy"
-   $e2->getMessage()                # same as "$e2"
-   $e2->getChained()->getMessage(); # same as "$e1"
-
-
-
-=head2 Object methods
-
-=head3 C<getMessage>
-
-   $e->getMessage();
-
-Returns the messsage, i.e. the value displayed when this exception
-is treated as a string.  This is the value without line numbers
-stack trace or other information.  It includes only the format
-string with the property values inserted.
-
-=head3 C<getProperty>
-
-   $e->getProperty($sName);
-
-Returns the property value for the C<$sName> property.
-
-=head3 C<isProperty>
-
-   $e->isProperty($sName)
-
-Returns true if the exception has the C<$sName> property, even if
-the value is undefined. (checks existance, not definition).
-
-=head3 C<getPid>
-
-   $e->getPid();
-
-Returns the process id of the process where the exception was
-thrown.
-
-=head3 C<getPackage>
-
-   $e->getPackage();
-
-Returns the package contining the entry point of the process, i.e.
-the package identified at the top of the stack.
-
-
-=head3 C<getTid>
-
-Returns the thread where the exception was thrown.
-
-   $e->getTid();
-
-=head3 C<getStackTrace>
-
-   $e->getStackTrace();
-
-Returns the stack trace from the point where the exception was
-thrown (frame 0) to the entry point (frame -1).  The stack trace
-is structured as an array of arrays (AoA) where each member array
-represents a single lightweight frame with four data per frame:
-
-   [0]  the file
-   [1]  the line number within the file
-   [2]  the subroutine where the exception was called. File and
-        line number will be within this subroutine.
-   [3]  a comma delimited string containing string representations
-        of the values that were stored in @_ at the time the
-        exception was thrown. If shift was used to process the
-        incoming subroutine arguments, @_ will usually contain
-        several leading undefs.
-
-For more information about each component of a stack frame, please
-see the documentation below for the following methods:
-
-* C<getFile>       - explains what to expect in [0] of stack frame
-
-* C<getLine>       - explains what to expect in [1] of stack frame
-
-* C<getSubroutine> - explains what to expect in [2] of stack frame
-
-* C<getArgs>       - explains what to expect in [3] of stack frame
-
-The frame closest to the thrown exception is numbered 0. In fact
-frame 0, stores information about the actual point where the exception
-was thrown.
-
-
-=head3 C<getFrameCount>
-
-   $e->getFrameCount();
-
-Returns the number of frames in the stack trace.
-
-=head3 C<getFile>
-
-   $e->getFile(0);    # gets frame where exception was thrown
-   $e->getFile(-1);   # gets entry point frame
-
-   $e->getFile();     # short hand for $e->getFile(0)
-   $e->getFile($i);
-
-Without an argument, this method returns the name of the file where
-the exception was thrown.  With an argument it returns the name of
-the file in the C<$i>th frame of the stack trace.
-
-Negative values of C<$i> will be counted from the entry point with
-C<-1> representing the entry point frame, C<-2> representing the
-first call made within the script and so on.
-
-=head3 C<getLine>
-
-   $e->getLine(0);    # gets frame where exception was thrown
-   $e->getLine(-1);   # gets entry point frame
-
-   $e->getLine();     # short hand for $e->getLine(0)
-   $e->getLine($i);
-
-Without an argument, this method returns the line number where the
-exception was thrown.  With an argument it returns the line number
-in the C<$i>th frame of the stack trace.
-
-Negative values of C<$i> will be counted from the entry point with
-C<-1> representing the entry point frame, C<-2> representing the
-first call made within the script and so on.
-
-=head3 C<getSubroutine>
-
-   $e->getSubroutine(0);    # gets frame where exception was thrown
-   $e->getSubroutine(-1);   # gets entry point frame
-
-   $e->getSubroutine();     # short hand for $e->getSubroutine(0)
-   $e->getSubroutine($i);
-
-Without an argument, this method returns the name of the subroutine
-where this exception was created via C<new(...)>.  With an argument
-it returns the value of the subroutine (or package entry point) in
-the C<$i>th frame of the stack trace.
-
-Negative values of C<$i> will be counted from the entry point with
-C<-1> representing the entry point frame, C<-2> representing the
-first call made within the script and so on.
-
-Note: This is not the same value as returned by C<caller($i)>. C<caller> returns the name of the subroutine that was being called
-at the time of death rather than the containing subroutine.
-
-The subroutine name in array element [2] includes the package name
-so it will be 'MyPackage::Utils::doit' and not just 'doit'. In the
-entry point frame there is, of course, no containing subroutine so
-the value in this string is instead the package name embedded in
-the string "<package: packageName>".
-
-
-=head3 C<getArgs>
-
-   $e->getArgs(0);    # gets frame where exception was thrown
-   $e->getArgs(-1);   # gets entry point frame
-
-   $e->getArgs();     # short hand for $e->getArgs(0)
-   $e->getArgs($i);
-
-Without an argument, this method returns the value of C<@_> (or
-C<@ARGV> for an entry point frame) at the time the exception was
-thrown.  With an argument it returns the name of
-the file in the C<$i>th frame of the stack trace.
-
-Negative values of C<$i> will be counted from the entry point with
-C<-1> representing the entry point frame, C<-2> representing the
-first call made within the script and so on.
-
- @_, is the best approximation Perl provides for the arguments
-used to call the subroutine.  At the start of the subroutine it does
-in fact reflect the parameters passed in, but frequently programmers
-will process this array with the C<shift> operator which will set
-leading arguments to C<undef>. The debugger does not cache the
-oiginal value of @_, so all you can get from its stack trace is the
-value at the time the exception was thrown, not the value when the
-subroutine was entered.
-
-=head3 C<getPropagation>
-
-   $e->getPropagation();
-
-Returns an array reference with one element for each time this
-exception was caught and rethrown using either Perl's own rethrow
-syntax C<$@=$e; die;> or this packages: C<< die->rethrow() >>.
-
-Each element of the array contains a file and line number where
-the exception was rethrown:
-
- [0]  file where exception was caught and rethrown
- [1]  line number where the exception was caught and rethrown
-
-Note: do not confuse the stack trace with propagation. The stack
-trace is the sequence of calls that were made I<before> the
-exception was thrown.  The propagation file and line numbers 
-refer to where the exception was caught in an exception handling
-block I<after> the exception was thrown.
-
-Generally, bad data is the reason behind an exception.  To see
-where the bad data came from, it is generally more useful to
-look at the stack and see what data was passed down to the point
-where the exception was generated than it is to look at where
-the exception was caught after the fact.
-
-=head3 C<getChained>
-
-   my $eChained = $e->getChained();
-
-Returns the chained exception, or undef if the exception is not
-chained.  Chained exceptions are created by inserting the triggering
-exception as the first parameter to C<new(...)>.
-
-  # class level format
-  MyException1->new(reason=>'blahblahblah');       #unchained
-  MyException1->new($e, reason=>'blahblahblah');   #chained
-
-  # no format string
-  MyException1->new('blahblahblah');               #unchained
-  MyException1->new($e, reason=>'blahblahblah');   #chained
-
-
-The chained exception can be a reference to any sort of data. It
-does not need to belong to the same class as the new exception,
-nor does it even have to belong to a class generated by
-C<Exception::Lite>. Its only restriction is that it may not be
-a scalar(string, number, ec).  To see if an exception
-may be chained you can call C<Exception::Lite::isChainable()>:
-
-   if (Exception::Lite::isChainable($e)) {
-      die MyException1->new($e, reason=>'blahblahblah');
-   } else {
-
-      # another alternative for string exceptions
-      my $eWrapper=MyWrapperForStringExceptions->new($e);
-      die MyException1->new($eWrapper, reason=>'blahblahblah');
-
-      # another alternative for string exceptions
-      die MyException1->new($eWrapper, reason=>"blahblahblah: $e");
-   }
-
-
-=head3 C<rethrow>
-
-   $e->rethrow();
-   $e->rethrow($prop => $newValue);         # format rule
-
-   $e->rethrow($newMsg, $p1 => $newValue);  # no format rule
-   $e->rethrow(undef, $pl => $newValue);    # no format rule
-   $e->rethrow($sNewMsg);                   # no format rule
-
-
-Propagates the exception using the method (C<PROPAGATE>) as would
-be called were one to use Perl's native 'rethrow' syntax,
-C<$@=$e; die>.
-
-The first form with no arguments simply rethrows the exception.
-The remain formats let one override property values and/or update
-the message. The argument list is the same as for C<new> except
-that exceptions with no or object level format strings may have
-an undefined message.
-
-For class format exceptions, the message will automatically be
-updated if any of the properties used to construct it have changed.
-
-For exception classes with no formatting, property and message
-changes are independent of each other. If C<$sMsg> is set to C<undef>
-the properties will be changed and the message will be left alone.
-If C<$sMsg> is provided, but no override properties are provided,
-the message will change but the properties will be left untouched.
-
-=head3 C<_p_getSubclassData>
-
-Method for internal use by custom subclasses. This method retrieves
-the data hash reserved for use by custom methods.
-
-
-=head1 SEE ALSO
-
-=head2 Canned test modules
-
-Test modules for making sure your code generates the right
-exceptions.  They work with any OOP solution, even C<Exception::Lite>
-
-* L<Test::Exception|Test::Exception>  - works with any OOP solution
-
-* L<Test::Exception::LessClever|Test::Exception::LessClever> - works
-  with any OOP solution
-
-=head2 Alternate OOP solutions
-
-=head3 L<Exception::Class|Exception::Class>
-
-This module has a fair number of non-core modules. There are several
-extension modules. Most are adapter classes that convert exceptions
-produced by popular CPAN modules into Exception::Class modules:
-
-* L<Exception::Class::Nested|Exception::Class::Nested> - changes
-  the syntax for declaring exceptions.
-
-* L<MooseX::Error::Exception::Class|MooseX::Error::Exception::Class>
-  - converts Moose exceptions to
-  C<Exception::Class> instances.
-
-* L<HTTP::Exception|HTTP::Exception>  - wrapper around HTTP exceptions
-
-* L<Mail::Log::Exceptions|Mail::Log::Exceptions> - wrapper around
-  Mail::Log exceptions
-
-* L<Exception::Class::DBI|Exception::Class::DBI> - wrapper around
-  DBI exceptions
-
-* L<Error::Exception|Error::Exception> - prints out exception
-  properties as part of exception stringification.
-
-It takes a heavy approach to OOP, requiring all properties to be
-predeclared.  It also stores a lot of information about an exception,
-not all of which is likely to be important to the average user, e.g.
-pid, uid, guid and even the entire stack trace.
-
-There is no support for auto-generating messages based on
-properties.
-
-For an extended discussion of C<Exception::Class>, see
-L<http://www.drdobbs.com/web-development/184416129>.
-
-=head3 L<Exception::Base|Exception::Base>
-
-A light weight version of L<Exception::Class|Exception::Class>.
-Uses only core modules but is fairly new and has no significant
-eco-system of extensions (yet).
-Like C<Exception::Class> properties must be explicitly declared and
-there is no support for autogenerating messages based on properties.
-
-
-=head3 L<Class::Throwable|Class::Throwable>
-
-Another light weight version of L<Exception::Class|Exception::Class>.
-Unlike C<Exception::Class> you can control the amount of system
-state and stack trace information stored at the time an exception
-is generated.
-
-=head2 Syntactic sugar solutions
-
-Syntactical sugar solutions allow java like try/catch blocks to
-replace the more awkward C<die>, C<eval/do>, and C<$@=$e; die>
-pattern. Take care in chosing these methods as they sometimes
-use coding strategies known to cause problems:
-
-=over
-
-=item *
-
-overriding signal handlers - possible interference with your own
-code or third party module use of those handlers.
-
-=item *
-
-source code filtering - can shift line numbers so that the reported
-line number and the actual line number may not be the same.
-
-=item *
-
-closures - there is a apparently a problem with nested closures
-causing memory leaks in some versions of Perl (pre 5.8.4). This
-has been since fixed since 5.8.4.
-
-=back
-
-Modules providing syntactic sugar include:
-
-* L<Try::Catch|Try::Catch>
-
-* L<Try::Tiny|Try::Tiny>
-
-* C<Error|Error>
-
-* L<Exception::Caught|Exception::Caught>
-
-* L<Exception::SEH|Exception::SEH>
-
-* C<Exception|Exception>
-
-* L<Exception::Class::TryCatch|Exception::Class::TryCatch> - extension of L<Exception::Class|Exception::Class>
-
-* L<Exception::Class::TCF|Exception::Class::TCF> - extension of L<Exception::Class|Exception::Class>
-
-
-=head1 EXPORTS
-
-No subroutines are exported by default. See the start of the synopsis
-for optional exports.
-
-
-=head1 AUTHOR
-
-Elizabeth Grace Frank-Backman
-
-=head1 COPYRIGHT
-
-Copyright (c) 2011 Elizabeth Grace Frank-Backman.
-All rights reserved.
-
-=head1 LICENSE
-
-This program is free software; you can redistribute it and/or
-modify it under the same terms as Perl itself.
diff --git a/modules/fallback/Set/Crontab.pm b/modules/fallback/Set/Crontab.pm
deleted file mode 100644 (file)
index 033d20d..0000000
+++ /dev/null
@@ -1,160 +0,0 @@
-# Copyright 2001 Abhijit Menon-Sen <ams@toroid.org>
-
-package Set::Crontab;
-
-use strict;
-use Carp;
-use vars qw( $VERSION );
-
-$VERSION = '1.03';
-
-sub _expand
-{
-    my (@list, @and, @not);
-    my ($self, $spec, $range) = @_;
-
-    # 1,2-4,*/3,!13,>9,<15
-    foreach (split /,/, $spec) {
-        my @pick;
-        my $step = $1 if s#/(\d+)$##;
-
-        # 0+"01" == 1
-        if    (/^(\d+)$/)       { push @pick, 0+$1;          }
-        elsif (/^\*$/)          { push @pick, @$range;       }
-        elsif (/^(\d+)-(\d+)$/) { push @pick, 0+$1..0+$2;    } 
-        elsif (/^!(\d+)$/)      { push @not,  "\$_ != 0+$1"; }
-        elsif (/^([<>])(\d+)$/) { push @and,  "\$_ $1 0+$2"; }
-
-        if ($step) {
-            my $i;
-            @pick = grep { defined $_ if $i++ % $step == 0 } @pick;
-        }
-
-        push @list, @pick;
-    }
-
-    if (@and) {
-        my $and = join q{ && }, @and;
-        push @list, grep { defined $_ if eval $and } @$range;
-    }
-
-    if (@not) {
-        my $not = join q{ && }, @not;
-        @list = grep { defined $_ if eval $not } (@list ? @list : @$range);
-    }
-
-    @list = sort { $a <=> $b } @list;
-    return \@list;
-}
-
-sub _initialise
-{
-    my ($self, $spec, $range) = @_;
-    return undef unless ref($self);
-
-    croak "Usage: ".__PACKAGE__."->new(\$spec, [\@range])"
-        unless defined $spec && ref($range) eq "ARRAY";
-
-    $self->{LIST} = $self->_expand($spec, $range);
-    $self->{HASH} = {map {$_ => 1} @{$self->{LIST}}};
-
-    return $self;
-};
-
-sub new
-{
-    my $class = shift;
-    my $self  = bless {}, ref($class) || $class;
-    return $self->_initialise(@_);
-}
-
-sub contains
-{
-    my ($self, $num) = @_;
-
-    croak "Usage: \$set->contains(\$num)" unless ref($self) && defined $num;
-    return exists $self->{HASH}{$num};
-}
-
-sub list
-{
-    my $self = shift;
-
-    croak "Usage: \$set->list()" unless ref($self);
-    return @{$self->{LIST}};
-}
-
-1;
-__END__
-
-=head1 NAME
-
-Set::Crontab - Expand crontab(5)-style integer lists
-
-=head1 SYNOPSIS
-
-$s = Set::Crontab->new("1-9/3,>15,>30,!23", [0..30]);
-
-if ($s->contains(3)) { ... }
-
-=head1 DESCRIPTION
-
-Set::Crontab parses crontab-style lists of integers and defines some
-utility functions to make it easier to deal with them.
-
-=head2 Syntax
-
-Numbers, ranges, *, and step values all work exactly as described in
-L<crontab(5)>. A few extensions to the standard syntax are described
-below.
-
-=over 4
-
-=item < and >
-
-<N selects the elements smaller than N from the entire range, and adds
-them to the set. >N does likewise for elements larger than N.
-
-=item !
-
-!N excludes N from the set. It applies to the other specified 
-range; otherwise it applies to the specified ranges (i.e. "!3" with a
-range of "1-10" corresponds to "1-2,4-10", but ">3,!7" in the same range
-means "4-6,8-10").
-
-=back
-
-=head2 Functions
-
-=over 4
-
-=item new($spec, [@range])
-
-Creates a new Set::Crontab object and returns a reference to it.
-
-=item contains($num)
-
-Returns true if C<$num> exists in the set.
-
-=item list()
-
-Returns the expanded list corresponding to the set. Elements are in
-ascending order.
-
-=back
-
-The functions described above croak if they are called with incorrect
-arguments.
-
-=head1 SEE ALSO
-
-L<crontab(5)>
-
-=head1 AUTHOR
-
-Abhijit Menon-Sen <ams@toroid.org>
-
-Copyright 2001 Abhijit Menon-Sen <ams@toroid.org>
-
-This module is free software; you can redistribute it and/or modify it
-under the same terms as Perl itself.
diff --git a/modules/fallback/Sort/Naturally.pm b/modules/fallback/Sort/Naturally.pm
deleted file mode 100644 (file)
index a62af08..0000000
+++ /dev/null
@@ -1,812 +0,0 @@
-
-require 5;
-package Sort::Naturally;  # Time-stamp: "2004-12-29 18:30:03 AST"
-$VERSION = '1.02';
-@EXPORT = ('nsort', 'ncmp');
-require Exporter;
-@ISA = ('Exporter');
-
-use strict;
-use locale;
-use integer;
-
-#-----------------------------------------------------------------------------
-# constants:
-BEGIN { *DEBUG = sub () {0} unless defined &DEBUG }
-
-use Config ();
-BEGIN {
-  # Make a constant such that if a whole-number string is that long
-  #  or shorter, we KNOW it's treatable as an integer
-  no integer;
-  my $x = length(256 ** $Config::Config{'intsize'} / 2) - 1;
-  die "Crazy intsize: <$Config::Config{'intsize'}>" if $x < 4;
-  eval 'sub MAX_INT_SIZE () {' . $x . '}';
-  die $@ if $@;
-  print "intsize $Config::Config{'intsize'} => MAX_INT_SIZE $x\n" if DEBUG;
-}
-
-sub X_FIRST () {-1}
-sub Y_FIRST () { 1}
-
-my @ORD = ('same', 'swap', 'asis');
-
-#-----------------------------------------------------------------------------
-# For lack of a preprocessor:
-
-my($code, $guts);
-$guts = <<'EOGUTS';  # This is the guts of both ncmp and nsort:
-
-    if($x eq $y) {
-      # trap this expensive case first, and then fall thru to tiebreaker
-      $rv = 0;
-
-    # Convoluted hack to get numerics to sort first, at string start:
-    } elsif($x =~ m/^\d/s) {
-      if($y =~ m/^\d/s) {
-        $rv = 0;    # fall thru to normal comparison for the two numbers
-      } else {
-        $rv = X_FIRST;
-        DEBUG > 1 and print "Numeric-initial $x trumps letter-initial $y\n";
-      }
-    } elsif($y =~ m/^\d/s) {
-      $rv = Y_FIRST;
-      DEBUG > 1 and print "Numeric-initial $y trumps letter-initial $x\n";
-    } else {
-      $rv = 0;
-    }
-    
-    unless($rv) {
-      # Normal case:
-      $rv = 0;
-      DEBUG and print "<$x> and <$y> compared...\n";
-      
-     Consideration:
-      while(length $x and length $y) {
-      
-        DEBUG > 2 and print " <$x> and <$y>...\n";
-        
-        # First, non-numeric comparison:
-        $x2 = ($x =~ m/^(\D+)/s) ? length($1) : 0;
-        $y2 = ($y =~ m/^(\D+)/s) ? length($1) : 0;
-        # Now make x2 the min length of the two:
-        $x2 = $y2 if $x2 > $y2;
-        if($x2) {
-          DEBUG > 1 and printf " <%s> and <%s> lexically for length $x2...\n", 
-            substr($x,0,$x2), substr($y,0,$x2);
-          do {
-           my $i = substr($x,0,$x2);
-           my $j = substr($y,0,$x2);
-           my $sv = $i cmp $j;
-           print "SCREAM! on <$i><$j> -- $sv != $rv \n" unless $rv == $sv;
-           last;
-          }
-          
-          
-           if $rv =
-           # The ''. things here force a copy that seems to work around a 
-           #  mysterious intermittent bug that 'use locale' provokes in
-           #  many versions of Perl.
-                   $cmp
-                   ? $cmp->(substr($x,0,$x2) . '',
-                            substr($y,0,$x2) . '',
-                           )
-                   :
-                   scalar(( substr($x,0,$x2) . '' ) cmp
-                          ( substr($y,0,$x2) . '' )
-                          )
-          ;
-          # otherwise trim and keep going:
-          substr($x,0,$x2) = '';
-          substr($y,0,$x2) = '';
-        }
-        
-        # Now numeric:
-        #  (actually just using $x2 and $y2 as scratch)
-
-        if( $x =~ s/^(\d+)//s ) {
-          $x2 = $1;
-          if( $y =~ s/^(\d+)//s ) {
-            # We have two numbers here.
-            DEBUG > 1 and print " <$x2> and <$1> numerically\n";
-            if(length($x2) < MAX_INT_SIZE and length($1) < MAX_INT_SIZE) {
-              # small numbers: we can compare happily
-              last if $rv = $x2 <=> $1;
-            } else {
-              # ARBITRARILY large integers!
-              
-              # This saves on loss of precision that could happen
-              #  with actual stringification.
-              # Also, I sense that very large numbers aren't too
-              #  terribly common in sort data.
-              
-              # trim leading 0's:
-              ($y2 = $1) =~ s/^0+//s;
-              $x2 =~ s/^0+//s;
-              print "   Treating $x2 and $y2 as bigint\n" if DEBUG;
-
-              no locale; # we want the dumb cmp back.
-              last if $rv = (
-                 # works only for non-negative whole numbers:
-                 length($x2) <=> length($y2)
-                   # the longer the numeral, the larger the value
-                 or $x2 cmp $y2
-                   # between equals, compare lexically!!  amazing but true.
-              );
-            }
-          } else {
-            # X is numeric but Y isn't
-            $rv = Y_FIRST;
-            last;
-          }        
-        } elsif( $y =~ s/^\d+//s ) {  # we don't need to capture the substring
-          $rv = X_FIRST;
-          last;
-        }
-         # else one of them is 0-length.
-
-       # end-while
-      }
-    }
-EOGUTS
-
-sub maker {
-  my $code = $_[0];
-  $code =~ s/~COMPARATOR~/$guts/g || die "Can't find ~COMPARATOR~";
-  eval $code;
-  die $@ if $@;
-}
-
-##############################################################################
-
-maker(<<'EONSORT');
-sub nsort {
-  # get options:
-  my($cmp, $lc);
-  ($cmp,$lc) = @{shift @_} if @_ and ref($_[0]) eq 'ARRAY';
-
-  return @_ unless @_ > 1 or wantarray; # be clever
-  
-  my($x, $x2, $y, $y2, $rv);  # scratch vars
-
-  # We use a Schwartzian xform to memoize the lc'ing and \W-removal
-
-  map $_->[0],
-  sort {
-    if($a->[0] eq $b->[0]) { 0 }   # trap this expensive case
-    else {
-    
-    $x = $a->[1];
-    $y = $b->[1];
-
-~COMPARATOR~
-
-    # Tiebreakers...
-    DEBUG > 1 and print " -<${$a}[0]> cmp <${$b}[0]> is $rv ($ORD[$rv])\n";
-    $rv ||= (length($x) <=> length($y))  # shorter is always first
-        ||  ($cmp and $cmp->($x,$y) || $cmp->($a->[0], $b->[0]))
-        ||  ($x      cmp $y     )
-        ||  ($a->[0] cmp $b->[0])
-    ;
-    
-    DEBUG > 1 and print "  <${$a}[0]> cmp <${$b}[0]> is $rv ($ORD[$rv])\n";
-    $rv;
-  }}
-
-  map {;
-    $x = $lc ? $lc->($_) : lc($_); # x as scratch
-    $x =~ s/\W+//s;
-    [$_, $x];
-  }
-  @_
-}
-EONSORT
-
-#-----------------------------------------------------------------------------
-maker(<<'EONCMP');
-sub ncmp {
-  # The guts are basically the same as above...
-
-  # get options:
-  my($cmp, $lc);
-  ($cmp,$lc) = @{shift @_} if @_ and ref($_[0]) eq 'ARRAY';
-
-  if(@_ == 0) {
-    @_ = ($a, $b); # bit of a hack!
-    DEBUG > 1 and print "Hacking in <$a><$b>\n";
-  } elsif(@_ != 2) {
-    require Carp;
-    Carp::croak("Not enough options to ncmp!");
-  }
-  my($a,$b) = @_;
-  my($x, $x2, $y, $y2, $rv);  # scratch vars
-  
-  DEBUG > 1 and print "ncmp args <$a><$b>\n";
-  if($a eq $b) { # trap this expensive case
-    0;
-  } else {
-    $x = ($lc ? $lc->($a) : lc($a));
-    $x =~ s/\W+//s;
-    $y = ($lc ? $lc->($b) : lc($b));
-    $y =~ s/\W+//s;
-    
-~COMPARATOR~
-
-
-    # Tiebreakers...
-    DEBUG > 1 and print " -<$a> cmp <$b> is $rv ($ORD[$rv])\n";
-    $rv ||= (length($x) <=> length($y))  # shorter is always first
-        ||  ($cmp and $cmp->($x,$y) || $cmp->($a,$b))
-        ||  ($x cmp $y)
-        ||  ($a cmp $b)
-    ;
-    
-    DEBUG > 1 and print "  <$a> cmp <$b> is $rv\n";
-    $rv;
-  }
-}
-EONCMP
-
-# clean up:
-undef $guts;
-undef &maker;
-
-#-----------------------------------------------------------------------------
-1;
-
-############### END OF MAIN SOURCE ###########################################
-__END__
-
-=head1 NAME
-
-Sort::Naturally -- sort lexically, but sort numeral parts numerically
-
-=head1 SYNOPSIS
-
-  @them = nsort(qw(
-   foo12a foo12z foo13a foo 14 9x foo12 fooa foolio Foolio Foo12a
-  ));
-  print join(' ', @them), "\n";
-
-Prints:
-
-  9x 14 foo fooa foolio Foolio foo12 foo12a Foo12a foo12z foo13a
-
-(Or "foo12a" + "Foo12a" and "foolio" + "Foolio" and might be
-switched, depending on your locale.)
-
-=head1 DESCRIPTION
-
-This module exports two functions, C<nsort> and C<ncmp>; they are used
-in implementing my idea of a "natural sorting" algorithm.  Under natural
-sorting, numeric substrings are compared numerically, and other
-word-characters are compared lexically.
-
-This is the way I define natural sorting:
-
-=over
-
-=item *
-
-Non-numeric word-character substrings are sorted lexically,
-case-insensitively: "Foo" comes between "fish" and "fowl".
-
-=item *
-
-Numeric substrings are sorted numerically:
-"100" comes after "20", not before.
-
-=item *
-
-\W substrings (neither words-characters nor digits) are I<ignored>.
-
-=item *
-
-Our use of \w, \d, \D, and \W is locale-sensitive:  Sort::Naturally
-uses a C<use locale> statement.
-
-=item *
-
-When comparing two strings, where a numeric substring in one
-place is I<not> up against a numeric substring in another,
-the non-numeric always comes first.  This is fudged by
-reading pretending that the lack of a number substring has
-the value -1, like so:
-
-  foo       =>  "foo",  -1
-  foobar    =>  "foo",  -1,  "bar"
-  foo13     =>  "foo",  13,
-  foo13xyz  =>  "foo",  13,  "xyz"
-
-That's so that "foo" will come before "foo13", which will come
-before "foobar".
-
-=item *
-
-The start of a string is exceptional: leading non-\W (non-word,
-non-digit)
-components are are ignored, and numbers come I<before> letters.
-
-=item *
-
-I define "numeric substring" just as sequences matching m/\d+/ --
-scientific notation, commas, decimals, etc., are not seen.  If
-your data has thousands separators in numbers
-("20,000 Leagues Under The Sea" or "20.000 lieues sous les mers"),
-consider stripping them before feeding them to C<nsort> or
-C<ncmp>.
-
-=back
-
-=head2 The nsort function
-
-This function takes a list of strings, and returns a copy of the list,
-sorted.
-
-This is what most people will want to use:
-
-  @stuff = nsort(...list...);
-
-When nsort needs to compare non-numeric substrings, it
-uses Perl's C<lc> function in scope of a <use locale>.
-And when nsort needs to lowercase things, it uses Perl's
-C<lc> function in scope of a <use locale>.  If you want nsort
-to use other functions instead, you can specify them in
-an arrayref as the first argument to nsort:
-
-  @stuff = nsort( [
-                    \&string_comparator,   # optional
-                    \&lowercaser_function  # optional
-                  ],
-                  ...list...
-                );
-
-If you want to specify a string comparator but no lowercaser,
-then the options list is C<[\&comparator, '']> or
-C<[\&comparator]>.  If you want to specify no string comparator
-but a lowercaser, then the options list is
-C<['', \&lowercaser]>.
-
-Any comparator you specify is called as
-C<$comparator-E<gt>($left, $right)>,
-and, like a normal Perl C<cmp> replacement, must return
--1, 0, or 1 depending on whether the left argument is stringwise
-less than, equal to, or greater than the right argument.
-
-Any lowercaser function you specify is called as
-C<$lowercased = $lowercaser-E<gt>($original)>.  The routine
-must not modify its C<$_[0]>.
-
-=head2 The ncmp function
-
-Often, when sorting non-string values like this:
-
-   @objects_sorted = sort { $a->tag cmp $b->tag } @objects;
-
-...or even in a Schwartzian transform, like this:
-
-   @strings =
-     map $_->[0]
-     sort { $a->[1] cmp $b->[1] }
-     map { [$_, make_a_sort_key_from($_) ]
-     @_
-   ;
-   
-...you wight want something that replaces not C<sort>, but C<cmp>.
-That's what Sort::Naturally's C<ncmp> function is for.  Call it with
-the syntax C<ncmp($left,$right)> instead of C<$left cmp $right>,
-but otherwise it's a fine replacement:
-
-   @objects_sorted = sort { ncmp($a->tag,$b->tag) } @objects;
-
-   @strings =
-     map $_->[0]
-     sort { ncmp($a->[1], $b->[1]) }
-     map { [$_, make_a_sort_key_from($_) ]
-     @_
-   ;
-
-Just as with C<nsort> can take different a string-comparator
-and/or lowercaser, you can do the same with C<ncmp>, by passing
-an arrayref as the first argument:
-
-  ncmp( [
-          \&string_comparator,   # optional
-          \&lowercaser_function  # optional
-        ],
-        $left, $right
-      )
-
-You might get string comparators from L<Sort::ArbBiLex|Sort::ArbBiLex>.
-
-=head1 NOTES
-
-=over
-
-=item *
-
-This module is not a substitute for
-L<Sort::Versions|Sort::Versions>!  If
-you just need proper version sorting, use I<that!>
-
-=item *
-
-If you need something that works I<sort of> like this module's
-functions, but not quite the same, consider scouting thru this
-module's source code, and adapting what you see.  Besides
-the functions that actually compile in this module, after the POD,
-there's several alternate attempts of mine at natural sorting
-routines, which are not compiled as part of the module, but which you
-might find useful.  They should all be I<working> implementations of
-slightly different algorithms
-(all of them based on Martin Pool's C<nsort>) which I eventually
-discarded in favor of my algorithm.  If you are having to
-naturally-sort I<very large> data sets, and sorting is getting
-ridiculously slow, you might consider trying one of those
-discarded functions -- I have a feeling they might be faster on
-large data sets.  Benchmark them on your data and see.  (Unless
-you I<need> the speed, don't bother.  Hint: substitute C<sort>
-for C<nsort> in your code, and unless your program speeds up
-drastically, it's not the sorting that's slowing things down.
-But if it I<is> C<nsort> that's slowing things down, consider
-just:
-
-      if(@set >= SOME_VERY_BIG_NUMBER) {
-        no locale; # vroom vroom
-        @sorted = sort(@set);  # feh, good enough
-      } elsif(@set >= SOME_BIG_NUMBER) {
-        use locale;
-        @sorted = sort(@set);  # feh, good enough
-      } else {
-        # but keep it pretty for normal cases
-        @sorted = nsort(@set);
-      }
-
-=item *
-
-If you do adapt the routines in this module, email me; I'd
-just be interested in hearing about it.
-
-=item *
-
-Thanks to the EFNet #perl people for encouraging this module,
-especially magister and a-mused.
-
-=back
-
-=head1 COPYRIGHT AND DISCLAIMER
-
-Copyright 2001, Sean M. Burke C<sburke@cpan.org>, all rights
-reserved.  This program is free software; you can redistribute it
-and/or modify it under the same terms as Perl itself.
-
-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.
-
-=head1 AUTHOR
-
-Sean M. Burke C<sburke@cpan.org>
-
-=cut
-
-############   END OF DOCS   ############
-
-############################################################################
-############################################################################
-
-############ BEGIN OLD STUFF ############
-
-# We can't have "use integer;", or else (5 <=> 5.1) comes out "0" !
-
-#-----------------------------------------------------------------------------
-sub nsort {
-  my($cmp, $lc);
-  return @_ if @_ < 2;   # Just to be CLEVER.
-  
-  my($x, $i);  # scratch vars
-  
-  # And now, the GREAT BIG Schwartzian transform:
-  
-  map
-    $_->[0],
-
-  sort {
-    # Uses $i as the index variable, $x as the result.
-    $x = 0;
-    $i = 1;
-    DEBUG and print "\nComparing ", map("{$_}", @$a),
-                 ' : ', map("{$_}", @$b), , "...\n";
-
-    while($i < @$a and $i < @$b) {
-      DEBUG and print "  comparing $i: {$a->[$i]} cmp {$b->[$i]} => ",
-        $a->[$i] cmp $b->[$i], "\n";
-      last if ($x = ($a->[$i] cmp $b->[$i])); # lexicographic
-      ++$i;
-
-      DEBUG and print "  comparing $i: {$a->[$i]} <=> {$b->[$i]} => ",
-        $a->[$i] <=> $b->[$i], "\n";
-      last if ($x = ($a->[$i] <=> $b->[$i])); # numeric
-      ++$i;
-    }
-
-    DEBUG and print "{$a->[0]} : {$b->[0]} is ",
-      $x || (@$a <=> @$b) || 0
-      ,"\n"
-    ;
-    $x || (@$a <=> @$b) || ($a->[0] cmp $b->[0]);
-      # unless we found a result for $x in the while loop,
-      #  use length as a tiebreaker, otherwise use cmp
-      #  on the original string as a fallback tiebreaker.
-  }
-
-  map {
-    my @bit = ($x = defined($_) ? $_ : '');
-    
-    if($x =~ m/^[+-]?(?=\d|\.\d)\d*(?:\.\d*)?(?:[Ee](?:[+-]?\d+))?\z/s) {
-      # It's entirely purely numeric, so treat it specially:
-      push @bit, '', $x;
-    } else {
-      # Consume the string.
-      while(length $x) {
-        push @bit, ($x =~ s/^(\D+)//s) ? lc($1) : '';
-        push @bit, ($x =~ s/^(\d+)//s) ?    $1  :  0;
-      }
-    }
-    DEBUG and print "$bit[0] => ", map("{$_} ", @bit), "\n";
-
-    # End result: [original bit         , (text, number), (text, number), ...]
-    # Minimally:  [0-length original bit,]
-    # Examples:
-    #    ['10'         => ''   ,  10,              ]
-    #    ['fo900'      => 'fo' , 900,              ]
-    #    ['foo10'      => 'foo',  10,              ]
-    #    ['foo9.pl'    => 'foo',   9,   , '.pl', 0 ]
-    #    ['foo32.pl'   => 'foo',  32,   , '.pl', 0 ]
-    #    ['foo325.pl'  => 'foo', 325,   , '.pl', 0 ]
-    #  Yes, always an ODD number of elements.
-    
-    \@bit;
-  }
-  @_;
-}
-
-#-----------------------------------------------------------------------------
-# Same as before, except without the pure-number trap.
-
-sub nsorts {
-  return @_ if @_ < 2;   # Just to be CLEVER.
-  
-  my($x, $i);  # scratch vars
-  
-  # And now, the GREAT BIG Schwartzian transform:
-  
-  map
-    $_->[0],
-
-  sort {
-    # Uses $i as the index variable, $x as the result.
-    $x = 0;
-    $i = 1;
-    DEBUG and print "\nComparing ", map("{$_}", @$a),
-                 ' : ', map("{$_}", @$b), , "...\n";
-
-    while($i < @$a and $i < @$b) {
-      DEBUG and print "  comparing $i: {$a->[$i]} cmp {$b->[$i]} => ",
-        $a->[$i] cmp $b->[$i], "\n";
-      last if ($x = ($a->[$i] cmp $b->[$i])); # lexicographic
-      ++$i;
-
-      DEBUG and print "  comparing $i: {$a->[$i]} <=> {$b->[$i]} => ",
-        $a->[$i] <=> $b->[$i], "\n";
-      last if ($x = ($a->[$i] <=> $b->[$i])); # numeric
-      ++$i;
-    }
-
-    DEBUG and print "{$a->[0]} : {$b->[0]} is ",
-      $x || (@$a <=> @$b) || 0
-      ,"\n"
-    ;
-    $x || (@$a <=> @$b) || ($a->[0] cmp $b->[0]);
-      # unless we found a result for $x in the while loop,
-      #  use length as a tiebreaker, otherwise use cmp
-      #  on the original string as a fallback tiebreaker.
-  }
-
-  map {
-    my @bit = ($x = defined($_) ? $_ : '');
-    
-    while(length $x) {
-      push @bit, ($x =~ s/^(\D+)//s) ? lc($1) : '';
-      push @bit, ($x =~ s/^(\d+)//s) ?    $1  :  0;
-    }
-    DEBUG and print "$bit[0] => ", map("{$_} ", @bit), "\n";
-
-    # End result: [original bit         , (text, number), (text, number), ...]
-    # Minimally:  [0-length original bit,]
-    # Examples:
-    #    ['10'         => ''   ,  10,              ]
-    #    ['fo900'      => 'fo' , 900,              ]
-    #    ['foo10'      => 'foo',  10,              ]
-    #    ['foo9.pl'    => 'foo',   9,   , '.pl', 0 ]
-    #    ['foo32.pl'   => 'foo',  32,   , '.pl', 0 ]
-    #    ['foo325.pl'  => 'foo', 325,   , '.pl', 0 ]
-    #  Yes, always an ODD number of elements.
-    
-    \@bit;
-  }
-  @_;
-}
-
-#-----------------------------------------------------------------------------
-# Same as before, except for the sort-key-making
-
-sub nsort0 {
-  return @_ if @_ < 2;   # Just to be CLEVER.
-  
-  my($x, $i);  # scratch vars
-  
-  # And now, the GREAT BIG Schwartzian transform:
-  
-  map
-    $_->[0],
-
-  sort {
-    # Uses $i as the index variable, $x as the result.
-    $x = 0;
-    $i = 1;
-    DEBUG and print "\nComparing ", map("{$_}", @$a),
-                 ' : ', map("{$_}", @$b), , "...\n";
-
-    while($i < @$a and $i < @$b) {
-      DEBUG and print "  comparing $i: {$a->[$i]} cmp {$b->[$i]} => ",
-        $a->[$i] cmp $b->[$i], "\n";
-      last if ($x = ($a->[$i] cmp $b->[$i])); # lexicographic
-      ++$i;
-
-      DEBUG and print "  comparing $i: {$a->[$i]} <=> {$b->[$i]} => ",
-        $a->[$i] <=> $b->[$i], "\n";
-      last if ($x = ($a->[$i] <=> $b->[$i])); # numeric
-      ++$i;
-    }
-
-    DEBUG and print "{$a->[0]} : {$b->[0]} is ",
-      $x || (@$a <=> @$b) || 0
-      ,"\n"
-    ;
-    $x || (@$a <=> @$b) || ($a->[0] cmp $b->[0]);
-      # unless we found a result for $x in the while loop,
-      #  use length as a tiebreaker, otherwise use cmp
-      #  on the original string as a fallback tiebreaker.
-  }
-
-  map {
-    my @bit = ($x = defined($_) ? $_ : '');
-    
-    if($x =~ m/^[+-]?(?=\d|\.\d)\d*(?:\.\d*)?(?:[Ee](?:[+-]?\d+))?\z/s) {
-      # It's entirely purely numeric, so treat it specially:
-      push @bit, '', $x;
-    } else {
-      # Consume the string.
-      while(length $x) {
-        push @bit, ($x =~ s/^(\D+)//s) ? lc($1) : '';
-        # Secret sauce:
-        if($x =~ s/^(\d+)//s) {
-          if(substr($1,0,1) eq '0' and $1 != 0) {
-            push @bit, $1 / (10 ** length($1));
-          } else {
-            push @bit, $1;
-          }
-        } else {
-          push @bit, 0;
-        }
-      }
-    }
-    DEBUG and print "$bit[0] => ", map("{$_} ", @bit), "\n";
-    
-    \@bit;
-  }
-  @_;
-}
-
-#-----------------------------------------------------------------------------
-# Like nsort0, but WITHOUT pure number handling, and WITH special treatment
-# of pulling off extensions and version numbers.
-
-sub nsortf {
-  return @_ if @_ < 2;   # Just to be CLEVER.
-  
-  my($x, $i);  # scratch vars
-  
-  # And now, the GREAT BIG Schwartzian transform:
-  
-  map
-    $_->[0],
-
-  sort {
-    # Uses $i as the index variable, $x as the result.
-    $x = 0;
-    $i = 3;
-    DEBUG and print "\nComparing ", map("{$_}", @$a),
-                 ' : ', map("{$_}", @$b), , "...\n";
-
-    while($i < @$a and $i < @$b) {
-      DEBUG and print "  comparing $i: {$a->[$i]} cmp {$b->[$i]} => ",
-        $a->[$i] cmp $b->[$i], "\n";
-      last if ($x = ($a->[$i] cmp $b->[$i])); # lexicographic
-      ++$i;
-
-      DEBUG and print "  comparing $i: {$a->[$i]} <=> {$b->[$i]} => ",
-        $a->[$i] <=> $b->[$i], "\n";
-      last if ($x = ($a->[$i] <=> $b->[$i])); # numeric
-      ++$i;
-    }
-
-    DEBUG and print "{$a->[0]} : {$b->[0]} is ",
-      $x || (@$a <=> @$b) || 0
-      ,"\n"
-    ;
-    $x || (@$a     <=> @$b    ) || ($a->[1] cmp $b->[1])
-       || ($a->[2] <=> $b->[2]) || ($a->[0] cmp $b->[0]);
-      # unless we found a result for $x in the while loop,
-      #  use length as a tiebreaker, otherwise use the 
-      #  lc'd extension, otherwise the verison, otherwise use
-      #  the original string as a fallback tiebreaker.
-  }
-
-  map {
-    my @bit = ( ($x = defined($_) ? $_ : ''), '',0 );
-    
-    {
-      # Consume the string.
-      
-      # First, pull off any VAX-style version
-      $bit[2] = $1 if $x =~ s/;(\d+)$//;
-      
-      # Then pull off any apparent extension
-      if( $x !~ m/^\.+$/s and     # don't mangle ".", "..", or "..."
-          $x =~ s/(\.[^\.\;]*)$//sg
-          # We could try to avoid catching all-digit extensions,
-          #  but I think that's getting /too/ clever.
-      ) {
-        $i = $1;
-        if($x =~ m<[^\\\://]$>s) {
-          # We didn't take the whole basename.
-          $bit[1] = lc $i;
-          DEBUG and print "Consuming extension \"$1\"\n";
-        } else {
-          # We DID take the whole basename.  Fix it.
-          $x = $1;  # Repair it.
-        }
-      }
-
-      push @bit, '', -1   if $x =~ m/^\./s;
-       # A hack to make .-initial filenames sort first, regardless of locale.
-       # And -1 is always a sort-firster, since in the code below, there's
-       # no allowance for filenames containing negative numbers: -1.dat
-       # will be read as string '-' followed by number 1.
-
-      while(length $x) {
-        push @bit, ($x =~ s/^(\D+)//s) ? lc($1) : '';
-        # Secret sauce:
-        if($x =~ s/^(\d+)//s) {
-          if(substr($1,0,1) eq '0' and $1 != 0) {
-            push @bit, $1 / (10 ** length($1));
-          } else {
-            push @bit, $1;
-          }
-        } else {
-          push @bit, 0;
-        }
-      }
-    }
-    
-    DEBUG and print "$bit[0] => ", map("{$_} ", @bit), "\n";
-    
-    \@bit;
-  }
-  @_;
-}
-
-# yowza yowza yowza.
-
diff --git a/modules/override/Devel/REPL/Plugin/AutoloadModules.pm b/modules/override/Devel/REPL/Plugin/AutoloadModules.pm
deleted file mode 100644 (file)
index e36ee96..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-package Devel::REPL::Plugin::AutoloadModules;
-
-use Moose::Role;
-use namespace::clean -except => [ 'meta' ];
-use Data::Dumper;
-
-has 'autoloaded' => ( is => 'rw', isa => 'HashRef', default => sub { {} } );
-
-my $re = qr/Runtime error: Can.t locate object method "\w+" via package "\w+" \(perhaps you forgot to load "(\w+)"\?\)/;
-around 'execute' => sub {
-  my $orig = shift;
-  my $self = shift;
-
-  my @re = $self->$orig(@_);                           # original call
-
-  return @re unless defined $re[0] && $re[0] =~ /$re/; # if there is no "perhaps you forgot" error, just return
-  my $module = $1;                                     # save the missing package name
-
-  return @re if $self->autoloaded->{$module};          # if we tried to load it before, give up and return the error
-
-  $self->autoloaded->{$module} = 1;                    # make sure we don't try this again
-  $self->eval("use SL::$module");                      # try to load the missing module
-
-  @re = $self->$orig(@_);                              # try again
-
-  return @re;
-};
-
-1;
diff --git a/modules/override/Devel/REPL/Plugin/PermanentHistory.pm b/modules/override/Devel/REPL/Plugin/PermanentHistory.pm
deleted file mode 100644 (file)
index 3a46b56..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-package Devel::REPL::Plugin::PermanentHistory;
-
-use Moose::Role;
-use namespace::clean -except => [ 'meta' ];
-use File::Slurp;
-use Data::Dumper;
-
-has 'history_file' => ( is => 'rw' );
-
-sub load_history {
-  my $self = shift;
-  my $file = shift;
-
-  $self->history_file( $file );
-
-  return unless $self->history_file && -f $self->history_file;
-
-  my @history =
-    map { chomp; $_ }
-    read_file($self->history_file);
-#  print  Dumper(\@history);
-  $self->history( \@history );
-  $self->term->addhistory($_) for @history;
-}
-
-before 'DESTROY' => sub {
-  my $self = shift;
-
-  return unless $self->history_file;
-
-  write_file $self->history_file,
-    map { $_, $/ }
-    grep $_,
-    grep { !/^quit\b/ }
-    @{ $self->history };
-};
-
-1;
-
old mode 100644 (file)
new mode 100755 (executable)
index 5934fcb..602c887
@@ -1,11 +1,16 @@
-package PDF::Table;
+#!/usr/bin/env perl
+# vim: softtabstop=4 tabstop=4 shiftwidth=4 ft=perl expandtab smarttab
 
 use 5.006;
 use strict;
 use warnings;
+
+package PDF::Table;
+
 use Carp;
 use List::Util qw(sum);
-our $VERSION = '0.9.10';
+
+our $VERSION = '0.10.1';
 
 print __PACKAGE__.' is version: '.$VERSION.$/ if($ENV{'PDF_TABLE_DEBUG'});
 
@@ -36,7 +41,7 @@ sub _init
 {
     my ($self, $pdf, $page, $data, %options ) = @_;
 
-    # Check and set default values 
+    # Check and set default values
     $self->set_defaults();
 
     # Check and set mandatory params
@@ -49,9 +54,9 @@ sub _init
 }
 
 sub set_defaults{
-       my $self = shift;
-       
-       $self->{'font_size'} = 12;
+    my $self = shift;
+
+    $self->{'font_size'} = 12;
 }
 
 sub set_pdf{
@@ -98,9 +103,9 @@ sub text_block
     my $text        = shift;    # The text to be displayed
     my %arg         = @_;       # Additional Arguments
 
-    my  ( $align, $xpos, $ypos, $xbase, $ybase, $line_width, $wordspace, $endw , $width, $height) = 
+    my  ( $align, $xpos, $ypos, $xbase, $ybase, $line_width, $wordspace, $endw , $width, $height) =
         ( undef , undef, undef, undef , undef , undef      , undef     , undef , undef , undef  );
-    my @line        = ();       # Temp data array with words on one line 
+    my @line        = ();       # Temp data array with words on one line
     my %width       = ();       # The width of every unique word in the givven text
 
     # Try to provide backward compatibility
@@ -143,7 +148,7 @@ sub text_block
     # Calculate width of all words
     my $space_width = $text_object->advancewidth("\x20");
     my @words = split(/\s+/, $text);
-    foreach (@words) 
+    foreach (@words)
     {
         next if exists $width{$_};
         $width{$_} = $text_object->advancewidth($_);
@@ -157,12 +162,12 @@ sub text_block
     $xpos = $xbase;
     $ypos = $ybase;
     $ypos = $ybase + $line_space;
-    my $bottom_border = $ypos - $height; 
+    my $bottom_border = $ypos - $height;
     # While we can add another line
-    while ( $ypos >= $bottom_border + $line_space ) 
+    while ( $ypos >= $bottom_border + $line_space )
     {
         # Is there any text to render ?
-        unless (@paragraph) 
+        unless (@paragraph)
         {
             # Finish if nothing left
             last unless scalar @paragraphs;
@@ -178,34 +183,34 @@ sub text_block
         # While there's room on the line, add another word
         @line = ();
         $line_width = 0;
-        if( $first_line && exists $arg{'hang'} ) 
+        if( $first_line && exists $arg{'hang'} )
         {
             my $hang_width = $text_object->advancewidth($arg{'hang'});
-    
+
             $text_object->translate( $xpos, $ypos );
             $text_object->text( $arg{'hang'} );
-    
+
             $xpos         += $hang_width;
             $line_width   += $hang_width;
             $arg{'indent'} += $hang_width if $first_paragraph;
         }
-        elsif( $first_line && exists $arg{'flindent'} && $arg{'flindent'} > 0 ) 
+        elsif( $first_line && exists $arg{'flindent'} && $arg{'flindent'} > 0 )
         {
             $xpos += $arg{'flindent'};
             $line_width += $arg{'flindent'};
         }
-        elsif( $first_paragraph && exists $arg{'fpindent'} && $arg{'fpindent'} > 0 ) 
+        elsif( $first_paragraph && exists $arg{'fpindent'} && $arg{'fpindent'} > 0 )
         {
             $xpos += $arg{'fpindent'};
             $line_width += $arg{'fpindent'};
         }
-        elsif (exists $arg{'indent'} && $arg{'indent'} > 0 ) 
+        elsif (exists $arg{'indent'} && $arg{'indent'} > 0 )
         {
             $xpos += $arg{'indent'};
             $line_width += $arg{'indent'};
         }
-    
-        # Lets take from paragraph as many words as we can put into $width - $indent; 
+
+        # Lets take from paragraph as many words as we can put into $width - $indent;
         # Always take at least one word; otherwise we'd end up in an infinite loop.
         while ( !scalar(@line) || (
           @paragraph && (
@@ -216,43 +221,43 @@ sub text_block
             push(@line, shift(@paragraph));
         }
         $line_width += $text_object->advancewidth(join('', @line));
-            
+
         # calculate the space width
-        if( $arg{'align'} eq 'fulljustify' or ($arg{'align'} eq 'justify' and @paragraph)) 
+        if( $arg{'align'} eq 'fulljustify' or ($arg{'align'} eq 'justify' and @paragraph))
         {
             @line = split(//,$line[0]) if (scalar(@line) == 1) ;
             $wordspace = ($width - $line_width) / (scalar(@line) - 1);
             $align='justify';
-        } 
-        else 
+        }
+        else
         {
             $align=($arg{'align'} eq 'justify') ? 'left' : $arg{'align'};
             $wordspace = $space_width;
         }
         $line_width += $wordspace * (scalar(@line) - 1);
-    
-        if( $align eq 'justify') 
+
+        if( $align eq 'justify')
         {
-            foreach my $word (@line) 
+            foreach my $word (@line)
             {
                 $text_object->translate( $xpos, $ypos );
                 $text_object->text( $word );
                 $xpos += ($width{$word} + $wordspace) if (@line);
             }
             $endw = $width;
-        } 
-        else 
+        }
+        else
         {
             # calculate the left hand position of the line
-            if( $align eq 'right' ) 
+            if( $align eq 'right' )
             {
                 $xpos += $width - $line_width;
-            } 
-            elsif( $align eq 'center' ) 
+            }
+            elsif( $align eq 'center' )
             {
                 $xpos += ( $width / 2 ) - ( $line_width / 2 );
             }
-    
+
             # render the line
             $text_object->translate( $xpos, $ypos );
             $endw = $text_object->text( join("\x20", @line));
@@ -292,7 +297,7 @@ sub table
 
     # Validate settings key
     my %valid_settings_key = (
-       x                     => 1,
+        x                     => 1,
         w                     => 1,
         start_y               => 1,
         start_h               => 1,
@@ -313,8 +318,10 @@ sub table
         vertical_borders      => 1,
         font                  => 1,
         font_size             => 1,
+        font_underline        => 1,
         font_color            => 1,
         font_color_even       => 1,
+        font_color_odd        => 1,
         background_color_odd  => 1,
         background_color_even => 1,
         row_height            => 1,
@@ -323,35 +330,31 @@ sub table
         column_props          => 1,
         cell_props            => 1,
         max_word_length       => 1,
+        cell_render_hook      => 1,
+        default_text          => 1,
         num_header_rows       => 1,
     );
-    foreach my $key (keys %arg) {
-       croak "Error: Invalid setting key '$key' received." 
-            unless (exists $valid_settings_key{$key});
-    }
-
-    # Try to provide backward compatibility
     foreach my $key (keys %arg)
     {
-        my $newkey = $key;
-        if($newkey =~ s#^-##)
-        {
-            $arg{$newkey} = $arg{$key};
-            delete $arg{$key};
-        }
+        # Provide backward compatibility
+        $arg{$key} = delete $arg{"-$key"} if $key =~ s/^-//;
+
+        croak "Error: Invalid setting key '$key' received."
+            unless exists $valid_settings_key{$key};
     }
-    
+
+
     ######
     #TODO: Add code for header props compatibility and col_props comp....
     ######
     my ( $xbase, $ybase, $width, $height ) = ( undef, undef, undef, undef );
     # Could be 'int' or 'real' values
-    $xbase  = $arg{'x'      } || -1;    
+    $xbase  = $arg{'x'      } || -1;
     $ybase  = $arg{'start_y'} || -1;
     $width  = $arg{'w'      } || -1;
     $height = $arg{'start_h'} || -1;
 
-    # Global geometry parameters are also mandatory. 
+    # Global geometry parameters are also mandatory.
     unless( $xbase  > 0 ){ carp "Error: Left Edge of Table is NOT defined!\n";  return; }
     unless( $ybase  > 0 ){ carp "Error: Base Line of Table is NOT defined!\n"; return; }
     unless( $width  > 0 ){ carp "Error: Width of Table is NOT defined!\n";  return; }
@@ -365,9 +368,10 @@ sub table
     my $txt     = $page->text;
 
     # Set Default Properties
-    my $fnt_name    = $arg{'font'            } || $pdf->corefont('Times',-encode => 'utf8');
-    my $fnt_size    = $arg{'font_size'       } || 12;
-    my $max_word_len= $arg{'max_word_length' } || 20;
+    my $fnt_name       = $arg{'font'            } || $pdf->corefont('Times',-encode => 'utf8');
+    my $fnt_size       = $arg{'font_size'       } || 12;
+    my $fnt_underline  = $arg{'font_underline'  } || undef; # merely stating undef is the intended default
+    my $max_word_len   = $arg{'max_word_length' } || 20;
 
     #=====================================
     # Table Header Section
@@ -386,6 +390,7 @@ sub table
         $header_props->{'font'          } = $header_props->{'font'          } || $fnt_name;
         $header_props->{'font_color'    } = $header_props->{'font_color'    } || '#000066';
         $header_props->{'font_size'     } = $header_props->{'font_size'     } || $fnt_size + 2;
+        $header_props->{'font_underline'} = $header_props->{'font_underline'} || $fnt_underline;
         $header_props->{'bg_color'      } = $header_props->{'bg_color'      } || '#FFFFAA';
         $header_props->{'justify'       } = $header_props->{'justify'       };
         $header_props->{num_header_rows } = $arg{num_header_rows } || 1;
@@ -398,6 +403,7 @@ sub table
     my $pad_right     = $arg{'padding_right' } || $arg{'padding'} || 0;
     my $pad_top       = $arg{'padding_top'   } || $arg{'padding'} || 0;
     my $pad_bot       = $arg{'padding_bottom'} || $arg{'padding'} || 0;
+    my $default_text  = $arg{'default_text'  } // '-';
     my $line_w        = defined $arg{'border'} ? $arg{'border'} : 1 ;
     my $horiz_borders = defined $arg{'horizontal_borders'}
         ? $arg{'horizontal_borders'}
@@ -405,7 +411,7 @@ sub table
     my $vert_borders  = defined $arg{'vertical_borders'}
         ? $arg{'vertical_borders'}
         : $line_w;
-    
+
     my $background_color_even   = $arg{'background_color_even'  } || $arg{'background_color'} || undef;
     my $background_color_odd    = $arg{'background_color_odd'   } || $arg{'background_color'} || undef;
     my $font_color_even         = $arg{'font_color_even'        } || $arg{'font_color'      } || 'black';
@@ -413,10 +419,10 @@ sub table
     my $border_color            = $arg{'border_color'           } || 'black';
 
     my $min_row_h   = $fnt_size + $pad_top + $pad_bot;
-    my $row_h       = defined ($arg{'row_height'}) 
-                                && 
-                    ($arg{'row_height'} > $min_row_h) 
-                                ? 
+    my $row_h       = defined ($arg{'row_height'})
+                                &&
+                    ($arg{'row_height'} > $min_row_h)
+                                ?
                      $arg{'row_height'} : $min_row_h;
 
     my $pg_cnt      = 1;
@@ -437,22 +443,23 @@ sub table
     }
     # Determine column widths based on content
 
-    #  an arrayref whose values are a hashref holding 
+    #  an arrayref whose values are a hashref holding
     #  the minimum and maximum width of that column
     my $col_props =  $arg{'column_props'} || [];
 
-    # An array ref of arrayrefs whose values are 
+    # An array ref of arrayrefs whose values are
     #  the actual widths of the column/row intersection
     my $row_col_widths = [];
-    # An array ref with the widths of the header row 
+    # An array ref with the widths of the header row
     my @header_row_widths;
-    # Scalars that hold sum of the maximum and minimum widths of all columns 
+
+    # Scalars that hold sum of the maximum and minimum widths of all columns
     my ( $max_col_w  , $min_col_w   ) = ( 0,0 );
-    my ( $row, $col_name, $col_fnt_size, $space_w );
+    my ( $row, $col_name, $col_fnt_size, $col_fnt_underline, $space_w );
 
     my $word_widths  = {};
     my $rows_height  = [];
+    my $first_row    = 1;
 
     for( my $row_idx = 0; $row_idx < scalar(@$data) ; $row_idx++ )
     {
@@ -461,33 +468,40 @@ sub table
         my $column_widths = []; #holds the width of each column
         # Init the height for this row
         $rows_height->[$row_idx] = 0;
-        
+
         for( my $column_idx = 0; $column_idx < scalar(@{$data->[$row_idx]}) ; $column_idx++ )
         {
             # look for font information for this column
-            my ($cell_font, $cell_font_size);
-            
+            my ($cell_font, $cell_font_size, $cell_font_underline);
+
             if( !$row_idx and ref $header_props )
-            {   
-                $cell_font      = $header_props->{'font'};
-                $cell_font_size = $header_props->{'font_size'};
+            {
+                $cell_font           = $header_props->{'font'};
+                $cell_font_size      = $header_props->{'font_size'};
+                $cell_font_underline = $header_props->{'font_underline'};
             }
-            
+
             # Get the most specific value if none was already set from header_props
-            $cell_font      ||= $cell_props->[$row_idx][$column_idx]->{'font'} 
+            $cell_font      ||= $cell_props->[$row_idx][$column_idx]->{'font'}
                             ||  $col_props->[$column_idx]->{'font'}
                             ||  $fnt_name;
-                              
+
             $cell_font_size ||= $cell_props->[$row_idx][$column_idx]->{'font_size'}
                             ||  $col_props->[$column_idx]->{'font_size'}
                             ||  $fnt_size;
-                              
+
+            $cell_font_underline ||= $cell_props->[$row_idx][$column_idx]->{'font_underline'}
+                                 ||  $col_props->[$column_idx]->{'font_underline'}
+                                 ||  $fnt_underline;
+
+            # Set Font
+
             # Set Font
-            $txt->font( $cell_font, $cell_font_size ); 
-            
+            $txt->font( $cell_font, $cell_font_size );
+
             # Set row height to biggest font size from row's cells
             if( $cell_font_size  > $rows_height->[$row_idx] )
-            {   
+            {
                 $rows_height->[$row_idx] = $cell_font_size;
             }
 
@@ -509,18 +523,18 @@ sub table
 
             my @words = split( /\s+/, $data->[$row_idx][$column_idx] );
 
-            foreach( @words ) 
+            foreach( @words )
             {
                 unless( exists $word_widths->{$_} )
                 {   # Calculate the width of every word and add the space width to it
                     $word_widths->{$_} = $txt->advancewidth( $_ ) + $space_w;
                 }
-                
+
                 $column_widths->[$column_idx] += $word_widths->{$_};
                 $min_col_w                     = $word_widths->{$_} if( $word_widths->{$_} > $min_col_w );
                 $max_col_w                    += $word_widths->{$_};
             }
-            
+
             $min_col_w                    += $pad_left + $pad_right;
             $max_col_w                    += $pad_left + $pad_right;
             $column_widths->[$column_idx] += $pad_left + $pad_right;
@@ -533,23 +547,23 @@ sub table
             {   # Calculated Minimum Column Width is more than user-defined
                 $col_props->[$column_idx]->{'min_w'} = $min_col_w ;
             }
-            
+
             if( $max_col_w > $col_props->[$column_idx]->{'max_w'} )
             {   # Calculated Maximum Column Width is more than user-defined
                 $col_props->[$column_idx]->{'max_w'} = $max_col_w ;
             }
         }#End of for(my $column_idx....
-        
+
         $row_col_widths->[$row_idx] = $column_widths;
-        
-        # Copy the calculated row properties of header row. 
+
+        # Copy the calculated row properties of header row.
         if (ref $header_props && $row_idx < $header_props->{num_header_rows}) {
           push @header_row_widths, [ @{ $column_widths } ];
         }
     }
 
     # Calc real column widths and expand table width if needed.
-    my $calc_column_widths; 
+    my $calc_column_widths;
     ($calc_column_widths, $width) = CalcColumnWidths( $col_props, $width );
     my $num_cols = scalar @{ $calc_column_widths };
 
@@ -565,46 +579,56 @@ sub table
     # Each iteration adds a new page as neccessary
     while(scalar(@{$data}))
     {
-        my ($page_header, $columns_number);
+        my ($page_header);
+        my $columns_number = 0;
 
         if($pg_cnt == 1)
         {
             $table_top_y = $ybase;
             $bot_marg = $table_top_y - $height;
+
+            # Check for safety reasons
+            if( $bot_marg < 0 )
+            {   # This warning should remain i think
+                #carp "!!! Warning: !!! Incorrect Table Geometry! start_h (${height}) is above start_y (${table_top_y}). Setting bottom margin to end of sheet!\n";
+                $bot_marg = 0;
+            }
+
         }
         else
         {
             if(ref $arg{'new_page_func'})
-            {   
-                $page = &{$arg{'new_page_func'}};   
+            {
+                $page = &{$arg{'new_page_func'}};
             }
             else
-            {   
-                $page = $pdf->page; 
+            {
+                $page = $pdf->page;
             }
-    
+
             $table_top_y = $next_y;
             $bot_marg = $table_top_y - $next_h;
 
+            # Check for safety reasons
+            if( $bot_marg < 0 )
+            {   # This warning should remain i think
+                #carp "!!! Warning: !!! Incorrect Table Geometry! next_y or start_y (${next_y}) is above next_h or start_h (${next_h}). Setting bottom margin to end of sheet!\n";
+                $bot_marg = 0;
+            }
+
             if( ref $header_props and $header_props->{'repeat'})
             {
                 unshift @$data,           @header_rows;
                 unshift @$row_col_widths, @header_row_widths;
                 unshift @$rows_height,    @header_row_heights;
                 $remaining_header_rows = $header_props->{num_header_rows};
+                $first_row = 1;
             }
         }
 
-        # Check for safety reasons
-        if( $bot_marg < 0 )
-        {   # This warning should remain i think
-#            carp "!!! Warning: !!! Incorrect Table Geometry! Setting bottom margin to end of sheet!\n";
-            $bot_marg = 0;
-        }
-
         $gfx_bg = $page->gfx;
         $txt = $page->text;
-        $txt->font($fnt_name, $fnt_size); 
+        $txt->font($fnt_name, $fnt_size);
 
         $cur_y = $table_top_y;
 
@@ -615,7 +639,7 @@ sub table
             $gfx->linewidth($line_w);
 
             # Draw the top line
-            if ($horiz_borders) 
+            if ($horiz_borders)
             {
                 $gfx->move( $xbase , $cur_y );
                 $gfx->hline($xbase + $width );
@@ -626,17 +650,17 @@ sub table
             $gfx = undef;
         }
 
-        # Each iteration adds a row to the current page until the page is full 
+        # Each iteration adds a row to the current page until the page is full
         #  or there are no more rows to add
         # Row_Loop
         while(scalar(@{$data}) and $cur_y-$row_h > $bot_marg)
         {
             # Remove the next item from $data
             my $record = shift @{$data};
-            
-            # Get columns number to know later how many vertical lines to draw
-            # TODO: get the max number of columns per page as currently last row's columns overrides
-            $columns_number = scalar(@$record);
+
+            # Get max columns number to know later how many vertical lines to draw
+            $columns_number = scalar(@$record)
+                if scalar(@$record) > $columns_number;
 
             # Get the next set of row related settings
             # Row Height
@@ -651,7 +675,7 @@ sub table
 
             # Added to resolve infite loop bug with returned undef values
             for(my $d = 0; $d < scalar(@{$record}) ; $d++)
-            { 
+            {
                 $record->[$d] = ' ' unless( defined $record->[$d]);
             }
 
@@ -678,45 +702,56 @@ sub table
             my ($colspan, @vertical_lines);
 
             # Process every cell(column) from current row
-            for( my $column_idx = 0; $column_idx < scalar( @$record); $column_idx++ ) 
+            for( my $column_idx = 0; $column_idx < scalar( @$record); $column_idx++ )
             {
                 next unless $col_props->[$column_idx]->{'max_w'};
-                next unless $col_props->[$column_idx]->{'min_w'};  
+                next unless $col_props->[$column_idx]->{'min_w'};
                 $leftovers->[$column_idx] = undef;
 
                 # look for font information for this cell
-                my ($cell_font, $cell_font_size, $cell_font_color, $justify);
-                                    
+                my ($cell_font, $cell_font_size, $cell_font_color, $cell_font_underline, $justify);
+
                 if( $remaining_header_rows and ref $header_props)
-                {   
-                    $cell_font       = $header_props->{'font'};
-                    $cell_font_size  = $header_props->{'font_size'};
-                    $cell_font_color = $header_props->{'font_color'};
-                    $justify         = $header_props->{'justify'};
+                {
+                    $cell_font           = $header_props->{'font'};
+                    $cell_font_size      = $header_props->{'font_size'};
+                    $cell_font_color     = $header_props->{'font_color'};
+                    $cell_font_underline = $header_props->{'font_underline'};
+                    $justify             = $header_props->{'justify'};
                 }
-                
+
                 # Get the most specific value if none was already set from header_props
-                $cell_font       ||= $cell_props->[$row_index][$column_idx]->{'font'} 
+                $cell_font       ||= $cell_props->[$row_index][$column_idx]->{'font'}
                                  ||  $col_props->[$column_idx]->{'font'}
                                  ||  $fnt_name;
-                                  
+
                 $cell_font_size  ||= $cell_props->[$row_index][$column_idx]->{'font_size'}
                                  ||  $col_props->[$column_idx]->{'font_size'}
                                  ||  $fnt_size;
-                                  
+
                 $cell_font_color ||= $cell_props->[$row_index][$column_idx]->{'font_color'}
                                  ||  $col_props->[$column_idx]->{'font_color'}
                                  ||  $font_color;
-                                
+
+                $cell_font_underline ||= $cell_props->[$row_index][$column_idx]->{'font_underline'}
+                                     ||  $col_props->[$column_idx]->{'font_underline'}
+                                     ||  $fnt_underline;
+
+
                 $justify         ||= $cell_props->[$row_index][$column_idx]->{'justify'}
                                  ||  $col_props->[$column_idx]->{'justify'}
                                  ||  $arg{'justify'}
-                                 ||  'left';                                    
-                
+                                 ||  'left';
+
                 # Init cell font object
                 $txt->font( $cell_font, $cell_font_size );
                 $txt->fillcolor($cell_font_color);
 
+                # Added to resolve infite loop bug with returned undef values
+                $record->[$column_idx] //= $cell_props->[$row_index][$column_idx]->{'default_text'}
+                                       //  $col_props->[$column_idx]->{'default_text'}
+                                       //  $default_text;
+
                 my $this_width;
                 if (!$remaining_header_rows && $cell_props->[$row_index + $header_props->{num_header_rows}][$column_idx]->{colspan}) {
                     $colspan = $cell_props->[$row_index + $header_props->{num_header_rows}][$column_idx]->{colspan};
@@ -731,10 +766,10 @@ sub table
                 } else {
                     $this_width = $calc_column_widths->[$column_idx];
                 }
+
                 # If the content is wider than the specified width, we need to add the text as a text block
                 if( $record->[$column_idx] !~ m/(.\n.)/ and
-                    $record_widths->[$column_idx] and 
+                    $record_widths->[$column_idx] and
                     $record_widths->[$column_idx] <= $this_width
                 ){
                     my $space = $pad_left;
@@ -747,7 +782,9 @@ sub table
                         $space = ($this_width - $txt->advancewidth($record->[$column_idx])) / 2;
                     }
                     $txt->translate( $cur_x + $space, $text_start );
-                    $txt->text( $record->[$column_idx] );
+                    my %text_options;
+                    $text_options{'-underline'} = $cell_font_underline if $cell_font_underline;
+                    $txt->text( $record->[$column_idx], %text_options );
                 }
                 # Otherwise just use the $page->text() method
                 else
@@ -768,13 +805,28 @@ sub table
                     {
                         $current_row_height = $current_cell_height;
                     }
-                    
+
                     if( $left_over_text )
                     {
                         $leftovers->[$column_idx] = $left_over_text;
                         $do_leftovers = 1;
                     }
                 }
+
+                # Hook to pass coordinates back - http://www.perlmonks.org/?node_id=754777
+                if (ref $arg{cell_render_hook} eq 'CODE') {
+                   $arg{cell_render_hook}->(
+                                            $page,
+                                            $first_row,
+                                            $row_index,
+                                            $column_idx,
+                                            $cur_x,
+                                            $cur_y-$row_h,
+                                            $calc_column_widths->[$column_idx],
+                                            $row_h
+                                           );
+                }
+
                 $cur_x += $calc_column_widths->[$column_idx];
 
                 push @vertical_lines, (!$colspan || (1 >= $colspan)) ? 1 : 0;
@@ -786,20 +838,20 @@ sub table
                 unshift @$row_col_widths, $record_widths;
                 unshift @$rows_height, $pre_calculated_row_height;
             }
-            
+
             # Draw cell bgcolor
-            # This has to be separately from the text loop 
+            # This has to be separately from the text loop
             #  because we do not know the final height of the cell until all text has been drawn
             $cur_x = $xbase;
             for(my $column_idx = 0 ; $column_idx < scalar(@$record) ; $column_idx++)
             {
                 my $cell_bg_color;
-                                    
+
                 if( $remaining_header_rows and ref $header_props)
-                {                                  #Compatibility                 Consistency with other props    
+                {                                  #Compatibility                 Consistency with other props
                     $cell_bg_color = $header_props->{'bg_color'} || $header_props->{'background_color'};
                 }
-                
+
                 # Get the most specific value if none was already set from header_props
                 $cell_bg_color ||= $cell_props->[$row_index + $header_props->{num_header_rows}][$column_idx]->{'background_color'}
                                ||  $col_props->[$column_idx]->{'background_color'}
@@ -827,6 +879,7 @@ sub table
                 $gfx->hline( $xbase + $width );
             }
 
+            $first_row = 0;
             if ($remaining_header_rows) {
               $remaining_header_rows--;
             } else {
@@ -837,7 +890,7 @@ sub table
         if ($gfx)
         {
             # Draw vertical lines
-            if ($vert_borders) 
+            if ($vert_borders)
             {
                 $gfx->move(  $xbase, $table_top_y);
                 $gfx->vline( $cur_y );
@@ -963,12 +1016,12 @@ For a complete working example or initial script look into distribution`s 'examp
 
 =head1 DESCRIPTION
 
-This class is a utility for use with the PDF::API2 module from CPAN. 
-It can be used to display text data in a table layout within a PDF. 
-The text data must be in a 2D array (such as returned by a DBI statement handle fetchall_arrayref() call). 
-The PDF::Table will automatically add as many new pages as necessary to display all of the data. 
-Various layout properties, such as font, font size, and cell padding and background color can be specified for each column and/or for even/odd rows. 
-Also a (non)repeated header row with different layout properties can be specified. 
+This class is a utility for use with the PDF::API2 module from CPAN.
+It can be used to display text data in a table layout within a PDF.
+The text data must be in a 2D array (such as returned by a DBI statement handle fetchall_arrayref() call).
+The PDF::Table will automatically add as many new pages as necessary to display all of the data.
+Various layout properties, such as font, font size, and cell padding and background color can be specified for each column and/or for even/odd rows.
+Also a (non)repeated header row with different layout properties can be specified.
 
 See the L</METHODS> section for complete documentation of every parameter.
 
@@ -986,7 +1039,7 @@ Creates a new instance of the class. (to be improved)
 
 =item Parameters
 
-There are no parameters. 
+There are no parameters.
 
 =item Returns
 
@@ -997,7 +1050,7 @@ Reference to the new instance
 =head2 table()
 
     my ($final_page, $number_of_pages, $final_y) = table($pdf, $page, $data, %settings)
-    
+
 =over
 
 =item Description
@@ -1009,15 +1062,15 @@ Generates a multi-row, multi-column table into an existing PDF document based on
     $pdf      - a PDF::API2 instance representing the document being created
     $page     - a PDF::API2::Page instance representing the current page of the document
     $data     - an ARRAY reference to a 2D data structure that will be used to build the table
-    %settings - HASH with geometry and formatting parameters. 
+    %settings - HASH with geometry and formatting parameters.
 
 For full %settings description see section L</Table settings> below.
 
 This method will add more pages to the pdf instance as required based on the formatting options and the amount of data.
 
-=item Reuturns
+=item Returns
 
-The return value is a 3 items list where 
+The return value is a 3 items list where
 
     $final_page - The first item is a PDF::API2::Page instance that the table ends on
     $number_of_pages - The second item is the count of pages that the table spans on
@@ -1037,7 +1090,7 @@ The return value is a 3 items list where
         start_y => 220,
         start_h => 180,
     );
-    
+
     my ($final_page, $number_of_pages, $final_y) = $pdftable->table( $pdf, $page, $data, %options );
 
 =back
@@ -1048,12 +1101,12 @@ The return value is a 3 items list where
 
 There are some mandatory parameteres for setting table geometry and position across page(s)
 
-=over 
+=over
 
 =item B<x> - X coordinate of upper left corner of the table. Left edge of the sheet is 0.
 
 B<Value:> can be any whole number satisfying 0 =< X < PageWidth
-B<Default:> No default value 
+B<Default:> No default value
 
     x => 10
 
@@ -1077,7 +1130,7 @@ B<Value:> can be any whole number satisfying 0 < start_h < PageHeight - Current
 B<Default:> No default value
 
     start_h => 250
-    
+
 =back
 
 =head4 Optional
@@ -1098,14 +1151,14 @@ B<Default:> Value of param B<'start_y'>
 
     next_y  => 750
 
-=item B<max_word_length> - Breaks long words (like serial numbers hashes etc.) by adding a space after every Nth symbol 
+=item B<max_word_length> - Breaks long words (like serial numbers hashes etc.) by adding a space after every Nth symbol
 
 B<Value:> can be any whole positive number
 B<Default:> 20
 
     max_word_length => 20    # Will add a space after every 20 symbols
 
-=item B<padding> - Padding applied to every cell 
+=item B<padding> - Padding applied to every cell
 
 =item B<padding_top>    - top cell padding, overrides 'padding'
 
@@ -1120,14 +1173,14 @@ B<Value:> can be any whole positive number
 B<Default padding:> 0
 
 B<Default padding_*> $padding
-    
+
     padding        => 5      # all sides cell padding
     padding_top    => 8,     # top cell padding, overrides 'padding'
     padding_right  => 6,     # right cell padding, overrides 'padding'
     padding_left   => 2,     # left cell padding, overrides 'padding'
     padding_bottom => undef  # bottom padding will be 5 as it will fallback to 'padding'
 
-=item B<border> - Width of table border lines. 
+=item B<border> - Width of table border lines.
 
 =item B<horizontal_borders> - Width of horizontal border lines. Overrides 'border' value.
 
@@ -1135,7 +1188,7 @@ B<Default padding_*> $padding
 
 B<Value:> can be any whole positive number. When set to 0 will disable border lines.
 B<Default:> 1
-      
+
     border             => 3     # border width is 3
     horizontal_borders => 1     # horizontal borders will be 1 overriding 3
     vertical_borders   => undef # vertical borders will be 3 as it will fallback to 'border'
@@ -1158,14 +1211,19 @@ B<Default:> 'Times' with UTF8 encoding
 
 B<Value:> can be any positive number
 B<Default:> 12
-    
+
     font_size => 16
 
 =item B<font_color> - Font color for all rows
 
 =item B<font_color_odd> - Font color for odd rows
 
-=item B<font_color_even> - Font color for even rows 
+=item B<font_color_even> - Font color for even rows
+
+=item B<font_underline> - Font underline of the header row
+
+B<Value:> 'auto', integer of distance, or arrayref of distance & thickness (more than one pair will provide mlultiple underlines. Negative distance gives strike-through.
+B<Default:> none
 
 =item B<background_color_odd> - Background color for odd rows
 
@@ -1177,16 +1235,16 @@ B<Default:> 'black' font on 'white' background
     font_color            => '#333333'
     font_color_odd        => 'purple'
     font_color_even       => '#00FF00'
-    background_color_odd  => 'gray'     
+    background_color_odd  => 'gray'
     background_color_even => 'lightblue'
 
 =item B<row_height> - Desired row height but it will be honored only if row_height > font_size + padding_top + padding_bottom
 
 B<Value:> can be any whole positive number
 B<Default:> font_size + padding_top + padding_bottom
-    
+
     row_height => 24
+
 =item B<new_page_func> - CODE reference to a function that returns a PDF::API2::Page instance.
 
 If used the parameter 'new_page_func' must be a function reference which when executed will create a new page and will return the object back to the module.
@@ -1195,9 +1253,9 @@ Also if you need some different type of paper size and orientation than the defa
 Don't forget that your function must return a page object created with PDF::API2 page() method.
 
     new_page_func  => $code_ref
-    
+
 =item B<header_props> - HASH reference to specific settings for the Header row of the table. See section L</Header Row Properties> below
-    
+
     header_props => $hdr_props
 
 =item B<column_props> - HASH reference to specific settings for each column of the table. See section L</Column Properties> below
@@ -1205,9 +1263,26 @@ Don't forget that your function must return a page object created with PDF::API2
     column_props => $col_props
 
 =item B<cell_props> - HASH reference to specific settings for each column of the table. See section L</Cell Properties> below
-    
+
     cell_props => $cel_props
 
+=item B<cell_render_hook> - CODE reference to a function called with the current cell coordinates.  If used the parameter 'cell_render_hook' must be a function reference. It is most useful for creating a url link inside of a cell. The following example adds a link in the first column of each non-header row:
+
+    cell_render_hook  => sub {
+        my ($page, $first_row, $row, $col, $x, $y, $w, $h) = @_;
+
+        # Do nothing except for first column (and not a header row)
+        return unless ($col == 0);
+        return if ($first_row);
+
+        # Create link
+        my $value = $list_of_vals[$row-1];
+        my $url = "https://${hostname}/app/${value}";
+
+        my $annot = $page->annotation();
+        $annot->url( $url, -rect => [$x, $y, $x+$w, $y+$h] );
+    },
+
 =back
 
 =head4 Header Row Properties
@@ -1225,13 +1300,18 @@ B<Default:> 'font' of the table. See table parameter 'font' for more details.
 =item B<font_size> - Font size of the header row
 
 B<Value:> can be any positive number
-B<Default:> 'font_size' of the table + 2  
+B<Default:> 'font_size' of the table + 2
 
 =item B<font_color> - Font color of the header row
 
 B<Value:> Color specifier as 'name' or 'HEX'
 B<Default:> '#000066'
 
+=item B<font_underline> - Font underline of the header row
+
+B<Value:> 'auto', integer of distance, or arrayref of distance & thickness (more than one pair will provide mlultiple underlines. Negative distance gives strike-through.
+B<Default:> none
+
 =item B<bg_color> - Background color of the header row
 
 B<Value:> Color specifier as 'name' or 'HEX'
@@ -1239,7 +1319,7 @@ B<Default:> #FFFFAA
 
 =item B<repeat> - Flag showing if header row should be repeated on every new page
 
-B<Value:> 0,1   1-Yes/True, 0-No/False 
+B<Value:> 0,1   1-Yes/True, 0-No/False
 B<Default:> 0
 
 =item B<justify> - Alignment of text in the header row.
@@ -1247,13 +1327,13 @@ B<Default:> 0
 B<Value:> One of 'left', 'right', 'center'
 B<Default:> Same as column alignment (or 'left' if undefined)
 
-    my $hdr_props = 
+    my $hdr_props =
     {
         font       => $pdf->corefont("Helvetica", -encoding => "utf8"),
         font_size  => 18,
         font_color => '#004444',
-        bg_color   => 'yellow', 
-        repeat     => 1,    
+        bg_color   => 'yellow',
+        repeat     => 1,
         justify    => 'center'
     };
 
@@ -1261,8 +1341,8 @@ B<Default:> Same as column alignment (or 'left' if undefined)
 
 =head4 Column Properties
 
-If the 'column_props' parameter is used, it should be an arrayref of hashrefs, 
-with one hashref for each column of the table. The columns are counted from left to right so the hash reference at $col_props[0] will hold properties for the first column from left to right. 
+If the 'column_props' parameter is used, it should be an arrayref of hashrefs,
+with one hashref for each column of the table. The columns are counted from left to right so the hash reference at $col_props[0] will hold properties for the first column from left to right.
 If you DO NOT want to give properties for a column but to give for another just insert and empty hash reference into the array for the column that you want to skip. This will cause the counting to proceed as expected and the properties to be applyed at the right columns.
 
 Each hashref can contain any of the keys shown below:
@@ -1294,6 +1374,11 @@ B<Default:> 'font_size' of the table.
 B<Value:> Color specifier as 'name' or 'HEX'
 B<Default:> 'font_color' of the table.
 
+=item B<font_underline> - Font underline of this cell
+
+B<Value:> 'auto', integer of distance, or arrayref of distance & thickness (more than one pair will provide mlultiple underlines. Negative distance gives strike-through.
+B<Default:> none
+
 =item B<background_color> - Background color of this column
 
 B<Value:> Color specifier as 'name' or 'HEX'
@@ -1322,7 +1407,7 @@ Example:
 
 =back
 
-NOTE: If 'min_w' and/or 'max_w' parameter is used in 'col_props', have in mind that it may be overriden by the calculated minimum/maximum cell witdh so that table can be created.
+NOTE: If 'min_w' and/or 'max_w' parameter is used in 'col_props', have in mind that it may be overridden by the calculated minimum/maximum cell witdh so that table can be created.
 When this happens a warning will be issued with some advises what can be done.
 In cases of a conflict between column formatting and odd/even row formatting, 'col_props' will override odd/even.
 
@@ -1350,6 +1435,11 @@ B<Default:> 'font_size' of the table.
 B<Value:> Color specifier as 'name' or 'HEX'
 B<Default:> 'font_color' of the table.
 
+=item B<font_underline> - Font underline of this cell
+
+B<Value:> 'auto', integer of distance, or arrayref of distance & thickness (more than one pair will provide mlultiple underlines. Negative distance gives strike-through.
+B<Default:> none
+
 =item B<background_color> - Background color of this cell
 
 B<Value:> Color specifier as 'name' or 'HEX'
@@ -1367,6 +1457,7 @@ Example:
             {    #Row 1 cell 1
                 background_color => '#AAAA00',
                 font_color       => 'yellow',
+                font_underline   => [ 2, 2 ],
             },
 
             # etc.
@@ -1386,7 +1477,7 @@ Example:
     ];
 
     OR
-    
+
     my $cell_props = [];
     $cell_props->[1][0] = {
         #Row 2 cell 1
@@ -1395,9 +1486,9 @@ Example:
     };
 
 =back
-    
-NOTE: In case of a conflict between column, odd/even and cell formating, cell formating will overwrite the other two.
-In case of a conflict between header row and cell formating, header formating will override cell.
+
+NOTE: In case of a conflict between column, odd/even and cell formatting, cell formatting will overwrite the other two.
+In case of a conflict between header row and cell formatting, header formatting will override cell.
 
 =head2 text_block()
 
@@ -1408,7 +1499,7 @@ In case of a conflict between header row and cell formating, header formating wi
 =item Description
 
 Utility method to create a block of text. The block may contain multiple paragraphs.
-It is mainly used internaly but you can use it from outside for placing formated text anywhere on the sheet.
+It is mainly used internaly but you can use it from outside for placing formatted text anywhere on the sheet.
 
 NOTE: This method will NOT add more pages to the pdf instance if the space is not enough to place the string inside the block.
 Leftover text will be returned and has to be handled by the caller - i.e. add a new page and a new block with the leftover.
@@ -1418,15 +1509,15 @@ Leftover text will be returned and has to be handled by the caller - i.e. add a
     $txt  - a PDF::API2::Page::Text instance representing the text tool
     $data - a string that will be placed inside the block
     %settings - HASH with geometry and formatting parameters.
-     
+
 =item Reuturns
 
-The return value is a 3 items list where 
+The return value is a 3 items list where
 
     $width_of_last_line - Width of last line in the block
     $final_y - The Y coordinate of the block bottom so that additional content can be added after it
     $left_over_text - Text that was did not fit in the provided box geometry.
-    
+
 =item Example
 
     # PDF::API2 objects
@@ -1438,21 +1529,21 @@ The return value is a 3 items list where
         y => 570,
         w => 220,
         h => 180
-        
+
         #OPTIONAL PARAMS
         lead     => $font_size | $distance_between_lines,
         align    => "left|right|center|justify|fulljustify",
         hang     => $optional_hanging_indent,
-        Only one of the subsequent 3params can be given. 
+        Only one of the subsequent 3params can be given.
         They override each other.-parspace is the weightest
         parspace => $optional_vertical_space_before_first_paragraph,
         flindent => $optional_indent_of_first_line,
         fpindent => $optional_indent_of_first_paragraph,
         indent   => $optional_indent_of_text_to_every_non_first_line,
     );
-    
+
     my ( $width_of_last_line, $final_y, $left_over_text ) = $pdftable->text_block( $txt, $data, %settings );
+
 =back
 
 =head1 VERSION
@@ -1478,7 +1569,7 @@ at your option, any later version of Perl 5 you may have available.
 
 =head1 PLUGS
 
-=over 
+=over
 
 =item by Daemmon Hughes
 
@@ -1486,7 +1577,8 @@ Much of the work on this module was sponsered by
 Stone Environmental Inc. (www.stone-env.com).
 
 The text_block() method is a slightly modified copy of the one from
-Rick Measham's PDF::API2 L<tutorial|http://rick.measham.id.au/pdf-api2>.
+Rick Measham's PDF::API2 tutorial at
+http://pdfapi2.sourceforge.net/cgi-bin/view/Main/YourFirstDocument
 
 =item by Desislav Kamenov (@deskata on Twitter)
 
diff --git a/modules/override/Rose/DBx/Cache/Anywhere.pm b/modules/override/Rose/DBx/Cache/Anywhere.pm
deleted file mode 100644 (file)
index abc87c7..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-package Rose::DBx::Cache::Anywhere;
-use strict;
-use warnings;
-use Carp;
-use base qw( Rose::DB::Cache );
-
-=head1 NAME
-
-Rose::DBx::Cache::Anywhere - get Apache::DBI behaviour without Apache
-
-=head1 DESCRIPTION
-
-This class is used by Rose::DBx::AutoReconnect.
-The author uses
-Rose::DB with Catalyst under both the Catalyst dev server and
-FastCGI and found that the standard Rose::DB::Cache behaviour
-did not work well with those environments.
-
-=head1 METHODS
-
-=head2 prepare_db( I<rose_db>, I<entry> )
-
-Overrides default method to always ping() dbh if not running
-under mod_perl.
-
-=cut
-
-sub prepare_db {
-    my ( $self, $db, $entry ) = @_;
-
-    if ( Rose::DB::Cache::MOD_PERL_1 || Rose::DB::Cache::MOD_PERL_2 ) {
-        return $self->SUPER::prepare_db( $db, $entry );
-    }
-
-    if ( !$entry->is_prepared ) {
-        if ( $entry->created_during_apache_startup ) {
-            if ( $db->has_dbh ) {
-                eval { $db->dbh->disconnect };    # will probably fail!
-                $db->dbh(undef);
-            }
-
-            $entry->created_during_apache_startup(0);
-            return;
-        }
-
-        # if this a dummy kivitendo dbh, don't try to actually prepare this.
-        if ($db->type =~ /KIVITENDO_EMPTY/) {
-          return;
-        }
-
-        $entry->prepared(1);
-    }
-
-    if ( !$db->dbh->ping ) {
-        $db->dbh(undef);
-    }
-}
-
-1;
-
-__END__
-
-=head1 AUTHOR
-
-Peter Karman, C<< <karman at cpan.org> >>
-
-=head1 BUGS
-
-Please report any bugs or feature requests to
-C<bug-rose-dbx-autoreconnect at rt.cpan.org>, or through the web interface at
-L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Rose-DBx-AutoReconnect>.
-I will be notified, and then you'll automatically be notified of progress on
-your bug as I make changes.
-
-=head1 SUPPORT
-
-You can find documentation for this module with the perldoc command.
-
-    perldoc Rose::DBx::AutoReconnect
-
-You can also look for information at:
-
-=over 4
-
-=item * AnnoCPAN: Annotated CPAN documentation
-
-L<http://annocpan.org/dist/Rose-DBx-AutoReconnect>
-
-=item * CPAN Ratings
-
-L<http://cpanratings.perl.org/d/Rose-DBx-AutoReconnect>
-
-=item * RT: CPAN's request tracker
-
-L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Rose-DBx-AutoReconnect>
-
-=item * Search CPAN
-
-L<http://search.cpan.org/dist/Rose-DBx-AutoReconnect>
-
-=back
-
-=head1 ACKNOWLEDGEMENTS
-
-The Minnesota Supercomputing Institute C<< http://www.msi.umn.edu/ >>
-sponsored the development of this software.
-
-=head1 COPYRIGHT
-
-Copyright 2008 by the Regents of the University of Minnesota.
-All rights reserved.
-
-This program is free software; you can redistribute it and/or modify it
-under the same terms as Perl itself.
-
-=cut
diff --git a/modules/override/YAML.pm b/modules/override/YAML.pm
deleted file mode 100644 (file)
index 56c3c95..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-package YAML;
-our $VERSION = '1.14';
-
-use YAML::Mo;
-
-use Exporter;
-push @YAML::ISA, 'Exporter';
-our @EXPORT = qw{ Dump Load };
-our @EXPORT_OK = qw{ freeze thaw DumpFile LoadFile Bless Blessed };
-
-use YAML::Node; # XXX This is a temp fix for Module::Build
-
-# XXX This VALUE nonsense needs to go.
-use constant VALUE => "\x07YAML\x07VALUE\x07";
-
-# YAML Object Properties
-has dumper_class => default => sub {'YAML::Dumper'};
-has loader_class => default => sub {'YAML::Loader'};
-has dumper_object => default => sub {$_[0]->init_action_object("dumper")};
-has loader_object => default => sub {$_[0]->init_action_object("loader")};
-
-sub Dump {
-    my $yaml = YAML->new;
-    $yaml->dumper_class($YAML::DumperClass)
-        if $YAML::DumperClass;
-    return $yaml->dumper_object->dump(@_);
-}
-
-sub Load {
-    my $yaml = YAML->new;
-    $yaml->loader_class($YAML::LoaderClass)
-        if $YAML::LoaderClass;
-    return $yaml->loader_object->load(@_);
-}
-
-{
-    no warnings 'once';
-    # freeze/thaw is the API for Storable string serialization. Some
-    # modules make use of serializing packages on if they use freeze/thaw.
-    *freeze = \ &Dump;
-    *thaw   = \ &Load;
-}
-
-sub DumpFile {
-    my $OUT;
-    my $filename = shift;
-    if (ref $filename eq 'GLOB') {
-        $OUT = $filename;
-    }
-    else {
-        my $mode = '>';
-        if ($filename =~ /^\s*(>{1,2})\s*(.*)$/) {
-            ($mode, $filename) = ($1, $2);
-        }
-        open $OUT, $mode, $filename
-          or YAML::Mo::Object->die('YAML_DUMP_ERR_FILE_OUTPUT', $filename, $!);
-    }
-    binmode $OUT, ':utf8';  # if $Config{useperlio} eq 'define';
-    local $/ = "\n"; # reset special to "sane"
-    print $OUT Dump(@_);
-}
-
-sub LoadFile {
-    my $IN;
-    my $filename = shift;
-    if (ref $filename eq 'GLOB') {
-        $IN = $filename;
-    }
-    else {
-        open $IN, '<', $filename
-          or YAML::Mo::Object->die('YAML_LOAD_ERR_FILE_INPUT', $filename, $!);
-    }
-    binmode $IN, ':utf8';  # if $Config{useperlio} eq 'define';
-    return Load(do { local $/; <$IN> });
-}
-
-sub init_action_object {
-    my $self = shift;
-    my $object_class = (shift) . '_class';
-    my $module_name = $self->$object_class;
-    eval "require $module_name";
-    $self->die("Error in require $module_name - $@")
-        if $@ and "$@" !~ /Can't locate/;
-    my $object = $self->$object_class->new;
-    $object->set_global_options;
-    return $object;
-}
-
-my $global = {};
-sub Bless {
-    require YAML::Dumper::Base;
-    YAML::Dumper::Base::bless($global, @_)
-}
-sub Blessed {
-    require YAML::Dumper::Base;
-    YAML::Dumper::Base::blessed($global, @_)
-}
-sub global_object { $global }
-
-1;
diff --git a/modules/override/YAML/Any.pm b/modules/override/YAML/Any.pm
deleted file mode 100644 (file)
index c2d35ee..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-use strict; use warnings;
-package YAML::Any;
-our $VERSION = '1.14';
-
-use Exporter ();
-
-@YAML::Any::ISA       = 'Exporter';
-@YAML::Any::EXPORT    = qw(Dump Load);
-@YAML::Any::EXPORT_OK = qw(DumpFile LoadFile);
-
-my @dump_options = qw(
-    UseCode
-    DumpCode
-    SpecVersion
-    Indent
-    UseHeader
-    UseVersion
-    SortKeys
-    AnchorPrefix
-    UseBlock
-    UseFold
-    CompressSeries
-    InlineSeries
-    UseAliases
-    Purity
-    Stringify
-);
-
-my @load_options = qw(
-    UseCode
-    LoadCode
-);
-
-my @implementations = qw(
-    YAML::XS
-    YAML::Syck
-    YAML::Old
-    YAML
-    YAML::Tiny
-);
-
-sub import {
-    __PACKAGE__->implementation;
-    goto &Exporter::import;
-}
-
-sub Dump {
-    no strict 'refs';
-    no warnings 'once';
-    my $implementation = __PACKAGE__->implementation;
-    for my $option (@dump_options) {
-        my $var = "$implementation\::$option";
-        my $value = $$var;
-        local $$var;
-        $$var = defined $value ? $value : ${"YAML::$option"};
-    }
-    return &{"$implementation\::Dump"}(@_);
-}
-
-sub DumpFile {
-    no strict 'refs';
-    no warnings 'once';
-    my $implementation = __PACKAGE__->implementation;
-    for my $option (@dump_options) {
-        my $var = "$implementation\::$option";
-        my $value = $$var;
-        local $$var;
-        $$var = defined $value ? $value : ${"YAML::$option"};
-    }
-    return &{"$implementation\::DumpFile"}(@_);
-}
-
-sub Load {
-    no strict 'refs';
-    no warnings 'once';
-    my $implementation = __PACKAGE__->implementation;
-    for my $option (@load_options) {
-        my $var = "$implementation\::$option";
-        my $value = $$var;
-        local $$var;
-        $$var = defined $value ? $value : ${"YAML::$option"};
-    }
-    return &{"$implementation\::Load"}(@_);
-}
-
-sub LoadFile {
-    no strict 'refs';
-    no warnings 'once';
-    my $implementation = __PACKAGE__->implementation;
-    for my $option (@load_options) {
-        my $var = "$implementation\::$option";
-        my $value = $$var;
-        local $$var;
-        $$var = defined $value ? $value : ${"YAML::$option"};
-    }
-    return &{"$implementation\::LoadFile"}(@_);
-}
-
-sub order {
-    return @YAML::Any::_TEST_ORDER
-        if @YAML::Any::_TEST_ORDER;
-    return @implementations;
-}
-
-sub implementation {
-    my @order = __PACKAGE__->order;
-    for my $module (@order) {
-        my $path = $module;
-        $path =~ s/::/\//g;
-        $path .= '.pm';
-        return $module if exists $INC{$path};
-        eval "require $module; 1" and return $module;
-    }
-    croak("YAML::Any couldn't find any of these YAML implementations: @order");
-}
-
-sub croak {
-    require Carp;
-    Carp::croak(@_);
-}
-
-1;
diff --git a/modules/override/YAML/Dumper.pm b/modules/override/YAML/Dumper.pm
deleted file mode 100644 (file)
index 5f75ab2..0000000
+++ /dev/null
@@ -1,575 +0,0 @@
-package YAML::Dumper;
-
-use YAML::Mo;
-extends 'YAML::Dumper::Base';
-
-use YAML::Dumper::Base;
-use YAML::Node;
-use YAML::Types;
-use Scalar::Util qw();
-
-# Context constants
-use constant KEY       => 3;
-use constant BLESSED   => 4;
-use constant FROMARRAY => 5;
-use constant VALUE     => "\x07YAML\x07VALUE\x07";
-
-# Common YAML character sets
-my $ESCAPE_CHAR = '[\\x00-\\x08\\x0b-\\x0d\\x0e-\\x1f]';
-my $LIT_CHAR    = '|';
-
-#==============================================================================
-# OO version of Dump. YAML->new->dump($foo);
-sub dump {
-    my $self = shift;
-    $self->stream('');
-    $self->document(0);
-    for my $document (@_) {
-        $self->{document}++;
-        $self->transferred({});
-        $self->id_refcnt({});
-        $self->id_anchor({});
-        $self->anchor(1);
-        $self->level(0);
-        $self->offset->[0] = 0 - $self->indent_width;
-        $self->_prewalk($document);
-        $self->_emit_header($document);
-        $self->_emit_node($document);
-    }
-    return $self->stream;
-}
-
-# Every YAML document in the stream must begin with a YAML header, unless
-# there is only a single document and the user requests "no header".
-sub _emit_header {
-    my $self = shift;
-    my ($node) = @_;
-    if (not $self->use_header and
-        $self->document == 1
-       ) {
-        $self->die('YAML_DUMP_ERR_NO_HEADER')
-          unless ref($node) =~ /^(HASH|ARRAY)$/;
-        $self->die('YAML_DUMP_ERR_NO_HEADER')
-          if ref($node) eq 'HASH' and keys(%$node) == 0;
-        $self->die('YAML_DUMP_ERR_NO_HEADER')
-          if ref($node) eq 'ARRAY' and @$node == 0;
-        # XXX Also croak if aliased, blessed, or ynode
-        $self->headless(1);
-        return;
-    }
-    $self->{stream} .= '---';
-# XXX Consider switching to 1.1 style
-    if ($self->use_version) {
-#         $self->{stream} .= " #YAML:1.0";
-    }
-}
-
-# Walk the tree to be dumped and keep track of its reference counts.
-# This function is where the Dumper does all its work. All type
-# transfers happen here.
-sub _prewalk {
-    my $self = shift;
-    my $stringify = $self->stringify;
-    my ($class, $type, $node_id) = $self->node_info(\$_[0], $stringify);
-
-    # Handle typeglobs
-    if ($type eq 'GLOB') {
-        $self->transferred->{$node_id} =
-          YAML::Type::glob->yaml_dump($_[0]);
-        $self->_prewalk($self->transferred->{$node_id});
-        return;
-    }
-
-    # Handle regexps
-    if (ref($_[0]) eq 'Regexp') {
-        return;
-    }
-
-    # Handle Purity for scalars.
-    # XXX can't find a use case yet. Might be YAGNI.
-    if (not ref $_[0]) {
-        $self->{id_refcnt}{$node_id}++ if $self->purity;
-        return;
-    }
-
-    # Make a copy of original
-    my $value = $_[0];
-    ($class, $type, $node_id) = $self->node_info($value, $stringify);
-
-    # Must be a stringified object.
-    return if (ref($value) and not $type);
-
-    # Look for things already transferred.
-    if ($self->transferred->{$node_id}) {
-        (undef, undef, $node_id) = (ref $self->transferred->{$node_id})
-          ? $self->node_info($self->transferred->{$node_id}, $stringify)
-          : $self->node_info(\ $self->transferred->{$node_id}, $stringify);
-        $self->{id_refcnt}{$node_id}++;
-        return;
-    }
-
-    # Handle code refs
-    if ($type eq 'CODE') {
-        $self->transferred->{$node_id} = 'placeholder';
-        YAML::Type::code->yaml_dump(
-            $self->dump_code,
-            $_[0],
-            $self->transferred->{$node_id}
-        );
-        ($class, $type, $node_id) =
-          $self->node_info(\ $self->transferred->{$node_id}, $stringify);
-        $self->{id_refcnt}{$node_id}++;
-        return;
-    }
-
-    # Handle blessed things
-    if (defined $class) {
-        if ($value->can('yaml_dump')) {
-            $value = $value->yaml_dump;
-        }
-        elsif ($type eq 'SCALAR') {
-            $self->transferred->{$node_id} = 'placeholder';
-            YAML::Type::blessed->yaml_dump
-              ($_[0], $self->transferred->{$node_id});
-            ($class, $type, $node_id) =
-              $self->node_info(\ $self->transferred->{$node_id}, $stringify);
-            $self->{id_refcnt}{$node_id}++;
-            return;
-        }
-        else {
-            $value = YAML::Type::blessed->yaml_dump($value);
-        }
-        $self->transferred->{$node_id} = $value;
-        (undef, $type, $node_id) = $self->node_info($value, $stringify);
-    }
-
-    # Handle YAML Blessed things
-    require YAML;
-    if (defined YAML->global_object()->{blessed_map}{$node_id}) {
-        $value = YAML->global_object()->{blessed_map}{$node_id};
-        $self->transferred->{$node_id} = $value;
-        ($class, $type, $node_id) = $self->node_info($value, $stringify);
-        $self->_prewalk($value);
-        return;
-    }
-
-    # Handle hard refs
-    if ($type eq 'REF' or $type eq 'SCALAR') {
-        $value = YAML::Type::ref->yaml_dump($value);
-        $self->transferred->{$node_id} = $value;
-        (undef, $type, $node_id) = $self->node_info($value, $stringify);
-    }
-
-    # Handle ref-to-glob's
-    elsif ($type eq 'GLOB') {
-        my $ref_ynode = $self->transferred->{$node_id} =
-          YAML::Type::ref->yaml_dump($value);
-
-        my $glob_ynode = $ref_ynode->{&VALUE} =
-          YAML::Type::glob->yaml_dump($$value);
-
-        (undef, undef, $node_id) = $self->node_info($glob_ynode, $stringify);
-        $self->transferred->{$node_id} = $glob_ynode;
-        $self->_prewalk($glob_ynode);
-        return;
-    }
-
-    # Increment ref count for node
-    return if ++($self->{id_refcnt}{$node_id}) > 1;
-
-    # Keep on walking
-    if ($type eq 'HASH') {
-        $self->_prewalk($value->{$_})
-            for keys %{$value};
-        return;
-    }
-    elsif ($type eq 'ARRAY') {
-        $self->_prewalk($_)
-            for @{$value};
-        return;
-    }
-
-    # Unknown type. Need to know about it.
-    $self->warn(<<"...");
-YAML::Dumper can't handle dumping this type of data.
-Please report this to the author.
-
-id:    $node_id
-type:  $type
-class: $class
-value: $value
-
-...
-
-    return;
-}
-
-# Every data element and sub data element is a node.
-# Everything emitted goes through this function.
-sub _emit_node {
-    my $self = shift;
-    my ($type, $node_id);
-    my $ref = ref($_[0]);
-    if ($ref) {
-        if ($ref eq 'Regexp') {
-            $self->_emit(' !!perl/regexp');
-            $self->_emit_str("$_[0]");
-            return;
-        }
-        (undef, $type, $node_id) = $self->node_info($_[0], $self->stringify);
-    }
-    else {
-        $type = $ref || 'SCALAR';
-        (undef, undef, $node_id) = $self->node_info(\$_[0], $self->stringify);
-    }
-
-    my ($ynode, $tag) = ('') x 2;
-    my ($value, $context) = (@_, 0);
-
-    if (defined $self->transferred->{$node_id}) {
-        $value = $self->transferred->{$node_id};
-        $ynode = ynode($value);
-        if (ref $value) {
-            $tag = defined $ynode ? $ynode->tag->short : '';
-            (undef, $type, $node_id) =
-              $self->node_info($value, $self->stringify);
-        }
-        else {
-            $ynode = ynode($self->transferred->{$node_id});
-            $tag = defined $ynode ? $ynode->tag->short : '';
-            $type = 'SCALAR';
-            (undef, undef, $node_id) =
-              $self->node_info(
-                  \ $self->transferred->{$node_id},
-                  $self->stringify
-              );
-        }
-    }
-    elsif ($ynode = ynode($value)) {
-        $tag = $ynode->tag->short;
-    }
-
-    if ($self->use_aliases) {
-        $self->{id_refcnt}{$node_id} ||= 0;
-        if ($self->{id_refcnt}{$node_id} > 1) {
-            if (defined $self->{id_anchor}{$node_id}) {
-                $self->{stream} .= ' *' . $self->{id_anchor}{$node_id} . "\n";
-                return;
-            }
-            my $anchor = $self->anchor_prefix . $self->{anchor}++;
-            $self->{stream} .= ' &' . $anchor;
-            $self->{id_anchor}{$node_id} = $anchor;
-        }
-    }
-
-    return $self->_emit_str("$value")   # Stringified object
-      if ref($value) and not $type;
-    return $self->_emit_scalar($value, $tag)
-      if $type eq 'SCALAR' and $tag;
-    return $self->_emit_str($value)
-      if $type eq 'SCALAR';
-    return $self->_emit_mapping($value, $tag, $node_id, $context)
-      if $type eq 'HASH';
-    return $self->_emit_sequence($value, $tag)
-      if $type eq 'ARRAY';
-    $self->warn('YAML_DUMP_WARN_BAD_NODE_TYPE', $type);
-    return $self->_emit_str("$value");
-}
-
-# A YAML mapping is akin to a Perl hash.
-sub _emit_mapping {
-    my $self = shift;
-    my ($value, $tag, $node_id, $context) = @_;
-    $self->{stream} .= " !$tag" if $tag;
-
-    # Sometimes 'keys' fails. Like on a bad tie implementation.
-    my $empty_hash = not(eval {keys %$value});
-    $self->warn('YAML_EMIT_WARN_KEYS', $@) if $@;
-    return ($self->{stream} .= " {}\n") if $empty_hash;
-
-    # If CompressSeries is on (default) and legal is this context, then
-    # use it and make the indent level be 2 for this node.
-    if ($context == FROMARRAY and
-        $self->compress_series and
-        not (defined $self->{id_anchor}{$node_id} or $tag or $empty_hash)
-       ) {
-        $self->{stream} .= ' ';
-        $self->offset->[$self->level+1] = $self->offset->[$self->level] + 2;
-    }
-    else {
-        $context = 0;
-        $self->{stream} .= "\n"
-          unless $self->headless && not($self->headless(0));
-        $self->offset->[$self->level+1] =
-          $self->offset->[$self->level] + $self->indent_width;
-    }
-
-    $self->{level}++;
-    my @keys;
-    if ($self->sort_keys == 1) {
-        if (ynode($value)) {
-            @keys = keys %$value;
-        }
-        else {
-            @keys = sort keys %$value;
-        }
-    }
-    elsif ($self->sort_keys == 2) {
-        @keys = sort keys %$value;
-    }
-    # XXX This is hackish but sometimes handy. Not sure whether to leave it in.
-    elsif (ref($self->sort_keys) eq 'ARRAY') {
-        my $i = 1;
-        my %order = map { ($_, $i++) } @{$self->sort_keys};
-        @keys = sort {
-            (defined $order{$a} and defined $order{$b})
-              ? ($order{$a} <=> $order{$b})
-              : ($a cmp $b);
-        } keys %$value;
-    }
-    else {
-        @keys = keys %$value;
-    }
-    # Force the YAML::VALUE ('=') key to sort last.
-    if (exists $value->{&VALUE}) {
-        for (my $i = 0; $i < @keys; $i++) {
-            if ($keys[$i] eq &VALUE) {
-                splice(@keys, $i, 1);
-                push @keys, &VALUE;
-                last;
-            }
-        }
-    }
-
-    for my $key (@keys) {
-        $self->_emit_key($key, $context);
-        $context = 0;
-        $self->{stream} .= ':';
-        $self->_emit_node($value->{$key});
-    }
-    $self->{level}--;
-}
-
-# A YAML series is akin to a Perl array.
-sub _emit_sequence {
-    my $self = shift;
-    my ($value, $tag) = @_;
-    $self->{stream} .= " !$tag" if $tag;
-
-    return ($self->{stream} .= " []\n") if @$value == 0;
-
-    $self->{stream} .= "\n"
-      unless $self->headless && not($self->headless(0));
-
-    # XXX Really crufty feature. Better implemented by ynodes.
-    if ($self->inline_series and
-        @$value <= $self->inline_series and
-        not (scalar grep {ref or /\n/} @$value)
-       ) {
-        $self->{stream} =~ s/\n\Z/ /;
-        $self->{stream} .= '[';
-        for (my $i = 0; $i < @$value; $i++) {
-            $self->_emit_str($value->[$i], KEY);
-            last if $i == $#{$value};
-            $self->{stream} .= ', ';
-        }
-        $self->{stream} .= "]\n";
-        return;
-    }
-
-    $self->offset->[$self->level + 1] =
-      $self->offset->[$self->level] + $self->indent_width;
-    $self->{level}++;
-    for my $val (@$value) {
-        $self->{stream} .= ' ' x $self->offset->[$self->level];
-        $self->{stream} .= '-';
-        $self->_emit_node($val, FROMARRAY);
-    }
-    $self->{level}--;
-}
-
-# Emit a mapping key
-sub _emit_key {
-    my $self = shift;
-    my ($value, $context) = @_;
-    $self->{stream} .= ' ' x $self->offset->[$self->level]
-      unless $context == FROMARRAY;
-    $self->_emit_str($value, KEY);
-}
-
-# Emit a blessed SCALAR
-sub _emit_scalar {
-    my $self = shift;
-    my ($value, $tag) = @_;
-    $self->{stream} .= " !$tag";
-    $self->_emit_str($value, BLESSED);
-}
-
-sub _emit {
-    my $self = shift;
-    $self->{stream} .= join '', @_;
-}
-
-# Emit a string value. YAML has many scalar styles. This routine attempts to
-# guess the best style for the text.
-sub _emit_str {
-    my $self = shift;
-    my $type = $_[1] || 0;
-
-    # Use heuristics to find the best scalar emission style.
-    $self->offset->[$self->level + 1] =
-      $self->offset->[$self->level] + $self->indent_width;
-    $self->{level}++;
-
-    my $sf = $type == KEY ? '' : ' ';
-    my $sb = $type == KEY ? '? ' : ' ';
-    my $ef = $type == KEY ? '' : "\n";
-    my $eb = "\n";
-
-    while (1) {
-        $self->_emit($sf),
-        $self->_emit_plain($_[0]),
-        $self->_emit($ef), last
-          if not defined $_[0];
-        $self->_emit($sf, '=', $ef), last
-          if $_[0] eq VALUE;
-        $self->_emit($sf),
-        $self->_emit_double($_[0]),
-        $self->_emit($ef), last
-          if $_[0] =~ /$ESCAPE_CHAR/;
-        if ($_[0] =~ /\n/) {
-            $self->_emit($sb),
-            $self->_emit_block($LIT_CHAR, $_[0]),
-            $self->_emit($eb), last
-              if $self->use_block;
-              Carp::cluck "[YAML] \$UseFold is no longer supported"
-              if $self->use_fold;
-            $self->_emit($sf),
-            $self->_emit_double($_[0]),
-            $self->_emit($ef), last
-              if length $_[0] <= 30;
-            $self->_emit($sf),
-            $self->_emit_double($_[0]),
-            $self->_emit($ef), last
-              if $_[0] !~ /\n\s*\S/;
-            $self->_emit($sb),
-            $self->_emit_block($LIT_CHAR, $_[0]),
-            $self->_emit($eb), last;
-        }
-        $self->_emit($sf),
-        $self->_emit_number($_[0]),
-        $self->_emit($ef), last
-          if $self->is_literal_number($_[0]);
-        $self->_emit($sf),
-        $self->_emit_plain($_[0]),
-        $self->_emit($ef), last
-          if $self->is_valid_plain($_[0]);
-        $self->_emit($sf),
-        $self->_emit_double($_[0]),
-        $self->_emit($ef), last
-          if $_[0] =~ /'/;
-        $self->_emit($sf),
-        $self->_emit_single($_[0]),
-        $self->_emit($ef);
-        last;
-    }
-
-    $self->{level}--;
-
-    return;
-}
-
-sub is_literal_number {
-    my $self = shift;
-    # Stolen from JSON::Tiny
-    return B::svref_2object(\$_[0])->FLAGS & (B::SVp_IOK | B::SVp_NOK)
-            && 0 + $_[0] eq $_[0];
-}
-
-sub _emit_number {
-    my $self = shift;
-    return $self->_emit_plain($_[0]);
-}
-
-# Check whether or not a scalar should be emitted as an plain scalar.
-sub is_valid_plain {
-    my $self = shift;
-    return 0 unless length $_[0];
-    return 0 if $self->quote_numeric_strings and Scalar::Util::looks_like_number($_[0]);
-    # refer to YAML::Loader::parse_inline_simple()
-    return 0 if $_[0] =~ /^[\s\{\[\~\`\'\"\!\@\#\>\|\%\&\?\*\^]/;
-    return 0 if $_[0] =~ /[\{\[\]\},]/;
-    return 0 if $_[0] =~ /[:\-\?]\s/;
-    return 0 if $_[0] =~ /\s#/;
-    return 0 if $_[0] =~ /\:(\s|$)/;
-    return 0 if $_[0] =~ /[\s\|\>]$/;
-    return 0 if $_[0] eq '-';
-    return 1;
-}
-
-sub _emit_block {
-    my $self = shift;
-    my ($indicator, $value) = @_;
-    $self->{stream} .= $indicator;
-    $value =~ /(\n*)\Z/;
-    my $chomp = length $1 ? (length $1 > 1) ? '+' : '' : '-';
-    $value = '~' if not defined $value;
-    $self->{stream} .= $chomp;
-    $self->{stream} .= $self->indent_width if $value =~ /^\s/;
-    $self->{stream} .= $self->indent($value);
-}
-
-# Plain means that the scalar is unquoted.
-sub _emit_plain {
-    my $self = shift;
-    $self->{stream} .= defined $_[0] ? $_[0] : '~';
-}
-
-# Double quoting is for single lined escaped strings.
-sub _emit_double {
-    my $self = shift;
-    (my $escaped = $self->escape($_[0])) =~ s/"/\\"/g;
-    $self->{stream} .= qq{"$escaped"};
-}
-
-# Single quoting is for single lined unescaped strings.
-sub _emit_single {
-    my $self = shift;
-    my $item = shift;
-    $item =~ s{'}{''}g;
-    $self->{stream} .= "'$item'";
-}
-
-#==============================================================================
-# Utility subroutines.
-#==============================================================================
-
-# Indent a scalar to the current indentation level.
-sub indent {
-    my $self = shift;
-    my ($text) = @_;
-    return $text unless length $text;
-    $text =~ s/\n\Z//;
-    my $indent = ' ' x $self->offset->[$self->level];
-    $text =~ s/^/$indent/gm;
-    $text = "\n$text";
-    return $text;
-}
-
-# Escapes for unprintable characters
-my @escapes = qw(\0   \x01 \x02 \x03 \x04 \x05 \x06 \a
-                 \x08 \t   \n   \v   \f   \r   \x0e \x0f
-                 \x10 \x11 \x12 \x13 \x14 \x15 \x16 \x17
-                 \x18 \x19 \x1a \e   \x1c \x1d \x1e \x1f
-                );
-
-# Escape the unprintable characters
-sub escape {
-    my $self = shift;
-    my ($text) = @_;
-    $text =~ s/\\/\\\\/g;
-    $text =~ s/([\x00-\x1f])/$escapes[ord($1)]/ge;
-    return $text;
-}
-
-1;
diff --git a/modules/override/YAML/Dumper/Base.pm b/modules/override/YAML/Dumper/Base.pm
deleted file mode 100644 (file)
index 23db7b1..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-package YAML::Dumper::Base;
-
-use YAML::Mo;
-
-use YAML::Node;
-
-# YAML Dumping options
-has spec_version    => default => sub {'1.0'};
-has indent_width    => default => sub {2};
-has use_header      => default => sub {1};
-has use_version     => default => sub {0};
-has sort_keys       => default => sub {1};
-has anchor_prefix   => default => sub {''};
-has dump_code       => default => sub {0};
-has use_block       => default => sub {0};
-has use_fold        => default => sub {0};
-has compress_series => default => sub {1};
-has inline_series   => default => sub {0};
-has use_aliases     => default => sub {1};
-has purity          => default => sub {0};
-has stringify       => default => sub {0};
-has quote_numeric_strings => default => sub {0};
-
-# Properties
-has stream      => default => sub {''};
-has document    => default => sub {0};
-has transferred => default => sub {{}};
-has id_refcnt   => default => sub {{}};
-has id_anchor   => default => sub {{}};
-has anchor      => default => sub {1};
-has level       => default => sub {0};
-has offset      => default => sub {[]};
-has headless    => default => sub {0};
-has blessed_map => default => sub {{}};
-
-# Global Options are an idea taken from Data::Dumper. Really they are just
-# sugar on top of real OO properties. They make the simple Dump/Load API
-# easy to configure.
-sub set_global_options {
-    my $self = shift;
-    $self->spec_version($YAML::SpecVersion)
-      if defined $YAML::SpecVersion;
-    $self->indent_width($YAML::Indent)
-      if defined $YAML::Indent;
-    $self->use_header($YAML::UseHeader)
-      if defined $YAML::UseHeader;
-    $self->use_version($YAML::UseVersion)
-      if defined $YAML::UseVersion;
-    $self->sort_keys($YAML::SortKeys)
-      if defined $YAML::SortKeys;
-    $self->anchor_prefix($YAML::AnchorPrefix)
-      if defined $YAML::AnchorPrefix;
-    $self->dump_code($YAML::DumpCode || $YAML::UseCode)
-      if defined $YAML::DumpCode or defined $YAML::UseCode;
-    $self->use_block($YAML::UseBlock)
-      if defined $YAML::UseBlock;
-    $self->use_fold($YAML::UseFold)
-      if defined $YAML::UseFold;
-    $self->compress_series($YAML::CompressSeries)
-      if defined $YAML::CompressSeries;
-    $self->inline_series($YAML::InlineSeries)
-      if defined $YAML::InlineSeries;
-    $self->use_aliases($YAML::UseAliases)
-      if defined $YAML::UseAliases;
-    $self->purity($YAML::Purity)
-      if defined $YAML::Purity;
-    $self->stringify($YAML::Stringify)
-      if defined $YAML::Stringify;
-    $self->quote_numeric_strings($YAML::QuoteNumericStrings)
-      if defined $YAML::QuoteNumericStrings;
-}
-
-sub dump {
-    my $self = shift;
-    $self->die('dump() not implemented in this class.');
-}
-
-sub blessed {
-    my $self = shift;
-    my ($ref) = @_;
-    $ref = \$_[0] unless ref $ref;
-    my (undef, undef, $node_id) = YAML::Mo::Object->node_info($ref);
-    $self->{blessed_map}->{$node_id};
-}
-
-sub bless {
-    my $self = shift;
-    my ($ref, $blessing) = @_;
-    my $ynode;
-    $ref = \$_[0] unless ref $ref;
-    my (undef, undef, $node_id) = YAML::Mo::Object->node_info($ref);
-    if (not defined $blessing) {
-        $ynode = YAML::Node->new($ref);
-    }
-    elsif (ref $blessing) {
-        $self->die() unless ynode($blessing);
-        $ynode = $blessing;
-    }
-    else {
-        no strict 'refs';
-        my $transfer = $blessing . "::yaml_dump";
-        $self->die() unless defined &{$transfer};
-        $ynode = &{$transfer}($ref);
-        $self->die() unless ynode($ynode);
-    }
-    $self->{blessed_map}->{$node_id} = $ynode;
-    my $object = ynode($ynode) or $self->die();
-    return $object;
-}
-
-1;
diff --git a/modules/override/YAML/Error.pm b/modules/override/YAML/Error.pm
deleted file mode 100644 (file)
index e855092..0000000
+++ /dev/null
@@ -1,191 +0,0 @@
-package YAML::Error;
-
-use YAML::Mo;
-
-has 'code';
-has 'type' => default => sub {'Error'};
-has 'line';
-has 'document';
-has 'arguments' => default => sub {[]};
-
-my ($error_messages, %line_adjust);
-
-sub format_message {
-    my $self = shift;
-    my $output = 'YAML ' . $self->type . ': ';
-    my $code = $self->code;
-    if ($error_messages->{$code}) {
-        $code = sprintf($error_messages->{$code}, @{$self->arguments});
-    }
-    $output .= $code . "\n";
-
-    $output .= '   Code: ' . $self->code . "\n"
-        if defined $self->code;
-    $output .= '   Line: ' . $self->line . "\n"
-        if defined $self->line;
-    $output .= '   Document: ' . $self->document . "\n"
-        if defined $self->document;
-    return $output;
-}
-
-sub error_messages {
-    $error_messages;
-}
-
-%$error_messages = map {s/^\s+//;$_} split "\n", <<'...';
-YAML_PARSE_ERR_BAD_CHARS
-  Invalid characters in stream. This parser only supports printable ASCII
-YAML_PARSE_ERR_NO_FINAL_NEWLINE
-  Stream does not end with newline character
-YAML_PARSE_ERR_BAD_MAJOR_VERSION
-  Can't parse a %s document with a 1.0 parser
-YAML_PARSE_WARN_BAD_MINOR_VERSION
-  Parsing a %s document with a 1.0 parser
-YAML_PARSE_WARN_MULTIPLE_DIRECTIVES
-  '%s directive used more than once'
-YAML_PARSE_ERR_TEXT_AFTER_INDICATOR
-  No text allowed after indicator
-YAML_PARSE_ERR_NO_ANCHOR
-  No anchor for alias '*%s'
-YAML_PARSE_ERR_NO_SEPARATOR
-  Expected separator '---'
-YAML_PARSE_ERR_SINGLE_LINE
-  Couldn't parse single line value
-YAML_PARSE_ERR_BAD_ANCHOR
-  Invalid anchor
-YAML_DUMP_ERR_INVALID_INDENT
-  Invalid Indent width specified: '%s'
-YAML_LOAD_USAGE
-  usage: YAML::Load($yaml_stream_scalar)
-YAML_PARSE_ERR_BAD_NODE
-  Can't parse node
-YAML_PARSE_ERR_BAD_EXPLICIT
-  Unsupported explicit transfer: '%s'
-YAML_DUMP_USAGE_DUMPCODE
-  Invalid value for DumpCode: '%s'
-YAML_LOAD_ERR_FILE_INPUT
-  Couldn't open %s for input:\n%s
-YAML_DUMP_ERR_FILE_CONCATENATE
-  Can't concatenate to YAML file %s
-YAML_DUMP_ERR_FILE_OUTPUT
-  Couldn't open %s for output:\n%s
-YAML_DUMP_ERR_NO_HEADER
-  With UseHeader=0, the node must be a plain hash or array
-YAML_DUMP_WARN_BAD_NODE_TYPE
-  Can't perform serialization for node type: '%s'
-YAML_EMIT_WARN_KEYS
-  Encountered a problem with 'keys':\n%s
-YAML_DUMP_WARN_DEPARSE_FAILED
-  Deparse failed for CODE reference
-YAML_DUMP_WARN_CODE_DUMMY
-  Emitting dummy subroutine for CODE reference
-YAML_PARSE_ERR_MANY_EXPLICIT
-  More than one explicit transfer
-YAML_PARSE_ERR_MANY_IMPLICIT
-  More than one implicit request
-YAML_PARSE_ERR_MANY_ANCHOR
-  More than one anchor
-YAML_PARSE_ERR_ANCHOR_ALIAS
-  Can't define both an anchor and an alias
-YAML_PARSE_ERR_BAD_ALIAS
-  Invalid alias
-YAML_PARSE_ERR_MANY_ALIAS
-  More than one alias
-YAML_LOAD_ERR_NO_CONVERT
-  Can't convert implicit '%s' node to explicit '%s' node
-YAML_LOAD_ERR_NO_DEFAULT_VALUE
-  No default value for '%s' explicit transfer
-YAML_LOAD_ERR_NON_EMPTY_STRING
-  Only the empty string can be converted to a '%s'
-YAML_LOAD_ERR_BAD_MAP_TO_SEQ
-  Can't transfer map as sequence. Non numeric key '%s' encountered.
-YAML_DUMP_ERR_BAD_GLOB
-  '%s' is an invalid value for Perl glob
-YAML_DUMP_ERR_BAD_REGEXP
-  '%s' is an invalid value for Perl Regexp
-YAML_LOAD_ERR_BAD_MAP_ELEMENT
-  Invalid element in map
-YAML_LOAD_WARN_DUPLICATE_KEY
-  Duplicate map key found. Ignoring.
-YAML_LOAD_ERR_BAD_SEQ_ELEMENT
-  Invalid element in sequence
-YAML_PARSE_ERR_INLINE_MAP
-  Can't parse inline map
-YAML_PARSE_ERR_INLINE_SEQUENCE
-  Can't parse inline sequence
-YAML_PARSE_ERR_BAD_DOUBLE
-  Can't parse double quoted string
-YAML_PARSE_ERR_BAD_SINGLE
-  Can't parse single quoted string
-YAML_PARSE_ERR_BAD_INLINE_IMPLICIT
-  Can't parse inline implicit value '%s'
-YAML_PARSE_ERR_BAD_IMPLICIT
-  Unrecognized implicit value '%s'
-YAML_PARSE_ERR_INDENTATION
-  Error. Invalid indentation level
-YAML_PARSE_ERR_INCONSISTENT_INDENTATION
-  Inconsistent indentation level
-YAML_LOAD_WARN_UNRESOLVED_ALIAS
-  Can't resolve alias *%s
-YAML_LOAD_WARN_NO_REGEXP_IN_REGEXP
-  No 'REGEXP' element for Perl regexp
-YAML_LOAD_WARN_BAD_REGEXP_ELEM
-  Unknown element '%s' in Perl regexp
-YAML_LOAD_WARN_GLOB_NAME
-  No 'NAME' element for Perl glob
-YAML_LOAD_WARN_PARSE_CODE
-  Couldn't parse Perl code scalar: %s
-YAML_LOAD_WARN_CODE_DEPARSE
-  Won't parse Perl code unless $YAML::LoadCode is set
-YAML_EMIT_ERR_BAD_LEVEL
-  Internal Error: Bad level detected
-YAML_PARSE_WARN_AMBIGUOUS_TAB
-  Amibiguous tab converted to spaces
-YAML_LOAD_WARN_BAD_GLOB_ELEM
-  Unknown element '%s' in Perl glob
-YAML_PARSE_ERR_ZERO_INDENT
-  Can't use zero as an indentation width
-YAML_LOAD_WARN_GLOB_IO
-  Can't load an IO filehandle. Yet!!!
-...
-
-%line_adjust = map {($_, 1)}
-  qw(YAML_PARSE_ERR_BAD_MAJOR_VERSION
-     YAML_PARSE_WARN_BAD_MINOR_VERSION
-     YAML_PARSE_ERR_TEXT_AFTER_INDICATOR
-     YAML_PARSE_ERR_NO_ANCHOR
-     YAML_PARSE_ERR_MANY_EXPLICIT
-     YAML_PARSE_ERR_MANY_IMPLICIT
-     YAML_PARSE_ERR_MANY_ANCHOR
-     YAML_PARSE_ERR_ANCHOR_ALIAS
-     YAML_PARSE_ERR_BAD_ALIAS
-     YAML_PARSE_ERR_MANY_ALIAS
-     YAML_LOAD_ERR_NO_CONVERT
-     YAML_LOAD_ERR_NO_DEFAULT_VALUE
-     YAML_LOAD_ERR_NON_EMPTY_STRING
-     YAML_LOAD_ERR_BAD_MAP_TO_SEQ
-     YAML_LOAD_ERR_BAD_STR_TO_INT
-     YAML_LOAD_ERR_BAD_STR_TO_DATE
-     YAML_LOAD_ERR_BAD_STR_TO_TIME
-     YAML_LOAD_WARN_DUPLICATE_KEY
-     YAML_PARSE_ERR_INLINE_MAP
-     YAML_PARSE_ERR_INLINE_SEQUENCE
-     YAML_PARSE_ERR_BAD_DOUBLE
-     YAML_PARSE_ERR_BAD_SINGLE
-     YAML_PARSE_ERR_BAD_INLINE_IMPLICIT
-     YAML_PARSE_ERR_BAD_IMPLICIT
-     YAML_LOAD_WARN_NO_REGEXP_IN_REGEXP
-     YAML_LOAD_WARN_BAD_REGEXP_ELEM
-     YAML_LOAD_WARN_REGEXP_CREATE
-     YAML_LOAD_WARN_GLOB_NAME
-     YAML_LOAD_WARN_PARSE_CODE
-     YAML_LOAD_WARN_CODE_DEPARSE
-     YAML_LOAD_WARN_BAD_GLOB_ELEM
-     YAML_PARSE_ERR_ZERO_INDENT
-    );
-
-package YAML::Warning;
-
-our @ISA = 'YAML::Error';
-
-1;
diff --git a/modules/override/YAML/Loader.pm b/modules/override/YAML/Loader.pm
deleted file mode 100644 (file)
index 2cef54e..0000000
+++ /dev/null
@@ -1,756 +0,0 @@
-package YAML::Loader;
-
-use YAML::Mo;
-extends 'YAML::Loader::Base';
-
-use YAML::Loader::Base;
-use YAML::Types;
-
-# Context constants
-use constant LEAF       => 1;
-use constant COLLECTION => 2;
-use constant VALUE      => "\x07YAML\x07VALUE\x07";
-use constant COMMENT    => "\x07YAML\x07COMMENT\x07";
-
-# Common YAML character sets
-my $ESCAPE_CHAR = '[\\x00-\\x08\\x0b-\\x0d\\x0e-\\x1f]';
-my $FOLD_CHAR   = '>';
-my $LIT_CHAR    = '|';
-my $LIT_CHAR_RX = "\\$LIT_CHAR";
-
-sub load {
-    my $self = shift;
-    $self->stream($_[0] || '');
-    return $self->_parse();
-}
-
-# Top level function for parsing. Parse each document in order and
-# handle processing for YAML headers.
-sub _parse {
-    my $self = shift;
-    my (%directives, $preface);
-    $self->{stream} =~ s|\015\012|\012|g;
-    $self->{stream} =~ s|\015|\012|g;
-    $self->line(0);
-    $self->die('YAML_PARSE_ERR_BAD_CHARS')
-      if $self->stream =~ /$ESCAPE_CHAR/;
-#     $self->die('YAML_PARSE_ERR_NO_FINAL_NEWLINE')
-    $self->{stream} .= "\n"
-      if length($self->stream) and
-         $self->{stream} !~ s/(.)\n\Z/$1/s;
-    $self->lines([split /\x0a/, $self->stream, -1]);
-    $self->line(1);
-    # Throw away any comments or blanks before the header (or start of
-    # content for headerless streams)
-    $self->_parse_throwaway_comments();
-    $self->document(0);
-    $self->documents([]);
-    # Add an "assumed" header if there is no header and the stream is
-    # not empty (after initial throwaways).
-    if (not $self->eos) {
-        if ($self->lines->[0] !~ /^---(\s|$)/) {
-            unshift @{$self->lines}, '---';
-            $self->{line}--;
-        }
-    }
-
-    # Main Loop. Parse out all the top level nodes and return them.
-    while (not $self->eos) {
-        $self->anchor2node({});
-        $self->{document}++;
-        $self->done(0);
-        $self->level(0);
-        $self->offset->[0] = -1;
-
-        if ($self->lines->[0] =~ /^---\s*(.*)$/) {
-            my @words = split /\s+/, $1;
-            %directives = ();
-            while (@words && $words[0] =~ /^#(\w+):(\S.*)$/) {
-                my ($key, $value) = ($1, $2);
-                shift(@words);
-                if (defined $directives{$key}) {
-                    $self->warn('YAML_PARSE_WARN_MULTIPLE_DIRECTIVES',
-                      $key, $self->document);
-                    next;
-                }
-                $directives{$key} = $value;
-            }
-            $self->preface(join ' ', @words);
-        }
-        else {
-            $self->die('YAML_PARSE_ERR_NO_SEPARATOR');
-        }
-
-        if (not $self->done) {
-            $self->_parse_next_line(COLLECTION);
-        }
-        if ($self->done) {
-            $self->{indent} = -1;
-            $self->content('');
-        }
-
-        $directives{YAML} ||= '1.0';
-        $directives{TAB} ||= 'NONE';
-        ($self->{major_version}, $self->{minor_version}) =
-          split /\./, $directives{YAML}, 2;
-        $self->die('YAML_PARSE_ERR_BAD_MAJOR_VERSION', $directives{YAML})
-          if $self->major_version ne '1';
-        $self->warn('YAML_PARSE_WARN_BAD_MINOR_VERSION', $directives{YAML})
-          if $self->minor_version ne '0';
-        $self->die('Unrecognized TAB policy')
-          unless $directives{TAB} =~ /^(NONE|\d+)(:HARD)?$/;
-
-        push @{$self->documents}, $self->_parse_node();
-    }
-    return wantarray ? @{$self->documents} : $self->documents->[-1];
-}
-
-# This function is the dispatcher for parsing each node. Every node
-# recurses back through here. (Inlines are an exception as they have
-# their own sub-parser.)
-sub _parse_node {
-    my $self = shift;
-    my $preface = $self->preface;
-    $self->preface('');
-    my ($node, $type, $indicator, $escape, $chomp) = ('') x 5;
-    my ($anchor, $alias, $explicit, $implicit, $class) = ('') x 5;
-    ($anchor, $alias, $explicit, $implicit, $preface) =
-      $self->_parse_qualifiers($preface);
-    if ($anchor) {
-        $self->anchor2node->{$anchor} = CORE::bless [], 'YAML-anchor2node';
-    }
-    $self->inline('');
-    while (length $preface) {
-        my $line = $self->line - 1;
-        if ($preface =~ s/^($FOLD_CHAR|$LIT_CHAR_RX)(-|\+)?\d*\s*//) {
-            $indicator = $1;
-            $chomp = $2 if defined($2);
-        }
-        else {
-            $self->die('YAML_PARSE_ERR_TEXT_AFTER_INDICATOR') if $indicator;
-            $self->inline($preface);
-            $preface = '';
-        }
-    }
-    if ($alias) {
-        $self->die('YAML_PARSE_ERR_NO_ANCHOR', $alias)
-          unless defined $self->anchor2node->{$alias};
-        if (ref($self->anchor2node->{$alias}) ne 'YAML-anchor2node') {
-            $node = $self->anchor2node->{$alias};
-        }
-        else {
-            $node = do {my $sv = "*$alias"};
-            push @{$self->anchor2node->{$alias}}, [\$node, $self->line];
-        }
-    }
-    elsif (length $self->inline) {
-        $node = $self->_parse_inline(1, $implicit, $explicit);
-        if (length $self->inline) {
-            $self->die('YAML_PARSE_ERR_SINGLE_LINE');
-        }
-    }
-    elsif ($indicator eq $LIT_CHAR) {
-        $self->{level}++;
-        $node = $self->_parse_block($chomp);
-        $node = $self->_parse_implicit($node) if $implicit;
-        $self->{level}--;
-    }
-    elsif ($indicator eq $FOLD_CHAR) {
-        $self->{level}++;
-        $node = $self->_parse_unfold($chomp);
-        $node = $self->_parse_implicit($node) if $implicit;
-        $self->{level}--;
-    }
-    else {
-        $self->{level}++;
-        $self->offset->[$self->level] ||= 0;
-        if ($self->indent == $self->offset->[$self->level]) {
-            if ($self->content =~ /^-( |$)/) {
-                $node = $self->_parse_seq($anchor);
-            }
-            elsif ($self->content =~ /(^\?|\:( |$))/) {
-                $node = $self->_parse_mapping($anchor);
-            }
-            elsif ($preface =~ /^\s*$/) {
-                $node = $self->_parse_implicit('');
-            }
-            else {
-                $self->die('YAML_PARSE_ERR_BAD_NODE');
-            }
-        }
-        else {
-            $node = undef;
-        }
-        $self->{level}--;
-    }
-    $#{$self->offset} = $self->level;
-
-    if ($explicit) {
-        if ($class) {
-            if (not ref $node) {
-                my $copy = $node;
-                undef $node;
-                $node = \$copy;
-            }
-            CORE::bless $node, $class;
-        }
-        else {
-            $node = $self->_parse_explicit($node, $explicit);
-        }
-    }
-    if ($anchor) {
-        if (ref($self->anchor2node->{$anchor}) eq 'YAML-anchor2node') {
-            # XXX Can't remember what this code actually does
-            for my $ref (@{$self->anchor2node->{$anchor}}) {
-                ${$ref->[0]} = $node;
-                $self->warn('YAML_LOAD_WARN_UNRESOLVED_ALIAS',
-                    $anchor, $ref->[1]);
-            }
-        }
-        $self->anchor2node->{$anchor} = $node;
-    }
-    return $node;
-}
-
-# Preprocess the qualifiers that may be attached to any node.
-sub _parse_qualifiers {
-    my $self = shift;
-    my ($preface) = @_;
-    my ($anchor, $alias, $explicit, $implicit, $token) = ('') x 5;
-    $self->inline('');
-    while ($preface =~ /^[&*!]/) {
-        my $line = $self->line - 1;
-        if ($preface =~ s/^\!(\S+)\s*//) {
-            $self->die('YAML_PARSE_ERR_MANY_EXPLICIT') if $explicit;
-            $explicit = $1;
-        }
-        elsif ($preface =~ s/^\!\s*//) {
-            $self->die('YAML_PARSE_ERR_MANY_IMPLICIT') if $implicit;
-            $implicit = 1;
-        }
-        elsif ($preface =~ s/^\&([^ ,:]+)\s*//) {
-            $token = $1;
-            $self->die('YAML_PARSE_ERR_BAD_ANCHOR')
-              unless $token =~ /^[a-zA-Z0-9]+$/;
-            $self->die('YAML_PARSE_ERR_MANY_ANCHOR') if $anchor;
-            $self->die('YAML_PARSE_ERR_ANCHOR_ALIAS') if $alias;
-            $anchor = $token;
-        }
-        elsif ($preface =~ s/^\*([^ ,:]+)\s*//) {
-            $token = $1;
-            $self->die('YAML_PARSE_ERR_BAD_ALIAS')
-              unless $token =~ /^[a-zA-Z0-9]+$/;
-            $self->die('YAML_PARSE_ERR_MANY_ALIAS') if $alias;
-            $self->die('YAML_PARSE_ERR_ANCHOR_ALIAS') if $anchor;
-            $alias = $token;
-        }
-    }
-    return ($anchor, $alias, $explicit, $implicit, $preface);
-}
-
-# Morph a node to it's explicit type
-sub _parse_explicit {
-    my $self = shift;
-    my ($node, $explicit) = @_;
-    my ($type, $class);
-    if ($explicit =~ /^\!?perl\/(hash|array|ref|scalar)(?:\:(\w(\w|\:\:)*)?)?$/) {
-        ($type, $class) = (($1 || ''), ($2 || ''));
-
-        # FIXME # die unless uc($type) eq ref($node) ?
-
-        if ( $type eq "ref" ) {
-            $self->die('YAML_LOAD_ERR_NO_DEFAULT_VALUE', 'XXX', $explicit)
-            unless exists $node->{VALUE()} and scalar(keys %$node) == 1;
-
-            my $value = $node->{VALUE()};
-            $node = \$value;
-        }
-
-        if ( $type eq "scalar" and length($class) and !ref($node) ) {
-            my $value = $node;
-            $node = \$value;
-        }
-
-        if ( length($class) ) {
-            CORE::bless($node, $class);
-        }
-
-        return $node;
-    }
-    if ($explicit =~ m{^!?perl/(glob|regexp|code)(?:\:(\w(\w|\:\:)*)?)?$}) {
-        ($type, $class) = (($1 || ''), ($2 || ''));
-        my $type_class = "YAML::Type::$type";
-        no strict 'refs';
-        if ($type_class->can('yaml_load')) {
-            return $type_class->yaml_load($node, $class, $self);
-        }
-        else {
-            $self->die('YAML_LOAD_ERR_NO_CONVERT', 'XXX', $explicit);
-        }
-    }
-    # This !perl/@Foo and !perl/$Foo are deprecated but still parsed
-    elsif ($YAML::TagClass->{$explicit} ||
-           $explicit =~ m{^perl/(\@|\$)?([a-zA-Z](\w|::)+)$}
-          ) {
-        $class = $YAML::TagClass->{$explicit} || $2;
-        if ($class->can('yaml_load')) {
-            require YAML::Node;
-            return $class->yaml_load(YAML::Node->new($node, $explicit));
-        }
-        else {
-            if (ref $node) {
-                return CORE::bless $node, $class;
-            }
-            else {
-                return CORE::bless \$node, $class;
-            }
-        }
-    }
-    elsif (ref $node) {
-        require YAML::Node;
-        return YAML::Node->new($node, $explicit);
-    }
-    else {
-        # XXX This is likely wrong. Failing test:
-        # --- !unknown 'scalar value'
-        return $node;
-    }
-}
-
-# Parse a YAML mapping into a Perl hash
-sub _parse_mapping {
-    my $self = shift;
-    my ($anchor) = @_;
-    my $mapping = {};
-    $self->anchor2node->{$anchor} = $mapping;
-    my $key;
-    while (not $self->done and $self->indent == $self->offset->[$self->level]) {
-        # If structured key:
-        if ($self->{content} =~ s/^\?\s*//) {
-            $self->preface($self->content);
-            $self->_parse_next_line(COLLECTION);
-            $key = $self->_parse_node();
-            $key = "$key";
-        }
-        # If "default" key (equals sign)
-        elsif ($self->{content} =~ s/^\=\s*//) {
-            $key = VALUE;
-        }
-        # If "comment" key (slash slash)
-        elsif ($self->{content} =~ s/^\=\s*//) {
-            $key = COMMENT;
-        }
-        # Regular scalar key:
-        else {
-            $self->inline($self->content);
-            $key = $self->_parse_inline();
-            $key = "$key";
-            $self->content($self->inline);
-            $self->inline('');
-        }
-
-        unless ($self->{content} =~ s/^:\s*//) {
-            $self->die('YAML_LOAD_ERR_BAD_MAP_ELEMENT');
-        }
-        $self->preface($self->content);
-        my $line = $self->line;
-        $self->_parse_next_line(COLLECTION);
-        my $value = $self->_parse_node();
-        if (exists $mapping->{$key}) {
-            $self->warn('YAML_LOAD_WARN_DUPLICATE_KEY');
-        }
-        else {
-            $mapping->{$key} = $value;
-        }
-    }
-    return $mapping;
-}
-
-# Parse a YAML sequence into a Perl array
-sub _parse_seq {
-    my $self = shift;
-    my ($anchor) = @_;
-    my $seq = [];
-    $self->anchor2node->{$anchor} = $seq;
-    while (not $self->done and $self->indent == $self->offset->[$self->level]) {
-        if ($self->content =~ /^-(?: (.*))?$/) {
-            $self->preface(defined($1) ? $1 : '');
-        }
-        else {
-            $self->die('YAML_LOAD_ERR_BAD_SEQ_ELEMENT');
-        }
-        if ($self->preface =~ /^(\s*)(\w.*\:(?: |$).*)$/) {
-            $self->indent($self->offset->[$self->level] + 2 + length($1));
-            $self->content($2);
-            $self->level($self->level + 1);
-            $self->offset->[$self->level] = $self->indent;
-            $self->preface('');
-            push @$seq, $self->_parse_mapping('');
-            $self->{level}--;
-            $#{$self->offset} = $self->level;
-        }
-        else {
-            $self->_parse_next_line(COLLECTION);
-            push @$seq, $self->_parse_node();
-        }
-    }
-    return $seq;
-}
-
-# Parse an inline value. Since YAML supports inline collections, this is
-# the top level of a sub parsing.
-sub _parse_inline {
-    my $self = shift;
-    my ($top, $top_implicit, $top_explicit) = (@_, '', '', '');
-    $self->{inline} =~ s/^\s*(.*)\s*$/$1/; # OUCH - mugwump
-    my ($node, $anchor, $alias, $explicit, $implicit) = ('') x 5;
-    ($anchor, $alias, $explicit, $implicit, $self->{inline}) =
-      $self->_parse_qualifiers($self->inline);
-    if ($anchor) {
-        $self->anchor2node->{$anchor} = CORE::bless [], 'YAML-anchor2node';
-    }
-    $implicit ||= $top_implicit;
-    $explicit ||= $top_explicit;
-    ($top_implicit, $top_explicit) = ('', '');
-    if ($alias) {
-        $self->die('YAML_PARSE_ERR_NO_ANCHOR', $alias)
-          unless defined $self->anchor2node->{$alias};
-        if (ref($self->anchor2node->{$alias}) ne 'YAML-anchor2node') {
-            $node = $self->anchor2node->{$alias};
-        }
-        else {
-            $node = do {my $sv = "*$alias"};
-            push @{$self->anchor2node->{$alias}}, [\$node, $self->line];
-        }
-    }
-    elsif ($self->inline =~ /^\{/) {
-        $node = $self->_parse_inline_mapping($anchor);
-    }
-    elsif ($self->inline =~ /^\[/) {
-        $node = $self->_parse_inline_seq($anchor);
-    }
-    elsif ($self->inline =~ /^"/) {
-        $node = $self->_parse_inline_double_quoted();
-        $node = $self->_unescape($node);
-        $node = $self->_parse_implicit($node) if $implicit;
-    }
-    elsif ($self->inline =~ /^'/) {
-        $node = $self->_parse_inline_single_quoted();
-        $node = $self->_parse_implicit($node) if $implicit;
-    }
-    else {
-        if ($top) {
-            $node = $self->inline;
-            $self->inline('');
-        }
-        else {
-            $node = $self->_parse_inline_simple();
-        }
-        $node = $self->_parse_implicit($node) unless $explicit;
-    }
-    if ($explicit) {
-        $node = $self->_parse_explicit($node, $explicit);
-    }
-    if ($anchor) {
-        if (ref($self->anchor2node->{$anchor}) eq 'YAML-anchor2node') {
-            for my $ref (@{$self->anchor2node->{$anchor}}) {
-                ${$ref->[0]} = $node;
-                $self->warn('YAML_LOAD_WARN_UNRESOLVED_ALIAS',
-                    $anchor, $ref->[1]);
-            }
-        }
-        $self->anchor2node->{$anchor} = $node;
-    }
-    return $node;
-}
-
-# Parse the inline YAML mapping into a Perl hash
-sub _parse_inline_mapping {
-    my $self = shift;
-    my ($anchor) = @_;
-    my $node = {};
-    $self->anchor2node->{$anchor} = $node;
-
-    $self->die('YAML_PARSE_ERR_INLINE_MAP')
-      unless $self->{inline} =~ s/^\{\s*//;
-    while (not $self->{inline} =~ s/^\s*\}//) {
-        my $key = $self->_parse_inline();
-        $self->die('YAML_PARSE_ERR_INLINE_MAP')
-          unless $self->{inline} =~ s/^\: \s*//;
-        my $value = $self->_parse_inline();
-        if (exists $node->{$key}) {
-            $self->warn('YAML_LOAD_WARN_DUPLICATE_KEY');
-        }
-        else {
-            $node->{$key} = $value;
-        }
-        next if $self->inline =~ /^\s*\}/;
-        $self->die('YAML_PARSE_ERR_INLINE_MAP')
-          unless $self->{inline} =~ s/^\,\s*//;
-    }
-    return $node;
-}
-
-# Parse the inline YAML sequence into a Perl array
-sub _parse_inline_seq {
-    my $self = shift;
-    my ($anchor) = @_;
-    my $node = [];
-    $self->anchor2node->{$anchor} = $node;
-
-    $self->die('YAML_PARSE_ERR_INLINE_SEQUENCE')
-      unless $self->{inline} =~ s/^\[\s*//;
-    while (not $self->{inline} =~ s/^\s*\]//) {
-        my $value = $self->_parse_inline();
-        push @$node, $value;
-        next if $self->inline =~ /^\s*\]/;
-        $self->die('YAML_PARSE_ERR_INLINE_SEQUENCE')
-          unless $self->{inline} =~ s/^\,\s*//;
-    }
-    return $node;
-}
-
-# Parse the inline double quoted string.
-sub _parse_inline_double_quoted {
-    my $self = shift;
-    my $node;
-    # https://rt.cpan.org/Public/Bug/Display.html?id=90593
-    if ($self->inline =~ /^"((?:(?:\\"|[^"]){0,32766}){0,32766})"\s*(.*)$/) {
-        $node = $1;
-        $self->inline($2);
-        $node =~ s/\\"/"/g;
-    }
-    else {
-        $self->die('YAML_PARSE_ERR_BAD_DOUBLE');
-    }
-    return $node;
-}
-
-
-# Parse the inline single quoted string.
-sub _parse_inline_single_quoted {
-    my $self = shift;
-    my $node;
-    if ($self->inline =~ /^'((?:(?:''|[^']){0,32766}){0,32766})'\s*(.*)$/) {
-        $node = $1;
-        $self->inline($2);
-        $node =~ s/''/'/g;
-    }
-    else {
-        $self->die('YAML_PARSE_ERR_BAD_SINGLE');
-    }
-    return $node;
-}
-
-# Parse the inline unquoted string and do implicit typing.
-sub _parse_inline_simple {
-    my $self = shift;
-    my $value;
-    if ($self->inline =~ /^(|[^!@#%^&*].*?)(?=[\[\]\{\},]|, |: |- |:\s*$|$)/) {
-        $value = $1;
-        substr($self->{inline}, 0, length($1)) = '';
-    }
-    else {
-        $self->die('YAML_PARSE_ERR_BAD_INLINE_IMPLICIT', $value);
-    }
-    return $value;
-}
-
-sub _parse_implicit {
-    my $self = shift;
-    my ($value) = @_;
-    $value =~ s/\s*$//;
-    return $value if $value eq '';
-    return undef if $value =~ /^~$/;
-    return $value
-      unless $value =~ /^[\@\`]/ or
-             $value =~ /^[\-\?]\s/;
-    $self->die('YAML_PARSE_ERR_BAD_IMPLICIT', $value);
-}
-
-# Unfold a YAML multiline scalar into a single string.
-sub _parse_unfold {
-    my $self = shift;
-    my ($chomp) = @_;
-    my $node = '';
-    my $space = 0;
-    while (not $self->done and $self->indent == $self->offset->[$self->level]) {
-        $node .= $self->content. "\n";
-        $self->_parse_next_line(LEAF);
-    }
-    $node =~ s/^(\S.*)\n(?=\S)/$1 /gm;
-    $node =~ s/^(\S.*)\n(\n+\S)/$1$2/gm;
-    $node =~ s/\n*\Z// unless $chomp eq '+';
-    $node .= "\n" unless $chomp;
-    return $node;
-}
-
-# Parse a YAML block style scalar. This is like a Perl here-document.
-sub _parse_block {
-    my $self = shift;
-    my ($chomp) = @_;
-    my $node = '';
-    while (not $self->done and $self->indent == $self->offset->[$self->level]) {
-        $node .= $self->content . "\n";
-        $self->_parse_next_line(LEAF);
-    }
-    return $node if '+' eq $chomp;
-    $node =~ s/\n*\Z/\n/;
-    $node =~ s/\n\Z// if $chomp eq '-';
-    return $node;
-}
-
-# Handle Perl style '#' comments. Comments must be at the same indentation
-# level as the collection line following them.
-sub _parse_throwaway_comments {
-    my $self = shift;
-    while (@{$self->lines} and
-           $self->lines->[0] =~ m{^\s*(\#|$)}
-          ) {
-        shift @{$self->lines};
-        $self->{line}++;
-    }
-    $self->eos($self->{done} = not @{$self->lines});
-}
-
-# This is the routine that controls what line is being parsed. It gets called
-# once for each line in the YAML stream.
-#
-# This routine must:
-# 1) Skip past the current line
-# 2) Determine the indentation offset for a new level
-# 3) Find the next _content_ line
-#   A) Skip over any throwaways (Comments/blanks)
-#   B) Set $self->indent, $self->content, $self->line
-# 4) Expand tabs appropriately
-sub _parse_next_line {
-    my $self = shift;
-    my ($type) = @_;
-    my $level = $self->level;
-    my $offset = $self->offset->[$level];
-    $self->die('YAML_EMIT_ERR_BAD_LEVEL') unless defined $offset;
-    shift @{$self->lines};
-    $self->eos($self->{done} = not @{$self->lines});
-    return if $self->eos;
-    $self->{line}++;
-
-    # Determine the offset for a new leaf node
-    if ($self->preface =~
-        qr/(?:^|\s)(?:$FOLD_CHAR|$LIT_CHAR_RX)(?:-|\+)?(\d*)\s*$/
-       ) {
-        $self->die('YAML_PARSE_ERR_ZERO_INDENT')
-          if length($1) and $1 == 0;
-        $type = LEAF;
-        if (length($1)) {
-            $self->offset->[$level + 1] = $offset + $1;
-        }
-        else {
-            # First get rid of any comments.
-            while (@{$self->lines} && ($self->lines->[0] =~ /^\s*#/)) {
-                $self->lines->[0] =~ /^( *)/;
-                last unless length($1) <= $offset;
-                shift @{$self->lines};
-                $self->{line}++;
-            }
-            $self->eos($self->{done} = not @{$self->lines});
-            return if $self->eos;
-            if ($self->lines->[0] =~ /^( *)\S/ and length($1) > $offset) {
-                $self->offset->[$level+1] = length($1);
-            }
-            else {
-                $self->offset->[$level+1] = $offset + 1;
-            }
-        }
-        $offset = $self->offset->[++$level];
-    }
-    # Determine the offset for a new collection level
-    elsif ($type == COLLECTION and
-           $self->preface =~ /^(\s*(\!\S*|\&\S+))*\s*$/) {
-        $self->_parse_throwaway_comments();
-        if ($self->eos) {
-            $self->offset->[$level+1] = $offset + 1;
-            return;
-        }
-        else {
-            $self->lines->[0] =~ /^( *)\S/ or
-                $self->die('YAML_PARSE_ERR_NONSPACE_INDENTATION');
-            if (length($1) > $offset) {
-                $self->offset->[$level+1] = length($1);
-            }
-            else {
-                $self->offset->[$level+1] = $offset + 1;
-            }
-        }
-        $offset = $self->offset->[++$level];
-    }
-
-    if ($type == LEAF) {
-        while (@{$self->lines} and
-               $self->lines->[0] =~ m{^( *)(\#)} and
-               length($1) < $offset
-              ) {
-            shift @{$self->lines};
-            $self->{line}++;
-        }
-        $self->eos($self->{done} = not @{$self->lines});
-    }
-    else {
-        $self->_parse_throwaway_comments();
-    }
-    return if $self->eos;
-
-    if ($self->lines->[0] =~ /^---(\s|$)/) {
-        $self->done(1);
-        return;
-    }
-    if ($type == LEAF and
-        $self->lines->[0] =~ /^ {$offset}(.*)$/
-       ) {
-        $self->indent($offset);
-        $self->content($1);
-    }
-    elsif ($self->lines->[0] =~ /^\s*$/) {
-        $self->indent($offset);
-        $self->content('');
-    }
-    else {
-        $self->lines->[0] =~ /^( *)(\S.*)$/;
-        while ($self->offset->[$level] > length($1)) {
-            $level--;
-        }
-        $self->die('YAML_PARSE_ERR_INCONSISTENT_INDENTATION')
-          if $self->offset->[$level] != length($1);
-        $self->indent(length($1));
-        $self->content($2);
-    }
-    $self->die('YAML_PARSE_ERR_INDENTATION')
-      if $self->indent - $offset > 1;
-}
-
-#==============================================================================
-# Utility subroutines.
-#==============================================================================
-
-# Printable characters for escapes
-my %unescapes = (
-   0 => "\x00",
-   a => "\x07",
-   t => "\x09",
-   n => "\x0a",
-   'v' => "\x0b", # Potential v-string error on 5.6.2 if not quoted
-   f => "\x0c",
-   r => "\x0d",
-   e => "\x1b",
-   '\\' => '\\',
-  );
-
-# Transform all the backslash style escape characters to their literal meaning
-sub _unescape {
-    my $self = shift;
-    my ($node) = @_;
-    $node =~ s/\\([never\\fart0]|x([0-9a-fA-F]{2}))/
-              (length($1)>1)?pack("H2",$2):$unescapes{$1}/gex;
-    return $node;
-}
-
-1;
diff --git a/modules/override/YAML/Loader/Base.pm b/modules/override/YAML/Loader/Base.pm
deleted file mode 100644 (file)
index 6a3504c..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-package YAML::Loader::Base;
-
-use YAML::Mo;
-
-has load_code     => default => sub {0};
-has stream        => default => sub {''};
-has document      => default => sub {0};
-has line          => default => sub {0};
-has documents     => default => sub {[]};
-has lines         => default => sub {[]};
-has eos           => default => sub {0};
-has done          => default => sub {0};
-has anchor2node   => default => sub {{}};
-has level         => default => sub {0};
-has offset        => default => sub {[]};
-has preface       => default => sub {''};
-has content       => default => sub {''};
-has indent        => default => sub {0};
-has major_version => default => sub {0};
-has minor_version => default => sub {0};
-has inline        => default => sub {''};
-
-sub set_global_options {
-    my $self = shift;
-    $self->load_code($YAML::LoadCode || $YAML::UseCode)
-      if defined $YAML::LoadCode or defined $YAML::UseCode;
-}
-
-sub load {
-    die 'load() not implemented in this class.';
-}
-
-1;
diff --git a/modules/override/YAML/Marshall.pm b/modules/override/YAML/Marshall.pm
deleted file mode 100644 (file)
index 14d378b..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-use strict; use warnings;
-package YAML::Marshall;
-
-use YAML::Node ();
-
-sub import {
-    my $class = shift;
-    no strict 'refs';
-    my $package = caller;
-    unless (grep { $_ eq $class} @{$package . '::ISA'}) {
-        push @{$package . '::ISA'}, $class;
-    }
-
-    my $tag = shift;
-    if ( $tag ) {
-        no warnings 'once';
-        $YAML::TagClass->{$tag} = $package;
-        ${$package . "::YamlTag"} = $tag;
-    }
-}
-
-sub yaml_dump {
-    my $self = shift;
-    no strict 'refs';
-    my $tag = ${ref($self) . "::YamlTag"} || 'perl/' . ref($self);
-    $self->yaml_node($self, $tag);
-}
-
-sub yaml_load {
-    my ($class, $node) = @_;
-    if (my $ynode = $class->yaml_ynode($node)) {
-        $node = $ynode->{NODE};
-    }
-    bless $node, $class;
-}
-
-sub yaml_node {
-    shift;
-    YAML::Node->new(@_);
-}
-
-sub yaml_ynode {
-    shift;
-    YAML::Node::ynode(@_);
-}
-
-1;
diff --git a/modules/override/YAML/Mo.pm b/modules/override/YAML/Mo.pm
deleted file mode 100644 (file)
index c669ff0..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-package YAML::Mo; $VERSION = '0.88';
-# use Mo qw[builder default import];
-#   The following line of code was produced from the previous line by
-#   Mo::Inline version 0.31
-no warnings;my$M=__PACKAGE__.'::';*{$M.Object::new}=sub{bless{@_[1..$#_]},$_[0]};*{$M.import}=sub{import warnings;$^H|=1538;my($P,%e,%o)=caller.'::';shift;eval"no Mo::$_",&{$M.$_.::e}($P,\%e,\%o,\@_)for@_;return if$e{M};%e=(extends,sub{eval"no $_[0]()";@{$P.ISA}=$_[0]},has,sub{my$n=shift;my$m=sub{$#_?$_[0]{$n}=$_[1]:$_[0]{$n}};$m=$o{$_}->($m,$n,@_)for sort keys%o;*{$P.$n}=$m},%e,);*{$P.$_}=$e{$_}for keys%e;@{$P.ISA}=$M.Object};*{$M.'builder::e'}=sub{my($P,$e,$o)=@_;$o->{builder}=sub{my($m,$n,%a)=@_;my$b=$a{builder}or return$m;sub{$#_?$m->(@_):!exists$_[0]{$n}?$_[0]{$n}=$_[0]->$b:$m->(@_)}}};*{$M.'default::e'}=sub{my($P,$e,$o)=@_;$o->{default}=sub{my($m,$n,%a)=@_;$a{default}or return$m;sub{$#_?$m->(@_):!exists$_[0]{$n}?$_[0]{$n}=$a{default}->(@_):$m->(@_)}}};my$i=\&import;*{$M.import}=sub{(@_==2 and not $_[1])?pop@_:@_==1?push@_,grep!/import/,@f:();goto&$i};@f=qw[builder default import];use strict;use warnings;
-
-our $DumperModule = 'Data::Dumper';
-
-my ($_new_error, $_info, $_scalar_info);
-
-no strict 'refs';
-*{$M.'Object::die'} = sub {
-    my $self = shift;
-    my $error = $self->$_new_error(@_);
-    $error->type('Error');
-    Carp::croak($error->format_message);
-};
-
-*{$M.'Object::warn'} = sub {
-    my $self = shift;
-    return unless $^W;
-    my $error = $self->$_new_error(@_);
-    $error->type('Warning');
-    Carp::cluck($error->format_message);
-};
-
-# This code needs to be refactored to be simpler and more precise, and no,
-# Scalar::Util doesn't DWIM.
-#
-# Can't handle:
-# * blessed regexp
-*{$M.'Object::node_info'} = sub {
-    my $self = shift;
-    my $stringify = $_[1] || 0;
-    my ($class, $type, $id) =
-        ref($_[0])
-        ? $stringify
-          ? &$_info("$_[0]")
-          : do {
-              require overload;
-              my @info = &$_info(overload::StrVal($_[0]));
-              if (ref($_[0]) eq 'Regexp') {
-                  @info[0, 1] = (undef, 'REGEXP');
-              }
-              @info;
-          }
-        : &$_scalar_info($_[0]);
-    ($class, $type, $id) = &$_scalar_info("$_[0]")
-        unless $id;
-    return wantarray ? ($class, $type, $id) : $id;
-};
-
-#-------------------------------------------------------------------------------
-$_info = sub {
-    return (($_[0]) =~ qr{^(?:(.*)\=)?([^=]*)\(([^\(]*)\)$}o);
-};
-
-$_scalar_info = sub {
-    my $id = 'undef';
-    if (defined $_[0]) {
-        \$_[0] =~ /\((\w+)\)$/o or CORE::die();
-        $id = "$1-S";
-    }
-    return (undef, undef, $id);
-};
-
-$_new_error = sub {
-    require Carp;
-    my $self = shift;
-    require YAML::Error;
-
-    my $code = shift || 'unknown error';
-    my $error = YAML::Error->new(code => $code);
-    $error->line($self->line) if $self->can('line');
-    $error->document($self->document) if $self->can('document');
-    $error->arguments([@_]);
-    return $error;
-};
-
-1;
diff --git a/modules/override/YAML/Node.pm b/modules/override/YAML/Node.pm
deleted file mode 100644 (file)
index 81c2727..0000000
+++ /dev/null
@@ -1,218 +0,0 @@
-use strict; use warnings;
-package YAML::Node;
-
-use YAML::Tag;
-require YAML::Mo;
-
-use Exporter;
-our @ISA     = qw(Exporter YAML::Mo::Object);
-our @EXPORT  = qw(ynode);
-
-sub ynode {
-    my $self;
-    if (ref($_[0]) eq 'HASH') {
-        $self = tied(%{$_[0]});
-    }
-    elsif (ref($_[0]) eq 'ARRAY') {
-        $self = tied(@{$_[0]});
-    }
-    elsif (ref(\$_[0]) eq 'GLOB') {
-        $self = tied(*{$_[0]});
-    }
-    else {
-        $self = tied($_[0]);
-    }
-    return (ref($self) =~ /^yaml_/) ? $self : undef;
-}
-
-sub new {
-    my ($class, $node, $tag) = @_;
-    my $self;
-    $self->{NODE} = $node;
-    my (undef, $type) = YAML::Mo::Object->node_info($node);
-    $self->{KIND} = (not defined $type) ? 'scalar' :
-                    ($type eq 'ARRAY') ? 'sequence' :
-                    ($type eq 'HASH') ? 'mapping' :
-                    $class->die("Can't create YAML::Node from '$type'");
-    tag($self, ($tag || ''));
-    if ($self->{KIND} eq 'scalar') {
-        yaml_scalar->new($self, $_[1]);
-        return \ $_[1];
-    }
-    my $package = "yaml_" . $self->{KIND};
-    $package->new($self)
-}
-
-sub node { $_->{NODE} }
-sub kind { $_->{KIND} }
-sub tag {
-    my ($self, $value) = @_;
-    if (defined $value) {
-               $self->{TAG} = YAML::Tag->new($value);
-        return $self;
-    }
-    else {
-       return $self->{TAG};
-    }
-}
-sub keys {
-    my ($self, $value) = @_;
-    if (defined $value) {
-               $self->{KEYS} = $value;
-        return $self;
-    }
-    else {
-       return $self->{KEYS};
-    }
-}
-
-#==============================================================================
-package yaml_scalar;
-
-@yaml_scalar::ISA = qw(YAML::Node);
-
-sub new {
-    my ($class, $self) = @_;
-    tie $_[2], $class, $self;
-}
-
-sub TIESCALAR {
-    my ($class, $self) = @_;
-    bless $self, $class;
-    $self
-}
-
-sub FETCH {
-    my ($self) = @_;
-    $self->{NODE}
-}
-
-sub STORE {
-    my ($self, $value) = @_;
-    $self->{NODE} = $value
-}
-
-#==============================================================================
-package yaml_sequence;
-
-@yaml_sequence::ISA = qw(YAML::Node);
-
-sub new {
-    my ($class, $self) = @_;
-    my $new;
-    tie @$new, $class, $self;
-    $new
-}
-
-sub TIEARRAY {
-    my ($class, $self) = @_;
-    bless $self, $class
-}
-
-sub FETCHSIZE {
-    my ($self) = @_;
-    scalar @{$self->{NODE}};
-}
-
-sub FETCH {
-    my ($self, $index) = @_;
-    $self->{NODE}[$index]
-}
-
-sub STORE {
-    my ($self, $index, $value) = @_;
-    $self->{NODE}[$index] = $value
-}
-
-sub undone {
-    die "Not implemented yet"; # XXX
-}
-
-*STORESIZE = *POP = *PUSH = *SHIFT = *UNSHIFT = *SPLICE = *DELETE = *EXISTS =
-*STORESIZE = *POP = *PUSH = *SHIFT = *UNSHIFT = *SPLICE = *DELETE = *EXISTS =
-*undone; # XXX Must implement before release
-
-#==============================================================================
-package yaml_mapping;
-
-@yaml_mapping::ISA = qw(YAML::Node);
-
-sub new {
-    my ($class, $self) = @_;
-    @{$self->{KEYS}} = sort keys %{$self->{NODE}};
-    my $new;
-    tie %$new, $class, $self;
-    $new
-}
-
-sub TIEHASH {
-    my ($class, $self) = @_;
-    bless $self, $class
-}
-
-sub FETCH {
-    my ($self, $key) = @_;
-    if (exists $self->{NODE}{$key}) {
-        return (grep {$_ eq $key} @{$self->{KEYS}})
-               ? $self->{NODE}{$key} : undef;
-    }
-    return $self->{HASH}{$key};
-}
-
-sub STORE {
-    my ($self, $key, $value) = @_;
-    if (exists $self->{NODE}{$key}) {
-        $self->{NODE}{$key} = $value;
-    }
-    elsif (exists $self->{HASH}{$key}) {
-        $self->{HASH}{$key} = $value;
-    }
-    else {
-        if (not grep {$_ eq $key} @{$self->{KEYS}}) {
-            push(@{$self->{KEYS}}, $key);
-        }
-        $self->{HASH}{$key} = $value;
-    }
-    $value
-}
-
-sub DELETE {
-    my ($self, $key) = @_;
-    my $return;
-    if (exists $self->{NODE}{$key}) {
-        $return = $self->{NODE}{$key};
-    }
-    elsif (exists $self->{HASH}{$key}) {
-        $return = delete $self->{NODE}{$key};
-    }
-    for (my $i = 0; $i < @{$self->{KEYS}}; $i++) {
-        if ($self->{KEYS}[$i] eq $key) {
-            splice(@{$self->{KEYS}}, $i, 1);
-        }
-    }
-    return $return;
-}
-
-sub CLEAR {
-    my ($self) = @_;
-    @{$self->{KEYS}} = ();
-    %{$self->{HASH}} = ();
-}
-
-sub FIRSTKEY {
-    my ($self) = @_;
-    $self->{ITER} = 0;
-    $self->{KEYS}[0]
-}
-
-sub NEXTKEY {
-    my ($self) = @_;
-    $self->{KEYS}[++$self->{ITER}]
-}
-
-sub EXISTS {
-    my ($self, $key) = @_;
-    exists $self->{NODE}{$key}
-}
-
-1;
diff --git a/modules/override/YAML/Tag.pm b/modules/override/YAML/Tag.pm
deleted file mode 100644 (file)
index 57aef46..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-use strict; use warnings;
-package YAML::Tag;
-
-use overload '""' => sub { ${$_[0]} };
-
-sub new {
-    my ($class, $self) = @_;
-    bless \$self, $class
-}
-
-sub short {
-    ${$_[0]}
-}
-
-sub canonical {
-    ${$_[0]}
-}
-
-1;
diff --git a/modules/override/YAML/Types.pm b/modules/override/YAML/Types.pm
deleted file mode 100644 (file)
index 8cbbde2..0000000
+++ /dev/null
@@ -1,235 +0,0 @@
-package YAML::Types;
-
-use YAML::Mo;
-use YAML::Node;
-
-# XXX These classes and their APIs could still use some refactoring,
-# but at least they work for now.
-#-------------------------------------------------------------------------------
-package YAML::Type::blessed;
-
-use YAML::Mo; # XXX
-
-sub yaml_dump {
-    my $self = shift;
-    my ($value) = @_;
-    my ($class, $type) = YAML::Mo::Object->node_info($value);
-    no strict 'refs';
-    my $kind = lc($type) . ':';
-    my $tag = ${$class . '::ClassTag'} ||
-              "!perl/$kind$class";
-    if ($type eq 'REF') {
-        YAML::Node->new(
-            {(&YAML::VALUE, ${$_[0]})}, $tag
-        );
-    }
-    elsif ($type eq 'SCALAR') {
-        $_[1] = $$value;
-        YAML::Node->new($_[1], $tag);
-    }
-    elsif ($type eq 'GLOB') {
-        # blessed glob support is minimal, and will not round-trip
-        # initial aim: to not cause an error
-        return YAML::Type::glob->yaml_dump($value, $tag);
-    } else {
-        YAML::Node->new($value, $tag);
-    }
-}
-
-#-------------------------------------------------------------------------------
-package YAML::Type::undef;
-
-sub yaml_dump {
-    my $self = shift;
-}
-
-sub yaml_load {
-    my $self = shift;
-}
-
-#-------------------------------------------------------------------------------
-package YAML::Type::glob;
-
-sub yaml_dump {
-    my $self = shift;
-    # $_[0] remains as the glob
-    my $tag = pop @_ if 2==@_;
-
-    $tag = '!perl/glob:' unless defined $tag;
-    my $ynode = YAML::Node->new({}, $tag);
-    for my $type (qw(PACKAGE NAME SCALAR ARRAY HASH CODE IO)) {
-        my $value = *{$_[0]}{$type};
-        $value = $$value if $type eq 'SCALAR';
-        if (defined $value) {
-            if ($type eq 'IO') {
-                my @stats = qw(device inode mode links uid gid rdev size
-                               atime mtime ctime blksize blocks);
-                undef $value;
-                $value->{stat} = YAML::Node->new({});
-                if ($value->{fileno} = fileno(*{$_[0]})) {
-                    local $^W;
-                    map {$value->{stat}{shift @stats} = $_} stat(*{$_[0]});
-                    $value->{tell} = tell(*{$_[0]});
-                }
-            }
-            $ynode->{$type} = $value;
-        }
-    }
-    return $ynode;
-}
-
-sub yaml_load {
-    my $self = shift;
-    my ($node, $class, $loader) = @_;
-    my ($name, $package);
-    if (defined $node->{NAME}) {
-        $name = $node->{NAME};
-        delete $node->{NAME};
-    }
-    else {
-        $loader->warn('YAML_LOAD_WARN_GLOB_NAME');
-        return undef;
-    }
-    if (defined $node->{PACKAGE}) {
-        $package = $node->{PACKAGE};
-        delete $node->{PACKAGE};
-    }
-    else {
-        $package = 'main';
-    }
-    no strict 'refs';
-    if (exists $node->{SCALAR}) {
-        *{"${package}::$name"} = \$node->{SCALAR};
-        delete $node->{SCALAR};
-    }
-    for my $elem (qw(ARRAY HASH CODE IO)) {
-        if (exists $node->{$elem}) {
-            if ($elem eq 'IO') {
-                $loader->warn('YAML_LOAD_WARN_GLOB_IO');
-                delete $node->{IO};
-                next;
-            }
-            *{"${package}::$name"} = $node->{$elem};
-            delete $node->{$elem};
-        }
-    }
-    for my $elem (sort keys %$node) {
-        $loader->warn('YAML_LOAD_WARN_BAD_GLOB_ELEM', $elem);
-    }
-    return *{"${package}::$name"};
-}
-
-#-------------------------------------------------------------------------------
-package YAML::Type::code;
-
-my $dummy_warned = 0;
-my $default = '{ "DUMMY" }';
-
-sub yaml_dump {
-    my $self = shift;
-    my $code;
-    my ($dumpflag, $value) = @_;
-    my ($class, $type) = YAML::Mo::Object->node_info($value);
-    my $tag = "!perl/code";
-    $tag .= ":$class" if defined $class;
-    if (not $dumpflag) {
-        $code = $default;
-    }
-    else {
-        bless $value, "CODE" if $class;
-        eval { use B::Deparse };
-        return if $@;
-        my $deparse = B::Deparse->new();
-        eval {
-            local $^W = 0;
-            $code = $deparse->coderef2text($value);
-        };
-        if ($@) {
-            warn YAML::YAML_DUMP_WARN_DEPARSE_FAILED() if $^W;
-            $code = $default;
-        }
-        bless $value, $class if $class;
-        chomp $code;
-        $code .= "\n";
-    }
-    $_[2] = $code;
-    YAML::Node->new($_[2], $tag);
-}
-
-sub yaml_load {
-    my $self = shift;
-    my ($node, $class, $loader) = @_;
-    if ($loader->load_code) {
-        my $code = eval "package main; sub $node";
-        if ($@) {
-            $loader->warn('YAML_LOAD_WARN_PARSE_CODE', $@);
-            return sub {};
-        }
-        else {
-            CORE::bless $code, $class if $class;
-            return $code;
-        }
-    }
-    else {
-        return CORE::bless sub {}, $class if $class;
-        return sub {};
-    }
-}
-
-#-------------------------------------------------------------------------------
-package YAML::Type::ref;
-
-sub yaml_dump {
-    my $self = shift;
-    YAML::Node->new({(&YAML::VALUE, ${$_[0]})}, '!perl/ref')
-}
-
-sub yaml_load {
-    my $self = shift;
-    my ($node, $class, $loader) = @_;
-    $loader->die('YAML_LOAD_ERR_NO_DEFAULT_VALUE', 'ptr')
-      unless exists $node->{&YAML::VALUE};
-    return \$node->{&YAML::VALUE};
-}
-
-#-------------------------------------------------------------------------------
-package YAML::Type::regexp;
-
-# XXX Be sure to handle blessed regexps (if possible)
-sub yaml_dump {
-    die "YAML::Type::regexp::yaml_dump not currently implemented";
-}
-
-use constant _QR_TYPES => {
-    '' => sub { qr{$_[0]} },
-    x => sub { qr{$_[0]}x },
-    i => sub { qr{$_[0]}i },
-    s => sub { qr{$_[0]}s },
-    m => sub { qr{$_[0]}m },
-    ix => sub { qr{$_[0]}ix },
-    sx => sub { qr{$_[0]}sx },
-    mx => sub { qr{$_[0]}mx },
-    si => sub { qr{$_[0]}si },
-    mi => sub { qr{$_[0]}mi },
-    ms => sub { qr{$_[0]}sm },
-    six => sub { qr{$_[0]}six },
-    mix => sub { qr{$_[0]}mix },
-    msx => sub { qr{$_[0]}msx },
-    msi => sub { qr{$_[0]}msi },
-    msix => sub { qr{$_[0]}msix },
-};
-
-sub yaml_load {
-    my $self = shift;
-    my ($node, $class) = @_;
-    return qr{$node} unless $node =~ /^\(\?([\^\-xism]*):(.*)\)\z/s;
-    my ($flags, $re) = ($1, $2);
-    $flags =~ s/-.*//;
-    $flags =~ s/^\^//;
-    my $sub = _QR_TYPES->{$flags} || sub { qr{$_[0]} };
-    my $qr = &$sub($re);
-    bless $qr, $class if length $class;
-    return $qr;
-}
-
-1;
index 9ba492f..734b030 100755 (executable)
@@ -5,7 +5,6 @@ BEGIN {
 
   unshift(@INC, $FindBin::Bin . '/../modules/override'); # Use our own versions of various modules (e.g. YAML).
   push   (@INC, $FindBin::Bin . '/..');                  # '.' will be removed from @INC soon.
-  push   (@INC, $FindBin::Bin . '/../modules/fallback'); # Only use our own versions of modules if there's no system version.
 }
 
 use strict;
index 2231b11..77c9cb7 100755 (executable)
@@ -5,7 +5,6 @@ BEGIN {
 
   unshift(@INC, $FindBin::Bin . '/../modules/override'); # Use our own versions of various modules (e.g. YAML).
   push   (@INC, $FindBin::Bin . '/..');
-  push   (@INC, $FindBin::Bin . '/../modules/fallback'); # Only use our own versions of modules if there's no system version.
 }
 
 use strict;
index 61bfff7..c583ecc 100755 (executable)
@@ -5,7 +5,6 @@ BEGIN {
 
   unshift(@INC, $FindBin::Bin . '/../modules/override'); # Use our own versions of various modules (e.g. YAML).
   push   (@INC, $FindBin::Bin . '/..');                  # '.' will be removed from @INC soon.
-  push   (@INC, $FindBin::Bin . '/../modules/fallback'); # Only use our own versions of modules if there's no system version.
 }
 
 use strict;
index 140ecdd..fa60838 100755 (executable)
@@ -6,7 +6,6 @@ BEGIN {
 
   unshift(@INC, $FindBin::Bin . '/../modules/override'); # Use our own versions of various modules (e.g. YAML).
   push   (@INC, $FindBin::Bin . '/..');                  # '.' will be removed from @INC soon.
-  push   (@INC, $FindBin::Bin . '/../modules/fallback'); # Only use our own versions of modules if there's no system version.
 
   # this is a default dir. may be wrong in your installation, change it then
   $master_templates = $FindBin::Bin . '/../templates/print/';
index 105ca7c..8faea21 100755 (executable)
@@ -14,7 +14,6 @@ BEGIN {
 
   unshift(@INC, $FindBin::Bin . '/../modules/override'); # Use our own versions of various modules (e.g. YAML).
   push   (@INC, $FindBin::Bin . '/..');
-  push   (@INC, $FindBin::Bin . '/../modules/fallback'); # Only use our own versions of modules if there's no system version.
 }
 
 use Carp;
@@ -28,10 +27,9 @@ use IO::Dir;
 use List::MoreUtils qw(apply);
 use List::Util qw(first);
 use Pod::Usage;
-use YAML ();
-use YAML::Loader (); # YAML tries to load Y:L at runtime, but can't find it after we chdir'ed
 use SL::DBUpgrade2;
 use SL::System::Process;
+use SL::YAML;
 
 $OUTPUT_AUTOFLUSH = 1;
 
@@ -534,7 +532,7 @@ sub scanfile {
 sub scanmenu {
   my $file = shift;
 
-  my $menu = YAML::LoadFile($file);
+  my $menu = SL::YAML::LoadFile($file);
 
   for my $node (@$menu) {
     # possible for override files
index 111b0c7..5a0f7c2 100755 (executable)
@@ -7,7 +7,6 @@ BEGIN {
 
   unshift(@INC, $FindBin::Bin . '/../modules/override'); # Use our own versions of various modules (e.g. YAML).
   push   (@INC, $FindBin::Bin . '/..');                  # '.' will be removed from @INC soon.
-  push   (@INC, $FindBin::Bin . '/../modules/fallback'); # Only use our own versions of modules if there's no system version.
 }
 
 use CGI qw( -no_xhtml);
index 2c36148..b3b0c2c 100755 (executable)
@@ -1,13 +1,15 @@
 #!/usr/bin/perl
 
 BEGIN {
+  use FindBin;
+
   if (! -d "bin" || ! -d "SL") {
     print("This tool must be run from the kivitendo ERP base directory.\n");
     exit(1);
   }
 
-  unshift @INC, "modules/override"; # Use our own versions of various modules (e.g. YAML).
-  push    @INC, "modules/fallback"; # Only use our own versions of modules if there's no system version.
+  unshift @INC, $FindBin::Bin . '/../modules/override'; # Use our own versions of various modules (e.g. YAML).
+  push    @INC, $FindBin::Bin . '/..';
 }
 
 
index fcdef49..3674eac 100755 (executable)
@@ -9,7 +9,6 @@ BEGIN {
 
   unshift(@INC, $FindBin::Bin . '/../modules/override'); # Use our own versions of various modules (e.g. YAML).
   push   (@INC, $FindBin::Bin . '/..');                  # '.' will be removed from @INC soon.
-  push   (@INC, $FindBin::Bin . '/../modules/fallback'); # Only use our own versions of modules if there's no system version.
 }
 
 use CGI qw( -no_xhtml);
index 0f02b13..68c6a48 100644 (file)
@@ -6,11 +6,10 @@ package SL::DBUpgrade2::convert_drafts_to_record_templates;
 use strict;
 use utf8;
 
-use YAML;
-
 use parent qw(SL::DBUpgrade2::Base);
 
 use SL::DBUtils;
+use SL::YAML;
 
 sub prepare_statements {
   my ($self) = @_;
@@ -77,7 +76,7 @@ sub migrate_ar_drafts {
   $self->{h_draft}->execute('ar') || die $self->{h_draft}->errstr;
 
   while (my $draft_record = $self->{h_draft}->fetchrow_hashref) {
-    my $draft       = YAML::Load($draft_record->{form});
+    my $draft       = SL::YAML::Load($draft_record->{form});
     my $currency_id = $self->{currency_ids_by_name}->{$draft->{currency}};
     my $employee_id = $draft_record->{employee_id} || $draft->{employee_id} || (split m{--}, $draft->{employee})[1] || undef;
 
@@ -152,7 +151,7 @@ sub migrate_ap_drafts {
   $self->{h_draft}->execute('ap') || die $self->{h_draft}->errstr;
 
   while (my $draft_record = $self->{h_draft}->fetchrow_hashref) {
-    my $draft       = YAML::Load($draft_record->{form});
+    my $draft       = SL::YAML::Load($draft_record->{form});
     my $currency_id = $self->{currency_ids_by_name}->{$draft->{currency}};
     my $employee_id = $draft_record->{employee_id} || $draft->{employee_id} || (split m{--}, $draft->{employee})[1] || undef;
 
@@ -227,7 +226,7 @@ sub migrate_gl_drafts {
   $self->{h_draft}->execute('gl') || die $self->{h_draft}->errstr;
 
   while (my $draft_record = $self->{h_draft}->fetchrow_hashref) {
-    my $draft       = YAML::Load($draft_record->{form});
+    my $draft       = SL::YAML::Load($draft_record->{form});
     my $employee_id = $draft_record->{employee_id} || $draft->{employee_id} || (split m{--}, $draft->{employee})[1] || undef;
 
     my @values = (
index 0d1657b..044d604 100644 (file)
@@ -70,7 +70,7 @@ sub test_compile_file {
   my ($file, $T) = @{ $_[0] };
 
 
-  my $command = "$perlapp -w -c$T -Imodules/fallback -Imodules/override -It -MSupport::CanonialGlobals $file 2>&1";
+  my $command = "$perlapp -w -c$T -Imodules/override -It -MSupport::CanonialGlobals $file 2>&1";
   my $loginfo=`$command`;
 
   if ($loginfo =~ /syntax ok$/im) {
index bdec8a4..bae6a43 100644 (file)
@@ -2,7 +2,6 @@ use strict;
 use utf8;
 
 use lib 't';
-use lib 'modules/fallback';
 BEGIN {
   unshift @INC, 'modules/override';
 }
@@ -104,4 +103,3 @@ is_deeply $tt,
           'action' => 'CsvImport/dispatch',
           'FILENAME' => 'from_wikipedia.csv'
         };
-
index dcc738b..ccdab40 100755 (executable)
--- a/t/test.pl
+++ b/t/test.pl
@@ -12,7 +12,6 @@ BEGIN {
 
   unshift(@INC, $FindBin::Bin . '/../modules/override'); # Use our own versions of various modules (e.g. YAML).
   push   (@INC, $FindBin::Bin . '/..');                  # '.' will be removed from @INC soon.
-  push   (@INC, $FindBin::Bin . '/../modules/fallback'); # Only use our own versions of modules if there's no system version.
 
   $ENV{HARNESS_OPTIONS} = 'c';