Showing 6 changed files with 6210 additions and 4927 deletions
+1
.gitignore
... ...
@@ -27,3 +27,4 @@ user/templates/*
27 27
 !user/templates/.gitignore
28 28
 db/*
29 29
 !db/.gitignore
30
+extlib
-19
Changes
... ...
@@ -1,19 +0,0 @@
1
-1.00
2
-  - First major release!
3
-0.05
4
-  - added reverse proxy support
5
-0.04
6
-  - added encoding option
7
-  - added text_exts option
8
-  - added prevent_xss option
9
-  - fixed many bugs.
10
-0.03 (beta)
11
-  - don't overwrite gitweblite.conf
12
-  - config file become JSON.
13
-  - URL become more restful.
14
-  - Git command automatically detect
15
-0.02 (beta)
16
-  - fixed blob, blog_plain, commitdiff, commitdiff_plain encoding bug
17
-
18
-0.01 (beta)
19
-  - first beta release.
+10 -1
README
... ...
@@ -2,6 +2,15 @@ gitprep
2 2
 
3 3
   Github clone. Serve git repository.
4 4
 
5
+Features
6
+
7
+  - Github clone
8
+  - Perl 5.8.7+ only needed
9
+
10
+Installation
11
+
12
+  perl cpanm -L extlib --installdeps .
13
+
5 14
 Operation
6 15
 
7 16
   Start
... ...
@@ -11,7 +20,7 @@ Operation
11 20
     Application start in back ground. Port is 10020.
12 21
     You can access the following URL.
13 22
       
14
-      http://localhost:10010
23
+      http://localhost:10020
15 24
     
16 25
     If you change port, edit githublite.conf.
17 26
   
+4
cpanfile
... ...
@@ -0,0 +1,4 @@
1
+requires 'DBI', '== 1.621';
2
+requires 'DBD::SQLite', '== 1.37';
3
+requires 'Object::Simple', '== 3.08';
4
+requires 'DBIx::Custom', '== 0.28';
+6194 -4907
cpanm
... ...
@@ -18,7 +18,7 @@ my %fatpacked;
18 18
 
19 19
 $fatpacked{"App/cpanminus.pm"} = <<'APP_CPANMINUS';
20 20
   package App::cpanminus;
21
-  our $VERSION = "1.5007";
21
+  our $VERSION = "1.6005";
22 22
   
23 23
   =head1 NAME
24 24
   
... ...
@@ -28,7 +28,7 @@ $fatpacked{"App/cpanminus.pm"} = <<'APP_CPANMINUS';
28 28
   
29 29
       cpanm Module
30 30
   
31
-  Run C<cpanm -h> for more options.
31
+  Run C<cpanm -h> or C<perldoc cpanm> for more options.
32 32
   
33 33
   =head1 DESCRIPTION
34 34
   
... ...
@@ -133,10 +133,10 @@ $fatpacked{"App/cpanminus.pm"} = <<'APP_CPANMINUS';
133 133
   
134 134
   =head2 Zero-conf? How does this module get/parse/update the CPAN index?
135 135
   
136
-  It queries the CPAN Meta DB site running on Google AppEngine at
137
-  L<http://cpanmetadb.plackperl.org/>. The site is updated every hour to reflect
138
-  the latest changes from fast syncing mirrors. The script then also falls back
139
-  to scrape the site L<http://search.cpan.org/>.
136
+  It queries the CPAN Meta DB site at L<http://cpanmetadb.plackperl.org/>.
137
+  The site is updated at least every hour to reflect the latest changes
138
+  from fast syncing mirrors. The script then also falls back to query the
139
+  module at L<http://metacpan.org/> using its wonderful API.
140 140
   
141 141
   Fetched files are unpacked in C<~/.cpanm> and automatically cleaned up
142 142
   periodically.  You can configure the location of this with the
... ...
@@ -247,15 +247,11 @@ $fatpacked{"App/cpanminus.pm"} = <<'APP_CPANMINUS';
247 247
   
248 248
   =item L<JSON::PP> Copyright 2007−2011 by Makamaka Hannyaharamitu
249 249
   
250
-  =item L<CPAN::Meta> Copyright (c) 2010 by David Golden and Ricardo Signes
250
+  =item L<CPAN::Meta>, L<CPAN::Meta::Requirements> Copyright (c) 2010 by David Golden and Ricardo Signes
251 251
   
252
-  =item L<Try::Tiny> Copyright (c) 2009 Yuval Kogman
252
+  =item L<CPAN::Meta::YAML> Copyright 2010 Adam Kennedy
253 253
   
254
-  =item L<parent> Copyright (c) 2007-10 Max Maischein
255
-  
256
-  =item L<Version::Requirements> copyright (c) 2010 by Ricardo Signes
257
-  
258
-  =item L<CPAN::Meta::YAML> copyright (c) 2010 by Adam Kennedy
254
+  =item L<File::pushd> Copyright 2012 David Golden
259 255
   
260 256
   =back
261 257
   
... ...
@@ -314,11 +310,13 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT';
314 310
   use strict;
315 311
   use Config;
316 312
   use Cwd ();
313
+  use App::cpanminus;
317 314
   use File::Basename ();
318 315
   use File::Find ();
319 316
   use File::Path ();
320 317
   use File::Spec ();
321 318
   use File::Copy ();
319
+  use File::Temp ();
322 320
   use Getopt::Long ();
323 321
   use Parse::CPAN::Meta;
324 322
   use Symbol ();
... ...
@@ -326,18 +324,47 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT';
326 324
   use constant WIN32 => $^O eq 'MSWin32';
327 325
   use constant SUNOS => $^O eq 'solaris';
328 326
   
329
-  our $VERSION = "1.5007";
327
+  our $VERSION = $App::cpanminus::VERSION;
328
+  
329
+  if ($INC{"App/FatPacker/Trace.pm"}) {
330
+      require JSON::PP;
331
+      require CPAN::Meta::YAML;
332
+      require CPAN::Meta::Prereqs;
333
+      require version::vpp;
334
+      require File::pushd;
335
+  }
330 336
   
331 337
   my $quote = WIN32 ? q/"/ : q/'/;
332 338
   
339
+  sub agent {
340
+      my $self = shift;
341
+      "cpanminus/$VERSION perl/$]";
342
+  }
343
+  
344
+  sub determine_home {
345
+      my $class = shift;
346
+  
347
+      my $homedir = $ENV{HOME}
348
+        || eval { require File::HomeDir; File::HomeDir->my_home }
349
+        || join('', @ENV{qw(HOMEDRIVE HOMEPATH)}); # Win32
350
+  
351
+      if (WIN32) {
352
+          require Win32; # no fatpack
353
+          $homedir = Win32::GetShortPathName($homedir);
354
+      }
355
+  
356
+      return "$homedir/.cpanm";
357
+  }
358
+  
333 359
   sub new {
334 360
       my $class = shift;
335 361
   
336 362
       bless {
337
-          home => "$ENV{HOME}/.cpanm",
363
+          home => $class->determine_home,
338 364
           cmd  => 'install',
339 365
           seen => {},
340 366
           notest => undef,
367
+          test_only => undef,
341 368
           installdeps => undef,
342 369
           force => undef,
343 370
           sudo => undef,
... ...
@@ -371,6 +398,7 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT';
371 398
           format   => 'tree',
372 399
           save_dists => undef,
373 400
           skip_configure => 0,
401
+          verify => 0,
374 402
           @_,
375 403
       }, $class;
376 404
   }
... ...
@@ -391,8 +419,10 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT';
391 419
       Getopt::Long::GetOptions(
392 420
           'f|force'   => sub { $self->{skip_installed} = 0; $self->{force} = 1 },
393 421
           'n|notest!' => \$self->{notest},
422
+          'test-only' => sub { $self->{notest} = 0; $self->{skip_installed} = 0; $self->{test_only} = 1 },
394 423
           'S|sudo!'   => \$self->{sudo},
395 424
           'v|verbose' => sub { $self->{verbose} = $self->{interactive} = 1 },
425
+          'verify!'   => \$self->{verify},
396 426
           'q|quiet!'  => \$self->{quiet},
397 427
           'h|help'    => sub { $self->{action} = 'show_help' },
398 428
           'V|version' => sub { $self->{action} = 'show_version' },
... ...
@@ -405,7 +435,7 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT';
405 435
           },
406 436
           'mirror=s@' => $self->{mirrors},
407 437
           'mirror-only!' => \$self->{mirror_only},
408
-          'mirror-index=s'  => sub { $self->{mirror_index} = $_[1]; $self->{mirror_only} = 1 },
438
+          'mirror-index=s'  => \$self->{mirror_index},
409 439
           'cascade-search!' => \$self->{cascade_search},
410 440
           'prompt!'   => \$self->{prompt},
411 441
           'installdeps' => \$self->{installdeps},
... ...
@@ -416,7 +446,7 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT';
416 446
           'i|install' => sub { $self->{cmd} = 'install' },
417 447
           'info'      => sub { $self->{cmd} = 'info' },
418 448
           'look'      => sub { $self->{cmd} = 'look'; $self->{skip_installed} = 0 },
419
-          'self-upgrade' => sub { $self->{cmd} = 'install'; $self->{skip_installed} = 1; push @ARGV, 'App::cpanminus' },
449
+          'self-upgrade' => sub { $self->check_upgrade; $self->{cmd} = 'install'; $self->{skip_installed} = 1; push @ARGV, 'App::cpanminus' },
420 450
           'uninst-shadows!'  => \$self->{uninstall_shadows},
421 451
           'lwp!'    => \$self->{try_lwp},
422 452
           'wget!'   => \$self->{try_wget},
... ...
@@ -430,7 +460,8 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT';
430 460
               $self->{save_dists} = $self->maybe_abs($_[1]);
431 461
           },
432 462
           'skip-configure!' => \$self->{skip_configure},
433
-          'metacpan'   => \$self->{metacpan},
463
+          'dev!'       => \$self->{dev_release},
464
+          'metacpan!'  => \$self->{metacpan},
434 465
       );
435 466
   
436 467
       if (!@ARGV && $0 ne '-' && !-t STDIN){ # e.g. # cpanm < author/requires.cpanm
... ...
@@ -441,6 +472,33 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT';
441 472
       $self->{argv} = \@ARGV;
442 473
   }
443 474
   
475
+  sub check_upgrade {
476
+      if ($0 !~ /^$Config{installsitebin}/) {
477
+          if ($0 =~ m!perlbrew/bin!) {
478
+              warn <<WARN;
479
+  It appears your cpanm executable was installed via `perlbrew install-cpanm`.
480
+  cpanm --self-upgrade won't upgrade the version of cpanm you're running.
481
+  
482
+  Run the following command to get it upgraded.
483
+  
484
+    perlbrew install-cpanm
485
+  
486
+  WARN
487
+          } else {
488
+              warn <<WARN;
489
+  You are running cpanm from the path where your current perl won't install executables to.
490
+  Because of that, cpanm --self-upgrade won't upgrade the version of cpanm you're running.
491
+  
492
+    cpanm path   : $0
493
+    Install path : $Config{installsitebin}
494
+  
495
+  It means you either installed cpanm globally with system perl, or use distro packages such
496
+  as rpm or apt-get, and you have to use them again to upgrade cpanm.
497
+  WARN
498
+          }
499
+      }
500
+  }
501
+  
444 502
   sub check_libs {
445 503
       my $self = shift;
446 504
       return if $self->{_checked}++;
... ...
@@ -453,11 +511,39 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT';
453 511
       }
454 512
   }
455 513
   
514
+  sub setup_verify {
515
+      my $self = shift;
516
+  
517
+      my $has_modules = eval { require Module::Signature; require Digest::SHA; 1 };
518
+      $self->{cpansign} = $self->which('cpansign');
519
+  
520
+      unless ($has_modules && $self->{cpansign}) {
521
+          warn "WARNING: Module::Signature and Digest::SHA is required for distribution verifications.\n";
522
+          $self->{verify} = 0;
523
+      }
524
+  }
525
+  
526
+  sub parse_module_args {
527
+      my($self, $module) = @_;
528
+  
529
+      # Plack@1.2 -> Plack~"==1.2"
530
+      # BUT don't expand @ in git URLs
531
+      $module =~ s/^([A-Za-z0-9_:]+)@([v\d\._]+)$/$1~== $2/;
532
+  
533
+      # Plack~1.20, DBI~"> 1.0, <= 2.0"
534
+      if ($module =~ /\~[v\d\._,\!<>= ]+$/) {
535
+          return split /\~/, $module, 2;
536
+      } else {
537
+          return $module, undef;
538
+      }
539
+  }
540
+  
456 541
   sub doit {
457 542
       my $self = shift;
458 543
   
459 544
       $self->setup_home;
460 545
       $self->init_tools;
546
+      $self->setup_verify if $self->{verify};
461 547
   
462 548
       if (my $action = $self->{action}) {
463 549
           $self->$action() and return 1;
... ...
@@ -477,12 +563,12 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT';
477 563
               $module = join '::', grep { $_ } File::Spec->splitdir($dirs), $file;
478 564
           }
479 565
   
480
-          ($module, my $version) = split /\~/, $module, 2;
481
-          if ($self->{skip_satisfied} or defined $version) {
566
+          ($module, my $version) = $self->parse_module_args($module);
567
+          if ($self->{skip_satisfied}) {
482 568
               $self->check_libs;
483 569
               my($ok, $local) = $self->check_module($module, $version || 0);
484 570
               if ($ok) {
485
-                  $self->diag("You have $module (" . ($local || 'undef') . ")\n", 1);
571
+                  $self->diag("You have $module ($local)\n", 1);
486 572
                   next;
487 573
               }
488 574
           }
... ...
@@ -504,6 +590,13 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT';
504 590
       if ($self->{scandeps}) {
505 591
           $self->dump_scandeps();
506 592
       }
593
+      # Workaround for older File::Temp's
594
+      # where creating a tempdir with an implicit $PWD
595
+      # causes tempdir non-cleanup if $PWD changes
596
+      # as paths are stored internally without being resolved
597
+      # absolutely.
598
+      # https://rt.cpan.org/Public/Bug/Display.html?id=44924
599
+      $self->chdir($cwd);
507 600
   
508 601
       return !@fail;
509 602
   }
... ...
@@ -595,7 +688,7 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT';
595 688
       open my $fh, '<', $file or return;
596 689
       my $found;
597 690
       while (<$fh>) {
598
-          if (m!^\Q$module\E\s+([\w\.]+)\s+(.*)!m) {
691
+          if (m!^\Q$module\E\s+([\w\.]+)\s+(\S*)!m) {
599 692
               $found = $self->cpan_module($module, $2, $1);
600 693
               last;
601 694
           }
... ...
@@ -604,66 +697,227 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT';
604 697
       return $found unless $self->{cascade_search};
605 698
   
606 699
       if ($found) {
607
-          if (!$version or
608
-              version->new($found->{version} || 0) >= version->new($version)) {
700
+          if ($self->satisfy_version($module, $found->{module_version}, $version)) {
609 701
               return $found;
610 702
           } else {
611
-              $self->chat("Found $module version $found->{version} < $version.\n");
703
+              $self->chat("Found $module $found->{module_version} which doesn't satisfy $version.\n");
612 704
           }
613 705
       }
614 706
   
615 707
       return;
616 708
   }
617 709
   
618
-  sub search_module {
710
+  sub with_version_range {
711
+      my($self, $version) = @_;
712
+      defined($version) && $version =~ /[<>=]/;
713
+  }
714
+  
715
+  sub encode_json {
716
+      my($self, $data) = @_;
717
+      require JSON::PP;
718
+  
719
+      my $json = JSON::PP::encode_json($data);
720
+      $json =~ s/([^a-zA-Z0-9_\-.])/uc sprintf("%%%02x",ord($1))/eg;
721
+      $json;
722
+  }
723
+  
724
+  # TODO extract this as a module?
725
+  sub version_to_query {
619 726
       my($self, $module, $version) = @_;
620 727
   
621
-      unless ($self->{mirror_only}) {
622
-          if ($self->{metacpan}) {
623
-              require JSON::PP;
624
-              $self->chat("Searching $module on metacpan ...\n");
625
-              my $module_uri  = "http://api.metacpan.org/module/$module";
626
-              my $module_json = $self->get($module_uri);
627
-              my $module_meta = eval { JSON::PP::decode_json($module_json) };
628
-              if ($module_meta && $module_meta->{distribution}) {
629
-                  my $dist_uri = "http://api.metacpan.org/release/$module_meta->{distribution}";
630
-                  my $dist_json = $self->get($dist_uri);
631
-                  my $dist_meta = eval { JSON::PP::decode_json($dist_json) };
632
-                  if ($dist_meta && $dist_meta->{download_url}) {
633
-                      (my $distfile = $dist_meta->{download_url}) =~ s!.+/authors/id/!!;
634
-                      local $self->{mirrors} = $self->{mirrors};
635
-                      if ($dist_meta->{stat}->{mtime} > time()-24*60*60) {
636
-                          $self->{mirrors} = ['http://cpan.metacpan.org'];
637
-                      }
638
-                      return $self->cpan_module($module, $distfile, $dist_meta->{version});
639
-                  }
728
+      require CPAN::Meta::Requirements;
729
+  
730
+      my $requirements = CPAN::Meta::Requirements->new;
731
+      $requirements->add_string_requirement($module, $version || '0');
732
+  
733
+      my $req = $requirements->requirements_for_module($module);
734
+  
735
+      if ($req =~ s/^==\s*//) {
736
+          return {
737
+              term => { 'module.version' => $req },
738
+          };
739
+      } elsif ($req !~ /\s/) {
740
+          return {
741
+              range => { 'module.version_numified' => { 'gte' => $self->numify_ver($req) } },
742
+          };
743
+      } else {
744
+          my %ops = qw(< lt <= lte > gt >= gte);
745
+          my(%range, @exclusion);
746
+          my @requirements = split /,\s*/, $req;
747
+          for my $r (@requirements) {
748
+              if ($r =~ s/^([<>]=?)\s*//) {
749
+                  $range{$ops{$1}} = $self->numify_ver($r);
750
+              } elsif ($r =~ s/\!=\s*//) {
751
+                  push @exclusion, $self->numify_ver($r);
640 752
               }
641
-              $self->diag_fail("Finding $module on metacpan failed.");
642 753
           }
643 754
   
644
-          $self->chat("Searching $module on cpanmetadb ...\n");
645
-          my $uri  = "http://cpanmetadb.plackperl.org/v1.0/package/$module";
646
-          my $yaml = $self->get($uri);
647
-          my $meta = $self->parse_meta_string($yaml);
648
-          if ($meta && $meta->{distfile}) {
649
-              return $self->cpan_module($module, $meta->{distfile}, $meta->{version});
755
+          my @filters= (
756
+              { range => { 'module.version_numified' => \%range } },
757
+          );
758
+  
759
+          if (@exclusion) {
760
+              push @filters, {
761
+                  not => { or => [ map { +{ term => { 'module.version_numified' => $self->numify_ver($_) } } } @exclusion ] },
762
+              };
763
+          }
764
+  
765
+          return @filters;
766
+      }
767
+  }
768
+  
769
+  sub numify_ver {
770
+      my($self, $ver) = @_;
771
+      version->new($ver)->numify;
772
+  }
773
+  
774
+  sub maturity_filter {
775
+      my($self, $module, $version) = @_;
776
+  
777
+      my @filters;
778
+  
779
+      # TODO: dev release should be enabled per dist
780
+      if (!$self->with_version_range($version) or $self->{dev_release}) {
781
+          # backpan'ed dev release are considered "cancelled"
782
+          push @filters, { not => { term => { status => 'backpan' } } };
783
+      }
784
+  
785
+      unless ($self->{dev_release} or $version =~ /==/) {
786
+          push @filters, { term => { maturity => 'released' } };
787
+      }
788
+  
789
+      return @filters;
790
+  }
791
+  
792
+  sub search_metacpan {
793
+      my($self, $module, $version) = @_;
794
+  
795
+      require JSON::PP;
796
+  
797
+      $self->chat("Searching $module ($version) on metacpan ...\n");
798
+  
799
+      my $metacpan_uri = 'http://api.metacpan.org/v0';
800
+  
801
+      my @filter = $self->maturity_filter($module, $version);
802
+  
803
+      my $query = { filtered => {
804
+          (@filter ? (filter => { and => \@filter }) : ()),
805
+          query => { nested => {
806
+              score_mode => 'max',
807
+              path => 'module',
808
+              query => { custom_score => {
809
+                  metacpan_script => "score_version_numified",
810
+                  query => { constant_score => {
811
+                      filter => { and => [
812
+                          { term => { 'module.authorized' => JSON::PP::true() } },
813
+                          { term => { 'module.indexed' => JSON::PP::true() } },
814
+                          { term => { 'module.name' => $module } },
815
+                          $self->version_to_query($module, $version),
816
+                      ] }
817
+                  } },
818
+              } },
819
+          } },
820
+      } };
821
+  
822
+      my $module_uri = "$metacpan_uri/file/_search?source=";
823
+      $module_uri .= $self->encode_json({
824
+          query => $query,
825
+          fields => [ 'release', 'module' ],
826
+      });
827
+  
828
+      my($release, $module_version);
829
+  
830
+      my $module_json = $self->get($module_uri);
831
+      my $module_meta = eval { JSON::PP::decode_json($module_json) };
832
+      my $match = $module_meta ? $module_meta->{hits}{hits}[0]{fields} : undef;
833
+      if ($match) {
834
+          $release = $match->{release};
835
+          my $module_matched = (grep { $_->{name} eq $module } @{$match->{module}})[0];
836
+          $module_version = $module_matched->{version};
837
+      }
838
+  
839
+      unless ($release) {
840
+          $self->chat("! Could not find a release matching $module ($version) on MetaCPAN.\n");
841
+          return;
842
+      }
843
+  
844
+      my $dist_uri = "$metacpan_uri/release/_search?source=";
845
+      $dist_uri .= $self->encode_json({
846
+          filter => {
847
+              term => { 'release.name' => $release },
848
+          },
849
+          fields => [ 'download_url', 'stat', 'status' ],
850
+      });
851
+  
852
+      my $dist_json = $self->get($dist_uri);
853
+      my $dist_meta = eval { JSON::PP::decode_json($dist_json) };
854
+  
855
+      if ($dist_meta) {
856
+          $dist_meta = $dist_meta->{hits}{hits}[0]{fields};
857
+      }
858
+      if ($dist_meta && $dist_meta->{download_url}) {
859
+          (my $distfile = $dist_meta->{download_url}) =~ s!.+/authors/id/!!;
860
+          local $self->{mirrors} = $self->{mirrors};
861
+          if ($dist_meta->{status} eq 'backpan') {
862
+              $self->{mirrors} = [ 'http://backpan.perl.org' ];
863
+          } elsif ($dist_meta->{stat}{mtime} > time()-24*60*60) {
864
+              $self->{mirrors} = [ 'http://cpan.metacpan.org' ];
650 865
           }
866
+          return $self->cpan_module($module, $distfile, $module_version);
867
+      }
868
+  
869
+      $self->diag_fail("Finding $module on metacpan failed.");
870
+      return;
871
+  }
872
+  
873
+  sub search_database {
874
+      my($self, $module, $version) = @_;
875
+  
876
+      my $found;
877
+      my $range = ($self->with_version_range($version) || $self->{dev_release});
878
+  
879
+      if ($range or $self->{metacpan}) {
880
+          $found = $self->search_metacpan($module, $version)   and return $found;
881
+          $found = $self->search_cpanmetadb($module, $version) and return $found;
882
+      } else {
883
+          $found = $self->search_cpanmetadb($module, $version) and return $found;
884
+          $found = $self->search_metacpan($module, $version)   and return $found;
885
+      }
886
+  }
651 887
   
652
-          $self->diag_fail("Finding $module on cpanmetadb failed.");
888
+  sub search_cpanmetadb {
889
+      my($self, $module, $version) = @_;
653 890
   
654
-          $self->chat("Searching $module on search.cpan.org ...\n");
655
-          my $uri  = "http://search.cpan.org/perldoc?$module";
656
-          my $html = $self->get($uri);
657
-          $html =~ m!<a href="/CPAN/authors/id/(.*?\.(?:tar\.gz|tgz|tar\.bz2|zip))">!
658
-              and return $self->cpan_module($module, $1);
891
+      $self->chat("Searching $module on cpanmetadb ...\n");
659 892
   
660
-          $self->diag_fail("Finding $module on search.cpan.org failed.");
893
+      my $uri  = "http://cpanmetadb.plackperl.org/v1.0/package/$module";
894
+      my $yaml = $self->get($uri);
895
+      my $meta = $self->parse_meta_string($yaml);
896
+      if ($meta && $meta->{distfile}) {
897
+          return $self->cpan_module($module, $meta->{distfile}, $meta->{version});
661 898
       }
662 899
   
900
+      $self->diag_fail("Finding $module on cpanmetadb failed.");
901
+      return;
902
+  }
903
+  
904
+  sub search_module {
905
+      my($self, $module, $version) = @_;
906
+  
663 907
       if ($self->{mirror_index}) {
664 908
           $self->chat("Searching $module on mirror index $self->{mirror_index} ...\n");
665 909
           my $pkg = $self->search_mirror_index_file($self->{mirror_index}, $module, $version);
666 910
           return $pkg if $pkg;
911
+  
912
+          unless ($self->{cascade_search}) {
913
+             $self->diag_fail("Finding $module ($version) on mirror index $self->{mirror_index} failed.");
914
+             return;
915
+          }
916
+      }
917
+  
918
+      unless ($self->{mirror_only}) {
919
+          my $found = $self->search_database($module, $version);
920
+          return $found if $found;
667 921
       }
668 922
   
669 923
       MIRROR: for my $mirror (@{ $self->{mirrors} }) {
... ...
@@ -738,6 +992,7 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT';
738 992
     --interactive             Turns on interactive configure (required for Task:: modules)
739 993
     -f,--force                force install
740 994
     -n,--notest               Do not run unit tests
995
+    --test-only               Run tests only, do not install
741 996
     -S,--sudo                 sudo to run install commands
742 997
     --installdeps             Only install dependencies
743 998
     --showdeps                Only display direct dependencies
... ...
@@ -794,8 +1049,11 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT';
794 1049
   
795 1050
   sub maybe_abs {
796 1051
       my($self, $lib) = @_;
797
-      return $lib if $lib eq '_'; # special case: gh-113
798
-      $lib =~ /^[~\/]/ ? $lib : File::Spec->canonpath(Cwd::cwd . "/$lib");
1052
+      if ($lib eq '_' or $lib =~ /^~/ or File::Spec->file_name_is_absolute($lib)) {
1053
+          return $lib;
1054
+      } else {
1055
+          return File::Spec->canonpath(File::Spec->catdir(Cwd::cwd(), $lib));
1056
+      }
799 1057
   }
800 1058
   
801 1059
   sub bootstrap_local_lib {
... ...
@@ -822,9 +1080,10 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT';
822 1080
   ! Can't write to $Config{installsitelib} and $Config{installsitebin}: Installing modules to $ENV{HOME}/perl5
823 1081
   ! To turn off this warning, you have to do one of the following:
824 1082
   !   - run me as a root or with --sudo option (to install to $Config{installsitelib} and $Config{installsitebin})
825
-  |   - run me with --local-lib option e.g. cpanm --local-lib=~/perl5
826
-  !   - Set PERL_CPANM_OPT="--local-lib=~/perl5" environment variable (in your shell rc file)
827
-  !   - Configure local::lib in your shell to set PERL_MM_OPT etc.
1083
+  !   - Configure local::lib your existing local::lib in this shell to set PERL_MM_OPT etc.
1084
+  !   - Install local::lib by running the following commands
1085
+  !
1086
+  !         cpanm --local-lib=~/perl5 local::lib && eval \$(perl -I ~/perl5/lib/perl5/ -Mlocal::lib)
828 1087
   !
829 1088
   DIAG
830 1089
       sleep 2;
... ...
@@ -834,8 +1093,8 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT';
834 1093
       my($self, $base) = @_;
835 1094
       require local::lib;
836 1095
       (
837
-          local::lib->install_base_perl_path($base),
838
-          local::lib->install_base_arch_path($base),
1096
+          local::lib->resolve_path(local::lib->install_base_perl_path($base)),
1097
+          local::lib->resolve_path(local::lib->install_base_arch_path($base)),
839 1098
           @Config{qw(privlibexp archlibexp)},
840 1099
       );
841 1100
   }
... ...
@@ -871,8 +1130,8 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT';
871 1130
               $self->{search_inc} = [ @inc ];
872 1131
           } else {
873 1132
               $self->{search_inc} = [
874
-                  local::lib->install_base_arch_path($base),
875
-                  local::lib->install_base_perl_path($base),
1133
+                  local::lib->resolve_path(local::lib->install_base_arch_path($base)),
1134
+                  local::lib->resolve_path(local::lib->install_base_perl_path($base)),
876 1135
                   @INC,
877 1136
               ];
878 1137
           }
... ...
@@ -1112,7 +1371,11 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT';
1112 1371
   }
1113 1372
   
1114 1373
   sub install {
1115
-      my($self, $cmd, $uninst_opts) = @_;
1374
+      my($self, $cmd, $uninst_opts, $depth) = @_;
1375
+  
1376
+      if ($depth == 0 && $self->{test_only}) {
1377
+          return 1;
1378
+      }
1116 1379
   
1117 1380
       if ($self->{sudo}) {
1118 1381
           unshift @$cmd, "sudo";
... ...
@@ -1173,7 +1436,7 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT';
1173 1436
   sub configure_mirrors {
1174 1437
       my $self = shift;
1175 1438
       unless (@{$self->{mirrors}}) {
1176
-          $self->{mirrors} = [ 'http://search.cpan.org/CPAN' ];
1439
+          $self->{mirrors} = [ 'http://www.cpan.org' ];
1177 1440
       }
1178 1441
       for (@{$self->{mirrors}}) {
1179 1442
           s!^/!file:///!;
... ...
@@ -1215,10 +1478,17 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT';
1215 1478
       $self->setup_module_build_patch unless $self->{pod2man};
1216 1479
   
1217 1480
       if ($dist->{module}) {
1218
-          my($ok, $local) = $self->check_module($dist->{module}, $dist->{module_version} || 0);
1219
-          if ($self->{skip_installed} && $ok) {
1220
-              $self->diag("$dist->{module} is up to date. ($local)\n", 1);
1221
-              return 1;
1481
+          unless ($self->with_version_range($version)) {
1482
+              my($ok, $local) = $self->check_module($dist->{module}, $dist->{module_version} || 0);
1483
+              if ($self->{skip_installed} && $ok) {
1484
+                  $self->diag("$dist->{module} is up to date. ($local)\n", 1);
1485
+                  return 1;
1486
+              }
1487
+          }
1488
+  
1489
+          unless ($self->satisfy_version($dist->{module}, $dist->{module_version}, $version)) {
1490
+              $self->diag("Found $dist->{module} $dist->{module_version} which doesn't satisfy $version.\n");
1491
+              return;
1222 1492
           }
1223 1493
       }
1224 1494
   
... ...
@@ -1299,7 +1569,7 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT';
1299 1569
           $self->diag_ok;
1300 1570
           $dist->{local_path} = File::Spec->rel2abs($name);
1301 1571
   
1302
-          my $dir = $self->unpack($file);
1572
+          my $dir = $self->unpack($file, $uri, $dist);
1303 1573
           next unless $dir; # unpack failed
1304 1574
   
1305 1575
           if (my $save = $self->{save_dists}) {
... ...
@@ -1314,7 +1584,12 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT';
1314 1584
   }
1315 1585
   
1316 1586
   sub unpack {
1317
-      my($self, $file) = @_;
1587
+      my($self, $file, $uri, $dist) = @_;
1588
+  
1589
+      if ($self->{verify}) {
1590
+          $self->verify_archive($file, $uri, $dist) or return;
1591
+      }
1592
+  
1318 1593
       $self->chat("Unpacking $file\n");
1319 1594
       my $dir = $file =~ /\.zip/i ? $self->unzip($file) : $self->untar($file);
1320 1595
       unless ($dir) {
... ...
@@ -1323,13 +1598,121 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT';
1323 1598
       return $dir;
1324 1599
   }
1325 1600
   
1601
+  sub verify_checksums_signature {
1602
+      my($self, $chk_file) = @_;
1603
+  
1604
+      require Module::Signature; # no fatpack
1605
+  
1606
+      $self->chat("Verifying the signature of CHECKSUMS\n");
1607
+  
1608
+      my $rv = eval {
1609
+          local $SIG{__WARN__} = sub {}; # suppress warnings
1610
+          my $v = Module::Signature::_verify($chk_file);
1611
+          $v == Module::Signature::SIGNATURE_OK();
1612
+      };
1613
+      if ($rv) {
1614
+          $self->chat("Verified OK!\n");
1615
+      } else {
1616
+          $self->diag_fail("Verifying CHECKSUMS signature failed: $rv\n");
1617
+          return;
1618
+      }
1619
+  
1620
+      return 1;
1621
+  }
1622
+  
1623
+  sub verify_archive {
1624
+      my($self, $file, $uri, $dist) = @_;
1625
+  
1626
+      unless ($dist->{cpanid}) {
1627
+          $self->chat("Archive '$file' does not seem to be from PAUSE. Skip verification.\n");
1628
+      }
1629
+  
1630
+      (my $mirror = $uri) =~ s!/authors/id.*$!!;
1631
+  
1632
+      (my $chksum_uri = $uri) =~ s!/[^/]*$!/CHECKSUMS!;
1633
+      my $chk_file = $self->source_for($mirror) . "/$dist->{cpanid}.CHECKSUMS";
1634
+      $self->diag_progress("Fetching $chksum_uri");
1635
+      $self->mirror($chksum_uri, $chk_file);
1636
+  
1637
+      unless (-e $chk_file) {
1638
+          $self->diag_fail("Fetching $chksum_uri failed.\n");
1639
+          return;
1640
+      }
1641
+  
1642
+      $self->diag_ok;
1643
+      $self->verify_checksums_signature($chk_file) or return;
1644
+      $self->verify_checksum($file, $chk_file);
1645
+  }
1646
+  
1647
+  sub verify_checksum {
1648
+      my($self, $file, $chk_file) = @_;
1649
+  
1650
+      $self->chat("Verifying the SHA1 for $file\n");
1651
+  
1652
+      open my $fh, "<$chk_file" or die "$chk_file: $!";
1653
+      my $data = join '', <$fh>;
1654
+      $data =~ s/\015?\012/\n/g;
1655
+  
1656
+      require Safe; # no fatpack
1657
+      my $chksum = Safe->new->reval($data);
1658
+  
1659
+      if (!ref $chksum or ref $chksum ne 'HASH') {
1660
+          $self->diag_fail("! Checksum file downloaded from $chk_file is broken.\n");
1661
+          return;
1662
+      }
1663
+  
1664
+      if (my $sha = $chksum->{$file}{sha256}) {
1665
+          my $hex = $self->sha1_for($file);
1666
+          if ($hex eq $sha) {
1667
+              $self->chat("Checksum for $file: Verified!\n");
1668
+          } else {
1669
+              $self->diag_fail("Checksum mismatch for $file\n");
1670
+              return;
1671
+          }
1672
+      } else {
1673
+          $self->chat("Checksum for $file not found in CHECKSUMS.\n");
1674
+          return;
1675
+      }
1676
+  }
1677
+  
1678
+  sub sha1_for {
1679
+      my($self, $file) = @_;
1680
+  
1681
+      require Digest::SHA; # no fatpack
1682
+  
1683
+      open my $fh, "<", $file or die "$file: $!";
1684
+      my $dg = Digest::SHA->new(256);
1685
+      my($data);
1686
+      while (read($fh, $data, 4096)) {
1687
+          $dg->add($data);
1688
+      }
1689
+  
1690
+      return $dg->hexdigest;
1691
+  }
1692
+  
1693
+  sub verify_signature {
1694
+      my($self, $dist) = @_;
1695
+  
1696
+      $self->diag_progress("Verifying the SIGNATURE file");
1697
+      my $out = `$self->{cpansign} -v --skip 2>&1`;
1698
+      $self->log($out);
1699
+  
1700
+      if ($out =~ /Signature verified OK/) {
1701
+          $self->diag_ok("Verified OK");
1702
+          return 1;
1703
+      } else {
1704
+          $self->diag_fail("SIGNATURE verificaion for $dist->{filename} failed\n");
1705
+          return;
1706
+      }
1707
+  }
1708
+  
1326 1709
   sub resolve_name {
1327 1710
       my($self, $module, $version) = @_;
1328 1711
   
1329 1712
       # URL
1330 1713
       if ($module =~ /^(ftp|https?|file):/) {
1331
-          if ($module =~ m!authors/id/!) {
1332
-              return $self->cpan_dist($module, $module);
1714
+          if ($module =~ m!authors/id/(.*)!) {
1715
+              return $self->cpan_dist($1, $module);
1333 1716
           } else {
1334 1717
               return { uris => [ $module ] };
1335 1718
           }
... ...
@@ -1351,6 +1734,11 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT';
1351 1734
           };
1352 1735
       }
1353 1736
   
1737
+      # Git
1738
+      if ($module =~ /(^git:|\.git$)/) {
1739
+          return $self->git_uri($module);
1740
+      }
1741
+  
1354 1742
       # cpan URI
1355 1743
       if ($module =~ s!^cpan:///distfile/!!) {
1356 1744
           return $self->cpan_dist($module);
... ...
@@ -1402,6 +1790,44 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT';
1402 1790
       };
1403 1791
   }
1404 1792
   
1793
+  sub git_uri {
1794
+      my ($self, $uri) = @_;
1795
+  
1796
+      # similar to http://www.pip-installer.org/en/latest/logic.html#vcs-support
1797
+      # git URL has to end with .git when you need to use pin @ commit/tag/branch
1798
+  
1799
+      ($uri, my $commitish) = split /(?<=\.git)@/i, $uri, 2;
1800
+  
1801
+      my $dh  = File::Temp->newdir(CLEANUP => 1);
1802
+      my $dir = Cwd::abs_path($dh->dirname);
1803
+  
1804
+      $self->diag_progress("Cloning $uri");
1805
+      $self->run([ 'git', 'clone', $uri, $dir ]);
1806
+  
1807
+      unless (-e "$dir/.git") {
1808
+          $self->diag_fail("Failed cloning git repository $uri");
1809
+          return;
1810
+      }
1811
+  
1812
+      if ($commitish) {
1813
+          require File::pushd;
1814
+          my $dir = File::pushd::pushd($dir);
1815
+  
1816
+          unless ($self->run([ 'git', 'checkout', $commitish ])) {
1817
+              $self->diag_fail("Failed to checkout '$commitish' in git repository $uri\n");
1818
+              return;
1819
+          }
1820
+      }
1821
+  
1822
+      $self->diag_ok;
1823
+  
1824
+      return {
1825
+          source => 'local',
1826
+          dir    => $dir,
1827
+          handle => $dh,
1828
+      };
1829
+  }
1830
+  
1405 1831
   sub setup_module_build_patch {
1406 1832
       my $self = shift;
1407 1833
   
... ...
@@ -1432,7 +1858,7 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT';
1432 1858
       # might be newer than (or actually wasn't core at) the version
1433 1859
       # that is shipped with the current perl
1434 1860
       if ($self->{self_contained} && $self->loaded_from_perl_lib($meta)) {
1435
-          require Module::CoreList;
1861
+          require Module::CoreList; # no fatpack
1436 1862
           unless (exists $Module::CoreList::version{$]+0}{$mod}) {
1437 1863
               return 0, undef;
1438 1864
           }
... ...
@@ -1443,23 +1869,43 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT';
1443 1869
   
1444 1870
       if ($self->is_deprecated($meta)){
1445 1871
           return 0, $version;
1446
-      } elsif (!$want_ver or $version >= version->new($want_ver)) {
1872
+      } elsif ($self->satisfy_version($mod, $version, $want_ver)) {
1447 1873
           return 1, ($version || 'undef');
1448 1874
       } else {
1449 1875
           return 0, $version;
1450 1876
       }
1451 1877
   }
1452 1878
   
1879
+  sub satisfy_version {
1880
+      my($self, $mod, $version, $want_ver) = @_;
1881
+  
1882
+      $want_ver = '0' unless defined($want_ver) && length($want_ver);
1883
+  
1884
+      require CPAN::Meta::Requirements;
1885
+      my $requirements = CPAN::Meta::Requirements->new;
1886
+      $requirements->add_string_requirement($mod, $want_ver);
1887
+      $requirements->accepts_module($mod, $version);
1888
+  }
1889
+  
1890
+  sub unsatisfy_how {
1891
+      my($self, $ver, $want_ver) = @_;
1892
+  
1893
+      if ($want_ver =~ /^[v0-9\.\_]+$/) {
1894
+          return "$ver < $want_ver";
1895
+      } else {
1896
+          return "$ver doesn't satisfy $want_ver";
1897
+      }
1898
+  }
1899
+  
1453 1900
   sub is_deprecated {
1454 1901
       my($self, $meta) = @_;
1455 1902
   
1456 1903
       my $deprecated = eval {
1457
-          require Module::CoreList;
1904
+          require Module::CoreList; # no fatpack
1458 1905
           Module::CoreList::is_deprecated($meta->{module});
1459 1906
       };
1460 1907
   
1461
-      return unless $deprecated;
1462
-      return $self->loaded_from_perl_lib($meta);
1908
+      return $deprecated && $self->loaded_from_perl_lib($meta);
1463 1909
   }
1464 1910
   
1465 1911
   sub loaded_from_perl_lib {
... ...
@@ -1483,7 +1929,7 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT';
1483 1929
       my($ok, $local) = $self->check_module($mod, $ver);
1484 1930
   
1485 1931
       if ($ok)       { $self->chat("Yes ($local)\n") }
1486
-      elsif ($local) { $self->chat("No ($local < $ver)\n") }
1932
+      elsif ($local) { $self->chat("No (" . $self->unsatisfy_how($local, $ver) . ")\n") }
1487 1933
       else           { $self->chat("No\n") }
1488 1934
   
1489 1935
       return $mod unless $ok;
... ...
@@ -1536,20 +1982,32 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT';
1536 1982
   sub build_stuff {
1537 1983
       my($self, $stuff, $dist, $depth) = @_;
1538 1984
   
1985
+      if ($self->{verify} && -e 'SIGNATURE') {
1986
+          $self->verify_signature($dist) or return;
1987
+      }
1988
+  
1539 1989
       my @config_deps;
1540
-      if (!%{$dist->{meta} || {}} && -e 'META.yml') {
1990
+      if (-e 'META.json') {
1991
+          $self->chat("Checking configure dependencies from META.json\n");
1992
+          $dist->{meta} = $self->parse_meta('META.json');
1993
+      } elsif (-e 'META.yml') {
1541 1994
           $self->chat("Checking configure dependencies from META.yml\n");
1542 1995
           $dist->{meta} = $self->parse_meta('META.yml');
1543 1996
       }
1544 1997
   
1545 1998
       if (!$dist->{meta} && $dist->{source} eq 'cpan') {
1546
-          $self->chat("META.yml not found or unparsable. Fetching META.yml from search.cpan.org\n");
1999
+          $self->chat("META.yml/json not found or unparsable. Fetching META.yml from search.cpan.org\n");
1547 2000
           $dist->{meta} = $self->fetch_meta_sco($dist);
1548 2001
       }
1549 2002
   
1550 2003
       $dist->{meta} ||= {};
1551 2004
   
1552
-      push @config_deps, %{$dist->{meta}{configure_requires} || {}};
2005
+      if ( $dist->{meta}->{prereqs} ) {
2006
+          push @config_deps, %{$dist->{meta}{prereqs}{configure}{requires} || {}};
2007
+      }
2008
+      else {
2009
+          push @config_deps, %{$dist->{meta}{configure_requires} || {}};
2010
+      }
1553 2011
   
1554 2012
       my $target = $dist->{meta}{name} ? "$dist->{meta}{name}-$dist->{meta}{version}" : $dist->{dir};
1555 2013
   
... ...
@@ -1558,7 +2016,7 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT';
1558 2016
   
1559 2017
       $self->diag_progress("Configuring $target");
1560 2018
   
1561
-      my $configure_state = $self->configure_this($dist);
2019
+      my $configure_state = $self->configure_this($dist, $depth);
1562 2020
   
1563 2021
       $self->diag_ok($configure_state->{configured_ok} ? "OK" : "N/A");
1564 2022
   
... ...
@@ -1617,13 +2075,13 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT';
1617 2075
           $self->diag_progress("Building " . ($self->{notest} ? "" : "and testing ") . $distname);
1618 2076
           $self->build([ $self->{perl}, @switches, "./Build" ], $distname) &&
1619 2077
           $self->test([ $self->{perl}, "./Build", "test" ], $distname) &&
1620
-          $self->install([ $self->{perl}, @switches, "./Build", "install" ], [ "--uninst", 1 ]) &&
2078
+          $self->install([ $self->{perl}, @switches, "./Build", "install" ], [ "--uninst", 1 ], $depth) &&
1621 2079
           $installed++;
1622 2080
       } elsif ($self->{make} && -e 'Makefile') {
1623 2081
           $self->diag_progress("Building " . ($self->{notest} ? "" : "and testing ") . $distname);
1624 2082
           $self->build([ $self->{make} ], $distname) &&
1625 2083
           $self->test([ $self->{make}, "test" ], $distname) &&
1626
-          $self->install([ $self->{make}, "install" ], [ "UNINST=1" ]) &&
2084
+          $self->install([ $self->{make}, "install" ], [ "UNINST=1" ], $depth) &&
1627 2085
           $installed++;
1628 2086
       } else {
1629 2087
           my $why;
... ...
@@ -1636,7 +2094,10 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT';
1636 2094
           return;
1637 2095
       }
1638 2096
   
1639
-      if ($installed) {
2097
+      if ($installed && $self->{test_only}) {
2098
+          $self->diag_ok;
2099
+          $self->diag("Successfully tested $distname\n", 1);
2100
+      } elsif ($installed) {
1640 2101
           my $local   = $self->{local_versions}{$dist->{module} || ''};
1641 2102
           my $version = $dist->{module_version} || $dist->{meta}{version} || $dist->{version};
1642 2103
           my $reinstall = $local && ($local eq $version);
... ...
@@ -1651,14 +2112,25 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT';
1651 2112
           $self->save_meta($stuff, $dist, $module_name, \@config_deps, \@deps);
1652 2113
           return 1;
1653 2114
       } else {
1654
-          my $msg = "Building $distname failed";
1655
-          $self->diag_fail("Installing $stuff failed. See $self->{log} for details.", 1);
2115
+          my $what = $self->{test_only} ? "Testing" : "Installing";
2116
+          $self->diag_fail("$what $stuff failed. See $self->{log} for details.", 1);
1656 2117
           return;
1657 2118
       }
1658 2119
   }
1659 2120
   
1660 2121
   sub configure_this {
1661
-      my($self, $dist) = @_;
2122
+      my($self, $dist, $depth) = @_;
2123
+  
2124
+      if (-e 'cpanfile' && $self->{installdeps} && $depth == 0) {
2125
+          require Module::CPANfile;
2126
+          $dist->{cpanfile} = eval { Module::CPANfile->load('cpanfile') };
2127
+          $self->diag_fail($@, 1) if $@;
2128
+          return {
2129
+              configured       => 1,
2130
+              configured_ok    => !!$dist->{cpanfile},
2131
+              use_module_build => 0,
2132
+          };
2133
+      }
1662 2134
   
1663 2135
       if ($self->{skip_configure}) {
1664 2136
           my $eumm = -e 'Makefile';
... ...
@@ -1723,10 +2195,10 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT';
1723 2195
       unless ($state->{configured_ok}) {
1724 2196
           while (1) {
1725 2197
               my $ans = lc $self->prompt("Configuring $dist->{dist} failed.\nYou can s)kip, r)etry, e)xamine build log, or l)ook ?", "s");
1726
-              last                                if $ans eq 's';
1727
-              return $self->configure_this($dist) if $ans eq 'r';
1728
-              $self->show_build_log               if $ans eq 'e';
1729
-              $self->look                         if $ans eq 'l';
2198
+              last                                        if $ans eq 's';
2199
+              return $self->configure_this($dist, $depth) if $ans eq 'r';
2200
+              $self->show_build_log                       if $ans eq 'e';
2201
+              $self->look                                 if $ans eq 'l';
1730 2202
           }
1731 2203
       }
1732 2204
   
... ...
@@ -1767,12 +2239,12 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT';
1767 2239
               qw( blib/lib blib/arch ) # FCGI.pm :(
1768 2240
       );
1769 2241
   
1770
-      mkdir "blib/meta", 0777 or die $!;
2242
+      File::Path::mkpath("blib/meta", 0, 0777);
1771 2243
   
1772 2244
       my $local = {
1773 2245
           name => $module_name,
1774
-          module => $module,
1775
-          version => $provides->{$module}{version} || $dist->{version},
2246
+          target => $module,
2247
+          version => $provides->{$module_name}{version} || $dist->{version},
1776 2248
           dist => $dist->{distvname},
1777 2249
           pathname => $dist->{pathname},
1778 2250
           provides => $provides,
... ...
@@ -1834,6 +2306,15 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT';
1834 2306
   sub extract_meta_prereqs {
1835 2307
       my($self, $dist) = @_;
1836 2308
   
2309
+      if ($dist->{cpanfile}) {
2310
+          my $prereq = $dist->{cpanfile}->prereq;
2311
+          my @phase = $self->{notest} ? qw( build runtime ) : qw( build test runtime );
2312
+          require CPAN::Meta::Requirements;
2313
+          my $req = CPAN::Meta::Requirements->new;
2314
+          $req->add_requirements($prereq->requirements_for($_, 'requires')) for @phase;
2315
+          return %{$req->as_string_hash};
2316
+      }
2317
+  
1837 2318
       my $meta = $dist->{meta};
1838 2319
   
1839 2320
       my @deps;
... ...
@@ -1865,7 +2346,7 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT';
1865 2346
           $self->chat("Finding PREREQ from Makefile ...\n");
1866 2347
           open my $mf, "Makefile";
1867 2348
           while (<$mf>) {
1868
-              if (/^\#\s+PREREQ_PM => {\s*(.*?)\s*}/) {
2349
+              if (/^\#\s+PREREQ_PM => \{\s*(.*?)\s*\}/) {
1869 2350
                   my @all;
1870 2351
                   my @pairs = split ', ', $1;
1871 2352
                   for (@pairs) {
... ...
@@ -1992,7 +2473,7 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT';
1992 2473
           require JSON::PP;
1993 2474
           print JSON::PP::encode_json($self->{scandeps_tree});
1994 2475
       } elsif ($self->{format} eq 'yaml') {
1995
-          require YAML;
2476
+          require YAML; # no fatpack
1996 2477
           print YAML::Dump($self->{scandeps_tree});
1997 2478
       } else {
1998 2479
           $self->diag("Unknown format: $self->{format}\n");
... ...
@@ -2042,20 +2523,50 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT';
2042 2523
       return;
2043 2524
   }
2044 2525
   
2045
-  sub get      { $_[0]->{_backends}{get}->(@_) };
2046
-  sub mirror   { $_[0]->{_backends}{mirror}->(@_) };
2526
+  sub get {
2527
+      my($self, $uri) = @_;
2528
+      if ($uri =~ /^file:/) {
2529
+          $self->file_get($uri);
2530
+      } else {
2531
+          $self->{_backends}{get}->(@_);
2532
+      }
2533
+  }
2534
+  
2535
+  sub mirror {
2536
+      my($self, $uri, $local) = @_;
2537
+      if ($uri =~ /^file:/) {
2538
+          $self->file_mirror($uri, $local);
2539
+      } else {
2540
+          $self->{_backends}{mirror}->(@_);
2541
+      }
2542
+  }
2543
+  
2047 2544
   sub untar    { $_[0]->{_backends}{untar}->(@_) };
2048 2545
   sub unzip    { $_[0]->{_backends}{unzip}->(@_) };
2049 2546
   
2547
+  sub uri_to_file {
2548
+      my($self, $uri) = @_;
2549
+  
2550
+      # file:///path/to/file -> /path/to/file
2551
+      # file://C:/path       -> C:/path
2552
+      if ($uri =~ s!file:/+!!) {
2553
+          $uri = "/$uri" unless $uri =~ m![a-zA-Z]:!;
2554
+      }
2555
+  
2556
+      return $uri;
2557
+  }
2558
+  
2050 2559
   sub file_get {
2051 2560
       my($self, $uri) = @_;
2052
-      open my $fh, "<$uri" or return;
2561
+      my $file = $self->uri_to_file($uri);
2562
+      open my $fh, "<$file" or return;
2053 2563
       join '', <$fh>;
2054 2564
   }
2055 2565
   
2056 2566
   sub file_mirror {
2057 2567
       my($self, $uri, $path) = @_;
2058
-      File::Copy::copy($uri, $path);
2568
+      my $file = $self->uri_to_file($uri);
2569
+      File::Copy::copy($file, $path);
2059 2570
   }
2060 2571
   
2061 2572
   sub init_tools {
... ...
@@ -2074,7 +2585,7 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT';
2074 2585
               LWP::UserAgent->new(
2075 2586
                   parse_head => 0,
2076 2587
                   env_proxy => 1,
2077
-                  agent => "cpanminus/$VERSION",
2588
+                  agent => $self->agent,
2078 2589
                   timeout => 30,
2079 2590
                   @_,
2080 2591
               );
... ...
@@ -2092,49 +2603,57 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT';
2092 2603
           };
2093 2604
       } elsif ($self->{try_wget} and my $wget = $self->which('wget')) {
2094 2605
           $self->chat("You have $wget\n");
2606
+          my @common = (
2607
+              '--user-agent', $self->agent,
2608
+              '--retry-connrefused',
2609
+              ($self->{verbose} ? () : ('-q')),
2610
+          );
2095 2611
           $self->{_backends}{get} = sub {
2096 2612
               my($self, $uri) = @_;
2097
-              return $self->file_get($uri) if $uri =~ s!^file:/+!/!;
2098
-              $self->safeexec( my $fh, $wget, $uri, ( $self->{verbose} ? () : '-q' ), '-O', '-' ) or die "wget $uri: $!";
2613
+              $self->safeexec( my $fh, $wget, $uri, @common, '-O', '-' ) or die "wget $uri: $!";
2099 2614
               local $/;
2100 2615
               <$fh>;
2101 2616
           };
2102 2617
           $self->{_backends}{mirror} = sub {
2103 2618
               my($self, $uri, $path) = @_;
2104
-              return $self->file_mirror($uri, $path) if $uri =~ s!^file:/+!/!;
2105
-              $self->safeexec( my $fh, $wget, '--retry-connrefused', $uri, ( $self->{verbose} ? () : '-q' ), '-O', $path ) or die "wget $uri: $!";
2619
+              $self->safeexec( my $fh, $wget, $uri, @common, '-O', $path ) or die "wget $uri: $!";
2106 2620
               local $/;
2107 2621
               <$fh>;
2108 2622
           };
2109 2623
       } elsif ($self->{try_curl} and my $curl = $self->which('curl')) {
2110 2624
           $self->chat("You have $curl\n");
2625
+          my @common = (
2626
+              '--location',
2627
+              '--user-agent', $self->agent,
2628
+              ($self->{verbose} ? () : '-s'),
2629
+          );
2111 2630
           $self->{_backends}{get} = sub {
2112 2631
               my($self, $uri) = @_;
2113
-              return $self->file_get($uri) if $uri =~ s!^file:/+!/!;
2114
-              $self->safeexec( my $fh, $curl, '-L', ( $self->{verbose} ? () : '-s' ), $uri ) or die "curl $uri: $!";
2632
+              $self->safeexec( my $fh, $curl, @common, $uri ) or die "curl $uri: $!";
2115 2633
               local $/;
2116 2634
               <$fh>;
2117 2635
           };
2118 2636
           $self->{_backends}{mirror} = sub {
2119 2637
               my($self, $uri, $path) = @_;
2120
-              return $self->file_mirror($uri, $path) if $uri =~ s!^file:/+!/!;
2121
-              $self->safeexec( my $fh, $curl, '-L', $uri, ( $self->{verbose} ? () : '-s' ), '-#', '-o', $path ) or die "curl $uri: $!";
2638
+              $self->safeexec( my $fh, $curl, @common, $uri, '-#', '-o', $path ) or die "curl $uri: $!";
2122 2639
               local $/;
2123 2640
               <$fh>;
2124 2641
           };
2125 2642
       } else {
2126 2643
           require HTTP::Tiny;
2127 2644
           $self->chat("Falling back to HTTP::Tiny $HTTP::Tiny::VERSION\n");
2128
-  
2645
+          my %common = (
2646
+              agent => $self->agent,
2647
+          );
2129 2648
           $self->{_backends}{get} = sub {
2130 2649
               my $self = shift;
2131
-              my $res = HTTP::Tiny->new->get($_[0]);
2650
+              my $res = HTTP::Tiny->new(%common)->get($_[0]);
2132 2651
               return unless $res->{success};
2133 2652
               return $res->{content};
2134 2653
           };
2135 2654
           $self->{_backends}{mirror} = sub {
2136 2655
               my $self = shift;
2137
-              my $res = HTTP::Tiny->new->mirror(@_);
2656
+              my $res = HTTP::Tiny->new(%common)->mirror(@_);
2138 2657
               return $res->{status};
2139 2658
           };
2140 2659
       }
... ...
@@ -2149,17 +2668,25 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT';
2149 2668
           $self->{_backends}{untar} = sub {
2150 2669
               my($self, $tarfile) = @_;
2151 2670
   
2152
-              my $xf = "xf" . ($self->{verbose} ? 'v' : '');
2671
+              my $xf = ($self->{verbose} ? 'v' : '')."xf";
2153 2672
               my $ar = $tarfile =~ /bz2$/ ? 'j' : 'z';
2154 2673
   
2155
-              my($root, @others) = `$tar tf$ar $tarfile`
2674
+              my($root, @others) = `$tar ${ar}tf $tarfile`
2156 2675
                   or return undef;
2157 2676
   
2158
-              chomp $root;
2159
-              $root =~ s!^\./!!;
2160
-              $root =~ s{^(.+?)/.*$}{$1};
2677
+              FILE: {
2678
+                  chomp $root;
2679
+                  $root =~ s!^\./!!;
2680
+                  $root =~ s{^(.+?)/.*$}{$1};
2161 2681
   
2162
-              system "$tar $xf$ar $tarfile";
2682
+                  if (!length($root)) {
2683
+                      # archive had ./ as the first entry, so try again
2684
+                      $root = shift(@others);
2685
+                      redo FILE if $root;
2686
+                  }
2687
+              }
2688
+  
2689
+              system "$tar $ar$xf $tarfile";
2163 2690
               return $root if -d $root;
2164 2691
   
2165 2692
               $self->diag_fail("Bad archive: $tarfile");
... ...
@@ -2178,8 +2705,17 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT';
2178 2705
               my($root, @others) = `$ar -dc $tarfile | $tar tf -`
2179 2706
                   or return undef;
2180 2707
   
2181
-              chomp $root;
2182
-              $root =~ s{^(.+?)/.*$}{$1};
2708
+              FILE: {
2709
+                  chomp $root;
2710
+                  $root =~ s!^\./!!;
2711
+                  $root =~ s{^(.+?)/.*$}{$1};
2712
+  
2713
+                  if (!length($root)) {
2714
+                      # archive had ./ as the first entry, so try again
2715
+                      $root = shift(@others);
2716
+                      redo FILE if $root;
2717
+                  }
2718
+              }
2183 2719
   
2184 2720
               system "$ar -dc $tarfile | $tar $x";
2185 2721
               return $root if -d $root;
... ...
@@ -2192,8 +2728,17 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT';
2192 2728
           $self->{_backends}{untar} = sub {
2193 2729
               my $self = shift;
2194 2730
               my $t = Archive::Tar->new($_[0]);
2195
-              my $root = ($t->list_files)[0];
2196
-              $root =~ s{^(.+?)/.*$}{$1};
2731
+              my($root, @others) = $t->list_files;
2732
+              FILE: {
2733
+                  $root =~ s!^\./!!;
2734
+                  $root =~ s{^(.+?)/.*$}{$1};
2735
+  
2736
+                  if (!length($root)) {
2737
+                      # archive had ./ as the first entry, so try again
2738
+                      $root = shift(@others);
2739
+                      redo FILE if $root;
2740
+                  }
2741
+              }
2197 2742
               $t->extract;
2198 2743
               return -d $root ? $root : undef;
2199 2744
           };
... ...
@@ -2213,7 +2758,7 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT';
2213 2758
                   or return undef;
2214 2759
   
2215 2760
               chomp $root;
2216
-              $root =~ s{^\s+testing:\s+(.+?)/\s+OK$}{$1};
2761
+              $root =~ s{^\s+testing:\s+([^/]+)/.*?\s+OK$}{$1};
2217 2762
   
2218 2763
               system "$unzip $opt $zipfile";
2219 2764
               return $root if -d $root;
... ...
@@ -2232,15 +2777,16 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT';
2232 2777
               $self->diag_fail("Read of file[$file] failed")
2233 2778
                   if $status != Archive::Zip::AZ_OK();
2234 2779
               my @members = $zip->members();
2235
-              my $root;
2236 2780
               for my $member ( @members ) {
2237 2781
                   my $af = $member->fileName();
2238 2782
                   next if ($af =~ m!^(/|\.\./)!);
2239
-                  $root = $af unless $root;
2240 2783
                   $status = $member->extractToFileNamed( $af );
2241 2784
                   $self->diag_fail("Extracting of file[$af] from zipfile[$file failed")
2242 2785
                       if $status != Archive::Zip::AZ_OK();
2243 2786
               }
2787
+  
2788
+              my ($root) = $zip->membersMatching( qr<^[^/]+/$> );
2789
+              $root &&= $root->fileName;
2244 2790
               return -d $root ? $root : undef;
2245 2791
           };
2246 2792
       }
... ...
@@ -2269,12 +2815,12 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT';
2269 2815
   
2270 2816
   sub parse_meta {
2271 2817
       my($self, $file) = @_;
2272
-      return eval { (Parse::CPAN::Meta::LoadFile($file))[0] } || undef;
2818
+      return eval { Parse::CPAN::Meta->load_file($file) };
2273 2819
   }
2274 2820
   
2275 2821
   sub parse_meta_string {
2276 2822
       my($self, $yaml) = @_;
2277
-      return eval { (Parse::CPAN::Meta::Load($yaml))[0] } || undef;
2823
+      return eval { Parse::CPAN::Meta->load_yaml_string($yaml) };
2278 2824
   }
2279 2825
   
2280 2826
   1;
... ...
@@ -2284,7 +2830,7 @@ $fatpacked{"CPAN/DistnameInfo.pm"} = <<'CPAN_DISTNAMEINFO';
2284 2830
   
2285 2831
   package CPAN::DistnameInfo;
2286 2832
   
2287
-  $VERSION = "0.11";
2833
+  $VERSION = "0.12";
2288 2834
   use strict;
2289 2835
   
2290 2836
   sub distname_info {
... ...
@@ -2315,6 +2861,14 @@ $fatpacked{"CPAN/DistnameInfo.pm"} = <<'CPAN_DISTNAMEINFO';
2315 2861
       $version = $2;
2316 2862
     }
2317 2863
   
2864
+    if ($version =~ /(.+_.*)-(\d.*)/) {
2865
+        # Catch names like Task-Deprecations5_14-1.00.tar.gz where the 5_14 is
2866
+        # part of the distname. However, names like libao-perl_0.03-1.tar.gz
2867
+        # should still have 0.03-1 as their version.
2868
+        $dist .= $1;
2869
+        $version = $2;
2870
+    }
2871
+  
2318 2872
     # Normalize the Dist.pm-1.23 convention which CGI.pm and
2319 2873
     # a few others use.
2320 2874
     $dist =~ s{\.pm$}{};
... ...
@@ -2392,10 +2946,7 @@ $fatpacked{"CPAN/Meta.pm"} = <<'CPAN_META';
2392 2946
   use strict;
2393 2947
   use warnings;
2394 2948
   package CPAN::Meta;
2395
-  BEGIN {
2396
-    $CPAN::Meta::VERSION = '2.110930';
2397
-  }
2398
-  # ABSTRACT: the distribution metadata for a CPAN dist
2949
+  our $VERSION = '2.120921'; # VERSION
2399 2950
   
2400 2951
   
2401 2952
   use Carp qw(carp croak);
... ...
@@ -2403,15 +2954,9 @@ $fatpacked{"CPAN/Meta.pm"} = <<'CPAN_META';
2403 2954
   use CPAN::Meta::Prereqs;
2404 2955
   use CPAN::Meta::Converter;
2405 2956
   use CPAN::Meta::Validator;
2406
-  use Parse::CPAN::Meta 1.4400 ();
2957
+  use Parse::CPAN::Meta 1.4403 ();
2407 2958
   
2408
-  sub _dclone {
2409
-    my $ref = shift;
2410
-    my $backend = Parse::CPAN::Meta->json_backend();
2411
-    return $backend->new->decode(
2412
-      $backend->new->convert_blessed->encode($ref)
2413
-    );
2414
-  }
2959
+  BEGIN { *_dclone = \&CPAN::Meta::Converter::_dclone }
2415 2960
   
2416 2961
   
2417 2962
   BEGIN {
... ...
@@ -2733,6 +3278,8 @@ $fatpacked{"CPAN/Meta.pm"} = <<'CPAN_META';
2733 3278
   
2734 3279
   1;
2735 3280
   
3281
+  # ABSTRACT: the distribution metadata for a CPAN dist
3282
+  
2736 3283
   
2737 3284
   
2738 3285
   
... ...
@@ -2746,21 +3293,27 @@ $fatpacked{"CPAN/Meta/Converter.pm"} = <<'CPAN_META_CONVERTER';
2746 3293
   use strict;
2747 3294
   use warnings;
2748 3295
   package CPAN::Meta::Converter;
2749
-  BEGIN {
2750
-    $CPAN::Meta::Converter::VERSION = '2.110930';
2751
-  }
2752
-  # ABSTRACT: Convert CPAN distribution metadata structures
3296
+  our $VERSION = '2.120921'; # VERSION
2753 3297
   
2754 3298
   
2755 3299
   use CPAN::Meta::Validator;
2756
-  use version 0.82 ();
3300
+  use CPAN::Meta::Requirements;
3301
+  use version 0.88 ();
2757 3302
   use Parse::CPAN::Meta 1.4400 ();
2758 3303
   
2759 3304
   sub _dclone {
2760 3305
     my $ref = shift;
3306
+  
3307
+    # if an object is in the data structure and doesn't specify how to
3308
+    # turn itself into JSON, we just stringify the object.  That does the
3309
+    # right thing for typical things that might be there, like version objects,
3310
+    # Path::Class objects, etc.
3311
+    no warnings 'once';
3312
+    local *UNIVERSAL::TO_JSON = sub { return "$_[0]" };
3313
+  
2761 3314
     my $backend = Parse::CPAN::Meta->json_backend();
2762
-    return $backend->new->decode(
2763
-      $backend->new->convert_blessed->encode($ref)
3315
+    return $backend->new->utf8->decode(
3316
+      $backend->new->utf8->allow_blessed->convert_blessed->encode($ref)
2764 3317
     );
2765 3318
   }
2766 3319
   
... ...
@@ -3055,7 +3608,10 @@ $fatpacked{"CPAN/Meta/Converter.pm"} = <<'CPAN_META_CONVERTER';
3055 3608
     return 0 if ! length $element;
3056 3609
     return 0 if ( $element eq 'undef' || $element eq '<undef>' );
3057 3610
   
3058
-    if ( my $v = eval { version->new($element) } ) {
3611
+    my $v = eval { version->new($element) };
3612
+    # XXX check defined $v and not just $v because version objects leak memory
3613
+    # in boolean context -- dagolden, 2012-02-03
3614
+    if ( defined $v ) {
3059 3615
       return $v->is_qv ? $v->normal : $element;
3060 3616
     }
3061 3617
     else {
... ...
@@ -3063,29 +3619,36 @@ $fatpacked{"CPAN/Meta/Converter.pm"} = <<'CPAN_META_CONVERTER';
3063 3619
     }
3064 3620
   }
3065 3621
   
3622
+  sub _bad_version_hook {
3623
+    my ($v) = @_;
3624
+    $v =~ s{[a-z]+$}{}; # strip trailing alphabetics
3625
+    my $vobj = eval { version->parse($v) };
3626
+    return defined($vobj) ? $vobj : version->parse(0); # or give up
3627
+  }
3628
+  
3066 3629
   sub _version_map {
3067 3630
     my ($element) = @_;
3068
-    return undef unless defined $element;
3631
+    return unless defined $element;
3069 3632
     if ( ref $element eq 'HASH' ) {
3070
-      my $new_map = {};
3071
-      for my $k ( keys %$element ) {
3633
+      # XXX turn this into CPAN::Meta::Requirements with bad version hook
3634
+      # and then turn it back into a hash
3635
+      my $new_map = CPAN::Meta::Requirements->new(
3636
+        { bad_version_hook => sub { version->new(0) } } # punt
3637
+      );
3638
+      while ( my ($k,$v) = each %$element ) {
3072 3639
         next unless _is_module_name($k);
3073
-        my $value = $element->{$k};
3074
-        if ( ! ( defined $value && length $value ) ) {
3075
-          $new_map->{$k} = 0;
3076
-        }
3077
-        elsif ( $value eq 'undef' || $value eq '<undef>' ) {
3078
-          $new_map->{$k} = 0;
3640
+        if ( !defined($v) || !length($v) || $v eq 'undef' || $v eq '<undef>'  ) {
3641
+          $v = 0;
3079 3642
         }
3080
-        elsif ( _is_module_name( $value ) ) { # some weird, old META have this
3081
-          $new_map->{$k} = 0;
3082
-          $new_map->{$value} = 0;
3083
-        }
3084
-        else {
3085
-          $new_map->{$k} = _clean_version($value);
3643
+        # some weird, old META have bad yml with module => module
3644
+        # so check if value is like a module name and not like a version
3645
+        if ( _is_module_name($v) && ! version::is_lax($v) ) {
3646
+          $new_map->add_minimum($k => 0);
3647
+          $new_map->add_minimum($v => 0);
3086 3648
         }
3649
+        $new_map->add_string_requirement($k => $v);
3087 3650
       }
3088
-      return $new_map;
3651
+      return $new_map->as_string_hash;
3089 3652
     }
3090 3653
     elsif ( ref $element eq 'ARRAY' ) {
3091 3654
       my $hashref = { map { $_ => 0 } @$element };
... ...
@@ -3168,9 +3731,8 @@ $fatpacked{"CPAN/Meta/Converter.pm"} = <<'CPAN_META_CONVERTER';
3168 3731
     my $test_h  = _extract_prereqs($_[2]->{prereqs}, qw(test  requires)) || {};
3169 3732
     my $build_h = _extract_prereqs($_[2]->{prereqs}, qw(build requires)) || {};
3170 3733
   
3171
-    require Version::Requirements;
3172
-    my $test_req  = Version::Requirements->from_string_hash($test_h);
3173
-    my $build_req = Version::Requirements->from_string_hash($build_h);
3734
+    my $test_req  = CPAN::Meta::Requirements->from_string_hash($test_h);
3735
+    my $build_req = CPAN::Meta::Requirements->from_string_hash($build_h);
3174 3736
   
3175 3737
     $test_req->add_requirements($build_req)->as_string_hash;
3176 3738
   }
... ...
@@ -3178,12 +3740,12 @@ $fatpacked{"CPAN/Meta/Converter.pm"} = <<'CPAN_META_CONVERTER';
3178 3740
   sub _extract_prereqs {
3179 3741
     my ($prereqs, $phase, $type) = @_;
3180 3742
     return unless ref $prereqs eq 'HASH';
3181
-    return $prereqs->{$phase}{$type};
3743
+    return scalar _version_map($prereqs->{$phase}{$type});
3182 3744
   }
3183 3745
   
3184 3746
   sub _downgrade_optional_features {
3185 3747
     my (undef, undef, $meta) = @_;
3186
-    return undef unless exists $meta->{optional_features};
3748
+    return unless exists $meta->{optional_features};
3187 3749
     my $origin = $meta->{optional_features};
3188 3750
     my $features = {};
3189 3751
     for my $name ( keys %$origin ) {
... ...
@@ -3204,7 +3766,7 @@ $fatpacked{"CPAN/Meta/Converter.pm"} = <<'CPAN_META_CONVERTER';
3204 3766
   
3205 3767
   sub _upgrade_optional_features {
3206 3768
     my (undef, undef, $meta) = @_;
3207
-    return undef unless exists $meta->{optional_features};
3769
+    return unless exists $meta->{optional_features};
3208 3770
     my $origin = $meta->{optional_features};
3209 3771
     my $features = {};
3210 3772
     for my $name ( keys %$origin ) {
... ...
@@ -3300,7 +3862,7 @@ $fatpacked{"CPAN/Meta/Converter.pm"} = <<'CPAN_META_CONVERTER';
3300 3862
       return unless $item;
3301 3863
       if ( $item =~ m{^mailto:(.*)$} ) { return { mailto => $1 } }
3302 3864
       elsif( _is_urlish($item) ) { return { web => $item } }
3303
-      else { return undef }
3865
+      else { return }
3304 3866
     },
3305 3867
     repository => sub { return _is_urlish($_[0]) ? { url => $_[0] } : undef },
3306 3868
     ':custom'  => \&_prefix_custom,
... ...
@@ -3308,7 +3870,7 @@ $fatpacked{"CPAN/Meta/Converter.pm"} = <<'CPAN_META_CONVERTER';
3308 3870
   
3309 3871
   sub _upgrade_resources_2 {
3310 3872
     my (undef, undef, $meta, $version) = @_;
3311
-    return undef unless exists $meta->{resources};
3873
+    return unless exists $meta->{resources};
3312 3874
     return _convert($meta->{resources}, $resource2_upgrade);
3313 3875
   }
3314 3876
   
... ...
@@ -3346,7 +3908,7 @@ $fatpacked{"CPAN/Meta/Converter.pm"} = <<'CPAN_META_CONVERTER';
3346 3908
   
3347 3909
   sub _cleanup_resources_2 {
3348 3910
     my ($resources, $key, $meta, $to_version) = @_;
3349
-    return undef unless $resources && ref $resources eq 'HASH';
3911
+    return unless $resources && ref $resources eq 'HASH';
3350 3912
     return _convert($resources, $resources2_cleanup, $to_version);
3351 3913
   }
3352 3914
   
... ...
@@ -3360,7 +3922,7 @@ $fatpacked{"CPAN/Meta/Converter.pm"} = <<'CPAN_META_CONVERTER';
3360 3922
   
3361 3923
   sub _resources_1_3 {
3362 3924
     my (undef, undef, $meta, $version) = @_;
3363
-    return undef unless exists $meta->{resources};
3925
+    return unless exists $meta->{resources};
3364 3926
     return _convert($meta->{resources}, $resource1_spec);
3365 3927
   }
3366 3928
   
... ...
@@ -3373,7 +3935,7 @@ $fatpacked{"CPAN/Meta/Converter.pm"} = <<'CPAN_META_CONVERTER';
3373 3935
       $resources->{license} = $meta->license_url
3374 3936
         if _is_urlish($meta->{license_url});
3375 3937
     }
3376
-    return undef unless keys %$resources;
3938
+    return unless keys %$resources;
3377 3939
     return _convert($resources, $resource1_spec);
3378 3940
   }
3379 3941
   
... ...
@@ -3387,7 +3949,7 @@ $fatpacked{"CPAN/Meta/Converter.pm"} = <<'CPAN_META_CONVERTER';
3387 3949
   
3388 3950
   sub _downgrade_resources {
3389 3951
     my (undef, undef, $meta, $version) = @_;
3390
-    return undef unless exists $meta->{resources};
3952
+    return unless exists $meta->{resources};
3391 3953
     return _convert($meta->{resources}, $resource_downgrade_spec);
3392 3954
   }
3393 3955
   
... ...
@@ -3987,6 +4549,8 @@ $fatpacked{"CPAN/Meta/Converter.pm"} = <<'CPAN_META_CONVERTER';
3987 4549
   
3988 4550
   1;
3989 4551
   
4552
+  # ABSTRACT: Convert CPAN distribution metadata structures
4553
+  
3990 4554
   
3991 4555
   
3992 4556
   
... ...
@@ -4000,10 +4564,7 @@ $fatpacked{"CPAN/Meta/Feature.pm"} = <<'CPAN_META_FEATURE';
4000 4564
   use strict;
4001 4565
   use warnings;
4002 4566
   package CPAN::Meta::Feature;
4003
-  BEGIN {
4004
-    $CPAN::Meta::Feature::VERSION = '2.110930';
4005
-  }
4006
-  # ABSTRACT: an optional feature provided by a CPAN distribution
4567
+  our $VERSION = '2.120921'; # VERSION
4007 4568
   
4008 4569
   use CPAN::Meta::Prereqs;
4009 4570
   
... ...
@@ -4031,6 +4592,8 @@ $fatpacked{"CPAN/Meta/Feature.pm"} = <<'CPAN_META_FEATURE';
4031 4592
   
4032 4593
   1;
4033 4594
   
4595
+  # ABSTRACT: an optional feature provided by a CPAN distribution
4596
+  
4034 4597
   
4035 4598
   
4036 4599
   
... ...
@@ -4046,12 +4609,12 @@ $fatpacked{"CPAN/Meta/History.pm"} = <<'CPAN_META_HISTORY';
4046 4609
   use strict;
4047 4610
   use warnings;
4048 4611
   package CPAN::Meta::History;
4049
-  BEGIN {
4050
-    $CPAN::Meta::History::VERSION = '2.110930';
4051
-  }
4052
-  # ABSTRACT: history of CPAN Meta Spec changes
4612
+  our $VERSION = '2.120921'; # VERSION
4613
+  
4053 4614
   1;
4054 4615
   
4616
+  # ABSTRACT: history of CPAN Meta Spec changes
4617
+  
4055 4618
   
4056 4619
   
4057 4620
   __END__
... ...
@@ -4064,15 +4627,12 @@ $fatpacked{"CPAN/Meta/Prereqs.pm"} = <<'CPAN_META_PREREQS';
4064 4627
   use strict;
4065 4628
   use warnings;
4066 4629
   package CPAN::Meta::Prereqs;
4067
-  BEGIN {
4068
-    $CPAN::Meta::Prereqs::VERSION = '2.110930';
4069
-  }
4070
-  # ABSTRACT: a set of distribution prerequisites by phase and type
4630
+  our $VERSION = '2.120921'; # VERSION
4071 4631
   
4072 4632
   
4073 4633
   use Carp qw(confess);
4074 4634
   use Scalar::Util qw(blessed);
4075
-  use Version::Requirements 0.101020; # finalize
4635
+  use CPAN::Meta::Requirements 2.121;
4076 4636
   
4077 4637
   
4078 4638
   sub __legal_phases { qw(configure build test runtime develop)   }
... ...
@@ -4100,7 +4660,7 @@ $fatpacked{"CPAN/Meta/Prereqs.pm"} = <<'CPAN_META_PREREQS';
4100 4660
   
4101 4661
         next TYPE unless keys %$spec;
4102 4662
   
4103
-        $guts{prereqs}{$phase}{$type} = Version::Requirements->from_string_hash(
4663
+        $guts{prereqs}{$phase}{$type} = CPAN::Meta::Requirements->from_string_hash(
4104 4664
           $spec
4105 4665
         );
4106 4666
       }
... ...
@@ -4124,7 +4684,7 @@ $fatpacked{"CPAN/Meta/Prereqs.pm"} = <<'CPAN_META_PREREQS';
4124 4684
       confess "requested requirements for unknown type: $type";
4125 4685
     }
4126 4686
   
4127
-    my $req = ($self->{prereqs}{$phase}{$type} ||= Version::Requirements->new);
4687
+    my $req = ($self->{prereqs}{$phase}{$type} ||= CPAN::Meta::Requirements->new);
4128 4688
   
4129 4689
     $req->finalize if $self->is_finalized;
4130 4690
   
... ...
@@ -4143,7 +4703,7 @@ $fatpacked{"CPAN/Meta/Prereqs.pm"} = <<'CPAN_META_PREREQS';
4143 4703
   
4144 4704
     for my $phase ($self->__legal_phases) {
4145 4705
       for my $type ($self->__legal_types) {
4146
-        my $req = Version::Requirements->new;
4706
+        my $req = CPAN::Meta::Requirements->new;
4147 4707
   
4148 4708
         for my $prereq (@prereq_objs) {
4149 4709
           my $this_req = $prereq->requirements_for($phase, $type);
... ...
@@ -4202,6 +4762,8 @@ $fatpacked{"CPAN/Meta/Prereqs.pm"} = <<'CPAN_META_PREREQS';
4202 4762
   
4203 4763
   1;
4204 4764
   
4765
+  # ABSTRACT: a set of distribution prerequisites by phase and type
4766
+  
4205 4767
   
4206 4768
   
4207 4769
   
... ...
@@ -4211,5793 +4773,6440 @@ $fatpacked{"CPAN/Meta/Prereqs.pm"} = <<'CPAN_META_PREREQS';
4211 4773
   
4212 4774
 CPAN_META_PREREQS
4213 4775
 
4214
-$fatpacked{"CPAN/Meta/Spec.pm"} = <<'CPAN_META_SPEC';
4215
-  # vi:tw=72
4216
-  use 5.006;
4776
+$fatpacked{"CPAN/Meta/Requirements.pm"} = <<'CPAN_META_REQUIREMENTS';
4217 4777
   use strict;
4218 4778
   use warnings;
4219
-  package CPAN::Meta::Spec;
4220
-  BEGIN {
4221
-    $CPAN::Meta::Spec::VERSION = '2.110930';
4222
-  }
4223
-  # ABSTRACT: specification for CPAN distribution metadata
4224
-  1;
4225
-  
4779
+  package CPAN::Meta::Requirements;
4780
+  our $VERSION = '2.122'; # VERSION
4781
+  # ABSTRACT: a set of version requirements for a CPAN dist
4226 4782
   
4227 4783
   
4228
-  __END__
4229
-  =pod
4784
+  use Carp ();
4785
+  use Scalar::Util ();
4786
+  use version 0.77 (); # the ->parse method
4230 4787
   
4231
-CPAN_META_SPEC
4232
-
4233
-$fatpacked{"CPAN/Meta/Validator.pm"} = <<'CPAN_META_VALIDATOR';
4234
-  use 5.006;
4235
-  use strict;
4236
-  use warnings;
4237
-  package CPAN::Meta::Validator;
4238
-  BEGIN {
4239
-    $CPAN::Meta::Validator::VERSION = '2.110930';
4240
-  }
4241
-  # ABSTRACT: validate CPAN distribution metadata structures
4242 4788
   
4789
+  my @valid_options = qw( bad_version_hook );
4243 4790
   
4244
-  #--------------------------------------------------------------------------#
4245
-  # This code copied and adapted from Test::CPAN::Meta
4246
-  # by Barbie, <barbie@cpan.org> for Miss Barbell Productions,
4247
-  # L<http://www.missbarbell.co.uk>
4248
-  #--------------------------------------------------------------------------#
4791
+  sub new {
4792
+    my ($class, $options) = @_;
4793
+    $options ||= {};
4794
+    Carp::croak "Argument to $class\->new() must be a hash reference"
4795
+      unless ref $options eq 'HASH';
4796
+    my %self = map {; $_ => $options->{$_}} @valid_options;
4249 4797
   
4250
-  #--------------------------------------------------------------------------#
4251
-  # Specification Definitions
4252
-  #--------------------------------------------------------------------------#
4798
+    return bless \%self => $class;
4799
+  }
4253 4800
   
4254
-  my %known_specs = (
4255
-      '1.4' => 'http://module-build.sourceforge.net/META-spec-v1.4.html',
4256
-      '1.3' => 'http://module-build.sourceforge.net/META-spec-v1.3.html',
4257
-      '1.2' => 'http://module-build.sourceforge.net/META-spec-v1.2.html',
4258
-      '1.1' => 'http://module-build.sourceforge.net/META-spec-v1.1.html',
4259
-      '1.0' => 'http://module-build.sourceforge.net/META-spec-v1.0.html'
4260
-  );
4261
-  my %known_urls = map {$known_specs{$_} => $_} keys %known_specs;
4801
+  sub _version_object {
4802
+    my ($self, $version) = @_;
4262 4803
   
4263
-  my $module_map1 = { 'map' => { ':key' => { name => \&module, value => \&exversion } } };
4804
+    my $vobj;
4264 4805
   
4265
-  my $module_map2 = { 'map' => { ':key' => { name => \&module, value => \&version   } } };
4806
+    eval {
4807
+      $vobj  = (! defined $version)                ? version->parse(0)
4808
+             : (! Scalar::Util::blessed($version)) ? version->parse($version)
4809
+             :                                       $version;
4810
+    };
4266 4811
   
4267
-  my $no_index_2 = {
4268
-      'map'       => { file       => { list => { value => \&string } },
4269
-                       directory  => { list => { value => \&string } },
4270
-                       'package'  => { list => { value => \&string } },
4271
-                       namespace  => { list => { value => \&string } },
4272
-                      ':key'      => { name => \&custom_2, value => \&anything },
4812
+    if ( my $err = $@ ) {
4813
+      my $hook = $self->{bad_version_hook};
4814
+      $vobj = eval { $hook->($version) }
4815
+        if ref $hook eq 'CODE';
4816
+      unless (Scalar::Util::blessed($vobj) && $vobj->isa("version")) {
4817
+        $err =~ s{ at .* line \d+.*$}{};
4818
+        die "Can't convert '$version': $err";
4273 4819
       }
4274
-  };
4820
+    }
4275 4821
   
4276
-  my $no_index_1_3 = {
4277
-      'map'       => { file       => { list => { value => \&string } },
4278
-                       directory  => { list => { value => \&string } },
4279
-                       'package'  => { list => { value => \&string } },
4280
-                       namespace  => { list => { value => \&string } },
4281
-                       ':key'     => { name => \&string, value => \&anything },
4282
-      }
4283
-  };
4822
+    # ensure no leading '.'
4823
+    if ( $vobj =~ m{\A\.} ) {
4824
+      $vobj = version->parse("0$vobj");
4825
+    }
4284 4826
   
4285
-  my $no_index_1_2 = {
4286
-      'map'       => { file       => { list => { value => \&string } },
4287
-                       dir        => { list => { value => \&string } },
4288
-                       'package'  => { list => { value => \&string } },
4289
-                       namespace  => { list => { value => \&string } },
4290
-                       ':key'     => { name => \&string, value => \&anything },
4291
-      }
4292
-  };
4827
+    # ensure normal v-string form
4828
+    if ( $vobj->is_qv ) {
4829
+      $vobj = version->parse($vobj->normal);
4830
+    }
4293 4831
   
4294
-  my $no_index_1_1 = {
4295
-      'map'       => { ':key'     => { name => \&string, list => { value => \&string } },
4296
-      }
4297
-  };
4832
+    return $vobj;
4833
+  }
4298 4834
   
4299
-  my $prereq_map = {
4300
-    map => {
4301
-      ':key' => {
4302
-        name => \&phase,
4303
-        'map' => {
4304
-          ':key'  => {
4305
-            name => \&relation,
4306
-            %$module_map1,
4307
-          },
4308
-        },
4309
-      }
4310
-    },
4311
-  };
4312 4835
   
4313
-  my %definitions = (
4314
-    '2' => {
4315
-      # REQUIRED
4316
-      'abstract'            => { mandatory => 1, value => \&string  },
4317
-      'author'              => { mandatory => 1, lazylist => { value => \&string } },
4318
-      'dynamic_config'      => { mandatory => 1, value => \&boolean },
4319
-      'generated_by'        => { mandatory => 1, value => \&string  },
4320
-      'license'             => { mandatory => 1, lazylist => { value => \&license } },
4321
-      'meta-spec' => {
4322
-        mandatory => 1,
4323
-        'map' => {
4324
-          version => { mandatory => 1, value => \&version},
4325
-          url     => { value => \&url },
4326
-          ':key' => { name => \&custom_2, value => \&anything },
4327
-        }
4328
-      },
4329
-      'name'                => { mandatory => 1, value => \&string  },
4330
-      'release_status'      => { mandatory => 1, value => \&release_status },
4331
-      'version'             => { mandatory => 1, value => \&version },
4836
+  BEGIN {
4837
+    for my $type (qw(minimum maximum exclusion exact_version)) {
4838
+      my $method = "with_$type";
4839
+      my $to_add = $type eq 'exact_version' ? $type : "add_$type";
4332 4840
   
4333
-      # OPTIONAL
4334
-      'description' => { value => \&string },
4335
-      'keywords'    => { lazylist => { value => \&string } },
4336
-      'no_index'    => $no_index_2,
4337
-      'optional_features'   => {
4338
-        'map'       => {
4339
-          ':key'  => {
4340
-            name => \&string,
4341
-            'map'   => {
4342
-              description        => { value => \&string },
4343
-              prereqs => $prereq_map,
4344
-              ':key' => { name => \&custom_2, value => \&anything },
4345
-            }
4346
-          }
4347
-        }
4348
-      },
4349
-      'prereqs' => $prereq_map,
4350
-      'provides'    => {
4351
-        'map'       => {
4352
-          ':key' => {
4353
-            name  => \&module,
4354
-            'map' => {
4355
-              file    => { mandatory => 1, value => \&file },
4356
-              version => { value => \&version },
4357
-              ':key' => { name => \&custom_2, value => \&anything },
4358
-            }
4359
-          }
4360
-        }
4361
-      },
4362
-      'resources'   => {
4363
-        'map'       => {
4364
-          license    => { lazylist => { value => \&url } },
4365
-          homepage   => { value => \&url },
4366
-          bugtracker => {
4367
-            'map' => {
4368
-              web => { value => \&url },
4369
-              mailto => { value => \&string},
4370
-              ':key' => { name => \&custom_2, value => \&anything },
4371
-            }
4372
-          },
4373
-          repository => {
4374
-            'map' => {
4375
-              web => { value => \&url },
4376
-              url => { value => \&url },
4377
-              type => { value => \&string },
4378
-              ':key' => { name => \&custom_2, value => \&anything },
4379
-            }
4380
-          },
4381
-          ':key'     => { value => \&string, name => \&custom_2 },
4382
-        }
4383
-      },
4841
+      my $code = sub {
4842
+        my ($self, $name, $version) = @_;
4384 4843
   
4385
-      # CUSTOM -- additional user defined key/value pairs
4386
-      # note we can only validate the key name, as the structure is user defined
4387
-      ':key'        => { name => \&custom_2, value => \&anything },
4388
-    },
4844
+        $version = $self->_version_object( $version );
4389 4845
   
4390
-  '1.4' => {
4391
-    'meta-spec'           => {
4392
-      mandatory => 1,
4393
-      'map' => {
4394
-        version => { mandatory => 1, value => \&version},
4395
-        url     => { mandatory => 1, value => \&urlspec },
4396
-        ':key'  => { name => \&string, value => \&anything },
4397
-      },
4398
-    },
4846
+        $self->__modify_entry_for($name, $method, $version);
4399 4847
   
4400
-    'name'                => { mandatory => 1, value => \&string  },
4401
-    'version'             => { mandatory => 1, value => \&version },
4402
-    'abstract'            => { mandatory => 1, value => \&string  },
4403
-    'author'              => { mandatory => 1, list  => { value => \&string } },
4404
-    'license'             => { mandatory => 1, value => \&license },
4405
-    'generated_by'        => { mandatory => 1, value => \&string  },
4848
+        return $self;
4849
+      };
4850
+      
4851
+      no strict 'refs';
4852
+      *$to_add = $code;
4853
+    }
4854
+  }
4406 4855
   
4407
-    'distribution_type'   => { value => \&string  },
4408
-    'dynamic_config'      => { value => \&boolean },
4409 4856
   
4410
-    'requires'            => $module_map1,
4411
-    'recommends'          => $module_map1,
4412
-    'build_requires'      => $module_map1,
4413
-    'configure_requires'  => $module_map1,
4414
-    'conflicts'           => $module_map2,
4857
+  sub add_requirements {
4858
+    my ($self, $req) = @_;
4415 4859
   
4416
-    'optional_features'   => {
4417
-      'map'       => {
4418
-          ':key'  => { name => \&string,
4419
-              'map'   => { description        => { value => \&string },
4420
-                           requires           => $module_map1,
4421
-                           recommends         => $module_map1,
4422
-                           build_requires     => $module_map1,
4423
-                           conflicts          => $module_map2,
4424
-                           ':key'  => { name => \&string, value => \&anything },
4425
-              }
4426
-          }
4427
-       }
4428
-    },
4429
-  
4430
-    'provides'    => {
4431
-      'map'       => {
4432
-        ':key' => { name  => \&module,
4433
-          'map' => {
4434
-            file    => { mandatory => 1, value => \&file },
4435
-            version => { value => \&version },
4436
-            ':key'  => { name => \&string, value => \&anything },
4437
-          }
4438
-        }
4439
-      }
4440
-    },
4860
+    for my $module ($req->required_modules) {
4861
+      my $modifiers = $req->__entry_for($module)->as_modifiers;
4862
+      for my $modifier (@$modifiers) {
4863
+        my ($method, @args) = @$modifier;
4864
+        $self->$method($module => @args);
4865
+      };
4866
+    }
4441 4867
   
4442
-    'no_index'    => $no_index_1_3,
4443
-    'private'     => $no_index_1_3,
4868
+    return $self;
4869
+  }
4444 4870
   
4445
-    'keywords'    => { list => { value => \&string } },
4446 4871
   
4447
-    'resources'   => {
4448
-      'map'       => { license    => { value => \&url },
4449
-                       homepage   => { value => \&url },
4450
-                       bugtracker => { value => \&url },
4451
-                       repository => { value => \&url },
4452
-                       ':key'     => { value => \&string, name => \&custom_1 },
4453
-      }
4454
-    },
4872
+  sub accepts_module {
4873
+    my ($self, $module, $version) = @_;
4455 4874
   
4456
-    # additional user defined key/value pairs
4457
-    # note we can only validate the key name, as the structure is user defined
4458
-    ':key'        => { name => \&string, value => \&anything },
4459
-  },
4875
+    $version = $self->_version_object( $version );
4460 4876
   
4461
-  '1.3' => {
4462
-    'meta-spec'           => {
4463
-      mandatory => 1,
4464
-      'map' => {
4465
-        version => { mandatory => 1, value => \&version},
4466
-        url     => { mandatory => 1, value => \&urlspec },
4467
-        ':key'  => { name => \&string, value => \&anything },
4468
-      },
4469
-    },
4877
+    return 1 unless my $range = $self->__entry_for($module);
4878
+    return $range->_accepts($version);
4879
+  }
4470 4880
   
4471
-    'name'                => { mandatory => 1, value => \&string  },
4472
-    'version'             => { mandatory => 1, value => \&version },
4473
-    'abstract'            => { mandatory => 1, value => \&string  },
4474
-    'author'              => { mandatory => 1, list  => { value => \&string } },
4475
-    'license'             => { mandatory => 1, value => \&license },
4476
-    'generated_by'        => { mandatory => 1, value => \&string  },
4477 4881
   
4478
-    'distribution_type'   => { value => \&string  },
4479
-    'dynamic_config'      => { value => \&boolean },
4882
+  sub clear_requirement {
4883
+    my ($self, $module) = @_;
4480 4884
   
4481
-    'requires'            => $module_map1,
4482
-    'recommends'          => $module_map1,
4483
-    'build_requires'      => $module_map1,
4484
-    'conflicts'           => $module_map2,
4885
+    return $self unless $self->__entry_for($module);
4485 4886
   
4486
-    'optional_features'   => {
4487
-      'map'       => {
4488
-          ':key'  => { name => \&string,
4489
-              'map'   => { description        => { value => \&string },
4490
-                           requires           => $module_map1,
4491
-                           recommends         => $module_map1,
4492
-                           build_requires     => $module_map1,
4493
-                           conflicts          => $module_map2,
4494
-                           ':key'  => { name => \&string, value => \&anything },
4495
-              }
4496
-          }
4497
-       }
4498
-    },
4887
+    Carp::confess("can't clear requirements on finalized requirements")
4888
+      if $self->is_finalized;
4499 4889
   
4500
-    'provides'    => {
4501
-      'map'       => {
4502
-        ':key' => { name  => \&module,
4503
-          'map' => {
4504
-            file    => { mandatory => 1, value => \&file },
4505
-            version => { value => \&version },
4506
-            ':key'  => { name => \&string, value => \&anything },
4507
-          }
4508
-        }
4509
-      }
4510
-    },
4890
+    delete $self->{requirements}{ $module };
4511 4891
   
4892
+    return $self;
4893
+  }
4512 4894
   
4513
-    'no_index'    => $no_index_1_3,
4514
-    'private'     => $no_index_1_3,
4515 4895
   
4516
-    'keywords'    => { list => { value => \&string } },
4896
+  sub requirements_for_module {
4897
+    my ($self, $module) = @_;
4898
+    my $entry = $self->__entry_for($module);
4899
+    return unless $entry;
4900
+    return $entry->as_string;
4901
+  }
4517 4902
   
4518
-    'resources'   => {
4519
-      'map'       => { license    => { value => \&url },
4520
-                       homepage   => { value => \&url },
4521
-                       bugtracker => { value => \&url },
4522
-                       repository => { value => \&url },
4523
-                       ':key'     => { value => \&string, name => \&custom_1 },
4524
-      }
4525
-    },
4526 4903
   
4527
-    # additional user defined key/value pairs
4528
-    # note we can only validate the key name, as the structure is user defined
4529
-    ':key'        => { name => \&string, value => \&anything },
4530
-  },
4904
+  sub required_modules { keys %{ $_[0]{requirements} } }
4531 4905
   
4532
-  # v1.2 is misleading, it seems to assume that a number of fields where created
4533
-  # within v1.1, when they were created within v1.2. This may have been an
4534
-  # original mistake, and that a v1.1 was retro fitted into the timeline, when
4535
-  # v1.2 was originally slated as v1.1. But I could be wrong ;)
4536
-  '1.2' => {
4537
-    'meta-spec'           => {
4538
-      mandatory => 1,
4539
-      'map' => {
4540
-        version => { mandatory => 1, value => \&version},
4541
-        url     => { mandatory => 1, value => \&urlspec },
4542
-        ':key'  => { name => \&string, value => \&anything },
4543
-      },
4544
-    },
4545 4906
   
4907
+  sub clone {
4908
+    my ($self) = @_;
4909
+    my $new = (ref $self)->new;
4546 4910
   
4547
-    'name'                => { mandatory => 1, value => \&string  },
4548
-    'version'             => { mandatory => 1, value => \&version },
4549
-    'license'             => { mandatory => 1, value => \&license },
4550
-    'generated_by'        => { mandatory => 1, value => \&string  },
4551
-    'author'              => { mandatory => 1, list => { value => \&string } },
4552
-    'abstract'            => { mandatory => 1, value => \&string  },
4911
+    return $new->add_requirements($self);
4912
+  }
4553 4913
   
4554
-    'distribution_type'   => { value => \&string  },
4555
-    'dynamic_config'      => { value => \&boolean },
4914
+  sub __entry_for     { $_[0]{requirements}{ $_[1] } }
4556 4915
   
4557
-    'keywords'            => { list => { value => \&string } },
4916
+  sub __modify_entry_for {
4917
+    my ($self, $name, $method, $version) = @_;
4558 4918
   
4559
-    'private'             => $no_index_1_2,
4560
-    '$no_index'           => $no_index_1_2,
4919
+    my $fin = $self->is_finalized;
4920
+    my $old = $self->__entry_for($name);
4561 4921
   
4562
-    'requires'            => $module_map1,
4563
-    'recommends'          => $module_map1,
4564
-    'build_requires'      => $module_map1,
4565
-    'conflicts'           => $module_map2,
4922
+    Carp::confess("can't add new requirements to finalized requirements")
4923
+      if $fin and not $old;
4566 4924
   
4567
-    'optional_features'   => {
4568
-      'map'       => {
4569
-          ':key'  => { name => \&string,
4570
-              'map'   => { description        => { value => \&string },
4571
-                           requires           => $module_map1,
4572
-                           recommends         => $module_map1,
4573
-                           build_requires     => $module_map1,
4574
-                           conflicts          => $module_map2,
4575
-                           ':key'  => { name => \&string, value => \&anything },
4576
-              }
4577
-          }
4578
-       }
4579
-    },
4925
+    my $new = ($old || 'CPAN::Meta::Requirements::_Range::Range')
4926
+            ->$method($version);
4580 4927
   
4581
-    'provides'    => {
4582
-      'map'       => {
4583
-        ':key' => { name  => \&module,
4584
-          'map' => {
4585
-            file    => { mandatory => 1, value => \&file },
4586
-            version => { value => \&version },
4587
-            ':key'  => { name => \&string, value => \&anything },
4588
-          }
4589
-        }
4590
-      }
4591
-    },
4928
+    Carp::confess("can't modify finalized requirements")
4929
+      if $fin and $old->as_string ne $new->as_string;
4592 4930
   
4593
-    'resources'   => {
4594
-      'map'       => { license    => { value => \&url },
4595
-                       homepage   => { value => \&url },
4596
-                       bugtracker => { value => \&url },
4597
-                       repository => { value => \&url },
4598
-                       ':key'     => { value => \&string, name => \&custom_1 },
4599
-      }
4600
-    },
4931
+    $self->{requirements}{ $name } = $new;
4932
+  }
4601 4933
   
4602
-    # additional user defined key/value pairs
4603
-    # note we can only validate the key name, as the structure is user defined
4604
-    ':key'        => { name => \&string, value => \&anything },
4605
-  },
4606 4934
   
4607
-  # note that the 1.1 spec only specifies 'version' as mandatory
4608
-  '1.1' => {
4609
-    'name'                => { value => \&string  },
4610
-    'version'             => { mandatory => 1, value => \&version },
4611
-    'license'             => { value => \&license },
4612
-    'generated_by'        => { value => \&string  },
4935
+  sub is_simple {
4936
+    my ($self) = @_;
4937
+    for my $module ($self->required_modules) {
4938
+      # XXX: This is a complete hack, but also entirely correct.
4939
+      return if $self->__entry_for($module)->as_string =~ /\s/;
4940
+    }
4613 4941
   
4614
-    'license_uri'         => { value => \&url },
4615
-    'distribution_type'   => { value => \&string  },
4616
-    'dynamic_config'      => { value => \&boolean },
4942
+    return 1;
4943
+  }
4617 4944
   
4618
-    'private'             => $no_index_1_1,
4619 4945
   
4620
-    'requires'            => $module_map1,
4621
-    'recommends'          => $module_map1,
4622
-    'build_requires'      => $module_map1,
4623
-    'conflicts'           => $module_map2,
4946
+  sub is_finalized { $_[0]{finalized} }
4624 4947
   
4625
-    # additional user defined key/value pairs
4626
-    # note we can only validate the key name, as the structure is user defined
4627
-    ':key'        => { name => \&string, value => \&anything },
4628
-  },
4629 4948
   
4630
-  # note that the 1.0 spec doesn't specify optional or mandatory fields
4631
-  # but we will treat version as mandatory since otherwise META 1.0 is
4632
-  # completely arbitrary and pointless
4633
-  '1.0' => {
4634
-    'name'                => { value => \&string  },
4635
-    'version'             => { mandatory => 1, value => \&version },
4636
-    'license'             => { value => \&license },
4637
-    'generated_by'        => { value => \&string  },
4949
+  sub finalize { $_[0]{finalized} = 1 }
4638 4950
   
4639
-    'license_uri'         => { value => \&url },
4640
-    'distribution_type'   => { value => \&string  },
4641
-    'dynamic_config'      => { value => \&boolean },
4642 4951
   
4643
-    'requires'            => $module_map1,
4644
-    'recommends'          => $module_map1,
4645
-    'build_requires'      => $module_map1,
4646
-    'conflicts'           => $module_map2,
4952
+  sub as_string_hash {
4953
+    my ($self) = @_;
4647 4954
   
4648
-    # additional user defined key/value pairs
4649
-    # note we can only validate the key name, as the structure is user defined
4650
-    ':key'        => { name => \&string, value => \&anything },
4651
-  },
4652
-  );
4955
+    my %hash = map {; $_ => $self->{requirements}{$_}->as_string }
4956
+               $self->required_modules;
4653 4957
   
4654
-  #--------------------------------------------------------------------------#
4655
-  # Code
4656
-  #--------------------------------------------------------------------------#
4958
+    return \%hash;
4959
+  }
4657 4960
   
4658 4961
   
4659
-  sub new {
4660
-    my ($class,$data) = @_;
4962
+  my %methods_for_op = (
4963
+    '==' => [ qw(exact_version) ],
4964
+    '!=' => [ qw(add_exclusion) ],
4965
+    '>=' => [ qw(add_minimum)   ],
4966
+    '<=' => [ qw(add_maximum)   ],
4967
+    '>'  => [ qw(add_minimum add_exclusion) ],
4968
+    '<'  => [ qw(add_maximum add_exclusion) ],
4969
+  );
4661 4970
   
4662
-    # create an attributes hash
4663
-    my $self = {
4664
-      'data'    => $data,
4665
-      'spec'    => $data->{'meta-spec'}{'version'} || "1.0",
4666
-      'errors'  => undef,
4667
-    };
4971
+  sub add_string_requirement {
4972
+    my ($self, $module, $req) = @_;
4668 4973
   
4669
-    # create the object
4670
-    return bless $self, $class;
4671
-  }
4974
+    Carp::confess("No requirement string provided for $module")
4975
+      unless defined $req && length $req;
4672 4976
   
4977
+    my @parts = split qr{\s*,\s*}, $req;
4673 4978
   
4674
-  sub is_valid {
4675
-      my $self = shift;
4676
-      my $data = $self->{data};
4677
-      my $spec_version = $self->{spec};
4678
-      $self->check_map($definitions{$spec_version},$data);
4679
-      return ! $self->errors;
4680
-  }
4681 4979
   
4980
+    for my $part (@parts) {
4981
+      my ($op, $ver) = $part =~ m{\A\s*(==|>=|>|<=|<|!=)\s*(.*)\z};
4682 4982
   
4683
-  sub errors {
4684
-      my $self = shift;
4685
-      return ()   unless(defined $self->{errors});
4686
-      return @{$self->{errors}};
4983
+      if (! defined $op) {
4984
+        $self->add_minimum($module => $part);
4985
+      } else {
4986
+        Carp::confess("illegal requirement string: $req")
4987
+          unless my $methods = $methods_for_op{ $op };
4988
+  
4989
+        $self->$_($module => $ver) for @$methods;
4990
+      }
4991
+    }
4687 4992
   }
4688 4993
   
4689 4994
   
4690
-  my $spec_error = "Missing validation action in specification. "
4691
-    . "Must be one of 'map', 'list', 'lazylist', or 'value'";
4995
+  sub from_string_hash {
4996
+    my ($class, $hash) = @_;
4692 4997
   
4693
-  sub check_map {
4694
-      my ($self,$spec,$data) = @_;
4998
+    my $self = $class->new;
4695 4999
   
4696
-      if(ref($spec) ne 'HASH') {
4697
-          $self->_error( "Unknown META specification, cannot validate." );
4698
-          return;
5000
+    for my $module (keys %$hash) {
5001
+      my $req = $hash->{$module};
5002
+      unless ( defined $req && length $req ) {
5003
+        $req = 0;
5004
+        Carp::carp("Undefined requirement for $module treated as '0'");
4699 5005
       }
5006
+      $self->add_string_requirement($module, $req);
5007
+    }
4700 5008
   
4701
-      if(ref($data) ne 'HASH') {
4702
-          $self->_error( "Expected a map structure from string or file." );
4703
-          return;
4704
-      }
5009
+    return $self;
5010
+  }
4705 5011
   
4706
-      for my $key (keys %$spec) {
4707
-          next    unless($spec->{$key}->{mandatory});
4708
-          next    if(defined $data->{$key});
4709
-          push @{$self->{stack}}, $key;
4710
-          $self->_error( "Missing mandatory field, '$key'" );
4711
-          pop @{$self->{stack}};
4712
-      }
5012
+  ##############################################################
4713 5013
   
4714
-      for my $key (keys %$data) {
4715
-          push @{$self->{stack}}, $key;
4716
-          if($spec->{$key}) {
4717
-              if($spec->{$key}{value}) {
4718
-                  $spec->{$key}{value}->($self,$key,$data->{$key});
4719
-              } elsif($spec->{$key}{'map'}) {
4720
-                  $self->check_map($spec->{$key}{'map'},$data->{$key});
4721
-              } elsif($spec->{$key}{'list'}) {
4722
-                  $self->check_list($spec->{$key}{'list'},$data->{$key});
4723
-              } elsif($spec->{$key}{'lazylist'}) {
4724
-                  $self->check_lazylist($spec->{$key}{'lazylist'},$data->{$key});
4725
-              } else {
4726
-                  $self->_error( "$spec_error for '$key'" );
4727
-              }
5014
+  {
5015
+    package
5016
+      CPAN::Meta::Requirements::_Range::Exact;
5017
+    sub _new     { bless { version => $_[1] } => $_[0] }
4728 5018
   
4729
-          } elsif ($spec->{':key'}) {
4730
-              $spec->{':key'}{name}->($self,$key,$key);
4731
-              if($spec->{':key'}{value}) {
4732
-                  $spec->{':key'}{value}->($self,$key,$data->{$key});
4733
-              } elsif($spec->{':key'}{'map'}) {
4734
-                  $self->check_map($spec->{':key'}{'map'},$data->{$key});
4735
-              } elsif($spec->{':key'}{'list'}) {
4736
-                  $self->check_list($spec->{':key'}{'list'},$data->{$key});
4737
-              } elsif($spec->{':key'}{'lazylist'}) {
4738
-                  $self->check_lazylist($spec->{':key'}{'lazylist'},$data->{$key});
4739
-              } else {
4740
-                  $self->_error( "$spec_error for ':key'" );
4741
-              }
5019
+    sub _accepts { return $_[0]{version} == $_[1] }
4742 5020
   
5021
+    sub as_string { return "== $_[0]{version}" }
4743 5022
   
4744
-          } else {
4745
-              $self->_error( "Unknown key, '$key', found in map structure" );
4746
-          }
4747
-          pop @{$self->{stack}};
4748
-      }
4749
-  }
5023
+    sub as_modifiers { return [ [ exact_version => $_[0]{version} ] ] }
4750 5024
   
4751
-  # if it's a string, make it into a list and check the list
4752
-  sub check_lazylist {
4753
-      my ($self,$spec,$data) = @_;
5025
+    sub _clone {
5026
+      (ref $_[0])->_new( version->new( $_[0]{version} ) )
5027
+    }
4754 5028
   
4755
-      if ( defined $data && ! ref($data) ) {
4756
-        $data = [ $data ];
4757
-      }
5029
+    sub with_exact_version {
5030
+      my ($self, $version) = @_;
4758 5031
   
4759
-      $self->check_list($spec,$data);
4760
-  }
5032
+      return $self->_clone if $self->_accepts($version);
4761 5033
   
4762
-  sub check_list {
4763
-      my ($self,$spec,$data) = @_;
5034
+      Carp::confess("illegal requirements: unequal exact version specified");
5035
+    }
4764 5036
   
4765
-      if(ref($data) ne 'ARRAY') {
4766
-          $self->_error( "Expected a list structure" );
4767
-          return;
4768
-      }
5037
+    sub with_minimum {
5038
+      my ($self, $minimum) = @_;
5039
+      return $self->_clone if $self->{version} >= $minimum;
5040
+      Carp::confess("illegal requirements: minimum above exact specification");
5041
+    }
4769 5042
   
4770
-      if(defined $spec->{mandatory}) {
4771
-          if(!defined $data->[0]) {
4772
-              $self->_error( "Missing entries from mandatory list" );
4773
-          }
4774
-      }
5043
+    sub with_maximum {
5044
+      my ($self, $maximum) = @_;
5045
+      return $self->_clone if $self->{version} <= $maximum;
5046
+      Carp::confess("illegal requirements: maximum below exact specification");
5047
+    }
4775 5048
   
4776
-      for my $value (@$data) {
4777
-          push @{$self->{stack}}, $value || "<undef>";
4778
-          if(defined $spec->{value}) {
4779
-              $spec->{value}->($self,'list',$value);
4780
-          } elsif(defined $spec->{'map'}) {
4781
-              $self->check_map($spec->{'map'},$value);
4782
-          } elsif(defined $spec->{'list'}) {
4783
-              $self->check_list($spec->{'list'},$value);
4784
-          } elsif(defined $spec->{'lazylist'}) {
4785
-              $self->check_lazylist($spec->{'lazylist'},$value);
4786
-          } elsif ($spec->{':key'}) {
4787
-              $self->check_map($spec,$value);
4788
-          } else {
4789
-            $self->_error( "$spec_error associated with '$self->{stack}[-2]'" );
4790
-          }
4791
-          pop @{$self->{stack}};
4792
-      }
5049
+    sub with_exclusion {
5050
+      my ($self, $exclusion) = @_;
5051
+      return $self->_clone unless $exclusion == $self->{version};
5052
+      Carp::confess("illegal requirements: excluded exact specification");
5053
+    }
4793 5054
   }
4794 5055
   
5056
+  ##############################################################
4795 5057
   
4796
-  sub header {
4797
-      my ($self,$key,$value) = @_;
4798
-      if(defined $value) {
4799
-          return 1    if($value && $value =~ /^--- #YAML:1.0/);
4800
-      }
4801
-      $self->_error( "file does not have a valid YAML header." );
4802
-      return 0;
4803
-  }
5058
+  {
5059
+    package
5060
+      CPAN::Meta::Requirements::_Range::Range;
4804 5061
   
4805
-  sub release_status {
4806
-    my ($self,$key,$value) = @_;
4807
-    if(defined $value) {
4808
-      my $version = $self->{data}{version} || '';
4809
-      if ( $version =~ /_/ ) {
4810
-        return 1 if ( $value =~ /\A(?:testing|unstable)\z/ );
4811
-        $self->_error( "'$value' for '$key' is invalid for version '$version'" );
4812
-      }
4813
-      else {
4814
-        return 1 if ( $value =~ /\A(?:stable|testing|unstable)\z/ );
4815
-        $self->_error( "'$value' for '$key' is invalid" );
4816
-      }
5062
+    sub _self { ref($_[0]) ? $_[0] : (bless { } => $_[0]) }
5063
+  
5064
+    sub _clone {
5065
+      return (bless { } => $_[0]) unless ref $_[0];
5066
+  
5067
+      my ($s) = @_;
5068
+      my %guts = (
5069
+        (exists $s->{minimum} ? (minimum => version->new($s->{minimum})) : ()),
5070
+        (exists $s->{maximum} ? (maximum => version->new($s->{maximum})) : ()),
5071
+  
5072
+        (exists $s->{exclusions}
5073
+          ? (exclusions => [ map { version->new($_) } @{ $s->{exclusions} } ])
5074
+          : ()),
5075
+      );
5076
+  
5077
+      bless \%guts => ref($s);
4817 5078
     }
4818
-    else {
4819
-      $self->_error( "'$key' is not defined" );
5079
+  
5080
+    sub as_modifiers {
5081
+      my ($self) = @_;
5082
+      my @mods;
5083
+      push @mods, [ add_minimum => $self->{minimum} ] if exists $self->{minimum};
5084
+      push @mods, [ add_maximum => $self->{maximum} ] if exists $self->{maximum};
5085
+      push @mods, map {; [ add_exclusion => $_ ] } @{$self->{exclusions} || []};
5086
+      return \@mods;
4820 5087
     }
4821
-    return 0;
4822
-  }
4823 5088
   
4824
-  # _uri_split taken from URI::Split by Gisle Aas, Copyright 2003
4825
-  sub _uri_split {
4826
-       return $_[0] =~ m,(?:([^:/?#]+):)?(?://([^/?#]*))?([^?#]*)(?:\?([^#]*))?(?:#(.*))?,;
4827
-  }
5089
+    sub as_string {
5090
+      my ($self) = @_;
4828 5091
   
4829
-  sub url {
4830
-      my ($self,$key,$value) = @_;
4831
-      if(defined $value) {
4832
-        my ($scheme, $auth, $path, $query, $frag) = _uri_split($value);
4833
-        unless ( defined $scheme && length $scheme ) {
4834
-          $self->_error( "'$value' for '$key' does not have a URL scheme" );
4835
-          return 0;
4836
-        }
4837
-        unless ( defined $auth && length $auth ) {
4838
-          $self->_error( "'$value' for '$key' does not have a URL authority" );
4839
-          return 0;
4840
-        }
4841
-        return 1;
4842
-      }
4843
-      $value ||= '';
4844
-      $self->_error( "'$value' for '$key' is not a valid URL." );
4845
-      return 0;
4846
-  }
5092
+      return 0 if ! keys %$self;
4847 5093
   
4848
-  sub urlspec {
4849
-      my ($self,$key,$value) = @_;
4850
-      if(defined $value) {
4851
-          return 1    if($value && $known_specs{$self->{spec}} eq $value);
4852
-          if($value && $known_urls{$value}) {
4853
-              $self->_error( 'META specification URL does not match version' );
4854
-              return 0;
4855
-          }
4856
-      }
4857
-      $self->_error( 'Unknown META specification' );
4858
-      return 0;
4859
-  }
5094
+      return "$self->{minimum}" if (keys %$self) == 1 and exists $self->{minimum};
4860 5095
   
4861
-  sub anything { return 1 }
5096
+      my @exclusions = @{ $self->{exclusions} || [] };
4862 5097
   
4863
-  sub string {
4864
-      my ($self,$key,$value) = @_;
4865
-      if(defined $value) {
4866
-          return 1    if($value || $value =~ /^0$/);
4867
-      }
4868
-      $self->_error( "value is an undefined string" );
4869
-      return 0;
4870
-  }
5098
+      my @parts;
4871 5099
   
4872
-  sub string_or_undef {
4873
-      my ($self,$key,$value) = @_;
4874
-      return 1    unless(defined $value);
4875
-      return 1    if($value || $value =~ /^0$/);
4876
-      $self->_error( "No string defined for '$key'" );
4877
-      return 0;
4878
-  }
5100
+      for my $pair (
5101
+        [ qw( >= > minimum ) ],
5102
+        [ qw( <= < maximum ) ],
5103
+      ) {
5104
+        my ($op, $e_op, $k) = @$pair;
5105
+        if (exists $self->{$k}) {
5106
+          my @new_exclusions = grep { $_ != $self->{ $k } } @exclusions;
5107
+          if (@new_exclusions == @exclusions) {
5108
+            push @parts, "$op $self->{ $k }";
5109
+          } else {
5110
+            push @parts, "$e_op $self->{ $k }";
5111
+            @exclusions = @new_exclusions;
5112
+          }
5113
+        }
5114
+      }
4879 5115
   
4880
-  sub file {
4881
-      my ($self,$key,$value) = @_;
4882
-      return 1    if(defined $value);
4883
-      $self->_error( "No file defined for '$key'" );
4884
-      return 0;
4885
-  }
5116
+      push @parts, map {; "!= $_" } @exclusions;
4886 5117
   
4887
-  sub exversion {
4888
-      my ($self,$key,$value) = @_;
4889
-      if(defined $value && ($value || $value =~ /0/)) {
4890
-          my $pass = 1;
4891
-          for(split(",",$value)) { $self->version($key,$_) or ($pass = 0); }
4892
-          return $pass;
4893
-      }
4894
-      $value = '<undef>'  unless(defined $value);
4895
-      $self->_error( "'$value' for '$key' is not a valid version." );
4896
-      return 0;
4897
-  }
5118
+      return join q{, }, @parts;
5119
+    }
4898 5120
   
4899
-  sub version {
4900
-      my ($self,$key,$value) = @_;
4901
-      if(defined $value) {
4902
-          return 0    unless($value || $value =~ /0/);
4903
-          return 1    if($value =~ /^\s*((<|<=|>=|>|!=|==)\s*)?v?\d+((\.\d+((_|\.)\d+)?)?)/);
4904
-      } else {
4905
-          $value = '<undef>';
4906
-      }
4907
-      $self->_error( "'$value' for '$key' is not a valid version." );
4908
-      return 0;
4909
-  }
5121
+    sub with_exact_version {
5122
+      my ($self, $version) = @_;
5123
+      $self = $self->_clone;
4910 5124
   
4911
-  sub boolean {
4912
-      my ($self,$key,$value) = @_;
4913
-      if(defined $value) {
4914
-          return 1    if($value =~ /^(0|1|true|false)$/);
4915
-      } else {
4916
-          $value = '<undef>';
4917
-      }
4918
-      $self->_error( "'$value' for '$key' is not a boolean value." );
4919
-      return 0;
4920
-  }
5125
+      Carp::confess("illegal requirements: exact specification outside of range")
5126
+        unless $self->_accepts($version);
4921 5127
   
4922
-  my %v1_licenses = (
4923
-      'perl'         => 'http://dev.perl.org/licenses/',
4924
-      'gpl'          => 'http://www.opensource.org/licenses/gpl-license.php',
4925
-      'apache'       => 'http://apache.org/licenses/LICENSE-2.0',
4926
-      'artistic'     => 'http://opensource.org/licenses/artistic-license.php',
4927
-      'artistic_2'   => 'http://opensource.org/licenses/artistic-license-2.0.php',
4928
-      'lgpl'         => 'http://www.opensource.org/licenses/lgpl-license.phpt',
4929
-      'bsd'          => 'http://www.opensource.org/licenses/bsd-license.php',
4930
-      'gpl'          => 'http://www.opensource.org/licenses/gpl-license.php',
4931
-      'mit'          => 'http://opensource.org/licenses/mit-license.php',
4932
-      'mozilla'      => 'http://opensource.org/licenses/mozilla1.1.php',
4933
-      'open_source'  => undef,
4934
-      'unrestricted' => undef,
4935
-      'restrictive'  => undef,
4936
-      'unknown'      => undef,
4937
-  );
5128
+      return CPAN::Meta::Requirements::_Range::Exact->_new($version);
5129
+    }
4938 5130
   
4939
-  my %v2_licenses = map { $_ => 1 } qw(
4940
-    agpl_3
4941
-    apache_1_1
4942
-    apache_2_0
4943
-    artistic_1
4944
-    artistic_2
4945
-    bsd
4946
-    freebsd
4947
-    gfdl_1_2
4948
-    gfdl_1_3
4949
-    gpl_1
4950
-    gpl_2
4951
-    gpl_3
4952
-    lgpl_2_1
4953
-    lgpl_3_0
4954
-    mit
4955
-    mozilla_1_0
4956
-    mozilla_1_1
4957
-    openssl
4958
-    perl_5
4959
-    qpl_1_0
4960
-    ssleay
4961
-    sun
4962
-    zlib
4963
-    open_source
4964
-    restricted
4965
-    unrestricted
4966
-    unknown
4967
-  );
5131
+    sub _simplify {
5132
+      my ($self) = @_;
4968 5133
   
4969
-  sub license {
4970
-      my ($self,$key,$value) = @_;
4971
-      my $licenses = $self->{spec} < 2 ? \%v1_licenses : \%v2_licenses;
4972
-      if(defined $value) {
4973
-          return 1    if($value && exists $licenses->{$value});
4974
-      } else {
4975
-          $value = '<undef>';
4976
-      }
4977
-      $self->_error( "License '$value' is invalid" );
4978
-      return 0;
4979
-  }
5134
+      if (defined $self->{minimum} and defined $self->{maximum}) {
5135
+        if ($self->{minimum} == $self->{maximum}) {
5136
+          Carp::confess("illegal requirements: excluded all values")
5137
+            if grep { $_ == $self->{minimum} } @{ $self->{exclusions} || [] };
4980 5138
   
4981
-  sub custom_1 {
4982
-      my ($self,$key) = @_;
4983
-      if(defined $key) {
4984
-          # a valid user defined key should be alphabetic
4985
-          # and contain at least one capital case letter.
4986
-          return 1    if($key && $key =~ /^[_a-z]+$/i && $key =~ /[A-Z]/);
4987
-      } else {
4988
-          $key = '<undef>';
4989
-      }
4990
-      $self->_error( "Custom resource '$key' must be in CamelCase." );
4991
-      return 0;
4992
-  }
5139
+          return CPAN::Meta::Requirements::_Range::Exact->_new($self->{minimum})
5140
+        }
4993 5141
   
4994
-  sub custom_2 {
4995
-      my ($self,$key) = @_;
4996
-      if(defined $key) {
4997
-          return 1    if($key && $key =~ /^x_/i);  # user defined
4998
-      } else {
4999
-          $key = '<undef>';
5142
+        Carp::confess("illegal requirements: minimum exceeds maximum")
5143
+          if $self->{minimum} > $self->{maximum};
5000 5144
       }
5001
-      $self->_error( "Custom key '$key' must begin with 'x_' or 'X_'." );
5002
-      return 0;
5003
-  }
5004 5145
   
5005
-  sub identifier {
5006
-      my ($self,$key) = @_;
5007
-      if(defined $key) {
5008
-          return 1    if($key && $key =~ /^([a-z][_a-z]+)$/i);    # spec 2.0 defined
5009
-      } else {
5010
-          $key = '<undef>';
5146
+      # eliminate irrelevant exclusions
5147
+      if ($self->{exclusions}) {
5148
+        my %seen;
5149
+        @{ $self->{exclusions} } = grep {
5150
+          (! defined $self->{minimum} or $_ >= $self->{minimum})
5151
+          and
5152
+          (! defined $self->{maximum} or $_ <= $self->{maximum})
5153
+          and
5154
+          ! $seen{$_}++
5155
+        } @{ $self->{exclusions} };
5011 5156
       }
5012
-      $self->_error( "Key '$key' is not a legal identifier." );
5013
-      return 0;
5014
-  }
5015 5157
   
5016
-  sub module {
5017
-      my ($self,$key) = @_;
5018
-      if(defined $key) {
5019
-          return 1    if($key && $key =~ /^[A-Za-z0-9_]+(::[A-Za-z0-9_]+)*$/);
5020
-      } else {
5021
-          $key = '<undef>';
5022
-      }
5023
-      $self->_error( "Key '$key' is not a legal module name." );
5024
-      return 0;
5025
-  }
5158
+      return $self;
5159
+    }
5026 5160
   
5027
-  my @valid_phases = qw/ configure build test runtime develop /;
5028
-  sub phase {
5029
-      my ($self,$key) = @_;
5030
-      if(defined $key) {
5031
-          return 1 if( length $key && grep { $key eq $_ } @valid_phases );
5032
-          return 1 if $key =~ /x_/i;
5161
+    sub with_minimum {
5162
+      my ($self, $minimum) = @_;
5163
+      $self = $self->_clone;
5164
+  
5165
+      if (defined (my $old_min = $self->{minimum})) {
5166
+        $self->{minimum} = (sort { $b cmp $a } ($minimum, $old_min))[0];
5033 5167
       } else {
5034
-          $key = '<undef>';
5168
+        $self->{minimum} = $minimum;
5035 5169
       }
5036
-      $self->_error( "Key '$key' is not a legal phase." );
5037
-      return 0;
5038
-  }
5039 5170
   
5040
-  my @valid_relations = qw/ requires recommends suggests conflicts /;
5041
-  sub relation {
5042
-      my ($self,$key) = @_;
5043
-      if(defined $key) {
5044
-          return 1 if( length $key && grep { $key eq $_ } @valid_relations );
5045
-          return 1 if $key =~ /x_/i;
5171
+      return $self->_simplify;
5172
+    }
5173
+  
5174
+    sub with_maximum {
5175
+      my ($self, $maximum) = @_;
5176
+      $self = $self->_clone;
5177
+  
5178
+      if (defined (my $old_max = $self->{maximum})) {
5179
+        $self->{maximum} = (sort { $a cmp $b } ($maximum, $old_max))[0];
5046 5180
       } else {
5047
-          $key = '<undef>';
5181
+        $self->{maximum} = $maximum;
5048 5182
       }
5049
-      $self->_error( "Key '$key' is not a legal prereq relationship." );
5050
-      return 0;
5051
-  }
5052 5183
   
5053
-  sub _error {
5054
-      my $self = shift;
5055
-      my $mess = shift;
5056
-  
5057
-      $mess .= ' ('.join(' -> ',@{$self->{stack}}).')'  if($self->{stack});
5058
-      $mess .= " [Validation: $self->{spec}]";
5184
+      return $self->_simplify;
5185
+    }
5059 5186
   
5060
-      push @{$self->{errors}}, $mess;
5061
-  }
5187
+    sub with_exclusion {
5188
+      my ($self, $exclusion) = @_;
5189
+      $self = $self->_clone;
5062 5190
   
5063
-  1;
5191
+      push @{ $self->{exclusions} ||= [] }, $exclusion;
5064 5192
   
5193
+      return $self->_simplify;
5194
+    }
5065 5195
   
5196
+    sub _accepts {
5197
+      my ($self, $version) = @_;
5066 5198
   
5199
+      return if defined $self->{minimum} and $version < $self->{minimum};
5200
+      return if defined $self->{maximum} and $version > $self->{maximum};
5201
+      return if defined $self->{exclusions}
5202
+            and grep { $version == $_ } @{ $self->{exclusions} };
5067 5203
   
5068
-  __END__
5204
+      return 1;
5205
+    }
5206
+  }
5069 5207
   
5208
+  1;
5209
+  # vim: ts=2 sts=2 sw=2 et:
5070 5210
   
5211
+  __END__
5212
+  =pod
5071 5213
   
5072
-CPAN_META_VALIDATOR
5214
+CPAN_META_REQUIREMENTS
5073 5215
 
5074
-$fatpacked{"CPAN/Meta/YAML.pm"} = <<'CPAN_META_YAML';
5075
-  package CPAN::Meta::YAML;
5076
-  BEGIN {
5077
-    $CPAN::Meta::YAML::VERSION = '0.003';
5078
-  }
5079
-  
5216
+$fatpacked{"CPAN/Meta/Spec.pm"} = <<'CPAN_META_SPEC';
5217
+  # vi:tw=72
5218
+  use 5.006;
5080 5219
   use strict;
5220
+  use warnings;
5221
+  package CPAN::Meta::Spec;
5222
+  our $VERSION = '2.120921'; # VERSION
5081 5223
   
5082
-  # UTF Support?
5083
-  sub HAVE_UTF8 () { $] >= 5.007003 }
5084
-  BEGIN {
5085
-  	if ( HAVE_UTF8 ) {
5086
-  		# The string eval helps hide this from Test::MinimumVersion
5087
-  		eval "require utf8;";
5088
-  		die "Failed to load UTF-8 support" if $@;
5089
-  	}
5090
-  
5091
-  	# Class structure
5092
-  	require 5.004;
5093
-  	require Exporter;
5094
-  	require Carp;
5095
-  	@CPAN::Meta::YAML::ISA       = qw{ Exporter  };
5096
-  	@CPAN::Meta::YAML::EXPORT    = qw{ Load Dump };
5097
-  	@CPAN::Meta::YAML::EXPORT_OK = qw{ LoadFile DumpFile freeze thaw };
5224
+  1;
5098 5225
   
5099
-  	# Error storage
5100
-  	$CPAN::Meta::YAML::errstr    = '';
5101
-  }
5226
+  # ABSTRACT: specification for CPAN distribution metadata
5102 5227
   
5103
-  # The character class of all characters we need to escape
5104
-  # NOTE: Inlined, since it's only used once
5105
-  # my $RE_ESCAPE = '[\\x00-\\x08\\x0b-\\x0d\\x0e-\\x1f\"\n]';
5106 5228
   
5107
-  # Printed form of the unprintable characters in the lowest range
5108
-  # of ASCII characters, listed by ASCII ordinal position.
5109
-  my @UNPRINTABLE = qw(
5110
-  	z    x01  x02  x03  x04  x05  x06  a
5111
-  	x08  t    n    v    f    r    x0e  x0f
5112
-  	x10  x11  x12  x13  x14  x15  x16  x17
5113
-  	x18  x19  x1a  e    x1c  x1d  x1e  x1f
5114
-  );
5115 5229
   
5116
-  # Printable characters for escapes
5117
-  my %UNESCAPES = (
5118
-  	z => "\x00", a => "\x07", t    => "\x09",
5119
-  	n => "\x0a", v => "\x0b", f    => "\x0c",
5120
-  	r => "\x0d", e => "\x1b", '\\' => '\\',
5121
-  );
5230
+  __END__
5231
+  =pod
5122 5232
   
5123
-  # Special magic boolean words
5124
-  my %QUOTE = map { $_ => 1 } qw{
5125
-  	null Null NULL
5126
-  	y Y yes Yes YES n N no No NO
5127
-  	true True TRUE false False FALSE
5128
-  	on On ON off Off OFF
5129
-  };
5233
+CPAN_META_SPEC
5234
+
5235
+$fatpacked{"CPAN/Meta/Validator.pm"} = <<'CPAN_META_VALIDATOR';
5236
+  use 5.006;
5237
+  use strict;
5238
+  use warnings;
5239
+  package CPAN::Meta::Validator;
5240
+  our $VERSION = '2.120921'; # VERSION
5130 5241
   
5131 5242
   
5243
+  #--------------------------------------------------------------------------#
5244
+  # This code copied and adapted from Test::CPAN::Meta
5245
+  # by Barbie, <barbie@cpan.org> for Miss Barbell Productions,
5246
+  # L<http://www.missbarbell.co.uk>
5247
+  #--------------------------------------------------------------------------#
5132 5248
   
5249
+  #--------------------------------------------------------------------------#
5250
+  # Specification Definitions
5251
+  #--------------------------------------------------------------------------#
5133 5252
   
5253
+  my %known_specs = (
5254
+      '1.4' => 'http://module-build.sourceforge.net/META-spec-v1.4.html',
5255
+      '1.3' => 'http://module-build.sourceforge.net/META-spec-v1.3.html',
5256
+      '1.2' => 'http://module-build.sourceforge.net/META-spec-v1.2.html',
5257
+      '1.1' => 'http://module-build.sourceforge.net/META-spec-v1.1.html',
5258
+      '1.0' => 'http://module-build.sourceforge.net/META-spec-v1.0.html'
5259
+  );
5260
+  my %known_urls = map {$known_specs{$_} => $_} keys %known_specs;
5134 5261
   
5135
-  #####################################################################
5136
-  # Implementation
5262
+  my $module_map1 = { 'map' => { ':key' => { name => \&module, value => \&exversion } } };
5137 5263
   
5138
-  # Create an empty CPAN::Meta::YAML object
5139
-  sub new {
5140
-  	my $class = shift;
5141
-  	bless [ @_ ], $class;
5142
-  }
5264
+  my $module_map2 = { 'map' => { ':key' => { name => \&module, value => \&version   } } };
5143 5265
   
5144
-  # Create an object from a file
5145
-  sub read {
5146
-  	my $class = ref $_[0] ? ref shift : shift;
5266
+  my $no_index_2 = {
5267
+      'map'       => { file       => { list => { value => \&string } },
5268
+                       directory  => { list => { value => \&string } },
5269
+                       'package'  => { list => { value => \&string } },
5270
+                       namespace  => { list => { value => \&string } },
5271
+                      ':key'      => { name => \&custom_2, value => \&anything },
5272
+      }
5273
+  };
5147 5274
   
5148
-  	# Check the file
5149
-  	my $file = shift or return $class->_error( 'You did not specify a file name' );
5150
-  	return $class->_error( "File '$file' does not exist" )              unless -e $file;
5151
-  	return $class->_error( "'$file' is a directory, not a file" )       unless -f _;
5152
-  	return $class->_error( "Insufficient permissions to read '$file'" ) unless -r _;
5275
+  my $no_index_1_3 = {
5276
+      'map'       => { file       => { list => { value => \&string } },
5277
+                       directory  => { list => { value => \&string } },
5278
+                       'package'  => { list => { value => \&string } },
5279
+                       namespace  => { list => { value => \&string } },
5280
+                       ':key'     => { name => \&string, value => \&anything },
5281
+      }
5282
+  };
5153 5283
   
5154
-  	# Slurp in the file
5155
-  	local $/ = undef;
5156
-  	local *CFG;
5157
-  	unless ( open(CFG, $file) ) {
5158
-  		return $class->_error("Failed to open file '$file': $!");
5159
-  	}
5160
-  	my $contents = <CFG>;
5161
-  	unless ( close(CFG) ) {
5162
-  		return $class->_error("Failed to close file '$file': $!");
5163
-  	}
5284
+  my $no_index_1_2 = {
5285
+      'map'       => { file       => { list => { value => \&string } },
5286
+                       dir        => { list => { value => \&string } },
5287
+                       'package'  => { list => { value => \&string } },
5288
+                       namespace  => { list => { value => \&string } },
5289
+                       ':key'     => { name => \&string, value => \&anything },
5290
+      }
5291
+  };
5164 5292
   
5165
-  	$class->read_string( $contents );
5166
-  }
5293
+  my $no_index_1_1 = {
5294
+      'map'       => { ':key'     => { name => \&string, list => { value => \&string } },
5295
+      }
5296
+  };
5167 5297
   
5168
-  # Create an object from a string
5169
-  sub read_string {
5170
-  	my $class  = ref $_[0] ? ref shift : shift;
5171
-  	my $self   = bless [], $class;
5172
-  	my $string = $_[0];
5173
-  	eval {
5174
-  		unless ( defined $string ) {
5175
-  			die \"Did not provide a string to load";
5176
-  		}
5298
+  my $prereq_map = {
5299
+    map => {
5300
+      ':key' => {
5301
+        name => \&phase,
5302
+        'map' => {
5303
+          ':key'  => {
5304
+            name => \&relation,
5305
+            %$module_map1,
5306
+          },
5307
+        },
5308
+      }
5309
+    },
5310
+  };
5177 5311
   
5178
-  		# Byte order marks
5179
-  		# NOTE: Keeping this here to educate maintainers
5180
-  		# my %BOM = (
5181
-  		#     "\357\273\277" => 'UTF-8',
5182
-  		#     "\376\377"     => 'UTF-16BE',
5183
-  		#     "\377\376"     => 'UTF-16LE',
5184
-  		#     "\377\376\0\0" => 'UTF-32LE'
5185
-  		#     "\0\0\376\377" => 'UTF-32BE',
5186
-  		# );
5187
-  		if ( $string =~ /^(?:\376\377|\377\376|\377\376\0\0|\0\0\376\377)/ ) {
5188
-  			die \"Stream has a non UTF-8 BOM";
5189
-  		} else {
5190
-  			# Strip UTF-8 bom if found, we'll just ignore it
5191
-  			$string =~ s/^\357\273\277//;
5192
-  		}
5312
+  my %definitions = (
5313
+    '2' => {
5314
+      # REQUIRED
5315
+      'abstract'            => { mandatory => 1, value => \&string  },
5316
+      'author'              => { mandatory => 1, lazylist => { value => \&string } },
5317
+      'dynamic_config'      => { mandatory => 1, value => \&boolean },
5318
+      'generated_by'        => { mandatory => 1, value => \&string  },
5319
+      'license'             => { mandatory => 1, lazylist => { value => \&license } },
5320
+      'meta-spec' => {
5321
+        mandatory => 1,
5322
+        'map' => {
5323
+          version => { mandatory => 1, value => \&version},
5324
+          url     => { value => \&url },
5325
+          ':key' => { name => \&custom_2, value => \&anything },
5326
+        }
5327
+      },
5328
+      'name'                => { mandatory => 1, value => \&string  },
5329
+      'release_status'      => { mandatory => 1, value => \&release_status },
5330
+      'version'             => { mandatory => 1, value => \&version },
5193 5331
   
5194
-  		# Try to decode as utf8
5195
-  		utf8::decode($string) if HAVE_UTF8;
5332
+      # OPTIONAL
5333
+      'description' => { value => \&string },
5334
+      'keywords'    => { lazylist => { value => \&string } },
5335
+      'no_index'    => $no_index_2,
5336
+      'optional_features'   => {
5337
+        'map'       => {
5338
+          ':key'  => {
5339
+            name => \&string,
5340
+            'map'   => {
5341
+              description        => { value => \&string },
5342
+              prereqs => $prereq_map,
5343
+              ':key' => { name => \&custom_2, value => \&anything },
5344
+            }
5345
+          }
5346
+        }
5347
+      },
5348
+      'prereqs' => $prereq_map,
5349
+      'provides'    => {
5350
+        'map'       => {
5351
+          ':key' => {
5352
+            name  => \&module,
5353
+            'map' => {
5354
+              file    => { mandatory => 1, value => \&file },
5355
+              version => { value => \&version },
5356
+              ':key' => { name => \&custom_2, value => \&anything },
5357
+            }
5358
+          }
5359
+        }
5360
+      },
5361
+      'resources'   => {
5362
+        'map'       => {
5363
+          license    => { lazylist => { value => \&url } },
5364
+          homepage   => { value => \&url },
5365
+          bugtracker => {
5366
+            'map' => {
5367
+              web => { value => \&url },
5368
+              mailto => { value => \&string},
5369
+              ':key' => { name => \&custom_2, value => \&anything },
5370
+            }
5371
+          },
5372
+          repository => {
5373
+            'map' => {
5374
+              web => { value => \&url },
5375
+              url => { value => \&url },
5376
+              type => { value => \&string },
5377
+              ':key' => { name => \&custom_2, value => \&anything },
5378
+            }
5379
+          },
5380
+          ':key'     => { value => \&string, name => \&custom_2 },
5381
+        }
5382
+      },
5196 5383
   
5197
-  		# Check for some special cases
5198
-  		return $self unless length $string;
5199
-  		unless ( $string =~ /[\012\015]+\z/ ) {
5200
-  			die \"Stream does not end with newline character";
5201
-  		}
5384
+      # CUSTOM -- additional user defined key/value pairs
5385
+      # note we can only validate the key name, as the structure is user defined
5386
+      ':key'        => { name => \&custom_2, value => \&anything },
5387
+    },
5202 5388
   
5203
-  		# Split the file into lines
5204
-  		my @lines = grep { ! /^\s*(?:\#.*)?\z/ }
5205
-  			    split /(?:\015{1,2}\012|\015|\012)/, $string;
5206
-  
5207
-  		# Strip the initial YAML header
5208
-  		@lines and $lines[0] =~ /^\%YAML[: ][\d\.]+.*\z/ and shift @lines;
5209
-  
5210
-  		# A nibbling parser
5211
-  		while ( @lines ) {
5212
-  			# Do we have a document header?
5213
-  			if ( $lines[0] =~ /^---\s*(?:(.+)\s*)?\z/ ) {
5214
-  				# Handle scalar documents
5215
-  				shift @lines;
5216
-  				if ( defined $1 and $1 !~ /^(?:\#.+|\%YAML[: ][\d\.]+)\z/ ) {
5217
-  					push @$self, $self->_read_scalar( "$1", [ undef ], \@lines );
5218
-  					next;
5219
-  				}
5220
-  			}
5389
+  '1.4' => {
5390
+    'meta-spec'           => {
5391
+      mandatory => 1,
5392
+      'map' => {
5393
+        version => { mandatory => 1, value => \&version},
5394
+        url     => { mandatory => 1, value => \&urlspec },
5395
+        ':key'  => { name => \&string, value => \&anything },
5396
+      },
5397
+    },
5221 5398
   
5222
-  			if ( ! @lines or $lines[0] =~ /^(?:---|\.\.\.)/ ) {
5223
-  				# A naked document
5224
-  				push @$self, undef;
5225
-  				while ( @lines and $lines[0] !~ /^---/ ) {
5226
-  					shift @lines;
5227
-  				}
5399
+    'name'                => { mandatory => 1, value => \&string  },
5400
+    'version'             => { mandatory => 1, value => \&version },
5401
+    'abstract'            => { mandatory => 1, value => \&string  },
5402
+    'author'              => { mandatory => 1, list  => { value => \&string } },
5403
+    'license'             => { mandatory => 1, value => \&license },
5404
+    'generated_by'        => { mandatory => 1, value => \&string  },
5228 5405
   
5229
-  			} elsif ( $lines[0] =~ /^\s*\-/ ) {
5230
-  				# An array at the root
5231
-  				my $document = [ ];
5232
-  				push @$self, $document;
5233
-  				$self->_read_array( $document, [ 0 ], \@lines );
5406
+    'distribution_type'   => { value => \&string  },
5407
+    'dynamic_config'      => { value => \&boolean },
5234 5408
   
5235
-  			} elsif ( $lines[0] =~ /^(\s*)\S/ ) {
5236
-  				# A hash at the root
5237
-  				my $document = { };
5238
-  				push @$self, $document;
5239
-  				$self->_read_hash( $document, [ length($1) ], \@lines );
5409
+    'requires'            => $module_map1,
5410
+    'recommends'          => $module_map1,
5411
+    'build_requires'      => $module_map1,
5412
+    'configure_requires'  => $module_map1,
5413
+    'conflicts'           => $module_map2,
5240 5414
   
5241
-  			} else {
5242
-  				die \"CPAN::Meta::YAML failed to classify the line '$lines[0]'";
5243
-  			}
5244
-  		}
5245
-  	};
5246
-  	if ( ref $@ eq 'SCALAR' ) {
5247
-  		return $self->_error(${$@});
5248
-  	} elsif ( $@ ) {
5249
-  		require Carp;
5250
-  		Carp::croak($@);
5251
-  	}
5415
+    'optional_features'   => {
5416
+      'map'       => {
5417
+          ':key'  => { name => \&string,
5418
+              'map'   => { description        => { value => \&string },
5419
+                           requires           => $module_map1,
5420
+                           recommends         => $module_map1,
5421
+                           build_requires     => $module_map1,
5422
+                           conflicts          => $module_map2,
5423
+                           ':key'  => { name => \&string, value => \&anything },
5424
+              }
5425
+          }
5426
+       }
5427
+    },
5252 5428
   
5253
-  	return $self;
5254
-  }
5429
+    'provides'    => {
5430
+      'map'       => {
5431
+        ':key' => { name  => \&module,
5432
+          'map' => {
5433
+            file    => { mandatory => 1, value => \&file },
5434
+            version => { value => \&version },
5435
+            ':key'  => { name => \&string, value => \&anything },
5436
+          }
5437
+        }
5438
+      }
5439
+    },
5255 5440
   
5256
-  # Deparse a scalar string to the actual scalar
5257
-  sub _read_scalar {
5258
-  	my ($self, $string, $indent, $lines) = @_;
5441
+    'no_index'    => $no_index_1_3,
5442
+    'private'     => $no_index_1_3,
5259 5443
   
5260
-  	# Trim trailing whitespace
5261
-  	$string =~ s/\s*\z//;
5444
+    'keywords'    => { list => { value => \&string } },
5262 5445
   
5263
-  	# Explitic null/undef
5264
-  	return undef if $string eq '~';
5446
+    'resources'   => {
5447
+      'map'       => { license    => { value => \&url },
5448
+                       homepage   => { value => \&url },
5449
+                       bugtracker => { value => \&url },
5450
+                       repository => { value => \&url },
5451
+                       ':key'     => { value => \&string, name => \&custom_1 },
5452
+      }
5453
+    },
5265 5454
   
5266
-  	# Single quote
5267
-  	if ( $string =~ /^\'(.*?)\'(?:\s+\#.*)?\z/ ) {
5268
-  		return '' unless defined $1;
5269
-  		$string = $1;
5270
-  		$string =~ s/\'\'/\'/g;
5271
-  		return $string;
5272
-  	}
5455
+    # additional user defined key/value pairs
5456
+    # note we can only validate the key name, as the structure is user defined
5457
+    ':key'        => { name => \&string, value => \&anything },
5458
+  },
5273 5459
   
5274
-  	# Double quote.
5275
-  	# The commented out form is simpler, but overloaded the Perl regex
5276
-  	# engine due to recursion and backtracking problems on strings
5277
-  	# larger than 32,000ish characters. Keep it for reference purposes.
5278
-  	# if ( $string =~ /^\"((?:\\.|[^\"])*)\"\z/ ) {
5279
-  	if ( $string =~ /^\"([^\\"]*(?:\\.[^\\"]*)*)\"(?:\s+\#.*)?\z/ ) {
5280
-  		# Reusing the variable is a little ugly,
5281
-  		# but avoids a new variable and a string copy.
5282
-  		$string = $1;
5283
-  		$string =~ s/\\"/"/g;
5284
-  		$string =~ s/\\([never\\fartz]|x([0-9a-fA-F]{2}))/(length($1)>1)?pack("H2",$2):$UNESCAPES{$1}/gex;
5285
-  		return $string;
5286
-  	}
5460
+  '1.3' => {
5461
+    'meta-spec'           => {
5462
+      mandatory => 1,
5463
+      'map' => {
5464
+        version => { mandatory => 1, value => \&version},
5465
+        url     => { mandatory => 1, value => \&urlspec },
5466
+        ':key'  => { name => \&string, value => \&anything },
5467
+      },
5468
+    },
5287 5469
   
5288
-  	# Special cases
5289
-  	if ( $string =~ /^[\'\"!&]/ ) {
5290
-  		die \"CPAN::Meta::YAML does not support a feature in line '$string'";
5291
-  	}
5292
-  	return {} if $string =~ /^{}(?:\s+\#.*)?\z/;
5293
-  	return [] if $string =~ /^\[\](?:\s+\#.*)?\z/;
5470
+    'name'                => { mandatory => 1, value => \&string  },
5471
+    'version'             => { mandatory => 1, value => \&version },
5472
+    'abstract'            => { mandatory => 1, value => \&string  },
5473
+    'author'              => { mandatory => 1, list  => { value => \&string } },
5474
+    'license'             => { mandatory => 1, value => \&license },
5475
+    'generated_by'        => { mandatory => 1, value => \&string  },
5294 5476
   
5295
-  	# Regular unquoted string
5296
-  	if ( $string !~ /^[>|]/ ) {
5297
-  		if (
5298
-  			$string =~ /^(?:-(?:\s|$)|[\@\%\`])/
5299
-  			or
5300
-  			$string =~ /:(?:\s|$)/
5301
-  		) {
5302
-  			die \"CPAN::Meta::YAML found illegal characters in plain scalar: '$string'";
5303
-  		}
5304
-  		$string =~ s/\s+#.*\z//;
5305
-  		return $string;
5306
-  	}
5477
+    'distribution_type'   => { value => \&string  },
5478
+    'dynamic_config'      => { value => \&boolean },
5307 5479
   
5308
-  	# Error
5309
-  	die \"CPAN::Meta::YAML failed to find multi-line scalar content" unless @$lines;
5480
+    'requires'            => $module_map1,
5481
+    'recommends'          => $module_map1,
5482
+    'build_requires'      => $module_map1,
5483
+    'conflicts'           => $module_map2,
5310 5484
   
5311
-  	# Check the indent depth
5312
-  	$lines->[0]   =~ /^(\s*)/;
5313
-  	$indent->[-1] = length("$1");
5314
-  	if ( defined $indent->[-2] and $indent->[-1] <= $indent->[-2] ) {
5315
-  		die \"CPAN::Meta::YAML found bad indenting in line '$lines->[0]'";
5316
-  	}
5485
+    'optional_features'   => {
5486
+      'map'       => {
5487
+          ':key'  => { name => \&string,
5488
+              'map'   => { description        => { value => \&string },
5489
+                           requires           => $module_map1,
5490
+                           recommends         => $module_map1,
5491
+                           build_requires     => $module_map1,
5492
+                           conflicts          => $module_map2,
5493
+                           ':key'  => { name => \&string, value => \&anything },
5494
+              }
5495
+          }
5496
+       }
5497
+    },
5317 5498
   
5318
-  	# Pull the lines
5319
-  	my @multiline = ();
5320
-  	while ( @$lines ) {
5321
-  		$lines->[0] =~ /^(\s*)/;
5322
-  		last unless length($1) >= $indent->[-1];
5323
-  		push @multiline, substr(shift(@$lines), length($1));
5324
-  	}
5499
+    'provides'    => {
5500
+      'map'       => {
5501
+        ':key' => { name  => \&module,
5502
+          'map' => {
5503
+            file    => { mandatory => 1, value => \&file },
5504
+            version => { value => \&version },
5505
+            ':key'  => { name => \&string, value => \&anything },
5506
+          }
5507
+        }
5508
+      }
5509
+    },
5325 5510
   
5326
-  	my $j = (substr($string, 0, 1) eq '>') ? ' ' : "\n";
5327
-  	my $t = (substr($string, 1, 1) eq '-') ? ''  : "\n";
5328
-  	return join( $j, @multiline ) . $t;
5329
-  }
5330 5511
   
5331
-  # Parse an array
5332
-  sub _read_array {
5333
-  	my ($self, $array, $indent, $lines) = @_;
5512
+    'no_index'    => $no_index_1_3,
5513
+    'private'     => $no_index_1_3,
5334 5514
   
5335
-  	while ( @$lines ) {
5336
-  		# Check for a new document
5337
-  		if ( $lines->[0] =~ /^(?:---|\.\.\.)/ ) {
5338
-  			while ( @$lines and $lines->[0] !~ /^---/ ) {
5339
-  				shift @$lines;
5340
-  			}
5341
-  			return 1;
5342
-  		}
5515
+    'keywords'    => { list => { value => \&string } },
5343 5516
   
5344
-  		# Check the indent level
5345
-  		$lines->[0] =~ /^(\s*)/;
5346
-  		if ( length($1) < $indent->[-1] ) {
5347
-  			return 1;
5348
-  		} elsif ( length($1) > $indent->[-1] ) {
5349
-  			die \"CPAN::Meta::YAML found bad indenting in line '$lines->[0]'";
5350
-  		}
5517
+    'resources'   => {
5518
+      'map'       => { license    => { value => \&url },
5519
+                       homepage   => { value => \&url },
5520
+                       bugtracker => { value => \&url },
5521
+                       repository => { value => \&url },
5522
+                       ':key'     => { value => \&string, name => \&custom_1 },
5523
+      }
5524
+    },
5351 5525
   
5352
-  		if ( $lines->[0] =~ /^(\s*\-\s+)[^\'\"]\S*\s*:(?:\s+|$)/ ) {
5353
-  			# Inline nested hash
5354
-  			my $indent2 = length("$1");
5355
-  			$lines->[0] =~ s/-/ /;
5356
-  			push @$array, { };
5357
-  			$self->_read_hash( $array->[-1], [ @$indent, $indent2 ], $lines );
5526
+    # additional user defined key/value pairs
5527
+    # note we can only validate the key name, as the structure is user defined
5528
+    ':key'        => { name => \&string, value => \&anything },
5529
+  },
5358 5530
   
5359
-  		} elsif ( $lines->[0] =~ /^\s*\-(\s*)(.+?)\s*\z/ ) {
5360
-  			# Array entry with a value
5361
-  			shift @$lines;
5362
-  			push @$array, $self->_read_scalar( "$2", [ @$indent, undef ], $lines );
5531
+  # v1.2 is misleading, it seems to assume that a number of fields where created
5532
+  # within v1.1, when they were created within v1.2. This may have been an
5533
+  # original mistake, and that a v1.1 was retro fitted into the timeline, when
5534
+  # v1.2 was originally slated as v1.1. But I could be wrong ;)
5535
+  '1.2' => {
5536
+    'meta-spec'           => {
5537
+      mandatory => 1,
5538
+      'map' => {
5539
+        version => { mandatory => 1, value => \&version},
5540
+        url     => { mandatory => 1, value => \&urlspec },
5541
+        ':key'  => { name => \&string, value => \&anything },
5542
+      },
5543
+    },
5363 5544
   
5364
-  		} elsif ( $lines->[0] =~ /^\s*\-\s*\z/ ) {
5365
-  			shift @$lines;
5366
-  			unless ( @$lines ) {
5367
-  				push @$array, undef;
5368
-  				return 1;
5369
-  			}
5370
-  			if ( $lines->[0] =~ /^(\s*)\-/ ) {
5371
-  				my $indent2 = length("$1");
5372
-  				if ( $indent->[-1] == $indent2 ) {
5373
-  					# Null array entry
5374
-  					push @$array, undef;
5375
-  				} else {
5376
-  					# Naked indenter
5377
-  					push @$array, [ ];
5378
-  					$self->_read_array( $array->[-1], [ @$indent, $indent2 ], $lines );
5379
-  				}
5380 5545
   
5381
-  			} elsif ( $lines->[0] =~ /^(\s*)\S/ ) {
5382
-  				push @$array, { };
5383
-  				$self->_read_hash( $array->[-1], [ @$indent, length("$1") ], $lines );
5546
+    'name'                => { mandatory => 1, value => \&string  },
5547
+    'version'             => { mandatory => 1, value => \&version },
5548
+    'license'             => { mandatory => 1, value => \&license },
5549
+    'generated_by'        => { mandatory => 1, value => \&string  },
5550
+    'author'              => { mandatory => 1, list => { value => \&string } },
5551
+    'abstract'            => { mandatory => 1, value => \&string  },
5384 5552
   
5385
-  			} else {
5386
-  				die \"CPAN::Meta::YAML failed to classify line '$lines->[0]'";
5387
-  			}
5553
+    'distribution_type'   => { value => \&string  },
5554
+    'dynamic_config'      => { value => \&boolean },
5388 5555
   
5389
-  		} elsif ( defined $indent->[-2] and $indent->[-1] == $indent->[-2] ) {
5390
-  			# This is probably a structure like the following...
5391
-  			# ---
5392
-  			# foo:
5393
-  			# - list
5394
-  			# bar: value
5395
-  			#
5396
-  			# ... so lets return and let the hash parser handle it
5397
-  			return 1;
5556
+    'keywords'            => { list => { value => \&string } },
5398 5557
   
5399
-  		} else {
5400
-  			die \"CPAN::Meta::YAML failed to classify line '$lines->[0]'";
5401
-  		}
5402
-  	}
5558
+    'private'             => $no_index_1_2,
5559
+    '$no_index'           => $no_index_1_2,
5403 5560
   
5404
-  	return 1;
5405
-  }
5561
+    'requires'            => $module_map1,
5562
+    'recommends'          => $module_map1,
5563
+    'build_requires'      => $module_map1,
5564
+    'conflicts'           => $module_map2,
5406 5565
   
5407
-  # Parse an array
5408
-  sub _read_hash {
5409
-  	my ($self, $hash, $indent, $lines) = @_;
5566
+    'optional_features'   => {
5567
+      'map'       => {
5568
+          ':key'  => { name => \&string,
5569
+              'map'   => { description        => { value => \&string },
5570
+                           requires           => $module_map1,
5571
+                           recommends         => $module_map1,
5572
+                           build_requires     => $module_map1,
5573
+                           conflicts          => $module_map2,
5574
+                           ':key'  => { name => \&string, value => \&anything },
5575
+              }
5576
+          }
5577
+       }
5578
+    },
5410 5579
   
5411
-  	while ( @$lines ) {
5412
-  		# Check for a new document
5413
-  		if ( $lines->[0] =~ /^(?:---|\.\.\.)/ ) {
5414
-  			while ( @$lines and $lines->[0] !~ /^---/ ) {
5415
-  				shift @$lines;
5416
-  			}
5417
-  			return 1;
5418
-  		}
5580
+    'provides'    => {
5581
+      'map'       => {
5582
+        ':key' => { name  => \&module,
5583
+          'map' => {
5584
+            file    => { mandatory => 1, value => \&file },
5585
+            version => { value => \&version },
5586
+            ':key'  => { name => \&string, value => \&anything },
5587
+          }
5588
+        }
5589
+      }
5590
+    },
5419 5591
   
5420
-  		# Check the indent level
5421
-  		$lines->[0] =~ /^(\s*)/;
5422
-  		if ( length($1) < $indent->[-1] ) {
5423
-  			return 1;
5424
-  		} elsif ( length($1) > $indent->[-1] ) {
5425
-  			die \"CPAN::Meta::YAML found bad indenting in line '$lines->[0]'";
5426
-  		}
5592
+    'resources'   => {
5593
+      'map'       => { license    => { value => \&url },
5594
+                       homepage   => { value => \&url },
5595
+                       bugtracker => { value => \&url },
5596
+                       repository => { value => \&url },
5597
+                       ':key'     => { value => \&string, name => \&custom_1 },
5598
+      }
5599
+    },
5427 5600
   
5428
-  		# Get the key
5429
-  		unless ( $lines->[0] =~ s/^\s*([^\'\" ][^\n]*?)\s*:(\s+(?:\#.*)?|$)// ) {
5430
-  			if ( $lines->[0] =~ /^\s*[?\'\"]/ ) {
5431
-  				die \"CPAN::Meta::YAML does not support a feature in line '$lines->[0]'";
5432
-  			}
5433
-  			die \"CPAN::Meta::YAML failed to classify line '$lines->[0]'";
5434
-  		}
5435
-  		my $key = $1;
5601
+    # additional user defined key/value pairs
5602
+    # note we can only validate the key name, as the structure is user defined
5603
+    ':key'        => { name => \&string, value => \&anything },
5604
+  },
5436 5605
   
5437
-  		# Do we have a value?
5438
-  		if ( length $lines->[0] ) {
5439
-  			# Yes
5440
-  			$hash->{$key} = $self->_read_scalar( shift(@$lines), [ @$indent, undef ], $lines );
5441
-  		} else {
5442
-  			# An indent
5443
-  			shift @$lines;
5444
-  			unless ( @$lines ) {
5445
-  				$hash->{$key} = undef;
5446
-  				return 1;
5447
-  			}
5448
-  			if ( $lines->[0] =~ /^(\s*)-/ ) {
5449
-  				$hash->{$key} = [];
5450
-  				$self->_read_array( $hash->{$key}, [ @$indent, length($1) ], $lines );
5451
-  			} elsif ( $lines->[0] =~ /^(\s*)./ ) {
5452
-  				my $indent2 = length("$1");
5453
-  				if ( $indent->[-1] >= $indent2 ) {
5454
-  					# Null hash entry
5455
-  					$hash->{$key} = undef;
5456
-  				} else {
5457
-  					$hash->{$key} = {};
5458
-  					$self->_read_hash( $hash->{$key}, [ @$indent, length($1) ], $lines );
5459
-  				}
5460
-  			}
5461
-  		}
5462
-  	}
5606
+  # note that the 1.1 spec only specifies 'version' as mandatory
5607
+  '1.1' => {
5608
+    'name'                => { value => \&string  },
5609
+    'version'             => { mandatory => 1, value => \&version },
5610
+    'license'             => { value => \&license },
5611
+    'generated_by'        => { value => \&string  },
5463 5612
   
5464
-  	return 1;
5465
-  }
5613
+    'license_uri'         => { value => \&url },
5614
+    'distribution_type'   => { value => \&string  },
5615
+    'dynamic_config'      => { value => \&boolean },
5466 5616
   
5467
-  # Save an object to a file
5468
-  sub write {
5469
-  	my $self = shift;
5470
-  	my $file = shift or return $self->_error('No file name provided');
5617
+    'private'             => $no_index_1_1,
5471 5618
   
5472
-  	# Write it to the file
5473
-  	open( CFG, '>' . $file ) or return $self->_error(
5474
-  		"Failed to open file '$file' for writing: $!"
5475
-  		);
5476
-  	print CFG $self->write_string;
5477
-  	close CFG;
5619
+    'requires'            => $module_map1,
5620
+    'recommends'          => $module_map1,
5621
+    'build_requires'      => $module_map1,
5622
+    'conflicts'           => $module_map2,
5478 5623
   
5479
-  	return 1;
5480
-  }
5624
+    # additional user defined key/value pairs
5625
+    # note we can only validate the key name, as the structure is user defined
5626
+    ':key'        => { name => \&string, value => \&anything },
5627
+  },
5481 5628
   
5482
-  # Save an object to a string
5483
-  sub write_string {
5484
-  	my $self = shift;
5485
-  	return '' unless @$self;
5629
+  # note that the 1.0 spec doesn't specify optional or mandatory fields
5630
+  # but we will treat version as mandatory since otherwise META 1.0 is
5631
+  # completely arbitrary and pointless
5632
+  '1.0' => {
5633
+    'name'                => { value => \&string  },
5634
+    'version'             => { mandatory => 1, value => \&version },
5635
+    'license'             => { value => \&license },
5636
+    'generated_by'        => { value => \&string  },
5486 5637
   
5487
-  	# Iterate over the documents
5488
-  	my $indent = 0;
5489
-  	my @lines  = ();
5490
-  	foreach my $cursor ( @$self ) {
5491
-  		push @lines, '---';
5638
+    'license_uri'         => { value => \&url },
5639
+    'distribution_type'   => { value => \&string  },
5640
+    'dynamic_config'      => { value => \&boolean },
5492 5641
   
5493
-  		# An empty document
5494
-  		if ( ! defined $cursor ) {
5495
-  			# Do nothing
5642
+    'requires'            => $module_map1,
5643
+    'recommends'          => $module_map1,
5644
+    'build_requires'      => $module_map1,
5645
+    'conflicts'           => $module_map2,
5496 5646
   
5497
-  		# A scalar document
5498
-  		} elsif ( ! ref $cursor ) {
5499
-  			$lines[-1] .= ' ' . $self->_write_scalar( $cursor, $indent );
5647
+    # additional user defined key/value pairs
5648
+    # note we can only validate the key name, as the structure is user defined
5649
+    ':key'        => { name => \&string, value => \&anything },
5650
+  },
5651
+  );
5500 5652
   
5501
-  		# A list at the root
5502
-  		} elsif ( ref $cursor eq 'ARRAY' ) {
5503
-  			unless ( @$cursor ) {
5504
-  				$lines[-1] .= ' []';
5505
-  				next;
5506
-  			}
5507
-  			push @lines, $self->_write_array( $cursor, $indent, {} );
5653
+  #--------------------------------------------------------------------------#
5654
+  # Code
5655
+  #--------------------------------------------------------------------------#
5508 5656
   
5509
-  		# A hash at the root
5510
-  		} elsif ( ref $cursor eq 'HASH' ) {
5511
-  			unless ( %$cursor ) {
5512
-  				$lines[-1] .= ' {}';
5513
-  				next;
5514
-  			}
5515
-  			push @lines, $self->_write_hash( $cursor, $indent, {} );
5516 5657
   
5517
-  		} else {
5518
-  			Carp::croak("Cannot serialize " . ref($cursor));
5519
-  		}
5520
-  	}
5658
+  sub new {
5659
+    my ($class,$data) = @_;
5521 5660
   
5522
-  	join '', map { "$_\n" } @lines;
5661
+    # create an attributes hash
5662
+    my $self = {
5663
+      'data'    => $data,
5664
+      'spec'    => $data->{'meta-spec'}{'version'} || "1.0",
5665
+      'errors'  => undef,
5666
+    };
5667
+  
5668
+    # create the object
5669
+    return bless $self, $class;
5523 5670
   }
5524 5671
   
5525
-  sub _write_scalar {
5526
-  	my $string = $_[1];
5527
-  	return '~'  unless defined $string;
5528
-  	return "''" unless length  $string;
5529
-  	if ( $string =~ /[\x00-\x08\x0b-\x0d\x0e-\x1f\"\'\n]/ ) {
5530
-  		$string =~ s/\\/\\\\/g;
5531
-  		$string =~ s/"/\\"/g;
5532
-  		$string =~ s/\n/\\n/g;
5533
-  		$string =~ s/([\x00-\x1f])/\\$UNPRINTABLE[ord($1)]/g;
5534
-  		return qq|"$string"|;
5535
-  	}
5536
-  	if ( $string =~ /(?:^\W|\s)/ or $QUOTE{$string} ) {
5537
-  		return "'$string'";
5538
-  	}
5539
-  	return $string;
5672
+  
5673
+  sub is_valid {
5674
+      my $self = shift;
5675
+      my $data = $self->{data};
5676
+      my $spec_version = $self->{spec};
5677
+      $self->check_map($definitions{$spec_version},$data);
5678
+      return ! $self->errors;
5540 5679
   }
5541 5680
   
5542
-  sub _write_array {
5543
-  	my ($self, $array, $indent, $seen) = @_;
5544
-  	if ( $seen->{refaddr($array)}++ ) {
5545
-  		die "CPAN::Meta::YAML does not support circular references";
5546
-  	}
5547
-  	my @lines  = ();
5548
-  	foreach my $el ( @$array ) {
5549
-  		my $line = ('  ' x $indent) . '-';
5550
-  		my $type = ref $el;
5551
-  		if ( ! $type ) {
5552
-  			$line .= ' ' . $self->_write_scalar( $el, $indent + 1 );
5553
-  			push @lines, $line;
5554 5681
   
5555
-  		} elsif ( $type eq 'ARRAY' ) {
5556
-  			if ( @$el ) {
5557
-  				push @lines, $line;
5558
-  				push @lines, $self->_write_array( $el, $indent + 1, $seen );
5559
-  			} else {
5560
-  				$line .= ' []';
5561
-  				push @lines, $line;
5562
-  			}
5682
+  sub errors {
5683
+      my $self = shift;
5684
+      return ()   unless(defined $self->{errors});
5685
+      return @{$self->{errors}};
5686
+  }
5563 5687
   
5564
-  		} elsif ( $type eq 'HASH' ) {
5565
-  			if ( keys %$el ) {
5566
-  				push @lines, $line;
5567
-  				push @lines, $self->_write_hash( $el, $indent + 1, $seen );
5568
-  			} else {
5569
-  				$line .= ' {}';
5570
-  				push @lines, $line;
5571
-  			}
5572 5688
   
5573
-  		} else {
5574
-  			die "CPAN::Meta::YAML does not support $type references";
5575
-  		}
5576
-  	}
5689
+  my $spec_error = "Missing validation action in specification. "
5690
+    . "Must be one of 'map', 'list', 'lazylist', or 'value'";
5577 5691
   
5578
-  	@lines;
5579
-  }
5692
+  sub check_map {
5693
+      my ($self,$spec,$data) = @_;
5580 5694
   
5581
-  sub _write_hash {
5582
-  	my ($self, $hash, $indent, $seen) = @_;
5583
-  	if ( $seen->{refaddr($hash)}++ ) {
5584
-  		die "CPAN::Meta::YAML does not support circular references";
5585
-  	}
5586
-  	my @lines  = ();
5587
-  	foreach my $name ( sort keys %$hash ) {
5588
-  		my $el   = $hash->{$name};
5589
-  		my $line = ('  ' x $indent) . "$name:";
5590
-  		my $type = ref $el;
5591
-  		if ( ! $type ) {
5592
-  			$line .= ' ' . $self->_write_scalar( $el, $indent + 1 );
5593
-  			push @lines, $line;
5695
+      if(ref($spec) ne 'HASH') {
5696
+          $self->_error( "Unknown META specification, cannot validate." );
5697
+          return;
5698
+      }
5594 5699
   
5595
-  		} elsif ( $type eq 'ARRAY' ) {
5596
-  			if ( @$el ) {
5597
-  				push @lines, $line;
5598
-  				push @lines, $self->_write_array( $el, $indent + 1, $seen );
5599
-  			} else {
5600
-  				$line .= ' []';
5601
-  				push @lines, $line;
5602
-  			}
5700
+      if(ref($data) ne 'HASH') {
5701
+          $self->_error( "Expected a map structure from string or file." );
5702
+          return;
5703
+      }
5603 5704
   
5604
-  		} elsif ( $type eq 'HASH' ) {
5605
-  			if ( keys %$el ) {
5606
-  				push @lines, $line;
5607
-  				push @lines, $self->_write_hash( $el, $indent + 1, $seen );
5608
-  			} else {
5609
-  				$line .= ' {}';
5610
-  				push @lines, $line;
5611
-  			}
5705
+      for my $key (keys %$spec) {
5706
+          next    unless($spec->{$key}->{mandatory});
5707
+          next    if(defined $data->{$key});
5708
+          push @{$self->{stack}}, $key;
5709
+          $self->_error( "Missing mandatory field, '$key'" );
5710
+          pop @{$self->{stack}};
5711
+      }
5612 5712
   
5613
-  		} else {
5614
-  			die "CPAN::Meta::YAML does not support $type references";
5615
-  		}
5616
-  	}
5713
+      for my $key (keys %$data) {
5714
+          push @{$self->{stack}}, $key;
5715
+          if($spec->{$key}) {
5716
+              if($spec->{$key}{value}) {
5717
+                  $spec->{$key}{value}->($self,$key,$data->{$key});
5718
+              } elsif($spec->{$key}{'map'}) {
5719
+                  $self->check_map($spec->{$key}{'map'},$data->{$key});
5720
+              } elsif($spec->{$key}{'list'}) {
5721
+                  $self->check_list($spec->{$key}{'list'},$data->{$key});
5722
+              } elsif($spec->{$key}{'lazylist'}) {
5723
+                  $self->check_lazylist($spec->{$key}{'lazylist'},$data->{$key});
5724
+              } else {
5725
+                  $self->_error( "$spec_error for '$key'" );
5726
+              }
5617 5727
   
5618
-  	@lines;
5619
-  }
5728
+          } elsif ($spec->{':key'}) {
5729
+              $spec->{':key'}{name}->($self,$key,$key);
5730
+              if($spec->{':key'}{value}) {
5731
+                  $spec->{':key'}{value}->($self,$key,$data->{$key});
5732
+              } elsif($spec->{':key'}{'map'}) {
5733
+                  $self->check_map($spec->{':key'}{'map'},$data->{$key});
5734
+              } elsif($spec->{':key'}{'list'}) {
5735
+                  $self->check_list($spec->{':key'}{'list'},$data->{$key});
5736
+              } elsif($spec->{':key'}{'lazylist'}) {
5737
+                  $self->check_lazylist($spec->{':key'}{'lazylist'},$data->{$key});
5738
+              } else {
5739
+                  $self->_error( "$spec_error for ':key'" );
5740
+              }
5620 5741
   
5621
-  # Set error
5622
-  sub _error {
5623
-  	$CPAN::Meta::YAML::errstr = $_[1];
5624
-  	undef;
5625
-  }
5626 5742
   
5627
-  # Retrieve error
5628
-  sub errstr {
5629
-  	$CPAN::Meta::YAML::errstr;
5743
+          } else {
5744
+              $self->_error( "Unknown key, '$key', found in map structure" );
5745
+          }
5746
+          pop @{$self->{stack}};
5747
+      }
5630 5748
   }
5631 5749
   
5750
+  # if it's a string, make it into a list and check the list
5751
+  sub check_lazylist {
5752
+      my ($self,$spec,$data) = @_;
5632 5753
   
5754
+      if ( defined $data && ! ref($data) ) {
5755
+        $data = [ $data ];
5756
+      }
5633 5757
   
5758
+      $self->check_list($spec,$data);
5759
+  }
5634 5760
   
5761
+  sub check_list {
5762
+      my ($self,$spec,$data) = @_;
5635 5763
   
5636
-  #####################################################################
5637
-  # YAML Compatibility
5764
+      if(ref($data) ne 'ARRAY') {
5765
+          $self->_error( "Expected a list structure" );
5766
+          return;
5767
+      }
5638 5768
   
5639
-  sub Dump {
5640
-  	CPAN::Meta::YAML->new(@_)->write_string;
5641
-  }
5769
+      if(defined $spec->{mandatory}) {
5770
+          if(!defined $data->[0]) {
5771
+              $self->_error( "Missing entries from mandatory list" );
5772
+          }
5773
+      }
5642 5774
   
5643
-  sub Load {
5644
-  	my $self = CPAN::Meta::YAML->read_string(@_);
5645
-  	unless ( $self ) {
5646
-  		Carp::croak("Failed to load YAML document from string");
5647
-  	}
5648
-  	if ( wantarray ) {
5649
-  		return @$self;
5650
-  	} else {
5651
-  		# To match YAML.pm, return the last document
5652
-  		return $self->[-1];
5653
-  	}
5775
+      for my $value (@$data) {
5776
+          push @{$self->{stack}}, $value || "<undef>";
5777
+          if(defined $spec->{value}) {
5778
+              $spec->{value}->($self,'list',$value);
5779
+          } elsif(defined $spec->{'map'}) {
5780
+              $self->check_map($spec->{'map'},$value);
5781
+          } elsif(defined $spec->{'list'}) {
5782
+              $self->check_list($spec->{'list'},$value);
5783
+          } elsif(defined $spec->{'lazylist'}) {
5784
+              $self->check_lazylist($spec->{'lazylist'},$value);
5785
+          } elsif ($spec->{':key'}) {
5786
+              $self->check_map($spec,$value);
5787
+          } else {
5788
+            $self->_error( "$spec_error associated with '$self->{stack}[-2]'" );
5789
+          }
5790
+          pop @{$self->{stack}};
5791
+      }
5654 5792
   }
5655 5793
   
5656
-  BEGIN {
5657
-  	*freeze = *Dump;
5658
-  	*thaw   = *Load;
5659
-  }
5660 5794
   
5661
-  sub DumpFile {
5662
-  	my $file = shift;
5663
-  	CPAN::Meta::YAML->new(@_)->write($file);
5795
+  sub header {
5796
+      my ($self,$key,$value) = @_;
5797
+      if(defined $value) {
5798
+          return 1    if($value && $value =~ /^--- #YAML:1.0/);
5799
+      }
5800
+      $self->_error( "file does not have a valid YAML header." );
5801
+      return 0;
5664 5802
   }
5665 5803
   
5666
-  sub LoadFile {
5667
-  	my $self = CPAN::Meta::YAML->read($_[0]);
5668
-  	unless ( $self ) {
5669
-  		Carp::croak("Failed to load YAML document from '" . ($_[0] || '') . "'");
5670
-  	}
5671
-  	if ( wantarray ) {
5672
-  		return @$self;
5673
-  	} else {
5674
-  		# Return only the last document to match YAML.pm, 
5675
-  		return $self->[-1];
5676
-  	}
5804
+  sub release_status {
5805
+    my ($self,$key,$value) = @_;
5806
+    if(defined $value) {
5807
+      my $version = $self->{data}{version} || '';
5808
+      if ( $version =~ /_/ ) {
5809
+        return 1 if ( $value =~ /\A(?:testing|unstable)\z/ );
5810
+        $self->_error( "'$value' for '$key' is invalid for version '$version'" );
5811
+      }
5812
+      else {
5813
+        return 1 if ( $value =~ /\A(?:stable|testing|unstable)\z/ );
5814
+        $self->_error( "'$value' for '$key' is invalid" );
5815
+      }
5816
+    }
5817
+    else {
5818
+      $self->_error( "'$key' is not defined" );
5819
+    }
5820
+    return 0;
5677 5821
   }
5678 5822
   
5823
+  # _uri_split taken from URI::Split by Gisle Aas, Copyright 2003
5824
+  sub _uri_split {
5825
+       return $_[0] =~ m,(?:([^:/?#]+):)?(?://([^/?#]*))?([^?#]*)(?:\?([^#]*))?(?:#(.*))?,;
5826
+  }
5679 5827
   
5680
-  
5681
-  
5682
-  
5683
-  #####################################################################
5684
-  # Use Scalar::Util if possible, otherwise emulate it
5685
-  
5686
-  BEGIN {
5687
-  	eval {
5688
-  		require Scalar::Util;
5689
-  		*refaddr = *Scalar::Util::refaddr;
5690
-  	};
5691
-  	eval <<'END_PERL' if $@;
5692
-  # Failed to load Scalar::Util	
5693
-  sub refaddr {
5694
-  	my $pkg = ref($_[0]) or return undef;
5695
-  	if ( !! UNIVERSAL::can($_[0], 'can') ) {
5696
-  		bless $_[0], 'Scalar::Util::Fake';
5697
-  	} else {
5698
-  		$pkg = undef;
5699
-  	}
5700
-  	"$_[0]" =~ /0x(\w+)/;
5701
-  	my $i = do { local $^W; hex $1 };
5702
-  	bless $_[0], $pkg if defined $pkg;
5703
-  	$i;
5828
+  sub url {
5829
+      my ($self,$key,$value) = @_;
5830
+      if(defined $value) {
5831
+        my ($scheme, $auth, $path, $query, $frag) = _uri_split($value);
5832
+        unless ( defined $scheme && length $scheme ) {
5833
+          $self->_error( "'$value' for '$key' does not have a URL scheme" );
5834
+          return 0;
5835
+        }
5836
+        unless ( defined $auth && length $auth ) {
5837
+          $self->_error( "'$value' for '$key' does not have a URL authority" );
5838
+          return 0;
5839
+        }
5840
+        return 1;
5841
+      }
5842
+      $value ||= '';
5843
+      $self->_error( "'$value' for '$key' is not a valid URL." );
5844
+      return 0;
5704 5845
   }
5705
-  END_PERL
5706 5846
   
5847
+  sub urlspec {
5848
+      my ($self,$key,$value) = @_;
5849
+      if(defined $value) {
5850
+          return 1    if($value && $known_specs{$self->{spec}} eq $value);
5851
+          if($value && $known_urls{$value}) {
5852
+              $self->_error( 'META specification URL does not match version' );
5853
+              return 0;
5854
+          }
5855
+      }
5856
+      $self->_error( 'Unknown META specification' );
5857
+      return 0;
5707 5858
   }
5708 5859
   
5709
-  1;
5710
-  
5711
-  
5712
-  
5713
-  
5714
-  __END__
5715
-  
5716
-  
5717
-  # ABSTRACT: Read and write a subset of YAML for CPAN Meta files
5718
-  
5860
+  sub anything { return 1 }
5719 5861
   
5720
-CPAN_META_YAML
5721
-
5722
-$fatpacked{"HTTP/Tiny.pm"} = <<'HTTP_TINY';
5723
-  # vim: ts=4 sts=4 sw=4 et:
5724
-  #
5725
-  # This file is part of HTTP-Tiny
5726
-  #
5727
-  # This software is copyright (c) 2011 by Christian Hansen.
5728
-  #
5729
-  # This is free software; you can redistribute it and/or modify it under
5730
-  # the same terms as the Perl 5 programming language system itself.
5731
-  #
5732
-  package HTTP::Tiny;
5733
-  BEGIN {
5734
-    $HTTP::Tiny::VERSION = '0.009';
5862
+  sub string {
5863
+      my ($self,$key,$value) = @_;
5864
+      if(defined $value) {
5865
+          return 1    if($value || $value =~ /^0$/);
5866
+      }
5867
+      $self->_error( "value is an undefined string" );
5868
+      return 0;
5735 5869
   }
5736
-  use strict;
5737
-  use warnings;
5738
-  # ABSTRACT: A small, simple, correct HTTP/1.1 client
5739
-  
5740
-  use Carp ();
5741 5870
   
5871
+  sub string_or_undef {
5872
+      my ($self,$key,$value) = @_;
5873
+      return 1    unless(defined $value);
5874
+      return 1    if($value || $value =~ /^0$/);
5875
+      $self->_error( "No string defined for '$key'" );
5876
+      return 0;
5877
+  }
5742 5878
   
5743
-  my @attributes;
5744
-  BEGIN {
5745
-      @attributes = qw(agent default_headers max_redirect max_size proxy timeout);
5746
-      no strict 'refs';
5747
-      for my $accessor ( @attributes ) {
5748
-          *{$accessor} = sub {
5749
-              @_ > 1 ? $_[0]->{$accessor} = $_[1] : $_[0]->{$accessor};
5750
-          };
5751
-      }
5879
+  sub file {
5880
+      my ($self,$key,$value) = @_;
5881
+      return 1    if(defined $value);
5882
+      $self->_error( "No file defined for '$key'" );
5883
+      return 0;
5752 5884
   }
5753 5885
   
5754
-  sub new {
5755
-      my($class, %args) = @_;
5756
-      (my $agent = $class) =~ s{::}{-}g;
5757
-      my $self = {
5758
-          agent        => $agent . "/" . ($class->VERSION || 0),
5759
-          max_redirect => 5,
5760
-          timeout      => 60,
5761
-      };
5762
-      for my $key ( @attributes ) {
5763
-          $self->{$key} = $args{$key} if exists $args{$key}
5886
+  sub exversion {
5887
+      my ($self,$key,$value) = @_;
5888
+      if(defined $value && ($value || $value =~ /0/)) {
5889
+          my $pass = 1;
5890
+          for(split(",",$value)) { $self->version($key,$_) or ($pass = 0); }
5891
+          return $pass;
5764 5892
       }
5765
-      return bless $self, $class;
5893
+      $value = '<undef>'  unless(defined $value);
5894
+      $self->_error( "'$value' for '$key' is not a valid version." );
5895
+      return 0;
5766 5896
   }
5767 5897
   
5768
-  
5769
-  sub get {
5770
-      my ($self, $url, $args) = @_;
5771
-      @_ == 2 || (@_ == 3 && ref $args eq 'HASH')
5772
-        or Carp::croak(q/Usage: $http->get(URL, [HASHREF])/);
5773
-      return $self->request('GET', $url, $args || {});
5898
+  sub version {
5899
+      my ($self,$key,$value) = @_;
5900
+      if(defined $value) {
5901
+          return 0    unless($value || $value =~ /0/);
5902
+          return 1    if($value =~ /^\s*((<|<=|>=|>|!=|==)\s*)?v?\d+((\.\d+((_|\.)\d+)?)?)/);
5903
+      } else {
5904
+          $value = '<undef>';
5905
+      }
5906
+      $self->_error( "'$value' for '$key' is not a valid version." );
5907
+      return 0;
5774 5908
   }
5775 5909
   
5776
-  
5777
-  sub mirror {
5778
-      my ($self, $url, $file, $args) = @_;
5779
-      @_ == 3 || (@_ == 4 && ref $args eq 'HASH')
5780
-        or Carp::croak(q/Usage: $http->mirror(URL, FILE, [HASHREF])/);
5781
-      if ( -e $file and my $mtime = (stat($file))[9] ) {
5782
-          $args->{headers}{'if-modified-since'} ||= $self->_http_date($mtime);
5783
-      }
5784
-      my $tempfile = $file . int(rand(2**31));
5785
-      open my $fh, ">", $tempfile
5786
-          or Carp::croak(qq/Error: Could not open temporary file $tempfile for downloading: $!/);
5787
-      $args->{data_callback} = sub { print {$fh} $_[0] };
5788
-      my $response = $self->request('GET', $url, $args);
5789
-      close $fh
5790
-          or Carp::croak(qq/Error: Could not close temporary file $tempfile: $!/);
5791
-      if ( $response->{success} ) {
5792
-          rename $tempfile, $file
5793
-              or Carp::croak "Error replacing $file with $tempfile: $!\n";
5794
-          my $lm = $response->{headers}{'last-modified'};
5795
-          if ( $lm and my $mtime = $self->_parse_http_date($lm) ) {
5796
-              utime $mtime, $mtime, $file;
5797
-          }
5910
+  sub boolean {
5911
+      my ($self,$key,$value) = @_;
5912
+      if(defined $value) {
5913
+          return 1    if($value =~ /^(0|1|true|false)$/);
5914
+      } else {
5915
+          $value = '<undef>';
5798 5916
       }
5799
-      $response->{success} ||= $response->{status} eq '304';
5800
-      unlink $tempfile;
5801
-      return $response;
5917
+      $self->_error( "'$value' for '$key' is not a boolean value." );
5918
+      return 0;
5802 5919
   }
5803 5920
   
5921
+  my %v1_licenses = (
5922
+      'perl'         => 'http://dev.perl.org/licenses/',
5923
+      'gpl'          => 'http://www.opensource.org/licenses/gpl-license.php',
5924
+      'apache'       => 'http://apache.org/licenses/LICENSE-2.0',
5925
+      'artistic'     => 'http://opensource.org/licenses/artistic-license.php',
5926
+      'artistic_2'   => 'http://opensource.org/licenses/artistic-license-2.0.php',
5927
+      'lgpl'         => 'http://www.opensource.org/licenses/lgpl-license.php',
5928
+      'bsd'          => 'http://www.opensource.org/licenses/bsd-license.php',
5929
+      'gpl'          => 'http://www.opensource.org/licenses/gpl-license.php',
5930
+      'mit'          => 'http://opensource.org/licenses/mit-license.php',
5931
+      'mozilla'      => 'http://opensource.org/licenses/mozilla1.1.php',
5932
+      'open_source'  => undef,
5933
+      'unrestricted' => undef,
5934
+      'restrictive'  => undef,
5935
+      'unknown'      => undef,
5936
+  );
5804 5937
   
5805
-  my %idempotent = map { $_ => 1 } qw/GET HEAD PUT DELETE OPTIONS TRACE/;
5938
+  my %v2_licenses = map { $_ => 1 } qw(
5939
+    agpl_3
5940
+    apache_1_1
5941
+    apache_2_0
5942
+    artistic_1
5943
+    artistic_2
5944
+    bsd
5945
+    freebsd
5946
+    gfdl_1_2
5947
+    gfdl_1_3
5948
+    gpl_1
5949
+    gpl_2
5950
+    gpl_3
5951
+    lgpl_2_1
5952
+    lgpl_3_0
5953
+    mit
5954
+    mozilla_1_0
5955
+    mozilla_1_1
5956
+    openssl
5957
+    perl_5
5958
+    qpl_1_0
5959
+    ssleay
5960
+    sun
5961
+    zlib
5962
+    open_source
5963
+    restricted
5964
+    unrestricted
5965
+    unknown
5966
+  );
5806 5967
   
5807
-  sub request {
5808
-      my ($self, $method, $url, $args) = @_;
5809
-      @_ == 3 || (@_ == 4 && ref $args eq 'HASH')
5810
-        or Carp::croak(q/Usage: $http->request(METHOD, URL, [HASHREF])/);
5811
-      $args ||= {}; # we keep some state in this during _request
5968
+  sub license {
5969
+      my ($self,$key,$value) = @_;
5970
+      my $licenses = $self->{spec} < 2 ? \%v1_licenses : \%v2_licenses;
5971
+      if(defined $value) {
5972
+          return 1    if($value && exists $licenses->{$value});
5973
+      } else {
5974
+          $value = '<undef>';
5975
+      }
5976
+      $self->_error( "License '$value' is invalid" );
5977
+      return 0;
5978
+  }
5812 5979
   
5813
-      # RFC 2616 Section 8.1.4 mandates a single retry on broken socket
5814
-      my $response;
5815
-      for ( 0 .. 1 ) {
5816
-          $response = eval { $self->_request($method, $url, $args) };
5817
-          last unless $@ && $idempotent{$method}
5818
-              && $@ =~ m{^(?:Socket closed|Unexpected end)};
5980
+  sub custom_1 {
5981
+      my ($self,$key) = @_;
5982
+      if(defined $key) {
5983
+          # a valid user defined key should be alphabetic
5984
+          # and contain at least one capital case letter.
5985
+          return 1    if($key && $key =~ /^[_a-z]+$/i && $key =~ /[A-Z]/);
5986
+      } else {
5987
+          $key = '<undef>';
5819 5988
       }
5989
+      $self->_error( "Custom resource '$key' must be in CamelCase." );
5990
+      return 0;
5991
+  }
5820 5992
   
5821
-      if (my $e = "$@") {
5822
-          $response = {
5823
-              success => q{},
5824
-              status  => 599,
5825
-              reason  => 'Internal Exception',
5826
-              content => $e,
5827
-              headers => {
5828
-                  'content-type'   => 'text/plain',
5829
-                  'content-length' => length $e,
5830
-              }
5831
-          };
5993
+  sub custom_2 {
5994
+      my ($self,$key) = @_;
5995
+      if(defined $key) {
5996
+          return 1    if($key && $key =~ /^x_/i);  # user defined
5997
+      } else {
5998
+          $key = '<undef>';
5832 5999
       }
5833
-      return $response;
6000
+      $self->_error( "Custom key '$key' must begin with 'x_' or 'X_'." );
6001
+      return 0;
5834 6002
   }
5835 6003
   
5836
-  my %DefaultPort = (
5837
-      http => 80,
5838
-      https => 443,
5839
-  );
5840
-  
5841
-  sub _request {
5842
-      my ($self, $method, $url, $args) = @_;
5843
-  
5844
-      my ($scheme, $host, $port, $path_query) = $self->_split_url($url);
5845
-  
5846
-      my $request = {
5847
-          method    => $method,
5848
-          scheme    => $scheme,
5849
-          host_port => ($port == $DefaultPort{$scheme} ? $host : "$host:$port"),
5850
-          uri       => $path_query,
5851
-          headers   => {},
5852
-      };
5853
-  
5854
-      my $handle  = HTTP::Tiny::Handle->new(timeout => $self->{timeout});
5855
-  
5856
-      if ($self->{proxy}) {
5857
-          $request->{uri} = "$scheme://$request->{host_port}$path_query";
5858
-          croak(qq/HTTPS via proxy is not supported/)
5859
-              if $request->{scheme} eq 'https';
5860
-          $handle->connect(($self->_split_url($self->{proxy}))[0..2]);
5861
-      }
5862
-      else {
5863
-          $handle->connect($scheme, $host, $port);
5864
-      }
5865
-  
5866
-      $self->_prepare_headers_and_cb($request, $args);
5867
-      $handle->write_request($request);
5868
-  
5869
-      my $response;
5870
-      do { $response = $handle->read_response_header }
5871
-          until (substr($response->{status},0,1) ne '1');
5872
-  
5873
-      if ( my @redir_args = $self->_maybe_redirect($request, $response, $args) ) {
5874
-          $handle->close;
5875
-          return $self->_request(@redir_args, $args);
6004
+  sub identifier {
6005
+      my ($self,$key) = @_;
6006
+      if(defined $key) {
6007
+          return 1    if($key && $key =~ /^([a-z][_a-z]+)$/i);    # spec 2.0 defined
6008
+      } else {
6009
+          $key = '<undef>';
5876 6010
       }
6011
+      $self->_error( "Key '$key' is not a legal identifier." );
6012
+      return 0;
6013
+  }
5877 6014
   
5878
-      if ($method eq 'HEAD' || $response->{status} =~ /^[23]04/) {
5879
-          # response has no message body
5880
-      }
5881
-      else {
5882
-          my $data_cb = $self->_prepare_data_cb($response, $args);
5883
-          $handle->read_body($data_cb, $response);
6015
+  sub module {
6016
+      my ($self,$key) = @_;
6017
+      if(defined $key) {
6018
+          return 1    if($key && $key =~ /^[A-Za-z0-9_]+(::[A-Za-z0-9_]+)*$/);
6019
+      } else {
6020
+          $key = '<undef>';
5884 6021
       }
5885
-  
5886
-      $handle->close;
5887
-      $response->{success} = substr($response->{status},0,1) eq '2';
5888
-      return $response;
6022
+      $self->_error( "Key '$key' is not a legal module name." );
6023
+      return 0;
5889 6024
   }
5890 6025
   
5891
-  sub _prepare_headers_and_cb {
5892
-      my ($self, $request, $args) = @_;
5893
-  
5894
-      for ($self->{default_headers}, $args->{headers}) {
5895
-          next unless defined;
5896
-          while (my ($k, $v) = each %$_) {
5897
-              $request->{headers}{lc $k} = $v;
5898
-          }
6026
+  my @valid_phases = qw/ configure build test runtime develop /;
6027
+  sub phase {
6028
+      my ($self,$key) = @_;
6029
+      if(defined $key) {
6030
+          return 1 if( length $key && grep { $key eq $_ } @valid_phases );
6031
+          return 1 if $key =~ /x_/i;
6032
+      } else {
6033
+          $key = '<undef>';
5899 6034
       }
5900
-      $request->{headers}{'host'}         = $request->{host_port};
5901
-      $request->{headers}{'connection'}   = "close";
5902
-      $request->{headers}{'user-agent'} ||= $self->{agent};
6035
+      $self->_error( "Key '$key' is not a legal phase." );
6036
+      return 0;
6037
+  }
5903 6038
   
5904
-      if (defined $args->{content}) {
5905
-          $request->{headers}{'content-type'} ||= "application/octet-stream";
5906
-          if (ref $args->{content} eq 'CODE') {
5907
-              $request->{headers}{'transfer-encoding'} = 'chunked'
5908
-                unless $request->{headers}{'content-length'}
5909
-                    || $request->{headers}{'transfer-encoding'};
5910
-              $request->{cb} = $args->{content};
5911
-          }
5912
-          else {
5913
-              my $content = $args->{content};
5914
-              if ( $] ge '5.008' ) {
5915
-                  utf8::downgrade($content, 1)
5916
-                      or Carp::croak(q/Wide character in request message body/);
5917
-              }
5918
-              $request->{headers}{'content-length'} = length $content
5919
-                unless $request->{headers}{'content-length'}
5920
-                    || $request->{headers}{'transfer-encoding'};
5921
-              $request->{cb} = sub { substr $content, 0, length $content, '' };
5922
-          }
5923
-          $request->{trailer_cb} = $args->{trailer_callback}
5924
-              if ref $args->{trailer_callback} eq 'CODE';
6039
+  my @valid_relations = qw/ requires recommends suggests conflicts /;
6040
+  sub relation {
6041
+      my ($self,$key) = @_;
6042
+      if(defined $key) {
6043
+          return 1 if( length $key && grep { $key eq $_ } @valid_relations );
6044
+          return 1 if $key =~ /x_/i;
6045
+      } else {
6046
+          $key = '<undef>';
5925 6047
       }
5926
-      return;
6048
+      $self->_error( "Key '$key' is not a legal prereq relationship." );
6049
+      return 0;
5927 6050
   }
5928 6051
   
5929
-  sub _prepare_data_cb {
5930
-      my ($self, $response, $args) = @_;
5931
-      my $data_cb = $args->{data_callback};
5932
-      $response->{content} = '';
6052
+  sub _error {
6053
+      my $self = shift;
6054
+      my $mess = shift;
5933 6055
   
5934
-      if (!$data_cb || $response->{status} !~ /^2/) {
5935
-          if (defined $self->{max_size}) {
5936
-              $data_cb = sub {
5937
-                  $_[1]->{content} .= $_[0];
5938
-                  die(qq/Size of response body exceeds the maximum allowed of $self->{max_size}\n/)
5939
-                    if length $_[1]->{content} > $self->{max_size};
5940
-              };
5941
-          }
5942
-          else {
5943
-              $data_cb = sub { $_[1]->{content} .= $_[0] };
5944
-          }
5945
-      }
5946
-      return $data_cb;
5947
-  }
6056
+      $mess .= ' ('.join(' -> ',@{$self->{stack}}).')'  if($self->{stack});
6057
+      $mess .= " [Validation: $self->{spec}]";
5948 6058
   
5949
-  sub _maybe_redirect {
5950
-      my ($self, $request, $response, $args) = @_;
5951
-      my $headers = $response->{headers};
5952
-      my ($status, $method) = ($response->{status}, $request->{method});
5953
-      if (($status eq '303' or ($status =~ /^30[127]/ && $method =~ /^GET|HEAD$/))
5954
-          and $headers->{location}
5955
-          and ++$args->{redirects} <= $self->{max_redirect}
5956
-      ) {
5957
-          my $location = ($headers->{location} =~ /^\//)
5958
-              ? "$request->{scheme}://$request->{host_port}$headers->{location}"
5959
-              : $headers->{location} ;
5960
-          return (($status eq '303' ? 'GET' : $method), $location);
5961
-      }
5962
-      return;
6059
+      push @{$self->{errors}}, $mess;
5963 6060
   }
5964 6061
   
5965
-  sub _split_url {
5966
-      my $url = pop;
6062
+  1;
5967 6063
   
5968
-      # URI regex adapted from the URI module
5969
-      my ($scheme, $authority, $path_query) = $url =~ m<\A([^:/?#]+)://([^/?#]*)([^#]*)>
5970
-        or Carp::croak(qq/Cannot parse URL: '$url'/);
6064
+  # ABSTRACT: validate CPAN distribution metadata structures
5971 6065
   
5972
-      $scheme     = lc $scheme;
5973
-      $path_query = "/$path_query" unless $path_query =~ m<\A/>;
5974 6066
   
5975
-      my $host = (length($authority)) ? lc $authority : 'localhost';
5976
-         $host =~ s/\A[^@]*@//;   # userinfo
5977
-      my $port = do {
5978
-         $host =~ s/:([0-9]*)\z// && length $1
5979
-           ? $1
5980
-           : ($scheme eq 'http' ? 80 : $scheme eq 'https' ? 443 : undef);
5981
-      };
5982 6067
   
5983
-      return ($scheme, $host, $port, $path_query);
5984
-  }
5985 6068
   
5986
-  # Date conversions adapted from HTTP::Date
5987
-  my $DoW = "Sun|Mon|Tue|Wed|Thu|Fri|Sat";
5988
-  my $MoY = "Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec";
5989
-  sub _http_date {
5990
-      my ($sec, $min, $hour, $mday, $mon, $year, $wday) = gmtime($_[1]);
5991
-      return sprintf("%s, %02d %s %04d %02d:%02d:%02d GMT",
5992
-          substr($DoW,$wday*4,3),
5993
-          $mday, substr($MoY,$mon*4,3), $year+1900,
5994
-          $hour, $min, $sec
5995
-      );
5996
-  }
6069
+  __END__
5997 6070
   
5998
-  sub _parse_http_date {
5999
-      my ($self, $str) = @_;
6000
-      require Time::Local;
6001
-      my @tl_parts;
6002
-      if ($str =~ /^[SMTWF][a-z]+, +(\d{1,2}) ($MoY) +(\d\d\d\d) +(\d\d):(\d\d):(\d\d) +GMT$/) {
6003
-          @tl_parts = ($6, $5, $4, $1, (index($MoY,$2)/4), $3);
6004
-      }
6005
-      elsif ($str =~ /^[SMTWF][a-z]+, +(\d\d)-($MoY)-(\d{2,4}) +(\d\d):(\d\d):(\d\d) +GMT$/ ) {
6006
-          @tl_parts = ($6, $5, $4, $1, (index($MoY,$2)/4), $3);
6007
-      }
6008
-      elsif ($str =~ /^[SMTWF][a-z]+ +($MoY) +(\d{1,2}) +(\d\d):(\d\d):(\d\d) +(?:[^0-9]+ +)?(\d\d\d\d)$/ ) {
6009
-          @tl_parts = ($5, $4, $3, $2, (index($MoY,$1)/4), $6);
6010
-      }
6011
-      return eval {
6012
-          my $t = @tl_parts ? Time::Local::timegm(@tl_parts) : -1;
6013
-          $t < 0 ? undef : $t;
6014
-      };
6015
-  }
6016 6071
   
6017
-  package
6018
-      HTTP::Tiny::Handle; # hide from PAUSE/indexers
6019
-  use strict;
6020
-  use warnings;
6021 6072
   
6022
-  use Carp       qw[croak];
6023
-  use Errno      qw[EINTR EPIPE];
6024
-  use IO::Socket qw[SOCK_STREAM];
6073
+CPAN_META_VALIDATOR
6074
+
6075
+$fatpacked{"CPAN/Meta/YAML.pm"} = <<'CPAN_META_YAML';
6076
+  package CPAN::Meta::YAML;
6077
+  {
6078
+    $CPAN::Meta::YAML::VERSION = '0.008';
6079
+  }
6025 6080
   
6026
-  sub BUFSIZE () { 32768 }
6081
+  use strict;
6027 6082
   
6028
-  my $Printable = sub {
6029
-      local $_ = shift;
6030
-      s/\r/\\r/g;
6031
-      s/\n/\\n/g;
6032
-      s/\t/\\t/g;
6033
-      s/([^\x20-\x7E])/sprintf('\\x%.2X', ord($1))/ge;
6034
-      $_;
6035
-  };
6083
+  # UTF Support?
6084
+  sub HAVE_UTF8 () { $] >= 5.007003 }
6085
+  BEGIN {
6086
+  	if ( HAVE_UTF8 ) {
6087
+  		# The string eval helps hide this from Test::MinimumVersion
6088
+  		eval "require utf8;";
6089
+  		die "Failed to load UTF-8 support" if $@;
6090
+  	}
6036 6091
   
6037
-  my $Token = qr/[\x21\x23-\x27\x2A\x2B\x2D\x2E\x30-\x39\x41-\x5A\x5E-\x7A\x7C\x7E]/;
6092
+  	# Class structure
6093
+  	require 5.004;
6094
+  	require Exporter;
6095
+  	require Carp;
6096
+  	@CPAN::Meta::YAML::ISA       = qw{ Exporter  };
6097
+  	@CPAN::Meta::YAML::EXPORT    = qw{ Load Dump };
6098
+  	@CPAN::Meta::YAML::EXPORT_OK = qw{ LoadFile DumpFile freeze thaw };
6038 6099
   
6039
-  sub new {
6040
-      my ($class, %args) = @_;
6041
-      return bless {
6042
-          rbuf             => '',
6043
-          timeout          => 60,
6044
-          max_line_size    => 16384,
6045
-          max_header_lines => 64,
6046
-          %args
6047
-      }, $class;
6100
+  	# Error storage
6101
+  	$CPAN::Meta::YAML::errstr    = '';
6048 6102
   }
6049 6103
   
6050
-  my $ssl_verify_args = {
6051
-      check_cn => "when_only",
6052
-      wildcards_in_alt => "anywhere",
6053
-      wildcards_in_cn => "anywhere"
6054
-  };
6055
-  
6056
-  sub connect {
6057
-      @_ == 4 || croak(q/Usage: $handle->connect(scheme, host, port)/);
6058
-      my ($self, $scheme, $host, $port) = @_;
6104
+  # The character class of all characters we need to escape
6105
+  # NOTE: Inlined, since it's only used once
6106
+  # my $RE_ESCAPE = '[\\x00-\\x08\\x0b-\\x0d\\x0e-\\x1f\"\n]';
6059 6107
   
6060
-      if ( $scheme eq 'https' ) {
6061
-          eval "require IO::Socket::SSL"
6062
-              unless exists $INC{'IO/Socket/SSL.pm'};
6063
-          croak(qq/IO::Socket::SSL must be installed for https support\n/)
6064
-              unless $INC{'IO/Socket/SSL.pm'};
6065
-      }
6066
-      elsif ( $scheme ne 'http' ) {
6067
-        croak(qq/Unsupported URL scheme '$scheme'/);
6068
-      }
6069
-  
6070
-      $self->{fh} = 'IO::Socket::INET'->new(
6071
-          PeerHost  => $host,
6072
-          PeerPort  => $port,
6073
-          Proto     => 'tcp',
6074
-          Type      => SOCK_STREAM,
6075
-          Timeout   => $self->{timeout}
6076
-      ) or croak(qq/Could not connect to '$host:$port': $@/);
6077
-  
6078
-      binmode($self->{fh})
6079
-        or croak(qq/Could not binmode() socket: '$!'/);
6080
-  
6081
-      if ( $scheme eq 'https') {
6082
-          IO::Socket::SSL->start_SSL($self->{fh});
6083
-          ref($self->{fh}) eq 'IO::Socket::SSL'
6084
-              or die(qq/SSL connection failed for $host\n/);
6085
-          $self->{fh}->verify_hostname( $host, $ssl_verify_args )
6086
-              or die(qq/SSL certificate not valid for $host\n/);
6087
-      }
6108
+  # Printed form of the unprintable characters in the lowest range
6109
+  # of ASCII characters, listed by ASCII ordinal position.
6110
+  my @UNPRINTABLE = qw(
6111
+  	z    x01  x02  x03  x04  x05  x06  a
6112
+  	x08  t    n    v    f    r    x0e  x0f
6113
+  	x10  x11  x12  x13  x14  x15  x16  x17
6114
+  	x18  x19  x1a  e    x1c  x1d  x1e  x1f
6115
+  );
6088 6116
   
6089
-      $self->{host} = $host;
6090
-      $self->{port} = $port;
6117
+  # Printable characters for escapes
6118
+  my %UNESCAPES = (
6119
+  	z => "\x00", a => "\x07", t    => "\x09",
6120
+  	n => "\x0a", v => "\x0b", f    => "\x0c",
6121
+  	r => "\x0d", e => "\x1b", '\\' => '\\',
6122
+  );
6091 6123
   
6092
-      return $self;
6093
-  }
6124
+  # Special magic boolean words
6125
+  my %QUOTE = map { $_ => 1 } qw{
6126
+  	null Null NULL
6127
+  	y Y yes Yes YES n N no No NO
6128
+  	true True TRUE false False FALSE
6129
+  	on On ON off Off OFF
6130
+  };
6094 6131
   
6095
-  sub close {
6096
-      @_ == 1 || croak(q/Usage: $handle->close()/);
6097
-      my ($self) = @_;
6098
-      CORE::close($self->{fh})
6099
-        or croak(qq/Could not close socket: '$!'/);
6100
-  }
6101 6132
   
6102
-  sub write {
6103
-      @_ == 2 || croak(q/Usage: $handle->write(buf)/);
6104
-      my ($self, $buf) = @_;
6105 6133
   
6106
-      if ( $] ge '5.008' ) {
6107
-          utf8::downgrade($buf, 1)
6108
-              or croak(q/Wide character in write()/);
6109
-      }
6110 6134
   
6111
-      my $len = length $buf;
6112
-      my $off = 0;
6113 6135
   
6114
-      local $SIG{PIPE} = 'IGNORE';
6136
+  #####################################################################
6137
+  # Implementation
6115 6138
   
6116
-      while () {
6117
-          $self->can_write
6118
-            or croak(q/Timed out while waiting for socket to become ready for writing/);
6119
-          my $r = syswrite($self->{fh}, $buf, $len, $off);
6120
-          if (defined $r) {
6121
-              $len -= $r;
6122
-              $off += $r;
6123
-              last unless $len > 0;
6124
-          }
6125
-          elsif ($! == EPIPE) {
6126
-              croak(qq/Socket closed by remote server: $!/);
6127
-          }
6128
-          elsif ($! != EINTR) {
6129
-              croak(qq/Could not write to socket: '$!'/);
6130
-          }
6131
-      }
6132
-      return $off;
6139
+  # Create an empty CPAN::Meta::YAML object
6140
+  sub new {
6141
+  	my $class = shift;
6142
+  	bless [ @_ ], $class;
6133 6143
   }
6134 6144
   
6145
+  # Create an object from a file
6135 6146
   sub read {
6136
-      @_ == 2 || @_ == 3 || croak(q/Usage: $handle->read(len [, allow_partial])/);
6137
-      my ($self, $len, $allow_partial) = @_;
6147
+  	my $class = ref $_[0] ? ref shift : shift;
6138 6148
   
6139
-      my $buf  = '';
6140
-      my $got = length $self->{rbuf};
6149
+  	# Check the file
6150
+  	my $file = shift or return $class->_error( 'You did not specify a file name' );
6151
+  	return $class->_error( "File '$file' does not exist" )              unless -e $file;
6152
+  	return $class->_error( "'$file' is a directory, not a file" )       unless -f _;
6153
+  	return $class->_error( "Insufficient permissions to read '$file'" ) unless -r _;
6141 6154
   
6142
-      if ($got) {
6143
-          my $take = ($got < $len) ? $got : $len;
6144
-          $buf  = substr($self->{rbuf}, 0, $take, '');
6145
-          $len -= $take;
6146
-      }
6155
+  	# Slurp in the file
6156
+  	local $/ = undef;
6157
+  	local *CFG;
6158
+  	unless ( open(CFG, $file) ) {
6159
+  		return $class->_error("Failed to open file '$file': $!");
6160
+  	}
6161
+  	my $contents = <CFG>;
6162
+  	unless ( close(CFG) ) {
6163
+  		return $class->_error("Failed to close file '$file': $!");
6164
+  	}
6147 6165
   
6148
-      while ($len > 0) {
6149
-          $self->can_read
6150
-            or croak(q/Timed out while waiting for socket to become ready for reading/);
6151
-          my $r = sysread($self->{fh}, $buf, $len, length $buf);
6152
-          if (defined $r) {
6153
-              last unless $r;
6154
-              $len -= $r;
6155
-          }
6156
-          elsif ($! != EINTR) {
6157
-              croak(qq/Could not read from socket: '$!'/);
6158
-          }
6159
-      }
6160
-      if ($len && !$allow_partial) {
6161
-          croak(q/Unexpected end of stream/);
6162
-      }
6163
-      return $buf;
6166
+  	$class->read_string( $contents );
6164 6167
   }
6165 6168
   
6166
-  sub readline {
6167
-      @_ == 1 || croak(q/Usage: $handle->readline()/);
6168
-      my ($self) = @_;
6169
+  # Create an object from a string
6170
+  sub read_string {
6171
+  	my $class  = ref $_[0] ? ref shift : shift;
6172
+  	my $self   = bless [], $class;
6173
+  	my $string = $_[0];
6174
+  	eval {
6175
+  		unless ( defined $string ) {
6176
+  			die \"Did not provide a string to load";
6177
+  		}
6169 6178
   
6170
-      while () {
6171
-          if ($self->{rbuf} =~ s/\A ([^\x0D\x0A]* \x0D?\x0A)//x) {
6172
-              return $1;
6173
-          }
6174
-          if (length $self->{rbuf} >= $self->{max_line_size}) {
6175
-              croak(qq/Line size exceeds the maximum allowed size of $self->{max_line_size}/);
6176
-          }
6177
-          $self->can_read
6178
-            or croak(q/Timed out while waiting for socket to become ready for reading/);
6179
-          my $r = sysread($self->{fh}, $self->{rbuf}, BUFSIZE, length $self->{rbuf});
6180
-          if (defined $r) {
6181
-              last unless $r;
6182
-          }
6183
-          elsif ($! != EINTR) {
6184
-              croak(qq/Could not read from socket: '$!'/);
6185
-          }
6186
-      }
6187
-      croak(q/Unexpected end of stream while looking for line/);
6188
-  }
6179
+  		# Byte order marks
6180
+  		# NOTE: Keeping this here to educate maintainers
6181
+  		# my %BOM = (
6182
+  		#     "\357\273\277" => 'UTF-8',
6183
+  		#     "\376\377"     => 'UTF-16BE',
6184
+  		#     "\377\376"     => 'UTF-16LE',
6185
+  		#     "\377\376\0\0" => 'UTF-32LE'
6186
+  		#     "\0\0\376\377" => 'UTF-32BE',
6187
+  		# );
6188
+  		if ( $string =~ /^(?:\376\377|\377\376|\377\376\0\0|\0\0\376\377)/ ) {
6189
+  			die \"Stream has a non UTF-8 BOM";
6190
+  		} else {
6191
+  			# Strip UTF-8 bom if found, we'll just ignore it
6192
+  			$string =~ s/^\357\273\277//;
6193
+  		}
6189 6194
   
6190
-  sub read_header_lines {
6191
-      @_ == 1 || @_ == 2 || croak(q/Usage: $handle->read_header_lines([headers])/);
6192
-      my ($self, $headers) = @_;
6193
-      $headers ||= {};
6194
-      my $lines   = 0;
6195
-      my $val;
6195
+  		# Try to decode as utf8
6196
+  		utf8::decode($string) if HAVE_UTF8;
6196 6197
   
6197
-      while () {
6198
-           my $line = $self->readline;
6198
+  		# Check for some special cases
6199
+  		return $self unless length $string;
6200
+  		unless ( $string =~ /[\012\015]+\z/ ) {
6201
+  			die \"Stream does not end with newline character";
6202
+  		}
6199 6203
   
6200
-           if (++$lines >= $self->{max_header_lines}) {
6201
-               croak(qq/Header lines exceeds maximum number allowed of $self->{max_header_lines}/);
6202
-           }
6203
-           elsif ($line =~ /\A ([^\x00-\x1F\x7F:]+) : [\x09\x20]* ([^\x0D\x0A]*)/x) {
6204
-               my ($field_name) = lc $1;
6205
-               if (exists $headers->{$field_name}) {
6206
-                   for ($headers->{$field_name}) {
6207
-                       $_ = [$_] unless ref $_ eq "ARRAY";
6208
-                       push @$_, $2;
6209
-                       $val = \$_->[-1];
6210
-                   }
6211
-               }
6212
-               else {
6213
-                   $val = \($headers->{$field_name} = $2);
6214
-               }
6215
-           }
6216
-           elsif ($line =~ /\A [\x09\x20]+ ([^\x0D\x0A]*)/x) {
6217
-               $val
6218
-                 or croak(q/Unexpected header continuation line/);
6219
-               next unless length $1;
6220
-               $$val .= ' ' if length $$val;
6221
-               $$val .= $1;
6222
-           }
6223
-           elsif ($line =~ /\A \x0D?\x0A \z/x) {
6224
-              last;
6225
-           }
6226
-           else {
6227
-              croak(q/Malformed header line: / . $Printable->($line));
6228
-           }
6229
-      }
6230
-      return $headers;
6231
-  }
6204
+  		# Split the file into lines
6205
+  		my @lines = grep { ! /^\s*(?:\#.*)?\z/ }
6206
+  			    split /(?:\015{1,2}\012|\015|\012)/, $string;
6232 6207
   
6233
-  sub write_request {
6234
-      @_ == 2 || croak(q/Usage: $handle->write_request(request)/);
6235
-      my($self, $request) = @_;
6236
-      $self->write_request_header(@{$request}{qw/method uri headers/});
6237
-      $self->write_body($request) if $request->{cb};
6238
-      return;
6239
-  }
6208
+  		# Strip the initial YAML header
6209
+  		@lines and $lines[0] =~ /^\%YAML[: ][\d\.]+.*\z/ and shift @lines;
6240 6210
   
6241
-  my %HeaderCase = (
6242
-      'content-md5'      => 'Content-MD5',
6243
-      'etag'             => 'ETag',
6244
-      'te'               => 'TE',
6245
-      'www-authenticate' => 'WWW-Authenticate',
6246
-      'x-xss-protection' => 'X-XSS-Protection',
6247
-  );
6211
+  		# A nibbling parser
6212
+  		while ( @lines ) {
6213
+  			# Do we have a document header?
6214
+  			if ( $lines[0] =~ /^---\s*(?:(.+)\s*)?\z/ ) {
6215
+  				# Handle scalar documents
6216
+  				shift @lines;
6217
+  				if ( defined $1 and $1 !~ /^(?:\#.+|\%YAML[: ][\d\.]+)\z/ ) {
6218
+  					push @$self, $self->_read_scalar( "$1", [ undef ], \@lines );
6219
+  					next;
6220
+  				}
6221
+  			}
6248 6222
   
6249
-  sub write_header_lines {
6250
-      (@_ == 2 && ref $_[1] eq 'HASH') || croak(q/Usage: $handle->write_header_lines(headers)/);
6251
-      my($self, $headers) = @_;
6223
+  			if ( ! @lines or $lines[0] =~ /^(?:---|\.\.\.)/ ) {
6224
+  				# A naked document
6225
+  				push @$self, undef;
6226
+  				while ( @lines and $lines[0] !~ /^---/ ) {
6227
+  					shift @lines;
6228
+  				}
6252 6229
   
6253
-      my $buf = '';
6254
-      while (my ($k, $v) = each %$headers) {
6255
-          my $field_name = lc $k;
6256
-          if (exists $HeaderCase{$field_name}) {
6257
-              $field_name = $HeaderCase{$field_name};
6258
-          }
6259
-          else {
6260
-              $field_name =~ /\A $Token+ \z/xo
6261
-                or croak(q/Invalid HTTP header field name: / . $Printable->($field_name));
6262
-              $field_name =~ s/\b(\w)/\u$1/g;
6263
-              $HeaderCase{lc $field_name} = $field_name;
6264
-          }
6265
-          for (ref $v eq 'ARRAY' ? @$v : $v) {
6266
-              /[^\x0D\x0A]/
6267
-                or croak(qq/Invalid HTTP header field value ($field_name): / . $Printable->($_));
6268
-              $buf .= "$field_name: $_\x0D\x0A";
6269
-          }
6270
-      }
6271
-      $buf .= "\x0D\x0A";
6272
-      return $self->write($buf);
6273
-  }
6230
+  			} elsif ( $lines[0] =~ /^\s*\-/ ) {
6231
+  				# An array at the root
6232
+  				my $document = [ ];
6233
+  				push @$self, $document;
6234
+  				$self->_read_array( $document, [ 0 ], \@lines );
6274 6235
   
6275
-  sub read_body {
6276
-      @_ == 3 || croak(q/Usage: $handle->read_body(callback, response)/);
6277
-      my ($self, $cb, $response) = @_;
6278
-      my $te = $response->{headers}{'transfer-encoding'} || '';
6279
-      if ( grep { /chunked/i } ( ref $te eq 'ARRAY' ? @$te : $te ) ) {
6280
-          $self->read_chunked_body($cb, $response);
6281
-      }
6282
-      else {
6283
-          $self->read_content_body($cb, $response);
6284
-      }
6285
-      return;
6286
-  }
6287
-  
6288
-  sub write_body {
6289
-      @_ == 2 || croak(q/Usage: $handle->write_body(request)/);
6290
-      my ($self, $request) = @_;
6291
-      if ($request->{headers}{'content-length'}) {
6292
-          return $self->write_content_body($request);
6293
-      }
6294
-      else {
6295
-          return $self->write_chunked_body($request);
6296
-      }
6297
-  }
6298
-  
6299
-  sub read_content_body {
6300
-      @_ == 3 || @_ == 4 || croak(q/Usage: $handle->read_content_body(callback, response, [read_length])/);
6301
-      my ($self, $cb, $response, $content_length) = @_;
6302
-      $content_length ||= $response->{headers}{'content-length'};
6236
+  			} elsif ( $lines[0] =~ /^(\s*)\S/ ) {
6237
+  				# A hash at the root
6238
+  				my $document = { };
6239
+  				push @$self, $document;
6240
+  				$self->_read_hash( $document, [ length($1) ], \@lines );
6303 6241
   
6304
-      if ( $content_length ) {
6305
-          my $len = $content_length;
6306
-          while ($len > 0) {
6307
-              my $read = ($len > BUFSIZE) ? BUFSIZE : $len;
6308
-              $cb->($self->read($read, 0), $response);
6309
-              $len -= $read;
6310
-          }
6311
-      }
6312
-      else {
6313
-          my $chunk;
6314
-          $cb->($chunk, $response) while length( $chunk = $self->read(BUFSIZE, 1) );
6315
-      }
6242
+  			} else {
6243
+  				die \"CPAN::Meta::YAML failed to classify the line '$lines[0]'";
6244
+  			}
6245
+  		}
6246
+  	};
6247
+  	if ( ref $@ eq 'SCALAR' ) {
6248
+  		return $self->_error(${$@});
6249
+  	} elsif ( $@ ) {
6250
+  		require Carp;
6251
+  		Carp::croak($@);
6252
+  	}
6316 6253
   
6317
-      return;
6254
+  	return $self;
6318 6255
   }
6319 6256
   
6320
-  sub write_content_body {
6321
-      @_ == 2 || croak(q/Usage: $handle->write_content_body(request)/);
6322
-      my ($self, $request) = @_;
6323
-  
6324
-      my ($len, $content_length) = (0, $request->{headers}{'content-length'});
6325
-      while () {
6326
-          my $data = $request->{cb}->();
6327
-  
6328
-          defined $data && length $data
6329
-            or last;
6257
+  # Deparse a scalar string to the actual scalar
6258
+  sub _read_scalar {
6259
+  	my ($self, $string, $indent, $lines) = @_;
6330 6260
   
6331
-          if ( $] ge '5.008' ) {
6332
-              utf8::downgrade($data, 1)
6333
-                  or croak(q/Wide character in write_content()/);
6334
-          }
6261
+  	# Trim trailing whitespace
6262
+  	$string =~ s/\s*\z//;
6335 6263
   
6336
-          $len += $self->write($data);
6337
-      }
6264
+  	# Explitic null/undef
6265
+  	return undef if $string eq '~';
6338 6266
   
6339
-      $len == $content_length
6340
-        or croak(qq/Content-Length missmatch (got: $len expected: $content_length)/);
6267
+  	# Single quote
6268
+  	if ( $string =~ /^\'(.*?)\'(?:\s+\#.*)?\z/ ) {
6269
+  		return '' unless defined $1;
6270
+  		$string = $1;
6271
+  		$string =~ s/\'\'/\'/g;
6272
+  		return $string;
6273
+  	}
6341 6274
   
6342
-      return $len;
6343
-  }
6275
+  	# Double quote.
6276
+  	# The commented out form is simpler, but overloaded the Perl regex
6277
+  	# engine due to recursion and backtracking problems on strings
6278
+  	# larger than 32,000ish characters. Keep it for reference purposes.
6279
+  	# if ( $string =~ /^\"((?:\\.|[^\"])*)\"\z/ ) {
6280
+  	if ( $string =~ /^\"([^\\"]*(?:\\.[^\\"]*)*)\"(?:\s+\#.*)?\z/ ) {
6281
+  		# Reusing the variable is a little ugly,
6282
+  		# but avoids a new variable and a string copy.
6283
+  		$string = $1;
6284
+  		$string =~ s/\\"/"/g;
6285
+  		$string =~ s/\\([never\\fartz]|x([0-9a-fA-F]{2}))/(length($1)>1)?pack("H2",$2):$UNESCAPES{$1}/gex;
6286
+  		return $string;
6287
+  	}
6344 6288
   
6345
-  sub read_chunked_body {
6346
-      @_ == 3 || croak(q/Usage: $handle->read_chunked_body(callback, $response)/);
6347
-      my ($self, $cb, $response) = @_;
6289
+  	# Special cases
6290
+  	if ( $string =~ /^[\'\"!&]/ ) {
6291
+  		die \"CPAN::Meta::YAML does not support a feature in line '$string'";
6292
+  	}
6293
+  	return {} if $string =~ /^{}(?:\s+\#.*)?\z/;
6294
+  	return [] if $string =~ /^\[\](?:\s+\#.*)?\z/;
6348 6295
   
6349
-      while () {
6350
-          my $head = $self->readline;
6296
+  	# Regular unquoted string
6297
+  	if ( $string !~ /^[>|]/ ) {
6298
+  		if (
6299
+  			$string =~ /^(?:-(?:\s|$)|[\@\%\`])/
6300
+  			or
6301
+  			$string =~ /:(?:\s|$)/
6302
+  		) {
6303
+  			die \"CPAN::Meta::YAML found illegal characters in plain scalar: '$string'";
6304
+  		}
6305
+  		$string =~ s/\s+#.*\z//;
6306
+  		return $string;
6307
+  	}
6351 6308
   
6352
-          $head =~ /\A ([A-Fa-f0-9]+)/x
6353
-            or croak(q/Malformed chunk head: / . $Printable->($head));
6309
+  	# Error
6310
+  	die \"CPAN::Meta::YAML failed to find multi-line scalar content" unless @$lines;
6354 6311
   
6355
-          my $len = hex($1)
6356
-            or last;
6312
+  	# Check the indent depth
6313
+  	$lines->[0]   =~ /^(\s*)/;
6314
+  	$indent->[-1] = length("$1");
6315
+  	if ( defined $indent->[-2] and $indent->[-1] <= $indent->[-2] ) {
6316
+  		die \"CPAN::Meta::YAML found bad indenting in line '$lines->[0]'";
6317
+  	}
6357 6318
   
6358
-          $self->read_content_body($cb, $response, $len);
6319
+  	# Pull the lines
6320
+  	my @multiline = ();
6321
+  	while ( @$lines ) {
6322
+  		$lines->[0] =~ /^(\s*)/;
6323
+  		last unless length($1) >= $indent->[-1];
6324
+  		push @multiline, substr(shift(@$lines), length($1));
6325
+  	}
6359 6326
   
6360
-          $self->read(2) eq "\x0D\x0A"
6361
-            or croak(q/Malformed chunk: missing CRLF after chunk data/);
6362
-      }
6363
-      $self->read_header_lines($response->{headers});
6364
-      return;
6327
+  	my $j = (substr($string, 0, 1) eq '>') ? ' ' : "\n";
6328
+  	my $t = (substr($string, 1, 1) eq '-') ? ''  : "\n";
6329
+  	return join( $j, @multiline ) . $t;
6365 6330
   }
6366 6331
   
6367
-  sub write_chunked_body {
6368
-      @_ == 2 || croak(q/Usage: $handle->write_chunked_body(request)/);
6369
-      my ($self, $request) = @_;
6370
-  
6371
-      my $len = 0;
6372
-      while () {
6373
-          my $data = $request->{cb}->();
6374
-  
6375
-          defined $data && length $data
6376
-            or last;
6332
+  # Parse an array
6333
+  sub _read_array {
6334
+  	my ($self, $array, $indent, $lines) = @_;
6377 6335
   
6378
-          if ( $] ge '5.008' ) {
6379
-              utf8::downgrade($data, 1)
6380
-                  or croak(q/Wide character in write_chunked_body()/);
6381
-          }
6336
+  	while ( @$lines ) {
6337
+  		# Check for a new document
6338
+  		if ( $lines->[0] =~ /^(?:---|\.\.\.)/ ) {
6339
+  			while ( @$lines and $lines->[0] !~ /^---/ ) {
6340
+  				shift @$lines;
6341
+  			}
6342
+  			return 1;
6343
+  		}
6382 6344
   
6383
-          $len += length $data;
6345
+  		# Check the indent level
6346
+  		$lines->[0] =~ /^(\s*)/;
6347
+  		if ( length($1) < $indent->[-1] ) {
6348
+  			return 1;
6349
+  		} elsif ( length($1) > $indent->[-1] ) {
6350
+  			die \"CPAN::Meta::YAML found bad indenting in line '$lines->[0]'";
6351
+  		}
6384 6352
   
6385
-          my $chunk  = sprintf '%X', length $data;
6386
-             $chunk .= "\x0D\x0A";
6387
-             $chunk .= $data;
6388
-             $chunk .= "\x0D\x0A";
6353
+  		if ( $lines->[0] =~ /^(\s*\-\s+)[^\'\"]\S*\s*:(?:\s+|$)/ ) {
6354
+  			# Inline nested hash
6355
+  			my $indent2 = length("$1");
6356
+  			$lines->[0] =~ s/-/ /;
6357
+  			push @$array, { };
6358
+  			$self->_read_hash( $array->[-1], [ @$indent, $indent2 ], $lines );
6389 6359
   
6390
-          $self->write($chunk);
6391
-      }
6392
-      $self->write("0\x0D\x0A");
6393
-      $self->write_header_lines($request->{trailer_cb}->())
6394
-          if ref $request->{trailer_cb} eq 'CODE';
6395
-      return $len;
6396
-  }
6360
+  		} elsif ( $lines->[0] =~ /^\s*\-(\s*)(.+?)\s*\z/ ) {
6361
+  			# Array entry with a value
6362
+  			shift @$lines;
6363
+  			push @$array, $self->_read_scalar( "$2", [ @$indent, undef ], $lines );
6397 6364
   
6398
-  sub read_response_header {
6399
-      @_ == 1 || croak(q/Usage: $handle->read_response_header()/);
6400
-      my ($self) = @_;
6365
+  		} elsif ( $lines->[0] =~ /^\s*\-\s*\z/ ) {
6366
+  			shift @$lines;
6367
+  			unless ( @$lines ) {
6368
+  				push @$array, undef;
6369
+  				return 1;
6370
+  			}
6371
+  			if ( $lines->[0] =~ /^(\s*)\-/ ) {
6372
+  				my $indent2 = length("$1");
6373
+  				if ( $indent->[-1] == $indent2 ) {
6374
+  					# Null array entry
6375
+  					push @$array, undef;
6376
+  				} else {
6377
+  					# Naked indenter
6378
+  					push @$array, [ ];
6379
+  					$self->_read_array( $array->[-1], [ @$indent, $indent2 ], $lines );
6380
+  				}
6401 6381
   
6402
-      my $line = $self->readline;
6382
+  			} elsif ( $lines->[0] =~ /^(\s*)\S/ ) {
6383
+  				push @$array, { };
6384
+  				$self->_read_hash( $array->[-1], [ @$indent, length("$1") ], $lines );
6403 6385
   
6404
-      $line =~ /\A (HTTP\/(0*\d+\.0*\d+)) [\x09\x20]+ ([0-9]{3}) [\x09\x20]+ ([^\x0D\x0A]*) \x0D?\x0A/x
6405
-        or croak(q/Malformed Status-Line: / . $Printable->($line));
6386
+  			} else {
6387
+  				die \"CPAN::Meta::YAML failed to classify line '$lines->[0]'";
6388
+  			}
6406 6389
   
6407
-      my ($protocol, $version, $status, $reason) = ($1, $2, $3, $4);
6390
+  		} elsif ( defined $indent->[-2] and $indent->[-1] == $indent->[-2] ) {
6391
+  			# This is probably a structure like the following...
6392
+  			# ---
6393
+  			# foo:
6394
+  			# - list
6395
+  			# bar: value
6396
+  			#
6397
+  			# ... so lets return and let the hash parser handle it
6398
+  			return 1;
6408 6399
   
6409
-      croak (qq/Unsupported HTTP protocol: $protocol/)
6410
-          unless $version =~ /0*1\.0*[01]/;
6400
+  		} else {
6401
+  			die \"CPAN::Meta::YAML failed to classify line '$lines->[0]'";
6402
+  		}
6403
+  	}
6411 6404
   
6412
-      return {
6413
-          status   => $status,
6414
-          reason   => $reason,
6415
-          headers  => $self->read_header_lines,
6416
-          protocol => $protocol,
6417
-      };
6405
+  	return 1;
6418 6406
   }
6419 6407
   
6420
-  sub write_request_header {
6421
-      @_ == 4 || croak(q/Usage: $handle->write_request_header(method, request_uri, headers)/);
6422
-      my ($self, $method, $request_uri, $headers) = @_;
6423
-  
6424
-      return $self->write("$method $request_uri HTTP/1.1\x0D\x0A")
6425
-           + $self->write_header_lines($headers);
6426
-  }
6408
+  # Parse an array
6409
+  sub _read_hash {
6410
+  	my ($self, $hash, $indent, $lines) = @_;
6427 6411
   
6428
-  sub _do_timeout {
6429
-      my ($self, $type, $timeout) = @_;
6430
-      $timeout = $self->{timeout}
6431
-          unless defined $timeout && $timeout >= 0;
6432
-  
6433
-      my $fd = fileno $self->{fh};
6434
-      defined $fd && $fd >= 0
6435
-        or croak(q/select(2): 'Bad file descriptor'/);
6412
+  	while ( @$lines ) {
6413
+  		# Check for a new document
6414
+  		if ( $lines->[0] =~ /^(?:---|\.\.\.)/ ) {
6415
+  			while ( @$lines and $lines->[0] !~ /^---/ ) {
6416
+  				shift @$lines;
6417
+  			}
6418
+  			return 1;
6419
+  		}
6436 6420
   
6437
-      my $initial = time;
6438
-      my $pending = $timeout;
6439
-      my $nfound;
6421
+  		# Check the indent level
6422
+  		$lines->[0] =~ /^(\s*)/;
6423
+  		if ( length($1) < $indent->[-1] ) {
6424
+  			return 1;
6425
+  		} elsif ( length($1) > $indent->[-1] ) {
6426
+  			die \"CPAN::Meta::YAML found bad indenting in line '$lines->[0]'";
6427
+  		}
6440 6428
   
6441
-      vec(my $fdset = '', $fd, 1) = 1;
6429
+  		# Get the key
6430
+  		unless ( $lines->[0] =~ s/^\s*([^\'\" ][^\n]*?)\s*:(\s+(?:\#.*)?|$)// ) {
6431
+  			if ( $lines->[0] =~ /^\s*[?\'\"]/ ) {
6432
+  				die \"CPAN::Meta::YAML does not support a feature in line '$lines->[0]'";
6433
+  			}
6434
+  			die \"CPAN::Meta::YAML failed to classify line '$lines->[0]'";
6435
+  		}
6436
+  		my $key = $1;
6442 6437
   
6443
-      while () {
6444
-          $nfound = ($type eq 'read')
6445
-              ? select($fdset, undef, undef, $pending)
6446
-              : select(undef, $fdset, undef, $pending) ;
6447
-          if ($nfound == -1) {
6448
-              $! == EINTR
6449
-                or croak(qq/select(2): '$!'/);
6450
-              redo if !$timeout || ($pending = $timeout - (time - $initial)) > 0;
6451
-              $nfound = 0;
6452
-          }
6453
-          last;
6454
-      }
6455
-      $! = 0;
6456
-      return $nfound;
6457
-  }
6438
+  		# Do we have a value?
6439
+  		if ( length $lines->[0] ) {
6440
+  			# Yes
6441
+  			$hash->{$key} = $self->_read_scalar( shift(@$lines), [ @$indent, undef ], $lines );
6442
+  		} else {
6443
+  			# An indent
6444
+  			shift @$lines;
6445
+  			unless ( @$lines ) {
6446
+  				$hash->{$key} = undef;
6447
+  				return 1;
6448
+  			}
6449
+  			if ( $lines->[0] =~ /^(\s*)-/ ) {
6450
+  				$hash->{$key} = [];
6451
+  				$self->_read_array( $hash->{$key}, [ @$indent, length($1) ], $lines );
6452
+  			} elsif ( $lines->[0] =~ /^(\s*)./ ) {
6453
+  				my $indent2 = length("$1");
6454
+  				if ( $indent->[-1] >= $indent2 ) {
6455
+  					# Null hash entry
6456
+  					$hash->{$key} = undef;
6457
+  				} else {
6458
+  					$hash->{$key} = {};
6459
+  					$self->_read_hash( $hash->{$key}, [ @$indent, length($1) ], $lines );
6460
+  				}
6461
+  			}
6462
+  		}
6463
+  	}
6458 6464
   
6459
-  sub can_read {
6460
-      @_ == 1 || @_ == 2 || croak(q/Usage: $handle->can_read([timeout])/);
6461
-      my $self = shift;
6462
-      return $self->_do_timeout('read', @_)
6465
+  	return 1;
6463 6466
   }
6464 6467
   
6465
-  sub can_write {
6466
-      @_ == 1 || @_ == 2 || croak(q/Usage: $handle->can_write([timeout])/);
6467
-      my $self = shift;
6468
-      return $self->_do_timeout('write', @_)
6469
-  }
6468
+  # Save an object to a file
6469
+  sub write {
6470
+  	my $self = shift;
6471
+  	my $file = shift or return $self->_error('No file name provided');
6470 6472
   
6471
-  1;
6473
+  	# Write it to the file
6474
+  	open( CFG, '>' . $file ) or return $self->_error(
6475
+  		"Failed to open file '$file' for writing: $!"
6476
+  		);
6477
+  	print CFG $self->write_string;
6478
+  	close CFG;
6472 6479
   
6480
+  	return 1;
6481
+  }
6473 6482
   
6483
+  # Save an object to a string
6484
+  sub write_string {
6485
+  	my $self = shift;
6486
+  	return '' unless @$self;
6474 6487
   
6475
-  __END__
6476
-  =pod
6488
+  	# Iterate over the documents
6489
+  	my $indent = 0;
6490
+  	my @lines  = ();
6491
+  	foreach my $cursor ( @$self ) {
6492
+  		push @lines, '---';
6477 6493
   
6478
-HTTP_TINY
6479
-
6480
-$fatpacked{"JSON/PP.pm"} = <<'JSON_PP';
6481
-  package JSON::PP;
6494
+  		# An empty document
6495
+  		if ( ! defined $cursor ) {
6496
+  			# Do nothing
6482 6497
   
6483
-  # JSON-2.0
6498
+  		# A scalar document
6499
+  		} elsif ( ! ref $cursor ) {
6500
+  			$lines[-1] .= ' ' . $self->_write_scalar( $cursor, $indent );
6484 6501
   
6485
-  use 5.005;
6486
-  use strict;
6487
-  use base qw(Exporter);
6488
-  use overload ();
6502
+  		# A list at the root
6503
+  		} elsif ( ref $cursor eq 'ARRAY' ) {
6504
+  			unless ( @$cursor ) {
6505
+  				$lines[-1] .= ' []';
6506
+  				next;
6507
+  			}
6508
+  			push @lines, $self->_write_array( $cursor, $indent, {} );
6489 6509
   
6490
-  use Carp ();
6491
-  use B ();
6492
-  #use Devel::Peek;
6510
+  		# A hash at the root
6511
+  		} elsif ( ref $cursor eq 'HASH' ) {
6512
+  			unless ( %$cursor ) {
6513
+  				$lines[-1] .= ' {}';
6514
+  				next;
6515
+  			}
6516
+  			push @lines, $self->_write_hash( $cursor, $indent, {} );
6493 6517
   
6494
-  $JSON::PP::VERSION = '2.27200';
6518
+  		} else {
6519
+  			Carp::croak("Cannot serialize " . ref($cursor));
6520
+  		}
6521
+  	}
6495 6522
   
6496
-  @JSON::PP::EXPORT = qw(encode_json decode_json from_json to_json);
6523
+  	join '', map { "$_\n" } @lines;
6524
+  }
6497 6525
   
6498
-  # instead of hash-access, i tried index-access for speed.
6499
-  # but this method is not faster than what i expected. so it will be changed.
6526
+  sub _write_scalar {
6527
+  	my $string = $_[1];
6528
+  	return '~'  unless defined $string;
6529
+  	return "''" unless length  $string;
6530
+  	if ( $string =~ /[\x00-\x08\x0b-\x0d\x0e-\x1f\"\'\n]/ ) {
6531
+  		$string =~ s/\\/\\\\/g;
6532
+  		$string =~ s/"/\\"/g;
6533
+  		$string =~ s/\n/\\n/g;
6534
+  		$string =~ s/([\x00-\x1f])/\\$UNPRINTABLE[ord($1)]/g;
6535
+  		return qq|"$string"|;
6536
+  	}
6537
+  	if ( $string =~ /(?:^\W|\s|:\z)/ or $QUOTE{$string} ) {
6538
+  		return "'$string'";
6539
+  	}
6540
+  	return $string;
6541
+  }
6500 6542
   
6501
-  use constant P_ASCII                => 0;
6502
-  use constant P_LATIN1               => 1;
6503
-  use constant P_UTF8                 => 2;
6504
-  use constant P_INDENT               => 3;
6505
-  use constant P_CANONICAL            => 4;
6506
-  use constant P_SPACE_BEFORE         => 5;
6507
-  use constant P_SPACE_AFTER          => 6;
6508
-  use constant P_ALLOW_NONREF         => 7;
6509
-  use constant P_SHRINK               => 8;
6510
-  use constant P_ALLOW_BLESSED        => 9;
6511
-  use constant P_CONVERT_BLESSED      => 10;
6512
-  use constant P_RELAXED              => 11;
6543
+  sub _write_array {
6544
+  	my ($self, $array, $indent, $seen) = @_;
6545
+  	if ( $seen->{refaddr($array)}++ ) {
6546
+  		die "CPAN::Meta::YAML does not support circular references";
6547
+  	}
6548
+  	my @lines  = ();
6549
+  	foreach my $el ( @$array ) {
6550
+  		my $line = ('  ' x $indent) . '-';
6551
+  		my $type = ref $el;
6552
+  		if ( ! $type ) {
6553
+  			$line .= ' ' . $self->_write_scalar( $el, $indent + 1 );
6554
+  			push @lines, $line;
6513 6555
   
6514
-  use constant P_LOOSE                => 12;
6515
-  use constant P_ALLOW_BIGNUM         => 13;
6516
-  use constant P_ALLOW_BAREKEY        => 14;
6517
-  use constant P_ALLOW_SINGLEQUOTE    => 15;
6518
-  use constant P_ESCAPE_SLASH         => 16;
6519
-  use constant P_AS_NONBLESSED        => 17;
6556
+  		} elsif ( $type eq 'ARRAY' ) {
6557
+  			if ( @$el ) {
6558
+  				push @lines, $line;
6559
+  				push @lines, $self->_write_array( $el, $indent + 1, $seen );
6560
+  			} else {
6561
+  				$line .= ' []';
6562
+  				push @lines, $line;
6563
+  			}
6520 6564
   
6521
-  use constant P_ALLOW_UNKNOWN        => 18;
6565
+  		} elsif ( $type eq 'HASH' ) {
6566
+  			if ( keys %$el ) {
6567
+  				push @lines, $line;
6568
+  				push @lines, $self->_write_hash( $el, $indent + 1, $seen );
6569
+  			} else {
6570
+  				$line .= ' {}';
6571
+  				push @lines, $line;
6572
+  			}
6522 6573
   
6523
-  use constant OLD_PERL => $] < 5.008 ? 1 : 0;
6574
+  		} else {
6575
+  			die "CPAN::Meta::YAML does not support $type references";
6576
+  		}
6577
+  	}
6524 6578
   
6525
-  BEGIN {
6526
-      my @xs_compati_bit_properties = qw(
6527
-              latin1 ascii utf8 indent canonical space_before space_after allow_nonref shrink
6528
-              allow_blessed convert_blessed relaxed allow_unknown
6529
-      );
6530
-      my @pp_bit_properties = qw(
6531
-              allow_singlequote allow_bignum loose
6532
-              allow_barekey escape_slash as_nonblessed
6533
-      );
6579
+  	@lines;
6580
+  }
6534 6581
   
6535
-      # Perl version check, Unicode handling is enable?
6536
-      # Helper module sets @JSON::PP::_properties.
6537
-      if ($] < 5.008 ) {
6538
-          my $helper = $] >= 5.006 ? 'JSON::PP::Compat5006' : 'JSON::PP::Compat5005';
6539
-          eval qq| require $helper |;
6540
-          if ($@) { Carp::croak $@; }
6541
-      }
6582
+  sub _write_hash {
6583
+  	my ($self, $hash, $indent, $seen) = @_;
6584
+  	if ( $seen->{refaddr($hash)}++ ) {
6585
+  		die "CPAN::Meta::YAML does not support circular references";
6586
+  	}
6587
+  	my @lines  = ();
6588
+  	foreach my $name ( sort keys %$hash ) {
6589
+  		my $el   = $hash->{$name};
6590
+  		my $line = ('  ' x $indent) . "$name:";
6591
+  		my $type = ref $el;
6592
+  		if ( ! $type ) {
6593
+  			$line .= ' ' . $self->_write_scalar( $el, $indent + 1 );
6594
+  			push @lines, $line;
6542 6595
   
6543
-      for my $name (@xs_compati_bit_properties, @pp_bit_properties) {
6544
-          my $flag_name = 'P_' . uc($name);
6596
+  		} elsif ( $type eq 'ARRAY' ) {
6597
+  			if ( @$el ) {
6598
+  				push @lines, $line;
6599
+  				push @lines, $self->_write_array( $el, $indent + 1, $seen );
6600
+  			} else {
6601
+  				$line .= ' []';
6602
+  				push @lines, $line;
6603
+  			}
6545 6604
   
6546
-          eval qq/
6547
-              sub $name {
6548
-                  my \$enable = defined \$_[1] ? \$_[1] : 1;
6549
-  
6550
-                  if (\$enable) {
6551
-                      \$_[0]->{PROPS}->[$flag_name] = 1;
6552
-                  }
6553
-                  else {
6554
-                      \$_[0]->{PROPS}->[$flag_name] = 0;
6555
-                  }
6605
+  		} elsif ( $type eq 'HASH' ) {
6606
+  			if ( keys %$el ) {
6607
+  				push @lines, $line;
6608
+  				push @lines, $self->_write_hash( $el, $indent + 1, $seen );
6609
+  			} else {
6610
+  				$line .= ' {}';
6611
+  				push @lines, $line;
6612
+  			}
6556 6613
   
6557
-                  \$_[0];
6558
-              }
6614
+  		} else {
6615
+  			die "CPAN::Meta::YAML does not support $type references";
6616
+  		}
6617
+  	}
6559 6618
   
6560
-              sub get_$name {
6561
-                  \$_[0]->{PROPS}->[$flag_name] ? 1 : '';
6562
-              }
6563
-          /;
6564
-      }
6619
+  	@lines;
6620
+  }
6565 6621
   
6622
+  # Set error
6623
+  sub _error {
6624
+  	$CPAN::Meta::YAML::errstr = $_[1];
6625
+  	undef;
6566 6626
   }
6567 6627
   
6628
+  # Retrieve error
6629
+  sub errstr {
6630
+  	$CPAN::Meta::YAML::errstr;
6631
+  }
6568 6632
   
6569 6633
   
6570
-  # Functions
6571 6634
   
6572
-  my %encode_allow_method
6573
-       = map {($_ => 1)} qw/utf8 pretty allow_nonref latin1 self_encode escape_slash
6574
-                            allow_blessed convert_blessed indent indent_length allow_bignum
6575
-                            as_nonblessed
6576
-                          /;
6577
-  my %decode_allow_method
6578
-       = map {($_ => 1)} qw/utf8 allow_nonref loose allow_singlequote allow_bignum
6579
-                            allow_barekey max_size relaxed/;
6580 6635
   
6581 6636
   
6582
-  my $JSON; # cache
6637
+  #####################################################################
6638
+  # YAML Compatibility
6583 6639
   
6584
-  sub encode_json ($) { # encode
6585
-      ($JSON ||= __PACKAGE__->new->utf8)->encode(@_);
6640
+  sub Dump {
6641
+  	CPAN::Meta::YAML->new(@_)->write_string;
6586 6642
   }
6587 6643
   
6644
+  sub Load {
6645
+  	my $self = CPAN::Meta::YAML->read_string(@_);
6646
+  	unless ( $self ) {
6647
+  		Carp::croak("Failed to load YAML document from string");
6648
+  	}
6649
+  	if ( wantarray ) {
6650
+  		return @$self;
6651
+  	} else {
6652
+  		# To match YAML.pm, return the last document
6653
+  		return $self->[-1];
6654
+  	}
6655
+  }
6588 6656
   
6589
-  sub decode_json { # decode
6590
-      ($JSON ||= __PACKAGE__->new->utf8)->decode(@_);
6657
+  BEGIN {
6658
+  	*freeze = *Dump;
6659
+  	*thaw   = *Load;
6591 6660
   }
6592 6661
   
6593
-  # Obsoleted
6662
+  sub DumpFile {
6663
+  	my $file = shift;
6664
+  	CPAN::Meta::YAML->new(@_)->write($file);
6665
+  }
6594 6666
   
6595
-  sub to_json($) {
6596
-     Carp::croak ("JSON::PP::to_json has been renamed to encode_json.");
6667
+  sub LoadFile {
6668
+  	my $self = CPAN::Meta::YAML->read($_[0]);
6669
+  	unless ( $self ) {
6670
+  		Carp::croak("Failed to load YAML document from '" . ($_[0] || '') . "'");
6671
+  	}
6672
+  	if ( wantarray ) {
6673
+  		return @$self;
6674
+  	} else {
6675
+  		# Return only the last document to match YAML.pm, 
6676
+  		return $self->[-1];
6677
+  	}
6597 6678
   }
6598 6679
   
6599 6680
   
6600
-  sub from_json($) {
6601
-     Carp::croak ("JSON::PP::from_json has been renamed to decode_json.");
6602
-  }
6603 6681
   
6604 6682
   
6605
-  # Methods
6606 6683
   
6607
-  sub new {
6608
-      my $class = shift;
6609
-      my $self  = {
6610
-          max_depth   => 512,
6611
-          max_size    => 0,
6612
-          indent      => 0,
6613
-          FLAGS       => 0,
6614
-          fallback      => sub { encode_error('Invalid value. JSON can only reference.') },
6615
-          indent_length => 3,
6616
-      };
6684
+  #####################################################################
6685
+  # Use Scalar::Util if possible, otherwise emulate it
6617 6686
   
6618
-      bless $self, $class;
6687
+  BEGIN {
6688
+  	local $@;
6689
+  	eval {
6690
+  		require Scalar::Util;
6691
+  	};
6692
+  	my $v = eval("$Scalar::Util::VERSION") || 0;
6693
+  	if ( $@ or $v < 1.18 ) {
6694
+  		eval <<'END_PERL';
6695
+  # Scalar::Util failed to load or too old
6696
+  sub refaddr {
6697
+  	my $pkg = ref($_[0]) or return undef;
6698
+  	if ( !! UNIVERSAL::can($_[0], 'can') ) {
6699
+  		bless $_[0], 'Scalar::Util::Fake';
6700
+  	} else {
6701
+  		$pkg = undef;
6702
+  	}
6703
+  	"$_[0]" =~ /0x(\w+)/;
6704
+  	my $i = do { local $^W; hex $1 };
6705
+  	bless $_[0], $pkg if defined $pkg;
6706
+  	$i;
6707
+  }
6708
+  END_PERL
6709
+  	} else {
6710
+  		*refaddr = *Scalar::Util::refaddr;
6711
+  	}
6619 6712
   }
6620 6713
   
6714
+  1;
6715
+  
6621 6716
   
6622
-  sub encode {
6623
-      return $_[0]->PP_encode_json($_[1]);
6624
-  }
6625 6717
   
6626 6718
   
6627
-  sub decode {
6628
-      return $_[0]->PP_decode_json($_[1], 0x00000000);
6629
-  }
6719
+  __END__
6630 6720
   
6631 6721
   
6632
-  sub decode_prefix {
6633
-      return $_[0]->PP_decode_json($_[1], 0x00000001);
6634
-  }
6722
+  # ABSTRACT: Read and write a subset of YAML for CPAN Meta files
6635 6723
   
6636 6724
   
6637
-  # accessor
6725
+CPAN_META_YAML
6726
+
6727
+$fatpacked{"File/pushd.pm"} = <<'FILE_PUSHD';
6728
+  use strict;
6729
+  use warnings;
6730
+  package File::pushd;
6731
+  # ABSTRACT: change directory temporarily for a limited scope
6732
+  our $VERSION = '1.004'; # VERSION
6733
+  
6734
+  our @EXPORT  = qw( pushd tempd );
6735
+  our @ISA     = qw( Exporter );
6736
+  
6737
+  use Exporter;
6738
+  use Carp;
6739
+  use Cwd         qw( cwd abs_path );
6740
+  use File::Path  qw( rmtree );
6741
+  use File::Temp  qw();
6742
+  use File::Spec;
6638 6743
   
6744
+  use overload
6745
+      q{""} => sub { File::Spec->canonpath( $_[0]->{_pushd} ) },
6746
+      fallback => 1;
6639 6747
   
6640
-  # pretty printing
6748
+  #--------------------------------------------------------------------------#
6749
+  # pushd()
6750
+  #--------------------------------------------------------------------------#
6641 6751
   
6642
-  sub pretty {
6643
-      my ($self, $v) = @_;
6644
-      my $enable = defined $v ? $v : 1;
6752
+  sub pushd {
6753
+      my ($target_dir, $options) = @_;
6754
+      $options->{untaint_pattern} ||= qr{^([-+@\w./]+)$};
6645 6755
   
6646
-      if ($enable) { # indent_length(3) for JSON::XS compatibility
6647
-          $self->indent(1)->indent_length(3)->space_before(1)->space_after(1);
6756
+      my $tainted_orig = cwd;
6757
+      my $orig;
6758
+      if ( $tainted_orig =~ $options->{untaint_pattern} ) {
6759
+        $orig = $1;
6648 6760
       }
6649 6761
       else {
6650
-          $self->indent(0)->space_before(0)->space_after(0);
6762
+        $orig = $tainted_orig;
6651 6763
       }
6652 6764
   
6653
-      $self;
6765
+      my $tainted_dest;
6766
+      eval { $tainted_dest   = $target_dir ? abs_path( $target_dir ) : $orig };
6767
+      croak "Can't locate directory $target_dir: $@" if $@;
6768
+  
6769
+      my $dest;
6770
+      if ( $tainted_dest =~ $options->{untaint_pattern} ) {
6771
+        $dest = $1;
6772
+      }
6773
+      else {
6774
+        $dest = $tainted_dest;
6775
+      }
6776
+  
6777
+      if ($dest ne $orig) {
6778
+          chdir $dest or croak "Can't chdir to $dest\: $!";
6779
+      }
6780
+  
6781
+      my $self = bless {
6782
+          _pushd => $dest,
6783
+          _original => $orig
6784
+      }, __PACKAGE__;
6785
+  
6786
+      return $self;
6654 6787
   }
6655 6788
   
6656
-  # etc
6789
+  #--------------------------------------------------------------------------#
6790
+  # tempd()
6791
+  #--------------------------------------------------------------------------#
6657 6792
   
6658
-  sub max_depth {
6659
-      my $max  = defined $_[1] ? $_[1] : 0x80000000;
6660
-      $_[0]->{max_depth} = $max;
6661
-      $_[0];
6793
+  sub tempd {
6794
+      my ($options) = @_;
6795
+      my $dir;
6796
+      eval { $dir = pushd( File::Temp::tempdir( CLEANUP => 0 ), $options ) };
6797
+      croak $@ if $@;
6798
+      $dir->{_tempd} = 1;
6799
+      return $dir;
6662 6800
   }
6663 6801
   
6802
+  #--------------------------------------------------------------------------#
6803
+  # preserve()
6804
+  #--------------------------------------------------------------------------#
6664 6805
   
6665
-  sub get_max_depth { $_[0]->{max_depth}; }
6806
+  sub preserve {
6807
+      my $self = shift;
6808
+      return 1 if ! $self->{"_tempd"};
6809
+      if ( @_ == 0 ) {
6810
+          return $self->{_preserve} = 1;
6811
+      }
6812
+      else {
6813
+          return $self->{_preserve} = $_[0] ? 1 : 0;
6814
+      }
6815
+  }
6666 6816
   
6817
+  #--------------------------------------------------------------------------#
6818
+  # DESTROY()
6819
+  # Revert to original directory as object is destroyed and cleanup
6820
+  # if necessary
6821
+  #--------------------------------------------------------------------------#
6667 6822
   
6668
-  sub max_size {
6669
-      my $max  = defined $_[1] ? $_[1] : 0;
6670
-      $_[0]->{max_size} = $max;
6671
-      $_[0];
6823
+  sub DESTROY {
6824
+      my ($self) = @_;
6825
+      my $orig = $self->{_original};
6826
+      chdir $orig if $orig; # should always be so, but just in case...
6827
+      if ( $self->{_tempd} &&
6828
+          !$self->{_preserve} ) {
6829
+          # don't destroy existing $@ if there is no error.
6830
+          my $err = do {
6831
+              local $@;
6832
+              eval { rmtree( $self->{_pushd} ) };
6833
+              $@;
6834
+          };
6835
+          carp $err if $err;
6836
+      }
6672 6837
   }
6673 6838
   
6839
+  1;
6840
+  
6841
+  __END__
6674 6842
   
6675
-  sub get_max_size { $_[0]->{max_size}; }
6843
+FILE_PUSHD
6844
+
6845
+$fatpacked{"HTTP/Tiny.pm"} = <<'HTTP_TINY';
6846
+  # vim: ts=4 sts=4 sw=4 et:
6847
+  package HTTP::Tiny;
6848
+  use strict;
6849
+  use warnings;
6850
+  # ABSTRACT: A small, simple, correct HTTP/1.1 client
6851
+  our $VERSION = '0.028'; # VERSION
6676 6852
   
6853
+  use Carp ();
6677 6854
   
6678
-  sub filter_json_object {
6679
-      $_[0]->{cb_object} = defined $_[1] ? $_[1] : 0;
6680
-      $_[0]->{F_HOOK} = ($_[0]->{cb_object} or $_[0]->{cb_sk_object}) ? 1 : 0;
6681
-      $_[0];
6682
-  }
6683 6855
   
6684
-  sub filter_json_single_key_object {
6685
-      if (@_ > 1) {
6686
-          $_[0]->{cb_sk_object}->{$_[1]} = $_[2];
6856
+  my @attributes;
6857
+  BEGIN {
6858
+      @attributes = qw(agent cookie_jar default_headers local_address max_redirect max_size proxy timeout SSL_options verify_SSL);
6859
+      no strict 'refs';
6860
+      for my $accessor ( @attributes ) {
6861
+          *{$accessor} = sub {
6862
+              @_ > 1 ? $_[0]->{$accessor} = $_[1] : $_[0]->{$accessor};
6863
+          };
6687 6864
       }
6688
-      $_[0]->{F_HOOK} = ($_[0]->{cb_object} or $_[0]->{cb_sk_object}) ? 1 : 0;
6689
-      $_[0];
6690 6865
   }
6691 6866
   
6692
-  sub indent_length {
6693
-      if (!defined $_[1] or $_[1] > 15 or $_[1] < 0) {
6694
-          Carp::carp "The acceptable range of indent_length() is 0 to 15.";
6867
+  sub new {
6868
+      my($class, %args) = @_;
6869
+  
6870
+      (my $default_agent = $class) =~ s{::}{-}g;
6871
+      $default_agent .= "/" . ($class->VERSION || 0);
6872
+  
6873
+      my $self = {
6874
+          agent        => $default_agent,
6875
+          max_redirect => 5,
6876
+          timeout      => 60,
6877
+          verify_SSL   => $args{verify_SSL} || $args{verify_ssl} || 0, # no verification by default
6878
+      };
6879
+  
6880
+      $args{agent} .= $default_agent
6881
+          if defined $args{agent} && $args{agent} =~ / $/;
6882
+  
6883
+      $class->_validate_cookie_jar( $args{cookie_jar} ) if $args{cookie_jar};
6884
+  
6885
+      for my $key ( @attributes ) {
6886
+          $self->{$key} = $args{$key} if exists $args{$key}
6695 6887
       }
6696
-      else {
6697
-          $_[0]->{indent_length} = $_[1];
6888
+  
6889
+      # Never override proxy argument as this breaks backwards compat.
6890
+      if (!exists $self->{proxy} && (my $http_proxy = $ENV{http_proxy})) {
6891
+          if ($http_proxy =~ m{\Ahttp://[^/?#:@]+:\d+/?\z}) {
6892
+              $self->{proxy} = $http_proxy;
6893
+          }
6894
+          else {
6895
+              Carp::croak(qq{Environment 'http_proxy' must be in format http://<host>:<port>/\n});
6896
+          }
6698 6897
       }
6699
-      $_[0];
6700
-  }
6701 6898
   
6702
-  sub get_indent_length {
6703
-      $_[0]->{indent_length};
6899
+      return bless $self, $class;
6704 6900
   }
6705 6901
   
6706
-  sub sort_by {
6707
-      $_[0]->{sort_by} = defined $_[1] ? $_[1] : 1;
6708
-      $_[0];
6709
-  }
6710 6902
   
6711
-  sub allow_bigint {
6712
-      Carp::carp("allow_bigint() is obsoleted. use allow_bignum() insted.");
6903
+  for my $sub_name ( qw/get head put post delete/ ) {
6904
+      my $req_method = uc $sub_name;
6905
+      no strict 'refs';
6906
+      eval <<"HERE"; ## no critic
6907
+      sub $sub_name {
6908
+          my (\$self, \$url, \$args) = \@_;
6909
+          \@_ == 2 || (\@_ == 3 && ref \$args eq 'HASH')
6910
+          or Carp::croak(q/Usage: \$http->$sub_name(URL, [HASHREF])/ . "\n");
6911
+          return \$self->request('$req_method', \$url, \$args || {});
6912
+      }
6913
+  HERE
6713 6914
   }
6714 6915
   
6715
-  ###############################
6716 6916
   
6717
-  ###
6718
-  ### Perl => JSON
6719
-  ###
6917
+  sub post_form {
6918
+      my ($self, $url, $data, $args) = @_;
6919
+      (@_ == 3 || @_ == 4 && ref $args eq 'HASH')
6920
+          or Carp::croak(q/Usage: $http->post_form(URL, DATAREF, [HASHREF])/ . "\n");
6720 6921
   
6922
+      my $headers = {};
6923
+      while ( my ($key, $value) = each %{$args->{headers} || {}} ) {
6924
+          $headers->{lc $key} = $value;
6925
+      }
6926
+      delete $args->{headers};
6721 6927
   
6722
-  { # Convert
6928
+      return $self->request('POST', $url, {
6929
+              %$args,
6930
+              content => $self->www_form_urlencode($data),
6931
+              headers => {
6932
+                  %$headers,
6933
+                  'content-type' => 'application/x-www-form-urlencoded'
6934
+              },
6935
+          }
6936
+      );
6937
+  }
6723 6938
   
6724
-      my $max_depth;
6725
-      my $indent;
6726
-      my $ascii;
6727
-      my $latin1;
6728
-      my $utf8;
6729
-      my $space_before;
6730
-      my $space_after;
6731
-      my $canonical;
6732
-      my $allow_blessed;
6733
-      my $convert_blessed;
6734 6939
   
6735
-      my $indent_length;
6736
-      my $escape_slash;
6737
-      my $bignum;
6738
-      my $as_nonblessed;
6940
+  sub mirror {
6941
+      my ($self, $url, $file, $args) = @_;
6942
+      @_ == 3 || (@_ == 4 && ref $args eq 'HASH')
6943
+        or Carp::croak(q/Usage: $http->mirror(URL, FILE, [HASHREF])/ . "\n");
6944
+      if ( -e $file and my $mtime = (stat($file))[9] ) {
6945
+          $args->{headers}{'if-modified-since'} ||= $self->_http_date($mtime);
6946
+      }
6947
+      my $tempfile = $file . int(rand(2**31));
6948
+      open my $fh, ">", $tempfile
6949
+          or Carp::croak(qq/Error: Could not open temporary file $tempfile for downloading: $!\n/);
6950
+      binmode $fh;
6951
+      $args->{data_callback} = sub { print {$fh} $_[0] };
6952
+      my $response = $self->request('GET', $url, $args);
6953
+      close $fh
6954
+          or Carp::croak(qq/Error: Could not close temporary file $tempfile: $!\n/);
6955
+      if ( $response->{success} ) {
6956
+          rename $tempfile, $file
6957
+              or Carp::croak(qq/Error replacing $file with $tempfile: $!\n/);
6958
+          my $lm = $response->{headers}{'last-modified'};
6959
+          if ( $lm and my $mtime = $self->_parse_http_date($lm) ) {
6960
+              utime $mtime, $mtime, $file;
6961
+          }
6962
+      }
6963
+      $response->{success} ||= $response->{status} eq '304';
6964
+      unlink $tempfile;
6965
+      return $response;
6966
+  }
6739 6967
   
6740
-      my $depth;
6741
-      my $indent_count;
6742
-      my $keysort;
6743 6968
   
6969
+  my %idempotent = map { $_ => 1 } qw/GET HEAD PUT DELETE OPTIONS TRACE/;
6744 6970
   
6745
-      sub PP_encode_json {
6746
-          my $self = shift;
6747
-          my $obj  = shift;
6971
+  sub request {
6972
+      my ($self, $method, $url, $args) = @_;
6973
+      @_ == 3 || (@_ == 4 && ref $args eq 'HASH')
6974
+        or Carp::croak(q/Usage: $http->request(METHOD, URL, [HASHREF])/ . "\n");
6975
+      $args ||= {}; # we keep some state in this during _request
6748 6976
   
6749
-          $indent_count = 0;
6750
-          $depth        = 0;
6977
+      # RFC 2616 Section 8.1.4 mandates a single retry on broken socket
6978
+      my $response;
6979
+      for ( 0 .. 1 ) {
6980
+          $response = eval { $self->_request($method, $url, $args) };
6981
+          last unless $@ && $idempotent{$method}
6982
+              && $@ =~ m{^(?:Socket closed|Unexpected end)};
6983
+      }
6751 6984
   
6752
-          my $idx = $self->{PROPS};
6985
+      if (my $e = "$@") {
6986
+          $response = {
6987
+              url     => $url,
6988
+              success => q{},
6989
+              status  => 599,
6990
+              reason  => 'Internal Exception',
6991
+              content => $e,
6992
+              headers => {
6993
+                  'content-type'   => 'text/plain',
6994
+                  'content-length' => length $e,
6995
+              }
6996
+          };
6997
+      }
6998
+      return $response;
6999
+  }
6753 7000
   
6754
-          ($ascii, $latin1, $utf8, $indent, $canonical, $space_before, $space_after, $allow_blessed,
6755
-              $convert_blessed, $escape_slash, $bignum, $as_nonblessed)
6756
-           = @{$idx}[P_ASCII .. P_SPACE_AFTER, P_ALLOW_BLESSED, P_CONVERT_BLESSED,
6757
-                      P_ESCAPE_SLASH, P_ALLOW_BIGNUM, P_AS_NONBLESSED];
6758 7001
   
6759
-          ($max_depth, $indent_length) = @{$self}{qw/max_depth indent_length/};
7002
+  sub www_form_urlencode {
7003
+      my ($self, $data) = @_;
7004
+      (@_ == 2 && ref $data)
7005
+          or Carp::croak(q/Usage: $http->www_form_urlencode(DATAREF)/ . "\n");
7006
+      (ref $data eq 'HASH' || ref $data eq 'ARRAY')
7007
+          or Carp::croak("form data must be a hash or array reference\n");
6760 7008
   
6761
-          $keysort = $canonical ? sub { $a cmp $b } : undef;
7009
+      my @params = ref $data eq 'HASH' ? %$data : @$data;
7010
+      @params % 2 == 0
7011
+          or Carp::croak("form data reference must have an even number of terms\n");
6762 7012
   
6763
-          if ($self->{sort_by}) {
6764
-              $keysort = ref($self->{sort_by}) eq 'CODE' ? $self->{sort_by}
6765
-                       : $self->{sort_by} =~ /\D+/       ? $self->{sort_by}
6766
-                       : sub { $a cmp $b };
7013
+      my @terms;
7014
+      while( @params ) {
7015
+          my ($key, $value) = splice(@params, 0, 2);
7016
+          if ( ref $value eq 'ARRAY' ) {
7017
+              unshift @params, map { $key => $_ } @$value;
7018
+          }
7019
+          else {
7020
+              push @terms, join("=", map { $self->_uri_escape($_) } $key, $value);
6767 7021
           }
7022
+      }
6768 7023
   
6769
-          encode_error("hash- or arrayref expected (not a simple scalar, use allow_nonref to allow this)")
6770
-               if(!ref $obj and !$idx->[ P_ALLOW_NONREF ]);
7024
+      return join("&", sort @terms);
7025
+  }
6771 7026
   
6772
-          my $str  = $self->object_to_json($obj);
7027
+  #--------------------------------------------------------------------------#
7028
+  # private methods
7029
+  #--------------------------------------------------------------------------#
6773 7030
   
6774
-          $str .= "\n" if ( $indent ); # JSON::XS 2.26 compatible
7031
+  my %DefaultPort = (
7032
+      http => 80,
7033
+      https => 443,
7034
+  );
6775 7035
   
6776
-          unless ($ascii or $latin1 or $utf8) {
6777
-              utf8::upgrade($str);
6778
-          }
7036
+  sub _request {
7037
+      my ($self, $method, $url, $args) = @_;
6779 7038
   
6780
-          if ($idx->[ P_SHRINK ]) {
6781
-              utf8::downgrade($str, 1);
6782
-          }
7039
+      my ($scheme, $host, $port, $path_query) = $self->_split_url($url);
6783 7040
   
6784
-          return $str;
7041
+      my $request = {
7042
+          method    => $method,
7043
+          scheme    => $scheme,
7044
+          host_port => ($port == $DefaultPort{$scheme} ? $host : "$host:$port"),
7045
+          uri       => $path_query,
7046
+          headers   => {},
7047
+      };
7048
+  
7049
+      my $handle  = HTTP::Tiny::Handle->new(
7050
+          timeout         => $self->{timeout},
7051
+          SSL_options     => $self->{SSL_options},
7052
+          verify_SSL      => $self->{verify_SSL},
7053
+          local_address   => $self->{local_address},
7054
+      );
7055
+  
7056
+      if ($self->{proxy}) {
7057
+          $request->{uri} = "$scheme://$request->{host_port}$path_query";
7058
+          die(qq/HTTPS via proxy is not supported\n/)
7059
+              if $request->{scheme} eq 'https';
7060
+          $handle->connect(($self->_split_url($self->{proxy}))[0..2]);
7061
+      }
7062
+      else {
7063
+          $handle->connect($scheme, $host, $port);
6785 7064
       }
6786 7065
   
7066
+      $self->_prepare_headers_and_cb($request, $args, $url);
7067
+      $handle->write_request($request);
6787 7068
   
6788
-      sub object_to_json {
6789
-          my ($self, $obj) = @_;
6790
-          my $type = ref($obj);
7069
+      my $response;
7070
+      do { $response = $handle->read_response_header }
7071
+          until (substr($response->{status},0,1) ne '1');
6791 7072
   
6792
-          if($type eq 'HASH'){
6793
-              return $self->hash_to_json($obj);
6794
-          }
6795
-          elsif($type eq 'ARRAY'){
6796
-              return $self->array_to_json($obj);
6797
-          }
6798
-          elsif ($type) { # blessed object?
6799
-              if (blessed($obj)) {
7073
+      $self->_update_cookie_jar( $url, $response ) if $self->{cookie_jar};
6800 7074
   
6801
-                  return $self->value_to_json($obj) if ( $obj->isa('JSON::PP::Boolean') );
7075
+      if ( my @redir_args = $self->_maybe_redirect($request, $response, $args) ) {
7076
+          $handle->close;
7077
+          return $self->_request(@redir_args, $args);
7078
+      }
6802 7079
   
6803
-                  if ( $convert_blessed and $obj->can('TO_JSON') ) {
6804
-                      my $result = $obj->TO_JSON();
6805
-                      if ( defined $result and ref( $result ) ) {
6806
-                          if ( refaddr( $obj ) eq refaddr( $result ) ) {
6807
-                              encode_error( sprintf(
6808
-                                  "%s::TO_JSON method returned same object as was passed instead of a new one",
6809
-                                  ref $obj
6810
-                              ) );
6811
-                          }
6812
-                      }
7080
+      if ($method eq 'HEAD' || $response->{status} =~ /^[23]04/) {
7081
+          # response has no message body
7082
+      }
7083
+      else {
7084
+          my $data_cb = $self->_prepare_data_cb($response, $args);
7085
+          $handle->read_body($data_cb, $response);
7086
+      }
6813 7087
   
6814
-                      return $self->object_to_json( $result );
6815
-                  }
7088
+      $handle->close;
7089
+      $response->{success} = substr($response->{status},0,1) eq '2';
7090
+      $response->{url} = $url;
7091
+      return $response;
7092
+  }
6816 7093
   
6817
-                  return "$obj" if ( $bignum and _is_bignum($obj) );
6818
-                  return $self->blessed_to_json($obj) if ($allow_blessed and $as_nonblessed); # will be removed.
7094
+  sub _prepare_headers_and_cb {
7095
+      my ($self, $request, $args, $url) = @_;
6819 7096
   
6820
-                  encode_error( sprintf("encountered object '%s', but neither allow_blessed "
6821
-                      . "nor convert_blessed settings are enabled", $obj)
6822
-                  ) unless ($allow_blessed);
7097
+      for ($self->{default_headers}, $args->{headers}) {
7098
+          next unless defined;
7099
+          while (my ($k, $v) = each %$_) {
7100
+              $request->{headers}{lc $k} = $v;
7101
+          }
7102
+      }
7103
+      $request->{headers}{'host'}         = $request->{host_port};
7104
+      $request->{headers}{'connection'}   = "close";
7105
+      $request->{headers}{'user-agent'} ||= $self->{agent};
6823 7106
   
6824
-                  return 'null';
6825
-              }
6826
-              else {
6827
-                  return $self->value_to_json($obj);
6828
-              }
7107
+      if (defined $args->{content}) {
7108
+          $request->{headers}{'content-type'} ||= "application/octet-stream";
7109
+          if (ref $args->{content} eq 'CODE') {
7110
+              $request->{headers}{'transfer-encoding'} = 'chunked'
7111
+                unless $request->{headers}{'content-length'}
7112
+                    || $request->{headers}{'transfer-encoding'};
7113
+              $request->{cb} = $args->{content};
6829 7114
           }
6830
-          else{
6831
-              return $self->value_to_json($obj);
7115
+          else {
7116
+              my $content = $args->{content};
7117
+              if ( $] ge '5.008' ) {
7118
+                  utf8::downgrade($content, 1)
7119
+                      or die(qq/Wide character in request message body\n/);
7120
+              }
7121
+              $request->{headers}{'content-length'} = length $content
7122
+                unless $request->{headers}{'content-length'}
7123
+                    || $request->{headers}{'transfer-encoding'};
7124
+              $request->{cb} = sub { substr $content, 0, length $content, '' };
6832 7125
           }
7126
+          $request->{trailer_cb} = $args->{trailer_callback}
7127
+              if ref $args->{trailer_callback} eq 'CODE';
6833 7128
       }
6834 7129
   
7130
+      ### If we have a cookie jar, then maybe add relevant cookies
7131
+      if ( $self->{cookie_jar} ) {
7132
+          my $cookies = $self->cookie_jar->cookie_header( $url );
7133
+          $request->{headers}{cookie} = $cookies if length $cookies;
7134
+      }
6835 7135
   
6836
-      sub hash_to_json {
6837
-          my ($self, $obj) = @_;
6838
-          my @res;
6839
-  
6840
-          encode_error("json text or perl structure exceeds maximum nesting level (max_depth set too low?)")
6841
-                                           if (++$depth > $max_depth);
7136
+      return;
7137
+  }
6842 7138
   
6843
-          my ($pre, $post) = $indent ? $self->_up_indent() : ('', '');
6844
-          my $del = ($space_before ? ' ' : '') . ':' . ($space_after ? ' ' : '');
7139
+  sub _prepare_data_cb {
7140
+      my ($self, $response, $args) = @_;
7141
+      my $data_cb = $args->{data_callback};
7142
+      $response->{content} = '';
6845 7143
   
6846
-          for my $k ( _sort( $obj ) ) {
6847
-              if ( OLD_PERL ) { utf8::decode($k) } # key for Perl 5.6 / be optimized
6848
-              push @res, string_to_json( $self, $k )
6849
-                            .  $del
6850
-                            . ( $self->object_to_json( $obj->{$k} ) || $self->value_to_json( $obj->{$k} ) );
7144
+      if (!$data_cb || $response->{status} !~ /^2/) {
7145
+          if (defined $self->{max_size}) {
7146
+              $data_cb = sub {
7147
+                  $_[1]->{content} .= $_[0];
7148
+                  die(qq/Size of response body exceeds the maximum allowed of $self->{max_size}\n/)
7149
+                    if length $_[1]->{content} > $self->{max_size};
7150
+              };
7151
+          }
7152
+          else {
7153
+              $data_cb = sub { $_[1]->{content} .= $_[0] };
6851 7154
           }
6852
-  
6853
-          --$depth;
6854
-          $self->_down_indent() if ($indent);
6855
-  
6856
-          return   '{' . ( @res ? $pre : '' ) . ( @res ? join( ",$pre", @res ) . $post : '' )  . '}';
6857 7155
       }
7156
+      return $data_cb;
7157
+  }
6858 7158
   
7159
+  sub _update_cookie_jar {
7160
+      my ($self, $url, $response) = @_;
6859 7161
   
6860
-      sub array_to_json {
6861
-          my ($self, $obj) = @_;
6862
-          my @res;
7162
+      my $cookies = $response->{headers}->{'set-cookie'};
7163
+      return unless defined $cookies;
6863 7164
   
6864
-          encode_error("json text or perl structure exceeds maximum nesting level (max_depth set too low?)")
6865
-                                           if (++$depth > $max_depth);
7165
+      my @cookies = ref $cookies ? @$cookies : $cookies;
6866 7166
   
6867
-          my ($pre, $post) = $indent ? $self->_up_indent() : ('', '');
7167
+      $self->cookie_jar->add( $url, $_ ) for @cookies;
6868 7168
   
6869
-          for my $v (@$obj){
6870
-              push @res, $self->object_to_json($v) || $self->value_to_json($v);
6871
-          }
7169
+      return;
7170
+  }
6872 7171
   
6873
-          --$depth;
6874
-          $self->_down_indent() if ($indent);
7172
+  sub _validate_cookie_jar {
7173
+      my ($class, $jar) = @_;
6875 7174
   
6876
-          return '[' . ( @res ? $pre : '' ) . ( @res ? join( ",$pre", @res ) . $post : '' ) . ']';
7175
+      # duck typing
7176
+      for my $method ( qw/add cookie_header/ ) {
7177
+          Carp::croak(qq/Cookie jar must provide the '$method' method\n/)
7178
+              unless ref($jar) && ref($jar)->can($method);
6877 7179
       }
6878 7180
   
7181
+      return;
7182
+  }
6879 7183
   
6880
-      sub value_to_json {
6881
-          my ($self, $value) = @_;
7184
+  sub _maybe_redirect {
7185
+      my ($self, $request, $response, $args) = @_;
7186
+      my $headers = $response->{headers};
7187
+      my ($status, $method) = ($response->{status}, $request->{method});
7188
+      if (($status eq '303' or ($status =~ /^30[127]/ && $method =~ /^GET|HEAD$/))
7189
+          and $headers->{location}
7190
+          and ++$args->{redirects} <= $self->{max_redirect}
7191
+      ) {
7192
+          my $location = ($headers->{location} =~ /^\//)
7193
+              ? "$request->{scheme}://$request->{host_port}$headers->{location}"
7194
+              : $headers->{location} ;
7195
+          return (($status eq '303' ? 'GET' : $method), $location);
7196
+      }
7197
+      return;
7198
+  }
6882 7199
   
6883
-          return 'null' if(!defined $value);
7200
+  sub _split_url {
7201
+      my $url = pop;
6884 7202
   
6885
-          my $b_obj = B::svref_2object(\$value);  # for round trip problem
6886
-          my $flags = $b_obj->FLAGS;
7203
+      # URI regex adapted from the URI module
7204
+      my ($scheme, $authority, $path_query) = $url =~ m<\A([^:/?#]+)://([^/?#]*)([^#]*)>
7205
+        or die(qq/Cannot parse URL: '$url'\n/);
6887 7206
   
6888
-          return $value # as is 
6889
-              if $flags & ( B::SVp_IOK | B::SVp_NOK ) and !( $flags & B::SVp_POK ); # SvTYPE is IV or NV?
7207
+      $scheme     = lc $scheme;
7208
+      $path_query = "/$path_query" unless $path_query =~ m<\A/>;
6890 7209
   
6891
-          my $type = ref($value);
7210
+      my $host = (length($authority)) ? lc $authority : 'localhost';
7211
+         $host =~ s/\A[^@]*@//;   # userinfo
7212
+      my $port = do {
7213
+         $host =~ s/:([0-9]*)\z// && length $1
7214
+           ? $1
7215
+           : ($scheme eq 'http' ? 80 : $scheme eq 'https' ? 443 : undef);
7216
+      };
6892 7217
   
6893
-          if(!$type){
6894
-              return string_to_json($self, $value);
6895
-          }
6896
-          elsif( blessed($value) and  $value->isa('JSON::PP::Boolean') ){
6897
-              return $$value == 1 ? 'true' : 'false';
6898
-          }
6899
-          elsif ($type) {
6900
-              if ((overload::StrVal($value) =~ /=(\w+)/)[0]) {
6901
-                  return $self->value_to_json("$value");
6902
-              }
7218
+      return ($scheme, $host, $port, $path_query);
7219
+  }
6903 7220
   
6904
-              if ($type eq 'SCALAR' and defined $$value) {
6905
-                  return   $$value eq '1' ? 'true'
6906
-                         : $$value eq '0' ? 'false'
6907
-                         : $self->{PROPS}->[ P_ALLOW_UNKNOWN ] ? 'null'
6908
-                         : encode_error("cannot encode reference to scalar");
6909
-              }
7221
+  # Date conversions adapted from HTTP::Date
7222
+  my $DoW = "Sun|Mon|Tue|Wed|Thu|Fri|Sat";
7223
+  my $MoY = "Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec";
7224
+  sub _http_date {
7225
+      my ($sec, $min, $hour, $mday, $mon, $year, $wday) = gmtime($_[1]);
7226
+      return sprintf("%s, %02d %s %04d %02d:%02d:%02d GMT",
7227
+          substr($DoW,$wday*4,3),
7228
+          $mday, substr($MoY,$mon*4,3), $year+1900,
7229
+          $hour, $min, $sec
7230
+      );
7231
+  }
6910 7232
   
6911
-               if ( $self->{PROPS}->[ P_ALLOW_UNKNOWN ] ) {
6912
-                   return 'null';
6913
-               }
6914
-               else {
6915
-                   if ( $type eq 'SCALAR' or $type eq 'REF' ) {
6916
-                      encode_error("cannot encode reference to scalar");
6917
-                   }
6918
-                   else {
6919
-                      encode_error("encountered $value, but JSON can only represent references to arrays or hashes");
6920
-                   }
6921
-               }
7233
+  sub _parse_http_date {
7234
+      my ($self, $str) = @_;
7235
+      require Time::Local;
7236
+      my @tl_parts;
7237
+      if ($str =~ /^[SMTWF][a-z]+, +(\d{1,2}) ($MoY) +(\d\d\d\d) +(\d\d):(\d\d):(\d\d) +GMT$/) {
7238
+          @tl_parts = ($6, $5, $4, $1, (index($MoY,$2)/4), $3);
7239
+      }
7240
+      elsif ($str =~ /^[SMTWF][a-z]+, +(\d\d)-($MoY)-(\d{2,4}) +(\d\d):(\d\d):(\d\d) +GMT$/ ) {
7241
+          @tl_parts = ($6, $5, $4, $1, (index($MoY,$2)/4), $3);
7242
+      }
7243
+      elsif ($str =~ /^[SMTWF][a-z]+ +($MoY) +(\d{1,2}) +(\d\d):(\d\d):(\d\d) +(?:[^0-9]+ +)?(\d\d\d\d)$/ ) {
7244
+          @tl_parts = ($5, $4, $3, $2, (index($MoY,$1)/4), $6);
7245
+      }
7246
+      return eval {
7247
+          my $t = @tl_parts ? Time::Local::timegm(@tl_parts) : -1;
7248
+          $t < 0 ? undef : $t;
7249
+      };
7250
+  }
6922 7251
   
6923
-          }
6924
-          else {
6925
-              return $self->{fallback}->($value)
6926
-                   if ($self->{fallback} and ref($self->{fallback}) eq 'CODE');
6927
-              return 'null';
6928
-          }
7252
+  # URI escaping adapted from URI::Escape
7253
+  # c.f. http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.1
7254
+  # perl 5.6 ready UTF-8 encoding adapted from JSON::PP
7255
+  my %escapes = map { chr($_) => sprintf("%%%02X", $_) } 0..255;
7256
+  $escapes{' '}="+";
7257
+  my $unsafe_char = qr/[^A-Za-z0-9\-\._~]/;
6929 7258
   
7259
+  sub _uri_escape {
7260
+      my ($self, $str) = @_;
7261
+      if ( $] ge '5.008' ) {
7262
+          utf8::encode($str);
6930 7263
       }
7264
+      else {
7265
+          $str = pack("U*", unpack("C*", $str)) # UTF-8 encode a byte string
7266
+              if ( length $str == do { use bytes; length $str } );
7267
+          $str = pack("C*", unpack("C*", $str)); # clear UTF-8 flag
7268
+      }
7269
+      $str =~ s/($unsafe_char)/$escapes{$1}/ge;
7270
+      return $str;
7271
+  }
6931 7272
   
7273
+  package
7274
+      HTTP::Tiny::Handle; # hide from PAUSE/indexers
7275
+  use strict;
7276
+  use warnings;
6932 7277
   
6933
-      my %esc = (
6934
-          "\n" => '\n',
6935
-          "\r" => '\r',
6936
-          "\t" => '\t',
6937
-          "\f" => '\f',
6938
-          "\b" => '\b',
6939
-          "\"" => '\"',
6940
-          "\\" => '\\\\',
6941
-          "\'" => '\\\'',
6942
-      );
6943
-  
7278
+  use Errno      qw[EINTR EPIPE];
7279
+  use IO::Socket qw[SOCK_STREAM];
6944 7280
   
6945
-      sub string_to_json {
6946
-          my ($self, $arg) = @_;
7281
+  sub BUFSIZE () { 32768 } ## no critic
6947 7282
   
6948
-          $arg =~ s/([\x22\x5c\n\r\t\f\b])/$esc{$1}/g;
6949
-          $arg =~ s/\//\\\//g if ($escape_slash);
6950
-          $arg =~ s/([\x00-\x08\x0b\x0e-\x1f])/'\\u00' . unpack('H2', $1)/eg;
7283
+  my $Printable = sub {
7284
+      local $_ = shift;
7285
+      s/\r/\\r/g;
7286
+      s/\n/\\n/g;
7287
+      s/\t/\\t/g;
7288
+      s/([^\x20-\x7E])/sprintf('\\x%.2X', ord($1))/ge;
7289
+      $_;
7290
+  };
6951 7291
   
6952
-          if ($ascii) {
6953
-              $arg = JSON_PP_encode_ascii($arg);
6954
-          }
7292
+  my $Token = qr/[\x21\x23-\x27\x2A\x2B\x2D\x2E\x30-\x39\x41-\x5A\x5E-\x7A\x7C\x7E]/;
6955 7293
   
6956
-          if ($latin1) {
6957
-              $arg = JSON_PP_encode_latin1($arg);
6958
-          }
7294
+  sub new {
7295
+      my ($class, %args) = @_;
7296
+      return bless {
7297
+          rbuf             => '',
7298
+          timeout          => 60,
7299
+          max_line_size    => 16384,
7300
+          max_header_lines => 64,
7301
+          verify_SSL       => 0,
7302
+          SSL_options      => {},
7303
+          %args
7304
+      }, $class;
7305
+  }
6959 7306
   
6960
-          if ($utf8) {
6961
-              utf8::encode($arg);
6962
-          }
7307
+  sub connect {
7308
+      @_ == 4 || die(q/Usage: $handle->connect(scheme, host, port)/ . "\n");
7309
+      my ($self, $scheme, $host, $port) = @_;
6963 7310
   
6964
-          return '"' . $arg . '"';
7311
+      if ( $scheme eq 'https' ) {
7312
+          die(qq/IO::Socket::SSL 1.56 must be installed for https support\n/)
7313
+              unless eval {require IO::Socket::SSL; IO::Socket::SSL->VERSION(1.56)};
7314
+          die(qq/Net::SSLeay 1.49 must be installed for https support\n/)
7315
+              unless eval {require Net::SSLeay; Net::SSLeay->VERSION(1.49)};
6965 7316
       }
6966
-  
6967
-  
6968
-      sub blessed_to_json {
6969
-          my $reftype = reftype($_[1]) || '';
6970
-          if ($reftype eq 'HASH') {
6971
-              return $_[0]->hash_to_json($_[1]);
6972
-          }
6973
-          elsif ($reftype eq 'ARRAY') {
6974
-              return $_[0]->array_to_json($_[1]);
6975
-          }
6976
-          else {
6977
-              return 'null';
6978
-          }
7317
+      elsif ( $scheme ne 'http' ) {
7318
+        die(qq/Unsupported URL scheme '$scheme'\n/);
6979 7319
       }
7320
+      $self->{fh} = 'IO::Socket::INET'->new(
7321
+          PeerHost  => $host,
7322
+          PeerPort  => $port,
7323
+          $self->{local_address} ?
7324
+              ( LocalAddr => $self->{local_address} ) : (),
7325
+          Proto     => 'tcp',
7326
+          Type      => SOCK_STREAM,
7327
+          Timeout   => $self->{timeout}
7328
+      ) or die(qq/Could not connect to '$host:$port': $@\n/);
6980 7329
   
7330
+      binmode($self->{fh})
7331
+        or die(qq/Could not binmode() socket: '$!'\n/);
6981 7332
   
6982
-      sub encode_error {
6983
-          my $error  = shift;
6984
-          Carp::croak "$error";
6985
-      }
6986
-  
7333
+      if ( $scheme eq 'https') {
7334
+          my $ssl_args = $self->_ssl_args($host);
7335
+          IO::Socket::SSL->start_SSL(
7336
+              $self->{fh},
7337
+              %$ssl_args,
7338
+              SSL_create_ctx_callback => sub {
7339
+                  my $ctx = shift;
7340
+                  Net::SSLeay::CTX_set_mode($ctx, Net::SSLeay::MODE_AUTO_RETRY());
7341
+              },
7342
+          );
6987 7343
   
6988
-      sub _sort {
6989
-          defined $keysort ? (sort $keysort (keys %{$_[0]})) : keys %{$_[0]};
7344
+          unless ( ref($self->{fh}) eq 'IO::Socket::SSL' ) {
7345
+              my $ssl_err = IO::Socket::SSL->errstr;
7346
+              die(qq/SSL connection failed for $host: $ssl_err\n/);
7347
+          }
6990 7348
       }
6991 7349
   
7350
+      $self->{host} = $host;
7351
+      $self->{port} = $port;
6992 7352
   
6993
-      sub _up_indent {
6994
-          my $self  = shift;
6995
-          my $space = ' ' x $indent_length;
6996
-  
6997
-          my ($pre,$post) = ('','');
6998
-  
6999
-          $post = "\n" . $space x $indent_count;
7353
+      return $self;
7354
+  }
7000 7355
   
7001
-          $indent_count++;
7356
+  sub close {
7357
+      @_ == 1 || die(q/Usage: $handle->close()/ . "\n");
7358
+      my ($self) = @_;
7359
+      CORE::close($self->{fh})
7360
+        or die(qq/Could not close socket: '$!'\n/);
7361
+  }
7002 7362
   
7003
-          $pre = "\n" . $space x $indent_count;
7363
+  sub write {
7364
+      @_ == 2 || die(q/Usage: $handle->write(buf)/ . "\n");
7365
+      my ($self, $buf) = @_;
7004 7366
   
7005
-          return ($pre,$post);
7367
+      if ( $] ge '5.008' ) {
7368
+          utf8::downgrade($buf, 1)
7369
+              or die(qq/Wide character in write()\n/);
7006 7370
       }
7007 7371
   
7372
+      my $len = length $buf;
7373
+      my $off = 0;
7008 7374
   
7009
-      sub _down_indent { $indent_count--; }
7375
+      local $SIG{PIPE} = 'IGNORE';
7010 7376
   
7377
+      while () {
7378
+          $self->can_write
7379
+            or die(qq/Timed out while waiting for socket to become ready for writing\n/);
7380
+          my $r = syswrite($self->{fh}, $buf, $len, $off);
7381
+          if (defined $r) {
7382
+              $len -= $r;
7383
+              $off += $r;
7384
+              last unless $len > 0;
7385
+          }
7386
+          elsif ($! == EPIPE) {
7387
+              die(qq/Socket closed by remote server: $!\n/);
7388
+          }
7389
+          elsif ($! != EINTR) {
7390
+              if ($self->{fh}->can('errstr')){
7391
+                  my $err = $self->{fh}->errstr();
7392
+                  die (qq/Could not write to SSL socket: '$err'\n /);
7393
+              }
7394
+              else {
7395
+                  die(qq/Could not write to socket: '$!'\n/);
7396
+              }
7011 7397
   
7012
-      sub PP_encode_box {
7013
-          {
7014
-              depth        => $depth,
7015
-              indent_count => $indent_count,
7016
-          };
7398
+          }
7017 7399
       }
7400
+      return $off;
7401
+  }
7018 7402
   
7019
-  } # Convert
7403
+  sub read {
7404
+      @_ == 2 || @_ == 3 || die(q/Usage: $handle->read(len [, allow_partial])/ . "\n");
7405
+      my ($self, $len, $allow_partial) = @_;
7020 7406
   
7407
+      my $buf  = '';
7408
+      my $got = length $self->{rbuf};
7021 7409
   
7022
-  sub _encode_ascii {
7023
-      join('',
7024
-          map {
7025
-              $_ <= 127 ?
7026
-                  chr($_) :
7027
-              $_ <= 65535 ?
7028
-                  sprintf('\u%04x', $_) : sprintf('\u%x\u%x', _encode_surrogates($_));
7029
-          } unpack('U*', $_[0])
7030
-      );
7031
-  }
7032
-  
7410
+      if ($got) {
7411
+          my $take = ($got < $len) ? $got : $len;
7412
+          $buf  = substr($self->{rbuf}, 0, $take, '');
7413
+          $len -= $take;
7414
+      }
7033 7415
   
7034
-  sub _encode_latin1 {
7035
-      join('',
7036
-          map {
7037
-              $_ <= 255 ?
7038
-                  chr($_) :
7039
-              $_ <= 65535 ?
7040
-                  sprintf('\u%04x', $_) : sprintf('\u%x\u%x', _encode_surrogates($_));
7041
-          } unpack('U*', $_[0])
7042
-      );
7416
+      while ($len > 0) {
7417
+          $self->can_read
7418
+            or die(q/Timed out while waiting for socket to become ready for reading/ . "\n");
7419
+          my $r = sysread($self->{fh}, $buf, $len, length $buf);
7420
+          if (defined $r) {
7421
+              last unless $r;
7422
+              $len -= $r;
7423
+          }
7424
+          elsif ($! != EINTR) {
7425
+              if ($self->{fh}->can('errstr')){
7426
+                  my $err = $self->{fh}->errstr();
7427
+                  die (qq/Could not read from SSL socket: '$err'\n /);
7428
+              }
7429
+              else {
7430
+                  die(qq/Could not read from socket: '$!'\n/);
7431
+              }
7432
+          }
7433
+      }
7434
+      if ($len && !$allow_partial) {
7435
+          die(qq/Unexpected end of stream\n/);
7436
+      }
7437
+      return $buf;
7043 7438
   }
7044 7439
   
7440
+  sub readline {
7441
+      @_ == 1 || die(q/Usage: $handle->readline()/ . "\n");
7442
+      my ($self) = @_;
7045 7443
   
7046
-  sub _encode_surrogates { # from perlunicode
7047
-      my $uni = $_[0] - 0x10000;
7048
-      return ($uni / 0x400 + 0xD800, $uni % 0x400 + 0xDC00);
7444
+      while () {
7445
+          if ($self->{rbuf} =~ s/\A ([^\x0D\x0A]* \x0D?\x0A)//x) {
7446
+              return $1;
7447
+          }
7448
+          if (length $self->{rbuf} >= $self->{max_line_size}) {
7449
+              die(qq/Line size exceeds the maximum allowed size of $self->{max_line_size}\n/);
7450
+          }
7451
+          $self->can_read
7452
+            or die(qq/Timed out while waiting for socket to become ready for reading\n/);
7453
+          my $r = sysread($self->{fh}, $self->{rbuf}, BUFSIZE, length $self->{rbuf});
7454
+          if (defined $r) {
7455
+              last unless $r;
7456
+          }
7457
+          elsif ($! != EINTR) {
7458
+              if ($self->{fh}->can('errstr')){
7459
+                  my $err = $self->{fh}->errstr();
7460
+                  die (qq/Could not read from SSL socket: '$err'\n /);
7461
+              }
7462
+              else {
7463
+                  die(qq/Could not read from socket: '$!'\n/);
7464
+              }
7465
+          }
7466
+      }
7467
+      die(qq/Unexpected end of stream while looking for line\n/);
7049 7468
   }
7050 7469
   
7470
+  sub read_header_lines {
7471
+      @_ == 1 || @_ == 2 || die(q/Usage: $handle->read_header_lines([headers])/ . "\n");
7472
+      my ($self, $headers) = @_;
7473
+      $headers ||= {};
7474
+      my $lines   = 0;
7475
+      my $val;
7476
+  
7477
+      while () {
7478
+           my $line = $self->readline;
7051 7479
   
7052
-  sub _is_bignum {
7053
-      $_[0]->isa('Math::BigInt') or $_[0]->isa('Math::BigFloat');
7480
+           if (++$lines >= $self->{max_header_lines}) {
7481
+               die(qq/Header lines exceeds maximum number allowed of $self->{max_header_lines}\n/);
7482
+           }
7483
+           elsif ($line =~ /\A ([^\x00-\x1F\x7F:]+) : [\x09\x20]* ([^\x0D\x0A]*)/x) {
7484
+               my ($field_name) = lc $1;
7485
+               if (exists $headers->{$field_name}) {
7486
+                   for ($headers->{$field_name}) {
7487
+                       $_ = [$_] unless ref $_ eq "ARRAY";
7488
+                       push @$_, $2;
7489
+                       $val = \$_->[-1];
7490
+                   }
7491
+               }
7492
+               else {
7493
+                   $val = \($headers->{$field_name} = $2);
7494
+               }
7495
+           }
7496
+           elsif ($line =~ /\A [\x09\x20]+ ([^\x0D\x0A]*)/x) {
7497
+               $val
7498
+                 or die(qq/Unexpected header continuation line\n/);
7499
+               next unless length $1;
7500
+               $$val .= ' ' if length $$val;
7501
+               $$val .= $1;
7502
+           }
7503
+           elsif ($line =~ /\A \x0D?\x0A \z/x) {
7504
+              last;
7505
+           }
7506
+           else {
7507
+              die(q/Malformed header line: / . $Printable->($line) . "\n");
7508
+           }
7509
+      }
7510
+      return $headers;
7054 7511
   }
7055 7512
   
7513
+  sub write_request {
7514
+      @_ == 2 || die(q/Usage: $handle->write_request(request)/ . "\n");
7515
+      my($self, $request) = @_;
7516
+      $self->write_request_header(@{$request}{qw/method uri headers/});
7517
+      $self->write_body($request) if $request->{cb};
7518
+      return;
7519
+  }
7056 7520
   
7521
+  my %HeaderCase = (
7522
+      'content-md5'      => 'Content-MD5',
7523
+      'etag'             => 'ETag',
7524
+      'te'               => 'TE',
7525
+      'www-authenticate' => 'WWW-Authenticate',
7526
+      'x-xss-protection' => 'X-XSS-Protection',
7527
+  );
7057 7528
   
7058
-  #
7059
-  # JSON => Perl
7060
-  #
7061
-  
7062
-  my $max_intsize;
7529
+  sub write_header_lines {
7530
+      (@_ == 2 && ref $_[1] eq 'HASH') || die(q/Usage: $handle->write_header_lines(headers)/ . "\n");
7531
+      my($self, $headers) = @_;
7063 7532
   
7064
-  BEGIN {
7065
-      my $checkint = 1111;
7066
-      for my $d (5..64) {
7067
-          $checkint .= 1;
7068
-          my $int   = eval qq| $checkint |;
7069
-          if ($int =~ /[eE]/) {
7070
-              $max_intsize = $d - 1;
7071
-              last;
7533
+      my $buf = '';
7534
+      while (my ($k, $v) = each %$headers) {
7535
+          my $field_name = lc $k;
7536
+          if (exists $HeaderCase{$field_name}) {
7537
+              $field_name = $HeaderCase{$field_name};
7538
+          }
7539
+          else {
7540
+              $field_name =~ /\A $Token+ \z/xo
7541
+                or die(q/Invalid HTTP header field name: / . $Printable->($field_name) . "\n");
7542
+              $field_name =~ s/\b(\w)/\u$1/g;
7543
+              $HeaderCase{lc $field_name} = $field_name;
7544
+          }
7545
+          for (ref $v eq 'ARRAY' ? @$v : $v) {
7546
+              /[^\x0D\x0A]/
7547
+                or die(qq/Invalid HTTP header field value ($field_name): / . $Printable->($_). "\n");
7548
+              $buf .= "$field_name: $_\x0D\x0A";
7072 7549
           }
7073 7550
       }
7551
+      $buf .= "\x0D\x0A";
7552
+      return $self->write($buf);
7074 7553
   }
7075 7554
   
7076
-  { # PARSE 
7077
-  
7078
-      my %escapes = ( #  by Jeremy Muhlich <jmuhlich [at] bitflood.org>
7079
-          b    => "\x8",
7080
-          t    => "\x9",
7081
-          n    => "\xA",
7082
-          f    => "\xC",
7083
-          r    => "\xD",
7084
-          '\\' => '\\',
7085
-          '"'  => '"',
7086
-          '/'  => '/',
7087
-      );
7555
+  sub read_body {
7556
+      @_ == 3 || die(q/Usage: $handle->read_body(callback, response)/ . "\n");
7557
+      my ($self, $cb, $response) = @_;
7558
+      my $te = $response->{headers}{'transfer-encoding'} || '';
7559
+      if ( grep { /chunked/i } ( ref $te eq 'ARRAY' ? @$te : $te ) ) {
7560
+          $self->read_chunked_body($cb, $response);
7561
+      }
7562
+      else {
7563
+          $self->read_content_body($cb, $response);
7564
+      }
7565
+      return;
7566
+  }
7088 7567
   
7089
-      my $text; # json data
7090
-      my $at;   # offset
7091
-      my $ch;   # 1chracter
7092
-      my $len;  # text length (changed according to UTF8 or NON UTF8)
7093
-      # INTERNAL
7094
-      my $depth;          # nest counter
7095
-      my $encoding;       # json text encoding
7096
-      my $is_valid_utf8;  # temp variable
7097
-      my $utf8_len;       # utf8 byte length
7098
-      # FLAGS
7099
-      my $utf8;           # must be utf8
7100
-      my $max_depth;      # max nest nubmer of objects and arrays
7101
-      my $max_size;
7102
-      my $relaxed;
7103
-      my $cb_object;
7104
-      my $cb_sk_object;
7568
+  sub write_body {
7569
+      @_ == 2 || die(q/Usage: $handle->write_body(request)/ . "\n");
7570
+      my ($self, $request) = @_;
7571
+      if ($request->{headers}{'content-length'}) {
7572
+          return $self->write_content_body($request);
7573
+      }
7574
+      else {
7575
+          return $self->write_chunked_body($request);
7576
+      }
7577
+  }
7105 7578
   
7106
-      my $F_HOOK;
7579
+  sub read_content_body {
7580
+      @_ == 3 || @_ == 4 || die(q/Usage: $handle->read_content_body(callback, response, [read_length])/ . "\n");
7581
+      my ($self, $cb, $response, $content_length) = @_;
7582
+      $content_length ||= $response->{headers}{'content-length'};
7107 7583
   
7108
-      my $allow_bigint;   # using Math::BigInt
7109
-      my $singlequote;    # loosely quoting
7110
-      my $loose;          # 
7111
-      my $allow_barekey;  # bareKey
7584
+      if ( $content_length ) {
7585
+          my $len = $content_length;
7586
+          while ($len > 0) {
7587
+              my $read = ($len > BUFSIZE) ? BUFSIZE : $len;
7588
+              $cb->($self->read($read, 0), $response);
7589
+              $len -= $read;
7590
+          }
7591
+      }
7592
+      else {
7593
+          my $chunk;
7594
+          $cb->($chunk, $response) while length( $chunk = $self->read(BUFSIZE, 1) );
7595
+      }
7112 7596
   
7113
-      # $opt flag
7114
-      # 0x00000001 .... decode_prefix
7115
-      # 0x10000000 .... incr_parse
7597
+      return;
7598
+  }
7116 7599
   
7117
-      sub PP_decode_json {
7118
-          my ($self, $opt); # $opt is an effective flag during this decode_json.
7600
+  sub write_content_body {
7601
+      @_ == 2 || die(q/Usage: $handle->write_content_body(request)/ . "\n");
7602
+      my ($self, $request) = @_;
7119 7603
   
7120
-          ($self, $text, $opt) = @_;
7604
+      my ($len, $content_length) = (0, $request->{headers}{'content-length'});
7605
+      while () {
7606
+          my $data = $request->{cb}->();
7121 7607
   
7122
-          ($at, $ch, $depth) = (0, '', 0);
7608
+          defined $data && length $data
7609
+            or last;
7123 7610
   
7124
-          if ( !defined $text or ref $text ) {
7125
-              decode_error("malformed JSON string, neither array, object, number, string or atom");
7611
+          if ( $] ge '5.008' ) {
7612
+              utf8::downgrade($data, 1)
7613
+                  or die(qq/Wide character in write_content()\n/);
7126 7614
           }
7127 7615
   
7128
-          my $idx = $self->{PROPS};
7616
+          $len += $self->write($data);
7617
+      }
7129 7618
   
7130
-          ($utf8, $relaxed, $loose, $allow_bigint, $allow_barekey, $singlequote)
7131
-              = @{$idx}[P_UTF8, P_RELAXED, P_LOOSE .. P_ALLOW_SINGLEQUOTE];
7619
+      $len == $content_length
7620
+        or die(qq/Content-Length missmatch (got: $len expected: $content_length)\n/);
7132 7621
   
7133
-          if ( $utf8 ) {
7134
-              utf8::downgrade( $text, 1 ) or Carp::croak("Wide character in subroutine entry");
7135
-          }
7136
-          else {
7137
-              utf8::upgrade( $text );
7138
-          }
7622
+      return $len;
7623
+  }
7139 7624
   
7140
-          $len = length $text;
7625
+  sub read_chunked_body {
7626
+      @_ == 3 || die(q/Usage: $handle->read_chunked_body(callback, $response)/ . "\n");
7627
+      my ($self, $cb, $response) = @_;
7141 7628
   
7142
-          ($max_depth, $max_size, $cb_object, $cb_sk_object, $F_HOOK)
7143
-               = @{$self}{qw/max_depth  max_size cb_object cb_sk_object F_HOOK/};
7629
+      while () {
7630
+          my $head = $self->readline;
7144 7631
   
7145
-          if ($max_size > 1) {
7146
-              use bytes;
7147
-              my $bytes = length $text;
7148
-              decode_error(
7149
-                  sprintf("attempted decode of JSON text of %s bytes size, but max_size is set to %s"
7150
-                      , $bytes, $max_size), 1
7151
-              ) if ($bytes > $max_size);
7152
-          }
7632
+          $head =~ /\A ([A-Fa-f0-9]+)/x
7633
+            or die(q/Malformed chunk head: / . $Printable->($head) . "\n");
7153 7634
   
7154
-          # Currently no effect
7155
-          # should use regexp
7156
-          my @octets = unpack('C4', $text);
7157
-          $encoding =   ( $octets[0] and  $octets[1]) ? 'UTF-8'
7158
-                      : (!$octets[0] and  $octets[1]) ? 'UTF-16BE'
7159
-                      : (!$octets[0] and !$octets[1]) ? 'UTF-32BE'
7160
-                      : ( $octets[2]                ) ? 'UTF-16LE'
7161
-                      : (!$octets[2]                ) ? 'UTF-32LE'
7162
-                      : 'unknown';
7635
+          my $len = hex($1)
7636
+            or last;
7163 7637
   
7164
-          white(); # remove head white space
7638
+          $self->read_content_body($cb, $response, $len);
7165 7639
   
7166
-          my $valid_start = defined $ch; # Is there a first character for JSON structure?
7640
+          $self->read(2) eq "\x0D\x0A"
7641
+            or die(qq/Malformed chunk: missing CRLF after chunk data\n/);
7642
+      }
7643
+      $self->read_header_lines($response->{headers});
7644
+      return;
7645
+  }
7167 7646
   
7168
-          my $result = value();
7647
+  sub write_chunked_body {
7648
+      @_ == 2 || die(q/Usage: $handle->write_chunked_body(request)/ . "\n");
7649
+      my ($self, $request) = @_;
7169 7650
   
7170
-          return undef if ( !$result && ( $opt & 0x10000000 ) ); # for incr_parse
7651
+      my $len = 0;
7652
+      while () {
7653
+          my $data = $request->{cb}->();
7171 7654
   
7172
-          decode_error("malformed JSON string, neither array, object, number, string or atom") unless $valid_start;
7655
+          defined $data && length $data
7656
+            or last;
7173 7657
   
7174
-          if ( !$idx->[ P_ALLOW_NONREF ] and !ref $result ) {
7175
-                  decode_error(
7176
-                  'JSON text must be an object or array (but found number, string, true, false or null,'
7177
-                         . ' use allow_nonref to allow this)', 1);
7658
+          if ( $] ge '5.008' ) {
7659
+              utf8::downgrade($data, 1)
7660
+                  or die(qq/Wide character in write_chunked_body()\n/);
7178 7661
           }
7179 7662
   
7180
-          Carp::croak('something wrong.') if $len < $at; # we won't arrive here.
7663
+          $len += length $data;
7181 7664
   
7182
-          my $consumed = defined $ch ? $at - 1 : $at; # consumed JSON text length
7665
+          my $chunk  = sprintf '%X', length $data;
7666
+             $chunk .= "\x0D\x0A";
7667
+             $chunk .= $data;
7668
+             $chunk .= "\x0D\x0A";
7183 7669
   
7184
-          white(); # remove tail white space
7670
+          $self->write($chunk);
7671
+      }
7672
+      $self->write("0\x0D\x0A");
7673
+      $self->write_header_lines($request->{trailer_cb}->())
7674
+          if ref $request->{trailer_cb} eq 'CODE';
7675
+      return $len;
7676
+  }
7185 7677
   
7186
-          if ( $ch ) {
7187
-              return ( $result, $consumed ) if ($opt & 0x00000001); # all right if decode_prefix
7188
-              decode_error("garbage after JSON object");
7189
-          }
7678
+  sub read_response_header {
7679
+      @_ == 1 || die(q/Usage: $handle->read_response_header()/ . "\n");
7680
+      my ($self) = @_;
7190 7681
   
7191
-          ( $opt & 0x00000001 ) ? ( $result, $consumed ) : $result;
7192
-      }
7682
+      my $line = $self->readline;
7193 7683
   
7684
+      $line =~ /\A (HTTP\/(0*\d+\.0*\d+)) [\x09\x20]+ ([0-9]{3}) [\x09\x20]+ ([^\x0D\x0A]*) \x0D?\x0A/x
7685
+        or die(q/Malformed Status-Line: / . $Printable->($line). "\n");
7194 7686
   
7195
-      sub next_chr {
7196
-          return $ch = undef if($at >= $len);
7197
-          $ch = substr($text, $at++, 1);
7198
-      }
7687
+      my ($protocol, $version, $status, $reason) = ($1, $2, $3, $4);
7199 7688
   
7689
+      die (qq/Unsupported HTTP protocol: $protocol\n/)
7690
+          unless $version =~ /0*1\.0*[01]/;
7200 7691
   
7201
-      sub value {
7202
-          white();
7203
-          return          if(!defined $ch);
7204
-          return object() if($ch eq '{');
7205
-          return array()  if($ch eq '[');
7206
-          return string() if($ch eq '"' or ($singlequote and $ch eq "'"));
7207
-          return number() if($ch =~ /[0-9]/ or $ch eq '-');
7208
-          return word();
7209
-      }
7692
+      return {
7693
+          status   => $status,
7694
+          reason   => $reason,
7695
+          headers  => $self->read_header_lines,
7696
+          protocol => $protocol,
7697
+      };
7698
+  }
7210 7699
   
7211
-      sub string {
7212
-          my ($i, $s, $t, $u);
7213
-          my $utf16;
7214
-          my $is_utf8;
7700
+  sub write_request_header {
7701
+      @_ == 4 || die(q/Usage: $handle->write_request_header(method, request_uri, headers)/ . "\n");
7702
+      my ($self, $method, $request_uri, $headers) = @_;
7215 7703
   
7216
-          ($is_valid_utf8, $utf8_len) = ('', 0);
7704
+      return $self->write("$method $request_uri HTTP/1.1\x0D\x0A")
7705
+           + $self->write_header_lines($headers);
7706
+  }
7217 7707
   
7218
-          $s = ''; # basically UTF8 flag on
7708
+  sub _do_timeout {
7709
+      my ($self, $type, $timeout) = @_;
7710
+      $timeout = $self->{timeout}
7711
+          unless defined $timeout && $timeout >= 0;
7219 7712
   
7220
-          if($ch eq '"' or ($singlequote and $ch eq "'")){
7221
-              my $boundChar = $ch;
7713
+      my $fd = fileno $self->{fh};
7714
+      defined $fd && $fd >= 0
7715
+        or die(qq/select(2): 'Bad file descriptor'\n/);
7222 7716
   
7223
-              OUTER: while( defined(next_chr()) ){
7717
+      my $initial = time;
7718
+      my $pending = $timeout;
7719
+      my $nfound;
7224 7720
   
7225
-                  if($ch eq $boundChar){
7226
-                      next_chr();
7721
+      vec(my $fdset = '', $fd, 1) = 1;
7227 7722
   
7228
-                      if ($utf16) {
7229
-                          decode_error("missing low surrogate character in surrogate pair");
7230
-                      }
7723
+      while () {
7724
+          $nfound = ($type eq 'read')
7725
+              ? select($fdset, undef, undef, $pending)
7726
+              : select(undef, $fdset, undef, $pending) ;
7727
+          if ($nfound == -1) {
7728
+              $! == EINTR
7729
+                or die(qq/select(2): '$!'\n/);
7730
+              redo if !$timeout || ($pending = $timeout - (time - $initial)) > 0;
7731
+              $nfound = 0;
7732
+          }
7733
+          last;
7734
+      }
7735
+      $! = 0;
7736
+      return $nfound;
7737
+  }
7231 7738
   
7232
-                      utf8::decode($s) if($is_utf8);
7739
+  sub can_read {
7740
+      @_ == 1 || @_ == 2 || die(q/Usage: $handle->can_read([timeout])/ . "\n");
7741
+      my $self = shift;
7742
+      return $self->_do_timeout('read', @_)
7743
+  }
7233 7744
   
7234
-                      return $s;
7235
-                  }
7236
-                  elsif($ch eq '\\'){
7237
-                      next_chr();
7238
-                      if(exists $escapes{$ch}){
7239
-                          $s .= $escapes{$ch};
7240
-                      }
7241
-                      elsif($ch eq 'u'){ # UNICODE handling
7242
-                          my $u = '';
7745
+  sub can_write {
7746
+      @_ == 1 || @_ == 2 || die(q/Usage: $handle->can_write([timeout])/ . "\n");
7747
+      my $self = shift;
7748
+      return $self->_do_timeout('write', @_)
7749
+  }
7243 7750
   
7244
-                          for(1..4){
7245
-                              $ch = next_chr();
7246
-                              last OUTER if($ch !~ /[0-9a-fA-F]/);
7247
-                              $u .= $ch;
7248
-                          }
7751
+  # Try to find a CA bundle to validate the SSL cert,
7752
+  # prefer Mozilla::CA or fallback to a system file
7753
+  sub _find_CA_file {
7754
+      my $self = shift();
7249 7755
   
7250
-                          # U+D800 - U+DBFF
7251
-                          if ($u =~ /^[dD][89abAB][0-9a-fA-F]{2}/) { # UTF-16 high surrogate?
7252
-                              $utf16 = $u;
7253
-                          }
7254
-                          # U+DC00 - U+DFFF
7255
-                          elsif ($u =~ /^[dD][c-fC-F][0-9a-fA-F]{2}/) { # UTF-16 low surrogate?
7256
-                              unless (defined $utf16) {
7257
-                                  decode_error("missing high surrogate character in surrogate pair");
7258
-                              }
7259
-                              $is_utf8 = 1;
7260
-                              $s .= JSON_PP_decode_surrogates($utf16, $u) || next;
7261
-                              $utf16 = undef;
7262
-                          }
7263
-                          else {
7264
-                              if (defined $utf16) {
7265
-                                  decode_error("surrogate pair expected");
7266
-                              }
7756
+      return $self->{SSL_options}->{SSL_ca_file}
7757
+          if $self->{SSL_options}->{SSL_ca_file} and -e $self->{SSL_options}->{SSL_ca_file};
7267 7758
   
7268
-                              if ( ( my $hex = hex( $u ) ) > 127 ) {
7269
-                                  $is_utf8 = 1;
7270
-                                  $s .= JSON_PP_decode_unicode($u) || next;
7271
-                              }
7272
-                              else {
7273
-                                  $s .= chr $hex;
7274
-                              }
7275
-                          }
7759
+      return Mozilla::CA::SSL_ca_file()
7760
+          if eval { require Mozilla::CA };
7276 7761
   
7277
-                      }
7278
-                      else{
7279
-                          unless ($loose) {
7280
-                              $at -= 2;
7281
-                              decode_error('illegal backslash escape sequence in string');
7282
-                          }
7283
-                          $s .= $ch;
7284
-                      }
7285
-                  }
7286
-                  else{
7762
+      foreach my $ca_bundle (qw{
7763
+          /etc/ssl/certs/ca-certificates.crt
7764
+          /etc/pki/tls/certs/ca-bundle.crt
7765
+          /etc/ssl/ca-bundle.pem
7766
+          }
7767
+      ) {
7768
+          return $ca_bundle if -e $ca_bundle;
7769
+      }
7287 7770
   
7288
-                      if ( ord $ch  > 127 ) {
7289
-                          if ( $utf8 ) {
7290
-                              unless( $ch = is_valid_utf8($ch) ) {
7291
-                                  $at -= 1;
7292
-                                  decode_error("malformed UTF-8 character in JSON string");
7293
-                              }
7294
-                              else {
7295
-                                  $at += $utf8_len - 1;
7296
-                              }
7297
-                          }
7298
-                          else {
7299
-                              utf8::encode( $ch );
7300
-                          }
7771
+      die qq/Couldn't find a CA bundle with which to verify the SSL certificate.\n/
7772
+        . qq/Try installing Mozilla::CA from CPAN\n/;
7773
+  }
7301 7774
   
7302
-                          $is_utf8 = 1;
7303
-                      }
7775
+  sub _ssl_args {
7776
+      my ($self, $host) = @_;
7304 7777
   
7305
-                      if (!$loose) {
7306
-                          if ($ch =~ /[\x00-\x1f\x22\x5c]/)  { # '/' ok
7307
-                              $at--;
7308
-                              decode_error('invalid character encountered while parsing JSON string');
7309
-                          }
7310
-                      }
7778
+      my %ssl_args = (
7779
+          SSL_hostname        => $host,  # SNI
7780
+      );
7311 7781
   
7312
-                      $s .= $ch;
7313
-                  }
7314
-              }
7315
-          }
7782
+      if ($self->{verify_SSL}) {
7783
+          $ssl_args{SSL_verifycn_scheme}  = 'http'; # enable CN validation
7784
+          $ssl_args{SSL_verifycn_name}    = $host;  # set validation hostname
7785
+          $ssl_args{SSL_verify_mode}      = 0x01;   # enable cert validation
7786
+          $ssl_args{SSL_ca_file}          = $self->_find_CA_file;
7787
+      }
7788
+      else {
7789
+          $ssl_args{SSL_verifycn_scheme}  = 'none'; # disable CN validation
7790
+          $ssl_args{SSL_verify_mode}      = 0x00;   # disable cert validation
7791
+      }
7316 7792
   
7317
-          decode_error("unexpected end of string while parsing JSON string");
7793
+      # user options override settings from verify_SSL
7794
+      for my $k ( keys %{$self->{SSL_options}} ) {
7795
+          $ssl_args{$k} = $self->{SSL_options}{$k} if $k =~ m/^SSL_/;
7318 7796
       }
7319 7797
   
7798
+      return \%ssl_args;
7799
+  }
7320 7800
   
7321
-      sub white {
7322
-          while( defined $ch  ){
7323
-              if($ch le ' '){
7324
-                  next_chr();
7325
-              }
7326
-              elsif($ch eq '/'){
7327
-                  next_chr();
7328
-                  if(defined $ch and $ch eq '/'){
7329
-                      1 while(defined(next_chr()) and $ch ne "\n" and $ch ne "\r");
7330
-                  }
7331
-                  elsif(defined $ch and $ch eq '*'){
7332
-                      next_chr();
7333
-                      while(1){
7334
-                          if(defined $ch){
7335
-                              if($ch eq '*'){
7336
-                                  if(defined(next_chr()) and $ch eq '/'){
7337
-                                      next_chr();
7338
-                                      last;
7339
-                                  }
7340
-                              }
7341
-                              else{
7342
-                                  next_chr();
7343
-                              }
7344
-                          }
7345
-                          else{
7346
-                              decode_error("Unterminated comment");
7347
-                          }
7348
-                      }
7349
-                      next;
7350
-                  }
7351
-                  else{
7352
-                      $at--;
7353
-                      decode_error("malformed JSON string, neither array, object, number, string or atom");
7354
-                  }
7355
-              }
7356
-              else{
7357
-                  if ($relaxed and $ch eq '#') { # correctly?
7358
-                      pos($text) = $at;
7359
-                      $text =~ /\G([^\n]*(?:\r\n|\r|\n|$))/g;
7360
-                      $at = pos($text);
7361
-                      next_chr;
7362
-                      next;
7363
-                  }
7801
+  1;
7364 7802
   
7365
-                  last;
7366
-              }
7367
-          }
7368
-      }
7803
+  __END__
7369 7804
   
7805
+HTTP_TINY
7806
+
7807
+$fatpacked{"JSON/PP.pm"} = <<'JSON_PP';
7808
+  package JSON::PP;
7370 7809
   
7371
-      sub array {
7372
-          my $a  = $_[0] || []; # you can use this code to use another array ref object.
7810
+  # JSON-2.0
7373 7811
   
7374
-          decode_error('json text or perl structure exceeds maximum nesting level (max_depth set too low?)')
7375
-                                                      if (++$depth > $max_depth);
7812
+  use 5.005;
7813
+  use strict;
7814
+  use base qw(Exporter);
7815
+  use overload ();
7376 7816
   
7377
-          next_chr();
7378
-          white();
7817
+  use Carp ();
7818
+  use B ();
7819
+  #use Devel::Peek;
7379 7820
   
7380
-          if(defined $ch and $ch eq ']'){
7381
-              --$depth;
7382
-              next_chr();
7383
-              return $a;
7384
-          }
7385
-          else {
7386
-              while(defined($ch)){
7387
-                  push @$a, value();
7821
+  $JSON::PP::VERSION = '2.27200';
7388 7822
   
7389
-                  white();
7823
+  @JSON::PP::EXPORT = qw(encode_json decode_json from_json to_json);
7390 7824
   
7391
-                  if (!defined $ch) {
7392
-                      last;
7393
-                  }
7825
+  # instead of hash-access, i tried index-access for speed.
7826
+  # but this method is not faster than what i expected. so it will be changed.
7394 7827
   
7395
-                  if($ch eq ']'){
7396
-                      --$depth;
7397
-                      next_chr();
7398
-                      return $a;
7399
-                  }
7828
+  use constant P_ASCII                => 0;
7829
+  use constant P_LATIN1               => 1;
7830
+  use constant P_UTF8                 => 2;
7831
+  use constant P_INDENT               => 3;
7832
+  use constant P_CANONICAL            => 4;
7833
+  use constant P_SPACE_BEFORE         => 5;
7834
+  use constant P_SPACE_AFTER          => 6;
7835
+  use constant P_ALLOW_NONREF         => 7;
7836
+  use constant P_SHRINK               => 8;
7837
+  use constant P_ALLOW_BLESSED        => 9;
7838
+  use constant P_CONVERT_BLESSED      => 10;
7839
+  use constant P_RELAXED              => 11;
7400 7840
   
7401
-                  if($ch ne ','){
7402
-                      last;
7403
-                  }
7841
+  use constant P_LOOSE                => 12;
7842
+  use constant P_ALLOW_BIGNUM         => 13;
7843
+  use constant P_ALLOW_BAREKEY        => 14;
7844
+  use constant P_ALLOW_SINGLEQUOTE    => 15;
7845
+  use constant P_ESCAPE_SLASH         => 16;
7846
+  use constant P_AS_NONBLESSED        => 17;
7404 7847
   
7405
-                  next_chr();
7406
-                  white();
7848
+  use constant P_ALLOW_UNKNOWN        => 18;
7407 7849
   
7408
-                  if ($relaxed and $ch eq ']') {
7409
-                      --$depth;
7410
-                      next_chr();
7411
-                      return $a;
7412
-                  }
7850
+  use constant OLD_PERL => $] < 5.008 ? 1 : 0;
7413 7851
   
7414
-              }
7415
-          }
7852
+  BEGIN {
7853
+      my @xs_compati_bit_properties = qw(
7854
+              latin1 ascii utf8 indent canonical space_before space_after allow_nonref shrink
7855
+              allow_blessed convert_blessed relaxed allow_unknown
7856
+      );
7857
+      my @pp_bit_properties = qw(
7858
+              allow_singlequote allow_bignum loose
7859
+              allow_barekey escape_slash as_nonblessed
7860
+      );
7416 7861
   
7417
-          decode_error(", or ] expected while parsing array");
7862
+      # Perl version check, Unicode handling is enable?
7863
+      # Helper module sets @JSON::PP::_properties.
7864
+      if ($] < 5.008 ) {
7865
+          my $helper = $] >= 5.006 ? 'JSON::PP::Compat5006' : 'JSON::PP::Compat5005';
7866
+          eval qq| require $helper |;
7867
+          if ($@) { Carp::croak $@; }
7418 7868
       }
7419 7869
   
7870
+      for my $name (@xs_compati_bit_properties, @pp_bit_properties) {
7871
+          my $flag_name = 'P_' . uc($name);
7420 7872
   
7421
-      sub object {
7422
-          my $o = $_[0] || {}; # you can use this code to use another hash ref object.
7423
-          my $k;
7873
+          eval qq/
7874
+              sub $name {
7875
+                  my \$enable = defined \$_[1] ? \$_[1] : 1;
7424 7876
   
7425
-          decode_error('json text or perl structure exceeds maximum nesting level (max_depth set too low?)')
7426
-                                                  if (++$depth > $max_depth);
7427
-          next_chr();
7428
-          white();
7877
+                  if (\$enable) {
7878
+                      \$_[0]->{PROPS}->[$flag_name] = 1;
7879
+                  }
7880
+                  else {
7881
+                      \$_[0]->{PROPS}->[$flag_name] = 0;
7882
+                  }
7429 7883
   
7430
-          if(defined $ch and $ch eq '}'){
7431
-              --$depth;
7432
-              next_chr();
7433
-              if ($F_HOOK) {
7434
-                  return _json_object_hook($o);
7884
+                  \$_[0];
7435 7885
               }
7436
-              return $o;
7437
-          }
7438
-          else {
7439
-              while (defined $ch) {
7440
-                  $k = ($allow_barekey and $ch ne '"' and $ch ne "'") ? bareKey() : string();
7441
-                  white();
7442 7886
   
7443
-                  if(!defined $ch or $ch ne ':'){
7444
-                      $at--;
7445
-                      decode_error("':' expected");
7446
-                  }
7887
+              sub get_$name {
7888
+                  \$_[0]->{PROPS}->[$flag_name] ? 1 : '';
7889
+              }
7890
+          /;
7891
+      }
7447 7892
   
7448
-                  next_chr();
7449
-                  $o->{$k} = value();
7450
-                  white();
7893
+  }
7451 7894
   
7452
-                  last if (!defined $ch);
7453 7895
   
7454
-                  if($ch eq '}'){
7455
-                      --$depth;
7456
-                      next_chr();
7457
-                      if ($F_HOOK) {
7458
-                          return _json_object_hook($o);
7459
-                      }
7460
-                      return $o;
7461
-                  }
7462 7896
   
7463
-                  if($ch ne ','){
7464
-                      last;
7465
-                  }
7897
+  # Functions
7466 7898
   
7467
-                  next_chr();
7468
-                  white();
7899
+  my %encode_allow_method
7900
+       = map {($_ => 1)} qw/utf8 pretty allow_nonref latin1 self_encode escape_slash
7901
+                            allow_blessed convert_blessed indent indent_length allow_bignum
7902
+                            as_nonblessed
7903
+                          /;
7904
+  my %decode_allow_method
7905
+       = map {($_ => 1)} qw/utf8 allow_nonref loose allow_singlequote allow_bignum
7906
+                            allow_barekey max_size relaxed/;
7469 7907
   
7470
-                  if ($relaxed and $ch eq '}') {
7471
-                      --$depth;
7472
-                      next_chr();
7473
-                      if ($F_HOOK) {
7474
-                          return _json_object_hook($o);
7475
-                      }
7476
-                      return $o;
7477
-                  }
7478 7908
   
7479
-              }
7909
+  my $JSON; # cache
7480 7910
   
7481
-          }
7911
+  sub encode_json ($) { # encode
7912
+      ($JSON ||= __PACKAGE__->new->utf8)->encode(@_);
7913
+  }
7482 7914
   
7483
-          $at--;
7484
-          decode_error(", or } expected while parsing object/hash");
7485
-      }
7486 7915
   
7916
+  sub decode_json { # decode
7917
+      ($JSON ||= __PACKAGE__->new->utf8)->decode(@_);
7918
+  }
7487 7919
   
7488
-      sub bareKey { # doesn't strictly follow Standard ECMA-262 3rd Edition
7489
-          my $key;
7490
-          while($ch =~ /[^\x00-\x23\x25-\x2F\x3A-\x40\x5B-\x5E\x60\x7B-\x7F]/){
7491
-              $key .= $ch;
7492
-              next_chr();
7493
-          }
7494
-          return $key;
7495
-      }
7920
+  # Obsoleted
7496 7921
   
7922
+  sub to_json($) {
7923
+     Carp::croak ("JSON::PP::to_json has been renamed to encode_json.");
7924
+  }
7497 7925
   
7498
-      sub word {
7499
-          my $word =  substr($text,$at-1,4);
7500 7926
   
7501
-          if($word eq 'true'){
7502
-              $at += 3;
7503
-              next_chr;
7504
-              return $JSON::PP::true;
7505
-          }
7506
-          elsif($word eq 'null'){
7507
-              $at += 3;
7508
-              next_chr;
7509
-              return undef;
7510
-          }
7511
-          elsif($word eq 'fals'){
7512
-              $at += 3;
7513
-              if(substr($text,$at,1) eq 'e'){
7514
-                  $at++;
7515
-                  next_chr;
7516
-                  return $JSON::PP::false;
7517
-              }
7518
-          }
7927
+  sub from_json($) {
7928
+     Carp::croak ("JSON::PP::from_json has been renamed to decode_json.");
7929
+  }
7519 7930
   
7520
-          $at--; # for decode_error report
7521 7931
   
7522
-          decode_error("'null' expected")  if ($word =~ /^n/);
7523
-          decode_error("'true' expected")  if ($word =~ /^t/);
7524
-          decode_error("'false' expected") if ($word =~ /^f/);
7525
-          decode_error("malformed JSON string, neither array, object, number, string or atom");
7526
-      }
7932
+  # Methods
7527 7933
   
7934
+  sub new {
7935
+      my $class = shift;
7936
+      my $self  = {
7937
+          max_depth   => 512,
7938
+          max_size    => 0,
7939
+          indent      => 0,
7940
+          FLAGS       => 0,
7941
+          fallback      => sub { encode_error('Invalid value. JSON can only reference.') },
7942
+          indent_length => 3,
7943
+      };
7528 7944
   
7529
-      sub number {
7530
-          my $n    = '';
7531
-          my $v;
7945
+      bless $self, $class;
7946
+  }
7532 7947
   
7533
-          # According to RFC4627, hex or oct digts are invalid.
7534
-          if($ch eq '0'){
7535
-              my $peek = substr($text,$at,1);
7536
-              my $hex  = $peek =~ /[xX]/; # 0 or 1
7537 7948
   
7538
-              if($hex){
7539
-                  decode_error("malformed number (leading zero must not be followed by another digit)");
7540
-                  ($n) = ( substr($text, $at+1) =~ /^([0-9a-fA-F]+)/);
7541
-              }
7542
-              else{ # oct
7543
-                  ($n) = ( substr($text, $at) =~ /^([0-7]+)/);
7544
-                  if (defined $n and length $n > 1) {
7545
-                      decode_error("malformed number (leading zero must not be followed by another digit)");
7546
-                  }
7547
-              }
7548
-  
7549
-              if(defined $n and length($n)){
7550
-                  if (!$hex and length($n) == 1) {
7551
-                     decode_error("malformed number (leading zero must not be followed by another digit)");
7552
-                  }
7553
-                  $at += length($n) + $hex;
7554
-                  next_chr;
7555
-                  return $hex ? hex($n) : oct($n);
7556
-              }
7557
-          }
7558
-  
7559
-          if($ch eq '-'){
7560
-              $n = '-';
7561
-              next_chr;
7562
-              if (!defined $ch or $ch !~ /\d/) {
7563
-                  decode_error("malformed number (no digits after initial minus)");
7564
-              }
7565
-          }
7566
-  
7567
-          while(defined $ch and $ch =~ /\d/){
7568
-              $n .= $ch;
7569
-              next_chr;
7570
-          }
7949
+  sub encode {
7950
+      return $_[0]->PP_encode_json($_[1]);
7951
+  }
7571 7952
   
7572
-          if(defined $ch and $ch eq '.'){
7573
-              $n .= '.';
7574 7953
   
7575
-              next_chr;
7576
-              if (!defined $ch or $ch !~ /\d/) {
7577
-                  decode_error("malformed number (no digits after decimal point)");
7578
-              }
7579
-              else {
7580
-                  $n .= $ch;
7581
-              }
7954
+  sub decode {
7955
+      return $_[0]->PP_decode_json($_[1], 0x00000000);
7956
+  }
7582 7957
   
7583
-              while(defined(next_chr) and $ch =~ /\d/){
7584
-                  $n .= $ch;
7585
-              }
7586
-          }
7587 7958
   
7588
-          if(defined $ch and ($ch eq 'e' or $ch eq 'E')){
7589
-              $n .= $ch;
7590
-              next_chr;
7959
+  sub decode_prefix {
7960
+      return $_[0]->PP_decode_json($_[1], 0x00000001);
7961
+  }
7591 7962
   
7592
-              if(defined($ch) and ($ch eq '+' or $ch eq '-')){
7593
-                  $n .= $ch;
7594
-                  next_chr;
7595
-                  if (!defined $ch or $ch =~ /\D/) {
7596
-                      decode_error("malformed number (no digits after exp sign)");
7597
-                  }
7598
-                  $n .= $ch;
7599
-              }
7600
-              elsif(defined($ch) and $ch =~ /\d/){
7601
-                  $n .= $ch;
7602
-              }
7603
-              else {
7604
-                  decode_error("malformed number (no digits after exp sign)");
7605
-              }
7606 7963
   
7607
-              while(defined(next_chr) and $ch =~ /\d/){
7608
-                  $n .= $ch;
7609
-              }
7964
+  # accessor
7610 7965
   
7611
-          }
7612 7966
   
7613
-          $v .= $n;
7967
+  # pretty printing
7614 7968
   
7615
-          if ($v !~ /[.eE]/ and length $v > $max_intsize) {
7616
-              if ($allow_bigint) { # from Adam Sussman
7617
-                  require Math::BigInt;
7618
-                  return Math::BigInt->new($v);
7619
-              }
7620
-              else {
7621
-                  return "$v";
7622
-              }
7623
-          }
7624
-          elsif ($allow_bigint) {
7625
-              require Math::BigFloat;
7626
-              return Math::BigFloat->new($v);
7627
-          }
7969
+  sub pretty {
7970
+      my ($self, $v) = @_;
7971
+      my $enable = defined $v ? $v : 1;
7628 7972
   
7629
-          return 0+$v;
7973
+      if ($enable) { # indent_length(3) for JSON::XS compatibility
7974
+          $self->indent(1)->indent_length(3)->space_before(1)->space_after(1);
7975
+      }
7976
+      else {
7977
+          $self->indent(0)->space_before(0)->space_after(0);
7630 7978
       }
7631 7979
   
7980
+      $self;
7981
+  }
7632 7982
   
7633
-      sub is_valid_utf8 {
7983
+  # etc
7634 7984
   
7635
-          $utf8_len = $_[0] =~ /[\x00-\x7F]/  ? 1
7636
-                    : $_[0] =~ /[\xC2-\xDF]/  ? 2
7637
-                    : $_[0] =~ /[\xE0-\xEF]/  ? 3
7638
-                    : $_[0] =~ /[\xF0-\xF4]/  ? 4
7639
-                    : 0
7640
-                    ;
7985
+  sub max_depth {
7986
+      my $max  = defined $_[1] ? $_[1] : 0x80000000;
7987
+      $_[0]->{max_depth} = $max;
7988
+      $_[0];
7989
+  }
7641 7990
   
7642
-          return unless $utf8_len;
7643 7991
   
7644
-          my $is_valid_utf8 = substr($text, $at - 1, $utf8_len);
7992
+  sub get_max_depth { $_[0]->{max_depth}; }
7645 7993
   
7646
-          return ( $is_valid_utf8 =~ /^(?:
7647
-               [\x00-\x7F]
7648
-              |[\xC2-\xDF][\x80-\xBF]
7649
-              |[\xE0][\xA0-\xBF][\x80-\xBF]
7650
-              |[\xE1-\xEC][\x80-\xBF][\x80-\xBF]
7651
-              |[\xED][\x80-\x9F][\x80-\xBF]
7652
-              |[\xEE-\xEF][\x80-\xBF][\x80-\xBF]
7653
-              |[\xF0][\x90-\xBF][\x80-\xBF][\x80-\xBF]
7654
-              |[\xF1-\xF3][\x80-\xBF][\x80-\xBF][\x80-\xBF]
7655
-              |[\xF4][\x80-\x8F][\x80-\xBF][\x80-\xBF]
7656
-          )$/x )  ? $is_valid_utf8 : '';
7657
-      }
7658 7994
   
7995
+  sub max_size {
7996
+      my $max  = defined $_[1] ? $_[1] : 0;
7997
+      $_[0]->{max_size} = $max;
7998
+      $_[0];
7999
+  }
7659 8000
   
7660
-      sub decode_error {
7661
-          my $error  = shift;
7662
-          my $no_rep = shift;
7663
-          my $str    = defined $text ? substr($text, $at) : '';
7664
-          my $mess   = '';
7665
-          my $type   = $] >= 5.008           ? 'U*'
7666
-                     : $] <  5.006           ? 'C*'
7667
-                     : utf8::is_utf8( $str ) ? 'U*' # 5.6
7668
-                     : 'C*'
7669
-                     ;
7670 8001
   
7671
-          for my $c ( unpack( $type, $str ) ) { # emulate pv_uni_display() ?
7672
-              $mess .=  $c == 0x07 ? '\a'
7673
-                      : $c == 0x09 ? '\t'
7674
-                      : $c == 0x0a ? '\n'
7675
-                      : $c == 0x0d ? '\r'
7676
-                      : $c == 0x0c ? '\f'
7677
-                      : $c <  0x20 ? sprintf('\x{%x}', $c)
7678
-                      : $c == 0x5c ? '\\\\'
7679
-                      : $c <  0x80 ? chr($c)
7680
-                      : sprintf('\x{%x}', $c)
7681
-                      ;
7682
-              if ( length $mess >= 20 ) {
7683
-                  $mess .= '...';
7684
-                  last;
7685
-              }
7686
-          }
8002
+  sub get_max_size { $_[0]->{max_size}; }
7687 8003
   
7688
-          unless ( length $mess ) {
7689
-              $mess = '(end of string)';
7690
-          }
7691 8004
   
7692
-          Carp::croak (
7693
-              $no_rep ? "$error" : "$error, at character offset $at (before \"$mess\")"
7694
-          );
8005
+  sub filter_json_object {
8006
+      $_[0]->{cb_object} = defined $_[1] ? $_[1] : 0;
8007
+      $_[0]->{F_HOOK} = ($_[0]->{cb_object} or $_[0]->{cb_sk_object}) ? 1 : 0;
8008
+      $_[0];
8009
+  }
7695 8010
   
8011
+  sub filter_json_single_key_object {
8012
+      if (@_ > 1) {
8013
+          $_[0]->{cb_sk_object}->{$_[1]} = $_[2];
7696 8014
       }
8015
+      $_[0]->{F_HOOK} = ($_[0]->{cb_object} or $_[0]->{cb_sk_object}) ? 1 : 0;
8016
+      $_[0];
8017
+  }
7697 8018
   
7698
-  
7699
-      sub _json_object_hook {
7700
-          my $o    = $_[0];
7701
-          my @ks = keys %{$o};
7702
-  
7703
-          if ( $cb_sk_object and @ks == 1 and exists $cb_sk_object->{ $ks[0] } and ref $cb_sk_object->{ $ks[0] } ) {
7704
-              my @val = $cb_sk_object->{ $ks[0] }->( $o->{$ks[0]} );
7705
-              if (@val == 1) {
7706
-                  return $val[0];
7707
-              }
7708
-          }
7709
-  
7710
-          my @val = $cb_object->($o) if ($cb_object);
7711
-          if (@val == 0 or @val > 1) {
7712
-              return $o;
7713
-          }
7714
-          else {
7715
-              return $val[0];
7716
-          }
8019
+  sub indent_length {
8020
+      if (!defined $_[1] or $_[1] > 15 or $_[1] < 0) {
8021
+          Carp::carp "The acceptable range of indent_length() is 0 to 15.";
7717 8022
       }
7718
-  
7719
-  
7720
-      sub PP_decode_box {
7721
-          {
7722
-              text    => $text,
7723
-              at      => $at,
7724
-              ch      => $ch,
7725
-              len     => $len,
7726
-              depth   => $depth,
7727
-              encoding      => $encoding,
7728
-              is_valid_utf8 => $is_valid_utf8,
7729
-          };
8023
+      else {
8024
+          $_[0]->{indent_length} = $_[1];
7730 8025
       }
8026
+      $_[0];
8027
+  }
7731 8028
   
7732
-  } # PARSE
7733
-  
7734
-  
7735
-  sub _decode_surrogates { # from perlunicode
7736
-      my $uni = 0x10000 + (hex($_[0]) - 0xD800) * 0x400 + (hex($_[1]) - 0xDC00);
7737
-      my $un  = pack('U*', $uni);
7738
-      utf8::encode( $un );
7739
-      return $un;
8029
+  sub get_indent_length {
8030
+      $_[0]->{indent_length};
7740 8031
   }
7741 8032
   
8033
+  sub sort_by {
8034
+      $_[0]->{sort_by} = defined $_[1] ? $_[1] : 1;
8035
+      $_[0];
8036
+  }
7742 8037
   
7743
-  sub _decode_unicode {
7744
-      my $un = pack('U', hex shift);
7745
-      utf8::encode( $un );
7746
-      return $un;
8038
+  sub allow_bigint {
8039
+      Carp::carp("allow_bigint() is obsoleted. use allow_bignum() insted.");
7747 8040
   }
7748 8041
   
7749
-  #
7750
-  # Setup for various Perl versions (the code from JSON::PP58)
7751
-  #
8042
+  ###############################
7752 8043
   
7753
-  BEGIN {
8044
+  ###
8045
+  ### Perl => JSON
8046
+  ###
7754 8047
   
7755
-      unless ( defined &utf8::is_utf8 ) {
7756
-         require Encode;
7757
-         *utf8::is_utf8 = *Encode::is_utf8;
7758
-      }
7759 8048
   
7760
-      if ( $] >= 5.008 ) {
7761
-          *JSON::PP::JSON_PP_encode_ascii      = \&_encode_ascii;
7762
-          *JSON::PP::JSON_PP_encode_latin1     = \&_encode_latin1;
7763
-          *JSON::PP::JSON_PP_decode_surrogates = \&_decode_surrogates;
7764
-          *JSON::PP::JSON_PP_decode_unicode    = \&_decode_unicode;
7765
-      }
8049
+  { # Convert
7766 8050
   
7767
-      if ($] >= 5.008 and $] < 5.008003) { # join() in 5.8.0 - 5.8.2 is broken.
7768
-          package JSON::PP;
7769
-          require subs;
7770
-          subs->import('join');
7771
-          eval q|
7772
-              sub join {
7773
-                  return '' if (@_ < 2);
7774
-                  my $j   = shift;
7775
-                  my $str = shift;
7776
-                  for (@_) { $str .= $j . $_; }
7777
-                  return $str;
7778
-              }
7779
-          |;
7780
-      }
7781
-  
7782
-  
7783
-      sub JSON::PP::incr_parse {
7784
-          local $Carp::CarpLevel = 1;
7785
-          ( $_[0]->{_incr_parser} ||= JSON::PP::IncrParser->new )->incr_parse( @_ );
7786
-      }
8051
+      my $max_depth;
8052
+      my $indent;
8053
+      my $ascii;
8054
+      my $latin1;
8055
+      my $utf8;
8056
+      my $space_before;
8057
+      my $space_after;
8058
+      my $canonical;
8059
+      my $allow_blessed;
8060
+      my $convert_blessed;
7787 8061
   
8062
+      my $indent_length;
8063
+      my $escape_slash;
8064
+      my $bignum;
8065
+      my $as_nonblessed;
7788 8066
   
7789
-      sub JSON::PP::incr_skip {
7790
-          ( $_[0]->{_incr_parser} ||= JSON::PP::IncrParser->new )->incr_skip;
7791
-      }
8067
+      my $depth;
8068
+      my $indent_count;
8069
+      my $keysort;
7792 8070
   
7793 8071
   
7794
-      sub JSON::PP::incr_reset {
7795
-          ( $_[0]->{_incr_parser} ||= JSON::PP::IncrParser->new )->incr_reset;
7796
-      }
8072
+      sub PP_encode_json {
8073
+          my $self = shift;
8074
+          my $obj  = shift;
7797 8075
   
7798
-      eval q{
7799
-          sub JSON::PP::incr_text : lvalue {
7800
-              $_[0]->{_incr_parser} ||= JSON::PP::IncrParser->new;
8076
+          $indent_count = 0;
8077
+          $depth        = 0;
7801 8078
   
7802
-              if ( $_[0]->{_incr_parser}->{incr_parsing} ) {
7803
-                  Carp::croak("incr_text can not be called when the incremental parser already started parsing");
7804
-              }
7805
-              $_[0]->{_incr_parser}->{incr_text};
7806
-          }
7807
-      } if ( $] >= 5.006 );
8079
+          my $idx = $self->{PROPS};
7808 8080
   
7809
-  } # Setup for various Perl versions (the code from JSON::PP58)
8081
+          ($ascii, $latin1, $utf8, $indent, $canonical, $space_before, $space_after, $allow_blessed,
8082
+              $convert_blessed, $escape_slash, $bignum, $as_nonblessed)
8083
+           = @{$idx}[P_ASCII .. P_SPACE_AFTER, P_ALLOW_BLESSED, P_CONVERT_BLESSED,
8084
+                      P_ESCAPE_SLASH, P_ALLOW_BIGNUM, P_AS_NONBLESSED];
7810 8085
   
8086
+          ($max_depth, $indent_length) = @{$self}{qw/max_depth indent_length/};
7811 8087
   
7812
-  ###############################
7813
-  # Utilities
7814
-  #
8088
+          $keysort = $canonical ? sub { $a cmp $b } : undef;
7815 8089
   
7816
-  BEGIN {
7817
-      eval 'require Scalar::Util';
7818
-      unless($@){
7819
-          *JSON::PP::blessed = \&Scalar::Util::blessed;
7820
-          *JSON::PP::reftype = \&Scalar::Util::reftype;
7821
-          *JSON::PP::refaddr = \&Scalar::Util::refaddr;
7822
-      }
7823
-      else{ # This code is from Sclar::Util.
7824
-          # warn $@;
7825
-          eval 'sub UNIVERSAL::a_sub_not_likely_to_be_here { ref($_[0]) }';
7826
-          *JSON::PP::blessed = sub {
7827
-              local($@, $SIG{__DIE__}, $SIG{__WARN__});
7828
-              ref($_[0]) ? eval { $_[0]->a_sub_not_likely_to_be_here } : undef;
7829
-          };
7830
-          my %tmap = qw(
7831
-              B::NULL   SCALAR
7832
-              B::HV     HASH
7833
-              B::AV     ARRAY
7834
-              B::CV     CODE
7835
-              B::IO     IO
7836
-              B::GV     GLOB
7837
-              B::REGEXP REGEXP
7838
-          );
7839
-          *JSON::PP::reftype = sub {
7840
-              my $r = shift;
8090
+          if ($self->{sort_by}) {
8091
+              $keysort = ref($self->{sort_by}) eq 'CODE' ? $self->{sort_by}
8092
+                       : $self->{sort_by} =~ /\D+/       ? $self->{sort_by}
8093
+                       : sub { $a cmp $b };
8094
+          }
7841 8095
   
7842
-              return undef unless length(ref($r));
8096
+          encode_error("hash- or arrayref expected (not a simple scalar, use allow_nonref to allow this)")
8097
+               if(!ref $obj and !$idx->[ P_ALLOW_NONREF ]);
7843 8098
   
7844
-              my $t = ref(B::svref_2object($r));
8099
+          my $str  = $self->object_to_json($obj);
7845 8100
   
7846
-              return
7847
-                  exists $tmap{$t} ? $tmap{$t}
7848
-                : length(ref($$r)) ? 'REF'
7849
-                :                    'SCALAR';
7850
-          };
7851
-          *JSON::PP::refaddr = sub {
7852
-            return undef unless length(ref($_[0]));
8101
+          $str .= "\n" if ( $indent ); # JSON::XS 2.26 compatible
7853 8102
   
7854
-            my $addr;
7855
-            if(defined(my $pkg = blessed($_[0]))) {
7856
-              $addr .= bless $_[0], 'Scalar::Util::Fake';
7857
-              bless $_[0], $pkg;
7858
-            }
7859
-            else {
7860
-              $addr .= $_[0]
7861
-            }
8103
+          unless ($ascii or $latin1 or $utf8) {
8104
+              utf8::upgrade($str);
8105
+          }
7862 8106
   
7863
-            $addr =~ /0x(\w+)/;
7864
-            local $^W;
7865
-            #no warnings 'portable';
7866
-            hex($1);
8107
+          if ($idx->[ P_SHRINK ]) {
8108
+              utf8::downgrade($str, 1);
7867 8109
           }
8110
+  
8111
+          return $str;
7868 8112
       }
7869
-  }
7870 8113
   
7871 8114
   
7872
-  # shamely copied and modified from JSON::XS code.
8115
+      sub object_to_json {
8116
+          my ($self, $obj) = @_;
8117
+          my $type = ref($obj);
7873 8118
   
7874
-  $JSON::PP::true  = do { bless \(my $dummy = 1), "JSON::PP::Boolean" };
7875
-  $JSON::PP::false = do { bless \(my $dummy = 0), "JSON::PP::Boolean" };
8119
+          if($type eq 'HASH'){
8120
+              return $self->hash_to_json($obj);
8121
+          }
8122
+          elsif($type eq 'ARRAY'){
8123
+              return $self->array_to_json($obj);
8124
+          }
8125
+          elsif ($type) { # blessed object?
8126
+              if (blessed($obj)) {
7876 8127
   
7877
-  sub is_bool { defined $_[0] and UNIVERSAL::isa($_[0], "JSON::PP::Boolean"); }
8128
+                  return $self->value_to_json($obj) if ( $obj->isa('JSON::PP::Boolean') );
7878 8129
   
7879
-  sub true  { $JSON::PP::true  }
7880
-  sub false { $JSON::PP::false }
7881
-  sub null  { undef; }
8130
+                  if ( $convert_blessed and $obj->can('TO_JSON') ) {
8131
+                      my $result = $obj->TO_JSON();
8132
+                      if ( defined $result and ref( $result ) ) {
8133
+                          if ( refaddr( $obj ) eq refaddr( $result ) ) {
8134
+                              encode_error( sprintf(
8135
+                                  "%s::TO_JSON method returned same object as was passed instead of a new one",
8136
+                                  ref $obj
8137
+                              ) );
8138
+                          }
8139
+                      }
7882 8140
   
7883
-  ###############################
8141
+                      return $self->object_to_json( $result );
8142
+                  }
7884 8143
   
7885
-  package JSON::PP::Boolean;
8144
+                  return "$obj" if ( $bignum and _is_bignum($obj) );
8145
+                  return $self->blessed_to_json($obj) if ($allow_blessed and $as_nonblessed); # will be removed.
7886 8146
   
7887
-  use overload (
7888
-     "0+"     => sub { ${$_[0]} },
7889
-     "++"     => sub { $_[0] = ${$_[0]} + 1 },
7890
-     "--"     => sub { $_[0] = ${$_[0]} - 1 },
7891
-     fallback => 1,
7892
-  );
8147
+                  encode_error( sprintf("encountered object '%s', but neither allow_blessed "
8148
+                      . "nor convert_blessed settings are enabled", $obj)
8149
+                  ) unless ($allow_blessed);
7893 8150
   
8151
+                  return 'null';
8152
+              }
8153
+              else {
8154
+                  return $self->value_to_json($obj);
8155
+              }
8156
+          }
8157
+          else{
8158
+              return $self->value_to_json($obj);
8159
+          }
8160
+      }
7894 8161
   
7895
-  ###############################
7896 8162
   
7897
-  package JSON::PP::IncrParser;
8163
+      sub hash_to_json {
8164
+          my ($self, $obj) = @_;
8165
+          my @res;
7898 8166
   
7899
-  use strict;
8167
+          encode_error("json text or perl structure exceeds maximum nesting level (max_depth set too low?)")
8168
+                                           if (++$depth > $max_depth);
7900 8169
   
7901
-  use constant INCR_M_WS   => 0; # initial whitespace skipping
7902
-  use constant INCR_M_STR  => 1; # inside string
7903
-  use constant INCR_M_BS   => 2; # inside backslash
7904
-  use constant INCR_M_JSON => 3; # outside anything, count nesting
7905
-  use constant INCR_M_C0   => 4;
7906
-  use constant INCR_M_C1   => 5;
8170
+          my ($pre, $post) = $indent ? $self->_up_indent() : ('', '');
8171
+          my $del = ($space_before ? ' ' : '') . ':' . ($space_after ? ' ' : '');
7907 8172
   
7908
-  $JSON::PP::IncrParser::VERSION = '1.01';
8173
+          for my $k ( _sort( $obj ) ) {
8174
+              if ( OLD_PERL ) { utf8::decode($k) } # key for Perl 5.6 / be optimized
8175
+              push @res, string_to_json( $self, $k )
8176
+                            .  $del
8177
+                            . ( $self->object_to_json( $obj->{$k} ) || $self->value_to_json( $obj->{$k} ) );
8178
+          }
7909 8179
   
7910
-  my $unpack_format = $] < 5.006 ? 'C*' : 'U*';
8180
+          --$depth;
8181
+          $self->_down_indent() if ($indent);
7911 8182
   
7912
-  sub new {
7913
-      my ( $class ) = @_;
8183
+          return   '{' . ( @res ? $pre : '' ) . ( @res ? join( ",$pre", @res ) . $post : '' )  . '}';
8184
+      }
7914 8185
   
7915
-      bless {
7916
-          incr_nest    => 0,
7917
-          incr_text    => undef,
7918
-          incr_parsing => 0,
7919
-          incr_p       => 0,
7920
-      }, $class;
7921
-  }
7922 8186
   
8187
+      sub array_to_json {
8188
+          my ($self, $obj) = @_;
8189
+          my @res;
7923 8190
   
7924
-  sub incr_parse {
7925
-      my ( $self, $coder, $text ) = @_;
8191
+          encode_error("json text or perl structure exceeds maximum nesting level (max_depth set too low?)")
8192
+                                           if (++$depth > $max_depth);
7926 8193
   
7927
-      $self->{incr_text} = '' unless ( defined $self->{incr_text} );
8194
+          my ($pre, $post) = $indent ? $self->_up_indent() : ('', '');
7928 8195
   
7929
-      if ( defined $text ) {
7930
-          if ( utf8::is_utf8( $text ) and !utf8::is_utf8( $self->{incr_text} ) ) {
7931
-              utf8::upgrade( $self->{incr_text} ) ;
7932
-              utf8::decode( $self->{incr_text} ) ;
8196
+          for my $v (@$obj){
8197
+              push @res, $self->object_to_json($v) || $self->value_to_json($v);
7933 8198
           }
7934
-          $self->{incr_text} .= $text;
7935
-      }
7936 8199
   
8200
+          --$depth;
8201
+          $self->_down_indent() if ($indent);
7937 8202
   
7938
-      my $max_size = $coder->get_max_size;
8203
+          return '[' . ( @res ? $pre : '' ) . ( @res ? join( ",$pre", @res ) . $post : '' ) . ']';
8204
+      }
7939 8205
   
7940
-      if ( defined wantarray ) {
7941 8206
   
7942
-          $self->{incr_mode} = INCR_M_WS unless defined $self->{incr_mode};
8207
+      sub value_to_json {
8208
+          my ($self, $value) = @_;
7943 8209
   
7944
-          if ( wantarray ) {
7945
-              my @ret;
8210
+          return 'null' if(!defined $value);
7946 8211
   
7947
-              $self->{incr_parsing} = 1;
8212
+          my $b_obj = B::svref_2object(\$value);  # for round trip problem
8213
+          my $flags = $b_obj->FLAGS;
7948 8214
   
7949
-              do {
7950
-                  push @ret, $self->_incr_parse( $coder, $self->{incr_text} );
8215
+          return $value # as is 
8216
+              if $flags & ( B::SVp_IOK | B::SVp_NOK ) and !( $flags & B::SVp_POK ); # SvTYPE is IV or NV?
7951 8217
   
7952
-                  unless ( !$self->{incr_nest} and $self->{incr_mode} == INCR_M_JSON ) {
7953
-                      $self->{incr_mode} = INCR_M_WS if $self->{incr_mode} != INCR_M_STR;
7954
-                  }
8218
+          my $type = ref($value);
7955 8219
   
7956
-              } until ( length $self->{incr_text} >= $self->{incr_p} );
8220
+          if(!$type){
8221
+              return string_to_json($self, $value);
8222
+          }
8223
+          elsif( blessed($value) and  $value->isa('JSON::PP::Boolean') ){
8224
+              return $$value == 1 ? 'true' : 'false';
8225
+          }
8226
+          elsif ($type) {
8227
+              if ((overload::StrVal($value) =~ /=(\w+)/)[0]) {
8228
+                  return $self->value_to_json("$value");
8229
+              }
7957 8230
   
7958
-              $self->{incr_parsing} = 0;
8231
+              if ($type eq 'SCALAR' and defined $$value) {
8232
+                  return   $$value eq '1' ? 'true'
8233
+                         : $$value eq '0' ? 'false'
8234
+                         : $self->{PROPS}->[ P_ALLOW_UNKNOWN ] ? 'null'
8235
+                         : encode_error("cannot encode reference to scalar");
8236
+              }
8237
+  
8238
+               if ( $self->{PROPS}->[ P_ALLOW_UNKNOWN ] ) {
8239
+                   return 'null';
8240
+               }
8241
+               else {
8242
+                   if ( $type eq 'SCALAR' or $type eq 'REF' ) {
8243
+                      encode_error("cannot encode reference to scalar");
8244
+                   }
8245
+                   else {
8246
+                      encode_error("encountered $value, but JSON can only represent references to arrays or hashes");
8247
+                   }
8248
+               }
7959 8249
   
7960
-              return @ret;
7961 8250
           }
7962
-          else { # in scalar context
7963
-              $self->{incr_parsing} = 1;
7964
-              my $obj = $self->_incr_parse( $coder, $self->{incr_text} );
7965
-              $self->{incr_parsing} = 0 if defined $obj; # pointed by Martin J. Evans
7966
-              return $obj ? $obj : undef; # $obj is an empty string, parsing was completed.
8251
+          else {
8252
+              return $self->{fallback}->($value)
8253
+                   if ($self->{fallback} and ref($self->{fallback}) eq 'CODE');
8254
+              return 'null';
7967 8255
           }
7968 8256
   
7969 8257
       }
7970 8258
   
7971
-  }
7972 8259
   
8260
+      my %esc = (
8261
+          "\n" => '\n',
8262
+          "\r" => '\r',
8263
+          "\t" => '\t',
8264
+          "\f" => '\f',
8265
+          "\b" => '\b',
8266
+          "\"" => '\"',
8267
+          "\\" => '\\\\',
8268
+          "\'" => '\\\'',
8269
+      );
7973 8270
   
7974
-  sub _incr_parse {
7975
-      my ( $self, $coder, $text, $skip ) = @_;
7976
-      my $p = $self->{incr_p};
7977
-      my $restore = $p;
7978 8271
   
7979
-      my @obj;
7980
-      my $len = length $text;
8272
+      sub string_to_json {
8273
+          my ($self, $arg) = @_;
7981 8274
   
7982
-      if ( $self->{incr_mode} == INCR_M_WS ) {
7983
-          while ( $len > $p ) {
7984
-              my $s = substr( $text, $p, 1 );
7985
-              $p++ and next if ( 0x20 >= unpack($unpack_format, $s) );
7986
-              $self->{incr_mode} = INCR_M_JSON;
7987
-              last;
7988
-         }
7989
-      }
8275
+          $arg =~ s/([\x22\x5c\n\r\t\f\b])/$esc{$1}/g;
8276
+          $arg =~ s/\//\\\//g if ($escape_slash);
8277
+          $arg =~ s/([\x00-\x08\x0b\x0e-\x1f])/'\\u00' . unpack('H2', $1)/eg;
7990 8278
   
7991
-      while ( $len > $p ) {
7992
-          my $s = substr( $text, $p++, 1 );
8279
+          if ($ascii) {
8280
+              $arg = JSON_PP_encode_ascii($arg);
8281
+          }
7993 8282
   
7994
-          if ( $s eq '"' ) {
7995
-              if (substr( $text, $p - 2, 1 ) eq '\\' ) {
7996
-                  next;
7997
-              }
8283
+          if ($latin1) {
8284
+              $arg = JSON_PP_encode_latin1($arg);
8285
+          }
7998 8286
   
7999
-              if ( $self->{incr_mode} != INCR_M_STR  ) {
8000
-                  $self->{incr_mode} = INCR_M_STR;
8001
-              }
8002
-              else {
8003
-                  $self->{incr_mode} = INCR_M_JSON;
8004
-                  unless ( $self->{incr_nest} ) {
8005
-                      last;
8006
-                  }
8007
-              }
8287
+          if ($utf8) {
8288
+              utf8::encode($arg);
8008 8289
           }
8009 8290
   
8010
-          if ( $self->{incr_mode} == INCR_M_JSON ) {
8291
+          return '"' . $arg . '"';
8292
+      }
8011 8293
   
8012
-              if ( $s eq '[' or $s eq '{' ) {
8013
-                  if ( ++$self->{incr_nest} > $coder->get_max_depth ) {
8014
-                      Carp::croak('json text or perl structure exceeds maximum nesting level (max_depth set too low?)');
8015
-                  }
8016
-              }
8017
-              elsif ( $s eq ']' or $s eq '}' ) {
8018
-                  last if ( --$self->{incr_nest} <= 0 );
8019
-              }
8020
-              elsif ( $s eq '#' ) {
8021
-                  while ( $len > $p ) {
8022
-                      last if substr( $text, $p++, 1 ) eq "\n";
8023
-                  }
8024
-              }
8025 8294
   
8295
+      sub blessed_to_json {
8296
+          my $reftype = reftype($_[1]) || '';
8297
+          if ($reftype eq 'HASH') {
8298
+              return $_[0]->hash_to_json($_[1]);
8299
+          }
8300
+          elsif ($reftype eq 'ARRAY') {
8301
+              return $_[0]->array_to_json($_[1]);
8302
+          }
8303
+          else {
8304
+              return 'null';
8026 8305
           }
8306
+      }
8307
+  
8027 8308
   
8309
+      sub encode_error {
8310
+          my $error  = shift;
8311
+          Carp::croak "$error";
8028 8312
       }
8029 8313
   
8030
-      $self->{incr_p} = $p;
8031 8314
   
8032
-      return if ( $self->{incr_mode} == INCR_M_STR and not $self->{incr_nest} );
8033
-      return if ( $self->{incr_mode} == INCR_M_JSON and $self->{incr_nest} > 0 );
8315
+      sub _sort {
8316
+          defined $keysort ? (sort $keysort (keys %{$_[0]})) : keys %{$_[0]};
8317
+      }
8034 8318
   
8035
-      return '' unless ( length substr( $self->{incr_text}, 0, $p ) );
8036 8319
   
8037
-      local $Carp::CarpLevel = 2;
8320
+      sub _up_indent {
8321
+          my $self  = shift;
8322
+          my $space = ' ' x $indent_length;
8038 8323
   
8039
-      $self->{incr_p} = $restore;
8040
-      $self->{incr_c} = $p;
8324
+          my ($pre,$post) = ('','');
8041 8325
   
8042
-      my ( $obj, $tail ) = $coder->PP_decode_json( substr( $self->{incr_text}, 0, $p ), 0x10000001 );
8326
+          $post = "\n" . $space x $indent_count;
8043 8327
   
8044
-      $self->{incr_text} = substr( $self->{incr_text}, $p );
8045
-      $self->{incr_p} = 0;
8328
+          $indent_count++;
8046 8329
   
8047
-      return $obj or '';
8048
-  }
8330
+          $pre = "\n" . $space x $indent_count;
8049 8331
   
8332
+          return ($pre,$post);
8333
+      }
8050 8334
   
8051
-  sub incr_text {
8052
-      if ( $_[0]->{incr_parsing} ) {
8053
-          Carp::croak("incr_text can not be called when the incremental parser already started parsing");
8335
+  
8336
+      sub _down_indent { $indent_count--; }
8337
+  
8338
+  
8339
+      sub PP_encode_box {
8340
+          {
8341
+              depth        => $depth,
8342
+              indent_count => $indent_count,
8343
+          };
8054 8344
       }
8055
-      $_[0]->{incr_text};
8056
-  }
8057 8345
   
8346
+  } # Convert
8058 8347
   
8059
-  sub incr_skip {
8060
-      my $self  = shift;
8061
-      $self->{incr_text} = substr( $self->{incr_text}, $self->{incr_c} );
8062
-      $self->{incr_p} = 0;
8348
+  
8349
+  sub _encode_ascii {
8350
+      join('',
8351
+          map {
8352
+              $_ <= 127 ?
8353
+                  chr($_) :
8354
+              $_ <= 65535 ?
8355
+                  sprintf('\u%04x', $_) : sprintf('\u%x\u%x', _encode_surrogates($_));
8356
+          } unpack('U*', $_[0])
8357
+      );
8063 8358
   }
8064 8359
   
8065 8360
   
8066
-  sub incr_reset {
8067
-      my $self = shift;
8068
-      $self->{incr_text}    = undef;
8069
-      $self->{incr_p}       = 0;
8070
-      $self->{incr_mode}    = 0;
8071
-      $self->{incr_nest}    = 0;
8072
-      $self->{incr_parsing} = 0;
8361
+  sub _encode_latin1 {
8362
+      join('',
8363
+          map {
8364
+              $_ <= 255 ?
8365
+                  chr($_) :
8366
+              $_ <= 65535 ?
8367
+                  sprintf('\u%04x', $_) : sprintf('\u%x\u%x', _encode_surrogates($_));
8368
+          } unpack('U*', $_[0])
8369
+      );
8073 8370
   }
8074 8371
   
8075
-  ###############################
8076
-  
8077 8372
   
8078
-  1;
8079
-  __END__
8080
-  =pod
8373
+  sub _encode_surrogates { # from perlunicode
8374
+      my $uni = $_[0] - 0x10000;
8375
+      return ($uni / 0x400 + 0xD800, $uni % 0x400 + 0xDC00);
8376
+  }
8081 8377
   
8082
-JSON_PP
8083
-
8084
-$fatpacked{"JSON/PP/Boolean.pm"} = <<'JSON_PP_BOOLEAN';
8085
-  use JSON::PP ();
8086
-  use strict;
8087 8378
   
8088
-  1;
8379
+  sub _is_bignum {
8380
+      $_[0]->isa('Math::BigInt') or $_[0]->isa('Math::BigFloat');
8381
+  }
8089 8382
   
8090
-JSON_PP_BOOLEAN
8091
-
8092
-$fatpacked{"Module/Metadata.pm"} = <<'MODULE_METADATA';
8093
-  # -*- mode: cperl; tab-width: 8; indent-tabs-mode: nil; basic-offset: 2 -*-
8094
-  # vim:ts=8:sw=2:et:sta:sts=2
8095
-  package Module::Metadata;
8096 8383
   
8097
-  # Adapted from Perl-licensed code originally distributed with
8098
-  # Module-Build by Ken Williams
8099 8384
   
8100
-  # This module provides routines to gather information about
8101
-  # perl modules (assuming this may be expanded in the distant
8102
-  # parrot future to look at other types of modules).
8385
+  #
8386
+  # JSON => Perl
8387
+  #
8103 8388
   
8104
-  use strict;
8105
-  use vars qw($VERSION);
8106
-  $VERSION = '1.000007';
8107
-  $VERSION = eval $VERSION;
8389
+  my $max_intsize;
8108 8390
   
8109
-  use File::Spec;
8110
-  use IO::File;
8111
-  use version 0.87;
8112 8391
   BEGIN {
8113
-    if ($INC{'Log/Contextual.pm'}) {
8114
-      Log::Contextual->import('log_info');
8115
-    } else {
8116
-      *log_info = sub (&) { warn $_[0]->() };
8117
-    }
8392
+      my $checkint = 1111;
8393
+      for my $d (5..64) {
8394
+          $checkint .= 1;
8395
+          my $int   = eval qq| $checkint |;
8396
+          if ($int =~ /[eE]/) {
8397
+              $max_intsize = $d - 1;
8398
+              last;
8399
+          }
8400
+      }
8118 8401
   }
8119
-  use File::Find qw(find);
8120 8402
   
8121
-  my $V_NUM_REGEXP = qr{v?[0-9._]+};  # crudely, a v-string or decimal
8403
+  { # PARSE 
8122 8404
   
8123
-  my $PKG_REGEXP  = qr{   # match a package declaration
8124
-    ^[\s\{;]*             # intro chars on a line
8125
-    package               # the word 'package'
8126
-    \s+                   # whitespace
8127
-    ([\w:]+)              # a package name
8128
-    \s*                   # optional whitespace
8129
-    ($V_NUM_REGEXP)?        # optional version number
8130
-    \s*                   # optional whitesapce
8131
-    [;\{]                 # semicolon line terminator or block start (since 5.16)
8132
-  }x;
8405
+      my %escapes = ( #  by Jeremy Muhlich <jmuhlich [at] bitflood.org>
8406
+          b    => "\x8",
8407
+          t    => "\x9",
8408
+          n    => "\xA",
8409
+          f    => "\xC",
8410
+          r    => "\xD",
8411
+          '\\' => '\\',
8412
+          '"'  => '"',
8413
+          '/'  => '/',
8414
+      );
8133 8415
   
8134
-  my $VARNAME_REGEXP = qr{ # match fully-qualified VERSION name
8135
-    ([\$*])         # sigil - $ or *
8136
-    (
8137
-      (             # optional leading package name
8138
-        (?:::|\')?  # possibly starting like just :: (�  la $::VERSION)
8139
-        (?:\w+(?:::|\'))*  # Foo::Bar:: ...
8140
-      )?
8141
-      VERSION
8142
-    )\b
8143
-  }x;
8416
+      my $text; # json data
8417
+      my $at;   # offset
8418
+      my $ch;   # 1chracter
8419
+      my $len;  # text length (changed according to UTF8 or NON UTF8)
8420
+      # INTERNAL
8421
+      my $depth;          # nest counter
8422
+      my $encoding;       # json text encoding
8423
+      my $is_valid_utf8;  # temp variable
8424
+      my $utf8_len;       # utf8 byte length
8425
+      # FLAGS
8426
+      my $utf8;           # must be utf8
8427
+      my $max_depth;      # max nest nubmer of objects and arrays
8428
+      my $max_size;
8429
+      my $relaxed;
8430
+      my $cb_object;
8431
+      my $cb_sk_object;
8144 8432
   
8145
-  my $VERS_REGEXP = qr{ # match a VERSION definition
8146
-    (?:
8147
-      \(\s*$VARNAME_REGEXP\s*\) # with parens
8148
-    |
8149
-      $VARNAME_REGEXP           # without parens
8150
-    )
8151
-    \s*
8152
-    =[^=~]  # = but not ==, nor =~
8153
-  }x;
8433
+      my $F_HOOK;
8154 8434
   
8435
+      my $allow_bigint;   # using Math::BigInt
8436
+      my $singlequote;    # loosely quoting
8437
+      my $loose;          # 
8438
+      my $allow_barekey;  # bareKey
8155 8439
   
8156
-  sub new_from_file {
8157
-    my $class    = shift;
8158
-    my $filename = File::Spec->rel2abs( shift );
8440
+      # $opt flag
8441
+      # 0x00000001 .... decode_prefix
8442
+      # 0x10000000 .... incr_parse
8159 8443
   
8160
-    return undef unless defined( $filename ) && -f $filename;
8161
-    return $class->_init(undef, $filename, @_);
8162
-  }
8444
+      sub PP_decode_json {
8445
+          my ($self, $opt); # $opt is an effective flag during this decode_json.
8163 8446
   
8164
-  sub new_from_handle {
8165
-    my $class    = shift;
8166
-    my $handle   = shift;
8167
-    my $filename = shift;
8168
-    return undef unless defined($handle) && defined($filename);
8169
-    $filename = File::Spec->rel2abs( $filename );
8447
+          ($self, $text, $opt) = @_;
8170 8448
   
8171
-    return $class->_init(undef, $filename, @_, handle => $handle);
8449
+          ($at, $ch, $depth) = (0, '', 0);
8172 8450
   
8173
-  }
8451
+          if ( !defined $text or ref $text ) {
8452
+              decode_error("malformed JSON string, neither array, object, number, string or atom");
8453
+          }
8174 8454
   
8455
+          my $idx = $self->{PROPS};
8175 8456
   
8176
-  sub new_from_module {
8177
-    my $class   = shift;
8178
-    my $module  = shift;
8179
-    my %props   = @_;
8457
+          ($utf8, $relaxed, $loose, $allow_bigint, $allow_barekey, $singlequote)
8458
+              = @{$idx}[P_UTF8, P_RELAXED, P_LOOSE .. P_ALLOW_SINGLEQUOTE];
8180 8459
   
8181
-    $props{inc} ||= \@INC;
8182
-    my $filename = $class->find_module_by_name( $module, $props{inc} );
8183
-    return undef unless defined( $filename ) && -f $filename;
8184
-    return $class->_init($module, $filename, %props);
8185
-  }
8460
+          if ( $utf8 ) {
8461
+              utf8::downgrade( $text, 1 ) or Carp::croak("Wide character in subroutine entry");
8462
+          }
8463
+          else {
8464
+              utf8::upgrade( $text );
8465
+          }
8186 8466
   
8187
-  {
8188
-    
8189
-    my $compare_versions = sub {
8190
-      my ($v1, $op, $v2) = @_;
8191
-      $v1 = version->new($v1)
8192
-        unless UNIVERSAL::isa($v1,'version');
8193
-    
8194
-      my $eval_str = "\$v1 $op \$v2";
8195
-      my $result   = eval $eval_str;
8196
-      log_info { "error comparing versions: '$eval_str' $@" } if $@;
8197
-    
8198
-      return $result;
8199
-    };
8467
+          $len = length $text;
8200 8468
   
8201
-    my $normalize_version = sub {
8202
-      my ($version) = @_;
8203
-      if ( $version =~ /[=<>!,]/ ) { # logic, not just version
8204
-        # take as is without modification
8205
-      }
8206
-      elsif ( ref $version eq 'version' ) { # version objects
8207
-        $version = $version->is_qv ? $version->normal : $version->stringify;
8208
-      }
8209
-      elsif ( $version =~ /^[^v][^.]*\.[^.]+\./ ) { # no leading v, multiple dots
8210
-        # normalize string tuples without "v": "1.2.3" -> "v1.2.3"
8211
-        $version = "v$version";
8212
-      }
8213
-      else {
8214
-        # leave alone
8215
-      }
8216
-      return $version;
8217
-    };
8469
+          ($max_depth, $max_size, $cb_object, $cb_sk_object, $F_HOOK)
8470
+               = @{$self}{qw/max_depth  max_size cb_object cb_sk_object F_HOOK/};
8218 8471
   
8219
-    # separate out some of the conflict resolution logic
8472
+          if ($max_size > 1) {
8473
+              use bytes;
8474
+              my $bytes = length $text;
8475
+              decode_error(
8476
+                  sprintf("attempted decode of JSON text of %s bytes size, but max_size is set to %s"
8477
+                      , $bytes, $max_size), 1
8478
+              ) if ($bytes > $max_size);
8479
+          }
8220 8480
   
8221
-    my $resolve_module_versions = sub {
8222
-      my $packages = shift;
8223
-    
8224
-      my( $file, $version );
8225
-      my $err = '';
8226
-        foreach my $p ( @$packages ) {
8227
-          if ( defined( $p->{version} ) ) {
8228
-    	if ( defined( $version ) ) {
8229
-     	  if ( $compare_versions->( $version, '!=', $p->{version} ) ) {
8230
-    	    $err .= "  $p->{file} ($p->{version})\n";
8231
-    	  } else {
8232
-    	    # same version declared multiple times, ignore
8233
-    	  }
8234
-    	} else {
8235
-    	  $file    = $p->{file};
8236
-    	  $version = $p->{version};
8237
-    	}
8481
+          # Currently no effect
8482
+          # should use regexp
8483
+          my @octets = unpack('C4', $text);
8484
+          $encoding =   ( $octets[0] and  $octets[1]) ? 'UTF-8'
8485
+                      : (!$octets[0] and  $octets[1]) ? 'UTF-16BE'
8486
+                      : (!$octets[0] and !$octets[1]) ? 'UTF-32BE'
8487
+                      : ( $octets[2]                ) ? 'UTF-16LE'
8488
+                      : (!$octets[2]                ) ? 'UTF-32LE'
8489
+                      : 'unknown';
8490
+  
8491
+          white(); # remove head white space
8492
+  
8493
+          my $valid_start = defined $ch; # Is there a first character for JSON structure?
8494
+  
8495
+          my $result = value();
8496
+  
8497
+          return undef if ( !$result && ( $opt & 0x10000000 ) ); # for incr_parse
8498
+  
8499
+          decode_error("malformed JSON string, neither array, object, number, string or atom") unless $valid_start;
8500
+  
8501
+          if ( !$idx->[ P_ALLOW_NONREF ] and !ref $result ) {
8502
+                  decode_error(
8503
+                  'JSON text must be an object or array (but found number, string, true, false or null,'
8504
+                         . ' use allow_nonref to allow this)', 1);
8238 8505
           }
8239
-          $file ||= $p->{file} if defined( $p->{file} );
8240
-        }
8241
-    
8242
-      if ( $err ) {
8243
-        $err = "  $file ($version)\n" . $err;
8244
-      }
8245
-    
8246
-      my %result = (
8247
-        file    => $file,
8248
-        version => $version,
8249
-        err     => $err
8250
-      );
8251
-    
8252
-      return \%result;
8253
-    };
8254 8506
   
8255
-    sub package_versions_from_directory {
8256
-      my ( $class, $dir, $files ) = @_;
8507
+          Carp::croak('something wrong.') if $len < $at; # we won't arrive here.
8257 8508
   
8258
-      my @files;
8509
+          my $consumed = defined $ch ? $at - 1 : $at; # consumed JSON text length
8259 8510
   
8260
-      if ( $files ) {
8261
-        @files = @$files;
8262
-      } else {
8263
-        find( {
8264
-          wanted => sub {
8265
-            push @files, $_ if -f $_ && /\.pm$/;
8266
-          },
8267
-          no_chdir => 1,
8268
-        }, $dir );
8269
-      }
8511
+          white(); # remove tail white space
8270 8512
   
8271
-      # First, we enumerate all packages & versions,
8272
-      # separating into primary & alternative candidates
8273
-      my( %prime, %alt );
8274
-      foreach my $file (@files) {
8275
-        my $mapped_filename = File::Spec->abs2rel( $file, $dir );
8276
-        my @path = split( /\//, $mapped_filename );
8277
-        (my $prime_package = join( '::', @path )) =~ s/\.pm$//;
8278
-    
8279
-        my $pm_info = $class->new_from_file( $file );
8280
-    
8281
-        foreach my $package ( $pm_info->packages_inside ) {
8282
-          next if $package eq 'main';  # main can appear numerous times, ignore
8283
-          next if $package eq 'DB';    # special debugging package, ignore
8284
-          next if grep /^_/, split( /::/, $package ); # private package, ignore
8285
-    
8286
-          my $version = $pm_info->version( $package );
8287
-    
8288
-          if ( $package eq $prime_package ) {
8289
-            if ( exists( $prime{$package} ) ) {
8290
-              die "Unexpected conflict in '$package'; multiple versions found.\n";
8291
-            } else {
8292
-              $prime{$package}{file} = $mapped_filename;
8293
-              $prime{$package}{version} = $version if defined( $version );
8294
-            }
8295
-          } else {
8296
-            push( @{$alt{$package}}, {
8297
-                                      file    => $mapped_filename,
8298
-                                      version => $version,
8299
-                                     } );
8513
+          if ( $ch ) {
8514
+              return ( $result, $consumed ) if ($opt & 0x00000001); # all right if decode_prefix
8515
+              decode_error("garbage after JSON object");
8300 8516
           }
8301
-        }
8517
+  
8518
+          ( $opt & 0x00000001 ) ? ( $result, $consumed ) : $result;
8302 8519
       }
8303
-    
8304
-      # Then we iterate over all the packages found above, identifying conflicts
8305
-      # and selecting the "best" candidate for recording the file & version
8306
-      # for each package.
8307
-      foreach my $package ( keys( %alt ) ) {
8308
-        my $result = $resolve_module_versions->( $alt{$package} );
8309
-    
8310
-        if ( exists( $prime{$package} ) ) { # primary package selected
8311
-    
8312
-          if ( $result->{err} ) {
8313
-    	# Use the selected primary package, but there are conflicting
8314
-    	# errors among multiple alternative packages that need to be
8315
-    	# reported
8316
-            log_info {
8317
-    	    "Found conflicting versions for package '$package'\n" .
8318
-    	    "  $prime{$package}{file} ($prime{$package}{version})\n" .
8319
-    	    $result->{err}
8320
-            };
8321
-    
8322
-          } elsif ( defined( $result->{version} ) ) {
8323
-    	# There is a primary package selected, and exactly one
8324
-    	# alternative package
8325
-    
8326
-    	if ( exists( $prime{$package}{version} ) &&
8327
-    	     defined( $prime{$package}{version} ) ) {
8328
-    	  # Unless the version of the primary package agrees with the
8329
-    	  # version of the alternative package, report a conflict
8330
-    	  if ( $compare_versions->(
8331
-                   $prime{$package}{version}, '!=', $result->{version}
8332
-                 )
8333
-               ) {
8334 8520
   
8335
-              log_info {
8336
-                "Found conflicting versions for package '$package'\n" .
8337
-    	      "  $prime{$package}{file} ($prime{$package}{version})\n" .
8338
-    	      "  $result->{file} ($result->{version})\n"
8339
-              };
8340
-    	  }
8341
-    
8342
-    	} else {
8343
-    	  # The prime package selected has no version so, we choose to
8344
-    	  # use any alternative package that does have a version
8345
-    	  $prime{$package}{file}    = $result->{file};
8346
-    	  $prime{$package}{version} = $result->{version};
8347
-    	}
8348
-    
8349
-          } else {
8350
-    	# no alt package found with a version, but we have a prime
8351
-    	# package so we use it whether it has a version or not
8352
-          }
8353
-    
8354
-        } else { # No primary package was selected, use the best alternative
8355
-    
8356
-          if ( $result->{err} ) {
8357
-            log_info {
8358
-              "Found conflicting versions for package '$package'\n" .
8359
-    	    $result->{err}
8360
-            };
8361
-          }
8362
-    
8363
-          # Despite possible conflicting versions, we choose to record
8364
-          # something rather than nothing
8365
-          $prime{$package}{file}    = $result->{file};
8366
-          $prime{$package}{version} = $result->{version}
8367
-    	  if defined( $result->{version} );
8368
-        }
8521
+  
8522
+      sub next_chr {
8523
+          return $ch = undef if($at >= $len);
8524
+          $ch = substr($text, $at++, 1);
8525
+      }
8526
+  
8527
+  
8528
+      sub value {
8529
+          white();
8530
+          return          if(!defined $ch);
8531
+          return object() if($ch eq '{');
8532
+          return array()  if($ch eq '[');
8533
+          return string() if($ch eq '"' or ($singlequote and $ch eq "'"));
8534
+          return number() if($ch =~ /[0-9]/ or $ch eq '-');
8535
+          return word();
8536
+      }
8537
+  
8538
+      sub string {
8539
+          my ($i, $s, $t, $u);
8540
+          my $utf16;
8541
+          my $is_utf8;
8542
+  
8543
+          ($is_valid_utf8, $utf8_len) = ('', 0);
8544
+  
8545
+          $s = ''; # basically UTF8 flag on
8546
+  
8547
+          if($ch eq '"' or ($singlequote and $ch eq "'")){
8548
+              my $boundChar = $ch;
8549
+  
8550
+              OUTER: while( defined(next_chr()) ){
8551
+  
8552
+                  if($ch eq $boundChar){
8553
+                      next_chr();
8554
+  
8555
+                      if ($utf16) {
8556
+                          decode_error("missing low surrogate character in surrogate pair");
8557
+                      }
8558
+  
8559
+                      utf8::decode($s) if($is_utf8);
8560
+  
8561
+                      return $s;
8562
+                  }
8563
+                  elsif($ch eq '\\'){
8564
+                      next_chr();
8565
+                      if(exists $escapes{$ch}){
8566
+                          $s .= $escapes{$ch};
8567
+                      }
8568
+                      elsif($ch eq 'u'){ # UNICODE handling
8569
+                          my $u = '';
8570
+  
8571
+                          for(1..4){
8572
+                              $ch = next_chr();
8573
+                              last OUTER if($ch !~ /[0-9a-fA-F]/);
8574
+                              $u .= $ch;
8575
+                          }
8576
+  
8577
+                          # U+D800 - U+DBFF
8578
+                          if ($u =~ /^[dD][89abAB][0-9a-fA-F]{2}/) { # UTF-16 high surrogate?
8579
+                              $utf16 = $u;
8580
+                          }
8581
+                          # U+DC00 - U+DFFF
8582
+                          elsif ($u =~ /^[dD][c-fC-F][0-9a-fA-F]{2}/) { # UTF-16 low surrogate?
8583
+                              unless (defined $utf16) {
8584
+                                  decode_error("missing high surrogate character in surrogate pair");
8585
+                              }
8586
+                              $is_utf8 = 1;
8587
+                              $s .= JSON_PP_decode_surrogates($utf16, $u) || next;
8588
+                              $utf16 = undef;
8589
+                          }
8590
+                          else {
8591
+                              if (defined $utf16) {
8592
+                                  decode_error("surrogate pair expected");
8593
+                              }
8594
+  
8595
+                              if ( ( my $hex = hex( $u ) ) > 127 ) {
8596
+                                  $is_utf8 = 1;
8597
+                                  $s .= JSON_PP_decode_unicode($u) || next;
8598
+                              }
8599
+                              else {
8600
+                                  $s .= chr $hex;
8601
+                              }
8602
+                          }
8603
+  
8604
+                      }
8605
+                      else{
8606
+                          unless ($loose) {
8607
+                              $at -= 2;
8608
+                              decode_error('illegal backslash escape sequence in string');
8609
+                          }
8610
+                          $s .= $ch;
8611
+                      }
8612
+                  }
8613
+                  else{
8614
+  
8615
+                      if ( ord $ch  > 127 ) {
8616
+                          if ( $utf8 ) {
8617
+                              unless( $ch = is_valid_utf8($ch) ) {
8618
+                                  $at -= 1;
8619
+                                  decode_error("malformed UTF-8 character in JSON string");
8620
+                              }
8621
+                              else {
8622
+                                  $at += $utf8_len - 1;
8623
+                              }
8624
+                          }
8625
+                          else {
8626
+                              utf8::encode( $ch );
8627
+                          }
8628
+  
8629
+                          $is_utf8 = 1;
8630
+                      }
8631
+  
8632
+                      if (!$loose) {
8633
+                          if ($ch =~ /[\x00-\x1f\x22\x5c]/)  { # '/' ok
8634
+                              $at--;
8635
+                              decode_error('invalid character encountered while parsing JSON string');
8636
+                          }
8637
+                      }
8638
+  
8639
+                      $s .= $ch;
8640
+                  }
8641
+              }
8642
+          }
8643
+  
8644
+          decode_error("unexpected end of string while parsing JSON string");
8645
+      }
8646
+  
8647
+  
8648
+      sub white {
8649
+          while( defined $ch  ){
8650
+              if($ch le ' '){
8651
+                  next_chr();
8652
+              }
8653
+              elsif($ch eq '/'){
8654
+                  next_chr();
8655
+                  if(defined $ch and $ch eq '/'){
8656
+                      1 while(defined(next_chr()) and $ch ne "\n" and $ch ne "\r");
8657
+                  }
8658
+                  elsif(defined $ch and $ch eq '*'){
8659
+                      next_chr();
8660
+                      while(1){
8661
+                          if(defined $ch){
8662
+                              if($ch eq '*'){
8663
+                                  if(defined(next_chr()) and $ch eq '/'){
8664
+                                      next_chr();
8665
+                                      last;
8666
+                                  }
8667
+                              }
8668
+                              else{
8669
+                                  next_chr();
8670
+                              }
8671
+                          }
8672
+                          else{
8673
+                              decode_error("Unterminated comment");
8674
+                          }
8675
+                      }
8676
+                      next;
8677
+                  }
8678
+                  else{
8679
+                      $at--;
8680
+                      decode_error("malformed JSON string, neither array, object, number, string or atom");
8681
+                  }
8682
+              }
8683
+              else{
8684
+                  if ($relaxed and $ch eq '#') { # correctly?
8685
+                      pos($text) = $at;
8686
+                      $text =~ /\G([^\n]*(?:\r\n|\r|\n|$))/g;
8687
+                      $at = pos($text);
8688
+                      next_chr;
8689
+                      next;
8690
+                  }
8691
+  
8692
+                  last;
8693
+              }
8694
+          }
8695
+      }
8696
+  
8697
+  
8698
+      sub array {
8699
+          my $a  = $_[0] || []; # you can use this code to use another array ref object.
8700
+  
8701
+          decode_error('json text or perl structure exceeds maximum nesting level (max_depth set too low?)')
8702
+                                                      if (++$depth > $max_depth);
8703
+  
8704
+          next_chr();
8705
+          white();
8706
+  
8707
+          if(defined $ch and $ch eq ']'){
8708
+              --$depth;
8709
+              next_chr();
8710
+              return $a;
8711
+          }
8712
+          else {
8713
+              while(defined($ch)){
8714
+                  push @$a, value();
8715
+  
8716
+                  white();
8717
+  
8718
+                  if (!defined $ch) {
8719
+                      last;
8720
+                  }
8721
+  
8722
+                  if($ch eq ']'){
8723
+                      --$depth;
8724
+                      next_chr();
8725
+                      return $a;
8726
+                  }
8727
+  
8728
+                  if($ch ne ','){
8729
+                      last;
8730
+                  }
8731
+  
8732
+                  next_chr();
8733
+                  white();
8734
+  
8735
+                  if ($relaxed and $ch eq ']') {
8736
+                      --$depth;
8737
+                      next_chr();
8738
+                      return $a;
8739
+                  }
8740
+  
8741
+              }
8742
+          }
8743
+  
8744
+          decode_error(", or ] expected while parsing array");
8745
+      }
8746
+  
8747
+  
8748
+      sub object {
8749
+          my $o = $_[0] || {}; # you can use this code to use another hash ref object.
8750
+          my $k;
8751
+  
8752
+          decode_error('json text or perl structure exceeds maximum nesting level (max_depth set too low?)')
8753
+                                                  if (++$depth > $max_depth);
8754
+          next_chr();
8755
+          white();
8756
+  
8757
+          if(defined $ch and $ch eq '}'){
8758
+              --$depth;
8759
+              next_chr();
8760
+              if ($F_HOOK) {
8761
+                  return _json_object_hook($o);
8762
+              }
8763
+              return $o;
8764
+          }
8765
+          else {
8766
+              while (defined $ch) {
8767
+                  $k = ($allow_barekey and $ch ne '"' and $ch ne "'") ? bareKey() : string();
8768
+                  white();
8769
+  
8770
+                  if(!defined $ch or $ch ne ':'){
8771
+                      $at--;
8772
+                      decode_error("':' expected");
8773
+                  }
8774
+  
8775
+                  next_chr();
8776
+                  $o->{$k} = value();
8777
+                  white();
8778
+  
8779
+                  last if (!defined $ch);
8780
+  
8781
+                  if($ch eq '}'){
8782
+                      --$depth;
8783
+                      next_chr();
8784
+                      if ($F_HOOK) {
8785
+                          return _json_object_hook($o);
8786
+                      }
8787
+                      return $o;
8788
+                  }
8789
+  
8790
+                  if($ch ne ','){
8791
+                      last;
8792
+                  }
8793
+  
8794
+                  next_chr();
8795
+                  white();
8796
+  
8797
+                  if ($relaxed and $ch eq '}') {
8798
+                      --$depth;
8799
+                      next_chr();
8800
+                      if ($F_HOOK) {
8801
+                          return _json_object_hook($o);
8802
+                      }
8803
+                      return $o;
8804
+                  }
8805
+  
8806
+              }
8807
+  
8808
+          }
8809
+  
8810
+          $at--;
8811
+          decode_error(", or } expected while parsing object/hash");
8812
+      }
8813
+  
8814
+  
8815
+      sub bareKey { # doesn't strictly follow Standard ECMA-262 3rd Edition
8816
+          my $key;
8817
+          while($ch =~ /[^\x00-\x23\x25-\x2F\x3A-\x40\x5B-\x5E\x60\x7B-\x7F]/){
8818
+              $key .= $ch;
8819
+              next_chr();
8820
+          }
8821
+          return $key;
8822
+      }
8823
+  
8824
+  
8825
+      sub word {
8826
+          my $word =  substr($text,$at-1,4);
8827
+  
8828
+          if($word eq 'true'){
8829
+              $at += 3;
8830
+              next_chr;
8831
+              return $JSON::PP::true;
8832
+          }
8833
+          elsif($word eq 'null'){
8834
+              $at += 3;
8835
+              next_chr;
8836
+              return undef;
8837
+          }
8838
+          elsif($word eq 'fals'){
8839
+              $at += 3;
8840
+              if(substr($text,$at,1) eq 'e'){
8841
+                  $at++;
8842
+                  next_chr;
8843
+                  return $JSON::PP::false;
8844
+              }
8845
+          }
8846
+  
8847
+          $at--; # for decode_error report
8848
+  
8849
+          decode_error("'null' expected")  if ($word =~ /^n/);
8850
+          decode_error("'true' expected")  if ($word =~ /^t/);
8851
+          decode_error("'false' expected") if ($word =~ /^f/);
8852
+          decode_error("malformed JSON string, neither array, object, number, string or atom");
8853
+      }
8854
+  
8855
+  
8856
+      sub number {
8857
+          my $n    = '';
8858
+          my $v;
8859
+  
8860
+          # According to RFC4627, hex or oct digts are invalid.
8861
+          if($ch eq '0'){
8862
+              my $peek = substr($text,$at,1);
8863
+              my $hex  = $peek =~ /[xX]/; # 0 or 1
8864
+  
8865
+              if($hex){
8866
+                  decode_error("malformed number (leading zero must not be followed by another digit)");
8867
+                  ($n) = ( substr($text, $at+1) =~ /^([0-9a-fA-F]+)/);
8868
+              }
8869
+              else{ # oct
8870
+                  ($n) = ( substr($text, $at) =~ /^([0-7]+)/);
8871
+                  if (defined $n and length $n > 1) {
8872
+                      decode_error("malformed number (leading zero must not be followed by another digit)");
8873
+                  }
8874
+              }
8875
+  
8876
+              if(defined $n and length($n)){
8877
+                  if (!$hex and length($n) == 1) {
8878
+                     decode_error("malformed number (leading zero must not be followed by another digit)");
8879
+                  }
8880
+                  $at += length($n) + $hex;
8881
+                  next_chr;
8882
+                  return $hex ? hex($n) : oct($n);
8883
+              }
8884
+          }
8885
+  
8886
+          if($ch eq '-'){
8887
+              $n = '-';
8888
+              next_chr;
8889
+              if (!defined $ch or $ch !~ /\d/) {
8890
+                  decode_error("malformed number (no digits after initial minus)");
8891
+              }
8892
+          }
8893
+  
8894
+          while(defined $ch and $ch =~ /\d/){
8895
+              $n .= $ch;
8896
+              next_chr;
8897
+          }
8898
+  
8899
+          if(defined $ch and $ch eq '.'){
8900
+              $n .= '.';
8901
+  
8902
+              next_chr;
8903
+              if (!defined $ch or $ch !~ /\d/) {
8904
+                  decode_error("malformed number (no digits after decimal point)");
8905
+              }
8906
+              else {
8907
+                  $n .= $ch;
8908
+              }
8909
+  
8910
+              while(defined(next_chr) and $ch =~ /\d/){
8911
+                  $n .= $ch;
8912
+              }
8913
+          }
8914
+  
8915
+          if(defined $ch and ($ch eq 'e' or $ch eq 'E')){
8916
+              $n .= $ch;
8917
+              next_chr;
8918
+  
8919
+              if(defined($ch) and ($ch eq '+' or $ch eq '-')){
8920
+                  $n .= $ch;
8921
+                  next_chr;
8922
+                  if (!defined $ch or $ch =~ /\D/) {
8923
+                      decode_error("malformed number (no digits after exp sign)");
8924
+                  }
8925
+                  $n .= $ch;
8926
+              }
8927
+              elsif(defined($ch) and $ch =~ /\d/){
8928
+                  $n .= $ch;
8929
+              }
8930
+              else {
8931
+                  decode_error("malformed number (no digits after exp sign)");
8932
+              }
8933
+  
8934
+              while(defined(next_chr) and $ch =~ /\d/){
8935
+                  $n .= $ch;
8936
+              }
8937
+  
8938
+          }
8939
+  
8940
+          $v .= $n;
8941
+  
8942
+          if ($v !~ /[.eE]/ and length $v > $max_intsize) {
8943
+              if ($allow_bigint) { # from Adam Sussman
8944
+                  require Math::BigInt;
8945
+                  return Math::BigInt->new($v);
8946
+              }
8947
+              else {
8948
+                  return "$v";
8949
+              }
8950
+          }
8951
+          elsif ($allow_bigint) {
8952
+              require Math::BigFloat;
8953
+              return Math::BigFloat->new($v);
8954
+          }
8955
+  
8956
+          return 0+$v;
8957
+      }
8958
+  
8959
+  
8960
+      sub is_valid_utf8 {
8961
+  
8962
+          $utf8_len = $_[0] =~ /[\x00-\x7F]/  ? 1
8963
+                    : $_[0] =~ /[\xC2-\xDF]/  ? 2
8964
+                    : $_[0] =~ /[\xE0-\xEF]/  ? 3
8965
+                    : $_[0] =~ /[\xF0-\xF4]/  ? 4
8966
+                    : 0
8967
+                    ;
8968
+  
8969
+          return unless $utf8_len;
8970
+  
8971
+          my $is_valid_utf8 = substr($text, $at - 1, $utf8_len);
8972
+  
8973
+          return ( $is_valid_utf8 =~ /^(?:
8974
+               [\x00-\x7F]
8975
+              |[\xC2-\xDF][\x80-\xBF]
8976
+              |[\xE0][\xA0-\xBF][\x80-\xBF]
8977
+              |[\xE1-\xEC][\x80-\xBF][\x80-\xBF]
8978
+              |[\xED][\x80-\x9F][\x80-\xBF]
8979
+              |[\xEE-\xEF][\x80-\xBF][\x80-\xBF]
8980
+              |[\xF0][\x90-\xBF][\x80-\xBF][\x80-\xBF]
8981
+              |[\xF1-\xF3][\x80-\xBF][\x80-\xBF][\x80-\xBF]
8982
+              |[\xF4][\x80-\x8F][\x80-\xBF][\x80-\xBF]
8983
+          )$/x )  ? $is_valid_utf8 : '';
8984
+      }
8985
+  
8986
+  
8987
+      sub decode_error {
8988
+          my $error  = shift;
8989
+          my $no_rep = shift;
8990
+          my $str    = defined $text ? substr($text, $at) : '';
8991
+          my $mess   = '';
8992
+          my $type   = $] >= 5.008           ? 'U*'
8993
+                     : $] <  5.006           ? 'C*'
8994
+                     : utf8::is_utf8( $str ) ? 'U*' # 5.6
8995
+                     : 'C*'
8996
+                     ;
8997
+  
8998
+          for my $c ( unpack( $type, $str ) ) { # emulate pv_uni_display() ?
8999
+              $mess .=  $c == 0x07 ? '\a'
9000
+                      : $c == 0x09 ? '\t'
9001
+                      : $c == 0x0a ? '\n'
9002
+                      : $c == 0x0d ? '\r'
9003
+                      : $c == 0x0c ? '\f'
9004
+                      : $c <  0x20 ? sprintf('\x{%x}', $c)
9005
+                      : $c == 0x5c ? '\\\\'
9006
+                      : $c <  0x80 ? chr($c)
9007
+                      : sprintf('\x{%x}', $c)
9008
+                      ;
9009
+              if ( length $mess >= 20 ) {
9010
+                  $mess .= '...';
9011
+                  last;
9012
+              }
9013
+          }
9014
+  
9015
+          unless ( length $mess ) {
9016
+              $mess = '(end of string)';
9017
+          }
9018
+  
9019
+          Carp::croak (
9020
+              $no_rep ? "$error" : "$error, at character offset $at (before \"$mess\")"
9021
+          );
9022
+  
9023
+      }
9024
+  
9025
+  
9026
+      sub _json_object_hook {
9027
+          my $o    = $_[0];
9028
+          my @ks = keys %{$o};
9029
+  
9030
+          if ( $cb_sk_object and @ks == 1 and exists $cb_sk_object->{ $ks[0] } and ref $cb_sk_object->{ $ks[0] } ) {
9031
+              my @val = $cb_sk_object->{ $ks[0] }->( $o->{$ks[0]} );
9032
+              if (@val == 1) {
9033
+                  return $val[0];
9034
+              }
9035
+          }
9036
+  
9037
+          my @val = $cb_object->($o) if ($cb_object);
9038
+          if (@val == 0 or @val > 1) {
9039
+              return $o;
9040
+          }
9041
+          else {
9042
+              return $val[0];
9043
+          }
9044
+      }
9045
+  
9046
+  
9047
+      sub PP_decode_box {
9048
+          {
9049
+              text    => $text,
9050
+              at      => $at,
9051
+              ch      => $ch,
9052
+              len     => $len,
9053
+              depth   => $depth,
9054
+              encoding      => $encoding,
9055
+              is_valid_utf8 => $is_valid_utf8,
9056
+          };
9057
+      }
9058
+  
9059
+  } # PARSE
9060
+  
9061
+  
9062
+  sub _decode_surrogates { # from perlunicode
9063
+      my $uni = 0x10000 + (hex($_[0]) - 0xD800) * 0x400 + (hex($_[1]) - 0xDC00);
9064
+      my $un  = pack('U*', $uni);
9065
+      utf8::encode( $un );
9066
+      return $un;
9067
+  }
9068
+  
9069
+  
9070
+  sub _decode_unicode {
9071
+      my $un = pack('U', hex shift);
9072
+      utf8::encode( $un );
9073
+      return $un;
9074
+  }
9075
+  
9076
+  #
9077
+  # Setup for various Perl versions (the code from JSON::PP58)
9078
+  #
9079
+  
9080
+  BEGIN {
9081
+  
9082
+      unless ( defined &utf8::is_utf8 ) {
9083
+         require Encode;
9084
+         *utf8::is_utf8 = *Encode::is_utf8;
9085
+      }
9086
+  
9087
+      if ( $] >= 5.008 ) {
9088
+          *JSON::PP::JSON_PP_encode_ascii      = \&_encode_ascii;
9089
+          *JSON::PP::JSON_PP_encode_latin1     = \&_encode_latin1;
9090
+          *JSON::PP::JSON_PP_decode_surrogates = \&_decode_surrogates;
9091
+          *JSON::PP::JSON_PP_decode_unicode    = \&_decode_unicode;
9092
+      }
9093
+  
9094
+      if ($] >= 5.008 and $] < 5.008003) { # join() in 5.8.0 - 5.8.2 is broken.
9095
+          package JSON::PP;
9096
+          require subs;
9097
+          subs->import('join');
9098
+          eval q|
9099
+              sub join {
9100
+                  return '' if (@_ < 2);
9101
+                  my $j   = shift;
9102
+                  my $str = shift;
9103
+                  for (@_) { $str .= $j . $_; }
9104
+                  return $str;
9105
+              }
9106
+          |;
9107
+      }
9108
+  
9109
+  
9110
+      sub JSON::PP::incr_parse {
9111
+          local $Carp::CarpLevel = 1;
9112
+          ( $_[0]->{_incr_parser} ||= JSON::PP::IncrParser->new )->incr_parse( @_ );
9113
+      }
9114
+  
9115
+  
9116
+      sub JSON::PP::incr_skip {
9117
+          ( $_[0]->{_incr_parser} ||= JSON::PP::IncrParser->new )->incr_skip;
8369 9118
       }
8370
-    
8371
-      # Normalize versions.  Can't use exists() here because of bug in YAML::Node.
8372
-      # XXX "bug in YAML::Node" comment seems irrelvant -- dagolden, 2009-05-18
8373
-      for (grep defined $_->{version}, values %prime) {
8374
-        $_->{version} = $normalize_version->( $_->{version} );
9119
+  
9120
+  
9121
+      sub JSON::PP::incr_reset {
9122
+          ( $_[0]->{_incr_parser} ||= JSON::PP::IncrParser->new )->incr_reset;
8375 9123
       }
8376
-    
8377
-      return \%prime;
8378
-    }
8379
-  } 
8380
-    
8381 9124
   
8382
-  sub _init {
8383
-    my $class    = shift;
8384
-    my $module   = shift;
8385
-    my $filename = shift;
8386
-    my %props = @_;
9125
+      eval q{
9126
+          sub JSON::PP::incr_text : lvalue {
9127
+              $_[0]->{_incr_parser} ||= JSON::PP::IncrParser->new;
8387 9128
   
8388
-    my $handle = delete $props{handle};
8389
-    my( %valid_props, @valid_props );
8390
-    @valid_props = qw( collect_pod inc );
8391
-    @valid_props{@valid_props} = delete( @props{@valid_props} );
8392
-    warn "Unknown properties: @{[keys %props]}\n" if scalar( %props );
9129
+              if ( $_[0]->{_incr_parser}->{incr_parsing} ) {
9130
+                  Carp::croak("incr_text can not be called when the incremental parser already started parsing");
9131
+              }
9132
+              $_[0]->{_incr_parser}->{incr_text};
9133
+          }
9134
+      } if ( $] >= 5.006 );
8393 9135
   
8394
-    my %data = (
8395
-      module       => $module,
8396
-      filename     => $filename,
8397
-      version      => undef,
8398
-      packages     => [],
8399
-      versions     => {},
8400
-      pod          => {},
8401
-      pod_headings => [],
8402
-      collect_pod  => 0,
9136
+  } # Setup for various Perl versions (the code from JSON::PP58)
8403 9137
   
8404
-      %valid_props,
8405
-    );
8406 9138
   
8407
-    my $self = bless(\%data, $class);
9139
+  ###############################
9140
+  # Utilities
9141
+  #
8408 9142
   
8409
-    if ( $handle ) {
8410
-      $self->_parse_fh($handle);
8411
-    }
8412
-    else {
8413
-      $self->_parse_file();
8414
-    }
9143
+  BEGIN {
9144
+      eval 'require Scalar::Util';
9145
+      unless($@){
9146
+          *JSON::PP::blessed = \&Scalar::Util::blessed;
9147
+          *JSON::PP::reftype = \&Scalar::Util::reftype;
9148
+          *JSON::PP::refaddr = \&Scalar::Util::refaddr;
9149
+      }
9150
+      else{ # This code is from Sclar::Util.
9151
+          # warn $@;
9152
+          eval 'sub UNIVERSAL::a_sub_not_likely_to_be_here { ref($_[0]) }';
9153
+          *JSON::PP::blessed = sub {
9154
+              local($@, $SIG{__DIE__}, $SIG{__WARN__});
9155
+              ref($_[0]) ? eval { $_[0]->a_sub_not_likely_to_be_here } : undef;
9156
+          };
9157
+          my %tmap = qw(
9158
+              B::NULL   SCALAR
9159
+              B::HV     HASH
9160
+              B::AV     ARRAY
9161
+              B::CV     CODE
9162
+              B::IO     IO
9163
+              B::GV     GLOB
9164
+              B::REGEXP REGEXP
9165
+          );
9166
+          *JSON::PP::reftype = sub {
9167
+              my $r = shift;
8415 9168
   
8416
-    unless($self->{module} and length($self->{module})) {
8417
-      my ($v, $d, $f) = File::Spec->splitpath($self->{filename});
8418
-      if($f =~ /\.pm$/) {
8419
-        $f =~ s/\..+$//;
8420
-        my @candidates = grep /$f$/, @{$self->{packages}};
8421
-        $self->{module} = shift(@candidates); # punt
9169
+              return undef unless length(ref($r));
9170
+  
9171
+              my $t = ref(B::svref_2object($r));
9172
+  
9173
+              return
9174
+                  exists $tmap{$t} ? $tmap{$t}
9175
+                : length(ref($$r)) ? 'REF'
9176
+                :                    'SCALAR';
9177
+          };
9178
+          *JSON::PP::refaddr = sub {
9179
+            return undef unless length(ref($_[0]));
9180
+  
9181
+            my $addr;
9182
+            if(defined(my $pkg = blessed($_[0]))) {
9183
+              $addr .= bless $_[0], 'Scalar::Util::Fake';
9184
+              bless $_[0], $pkg;
9185
+            }
9186
+            else {
9187
+              $addr .= $_[0]
9188
+            }
9189
+  
9190
+            $addr =~ /0x(\w+)/;
9191
+            local $^W;
9192
+            #no warnings 'portable';
9193
+            hex($1);
9194
+          }
8422 9195
       }
8423
-      else {
8424
-        if(grep /main/, @{$self->{packages}}) {
8425
-          $self->{module} = 'main';
8426
-        }
8427
-        else {
8428
-          $self->{module} = $self->{packages}[0] || '';
8429
-        }
9196
+  }
9197
+  
9198
+  
9199
+  # shamely copied and modified from JSON::XS code.
9200
+  
9201
+  $JSON::PP::true  = do { bless \(my $dummy = 1), "JSON::PP::Boolean" };
9202
+  $JSON::PP::false = do { bless \(my $dummy = 0), "JSON::PP::Boolean" };
9203
+  
9204
+  sub is_bool { defined $_[0] and UNIVERSAL::isa($_[0], "JSON::PP::Boolean"); }
9205
+  
9206
+  sub true  { $JSON::PP::true  }
9207
+  sub false { $JSON::PP::false }
9208
+  sub null  { undef; }
9209
+  
9210
+  ###############################
9211
+  
9212
+  package JSON::PP::Boolean;
9213
+  
9214
+  use overload (
9215
+     "0+"     => sub { ${$_[0]} },
9216
+     "++"     => sub { $_[0] = ${$_[0]} + 1 },
9217
+     "--"     => sub { $_[0] = ${$_[0]} - 1 },
9218
+     fallback => 1,
9219
+  );
9220
+  
9221
+  
9222
+  ###############################
9223
+  
9224
+  package JSON::PP::IncrParser;
9225
+  
9226
+  use strict;
9227
+  
9228
+  use constant INCR_M_WS   => 0; # initial whitespace skipping
9229
+  use constant INCR_M_STR  => 1; # inside string
9230
+  use constant INCR_M_BS   => 2; # inside backslash
9231
+  use constant INCR_M_JSON => 3; # outside anything, count nesting
9232
+  use constant INCR_M_C0   => 4;
9233
+  use constant INCR_M_C1   => 5;
9234
+  
9235
+  $JSON::PP::IncrParser::VERSION = '1.01';
9236
+  
9237
+  my $unpack_format = $] < 5.006 ? 'C*' : 'U*';
9238
+  
9239
+  sub new {
9240
+      my ( $class ) = @_;
9241
+  
9242
+      bless {
9243
+          incr_nest    => 0,
9244
+          incr_text    => undef,
9245
+          incr_parsing => 0,
9246
+          incr_p       => 0,
9247
+      }, $class;
9248
+  }
9249
+  
9250
+  
9251
+  sub incr_parse {
9252
+      my ( $self, $coder, $text ) = @_;
9253
+  
9254
+      $self->{incr_text} = '' unless ( defined $self->{incr_text} );
9255
+  
9256
+      if ( defined $text ) {
9257
+          if ( utf8::is_utf8( $text ) and !utf8::is_utf8( $self->{incr_text} ) ) {
9258
+              utf8::upgrade( $self->{incr_text} ) ;
9259
+              utf8::decode( $self->{incr_text} ) ;
9260
+          }
9261
+          $self->{incr_text} .= $text;
8430 9262
       }
8431
-    }
8432 9263
   
8433
-    $self->{version} = $self->{versions}{$self->{module}}
8434
-        if defined( $self->{module} );
8435 9264
   
8436
-    return $self;
9265
+      my $max_size = $coder->get_max_size;
9266
+  
9267
+      if ( defined wantarray ) {
9268
+  
9269
+          $self->{incr_mode} = INCR_M_WS unless defined $self->{incr_mode};
9270
+  
9271
+          if ( wantarray ) {
9272
+              my @ret;
9273
+  
9274
+              $self->{incr_parsing} = 1;
9275
+  
9276
+              do {
9277
+                  push @ret, $self->_incr_parse( $coder, $self->{incr_text} );
9278
+  
9279
+                  unless ( !$self->{incr_nest} and $self->{incr_mode} == INCR_M_JSON ) {
9280
+                      $self->{incr_mode} = INCR_M_WS if $self->{incr_mode} != INCR_M_STR;
9281
+                  }
9282
+  
9283
+              } until ( length $self->{incr_text} >= $self->{incr_p} );
9284
+  
9285
+              $self->{incr_parsing} = 0;
9286
+  
9287
+              return @ret;
9288
+          }
9289
+          else { # in scalar context
9290
+              $self->{incr_parsing} = 1;
9291
+              my $obj = $self->_incr_parse( $coder, $self->{incr_text} );
9292
+              $self->{incr_parsing} = 0 if defined $obj; # pointed by Martin J. Evans
9293
+              return $obj ? $obj : undef; # $obj is an empty string, parsing was completed.
9294
+          }
9295
+  
9296
+      }
9297
+  
8437 9298
   }
8438 9299
   
8439
-  # class method
8440
-  sub _do_find_module {
8441
-    my $class   = shift;
8442
-    my $module  = shift || die 'find_module_by_name() requires a package name';
8443
-    my $dirs    = shift || \@INC;
8444 9300
   
8445
-    my $file = File::Spec->catfile(split( /::/, $module));
8446
-    foreach my $dir ( @$dirs ) {
8447
-      my $testfile = File::Spec->catfile($dir, $file);
8448
-      return [ File::Spec->rel2abs( $testfile ), $dir ]
8449
-  	if -e $testfile and !-d _;  # For stuff like ExtUtils::xsubpp
8450
-      return [ File::Spec->rel2abs( "$testfile.pm" ), $dir ]
8451
-  	if -e "$testfile.pm";
8452
-    }
8453
-    return;
8454
-  }
9301
+  sub _incr_parse {
9302
+      my ( $self, $coder, $text, $skip ) = @_;
9303
+      my $p = $self->{incr_p};
9304
+      my $restore = $p;
8455 9305
   
8456
-  # class method
8457
-  sub find_module_by_name {
8458
-    my $found = shift()->_do_find_module(@_) or return;
8459
-    return $found->[0];
8460
-  }
9306
+      my @obj;
9307
+      my $len = length $text;
8461 9308
   
8462
-  # class method
8463
-  sub find_module_dir_by_name {
8464
-    my $found = shift()->_do_find_module(@_) or return;
8465
-    return $found->[1];
8466
-  }
9309
+      if ( $self->{incr_mode} == INCR_M_WS ) {
9310
+          while ( $len > $p ) {
9311
+              my $s = substr( $text, $p, 1 );
9312
+              $p++ and next if ( 0x20 >= unpack($unpack_format, $s) );
9313
+              $self->{incr_mode} = INCR_M_JSON;
9314
+              last;
9315
+         }
9316
+      }
8467 9317
   
9318
+      while ( $len > $p ) {
9319
+          my $s = substr( $text, $p++, 1 );
8468 9320
   
8469
-  # given a line of perl code, attempt to parse it if it looks like a
8470
-  # $VERSION assignment, returning sigil, full name, & package name
8471
-  sub _parse_version_expression {
8472
-    my $self = shift;
8473
-    my $line = shift;
9321
+          if ( $s eq '"' ) {
9322
+              if (substr( $text, $p - 2, 1 ) eq '\\' ) {
9323
+                  next;
9324
+              }
8474 9325
   
8475
-    my( $sig, $var, $pkg );
8476
-    if ( $line =~ $VERS_REGEXP ) {
8477
-      ( $sig, $var, $pkg ) = $2 ? ( $1, $2, $3 ) : ( $4, $5, $6 );
8478
-      if ( $pkg ) {
8479
-        $pkg = ($pkg eq '::') ? 'main' : $pkg;
8480
-        $pkg =~ s/::$//;
8481
-      }
8482
-    }
9326
+              if ( $self->{incr_mode} != INCR_M_STR  ) {
9327
+                  $self->{incr_mode} = INCR_M_STR;
9328
+              }
9329
+              else {
9330
+                  $self->{incr_mode} = INCR_M_JSON;
9331
+                  unless ( $self->{incr_nest} ) {
9332
+                      last;
9333
+                  }
9334
+              }
9335
+          }
8483 9336
   
8484
-    return ( $sig, $var, $pkg );
8485
-  }
9337
+          if ( $self->{incr_mode} == INCR_M_JSON ) {
8486 9338
   
8487
-  sub _parse_file {
8488
-    my $self = shift;
9339
+              if ( $s eq '[' or $s eq '{' ) {
9340
+                  if ( ++$self->{incr_nest} > $coder->get_max_depth ) {
9341
+                      Carp::croak('json text or perl structure exceeds maximum nesting level (max_depth set too low?)');
9342
+                  }
9343
+              }
9344
+              elsif ( $s eq ']' or $s eq '}' ) {
9345
+                  last if ( --$self->{incr_nest} <= 0 );
9346
+              }
9347
+              elsif ( $s eq '#' ) {
9348
+                  while ( $len > $p ) {
9349
+                      last if substr( $text, $p++, 1 ) eq "\n";
9350
+                  }
9351
+              }
8489 9352
   
8490
-    my $filename = $self->{filename};
8491
-    my $fh = IO::File->new( $filename )
8492
-      or die( "Can't open '$filename': $!" );
9353
+          }
8493 9354
   
8494
-    $self->_parse_fh($fh);
8495
-  }
9355
+      }
8496 9356
   
8497
-  sub _parse_fh {
8498
-    my ($self, $fh) = @_;
9357
+      $self->{incr_p} = $p;
8499 9358
   
8500
-    my( $in_pod, $seen_end, $need_vers ) = ( 0, 0, 0 );
8501
-    my( @pkgs, %vers, %pod, @pod );
8502
-    my $pkg = 'main';
8503
-    my $pod_sect = '';
8504
-    my $pod_data = '';
9359
+      return if ( $self->{incr_mode} == INCR_M_STR and not $self->{incr_nest} );
9360
+      return if ( $self->{incr_mode} == INCR_M_JSON and $self->{incr_nest} > 0 );
8505 9361
   
8506
-    while (defined( my $line = <$fh> )) {
8507
-      my $line_num = $.;
9362
+      return '' unless ( length substr( $self->{incr_text}, 0, $p ) );
8508 9363
   
8509
-      chomp( $line );
8510
-      next if $line =~ /^\s*#/;
9364
+      local $Carp::CarpLevel = 2;
8511 9365
   
8512
-      $in_pod = ($line =~ /^=(?!cut)/) ? 1 : ($line =~ /^=cut/) ? 0 : $in_pod;
9366
+      $self->{incr_p} = $restore;
9367
+      $self->{incr_c} = $p;
8513 9368
   
8514
-      # Would be nice if we could also check $in_string or something too
8515
-      last if !$in_pod && $line =~ /^__(?:DATA|END)__$/;
9369
+      my ( $obj, $tail ) = $coder->PP_decode_json( substr( $self->{incr_text}, 0, $p ), 0x10000001 );
8516 9370
   
8517
-      if ( $in_pod || $line =~ /^=cut/ ) {
9371
+      $self->{incr_text} = substr( $self->{incr_text}, $p );
9372
+      $self->{incr_p} = 0;
8518 9373
   
8519
-        if ( $line =~ /^=head\d\s+(.+)\s*$/ ) {
8520
-  	push( @pod, $1 );
8521
-  	if ( $self->{collect_pod} && length( $pod_data ) ) {
8522
-            $pod{$pod_sect} = $pod_data;
8523
-            $pod_data = '';
8524
-          }
8525
-  	$pod_sect = $1;
9374
+      return $obj or '';
9375
+  }
8526 9376
   
8527 9377
   
8528
-        } elsif ( $self->{collect_pod} ) {
8529
-  	$pod_data .= "$line\n";
9378
+  sub incr_text {
9379
+      if ( $_[0]->{incr_parsing} ) {
9380
+          Carp::croak("incr_text can not be called when the incremental parser already started parsing");
9381
+      }
9382
+      $_[0]->{incr_text};
9383
+  }
8530 9384
   
8531
-        }
8532 9385
   
8533
-      } else {
9386
+  sub incr_skip {
9387
+      my $self  = shift;
9388
+      $self->{incr_text} = substr( $self->{incr_text}, $self->{incr_c} );
9389
+      $self->{incr_p} = 0;
9390
+  }
8534 9391
   
8535
-        $pod_sect = '';
8536
-        $pod_data = '';
8537 9392
   
8538
-        # parse $line to see if it's a $VERSION declaration
8539
-        my( $vers_sig, $vers_fullname, $vers_pkg ) =
8540
-  	  $self->_parse_version_expression( $line );
9393
+  sub incr_reset {
9394
+      my $self = shift;
9395
+      $self->{incr_text}    = undef;
9396
+      $self->{incr_p}       = 0;
9397
+      $self->{incr_mode}    = 0;
9398
+      $self->{incr_nest}    = 0;
9399
+      $self->{incr_parsing} = 0;
9400
+  }
8541 9401
   
8542
-        if ( $line =~ $PKG_REGEXP ) {
8543
-          $pkg = $1;
8544
-          push( @pkgs, $pkg ) unless grep( $pkg eq $_, @pkgs );
8545
-          $vers{$pkg} = (defined $2 ? $2 : undef)  unless exists( $vers{$pkg} );
8546
-          $need_vers = defined $2 ? 0 : 1;
9402
+  ###############################
8547 9403
   
8548
-        # VERSION defined with full package spec, i.e. $Module::VERSION
8549
-        } elsif ( $vers_fullname && $vers_pkg ) {
8550
-  	push( @pkgs, $vers_pkg ) unless grep( $vers_pkg eq $_, @pkgs );
8551
-  	$need_vers = 0 if $vers_pkg eq $pkg;
8552 9404
   
8553
-  	unless ( defined $vers{$vers_pkg} && length $vers{$vers_pkg} ) {
8554
-  	  $vers{$vers_pkg} =
8555
-  	    $self->_evaluate_version_line( $vers_sig, $vers_fullname, $line );
8556
-  	} else {
8557
-  	  # Warn unless the user is using the "$VERSION = eval
8558
-  	  # $VERSION" idiom (though there are probably other idioms
8559
-  	  # that we should watch out for...)
8560
-  	  warn <<"EOM" unless $line =~ /=\s*eval/;
8561
-  Package '$vers_pkg' already declared with version '$vers{$vers_pkg}',
8562
-  ignoring subsequent declaration on line $line_num.
8563
-  EOM
8564
-  	}
9405
+  1;
9406
+  __END__
9407
+  =pod
8565 9408
   
8566
-        # first non-comment line in undeclared package main is VERSION
8567
-        } elsif ( !exists($vers{main}) && $pkg eq 'main' && $vers_fullname ) {
8568
-  	$need_vers = 0;
8569
-  	my $v =
8570
-  	  $self->_evaluate_version_line( $vers_sig, $vers_fullname, $line );
8571
-  	$vers{$pkg} = $v;
8572
-  	push( @pkgs, 'main' );
9409
+JSON_PP
9410
+
9411
+$fatpacked{"JSON/PP/Boolean.pm"} = <<'JSON_PP_BOOLEAN';
9412
+  use JSON::PP ();
9413
+  use strict;
8573 9414
   
8574
-        # first non-comment line in undeclared package defines package main
8575
-        } elsif ( !exists($vers{main}) && $pkg eq 'main' && $line =~ /\w+/ ) {
8576
-  	$need_vers = 1;
8577
-  	$vers{main} = '';
8578
-  	push( @pkgs, 'main' );
9415
+  1;
8579 9416
   
8580
-        # only keep if this is the first $VERSION seen
8581
-        } elsif ( $vers_fullname && $need_vers ) {
8582
-  	$need_vers = 0;
8583
-  	my $v =
8584
-  	  $self->_evaluate_version_line( $vers_sig, $vers_fullname, $line );
9417
+JSON_PP_BOOLEAN
9418
+
9419
+$fatpacked{"Module/CPANfile.pm"} = <<'MODULE_CPANFILE';
9420
+  package Module::CPANfile;
9421
+  use strict;
9422
+  use warnings;
9423
+  use Cwd;
8585 9424
   
9425
+  our $VERSION = '0.9010';
8586 9426
   
8587
-  	unless ( defined $vers{$pkg} && length $vers{$pkg} ) {
8588
-  	  $vers{$pkg} = $v;
8589
-  	} else {
8590
-  	  warn <<"EOM";
8591
-  Package '$pkg' already declared with version '$vers{$pkg}'
8592
-  ignoring new version '$v' on line $line_num.
8593
-  EOM
8594
-  	}
9427
+  sub new {
9428
+      my($class, $file) = @_;
9429
+      bless {}, $class;
9430
+  }
8595 9431
   
8596
-        }
9432
+  sub load {
9433
+      my($proto, $file) = @_;
9434
+      my $self = ref $proto ? $proto : $proto->new;
9435
+      $self->{file} = $file || "cpanfile";
9436
+      $self->parse;
9437
+      $self;
9438
+  }
8597 9439
   
8598
-      }
9440
+  sub parse {
9441
+      my $self = shift;
8599 9442
   
8600
-    }
9443
+      my $file = Cwd::abs_path($self->{file});
9444
+      $self->{result} = Module::CPANfile::Environment::parse($file) or die $@;
9445
+  }
8601 9446
   
8602
-    if ( $self->{collect_pod} && length($pod_data) ) {
8603
-      $pod{$pod_sect} = $pod_data;
8604
-    }
9447
+  sub prereqs { shift->prereq }
8605 9448
   
8606
-    $self->{versions} = \%vers;
8607
-    $self->{packages} = \@pkgs;
8608
-    $self->{pod} = \%pod;
8609
-    $self->{pod_headings} = \@pod;
9449
+  sub prereq {
9450
+      my $self = shift;
9451
+      require CPAN::Meta::Prereqs;
9452
+      CPAN::Meta::Prereqs->new($self->prereq_specs);
8610 9453
   }
8611 9454
   
8612
-  {
8613
-  my $pn = 0;
8614
-  sub _evaluate_version_line {
8615
-    my $self = shift;
8616
-    my( $sigil, $var, $line ) = @_;
9455
+  sub prereq_specs {
9456
+      my $self = shift;
9457
+      $self->{result}{spec};
9458
+  }
8617 9459
   
8618
-    # Some of this code came from the ExtUtils:: hierarchy.
9460
+  sub merge_meta {
9461
+      my($self, $file, $version) = @_;
8619 9462
   
8620
-    # We compile into $vsub because 'use version' would cause
8621
-    # compiletime/runtime issues with local()
8622
-    my $vsub;
8623
-    $pn++; # everybody gets their own package
8624
-    my $eval = qq{BEGIN { q#  Hide from _packages_inside()
8625
-      #; package Module::Metadata::_version::p$pn;
8626
-      use version;
8627
-      no strict;
9463
+      require CPAN::Meta;
8628 9464
   
8629
-        \$vsub = sub {
8630
-          local $sigil$var;
8631
-          \$$var=undef;
8632
-          $line;
8633
-          \$$var
8634
-        };
8635
-    }};
9465
+      $version ||= $file =~ /\.yml$/ ? '1.4' : '2';
8636 9466
   
8637
-    local $^W;
8638
-    # Try to get the $VERSION
8639
-    eval $eval;
8640
-    # some modules say $VERSION = $Foo::Bar::VERSION, but Foo::Bar isn't
8641
-    # installed, so we need to hunt in ./lib for it
8642
-    if ( $@ =~ /Can't locate/ && -d 'lib' ) {
8643
-      local @INC = ('lib',@INC);
8644
-      eval $eval;
8645
-    }
8646
-    warn "Error evaling version line '$eval' in $self->{filename}: $@\n"
8647
-      if $@;
8648
-    (ref($vsub) eq 'CODE') or
8649
-      die "failed to build version sub for $self->{filename}";
8650
-    my $result = eval { $vsub->() };
8651
-    die "Could not get version from $self->{filename} by executing:\n$eval\n\nThe fatal error was: $@\n"
8652
-      if $@;
9467
+      my $prereq = $self->prereqs;
8653 9468
   
8654
-    # Upgrade it into a version object
8655
-    my $version = eval { _dwim_version($result) };
9469
+      my $meta = CPAN::Meta->load_file($file);
9470
+      my $prereqs_hash = $prereq->with_merged_prereqs($meta->effective_prereqs)->as_string_hash;
9471
+      my $struct = { %{$meta->as_struct}, prereqs => $prereqs_hash };
9472
+  
9473
+      CPAN::Meta->new($struct)->save($file, { version => $version });
9474
+  }
9475
+  
9476
+  package Module::CPANfile::Environment;
9477
+  use strict;
9478
+  
9479
+  my @bindings = qw(
9480
+      on requires recommends suggests conflicts
9481
+      osname perl
9482
+      configure_requires build_requires test_requires author_requires
9483
+  );
9484
+  
9485
+  my $file_id = 1;
8656 9486
   
8657
-    die "Version '$result' from $self->{filename} does not appear to be valid:\n$eval\n\nThe fatal error was: $@\n"
8658
-      unless defined $version; # "0" is OK!
9487
+  sub import {
9488
+      my($class, $result_ref) = @_;
9489
+      my $pkg = caller;
8659 9490
   
8660
-    return $version;
8661
-  }
9491
+      $$result_ref = Module::CPANfile::Result->new;
9492
+      for my $binding (@bindings) {
9493
+          no strict 'refs';
9494
+          *{"$pkg\::$binding"} = sub { $$result_ref->$binding(@_) };
9495
+      }
8662 9496
   }
8663 9497
   
8664
-  # Try to DWIM when things fail the lax version test in obvious ways
8665
-  {
8666
-    my @version_prep = (
8667
-      # Best case, it just works
8668
-      sub { return shift },
9498
+  sub parse {
9499
+      my $file = shift;
8669 9500
   
8670
-      # If we still don't have a version, try stripping any
8671
-      # trailing junk that is prohibited by lax rules
8672
-      sub {
8673
-        my $v = shift;
8674
-        $v =~ s{([0-9])[a-z-].*$}{$1}i; # 1.23-alpha or 1.23b
8675
-        return $v;
8676
-      },
9501
+      my $code = do {
9502
+          open my $fh, "<", $file or die "$file: $!";
9503
+          join '', <$fh>;
9504
+      };
8677 9505
   
8678
-      # Activestate apparently creates custom versions like '1.23_45_01', which
8679
-      # cause version.pm to think it's an invalid alpha.  So check for that
8680
-      # and strip them
8681
-      sub {
8682
-        my $v = shift;
8683
-        my $num_dots = () = $v =~ m{(\.)}g;
8684
-        my $num_unders = () = $v =~ m{(_)}g;
8685
-        my $leading_v = substr($v,0,1) eq 'v';
8686
-        if ( ! $leading_v && $num_dots < 2 && $num_unders > 1 ) {
8687
-          $v =~ s{_}{}g;
8688
-          $num_unders = () = $v =~ m{(_)}g;
8689
-        }
8690
-        return $v;
8691
-      },
9506
+      my($res, $err);
8692 9507
   
8693
-      # Worst case, try numifying it like we would have before version objects
8694
-      sub {
8695
-        my $v = shift;
8696
-        no warnings 'numeric';
8697
-        return 0 + $v;
8698
-      },
9508
+      {
9509
+          local $@;
9510
+          $res = eval sprintf <<EVAL, $file_id++;
9511
+  package Module::CPANfile::Sandbox%d;
9512
+  no warnings;
9513
+  my \$_result;
9514
+  BEGIN { import Module::CPANfile::Environment \\\$_result };
8699 9515
   
8700
-    );
9516
+  $code;
8701 9517
   
8702
-    sub _dwim_version {
8703
-      my ($result) = shift;
9518
+  \$_result;
9519
+  EVAL
9520
+          $err = $@;
9521
+      }
8704 9522
   
8705
-      return $result if ref($result) eq 'version';
9523
+      if ($err) { die "Parsing $file failed: $err" };
8706 9524
   
8707
-      my ($version, $error);
8708
-      for my $f (@version_prep) {
8709
-        $result = $f->($result);
8710
-        $version = eval { version->new($result) };
8711
-        $error ||= $@ if $@; # capture first failure
8712
-        last if defined $version;
8713
-      }
9525
+      return $res;
9526
+  }
8714 9527
   
8715
-      die $error unless defined $version;
9528
+  package Module::CPANfile::Result;
9529
+  use strict;
8716 9530
   
8717
-      return $version;
8718
-    }
9531
+  sub new {
9532
+      bless {
9533
+          phase => 'runtime', # default phase
9534
+          spec  => {},
9535
+      }, shift;
8719 9536
   }
8720 9537
   
8721
-  ############################################################
9538
+  sub on {
9539
+      my($self, $phase, $code) = @_;
9540
+      local $self->{phase} = $phase;
9541
+      $code->()
9542
+  }
8722 9543
   
8723
-  # accessors
8724
-  sub name            { $_[0]->{module}           }
9544
+  sub osname { die "TODO" }
9545
+  sub perl { die "TODO" }
8725 9546
   
8726
-  sub filename        { $_[0]->{filename}         }
8727
-  sub packages_inside { @{$_[0]->{packages}}      }
8728
-  sub pod_inside      { @{$_[0]->{pod_headings}}  }
8729
-  sub contains_pod    { $#{$_[0]->{pod_headings}} }
9547
+  sub requires {
9548
+      my($self, $module, $requirement) = @_;
9549
+      $self->{spec}{$self->{phase}}{requires}{$module} = $requirement || 0;
9550
+  }
8730 9551
   
8731
-  sub version {
8732
-      my $self = shift;
8733
-      my $mod  = shift || $self->{module};
8734
-      my $vers;
8735
-      if ( defined( $mod ) && length( $mod ) &&
8736
-  	 exists( $self->{versions}{$mod} ) ) {
8737
-  	return $self->{versions}{$mod};
8738
-      } else {
8739
-  	return undef;
8740
-      }
9552
+  sub recommends {
9553
+      my($self, $module, $requirement) = @_;
9554
+      $self->{spec}->{$self->{phase}}{recommends}{$module} = $requirement || 0;
8741 9555
   }
8742 9556
   
8743
-  sub pod {
8744
-      my $self = shift;
8745
-      my $sect = shift;
8746
-      if ( defined( $sect ) && length( $sect ) &&
8747
-  	 exists( $self->{pod}{$sect} ) ) {
8748
-  	return $self->{pod}{$sect};
8749
-      } else {
8750
-  	return undef;
8751
-      }
9557
+  sub suggests {
9558
+      my($self, $module, $requirement) = @_;
9559
+      $self->{spec}->{$self->{phase}}{suggests}{$module} = $requirement || 0;
9560
+  }
9561
+  
9562
+  sub conflicts {
9563
+      my($self, $module, $requirement) = @_;
9564
+      $self->{spec}->{$self->{phase}}{conflicts}{$module} = $requirement || 0;
9565
+  }
9566
+  
9567
+  # Module::Install compatible shortcuts
9568
+  
9569
+  sub configure_requires {
9570
+      my($self, @args) = @_;
9571
+      $self->on(configure => sub { $self->requires(@args) });
9572
+  }
9573
+  
9574
+  sub build_requires {
9575
+      my($self, @args) = @_;
9576
+      $self->on(build => sub { $self->requires(@args) });
9577
+  }
9578
+  
9579
+  sub test_requires {
9580
+      my($self, @args) = @_;
9581
+      $self->on(test => sub { $self->requires(@args) });
9582
+  }
9583
+  
9584
+  sub author_requires {
9585
+      my($self, @args) = @_;
9586
+      $self->on(develop => sub { $self->requires(@args) });
8752 9587
   }
8753 9588
   
9589
+  package Module::CPANfile;
9590
+  
8754 9591
   1;
8755 9592
   
8756
-MODULE_METADATA
8757
-
8758
-$fatpacked{"Parse/CPAN/Meta.pm"} = <<'PARSE_CPAN_META';
8759
-  package Parse::CPAN::Meta;
8760
-  
8761
-  use strict;
8762
-  use Carp 'croak';
8763
-  
8764
-  # UTF Support?
8765
-  sub HAVE_UTF8 () { $] >= 5.007003 }
8766
-  sub IO_LAYER () { $] >= 5.008001 ? ":utf8" : "" }  
8767
-  
8768
-  BEGIN {
8769
-  	if ( HAVE_UTF8 ) {
8770
-  		# The string eval helps hide this from Test::MinimumVersion
8771
-  		eval "require utf8;";
8772
-  		die "Failed to load UTF-8 support" if $@;
8773
-  	}
8774
-  
8775
-  	# Class structure
8776
-  	require 5.004;
8777
-  	require Exporter;
8778
-  	$Parse::CPAN::Meta::VERSION   = '1.4401';
8779
-  	@Parse::CPAN::Meta::ISA       = qw{ Exporter      };
8780
-  	@Parse::CPAN::Meta::EXPORT_OK = qw{ Load LoadFile };
8781
-  }
8782
-  
8783
-  sub load_file {
8784
-    my ($class, $filename) = @_;
8785
-  
8786
-    if ($filename =~ /\.ya?ml$/) {
8787
-      return $class->load_yaml_string(_slurp($filename));
8788
-    }
8789
-  
8790
-    if ($filename =~ /\.json$/) {
8791
-      return $class->load_json_string(_slurp($filename));
8792
-    }
8793
-  
8794
-    croak("file type cannot be determined by filename");
8795
-  }
8796
-  
8797
-  sub load_yaml_string {
8798
-    my ($class, $string) = @_;
8799
-    my $backend = $class->yaml_backend();
8800
-    my $data = eval { no strict 'refs'; &{"$backend\::Load"}($string) };
8801
-    if ( $@ ) { 
8802
-      croak $backend->can('errstr') ? $backend->errstr : $@
8803
-    }
8804
-    return $data || {}; # in case document was valid but empty
8805
-  }
8806
-  
8807
-  sub load_json_string {
8808
-    my ($class, $string) = @_;
8809
-    return $class->json_backend()->new->decode($string);
8810
-  }
8811
-  
8812
-  sub yaml_backend {
8813
-    local $Module::Load::Conditional::CHECK_INC_HASH = 1;
8814
-    if (! defined $ENV{PERL_YAML_BACKEND} ) {
8815
-      _can_load( 'CPAN::Meta::YAML', 0.002 )
8816
-        or croak "CPAN::Meta::YAML 0.002 is not available\n";
8817
-      return "CPAN::Meta::YAML";
8818
-    }
8819
-    else {
8820
-      my $backend = $ENV{PERL_YAML_BACKEND};
8821
-      _can_load( $backend )
8822
-        or croak "Could not load PERL_YAML_BACKEND '$backend'\n";
8823
-      $backend->can("Load")
8824
-        or croak "PERL_YAML_BACKEND '$backend' does not implement Load()\n";
8825
-      return $backend;
8826
-    }
8827
-  }
8828
-  
8829
-  sub json_backend {
8830
-    local $Module::Load::Conditional::CHECK_INC_HASH = 1;
8831
-    if (! $ENV{PERL_JSON_BACKEND} or $ENV{PERL_JSON_BACKEND} eq 'JSON::PP') {
8832
-      _can_load( 'JSON::PP' => 2.27103 )
8833
-        or croak "JSON::PP 2.27103 is not available\n";
8834
-      return 'JSON::PP';
8835
-    }
8836
-    else {
8837
-      _can_load( 'JSON' => 2.5 )
8838
-        or croak  "JSON 2.5 is required for " .
8839
-                  "\$ENV{PERL_JSON_BACKEND} = '$ENV{PERL_JSON_BACKEND}'\n";
8840
-      return "JSON";
8841
-    }
8842
-  }
8843
-  
8844
-  sub _slurp {
8845
-    open my $fh, "<" . IO_LAYER, "$_[0]"
8846
-      or die "can't open $_[0] for reading: $!";
8847
-    return do { local $/; <$fh> };
8848
-  }
8849
-    
8850
-  sub _can_load {
8851
-    my ($module, $version) = @_;
8852
-    (my $file = $module) =~ s{::}{/}g;
8853
-    $file .= ".pm";
8854
-    return 1 if $INC{$file};
8855
-    return 0 if exists $INC{$file}; # prior load failed
8856
-    eval { require $file; 1 }
8857
-      or return 0;
8858
-    if ( defined $version ) {
8859
-      eval { $module->VERSION($version); 1 }
8860
-        or return 0;
8861
-    }
8862
-    return 1;
8863
-  }
8864
-  
8865
-  # Kept for backwards compatibility only
8866
-  # Create an object from a file
8867
-  sub LoadFile ($) {
8868
-    require CPAN::Meta::YAML;
8869
-    return CPAN::Meta::YAML::LoadFile(shift)
8870
-      or die CPAN::Meta::YAML->errstr;
8871
-  }
8872
-  
8873
-  # Parse a document from a string.
8874
-  sub Load ($) {
8875
-    require CPAN::Meta::YAML;
8876
-    return CPAN::Meta::YAML::Load(shift)
8877
-      or die CPAN::Meta::YAML->errstr;
8878
-  }
8879
-  
8880
-  1;
8881
-  
8882
-  __END__
8883
-  
8884
-PARSE_CPAN_META
9593
+  __END__
9594
+  
9595
+  
9596
+MODULE_CPANFILE
8885 9597
 
8886
-$fatpacked{"Try/Tiny.pm"} = <<'TRY_TINY';
8887
-  package Try::Tiny;
9598
+$fatpacked{"Module/Metadata.pm"} = <<'MODULE_METADATA';
9599
+  # -*- mode: cperl; tab-width: 8; indent-tabs-mode: nil; basic-offset: 2 -*-
9600
+  # vim:ts=8:sw=2:et:sta:sts=2
9601
+  package Module::Metadata;
8888 9602
   
8889
-  use strict;
8890
-  #use warnings;
9603
+  # Adapted from Perl-licensed code originally distributed with
9604
+  # Module-Build by Ken Williams
8891 9605
   
8892
-  use vars qw(@EXPORT @EXPORT_OK $VERSION @ISA);
9606
+  # This module provides routines to gather information about
9607
+  # perl modules (assuming this may be expanded in the distant
9608
+  # parrot future to look at other types of modules).
9609
+  
9610
+  use strict;
9611
+  use vars qw($VERSION);
9612
+  $VERSION = '1.000011';
9613
+  $VERSION = eval $VERSION;
8893 9614
   
9615
+  use Carp qw/croak/;
9616
+  use File::Spec;
9617
+  use IO::File;
9618
+  use version 0.87;
8894 9619
   BEGIN {
8895
-  	require Exporter;
8896
-  	@ISA = qw(Exporter);
9620
+    if ($INC{'Log/Contextual.pm'}) {
9621
+      Log::Contextual->import('log_info');
9622
+    } else {
9623
+      *log_info = sub (&) { warn $_[0]->() };
9624
+    }
8897 9625
   }
9626
+  use File::Find qw(find);
8898 9627
   
8899
-  $VERSION = "0.09";
9628
+  my $V_NUM_REGEXP = qr{v?[0-9._]+};  # crudely, a v-string or decimal
8900 9629
   
8901
-  $VERSION = eval $VERSION;
9630
+  my $PKG_REGEXP  = qr{   # match a package declaration
9631
+    ^[\s\{;]*             # intro chars on a line
9632
+    package               # the word 'package'
9633
+    \s+                   # whitespace
9634
+    ([\w:]+)              # a package name
9635
+    \s*                   # optional whitespace
9636
+    ($V_NUM_REGEXP)?        # optional version number
9637
+    \s*                   # optional whitesapce
9638
+    [;\{]                 # semicolon line terminator or block start (since 5.16)
9639
+  }x;
9640
+  
9641
+  my $VARNAME_REGEXP = qr{ # match fully-qualified VERSION name
9642
+    ([\$*])         # sigil - $ or *
9643
+    (
9644
+      (             # optional leading package name
9645
+        (?:::|\')?  # possibly starting like just :: (�  la $::VERSION)
9646
+        (?:\w+(?:::|\'))*  # Foo::Bar:: ...
9647
+      )?
9648
+      VERSION
9649
+    )\b
9650
+  }x;
9651
+  
9652
+  my $VERS_REGEXP = qr{ # match a VERSION definition
9653
+    (?:
9654
+      \(\s*$VARNAME_REGEXP\s*\) # with parens
9655
+    |
9656
+      $VARNAME_REGEXP           # without parens
9657
+    )
9658
+    \s*
9659
+    =[^=~]  # = but not ==, nor =~
9660
+  }x;
9661
+  
9662
+  sub new_from_file {
9663
+    my $class    = shift;
9664
+    my $filename = File::Spec->rel2abs( shift );
9665
+  
9666
+    return undef unless defined( $filename ) && -f $filename;
9667
+    return $class->_init(undef, $filename, @_);
9668
+  }
9669
+  
9670
+  sub new_from_handle {
9671
+    my $class    = shift;
9672
+    my $handle   = shift;
9673
+    my $filename = shift;
9674
+    return undef unless defined($handle) && defined($filename);
9675
+    $filename = File::Spec->rel2abs( $filename );
9676
+  
9677
+    return $class->_init(undef, $filename, @_, handle => $handle);
9678
+  
9679
+  }
9680
+  
9681
+  
9682
+  sub new_from_module {
9683
+    my $class   = shift;
9684
+    my $module  = shift;
9685
+    my %props   = @_;
9686
+  
9687
+    $props{inc} ||= \@INC;
9688
+    my $filename = $class->find_module_by_name( $module, $props{inc} );
9689
+    return undef unless defined( $filename ) && -f $filename;
9690
+    return $class->_init($module, $filename, %props);
9691
+  }
8902 9692
   
8903
-  @EXPORT = @EXPORT_OK = qw(try catch finally);
9693
+  {
9694
+    
9695
+    my $compare_versions = sub {
9696
+      my ($v1, $op, $v2) = @_;
9697
+      $v1 = version->new($v1)
9698
+        unless UNIVERSAL::isa($v1,'version');
9699
+    
9700
+      my $eval_str = "\$v1 $op \$v2";
9701
+      my $result   = eval $eval_str;
9702
+      log_info { "error comparing versions: '$eval_str' $@" } if $@;
9703
+    
9704
+      return $result;
9705
+    };
8904 9706
   
8905
-  $Carp::Internal{+__PACKAGE__}++;
9707
+    my $normalize_version = sub {
9708
+      my ($version) = @_;
9709
+      if ( $version =~ /[=<>!,]/ ) { # logic, not just version
9710
+        # take as is without modification
9711
+      }
9712
+      elsif ( ref $version eq 'version' ) { # version objects
9713
+        $version = $version->is_qv ? $version->normal : $version->stringify;
9714
+      }
9715
+      elsif ( $version =~ /^[^v][^.]*\.[^.]+\./ ) { # no leading v, multiple dots
9716
+        # normalize string tuples without "v": "1.2.3" -> "v1.2.3"
9717
+        $version = "v$version";
9718
+      }
9719
+      else {
9720
+        # leave alone
9721
+      }
9722
+      return $version;
9723
+    };
8906 9724
   
8907
-  # Need to prototype as @ not $$ because of the way Perl evaluates the prototype.
8908
-  # Keeping it at $$ means you only ever get 1 sub because we need to eval in a list
8909
-  # context & not a scalar one
9725
+    # separate out some of the conflict resolution logic
8910 9726
   
8911
-  sub try (&;@) {
8912
-  	my ( $try, @code_refs ) = @_;
9727
+    my $resolve_module_versions = sub {
9728
+      my $packages = shift;
9729
+    
9730
+      my( $file, $version );
9731
+      my $err = '';
9732
+        foreach my $p ( @$packages ) {
9733
+          if ( defined( $p->{version} ) ) {
9734
+    	if ( defined( $version ) ) {
9735
+     	  if ( $compare_versions->( $version, '!=', $p->{version} ) ) {
9736
+    	    $err .= "  $p->{file} ($p->{version})\n";
9737
+    	  } else {
9738
+    	    # same version declared multiple times, ignore
9739
+    	  }
9740
+    	} else {
9741
+    	  $file    = $p->{file};
9742
+    	  $version = $p->{version};
9743
+    	}
9744
+          }
9745
+          $file ||= $p->{file} if defined( $p->{file} );
9746
+        }
9747
+    
9748
+      if ( $err ) {
9749
+        $err = "  $file ($version)\n" . $err;
9750
+      }
9751
+    
9752
+      my %result = (
9753
+        file    => $file,
9754
+        version => $version,
9755
+        err     => $err
9756
+      );
9757
+    
9758
+      return \%result;
9759
+    };
8913 9760
   
8914
-  	# we need to save this here, the eval block will be in scalar context due
8915
-  	# to $failed
8916
-  	my $wantarray = wantarray;
9761
+    sub provides {
9762
+      my $class = shift;
8917 9763
   
8918
-  	my ( $catch, @finally );
9764
+      croak "provides() requires key/value pairs \n" if @_ % 2;
9765
+      my %args = @_;
8919 9766
   
8920
-  	# find labeled blocks in the argument list.
8921
-  	# catch and finally tag the blocks by blessing a scalar reference to them.
8922
-  	foreach my $code_ref (@code_refs) {
8923
-  		next unless $code_ref;
9767
+      croak "provides() takes only one of 'dir' or 'files'\n"
9768
+        if $args{dir} && $args{files};
8924 9769
   
8925
-  		my $ref = ref($code_ref);
9770
+      croak "provides() requires a 'version' argument"
9771
+        unless defined $args{version};
8926 9772
   
8927
-  		if ( $ref eq 'Try::Tiny::Catch' ) {
8928
-  			$catch = ${$code_ref};
8929
-  		} elsif ( $ref eq 'Try::Tiny::Finally' ) {
8930
-  			push @finally, ${$code_ref};
8931
-  		} else {
8932
-  			use Carp;
8933
-  			confess("Unknown code ref type given '${ref}'. Check your usage & try again");
8934
-  		}
8935
-  	}
9773
+      croak "provides() does not support version '$args{version}' metadata"
9774
+          unless grep { $args{version} eq $_ } qw/1.4 2/;
8936 9775
   
8937
-  	# save the value of $@ so we can set $@ back to it in the beginning of the eval
8938
-  	my $prev_error = $@;
9776
+      $args{prefix} = 'lib' unless defined $args{prefix};
8939 9777
   
8940
-  	my ( @ret, $error, $failed );
9778
+      my $p;
9779
+      if ( $args{dir} ) {
9780
+        $p = $class->package_versions_from_directory($args{dir});
9781
+      }
9782
+      else {
9783
+        croak "provides() requires 'files' to be an array reference\n"
9784
+          unless ref $args{files} eq 'ARRAY';
9785
+        $p = $class->package_versions_from_directory($args{files});
9786
+      }
8941 9787
   
8942
-  	# FIXME consider using local $SIG{__DIE__} to accumulate all errors. It's
8943
-  	# not perfect, but we could provide a list of additional errors for
8944
-  	# $catch->();
9788
+      # Now, fix up files with prefix
9789
+      if ( length $args{prefix} ) { # check in case disabled with q{}
9790
+        $args{prefix} =~ s{/$}{};
9791
+        for my $v ( values %$p ) {
9792
+          $v->{file} = "$args{prefix}/$v->{file}";
9793
+        }
9794
+      }
8945 9795
   
8946
-  	{
8947
-  		# localize $@ to prevent clobbering of previous value by a successful
8948
-  		# eval.
8949
-  		local $@;
8950
-  
8951
-  		# failed will be true if the eval dies, because 1 will not be returned
8952
-  		# from the eval body
8953
-  		$failed = not eval {
8954
-  			$@ = $prev_error;
8955
-  
8956
-  			# evaluate the try block in the correct context
8957
-  			if ( $wantarray ) {
8958
-  				@ret = $try->();
8959
-  			} elsif ( defined $wantarray ) {
8960
-  				$ret[0] = $try->();
8961
-  			} else {
8962
-  				$try->();
8963
-  			};
9796
+      return $p
9797
+    }
8964 9798
   
8965
-  			return 1; # properly set $fail to false
8966
-  		};
9799
+    sub package_versions_from_directory {
9800
+      my ( $class, $dir, $files ) = @_;
8967 9801
   
8968
-  		# copy $@ to $error; when we leave this scope, local $@ will revert $@
8969
-  		# back to its previous value
8970
-  		$error = $@;
8971
-  	}
9802
+      my @files;
8972 9803
   
8973
-  	# set up a scope guard to invoke the finally block at the end
8974
-  	my @guards =
8975
-      map { Try::Tiny::ScopeGuard->_new($_, $failed ? $error : ()) }
8976
-      @finally;
8977
-  
8978
-  	# at this point $failed contains a true value if the eval died, even if some
8979
-  	# destructor overwrote $@ as the eval was unwinding.
8980
-  	if ( $failed ) {
8981
-  		# if we got an error, invoke the catch block.
8982
-  		if ( $catch ) {
8983
-  			# This works like given($error), but is backwards compatible and
8984
-  			# sets $_ in the dynamic scope for the body of C<$catch>
8985
-  			for ($error) {
8986
-  				return $catch->($error);
8987
-  			}
9804
+      if ( $files ) {
9805
+        @files = @$files;
9806
+      } else {
9807
+        find( {
9808
+          wanted => sub {
9809
+            push @files, $_ if -f $_ && /\.pm$/;
9810
+          },
9811
+          no_chdir => 1,
9812
+        }, $dir );
9813
+      }
8988 9814
   
8989
-  			# in case when() was used without an explicit return, the C<for>
8990
-  			# loop will be aborted and there's no useful return value
8991
-  		}
9815
+      # First, we enumerate all packages & versions,
9816
+      # separating into primary & alternative candidates
9817
+      my( %prime, %alt );
9818
+      foreach my $file (@files) {
9819
+        my $mapped_filename = File::Spec::Unix->abs2rel( $file, $dir );
9820
+        my @path = split( /\//, $mapped_filename );
9821
+        (my $prime_package = join( '::', @path )) =~ s/\.pm$//;
9822
+    
9823
+        my $pm_info = $class->new_from_file( $file );
9824
+    
9825
+        foreach my $package ( $pm_info->packages_inside ) {
9826
+          next if $package eq 'main';  # main can appear numerous times, ignore
9827
+          next if $package eq 'DB';    # special debugging package, ignore
9828
+          next if grep /^_/, split( /::/, $package ); # private package, ignore
9829
+    
9830
+          my $version = $pm_info->version( $package );
9831
+    
9832
+          $prime_package = $package if lc($prime_package) eq lc($package);
9833
+          if ( $package eq $prime_package ) {
9834
+            if ( exists( $prime{$package} ) ) {
9835
+              croak "Unexpected conflict in '$package'; multiple versions found.\n";
9836
+            } else {
9837
+              $mapped_filename = "$package.pm" if lc("$package.pm") eq lc($mapped_filename);
9838
+              $prime{$package}{file} = $mapped_filename;
9839
+              $prime{$package}{version} = $version if defined( $version );
9840
+            }
9841
+          } else {
9842
+            push( @{$alt{$package}}, {
9843
+                                      file    => $mapped_filename,
9844
+                                      version => $version,
9845
+                                     } );
9846
+          }
9847
+        }
9848
+      }
9849
+    
9850
+      # Then we iterate over all the packages found above, identifying conflicts
9851
+      # and selecting the "best" candidate for recording the file & version
9852
+      # for each package.
9853
+      foreach my $package ( keys( %alt ) ) {
9854
+        my $result = $resolve_module_versions->( $alt{$package} );
9855
+    
9856
+        if ( exists( $prime{$package} ) ) { # primary package selected
9857
+    
9858
+          if ( $result->{err} ) {
9859
+    	# Use the selected primary package, but there are conflicting
9860
+    	# errors among multiple alternative packages that need to be
9861
+    	# reported
9862
+            log_info {
9863
+    	    "Found conflicting versions for package '$package'\n" .
9864
+    	    "  $prime{$package}{file} ($prime{$package}{version})\n" .
9865
+    	    $result->{err}
9866
+            };
9867
+    
9868
+          } elsif ( defined( $result->{version} ) ) {
9869
+    	# There is a primary package selected, and exactly one
9870
+    	# alternative package
9871
+    
9872
+    	if ( exists( $prime{$package}{version} ) &&
9873
+    	     defined( $prime{$package}{version} ) ) {
9874
+    	  # Unless the version of the primary package agrees with the
9875
+    	  # version of the alternative package, report a conflict
9876
+    	  if ( $compare_versions->(
9877
+                   $prime{$package}{version}, '!=', $result->{version}
9878
+                 )
9879
+               ) {
8992 9880
   
8993
-  		return;
8994
-  	} else {
8995
-  		# no failure, $@ is back to what it was, everything is fine
8996
-  		return $wantarray ? @ret : $ret[0];
8997
-  	}
8998
-  }
9881
+              log_info {
9882
+                "Found conflicting versions for package '$package'\n" .
9883
+    	      "  $prime{$package}{file} ($prime{$package}{version})\n" .
9884
+    	      "  $result->{file} ($result->{version})\n"
9885
+              };
9886
+    	  }
9887
+    
9888
+    	} else {
9889
+    	  # The prime package selected has no version so, we choose to
9890
+    	  # use any alternative package that does have a version
9891
+    	  $prime{$package}{file}    = $result->{file};
9892
+    	  $prime{$package}{version} = $result->{version};
9893
+    	}
9894
+    
9895
+          } else {
9896
+    	# no alt package found with a version, but we have a prime
9897
+    	# package so we use it whether it has a version or not
9898
+          }
9899
+    
9900
+        } else { # No primary package was selected, use the best alternative
9901
+    
9902
+          if ( $result->{err} ) {
9903
+            log_info {
9904
+              "Found conflicting versions for package '$package'\n" .
9905
+    	    $result->{err}
9906
+            };
9907
+          }
9908
+    
9909
+          # Despite possible conflicting versions, we choose to record
9910
+          # something rather than nothing
9911
+          $prime{$package}{file}    = $result->{file};
9912
+          $prime{$package}{version} = $result->{version}
9913
+    	  if defined( $result->{version} );
9914
+        }
9915
+      }
9916
+    
9917
+      # Normalize versions.  Can't use exists() here because of bug in YAML::Node.
9918
+      # XXX "bug in YAML::Node" comment seems irrelvant -- dagolden, 2009-05-18
9919
+      for (grep defined $_->{version}, values %prime) {
9920
+        $_->{version} = $normalize_version->( $_->{version} );
9921
+      }
9922
+    
9923
+      return \%prime;
9924
+    }
9925
+  } 
9926
+    
8999 9927
   
9000
-  sub catch (&;@) {
9001
-  	my ( $block, @rest ) = @_;
9928
+  sub _init {
9929
+    my $class    = shift;
9930
+    my $module   = shift;
9931
+    my $filename = shift;
9932
+    my %props = @_;
9002 9933
   
9003
-  	return (
9004
-  		bless(\$block, 'Try::Tiny::Catch'),
9005
-  		@rest,
9006
-  	);
9007
-  }
9934
+    my $handle = delete $props{handle};
9935
+    my( %valid_props, @valid_props );
9936
+    @valid_props = qw( collect_pod inc );
9937
+    @valid_props{@valid_props} = delete( @props{@valid_props} );
9938
+    warn "Unknown properties: @{[keys %props]}\n" if scalar( %props );
9008 9939
   
9009
-  sub finally (&;@) {
9010
-  	my ( $block, @rest ) = @_;
9940
+    my %data = (
9941
+      module       => $module,
9942
+      filename     => $filename,
9943
+      version      => undef,
9944
+      packages     => [],
9945
+      versions     => {},
9946
+      pod          => {},
9947
+      pod_headings => [],
9948
+      collect_pod  => 0,
9011 9949
   
9012
-  	return (
9013
-  		bless(\$block, 'Try::Tiny::Finally'),
9014
-  		@rest,
9015
-  	);
9016
-  }
9950
+      %valid_props,
9951
+    );
9017 9952
   
9018
-  {
9019
-    package # hide from PAUSE
9020
-      Try::Tiny::ScopeGuard;
9953
+    my $self = bless(\%data, $class);
9021 9954
   
9022
-    sub _new {
9023
-      shift;
9024
-      bless [ @_ ];
9955
+    if ( $handle ) {
9956
+      $self->_parse_fh($handle);
9025 9957
     }
9026
-  
9027
-    sub DESTROY {
9028
-      my @guts = @{ shift() };
9029
-      my $code = shift @guts;
9030
-      $code->(@guts);
9958
+    else {
9959
+      $self->_parse_file();
9031 9960
     }
9032
-  }
9033
-  
9034
-  __PACKAGE__
9035
-  
9036
-  __END__
9037
-  
9038
-TRY_TINY
9039
-
9040
-$fatpacked{"lib/core/only.pm"} = <<'LIB_CORE_ONLY';
9041
-  package lib::core::only;
9042
-  
9043
-  use strict;
9044
-  use warnings FATAL => 'all';
9045
-  use Config;
9046
-  
9047
-  sub import {
9048
-    @INC = @Config{qw(privlibexp archlibexp)};
9049
-    return
9050
-  }
9051
-  
9052
-  1;
9053
-LIB_CORE_ONLY
9054
-
9055
-$fatpacked{"local/lib.pm"} = <<'LOCAL_LIB';
9056
-  use strict;
9057
-  use warnings;
9058
-  
9059
-  package local::lib;
9060
-  
9061
-  use 5.008001; # probably works with earlier versions but I'm not supporting them
9062
-                # (patches would, of course, be welcome)
9063
-  
9064
-  use File::Spec ();
9065
-  use File::Path ();
9066
-  use Carp ();
9067
-  use Config;
9068
-  
9069
-  our $VERSION = '1.008001'; # 1.8.1
9070
-  
9071
-  our @KNOWN_FLAGS = qw(--self-contained);
9072
-  
9073
-  sub import {
9074
-    my ($class, @args) = @_;
9075
-  
9076
-    # Remember what PERL5LIB was when we started
9077
-    my $perl5lib = $ENV{PERL5LIB} || '';
9078 9961
   
9079
-    my %arg_store;
9080
-    for my $arg (@args) {
9081
-      # check for lethal dash first to stop processing before causing problems
9082
-      if ($arg =~ /−/) {
9083
-        die <<'DEATH';
9084
-  WHOA THERE! It looks like you've got some fancy dashes in your commandline!
9085
-  These are *not* the traditional -- dashes that software recognizes. You
9086
-  probably got these by copy-pasting from the perldoc for this module as
9087
-  rendered by a UTF8-capable formatter. This most typically happens on an OS X
9088
-  terminal, but can happen elsewhere too. Please try again after replacing the
9089
-  dashes with normal minus signs.
9090
-  DEATH
9091
-      }
9092
-      elsif(grep { $arg eq $_ } @KNOWN_FLAGS) {
9093
-        (my $flag = $arg) =~ s/--//;
9094
-        $arg_store{$flag} = 1;
9095
-      }
9096
-      elsif($arg =~ /^--/) {
9097
-        die "Unknown import argument: $arg";
9962
+    unless($self->{module} and length($self->{module})) {
9963
+      my ($v, $d, $f) = File::Spec->splitpath($self->{filename});
9964
+      if($f =~ /\.pm$/) {
9965
+        $f =~ s/\..+$//;
9966
+        my @candidates = grep /$f$/, @{$self->{packages}};
9967
+        $self->{module} = shift(@candidates); # punt
9098 9968
       }
9099 9969
       else {
9100
-        # assume that what's left is a path
9101
-        $arg_store{path} = $arg;
9970
+        if(grep /main/, @{$self->{packages}}) {
9971
+          $self->{module} = 'main';
9972
+        }
9973
+        else {
9974
+          $self->{module} = $self->{packages}[0] || '';
9975
+        }
9102 9976
       }
9103 9977
     }
9104 9978
   
9105
-    if($arg_store{'self-contained'}) {
9106
-      die "FATAL: The local::lib --self-contained flag has never worked reliably and the original author, Mark Stosberg, was unable or unwilling to maintain it. As such, this flag has been removed from the local::lib codebase in order to prevent misunderstandings and potentially broken builds. The local::lib authors recommend that you look at the lib::core::only module shipped with this distribution in order to create a more robust environment that is equivalent to what --self-contained provided (although quite possibly not what you originally thought it provided due to the poor quality of the documentation, for which we apologise).\n";
9107
-    }
9108
-  
9109
-    $arg_store{path} = $class->resolve_path($arg_store{path});
9110
-    $class->setup_local_lib_for($arg_store{path});
9111
-  
9112
-    for (@INC) { # Untaint @INC
9113
-      next if ref; # Skip entry if it is an ARRAY, CODE, blessed, etc.
9114
-      m/(.*)/ and $_ = $1;
9115
-    }
9979
+    $self->{version} = $self->{versions}{$self->{module}}
9980
+        if defined( $self->{module} );
9981
+  
9982
+    return $self;
9116 9983
   }
9117 9984
   
9118
-  sub pipeline;
9985
+  # class method
9986
+  sub _do_find_module {
9987
+    my $class   = shift;
9988
+    my $module  = shift || croak 'find_module_by_name() requires a package name';
9989
+    my $dirs    = shift || \@INC;
9119 9990
   
9120
-  sub pipeline {
9121
-    my @methods = @_;
9122
-    my $last = pop(@methods);
9123
-    if (@methods) {
9124
-      \sub {
9125
-        my ($obj, @args) = @_;
9126
-        $obj->${pipeline @methods}(
9127
-          $obj->$last(@args)
9128
-        );
9129
-      };
9130
-    } else {
9131
-      \sub {
9132
-        shift->$last(@_);
9133
-      };
9991
+    my $file = File::Spec->catfile(split( /::/, $module));
9992
+    foreach my $dir ( @$dirs ) {
9993
+      my $testfile = File::Spec->catfile($dir, $file);
9994
+      return [ File::Spec->rel2abs( $testfile ), $dir ]
9995
+  	if -e $testfile and !-d _;  # For stuff like ExtUtils::xsubpp
9996
+      return [ File::Spec->rel2abs( "$testfile.pm" ), $dir ]
9997
+  	if -e "$testfile.pm";
9134 9998
     }
9999
+    return;
9135 10000
   }
9136 10001
   
9137
-  sub _uniq {
9138
-      my %seen;
9139
-      grep { ! $seen{$_}++ } @_;
10002
+  # class method
10003
+  sub find_module_by_name {
10004
+    my $found = shift()->_do_find_module(@_) or return;
10005
+    return $found->[0];
9140 10006
   }
9141 10007
   
9142
-  sub resolve_path {
9143
-    my ($class, $path) = @_;
9144
-    $class->${pipeline qw(
9145
-      resolve_relative_path
9146
-      resolve_home_path
9147
-      resolve_empty_path
9148
-    )}($path);
10008
+  # class method
10009
+  sub find_module_dir_by_name {
10010
+    my $found = shift()->_do_find_module(@_) or return;
10011
+    return $found->[1];
9149 10012
   }
9150 10013
   
9151
-  sub resolve_empty_path {
9152
-    my ($class, $path) = @_;
9153
-    if (defined $path) {
9154
-      $path;
9155
-    } else {
9156
-      '~/perl5';
9157
-    }
9158
-  }
9159 10014
   
9160
-  sub resolve_home_path {
9161
-    my ($class, $path) = @_;
9162
-    return $path unless ($path =~ /^~/);
9163
-    my ($user) = ($path =~ /^~([^\/]+)/); # can assume ^~ so undef for 'us'
9164
-    my $tried_file_homedir;
9165
-    my $homedir = do {
9166
-      if (eval { require File::HomeDir } && $File::HomeDir::VERSION >= 0.65) {
9167
-        $tried_file_homedir = 1;
9168
-        if (defined $user) {
9169
-          File::HomeDir->users_home($user);
9170
-        } else {
9171
-          File::HomeDir->my_home;
9172
-        }
9173
-      } else {
9174
-        if (defined $user) {
9175
-          (getpwnam $user)[7];
9176
-        } else {
9177
-          if (defined $ENV{HOME}) {
9178
-            $ENV{HOME};
9179
-          } else {
9180
-            (getpwuid $<)[7];
9181
-          }
9182
-        }
10015
+  # given a line of perl code, attempt to parse it if it looks like a
10016
+  # $VERSION assignment, returning sigil, full name, & package name
10017
+  sub _parse_version_expression {
10018
+    my $self = shift;
10019
+    my $line = shift;
10020
+  
10021
+    my( $sig, $var, $pkg );
10022
+    if ( $line =~ /$VERS_REGEXP/o ) {
10023
+      ( $sig, $var, $pkg ) = $2 ? ( $1, $2, $3 ) : ( $4, $5, $6 );
10024
+      if ( $pkg ) {
10025
+        $pkg = ($pkg eq '::') ? 'main' : $pkg;
10026
+        $pkg =~ s/::$//;
9183 10027
       }
9184
-    };
9185
-    unless (defined $homedir) {
9186
-      Carp::croak(
9187
-        "Couldn't resolve homedir for "
9188
-        .(defined $user ? $user : 'current user')
9189
-        .($tried_file_homedir ? '' : ' - consider installing File::HomeDir')
9190
-      );
9191 10028
     }
9192
-    $path =~ s/^~[^\/]*/$homedir/;
9193
-    $path;
10029
+  
10030
+    return ( $sig, $var, $pkg );
9194 10031
   }
9195 10032
   
9196
-  sub resolve_relative_path {
9197
-    my ($class, $path) = @_;
9198
-    $path = File::Spec->rel2abs($path);
10033
+  sub _parse_file {
10034
+    my $self = shift;
10035
+  
10036
+    my $filename = $self->{filename};
10037
+    my $fh = IO::File->new( $filename )
10038
+      or croak( "Can't open '$filename': $!" );
10039
+  
10040
+    $self->_handle_bom($fh, $filename);
10041
+  
10042
+    $self->_parse_fh($fh);
9199 10043
   }
9200 10044
   
9201
-  sub setup_local_lib_for {
9202
-    my ($class, $path) = @_;
9203
-    $path = $class->ensure_dir_structure_for($path);
9204
-    if ($0 eq '-') {
9205
-      $class->print_environment_vars_for($path);
9206
-      exit 0;
10045
+  # Look for a UTF-8/UTF-16BE/UTF-16LE BOM at the beginning of the stream.
10046
+  # If there's one, then skip it and set the :encoding layer appropriately.
10047
+  sub _handle_bom {
10048
+    my ($self, $fh, $filename) = @_;
10049
+  
10050
+    my $pos = $fh->getpos;
10051
+    return unless defined $pos;
10052
+  
10053
+    my $buf = ' ' x 2;
10054
+    my $count = $fh->read( $buf, length $buf );
10055
+    return unless defined $count and $count >= 2;
10056
+  
10057
+    my $encoding;
10058
+    if ( $buf eq "\x{FE}\x{FF}" ) {
10059
+      $encoding = 'UTF-16BE';
10060
+    } elsif ( $buf eq "\x{FF}\x{FE}" ) {
10061
+      $encoding = 'UTF-16LE';
10062
+    } elsif ( $buf eq "\x{EF}\x{BB}" ) {
10063
+      $buf = ' ';
10064
+      $count = $fh->read( $buf, length $buf );
10065
+      if ( defined $count and $count >= 1 and $buf eq "\x{BF}" ) {
10066
+        $encoding = 'UTF-8';
10067
+      }
10068
+    }
10069
+  
10070
+    if ( defined $encoding ) {
10071
+      if ( "$]" >= 5.008 ) {
10072
+        # $fh->binmode requires perl 5.10
10073
+        binmode( $fh, ":encoding($encoding)" );
10074
+      }
9207 10075
     } else {
9208
-      $class->setup_env_hash_for($path);
9209
-      @INC = _uniq(split($Config{path_sep}, $ENV{PERL5LIB}), @INC);
10076
+      $fh->setpos($pos)
10077
+        or croak( sprintf "Can't reset position to the top of '$filename'" );
9210 10078
     }
9211
-  }
9212 10079
   
9213
-  sub install_base_bin_path {
9214
-    my ($class, $path) = @_;
9215
-    File::Spec->catdir($path, 'bin');
10080
+    return $encoding;
9216 10081
   }
9217 10082
   
9218
-  sub install_base_perl_path {
9219
-    my ($class, $path) = @_;
9220
-    File::Spec->catdir($path, 'lib', 'perl5');
9221
-  }
10083
+  sub _parse_fh {
10084
+    my ($self, $fh) = @_;
9222 10085
   
9223
-  sub install_base_arch_path {
9224
-    my ($class, $path) = @_;
9225
-    File::Spec->catdir($class->install_base_perl_path($path), $Config{archname});
9226
-  }
10086
+    my( $in_pod, $seen_end, $need_vers ) = ( 0, 0, 0 );
10087
+    my( @pkgs, %vers, %pod, @pod );
10088
+    my $pkg = 'main';
10089
+    my $pod_sect = '';
10090
+    my $pod_data = '';
9227 10091
   
9228
-  sub ensure_dir_structure_for {
9229
-    my ($class, $path) = @_;
9230
-    unless (-d $path) {
9231
-      warn "Attempting to create directory ${path}\n";
9232
-    }
9233
-    File::Path::mkpath($path);
9234
-    # Need to have the path exist to make a short name for it, so
9235
-    # converting to a short name here.
9236
-    $path = Win32::GetShortPathName($path) if $^O eq 'MSWin32';
10092
+    while (defined( my $line = <$fh> )) {
10093
+      my $line_num = $.;
9237 10094
   
9238
-    return $path;
9239
-  }
10095
+      chomp( $line );
9240 10096
   
9241
-  sub INTERPOLATE_ENV () { 1 }
9242
-  sub LITERAL_ENV     () { 0 }
10097
+      # From toke.c : any line that begins by "=X", where X is an alphabetic
10098
+      # character, introduces a POD segment.
10099
+      my $is_cut;
10100
+      if ( $line =~ /^=([a-zA-Z].*)/ ) {
10101
+        my $cmd = $1;
10102
+        # Then it goes back to Perl code for "=cutX" where X is a non-alphabetic
10103
+        # character (which includes the newline, but here we chomped it away).
10104
+        $is_cut = $cmd =~ /^cut(?:[^a-zA-Z]|$)/;
10105
+        $in_pod = !$is_cut;
10106
+      }
10107
+  
10108
+      if ( $in_pod ) {
10109
+  
10110
+        if ( $line =~ /^=head[1-4]\s+(.+)\s*$/ ) {
10111
+  	push( @pod, $1 );
10112
+  	if ( $self->{collect_pod} && length( $pod_data ) ) {
10113
+            $pod{$pod_sect} = $pod_data;
10114
+            $pod_data = '';
10115
+          }
10116
+  	$pod_sect = $1;
10117
+  
10118
+        } elsif ( $self->{collect_pod} ) {
10119
+  	$pod_data .= "$line\n";
9243 10120
   
9244
-  sub guess_shelltype {
9245
-    my $shellbin = 'sh';
9246
-    if(defined $ENV{'SHELL'}) {
9247
-        my @shell_bin_path_parts = File::Spec->splitpath($ENV{'SHELL'});
9248
-        $shellbin = $shell_bin_path_parts[-1];
9249
-    }
9250
-    my $shelltype = do {
9251
-        local $_ = $shellbin;
9252
-        if(/csh/) {
9253
-            'csh'
9254
-        } else {
9255
-            'bourne'
9256 10121
         }
9257
-    };
9258 10122
   
9259
-    # Both Win32 and Cygwin have $ENV{COMSPEC} set.
9260
-    if (defined $ENV{'COMSPEC'} && $^O ne 'cygwin') {
9261
-        my @shell_bin_path_parts = File::Spec->splitpath($ENV{'COMSPEC'});
9262
-        $shellbin = $shell_bin_path_parts[-1];
9263
-           $shelltype = do {
9264
-                   local $_ = $shellbin;
9265
-                   if(/command\.com/) {
9266
-                           'win32'
9267
-                   } elsif(/cmd\.exe/) {
9268
-                           'win32'
9269
-                   } elsif(/4nt\.exe/) {
9270
-                           'win32'
9271
-                   } else {
9272
-                           $shelltype
9273
-                   }
9274
-           };
9275
-    }
9276
-    return $shelltype;
9277
-  }
10123
+      } elsif ( $is_cut ) {
9278 10124
   
9279
-  sub print_environment_vars_for {
9280
-    my ($class, $path) = @_;
9281
-    print $class->environment_vars_string_for($path);
9282
-  }
10125
+        if ( $self->{collect_pod} && length( $pod_data ) ) {
10126
+          $pod{$pod_sect} = $pod_data;
10127
+          $pod_data = '';
10128
+        }
10129
+        $pod_sect = '';
9283 10130
   
9284
-  sub environment_vars_string_for {
9285
-    my ($class, $path) = @_;
9286
-    my @envs = $class->build_environment_vars_for($path, LITERAL_ENV);
9287
-    my $out = '';
10131
+      } else {
9288 10132
   
9289
-    # rather basic csh detection, goes on the assumption that something won't
9290
-    # call itself csh unless it really is. also, default to bourne in the
9291
-    # pathological situation where a user doesn't have $ENV{SHELL} defined.
9292
-    # note also that shells with funny names, like zoid, are assumed to be
9293
-    # bourne.
10133
+        # Skip comments in code
10134
+        next if $line =~ /^\s*#/;
9294 10135
   
9295
-    my $shelltype = $class->guess_shelltype;
10136
+        # Would be nice if we could also check $in_string or something too
10137
+        last if $line =~ /^__(?:DATA|END)__$/;
9296 10138
   
9297
-    while (@envs) {
9298
-      my ($name, $value) = (shift(@envs), shift(@envs));
9299
-      $value =~ s/(\\")/\\$1/g;
9300
-      $out .= $class->${\"build_${shelltype}_env_declaration"}($name, $value);
9301
-    }
9302
-    return $out;
9303
-  }
10139
+        # parse $line to see if it's a $VERSION declaration
10140
+        my( $vers_sig, $vers_fullname, $vers_pkg ) =
10141
+            ($line =~ /VERSION/)
10142
+                ? $self->_parse_version_expression( $line )
10143
+                : ();
9304 10144
   
9305
-  # simple routines that take two arguments: an %ENV key and a value. return
9306
-  # strings that are suitable for passing directly to the relevant shell to set
9307
-  # said key to said value.
9308
-  sub build_bourne_env_declaration {
9309
-    my $class = shift;
9310
-    my($name, $value) = @_;
9311
-    return qq{export ${name}="${value}"\n};
9312
-  }
10145
+        if ( $line =~ /$PKG_REGEXP/o ) {
10146
+          $pkg = $1;
10147
+          push( @pkgs, $pkg ) unless grep( $pkg eq $_, @pkgs );
10148
+          $vers{$pkg} = $2 unless exists( $vers{$pkg} );
10149
+          $need_vers = defined $2 ? 0 : 1;
9313 10150
   
9314
-  sub build_csh_env_declaration {
9315
-    my $class = shift;
9316
-    my($name, $value) = @_;
9317
-    return qq{setenv ${name} "${value}"\n};
9318
-  }
10151
+        # VERSION defined with full package spec, i.e. $Module::VERSION
10152
+        } elsif ( $vers_fullname && $vers_pkg ) {
10153
+  	push( @pkgs, $vers_pkg ) unless grep( $vers_pkg eq $_, @pkgs );
10154
+  	$need_vers = 0 if $vers_pkg eq $pkg;
9319 10155
   
9320
-  sub build_win32_env_declaration {
9321
-    my $class = shift;
9322
-    my($name, $value) = @_;
9323
-    return qq{set ${name}=${value}\n};
9324
-  }
10156
+  	unless ( defined $vers{$vers_pkg} && length $vers{$vers_pkg} ) {
10157
+  	  $vers{$vers_pkg} =
10158
+  	    $self->_evaluate_version_line( $vers_sig, $vers_fullname, $line );
10159
+  	}
9325 10160
   
9326
-  sub setup_env_hash_for {
9327
-    my ($class, $path) = @_;
9328
-    my %envs = $class->build_environment_vars_for($path, INTERPOLATE_ENV);
9329
-    @ENV{keys %envs} = values %envs;
9330
-  }
10161
+        # first non-comment line in undeclared package main is VERSION
10162
+        } elsif ( !exists($vers{main}) && $pkg eq 'main' && $vers_fullname ) {
10163
+  	$need_vers = 0;
10164
+  	my $v =
10165
+  	  $self->_evaluate_version_line( $vers_sig, $vers_fullname, $line );
10166
+  	$vers{$pkg} = $v;
10167
+  	push( @pkgs, 'main' );
9331 10168
   
9332
-  sub build_environment_vars_for {
9333
-    my ($class, $path, $interpolate) = @_;
9334
-    return (
9335
-      PERL_LOCAL_LIB_ROOT => $path,
9336
-      PERL_MB_OPT => "--install_base ${path}",
9337
-      PERL_MM_OPT => "INSTALL_BASE=${path}",
9338
-      PERL5LIB => join($Config{path_sep},
9339
-                    $class->install_base_arch_path($path),
9340
-                    $class->install_base_perl_path($path),
9341
-                    (($ENV{PERL5LIB}||()) ?
9342
-                      ($interpolate == INTERPOLATE_ENV
9343
-                        ? ($ENV{PERL5LIB})
9344
-                        : (($^O ne 'MSWin32') ? '$PERL5LIB' : '%PERL5LIB%' ))
9345
-                      : ())
9346
-                  ),
9347
-      PATH => join($Config{path_sep},
9348
-                $class->install_base_bin_path($path),
9349
-                ($interpolate == INTERPOLATE_ENV
9350
-                  ? ($ENV{PATH}||())
9351
-                  : (($^O ne 'MSWin32') ? '$PATH' : '%PATH%' ))
9352
-               ),
9353
-    )
9354
-  }
10169
+        # first non-comment line in undeclared package defines package main
10170
+        } elsif ( !exists($vers{main}) && $pkg eq 'main' && $line =~ /\w+/ ) {
10171
+  	$need_vers = 1;
10172
+  	$vers{main} = '';
10173
+  	push( @pkgs, 'main' );
9355 10174
   
9356
-  1;
9357
-LOCAL_LIB
9358
-
9359
-$fatpacked{"parent.pm"} = <<'PARENT';
9360
-  package parent;
9361
-  use strict;
9362
-  use vars qw($VERSION);
9363
-  $VERSION = '0.225';
10175
+        # only keep if this is the first $VERSION seen
10176
+        } elsif ( $vers_fullname && $need_vers ) {
10177
+  	$need_vers = 0;
10178
+  	my $v =
10179
+  	  $self->_evaluate_version_line( $vers_sig, $vers_fullname, $line );
9364 10180
   
9365
-  sub import {
9366
-      my $class = shift;
9367 10181
   
9368
-      my $inheritor = caller(0);
10182
+  	unless ( defined $vers{$pkg} && length $vers{$pkg} ) {
10183
+  	  $vers{$pkg} = $v;
10184
+  	} 
9369 10185
   
9370
-      if ( @_ and $_[0] eq '-norequire' ) {
9371
-          shift @_;
9372
-      } else {
9373
-          for ( my @filename = @_ ) {
9374
-              if ( $_ eq $inheritor ) {
9375
-                  warn "Class '$inheritor' tried to inherit from itself\n";
9376
-              };
10186
+        }
9377 10187
   
9378
-              s{::|'}{/}g;
9379
-              require "$_.pm"; # dies if the file is not found
9380
-          }
9381 10188
       }
9382 10189
   
9383
-      {
9384
-          no strict 'refs';
9385
-          push @{"$inheritor\::ISA"}, @_;
9386
-      };
9387
-  };
10190
+    }
9388 10191
   
9389
-  "All your base are belong to us"
10192
+    if ( $self->{collect_pod} && length($pod_data) ) {
10193
+      $pod{$pod_sect} = $pod_data;
10194
+    }
9390 10195
   
9391
-  __END__
10196
+    $self->{versions} = \%vers;
10197
+    $self->{packages} = \@pkgs;
10198
+    $self->{pod} = \%pod;
10199
+    $self->{pod_headings} = \@pod;
10200
+  }
9392 10201
   
9393
-PARENT
9394
-
9395
-$fatpacked{"version.pm"} = <<'VERSION';
9396
-  #!perl -w
9397
-  package version;
10202
+  {
10203
+  my $pn = 0;
10204
+  sub _evaluate_version_line {
10205
+    my $self = shift;
10206
+    my( $sigil, $var, $line ) = @_;
9398 10207
   
9399
-  use 5.005_04;
9400
-  use strict;
10208
+    # Some of this code came from the ExtUtils:: hierarchy.
9401 10209
   
9402
-  use vars qw(@ISA $VERSION $CLASS $STRICT $LAX *declare *qv);
10210
+    # We compile into $vsub because 'use version' would cause
10211
+    # compiletime/runtime issues with local()
10212
+    my $vsub;
10213
+    $pn++; # everybody gets their own package
10214
+    my $eval = qq{BEGIN { q#  Hide from _packages_inside()
10215
+      #; package Module::Metadata::_version::p$pn;
10216
+      use version;
10217
+      no strict;
9403 10218
   
9404
-  $VERSION = 0.88;
10219
+        \$vsub = sub {
10220
+          local $sigil$var;
10221
+          \$$var=undef;
10222
+          $line;
10223
+          \$$var
10224
+        };
10225
+    }};
9405 10226
   
9406
-  $CLASS = 'version';
10227
+    local $^W;
10228
+    # Try to get the $VERSION
10229
+    eval $eval;
10230
+    # some modules say $VERSION = $Foo::Bar::VERSION, but Foo::Bar isn't
10231
+    # installed, so we need to hunt in ./lib for it
10232
+    if ( $@ =~ /Can't locate/ && -d 'lib' ) {
10233
+      local @INC = ('lib',@INC);
10234
+      eval $eval;
10235
+    }
10236
+    warn "Error evaling version line '$eval' in $self->{filename}: $@\n"
10237
+      if $@;
10238
+    (ref($vsub) eq 'CODE') or
10239
+      croak "failed to build version sub for $self->{filename}";
10240
+    my $result = eval { $vsub->() };
10241
+    croak "Could not get version from $self->{filename} by executing:\n$eval\n\nThe fatal error was: $@\n"
10242
+      if $@;
9407 10243
   
9408
-  #--------------------------------------------------------------------------#
9409
-  # Version regexp components
9410
-  #--------------------------------------------------------------------------#
10244
+    # Upgrade it into a version object
10245
+    my $version = eval { _dwim_version($result) };
9411 10246
   
9412
-  # Fraction part of a decimal version number.  This is a common part of
9413
-  # both strict and lax decimal versions
10247
+    croak "Version '$result' from $self->{filename} does not appear to be valid:\n$eval\n\nThe fatal error was: $@\n"
10248
+      unless defined $version; # "0" is OK!
9414 10249
   
9415
-  my $FRACTION_PART = qr/\.[0-9]+/;
10250
+    return $version;
10251
+  }
10252
+  }
9416 10253
   
9417
-  # First part of either decimal or dotted-decimal strict version number.
9418
-  # Unsigned integer with no leading zeroes (except for zero itself) to
9419
-  # avoid confusion with octal.
10254
+  # Try to DWIM when things fail the lax version test in obvious ways
10255
+  {
10256
+    my @version_prep = (
10257
+      # Best case, it just works
10258
+      sub { return shift },
9420 10259
   
9421
-  my $STRICT_INTEGER_PART = qr/0|[1-9][0-9]*/;
10260
+      # If we still don't have a version, try stripping any
10261
+      # trailing junk that is prohibited by lax rules
10262
+      sub {
10263
+        my $v = shift;
10264
+        $v =~ s{([0-9])[a-z-].*$}{$1}i; # 1.23-alpha or 1.23b
10265
+        return $v;
10266
+      },
9422 10267
   
9423
-  # First part of either decimal or dotted-decimal lax version number.
9424
-  # Unsigned integer, but allowing leading zeros.  Always interpreted
9425
-  # as decimal.  However, some forms of the resulting syntax give odd
9426
-  # results if used as ordinary Perl expressions, due to how perl treats
9427
-  # octals.  E.g.
9428
-  #   version->new("010" ) == 10
9429
-  #   version->new( 010  ) == 8
9430
-  #   version->new( 010.2) == 82  # "8" . "2"
10268
+      # Activestate apparently creates custom versions like '1.23_45_01', which
10269
+      # cause version.pm to think it's an invalid alpha.  So check for that
10270
+      # and strip them
10271
+      sub {
10272
+        my $v = shift;
10273
+        my $num_dots = () = $v =~ m{(\.)}g;
10274
+        my $num_unders = () = $v =~ m{(_)}g;
10275
+        my $leading_v = substr($v,0,1) eq 'v';
10276
+        if ( ! $leading_v && $num_dots < 2 && $num_unders > 1 ) {
10277
+          $v =~ s{_}{}g;
10278
+          $num_unders = () = $v =~ m{(_)}g;
10279
+        }
10280
+        return $v;
10281
+      },
9431 10282
   
9432
-  my $LAX_INTEGER_PART = qr/[0-9]+/;
10283
+      # Worst case, try numifying it like we would have before version objects
10284
+      sub {
10285
+        my $v = shift;
10286
+        no warnings 'numeric';
10287
+        return 0 + $v;
10288
+      },
9433 10289
   
9434
-  # Second and subsequent part of a strict dotted-decimal version number.
9435
-  # Leading zeroes are permitted, and the number is always decimal.
9436
-  # Limited to three digits to avoid overflow when converting to decimal
9437
-  # form and also avoid problematic style with excessive leading zeroes.
10290
+    );
9438 10291
   
9439
-  my $STRICT_DOTTED_DECIMAL_PART = qr/\.[0-9]{1,3}/;
10292
+    sub _dwim_version {
10293
+      my ($result) = shift;
9440 10294
   
9441
-  # Second and subsequent part of a lax dotted-decimal version number.
9442
-  # Leading zeroes are permitted, and the number is always decimal.  No
9443
-  # limit on the numerical value or number of digits, so there is the
9444
-  # possibility of overflow when converting to decimal form.
10295
+      return $result if ref($result) eq 'version';
9445 10296
   
9446
-  my $LAX_DOTTED_DECIMAL_PART = qr/\.[0-9]+/;
10297
+      my ($version, $error);
10298
+      for my $f (@version_prep) {
10299
+        $result = $f->($result);
10300
+        $version = eval { version->new($result) };
10301
+        $error ||= $@ if $@; # capture first failure
10302
+        last if defined $version;
10303
+      }
9447 10304
   
9448
-  # Alpha suffix part of lax version number syntax.  Acts like a
9449
-  # dotted-decimal part.
10305
+      croak $error unless defined $version;
9450 10306
   
9451
-  my $LAX_ALPHA_PART = qr/_[0-9]+/;
10307
+      return $version;
10308
+    }
10309
+  }
9452 10310
   
9453
-  #--------------------------------------------------------------------------#
9454
-  # Strict version regexp definitions
9455
-  #--------------------------------------------------------------------------#
10311
+  ############################################################
9456 10312
   
9457
-  # Strict decimal version number.
10313
+  # accessors
10314
+  sub name            { $_[0]->{module}           }
9458 10315
   
9459
-  my $STRICT_DECIMAL_VERSION =
9460
-      qr/ $STRICT_INTEGER_PART $FRACTION_PART? /x;
10316
+  sub filename        { $_[0]->{filename}         }
10317
+  sub packages_inside { @{$_[0]->{packages}}      }
10318
+  sub pod_inside      { @{$_[0]->{pod_headings}}  }
10319
+  sub contains_pod    { $#{$_[0]->{pod_headings}} }
9461 10320
   
9462
-  # Strict dotted-decimal version number.  Must have both leading "v" and
9463
-  # at least three parts, to avoid confusion with decimal syntax.
10321
+  sub version {
10322
+      my $self = shift;
10323
+      my $mod  = shift || $self->{module};
10324
+      my $vers;
10325
+      if ( defined( $mod ) && length( $mod ) &&
10326
+  	 exists( $self->{versions}{$mod} ) ) {
10327
+  	return $self->{versions}{$mod};
10328
+      } else {
10329
+  	return undef;
10330
+      }
10331
+  }
9464 10332
   
9465
-  my $STRICT_DOTTED_DECIMAL_VERSION =
9466
-      qr/ v $STRICT_INTEGER_PART $STRICT_DOTTED_DECIMAL_PART{2,} /x;
10333
+  sub pod {
10334
+      my $self = shift;
10335
+      my $sect = shift;
10336
+      if ( defined( $sect ) && length( $sect ) &&
10337
+  	 exists( $self->{pod}{$sect} ) ) {
10338
+  	return $self->{pod}{$sect};
10339
+      } else {
10340
+  	return undef;
10341
+      }
10342
+  }
9467 10343
   
9468
-  # Complete strict version number syntax -- should generally be used
9469
-  # anchored: qr/ \A $STRICT \z /x
10344
+  1;
9470 10345
   
9471
-  $STRICT =
9472
-      qr/ $STRICT_DECIMAL_VERSION | $STRICT_DOTTED_DECIMAL_VERSION /x;
10346
+MODULE_METADATA
10347
+
10348
+$fatpacked{"Parse/CPAN/Meta.pm"} = <<'PARSE_CPAN_META';
10349
+  package Parse::CPAN::Meta;
9473 10350
   
9474
-  #--------------------------------------------------------------------------#
9475
-  # Lax version regexp definitions
9476
-  #--------------------------------------------------------------------------#
10351
+  use strict;
10352
+  use Carp 'croak';
9477 10353
   
9478
-  # Lax decimal version number.  Just like the strict one except for
9479
-  # allowing an alpha suffix or allowing a leading or trailing
9480
-  # decimal-point
10354
+  # UTF Support?
10355
+  sub HAVE_UTF8 () { $] >= 5.007003 }
10356
+  sub IO_LAYER () { $] >= 5.008001 ? ":utf8" : "" }  
9481 10357
   
9482
-  my $LAX_DECIMAL_VERSION =
9483
-      qr/ $LAX_INTEGER_PART (?: \. | $FRACTION_PART $LAX_ALPHA_PART? )?
9484
-  	|
9485
-  	$FRACTION_PART $LAX_ALPHA_PART?
9486
-      /x;
10358
+  BEGIN {
10359
+  	if ( HAVE_UTF8 ) {
10360
+  		# The string eval helps hide this from Test::MinimumVersion
10361
+  		eval "require utf8;";
10362
+  		die "Failed to load UTF-8 support" if $@;
10363
+  	}
9487 10364
   
9488
-  # Lax dotted-decimal version number.  Distinguished by having either
9489
-  # leading "v" or at least three non-alpha parts.  Alpha part is only
9490
-  # permitted if there are at least two non-alpha parts. Strangely
9491
-  # enough, without the leading "v", Perl takes .1.2 to mean v0.1.2,
9492
-  # so when there is no "v", the leading part is optional
10365
+  	# Class structure
10366
+  	require 5.004;
10367
+  	require Exporter;
10368
+  	$Parse::CPAN::Meta::VERSION   = '1.4404';
10369
+  	@Parse::CPAN::Meta::ISA       = qw{ Exporter      };
10370
+  	@Parse::CPAN::Meta::EXPORT_OK = qw{ Load LoadFile };
10371
+  }
9493 10372
   
9494
-  my $LAX_DOTTED_DECIMAL_VERSION =
9495
-      qr/
9496
-  	v $LAX_INTEGER_PART (?: $LAX_DOTTED_DECIMAL_PART+ $LAX_ALPHA_PART? )?
9497
-  	|
9498
-  	$LAX_INTEGER_PART? $LAX_DOTTED_DECIMAL_PART{2,} $LAX_ALPHA_PART?
9499
-      /x;
10373
+  sub load_file {
10374
+    my ($class, $filename) = @_;
9500 10375
   
9501
-  # Complete lax version number syntax -- should generally be used
9502
-  # anchored: qr/ \A $LAX \z /x
9503
-  #
9504
-  # The string 'undef' is a special case to make for easier handling
9505
-  # of return values from ExtUtils::MM->parse_version
10376
+    if ($filename =~ /\.ya?ml$/) {
10377
+      return $class->load_yaml_string(_slurp($filename));
10378
+    }
9506 10379
   
9507
-  $LAX =
9508
-      qr/ undef | $LAX_DECIMAL_VERSION | $LAX_DOTTED_DECIMAL_VERSION /x;
10380
+    if ($filename =~ /\.json$/) {
10381
+      return $class->load_json_string(_slurp($filename));
10382
+    }
9509 10383
   
9510
-  #--------------------------------------------------------------------------#
10384
+    croak("file type cannot be determined by filename");
10385
+  }
9511 10386
   
9512
-  eval "use version::vxs $VERSION";
9513
-  if ( $@ ) { # don't have the XS version installed
9514
-      eval "use version::vpp $VERSION"; # don't tempt fate
9515
-      die "$@" if ( $@ );
9516
-      push @ISA, "version::vpp";
9517
-      local $^W;
9518
-      *version::qv = \&version::vpp::qv;
9519
-      *version::declare = \&version::vpp::declare;
9520
-      *version::_VERSION = \&version::vpp::_VERSION;
9521
-      if ($] >= 5.009000 && $] < 5.011004) {
9522
-  	no strict 'refs';
9523
-  	*version::stringify = \&version::vpp::stringify;
9524
-  	*{'version::(""'} = \&version::vpp::stringify;
9525
-  	*version::new = \&version::vpp::new;
9526
-  	*version::parse = \&version::vpp::parse;
9527
-      }
9528
-  }
9529
-  else { # use XS module
9530
-      push @ISA, "version::vxs";
9531
-      local $^W;
9532
-      *version::declare = \&version::vxs::declare;
9533
-      *version::qv = \&version::vxs::qv;
9534
-      *version::_VERSION = \&version::vxs::_VERSION;
9535
-      *version::vcmp = \&version::vxs::VCMP;
9536
-      if ($] >= 5.009000 && $] < 5.011004) {
9537
-  	no strict 'refs';
9538
-  	*version::stringify = \&version::vxs::stringify;
9539
-  	*{'version::(""'} = \&version::vxs::stringify;
9540
-  	*version::new = \&version::vxs::new;
9541
-  	*version::parse = \&version::vxs::parse;
9542
-      }
10387
+  sub load_yaml_string {
10388
+    my ($class, $string) = @_;
10389
+    my $backend = $class->yaml_backend();
10390
+    my $data = eval { no strict 'refs'; &{"$backend\::Load"}($string) };
10391
+    if ( $@ ) { 
10392
+      croak $backend->can('errstr') ? $backend->errstr : $@
10393
+    }
10394
+    return $data || {}; # in case document was valid but empty
10395
+  }
9543 10396
   
10397
+  sub load_json_string {
10398
+    my ($class, $string) = @_;
10399
+    return $class->json_backend()->new->decode($string);
9544 10400
   }
9545 10401
   
9546
-  # Preloaded methods go here.
9547
-  sub import {
9548
-      no strict 'refs';
9549
-      my ($class) = shift;
10402
+  sub yaml_backend {
10403
+    local $Module::Load::Conditional::CHECK_INC_HASH = 1;
10404
+    if (! defined $ENV{PERL_YAML_BACKEND} ) {
10405
+      _can_load( 'CPAN::Meta::YAML', 0.002 )
10406
+        or croak "CPAN::Meta::YAML 0.002 is not available\n";
10407
+      return "CPAN::Meta::YAML";
10408
+    }
10409
+    else {
10410
+      my $backend = $ENV{PERL_YAML_BACKEND};
10411
+      _can_load( $backend )
10412
+        or croak "Could not load PERL_YAML_BACKEND '$backend'\n";
10413
+      $backend->can("Load")
10414
+        or croak "PERL_YAML_BACKEND '$backend' does not implement Load()\n";
10415
+      return $backend;
10416
+    }
10417
+  }
9550 10418
   
9551
-      # Set up any derived class
9552
-      unless ($class eq 'version') {
9553
-  	local $^W;
9554
-  	*{$class.'::declare'} =  \&version::declare;
9555
-  	*{$class.'::qv'} = \&version::qv;
9556
-      }
10419
+  sub json_backend {
10420
+    local $Module::Load::Conditional::CHECK_INC_HASH = 1;
10421
+    if (! $ENV{PERL_JSON_BACKEND} or $ENV{PERL_JSON_BACKEND} eq 'JSON::PP') {
10422
+      _can_load( 'JSON::PP' => 2.27103 )
10423
+        or croak "JSON::PP 2.27103 is not available\n";
10424
+      return 'JSON::PP';
10425
+    }
10426
+    else {
10427
+      _can_load( 'JSON' => 2.5 )
10428
+        or croak  "JSON 2.5 is required for " .
10429
+                  "\$ENV{PERL_JSON_BACKEND} = '$ENV{PERL_JSON_BACKEND}'\n";
10430
+      return "JSON";
10431
+    }
10432
+  }
9557 10433
   
9558
-      my %args;
9559
-      if (@_) { # any remaining terms are arguments
9560
-  	map { $args{$_} = 1 } @_
9561
-      }
9562
-      else { # no parameters at all on use line
9563
-      	%args = 
9564
-  	(
9565
-  	    qv => 1,
9566
-  	    'UNIVERSAL::VERSION' => 1,
9567
-  	);
9568
-      }
10434
+  sub _slurp {
10435
+    open my $fh, "<" . IO_LAYER, "$_[0]"
10436
+      or die "can't open $_[0] for reading: $!";
10437
+    return do { local $/; <$fh> };
10438
+  }
10439
+    
10440
+  sub _can_load {
10441
+    my ($module, $version) = @_;
10442
+    (my $file = $module) =~ s{::}{/}g;
10443
+    $file .= ".pm";
10444
+    return 1 if $INC{$file};
10445
+    return 0 if exists $INC{$file}; # prior load failed
10446
+    eval { require $file; 1 }
10447
+      or return 0;
10448
+    if ( defined $version ) {
10449
+      eval { $module->VERSION($version); 1 }
10450
+        or return 0;
10451
+    }
10452
+    return 1;
10453
+  }
9569 10454
   
9570
-      my $callpkg = caller();
9571
-      
9572
-      if (exists($args{declare})) {
9573
-  	*{$callpkg.'::declare'} = 
9574
-  	    sub {return $class->declare(shift) }
9575
-  	  unless defined(&{$callpkg.'::declare'});
9576
-      }
10455
+  # Kept for backwards compatibility only
10456
+  # Create an object from a file
10457
+  sub LoadFile ($) {
10458
+    require CPAN::Meta::YAML;
10459
+    return CPAN::Meta::YAML::LoadFile(shift)
10460
+      or die CPAN::Meta::YAML->errstr;
10461
+  }
9577 10462
   
9578
-      if (exists($args{qv})) {
9579
-  	*{$callpkg.'::qv'} =
9580
-  	    sub {return $class->qv(shift) }
9581
-  	  unless defined(&{$callpkg.'::qv'});
9582
-      }
10463
+  # Parse a document from a string.
10464
+  sub Load ($) {
10465
+    require CPAN::Meta::YAML;
10466
+    return CPAN::Meta::YAML::Load(shift)
10467
+      or die CPAN::Meta::YAML->errstr;
10468
+  }
9583 10469
   
9584
-      if (exists($args{'UNIVERSAL::VERSION'})) {
9585
-  	local $^W;
9586
-  	*UNIVERSAL::VERSION 
9587
-  		= \&version::_VERSION;
9588
-      }
10470
+  1;
9589 10471
   
9590
-      if (exists($args{'VERSION'})) {
9591
-  	*{$callpkg.'::VERSION'} = \&version::_VERSION;
9592
-      }
10472
+  __END__
9593 10473
   
9594
-      if (exists($args{'is_strict'})) {
9595
-  	*{$callpkg.'::is_strict'} = \&version::is_strict
9596
-  	  unless defined(&{$callpkg.'::is_strict'});
9597
-      }
10474
+PARSE_CPAN_META
10475
+
10476
+$fatpacked{"lib/core/only.pm"} = <<'LIB_CORE_ONLY';
10477
+  package lib::core::only;
9598 10478
   
9599
-      if (exists($args{'is_lax'})) {
9600
-  	*{$callpkg.'::is_lax'} = \&version::is_lax
9601
-  	  unless defined(&{$callpkg.'::is_lax'});
9602
-      }
9603
-  }
10479
+  use strict;
10480
+  use warnings FATAL => 'all';
10481
+  use Config;
9604 10482
   
9605
-  sub is_strict	{ defined $_[0] && $_[0] =~ qr/ \A $STRICT \z /x }
9606
-  sub is_lax	{ defined $_[0] && $_[0] =~ qr/ \A $LAX \z /x }
10483
+  sub import {
10484
+    @INC = @Config{qw(privlibexp archlibexp)};
10485
+    return
10486
+  }
9607 10487
   
9608 10488
   1;
9609
-VERSION
10489
+LIB_CORE_ONLY
9610 10490
 
9611
-$fatpacked{"Version/Requirements.pm"} = <<'VERSION_REQUIREMENTS';
10491
+$fatpacked{"local/lib.pm"} = <<'LOCAL_LIB';
9612 10492
   use strict;
9613 10493
   use warnings;
9614
-  package Version::Requirements;
9615
-  BEGIN {
9616
-    $Version::Requirements::VERSION = '0.101020';
9617
-  }
9618
-  # ABSTRACT: a set of version requirements for a CPAN dist
9619 10494
   
10495
+  package local::lib;
9620 10496
   
9621
-  use Carp ();
9622
-  use Scalar::Util ();
9623
-  use version 0.77 (); # the ->parse method
10497
+  use 5.008001; # probably works with earlier versions but I'm not supporting them
10498
+                # (patches would, of course, be welcome)
9624 10499
   
10500
+  use File::Spec ();
10501
+  use File::Path ();
10502
+  use Config;
9625 10503
   
9626
-  sub new {
9627
-    my ($class) = @_;
9628
-    return bless {} => $class;
9629
-  }
10504
+  our $VERSION = '1.008009'; # 1.8.9
9630 10505
   
9631
-  sub _version_object {
9632
-    my ($self, $version) = @_;
10506
+  our @KNOWN_FLAGS = qw(--self-contained --deactivate --deactivate-all);
9633 10507
   
9634
-    $version = (! defined $version)                ? version->parse(0)
9635
-             : (! Scalar::Util::blessed($version)) ? version->parse($version)
9636
-             :                                       $version;
10508
+  sub DEACTIVATE_ONE () { 1 }
10509
+  sub DEACTIVATE_ALL () { 2 }
9637 10510
   
9638
-    return $version;
9639
-  }
10511
+  sub INTERPOLATE_ENV () { 1 }
10512
+  sub LITERAL_ENV     () { 0 }
9640 10513
   
10514
+  sub import {
10515
+    my ($class, @args) = @_;
9641 10516
   
9642
-  BEGIN {
9643
-    for my $type (qw(minimum maximum exclusion exact_version)) {
9644
-      my $method = "with_$type";
9645
-      my $to_add = $type eq 'exact_version' ? $type : "add_$type";
10517
+    # Remember what PERL5LIB was when we started
10518
+    my $perl5lib = $ENV{PERL5LIB} || '';
9646 10519
   
9647
-      my $code = sub {
9648
-        my ($self, $name, $version) = @_;
10520
+    my %arg_store;
10521
+    for my $arg (@args) {
10522
+      # check for lethal dash first to stop processing before causing problems
10523
+      if ($arg =~ /−/) {
10524
+        die <<'DEATH';
10525
+  WHOA THERE! It looks like you've got some fancy dashes in your commandline!
10526
+  These are *not* the traditional -- dashes that software recognizes. You
10527
+  probably got these by copy-pasting from the perldoc for this module as
10528
+  rendered by a UTF8-capable formatter. This most typically happens on an OS X
10529
+  terminal, but can happen elsewhere too. Please try again after replacing the
10530
+  dashes with normal minus signs.
10531
+  DEATH
10532
+      }
10533
+      elsif(grep { $arg eq $_ } @KNOWN_FLAGS) {
10534
+        (my $flag = $arg) =~ s/--//;
10535
+        $arg_store{$flag} = 1;
10536
+      }
10537
+      elsif($arg =~ /^--/) {
10538
+        die "Unknown import argument: $arg";
10539
+      }
10540
+      else {
10541
+        # assume that what's left is a path
10542
+        $arg_store{path} = $arg;
10543
+      }
10544
+    }
9649 10545
   
9650
-        $version = $self->_version_object( $version );
10546
+    if($arg_store{'self-contained'}) {
10547
+      die "FATAL: The local::lib --self-contained flag has never worked reliably and the original author, Mark Stosberg, was unable or unwilling to maintain it. As such, this flag has been removed from the local::lib codebase in order to prevent misunderstandings and potentially broken builds. The local::lib authors recommend that you look at the lib::core::only module shipped with this distribution in order to create a more robust environment that is equivalent to what --self-contained provided (although quite possibly not what you originally thought it provided due to the poor quality of the documentation, for which we apologise).\n";
10548
+    }
9651 10549
   
9652
-        $self->__modify_entry_for($name, $method, $version);
10550
+    my $deactivating = 0;
10551
+    if ($arg_store{deactivate}) {
10552
+      $deactivating = DEACTIVATE_ONE;
10553
+    }
10554
+    if ($arg_store{'deactivate-all'}) {
10555
+      $deactivating = DEACTIVATE_ALL;
10556
+    }
9653 10557
   
9654
-        return $self;
9655
-      };
9656
-      
9657
-      no strict 'refs';
9658
-      *$to_add = $code;
10558
+    $arg_store{path} = $class->resolve_path($arg_store{path});
10559
+    $class->setup_local_lib_for($arg_store{path}, $deactivating);
10560
+  
10561
+    for (@INC) { # Untaint @INC
10562
+      next if ref; # Skip entry if it is an ARRAY, CODE, blessed, etc.
10563
+      m/(.*)/ and $_ = $1;
9659 10564
     }
9660 10565
   }
9661 10566
   
10567
+  sub pipeline;
9662 10568
   
9663
-  sub add_requirements {
9664
-    my ($self, $req) = @_;
9665
-  
9666
-    for my $module ($req->required_modules) {
9667
-      my $modifiers = $req->__entry_for($module)->as_modifiers;
9668
-      for my $modifier (@$modifiers) {
9669
-        my ($method, @args) = @$modifier;
9670
-        $self->$method($module => @args);
10569
+  sub pipeline {
10570
+    my @methods = @_;
10571
+    my $last = pop(@methods);
10572
+    if (@methods) {
10573
+      \sub {
10574
+        my ($obj, @args) = @_;
10575
+        $obj->${pipeline @methods}(
10576
+          $obj->$last(@args)
10577
+        );
10578
+      };
10579
+    } else {
10580
+      \sub {
10581
+        shift->$last(@_);
9671 10582
       };
9672 10583
     }
10584
+  }
9673 10585
   
9674
-    return $self;
10586
+  sub _uniq {
10587
+      my %seen;
10588
+      grep { ! $seen{$_}++ } @_;
9675 10589
   }
9676 10590
   
10591
+  sub resolve_path {
10592
+    my ($class, $path) = @_;
10593
+    $class->${pipeline qw(
10594
+      resolve_relative_path
10595
+      resolve_home_path
10596
+      resolve_empty_path
10597
+    )}($path);
10598
+  }
9677 10599
   
9678
-  sub accepts_module {
9679
-    my ($self, $module, $version) = @_;
10600
+  sub resolve_empty_path {
10601
+    my ($class, $path) = @_;
10602
+    if (defined $path) {
10603
+      $path;
10604
+    } else {
10605
+      '~/perl5';
10606
+    }
10607
+  }
9680 10608
   
9681
-    $version = $self->_version_object( $version );
10609
+  sub resolve_home_path {
10610
+    my ($class, $path) = @_;
10611
+    return $path unless ($path =~ /^~/);
10612
+    my ($user) = ($path =~ /^~([^\/]+)/); # can assume ^~ so undef for 'us'
10613
+    my $tried_file_homedir;
10614
+    my $homedir = do {
10615
+      if (eval { require File::HomeDir } && $File::HomeDir::VERSION >= 0.65) {
10616
+        $tried_file_homedir = 1;
10617
+        if (defined $user) {
10618
+          File::HomeDir->users_home($user);
10619
+        } else {
10620
+          File::HomeDir->my_home;
10621
+        }
10622
+      } else {
10623
+        if (defined $user) {
10624
+          (getpwnam $user)[7];
10625
+        } else {
10626
+          if (defined $ENV{HOME}) {
10627
+            $ENV{HOME};
10628
+          } else {
10629
+            (getpwuid $<)[7];
10630
+          }
10631
+        }
10632
+      }
10633
+    };
10634
+    unless (defined $homedir) {
10635
+      require Carp;
10636
+      Carp::croak(
10637
+        "Couldn't resolve homedir for "
10638
+        .(defined $user ? $user : 'current user')
10639
+        .($tried_file_homedir ? '' : ' - consider installing File::HomeDir')
10640
+      );
10641
+    }
10642
+    $path =~ s/^~[^\/]*/$homedir/;
10643
+    $path;
10644
+  }
9682 10645
   
9683
-    return 1 unless my $range = $self->__entry_for($module);
9684
-    return $range->_accepts($version);
10646
+  sub resolve_relative_path {
10647
+    my ($class, $path) = @_;
10648
+    $path = File::Spec->rel2abs($path);
9685 10649
   }
9686 10650
   
10651
+  sub setup_local_lib_for {
10652
+    my ($class, $path, $deactivating) = @_;
9687 10653
   
9688
-  sub clear_requirement {
9689
-    my ($self, $module) = @_;
10654
+    my $interpolate = LITERAL_ENV;
10655
+    my @active_lls = $class->active_paths;
9690 10656
   
9691
-    return $self unless $self->__entry_for($module);
10657
+    $class->ensure_dir_structure_for($path);
9692 10658
   
9693
-    Carp::confess("can't clear requirements on finalized requirements")
9694
-      if $self->is_finalized;
10659
+    # On Win32 directories often contain spaces. But some parts of the CPAN
10660
+    # toolchain don't like that. To avoid this, GetShortPathName() gives us
10661
+    # an alternate representation that has none.
10662
+    # This only works if the directory already exists.
10663
+    $path = Win32::GetShortPathName($path) if $^O eq 'MSWin32';
9695 10664
   
9696
-    delete $self->{requirements}{ $module };
10665
+    if (! $deactivating) {
10666
+      if (@active_lls && $active_lls[-1] eq $path) {
10667
+        exit 0 if $0 eq '-';
10668
+        return; # Asked to add what's already at the top of the stack
10669
+      } elsif (grep { $_ eq $path} @active_lls) {
10670
+        # Asked to add a dir that's lower in the stack -- so we remove it from
10671
+        # where it is, and then add it back at the top.
10672
+        $class->setup_env_hash_for($path, DEACTIVATE_ONE);
10673
+        # Which means we can no longer output "PERL5LIB=...:$PERL5LIB" stuff
10674
+        # anymore because we're taking something *out*.
10675
+        $interpolate = INTERPOLATE_ENV;
10676
+      }
10677
+    }
9697 10678
   
9698
-    return $self;
10679
+    if ($0 eq '-') {
10680
+      $class->print_environment_vars_for($path, $deactivating, $interpolate);
10681
+      exit 0;
10682
+    } else {
10683
+      $class->setup_env_hash_for($path, $deactivating);
10684
+      my $arch_dir = $Config{archname};
10685
+      @INC = _uniq(
10686
+    (
10687
+        # Inject $path/$archname for each path in PERL5LIB
10688
+        map { ( File::Spec->catdir($_, $arch_dir), $_ ) }
10689
+        split($Config{path_sep}, $ENV{PERL5LIB})
10690
+    ),
10691
+    @INC
10692
+      );
10693
+    }
9699 10694
   }
9700 10695
   
10696
+  sub install_base_bin_path {
10697
+    my ($class, $path) = @_;
10698
+    File::Spec->catdir($path, 'bin');
10699
+  }
9701 10700
   
9702
-  sub required_modules { keys %{ $_[0]{requirements} } }
9703
-  
10701
+  sub install_base_perl_path {
10702
+    my ($class, $path) = @_;
10703
+    File::Spec->catdir($path, 'lib', 'perl5');
10704
+  }
9704 10705
   
9705
-  sub clone {
9706
-    my ($self) = @_;
9707
-    my $new = (ref $self)->new;
10706
+  sub install_base_arch_path {
10707
+    my ($class, $path) = @_;
10708
+    File::Spec->catdir($class->install_base_perl_path($path), $Config{archname});
10709
+  }
9708 10710
   
9709
-    return $new->add_requirements($self);
10711
+  sub ensure_dir_structure_for {
10712
+    my ($class, $path) = @_;
10713
+    unless (-d $path) {
10714
+      warn "Attempting to create directory ${path}\n";
10715
+    }
10716
+    File::Path::mkpath($path);
10717
+    return
9710 10718
   }
9711 10719
   
9712
-  sub __entry_for     { $_[0]{requirements}{ $_[1] } }
10720
+  sub guess_shelltype {
10721
+    my $shellbin = 'sh';
10722
+    if(defined $ENV{'SHELL'}) {
10723
+        my @shell_bin_path_parts = File::Spec->splitpath($ENV{'SHELL'});
10724
+        $shellbin = $shell_bin_path_parts[-1];
10725
+    }
10726
+    my $shelltype = do {
10727
+        local $_ = $shellbin;
10728
+        if(/csh/) {
10729
+            'csh'
10730
+        } else {
10731
+            'bourne'
10732
+        }
10733
+    };
9713 10734
   
9714
-  sub __modify_entry_for {
9715
-    my ($self, $name, $method, $version) = @_;
10735
+    # Both Win32 and Cygwin have $ENV{COMSPEC} set.
10736
+    if (defined $ENV{'COMSPEC'} && $^O ne 'cygwin') {
10737
+        my @shell_bin_path_parts = File::Spec->splitpath($ENV{'COMSPEC'});
10738
+        $shellbin = $shell_bin_path_parts[-1];
10739
+           $shelltype = do {
10740
+                   local $_ = $shellbin;
10741
+                   if(/command\.com/) {
10742
+                           'win32'
10743
+                   } elsif(/cmd\.exe/) {
10744
+                           'win32'
10745
+                   } elsif(/4nt\.exe/) {
10746
+                           'win32'
10747
+                   } else {
10748
+                           $shelltype
10749
+                   }
10750
+           };
10751
+    }
10752
+    return $shelltype;
10753
+  }
9716 10754
   
9717
-    my $fin = $self->is_finalized;
9718
-    my $old = $self->__entry_for($name);
10755
+  sub print_environment_vars_for {
10756
+    my ($class, $path, $deactivating, $interpolate) = @_;
10757
+    print $class->environment_vars_string_for($path, $deactivating, $interpolate);
10758
+  }
9719 10759
   
9720
-    Carp::confess("can't add new requirements to finalized requirements")
9721
-      if $fin and not $old;
10760
+  sub environment_vars_string_for {
10761
+    my ($class, $path, $deactivating, $interpolate) = @_;
10762
+    my @envs = $class->build_environment_vars_for($path, $deactivating, $interpolate);
10763
+    my $out = '';
9722 10764
   
9723
-    my $new = ($old || 'Version::Requirements::_Range::Range')
9724
-            ->$method($version);
10765
+    # rather basic csh detection, goes on the assumption that something won't
10766
+    # call itself csh unless it really is. also, default to bourne in the
10767
+    # pathological situation where a user doesn't have $ENV{SHELL} defined.
10768
+    # note also that shells with funny names, like zoid, are assumed to be
10769
+    # bourne.
9725 10770
   
9726
-    Carp::confess("can't modify finalized requirements")
9727
-      if $fin and $old->as_string ne $new->as_string;
10771
+    my $shelltype = $class->guess_shelltype;
9728 10772
   
9729
-    $self->{requirements}{ $name } = $new;
10773
+    while (@envs) {
10774
+      my ($name, $value) = (shift(@envs), shift(@envs));
10775
+      $value =~ s/(\\")/\\$1/g if defined $value;
10776
+      $out .= $class->${\"build_${shelltype}_env_declaration"}($name, $value);
10777
+    }
10778
+    return $out;
9730 10779
   }
9731 10780
   
10781
+  # simple routines that take two arguments: an %ENV key and a value. return
10782
+  # strings that are suitable for passing directly to the relevant shell to set
10783
+  # said key to said value.
10784
+  sub build_bourne_env_declaration {
10785
+    my $class = shift;
10786
+    my($name, $value) = @_;
10787
+    return defined($value) ? qq{export ${name}="${value}";\n} : qq{unset ${name};\n};
10788
+  }
9732 10789
   
9733
-  sub is_simple {
9734
-    my ($self) = @_;
9735
-    for my $module ($self->required_modules) {
9736
-      # XXX: This is a complete hack, but also entirely correct.
9737
-      return if $self->__entry_for($module)->as_string =~ /\s/;
9738
-    }
9739
-  
9740
-    return 1;
10790
+  sub build_csh_env_declaration {
10791
+    my $class = shift;
10792
+    my($name, $value) = @_;
10793
+    return defined($value) ? qq{setenv ${name} "${value}"\n} : qq{unsetenv ${name}\n};
9741 10794
   }
9742 10795
   
10796
+  sub build_win32_env_declaration {
10797
+    my $class = shift;
10798
+    my($name, $value) = @_;
10799
+    return defined($value) ? qq{set ${name}=${value}\n} : qq{set ${name}=\n};
10800
+  }
9743 10801
   
9744
-  sub is_finalized { $_[0]{finalized} }
10802
+  sub setup_env_hash_for {
10803
+    my ($class, $path, $deactivating) = @_;
10804
+    my %envs = $class->build_environment_vars_for($path, $deactivating, INTERPOLATE_ENV);
10805
+    @ENV{keys %envs} = values %envs;
10806
+  }
9745 10807
   
10808
+  sub build_environment_vars_for {
10809
+    my ($class, $path, $deactivating, $interpolate) = @_;
9746 10810
   
9747
-  sub finalize { $_[0]{finalized} = 1 }
10811
+    if ($deactivating == DEACTIVATE_ONE) {
10812
+      return $class->build_deactivate_environment_vars_for($path, $interpolate);
10813
+    } elsif ($deactivating == DEACTIVATE_ALL) {
10814
+      return $class->build_deact_all_environment_vars_for($path, $interpolate);
10815
+    } else {
10816
+      return $class->build_activate_environment_vars_for($path, $interpolate);
10817
+    }
10818
+  }
9748 10819
   
10820
+  # Build an environment value for a variable like PATH from a list of paths.
10821
+  # References to existing variables are given as references to the variable name.
10822
+  # Duplicates are removed.
10823
+  #
10824
+  # options:
10825
+  # - interpolate: INTERPOLATE_ENV/LITERAL_ENV
10826
+  # - exists: paths are included only if they exist (default: interpolate == INTERPOLATE_ENV)
10827
+  # - filter: function to apply to each path do decide if it must be included
10828
+  # - empty: the value to return in the case of empty value
10829
+  my %ENV_LIST_VALUE_DEFAULTS = (
10830
+      interpolate => INTERPOLATE_ENV,
10831
+      exists => undef,
10832
+      filter => sub { 1 },
10833
+      empty => undef,
10834
+  );
10835
+  sub _env_list_value {
10836
+    my $options = shift;
10837
+    die(sprintf "unknown option '$_' at %s line %u\n", (caller)[1..2])
10838
+      for grep { !exists $ENV_LIST_VALUE_DEFAULTS{$_} } keys %$options;
10839
+    my %options = (%ENV_LIST_VALUE_DEFAULTS, %{ $options });
10840
+    $options{exists} = $options{interpolate} == INTERPOLATE_ENV
10841
+      unless defined $options{exists};
10842
+  
10843
+    my %seen;
10844
+  
10845
+    my $value = join($Config{path_sep}, map {
10846
+        ref $_ ? ($^O eq 'MSWin32' ? "%${$_}%" : "\$${$_}") : $_
10847
+      } grep {
10848
+        ref $_ || (defined $_
10849
+                   && length($_) > 0
10850
+                   && !$seen{$_}++
10851
+                   && $options{filter}->($_)
10852
+                   && (!$options{exists} || -e $_))
10853
+      } map {
10854
+        if (ref $_ eq 'SCALAR' && $options{interpolate} == INTERPOLATE_ENV) {
10855
+          exists $ENV{${$_}} ? (split /\Q$Config{path_sep}/, $ENV{${$_}}) : ()
10856
+        } else {
10857
+          $_
10858
+        }
10859
+      } @_);
10860
+    return length($value) ? $value : $options{empty};
10861
+  }
9749 10862
   
9750
-  sub as_string_hash {
9751
-    my ($self) = @_;
10863
+  sub build_activate_environment_vars_for {
10864
+    my ($class, $path, $interpolate) = @_;
10865
+    return (
10866
+      PERL_LOCAL_LIB_ROOT =>
10867
+              _env_list_value(
10868
+                { interpolate => $interpolate, exists => 0, empty => '' },
10869
+                \'PERL_LOCAL_LIB_ROOT',
10870
+                $path,
10871
+              ),
10872
+      PERL_MB_OPT => "--install_base ${path}",
10873
+      PERL_MM_OPT => "INSTALL_BASE=${path}",
10874
+      PERL5LIB =>
10875
+              _env_list_value(
10876
+                { interpolate => $interpolate, exists => 0, empty => '' },
10877
+                $class->install_base_perl_path($path),
10878
+                \'PERL5LIB',
10879
+              ),
10880
+      PATH => _env_list_value(
10881
+                { interpolate => $interpolate, exists => 0, empty => '' },
10882
+          $class->install_base_bin_path($path),
10883
+                \'PATH',
10884
+              ),
10885
+    )
10886
+  }
9752 10887
   
9753
-    my %hash = map {; $_ => $self->{requirements}{$_}->as_string }
9754
-               $self->required_modules;
10888
+  sub active_paths {
10889
+    my ($class) = @_;
9755 10890
   
9756
-    return \%hash;
10891
+    return () unless defined $ENV{PERL_LOCAL_LIB_ROOT};
10892
+    return grep { $_ ne '' } split /\Q$Config{path_sep}/, $ENV{PERL_LOCAL_LIB_ROOT};
9757 10893
   }
9758 10894
   
10895
+  sub build_deactivate_environment_vars_for {
10896
+    my ($class, $path, $interpolate) = @_;
9759 10897
   
9760
-  my %methods_for_op = (
9761
-    '==' => [ qw(exact_version) ],
9762
-    '!=' => [ qw(add_exclusion) ],
9763
-    '>=' => [ qw(add_minimum)   ],
9764
-    '<=' => [ qw(add_maximum)   ],
9765
-    '>'  => [ qw(add_minimum add_exclusion) ],
9766
-    '<'  => [ qw(add_maximum add_exclusion) ],
9767
-  );
10898
+    my @active_lls = $class->active_paths;
9768 10899
   
9769
-  sub from_string_hash {
9770
-    my ($class, $hash) = @_;
10900
+    if (!grep { $_ eq $path } @active_lls) {
10901
+      warn "Tried to deactivate inactive local::lib '$path'\n";
10902
+      return ();
10903
+    }
9771 10904
   
9772
-    my $self = $class->new;
10905
+    my $perl_path = $class->install_base_perl_path($path);
10906
+    my $arch_path = $class->install_base_arch_path($path);
10907
+    my $bin_path = $class->install_base_bin_path($path);
9773 10908
   
9774
-    for my $module (keys %$hash) {
9775
-      my @parts = split qr{\s*,\s*}, $hash->{ $module };
9776
-      for my $part (@parts) {
9777
-        my ($op, $ver) = split /\s+/, $part, 2;
9778 10909
   
9779
-        if (! defined $ver) {
9780
-          $self->add_minimum($module => $op);
9781
-        } else {
9782
-          Carp::confess("illegal requirement string: $hash->{ $module }")
9783
-            unless my $methods = $methods_for_op{ $op };
10910
+    my %env = (
10911
+      PERL_LOCAL_LIB_ROOT => _env_list_value(
10912
+        {
10913
+          exists => 0,
10914
+        },
10915
+        grep { $_ ne $path } @active_lls
10916
+      ),
10917
+      PERL5LIB => _env_list_value(
10918
+        {
10919
+          exists => 0,
10920
+          filter => sub {
10921
+            $_ ne $perl_path && $_ ne $arch_path
10922
+          },
10923
+        },
10924
+        \'PERL5LIB',
10925
+      ),
10926
+      PATH => _env_list_value(
10927
+        {
10928
+          exists => 0,
10929
+          filter => sub { $_ ne $bin_path },
10930
+        },
10931
+        \'PATH',
10932
+      ),
10933
+    );
9784 10934
   
9785
-          $self->$_($module => $ver) for @$methods;
9786
-        }
9787
-      }
10935
+    # If removing ourselves from the "top of the stack", set install paths to
10936
+    # correspond with the new top of stack.
10937
+    if ($active_lls[-1] eq $path) {
10938
+      my $new_top = $active_lls[-2];
10939
+      $env{PERL_MB_OPT} = defined($new_top) ? "--install_base ${new_top}" : undef;
10940
+      $env{PERL_MM_OPT} = defined($new_top) ? "INSTALL_BASE=${new_top}" : undef;
9788 10941
     }
9789 10942
   
9790
-    return $self;
10943
+    return %env;
9791 10944
   }
9792 10945
   
9793
-  ##############################################################
10946
+  sub build_deact_all_environment_vars_for {
10947
+    my ($class, $path, $interpolate) = @_;
9794 10948
   
9795
-  {
9796
-    package
9797
-      Version::Requirements::_Range::Exact;
9798
-  BEGIN {
9799
-    $Version::Requirements::_Range::Exact::VERSION = '0.101020';
10949
+    my @active_lls = $class->active_paths;
10950
+  
10951
+    my %perl_paths = map { (
10952
+        $class->install_base_perl_path($_) => 1,
10953
+        $class->install_base_arch_path($_) => 1
10954
+      ) } @active_lls;
10955
+    my %bin_paths = map { (
10956
+        $class->install_base_bin_path($_) => 1,
10957
+      ) } @active_lls;
10958
+  
10959
+    my %env = (
10960
+      PERL_LOCAL_LIB_ROOT => undef,
10961
+      PERL_MM_OPT => undef,
10962
+      PERL_MB_OPT => undef,
10963
+      PERL5LIB => _env_list_value(
10964
+        {
10965
+          exists => 0,
10966
+          filter => sub {
10967
+            ! scalar grep { exists $perl_paths{$_} } $_[0]
10968
+          },
10969
+        },
10970
+        \'PERL5LIB'
10971
+      ),
10972
+      PATH => _env_list_value(
10973
+        {
10974
+          exists => 0,
10975
+          filter => sub {
10976
+            ! scalar grep { exists $bin_paths{$_} } $_[0]
10977
+          },
10978
+        },
10979
+        \'PATH'
10980
+      ),
10981
+    );
10982
+  
10983
+    return %env;
9800 10984
   }
9801
-    sub _new     { bless { version => $_[1] } => $_[0] }
9802 10985
   
9803
-    sub _accepts { return $_[0]{version} == $_[1] }
10986
+  1;
10987
+LOCAL_LIB
10988
+
10989
+$fatpacked{"version.pm"} = <<'VERSION';
10990
+  #!perl -w
10991
+  package version;
9804 10992
   
9805
-    sub as_string { return "== $_[0]{version}" }
10993
+  use 5.005_04;
10994
+  use strict;
9806 10995
   
9807
-    sub as_modifiers { return [ [ exact_version => $_[0]{version} ] ] }
10996
+  use vars qw(@ISA $VERSION $CLASS $STRICT $LAX *declare *qv);
9808 10997
   
9809
-    sub _clone {
9810
-      (ref $_[0])->_new( version->new( $_[0]{version} ) )
9811
-    }
10998
+  $VERSION = 0.9901;
9812 10999
   
9813
-    sub with_exact_version {
9814
-      my ($self, $version) = @_;
11000
+  $CLASS = 'version';
9815 11001
   
9816
-      return $self->_clone if $self->_accepts($version);
11002
+  #--------------------------------------------------------------------------#
11003
+  # Version regexp components
11004
+  #--------------------------------------------------------------------------#
9817 11005
   
9818
-      Carp::confess("illegal requirements: unequal exact version specified");
9819
-    }
11006
+  # Fraction part of a decimal version number.  This is a common part of
11007
+  # both strict and lax decimal versions
9820 11008
   
9821
-    sub with_minimum {
9822
-      my ($self, $minimum) = @_;
9823
-      return $self->_clone if $self->{version} >= $minimum;
9824
-      Carp::confess("illegal requirements: minimum above exact specification");
9825
-    }
11009
+  my $FRACTION_PART = qr/\.[0-9]+/;
9826 11010
   
9827
-    sub with_maximum {
9828
-      my ($self, $maximum) = @_;
9829
-      return $self->_clone if $self->{version} <= $maximum;
9830
-      Carp::confess("illegal requirements: maximum below exact specification");
9831
-    }
11011
+  # First part of either decimal or dotted-decimal strict version number.
11012
+  # Unsigned integer with no leading zeroes (except for zero itself) to
11013
+  # avoid confusion with octal.
9832 11014
   
9833
-    sub with_exclusion {
9834
-      my ($self, $exclusion) = @_;
9835
-      return $self->_clone unless $exclusion == $self->{version};
9836
-      Carp::confess("illegal requirements: excluded exact specification");
9837
-    }
9838
-  }
11015
+  my $STRICT_INTEGER_PART = qr/0|[1-9][0-9]*/;
9839 11016
   
9840
-  ##############################################################
11017
+  # First part of either decimal or dotted-decimal lax version number.
11018
+  # Unsigned integer, but allowing leading zeros.  Always interpreted
11019
+  # as decimal.  However, some forms of the resulting syntax give odd
11020
+  # results if used as ordinary Perl expressions, due to how perl treats
11021
+  # octals.  E.g.
11022
+  #   version->new("010" ) == 10
11023
+  #   version->new( 010  ) == 8
11024
+  #   version->new( 010.2) == 82  # "8" . "2"
9841 11025
   
9842
-  {
9843
-    package
9844
-      Version::Requirements::_Range::Range;
9845
-  BEGIN {
9846
-    $Version::Requirements::_Range::Range::VERSION = '0.101020';
9847
-  }
11026
+  my $LAX_INTEGER_PART = qr/[0-9]+/;
11027
+  
11028
+  # Second and subsequent part of a strict dotted-decimal version number.
11029
+  # Leading zeroes are permitted, and the number is always decimal.
11030
+  # Limited to three digits to avoid overflow when converting to decimal
11031
+  # form and also avoid problematic style with excessive leading zeroes.
9848 11032
   
9849
-    sub _self { ref($_[0]) ? $_[0] : (bless { } => $_[0]) }
11033
+  my $STRICT_DOTTED_DECIMAL_PART = qr/\.[0-9]{1,3}/;
9850 11034
   
9851
-    sub _clone {
9852
-      return (bless { } => $_[0]) unless ref $_[0];
11035
+  # Second and subsequent part of a lax dotted-decimal version number.
11036
+  # Leading zeroes are permitted, and the number is always decimal.  No
11037
+  # limit on the numerical value or number of digits, so there is the
11038
+  # possibility of overflow when converting to decimal form.
9853 11039
   
9854
-      my ($s) = @_;
9855
-      my %guts = (
9856
-        (exists $s->{minimum} ? (minimum => version->new($s->{minimum})) : ()),
9857
-        (exists $s->{maximum} ? (maximum => version->new($s->{maximum})) : ()),
11040
+  my $LAX_DOTTED_DECIMAL_PART = qr/\.[0-9]+/;
9858 11041
   
9859
-        (exists $s->{exclusions}
9860
-          ? (exclusions => [ map { version->new($_) } @{ $s->{exclusions} } ])
9861
-          : ()),
9862
-      );
11042
+  # Alpha suffix part of lax version number syntax.  Acts like a
11043
+  # dotted-decimal part.
9863 11044
   
9864
-      bless \%guts => ref($s);
9865
-    }
11045
+  my $LAX_ALPHA_PART = qr/_[0-9]+/;
9866 11046
   
9867
-    sub as_modifiers {
9868
-      my ($self) = @_;
9869
-      my @mods;
9870
-      push @mods, [ add_minimum => $self->{minimum} ] if exists $self->{minimum};
9871
-      push @mods, [ add_maximum => $self->{maximum} ] if exists $self->{maximum};
9872
-      push @mods, map {; [ add_exclusion => $_ ] } @{$self->{exclusions} || []};
9873
-      return \@mods;
9874
-    }
11047
+  #--------------------------------------------------------------------------#
11048
+  # Strict version regexp definitions
11049
+  #--------------------------------------------------------------------------#
9875 11050
   
9876
-    sub as_string {
9877
-      my ($self) = @_;
11051
+  # Strict decimal version number.
9878 11052
   
9879
-      return 0 if ! keys %$self;
11053
+  my $STRICT_DECIMAL_VERSION =
11054
+      qr/ $STRICT_INTEGER_PART $FRACTION_PART? /x;
9880 11055
   
9881
-      return "$self->{minimum}" if (keys %$self) == 1 and exists $self->{minimum};
11056
+  # Strict dotted-decimal version number.  Must have both leading "v" and
11057
+  # at least three parts, to avoid confusion with decimal syntax.
9882 11058
   
9883
-      my @exclusions = @{ $self->{exclusions} || [] };
11059
+  my $STRICT_DOTTED_DECIMAL_VERSION =
11060
+      qr/ v $STRICT_INTEGER_PART $STRICT_DOTTED_DECIMAL_PART{2,} /x;
9884 11061
   
9885
-      my @parts;
11062
+  # Complete strict version number syntax -- should generally be used
11063
+  # anchored: qr/ \A $STRICT \z /x
9886 11064
   
9887
-      for my $pair (
9888
-        [ qw( >= > minimum ) ],
9889
-        [ qw( <= < maximum ) ],
9890
-      ) {
9891
-        my ($op, $e_op, $k) = @$pair;
9892
-        if (exists $self->{$k}) {
9893
-          my @new_exclusions = grep { $_ != $self->{ $k } } @exclusions;
9894
-          if (@new_exclusions == @exclusions) {
9895
-            push @parts, "$op $self->{ $k }";
9896
-          } else {
9897
-            push @parts, "$e_op $self->{ $k }";
9898
-            @exclusions = @new_exclusions;
9899
-          }
9900
-        }
9901
-      }
11065
+  $STRICT =
11066
+      qr/ $STRICT_DECIMAL_VERSION | $STRICT_DOTTED_DECIMAL_VERSION /x;
9902 11067
   
9903
-      push @parts, map {; "!= $_" } @exclusions;
11068
+  #--------------------------------------------------------------------------#
11069
+  # Lax version regexp definitions
11070
+  #--------------------------------------------------------------------------#
9904 11071
   
9905
-      return join q{, }, @parts;
9906
-    }
11072
+  # Lax decimal version number.  Just like the strict one except for
11073
+  # allowing an alpha suffix or allowing a leading or trailing
11074
+  # decimal-point
9907 11075
   
9908
-    sub with_exact_version {
9909
-      my ($self, $version) = @_;
9910
-      $self = $self->_clone;
11076
+  my $LAX_DECIMAL_VERSION =
11077
+      qr/ $LAX_INTEGER_PART (?: \. | $FRACTION_PART $LAX_ALPHA_PART? )?
11078
+  	|
11079
+  	$FRACTION_PART $LAX_ALPHA_PART?
11080
+      /x;
9911 11081
   
9912
-      Carp::confess("illegal requirements: exact specification outside of range")
9913
-        unless $self->_accepts($version);
11082
+  # Lax dotted-decimal version number.  Distinguished by having either
11083
+  # leading "v" or at least three non-alpha parts.  Alpha part is only
11084
+  # permitted if there are at least two non-alpha parts. Strangely
11085
+  # enough, without the leading "v", Perl takes .1.2 to mean v0.1.2,
11086
+  # so when there is no "v", the leading part is optional
9914 11087
   
9915
-      return Version::Requirements::_Range::Exact->_new($version);
9916
-    }
11088
+  my $LAX_DOTTED_DECIMAL_VERSION =
11089
+      qr/
11090
+  	v $LAX_INTEGER_PART (?: $LAX_DOTTED_DECIMAL_PART+ $LAX_ALPHA_PART? )?
11091
+  	|
11092
+  	$LAX_INTEGER_PART? $LAX_DOTTED_DECIMAL_PART{2,} $LAX_ALPHA_PART?
11093
+      /x;
9917 11094
   
9918
-    sub _simplify {
9919
-      my ($self) = @_;
11095
+  # Complete lax version number syntax -- should generally be used
11096
+  # anchored: qr/ \A $LAX \z /x
11097
+  #
11098
+  # The string 'undef' is a special case to make for easier handling
11099
+  # of return values from ExtUtils::MM->parse_version
9920 11100
   
9921
-      if (defined $self->{minimum} and defined $self->{maximum}) {
9922
-        if ($self->{minimum} == $self->{maximum}) {
9923
-          Carp::confess("illegal requirements: excluded all values")
9924
-            if grep { $_ == $self->{minimum} } @{ $self->{exclusions} || [] };
11101
+  $LAX =
11102
+      qr/ undef | $LAX_DECIMAL_VERSION | $LAX_DOTTED_DECIMAL_VERSION /x;
9925 11103
   
9926
-          return Version::Requirements::_Range::Exact->_new($self->{minimum})
9927
-        }
11104
+  #--------------------------------------------------------------------------#
9928 11105
   
9929
-        Carp::confess("illegal requirements: minimum exceeds maximum")
9930
-          if $self->{minimum} > $self->{maximum};
11106
+  {
11107
+      local $SIG{'__DIE__'};
11108
+      eval "use version::vxs $VERSION";
11109
+      if ( $@ ) { # don't have the XS version installed
11110
+  	eval "use version::vpp $VERSION"; # don't tempt fate
11111
+  	die "$@" if ( $@ );
11112
+  	push @ISA, "version::vpp";
11113
+  	local $^W;
11114
+  	*version::qv = \&version::vpp::qv;
11115
+  	*version::declare = \&version::vpp::declare;
11116
+  	*version::_VERSION = \&version::vpp::_VERSION;
11117
+  	*version::vcmp = \&version::vpp::vcmp;
11118
+  	if ($] >= 5.009000) {
11119
+  	    no strict 'refs';
11120
+  	    *version::stringify = \&version::vpp::stringify;
11121
+  	    *{'version::(""'} = \&version::vpp::stringify;
11122
+  	    *{'version::(<=>'} = \&version::vpp::vcmp;
11123
+  	    *version::new = \&version::vpp::new;
11124
+  	    *version::parse = \&version::vpp::parse;
11125
+  	}
9931 11126
       }
11127
+      else { # use XS module
11128
+  	push @ISA, "version::vxs";
11129
+  	local $^W;
11130
+  	*version::declare = \&version::vxs::declare;
11131
+  	*version::qv = \&version::vxs::qv;
11132
+  	*version::_VERSION = \&version::vxs::_VERSION;
11133
+  	*version::vcmp = \&version::vxs::VCMP;
11134
+  	if ($] >= 5.009000) {
11135
+  	    no strict 'refs';
11136
+  	    *version::stringify = \&version::vxs::stringify;
11137
+  	    *{'version::(""'} = \&version::vxs::stringify;
11138
+  	    *{'version::(<=>'} = \&version::vxs::VCMP;
11139
+  	    *version::new = \&version::vxs::new;
11140
+  	    *version::parse = \&version::vxs::parse;
11141
+  	}
9932 11142
   
9933
-      # eliminate irrelevant exclusions
9934
-      if ($self->{exclusions}) {
9935
-        my %seen;
9936
-        @{ $self->{exclusions} } = grep {
9937
-          (! defined $self->{minimum} or $_ >= $self->{minimum})
9938
-          and
9939
-          (! defined $self->{maximum} or $_ <= $self->{maximum})
9940
-          and
9941
-          ! $seen{$_}++
9942
-        } @{ $self->{exclusions} };
9943 11143
       }
11144
+  }
9944 11145
   
9945
-      return $self;
9946
-    }
9947
-  
9948
-    sub with_minimum {
9949
-      my ($self, $minimum) = @_;
9950
-      $self = $self->_clone;
11146
+  # Preloaded methods go here.
11147
+  sub import {
11148
+      no strict 'refs';
11149
+      my ($class) = shift;
9951 11150
   
9952
-      if (defined (my $old_min = $self->{minimum})) {
9953
-        $self->{minimum} = (sort { $b cmp $a } ($minimum, $old_min))[0];
9954
-      } else {
9955
-        $self->{minimum} = $minimum;
11151
+      # Set up any derived class
11152
+      unless ($class eq 'version') {
11153
+  	local $^W;
11154
+  	*{$class.'::declare'} =  \&version::declare;
11155
+  	*{$class.'::qv'} = \&version::qv;
9956 11156
       }
9957 11157
   
9958
-      return $self->_simplify;
9959
-    }
9960
-  
9961
-    sub with_maximum {
9962
-      my ($self, $maximum) = @_;
9963
-      $self = $self->_clone;
9964
-  
9965
-      if (defined (my $old_max = $self->{maximum})) {
9966
-        $self->{maximum} = (sort { $a cmp $b } ($maximum, $old_max))[0];
9967
-      } else {
9968
-        $self->{maximum} = $maximum;
11158
+      my %args;
11159
+      if (@_) { # any remaining terms are arguments
11160
+  	map { $args{$_} = 1 } @_
11161
+      }
11162
+      else { # no parameters at all on use line
11163
+      	%args = 
11164
+  	(
11165
+  	    qv => 1,
11166
+  	    'UNIVERSAL::VERSION' => 1,
11167
+  	);
9969 11168
       }
9970 11169
   
9971
-      return $self->_simplify;
9972
-    }
9973
-  
9974
-    sub with_exclusion {
9975
-      my ($self, $exclusion) = @_;
9976
-      $self = $self->_clone;
11170
+      my $callpkg = caller();
11171
+      
11172
+      if (exists($args{declare})) {
11173
+  	*{$callpkg.'::declare'} = 
11174
+  	    sub {return $class->declare(shift) }
11175
+  	  unless defined(&{$callpkg.'::declare'});
11176
+      }
9977 11177
   
9978
-      push @{ $self->{exclusions} ||= [] }, $exclusion;
11178
+      if (exists($args{qv})) {
11179
+  	*{$callpkg.'::qv'} =
11180
+  	    sub {return $class->qv(shift) }
11181
+  	  unless defined(&{$callpkg.'::qv'});
11182
+      }
9979 11183
   
9980
-      return $self->_simplify;
9981
-    }
11184
+      if (exists($args{'UNIVERSAL::VERSION'})) {
11185
+  	local $^W;
11186
+  	*UNIVERSAL::VERSION 
11187
+  		= \&version::_VERSION;
11188
+      }
9982 11189
   
9983
-    sub _accepts {
9984
-      my ($self, $version) = @_;
11190
+      if (exists($args{'VERSION'})) {
11191
+  	*{$callpkg.'::VERSION'} = \&version::_VERSION;
11192
+      }
9985 11193
   
9986
-      return if defined $self->{minimum} and $version < $self->{minimum};
9987
-      return if defined $self->{maximum} and $version > $self->{maximum};
9988
-      return if defined $self->{exclusions}
9989
-            and grep { $version == $_ } @{ $self->{exclusions} };
11194
+      if (exists($args{'is_strict'})) {
11195
+  	*{$callpkg.'::is_strict'} = \&version::is_strict
11196
+  	  unless defined(&{$callpkg.'::is_strict'});
11197
+      }
9990 11198
   
9991
-      return 1;
9992
-    }
11199
+      if (exists($args{'is_lax'})) {
11200
+  	*{$callpkg.'::is_lax'} = \&version::is_lax
11201
+  	  unless defined(&{$callpkg.'::is_lax'});
11202
+      }
9993 11203
   }
9994 11204
   
9995
-  1;
9996
-  
9997
-  __END__
9998
-  =pod
11205
+  sub is_strict	{ defined $_[0] && $_[0] =~ qr/ \A $STRICT \z /x }
11206
+  sub is_lax	{ defined $_[0] && $_[0] =~ qr/ \A $LAX \z /x }
9999 11207
   
10000
-VERSION_REQUIREMENTS
11208
+  1;
11209
+VERSION
10001 11210
 
10002 11211
 $fatpacked{"version/vpp.pm"} = <<'VERSION_VPP';
10003 11212
   package charstar;
... ...
@@ -10123,7 +11332,7 @@ $fatpacked{"version/vpp.pm"} = <<'VERSION_VPP';
10123 11332
   use POSIX qw/locale_h/;
10124 11333
   use locale;
10125 11334
   use vars qw ($VERSION @ISA @REGEXS);
10126
-  $VERSION = 0.88;
11335
+  $VERSION = 0.9901;
10127 11336
   
10128 11337
   use overload (
10129 11338
       '""'       => \&stringify,
... ...
@@ -10131,13 +11340,22 @@ $fatpacked{"version/vpp.pm"} = <<'VERSION_VPP';
10131 11340
       'cmp'      => \&vcmp,
10132 11341
       '<=>'      => \&vcmp,
10133 11342
       'bool'     => \&vbool,
10134
-      'nomethod' => \&vnoop,
11343
+      '+'        => \&vnoop,
11344
+      '-'        => \&vnoop,
11345
+      '*'        => \&vnoop,
11346
+      '/'        => \&vnoop,
11347
+      '+='        => \&vnoop,
11348
+      '-='        => \&vnoop,
11349
+      '*='        => \&vnoop,
11350
+      '/='        => \&vnoop,
11351
+      'abs'      => \&vnoop,
10135 11352
   );
10136 11353
   
10137 11354
   eval "use warnings";
10138 11355
   if ($@) {
10139 11356
       eval '
10140
-  	package warnings;
11357
+  	package
11358
+  	warnings;
10141 11359
   	sub enabled {return $^W;}
10142 11360
   	1;
10143 11361
       ';
... ...
@@ -10255,7 +11473,7 @@ $fatpacked{"version/vpp.pm"} = <<'VERSION_VPP';
10255 11473
   		}
10256 11474
   		$j = 0;
10257 11475
   	    }
10258
-  	
11476
+  
10259 11477
   	    if ($strict && $i < 2) {
10260 11478
   		# requires v1.2.3
10261 11479
   		return BADVERSION($s,$errstr,"Invalid version format (dotted-decimal versions require at least three parts)");
... ...
@@ -10264,6 +11482,7 @@ $fatpacked{"version/vpp.pm"} = <<'VERSION_VPP';
10264 11482
       } 					# end if dotted-decimal
10265 11483
       else
10266 11484
       {					# decimal versions
11485
+  	my $j = 0;
10267 11486
   	# special $strict case for leading '.' or '0'
10268 11487
   	if ($strict) {
10269 11488
   	    if ($d eq '.') {
... ...
@@ -10274,6 +11493,11 @@ $fatpacked{"version/vpp.pm"} = <<'VERSION_VPP';
10274 11493
   	    }
10275 11494
   	}
10276 11495
   
11496
+  	# and we never support negative version numbers
11497
+  	if ($d eq '-') {
11498
+  	    return BADVERSION($s,$errstr,"Invalid version format (negative version number)");
11499
+  	}
11500
+  
10277 11501
   	# consume all of the integer part
10278 11502
   	while (isDIGIT($d)) {
10279 11503
   	    $d++;
... ...
@@ -10321,7 +11545,7 @@ $fatpacked{"version/vpp.pm"} = <<'VERSION_VPP';
10321 11545
   	}
10322 11546
   
10323 11547
   	while (isDIGIT($d)) {
10324
-  	    $d++;
11548
+  	    $d++; $j++;
10325 11549
   	    if ($d eq '.' && isDIGIT($d-1)) {
10326 11550
   		if ($alpha) {
10327 11551
   		    return BADVERSION($s,$errstr,"Invalid version format (underscores before decimal)");
... ...
@@ -10343,6 +11567,7 @@ $fatpacked{"version/vpp.pm"} = <<'VERSION_VPP';
10343 11567
   		if ( ! isDIGIT($d+1) ) {
10344 11568
   		    return BADVERSION($s,$errstr,"Invalid version format (misplaced underscore)");
10345 11569
   		}
11570
+  		$width = $j;
10346 11571
   		$d++;
10347 11572
   		$alpha = TRUE;
10348 11573
   	    }
... ...
@@ -10418,7 +11643,7 @@ $fatpacked{"version/vpp.pm"} = <<'VERSION_VPP';
10418 11643
       if ( !$qv && $width < 3 ) {
10419 11644
   	$$rv->{width} = $width;
10420 11645
       }
10421
-      
11646
+  
10422 11647
       while (isDIGIT($pos)) {
10423 11648
   	$pos++;
10424 11649
       }
... ...
@@ -10443,7 +11668,7 @@ $fatpacked{"version/vpp.pm"} = <<'VERSION_VPP';
10443 11668
   			$orev = $rev;
10444 11669
    			$rev += $s * $mult;
10445 11670
    			$mult /= 10;
10446
-  			if (   (abs($orev) > abs($rev)) 
11671
+  			if (   (abs($orev) > abs($rev))
10447 11672
   			    || (abs($rev) > $VERSION_MAX )) {
10448 11673
   			    warn("Integer overflow in version %d",
10449 11674
   					   $VERSION_MAX);
... ...
@@ -10462,7 +11687,7 @@ $fatpacked{"version/vpp.pm"} = <<'VERSION_VPP';
10462 11687
   			$orev = $rev;
10463 11688
    			$rev += $end * $mult;
10464 11689
    			$mult *= 10;
10465
-  			if (   (abs($orev) > abs($rev)) 
11690
+  			if (   (abs($orev) > abs($rev))
10466 11691
   			    || (abs($rev) > $VERSION_MAX )) {
10467 11692
   			    warn("Integer overflow in version");
10468 11693
   			    $end = $s - 1;
... ...
@@ -10470,7 +11695,7 @@ $fatpacked{"version/vpp.pm"} = <<'VERSION_VPP';
10470 11695
   			    $vinf = 1;
10471 11696
   			}
10472 11697
    		    }
10473
-   		} 
11698
+   		}
10474 11699
     	    }
10475 11700
   
10476 11701
     	    # Append revision
... ...
@@ -10519,7 +11744,7 @@ $fatpacked{"version/vpp.pm"} = <<'VERSION_VPP';
10519 11744
   	#  gcc version 3.3 20030304 (Apple Computer, Inc. build 1640)
10520 11745
   	#  for ( len = 2 - len; len > 0; len-- )
10521 11746
   	#  av_push(MUTABLE_AV(sv), newSViv(0));
10522
-  	# 
11747
+  	#
10523 11748
   	$len = 2 - $len;
10524 11749
   	while ($len-- > 0) {
10525 11750
   	    push @av, 0;
... ...
@@ -10559,7 +11784,7 @@ $fatpacked{"version/vpp.pm"} = <<'VERSION_VPP';
10559 11784
   	my ($class, $value) = @_;
10560 11785
   	my $self = bless ({}, ref ($class) || $class);
10561 11786
   	my $qv = FALSE;
10562
-  	
11787
+  
10563 11788
   	if ( ref($value) && eval('$value->isa("version")') ) {
10564 11789
   	    # Can copy the elements directly
10565 11790
   	    $self->{version} = [ @{$value->{version} } ];
... ...
@@ -10598,7 +11823,7 @@ $fatpacked{"version/vpp.pm"} = <<'VERSION_VPP';
10598 11823
   	    $value = sprintf("%.9f",$value);
10599 11824
   	    $value =~ s/(0+)$//; # trim trailing zeros
10600 11825
   	}
10601
-  	
11826
+  
10602 11827
   	my $s = scan_version($value, \$self, $qv);
10603 11828
   
10604 11829
   	if ($s) { # must be something left over
... ...
@@ -10611,7 +11836,7 @@ $fatpacked{"version/vpp.pm"} = <<'VERSION_VPP';
10611 11836
   
10612 11837
   *parse = \&new;
10613 11838
   
10614
-  sub numify 
11839
+  sub numify
10615 11840
   {
10616 11841
       my ($self) = @_;
10617 11842
       unless (_verify($self)) {
... ...
@@ -10652,7 +11877,7 @@ $fatpacked{"version/vpp.pm"} = <<'VERSION_VPP';
10652 11877
       return $string;
10653 11878
   }
10654 11879
   
10655
-  sub normal 
11880
+  sub normal
10656 11881
   {
10657 11882
       my ($self) = @_;
10658 11883
       unless (_verify($self)) {
... ...
@@ -10695,9 +11920,9 @@ $fatpacked{"version/vpp.pm"} = <<'VERSION_VPP';
10695 11920
   	require Carp;
10696 11921
   	Carp::croak("Invalid version object");
10697 11922
       }
10698
-      return exists $self->{original} 
10699
-      	? $self->{original} 
10700
-  	: exists $self->{qv} 
11923
+      return exists $self->{original}
11924
+      	? $self->{original}
11925
+  	: exists $self->{qv}
10701 11926
   	    ? $self->normal
10702 11927
   	    : $self->numify;
10703 11928
   }
... ...
@@ -10720,7 +11945,7 @@ $fatpacked{"version/vpp.pm"} = <<'VERSION_VPP';
10720 11945
       }
10721 11946
       unless (_verify($right)) {
10722 11947
   	require Carp;
10723
-  	Carp::croak("Invalid version object");
11948
+  	Carp::croak("Invalid version format");
10724 11949
       }
10725 11950
       my $l = $#{$left->{version}};
10726 11951
       my $r = $#{$right->{version}};
... ...
@@ -10735,8 +11960,8 @@ $fatpacked{"version/vpp.pm"} = <<'VERSION_VPP';
10735 11960
       }
10736 11961
   
10737 11962
       # tiebreaker for alpha with identical terms
10738
-      if ( $retval == 0 
10739
-  	&& $l == $r 
11963
+      if ( $retval == 0
11964
+  	&& $l == $r
10740 11965
   	&& $left->{version}[$m] == $right->{version}[$m]
10741 11966
   	&& ( $lalpha || $ralpha ) ) {
10742 11967
   
... ...
@@ -10768,7 +11993,7 @@ $fatpacked{"version/vpp.pm"} = <<'VERSION_VPP';
10768 11993
   	}
10769 11994
       }
10770 11995
   
10771
-      return $retval;  
11996
+      return $retval;
10772 11997
   }
10773 11998
   
10774 11999
   sub vbool {
... ...
@@ -10776,8 +12001,8 @@ $fatpacked{"version/vpp.pm"} = <<'VERSION_VPP';
10776 12001
       return vcmp($self,$self->new("0"),1);
10777 12002
   }
10778 12003
   
10779
-  sub vnoop { 
10780
-      require Carp; 
12004
+  sub vnoop {
12005
+      require Carp;
10781 12006
       Carp::croak("operation not supported with version object");
10782 12007
   }
10783 12008
   
... ...
@@ -10796,8 +12021,8 @@ $fatpacked{"version/vpp.pm"} = <<'VERSION_VPP';
10796 12021
   
10797 12022
       $value = _un_vstring($value);
10798 12023
       $value = 'v'.$value unless $value =~ /(^v|\d+\.\d+\.\d)/;
10799
-      my $version = $class->new($value);
10800
-      return $version;
12024
+      my $obj = version->new($value);
12025
+      return bless $obj, $class;
10801 12026
   }
10802 12027
   
10803 12028
   *declare = \&qv;
... ...
@@ -10835,7 +12060,7 @@ $fatpacked{"version/vpp.pm"} = <<'VERSION_VPP';
10835 12060
   sub _un_vstring {
10836 12061
       my $value = shift;
10837 12062
       # may be a v-string
10838
-      if ( length($value) >= 3 && $value !~ /[._]/ 
12063
+      if ( length($value) >= 3 && $value !~ /[._]/
10839 12064
   	&& _is_non_alphanumeric($value)) {
10840 12065
   	my $tvalue;
10841 12066
   	if ( $] ge 5.008_001 ) {
... ...
@@ -10893,7 +12118,7 @@ $fatpacked{"version/vpp.pm"} = <<'VERSION_VPP';
10893 12118
       if ( defined $req ) {
10894 12119
   	unless ( defined $version ) {
10895 12120
   	    require Carp;
10896
-  	    my $msg =  $] < 5.006 
12121
+  	    my $msg =  $] < 5.006
10897 12122
   	    ? "$class version $req required--this is only version "
10898 12123
   	    : "$class does not define \$$class\::VERSION"
10899 12124
   	      ."--version check failed";
... ...
@@ -10911,14 +12136,14 @@ $fatpacked{"version/vpp.pm"} = <<'VERSION_VPP';
10911 12136
   	if ( $req > $version ) {
10912 12137
   	    require Carp;
10913 12138
   	    if ( $req->is_qv ) {
10914
-  		Carp::croak( 
12139
+  		Carp::croak(
10915 12140
   		    sprintf ("%s version %s required--".
10916 12141
   			"this is only version %s", $class,
10917 12142
   			$req->normal, $version->normal)
10918 12143
   		);
10919 12144
   	    }
10920 12145
   	    else {
10921
-  		Carp::croak( 
12146
+  		Carp::croak(
10922 12147
   		    sprintf ("%s version %s required--".
10923 12148
   			"this is only version %s", $class,
10924 12149
   			$req->stringify, $version->stringify)
... ...
@@ -10937,6 +12162,14 @@ s/^  //mg for values %fatpacked;
10937 12162
 
10938 12163
 unshift @INC, sub {
10939 12164
   if (my $fat = $fatpacked{$_[1]}) {
12165
+    if ($] < 5.008) {
12166
+      return sub {
12167
+        return 0 unless length $fat;
12168
+        $fat =~ s/^([^\n]*\n?)//;
12169
+        $_ = $1;
12170
+        return 1;
12171
+      };
12172
+    }
10940 12173
     open my $fh, '<', \$fat
10941 12174
       or die "FatPacker error loading $_[1] (could be a perl installation issue?)";
10942 12175
     return $fh;
... ...
@@ -10963,21 +12196,54 @@ cpanm - get, unpack build and install modules from CPAN
10963 12196
 
10964 12197
 =head1 SYNOPSIS
10965 12198
 
10966
-  cpanm Test::More                                          # install Test::More
10967
-  cpanm MIYAGAWA/Plack-0.99_05.tar.gz                       # full distribution path
10968
-  cpanm http://example.org/LDS/CGI.pm-3.20.tar.gz           # install from URL
10969
-  cpanm ~/dists/MyCompany-Enterprise-1.00.tar.gz            # install from a local file
10970
-  cpanm --interactive Task::Kensho                          # Configure interactively
10971
-  cpanm .                                                   # install from local directory
10972
-  cpanm --installdeps .                                     # install all the deps for the current directory
10973
-  cpanm -L extlib Plack                                     # install Plack and all non-core deps into extlib
10974
-  cpanm --mirror http://cpan.cpantesters.org/ DBI           # use the fast-syncing mirror
10975
-  cpanm --scandeps Moose                                    # See what modules will be installed for Moose
12199
+  cpanm Test::More                                 # install Test::More
12200
+  cpanm MIYAGAWA/Plack-0.99_05.tar.gz              # full distribution path
12201
+  cpanm http://example.org/LDS/CGI.pm-3.20.tar.gz  # install from URL
12202
+  cpanm ~/dists/MyCompany-Enterprise-1.00.tar.gz   # install from a local file
12203
+  cpanm --interactive Task::Kensho                 # Configure interactively
12204
+  cpanm .                                          # install from local directory
12205
+  cpanm --installdeps .                            # install all the deps for the current directory
12206
+  cpanm -L extlib Plack                            # install Plack and all non-core deps into extlib
12207
+  cpanm --mirror http://cpan.cpantesters.org/ DBI  # use the fast-syncing mirror
12208
+  cpanm --scandeps Moose                           # See what modules will be installed for Moose
10976 12209
 
10977 12210
 =head1 COMMANDS
10978 12211
 
10979 12212
 =over 4
10980 12213
 
12214
+=item (arguments)
12215
+
12216
+Command line arguments can be either a module name, distribution file,
12217
+local file path, HTTP URL or git repository URL. Following commands
12218
+will all work as you expect.
12219
+
12220
+    cpanm Plack
12221
+    cpanm Plack/Request.pm
12222
+    cpanm MIYAGAWA/Plack-1.0000.tar.gz
12223
+    cpanm /path/to/Plack-1.0000.tar.gz
12224
+    cpanm http://cpan.metacpan.org/authors/id/M/MI/MIYAGAWA/Plack-0.9990.tar.gz
12225
+    cpanm git://github.com/miyagawa/Plack.git
12226
+
12227
+Additionally, you can use the notation using C<~> and C<@> to specify
12228
+version for a given module. C<~> specifies the version requirement in
12229
+the L<CPAN::Meta::Spec> format, while C<@> pins the exact version, and
12230
+is a shortcut for C<~"== VERSION">.
12231
+
12232
+    cpanm Plack~1.0000                 # 1.0000 or later
12233
+    cpanm Plack~">= 1.0000, < 2.0000"  # latest of 1.xxxx
12234
+    cpanm Plack@0.9990                 # specific version. same as Plack~"== 0.9990"
12235
+
12236
+The version query including specific version or range will be sent to
12237
+L<MetaCPAN> to search for previous releases. The query will search for
12238
+BackPAN archives by default, unless you specify C<--dev> option, in
12239
+which case, archived versions will be filtered out.
12240
+
12241
+For a git repository, you can specify a branch, tag, or commit SHA to
12242
+build. The default is C<master>
12243
+
12244
+    cpanm git://github.com/miyagawa/Plack.git@1.0000        # tag
12245
+    cpanm git://github.com/miyagawa/Plack.git@devel         # branch
12246
+
10981 12247
 =item -i, --install
10982 12248
 
10983 12249
 Installs the modules. This is a default behavior and this is just a
... ...
@@ -11037,6 +12303,16 @@ architecture you've already tested to make sure it builds fine.
11037 12303
 Defaults to false, and you can say C<--no-notest> to override when it
11038 12304
 is set in the default options in C<PERL_CPANM_OPT>.
11039 12305
 
12306
+=item --test-only
12307
+
12308
+Run the tests only, and do not install the specified module or
12309
+distributions. Handy if you want to verify the new (or even old)
12310
+releases pass its unit tests without installing the module.
12311
+
12312
+Note that if you specify this option with a module or distribution
12313
+that has dependencies, these dependencies will be installed if you
12314
+don't currently have them.
12315
+
11040 12316
 =item -S, --sudo
11041 12317
 
11042 12318
 Switch to the root user with C<sudo> when installing modules. Use this
... ...
@@ -11084,6 +12360,14 @@ Specifies the base URL for the CPAN mirror to use, such as
11084 12360
 C<http://cpan.cpantesters.org/> (you can omit the trailing slash). You
11085 12361
 can specify multiple mirror URLs by repeating the command line option.
11086 12362
 
12363
+You can use a local directory that has a CPAN mirror structure
12364
+(created by tools such as L<OrePAN> or L<Pinto>) by using a special
12365
+URL scheme C<file://>. If the given URL begins with `/` (without any
12366
+scheme), it is considered as a file scheme as well.
12367
+
12368
+  cpanm --mirror file:///path/to/mirror
12369
+  cpanm --mirror ~/minicpan      # Because shell expands ~ to /home/user
12370
+
11087 12371
 Defaults to C<http://search.cpan.org/CPAN> which is a geo location
11088 12372
 aware redirector.
11089 12373
 
... ...
@@ -11106,11 +12390,6 @@ shell aliases, like:
11106 12390
 B<EXPERIMENTAL>: Specifies the file path to C<02packages.details.txt>
11107 12391
 for module search index.
11108 12392
 
11109
-=item --metacpan
11110
-
11111
-B<EXPERIMENTAL>: Use L<http://api.metacpan.org/> API for module lookup instead of
11112
-L<http://cpanmetadb.plackperl.org/>.
11113
-    
11114 12393
 =item --prompt
11115 12394
 
11116 12395
 Prompts when a test fails so that you can skip, force install, retry
... ...
@@ -11120,6 +12399,10 @@ one of the dependency failed if you want to proceed the installation.
11120 12399
 Defaults to false, and you can say C<--no-prompt> to override if it's
11121 12400
 set in the default options in C<PERL_CPANM_OPT>.
11122 12401
 
12402
+=item --dev
12403
+
12404
+B<EXPERIMENTAL>: search for a newer developer release as well. Defaults to false.
12405
+
11123 12406
 =item --reinstall
11124 12407
 
11125 12408
 cpanm, when given a module name in the command line (i.e. C<cpanm
... ...
@@ -11232,8 +12515,8 @@ library path.
11232 12515
 =item --cascade-search
11233 12516
 
11234 12517
 B<EXPERIMENTAL>: Specifies whether to cascade search when you specify
11235
-multiple mirrors and a mirror has a lower version of the module than
11236
-requested. Defaults to false.
12518
+multiple mirrors and a mirror doesn't have a module or has a lower
12519
+version of the module than requested. Defaults to false.
11237 12520
 
11238 12521
 =item --skip-installed
11239 12522
 
... ...
@@ -11258,8 +12541,12 @@ C<--skip-installed> but while C<--skip-installed> checks if the
11258 12541
 I<latest> version of CPAN is installed, C<--skip-satisfied> checks if
11259 12542
 a requested version (or not, which means any version) is installed.
11260 12543
 
11261
-Defaults to false for bare module names, but if you specify versions
11262
-with C<~>, it will always skip satisfied requirements.
12544
+Defaults to false.
12545
+
12546
+=item --verify
12547
+
12548
+Verify the integrity of distribution files retrieved from PAUSE using
12549
+CHECKSUMS and SIGNATURES (if found). Defaults to false.
11263 12550
 
11264 12551
 =item --auto-cleanup
11265 12552
 
+1
templates/main/admin.html.ep
... ...
@@ -7,3 +7,4 @@
7 7
     <td><a href="/_admin/user">User</a></td>
8 8
   </tr>
9 9
 </table>
10
+