The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
Changes 340
LICENSE 22
MANIFEST 512
META.json 812
META.yml 79
Makefile.PL 22
README 33
examples/isbn-check.pl 00
lib/WWW/Scraper/ISBN/AmazonUK_Driver.pm 2257
lib/WWW/Scraper/ISBN/AmazonUS_Driver.pm 2959
lib/WWW/Scraper/ISBN/Amazon_Driver.pm 063
t/01basic.t 12
t/10objectus.t 98
t/11objectuk.t 87
t/20parse-us.t 070
t/21parse-uk.t 070
t/94metatest.t 08
t/96metatest.t 19
t/data/all-fields-uk.html 0109
t/data/all-fields-us.html 068
t/data/empty-fields.html 08
t/lib/Fake/Mechanize.pm 041
22 files changed (This is a version diff) 100659
@@ -1,8 +1,45 @@
-Revision history for WWW::Scraper::ISBN::Amazon_Driver
-======================================================
+Revision history for WWW-Scraper-ISBN-Amazon_Driver
+===================================================
+
+0.41    2014-11-01
+        - ping fix for Cygwin (thanks to Alexandr Ciornii).
+        - uninitialized warning fix.
+
+0.40    2014-09-17
+        - fixed license fields in META.json to be lists.
+        - added new title/author pattern.
+
+0.39    2014-08-14
+        - further fixes for UK layout changes.
+
+0.38    2014-08-04
+        - fixed for UK website update.
+        - fixed UK site testing.
+
+0.37    2014-05-29
+        - added conversion routines to obtain EAN13.
+        - upgrade to WWW-Scraper-ISBN-1.00.
+        - changed to regex test for weight data on US site.
+        - fixed META tests to catch version differences.
+
+0.36    2014-04-28
+        - amazon.com updated HTML output.
+        - fixed distribution name in META.
+
+0.35    2014-04-05
+        - reduce size of test data footprint.
+
+0.34    2014-04-02
+        - getting the size can still fail, if data not available.
+        - extract parse functionality into separate method, to allow testing.
+        - protect against missing values causing undef errors.
+        - extended test suite.
+
+0.33    2014-03-24
+        - added Amazon_Driver.pm, to help with PAUSE permissions.
 
 0.32    2013-11-08
-        - amazon.com updated dscription for Perl Medic.
+        - amazon.com updated description for Perl Medic.
 
 0.31    2013-10-19
         - added git repository links to metadata.
@@ -1,6 +1,6 @@
-LICENSE FOR WWW-Scraper-ISBN-Amazon_Driver
+LICENSE for WWW-Scraper-ISBN-Amazon_Driver
 
-Copyright © 2004-2013 Barbie for Miss Barbell Productions.
+Copyright © 2004-2014 Barbie for Miss Barbell Productions.
 
 This distribution is free software; you can redistribute it and/or
 modify it under the Artistic Licence v2.
@@ -1,20 +1,27 @@
 Changes
+examples/examples.txt
+examples/isbn-check.pl
+lib/WWW/Scraper/ISBN/Amazon_Driver.pm
+lib/WWW/Scraper/ISBN/AmazonUK_Driver.pm
+lib/WWW/Scraper/ISBN/AmazonUS_Driver.pm
 LICENSE
+Makefile.PL
 MANIFEST
 META.json
 META.yml
-Makefile.PL
 README
-examples/examples.txt
-examples/isbn-check.pl
-lib/WWW/Scraper/ISBN/AmazonUK_Driver.pm
-lib/WWW/Scraper/ISBN/AmazonUS_Driver.pm
 t/01basic.t
 t/10objectus.t
 t/11objectuk.t
+t/20parse-us.t
+t/21parse-uk.t
 t/90podtest.t
 t/91podcover.t
 t/92distribution.t
 t/94metatest.t
 t/95changedate.t
 t/96metatest.t
+t/data/all-fields-uk.html
+t/data/all-fields-us.html
+t/data/empty-fields.html
+t/lib/Fake/Mechanize.pm
@@ -1,17 +1,17 @@
 {
     "name": "WWW-Scraper-ISBN-Amazon_Driver",
-    "version": "0.32",
+    "version": "0.41",
     "abstract": "Search drivers for the Amazon online catalog.",
     "author": ["Barbie <barbie@cpan.org>"],
 
-    "license": "artistic_2",
+    "license": [ "artistic_2" ],
     "dynamic_config" : 0,
     "release_status" : "stable",
     "meta-spec": {
         "version": "2",
         "url": "http://search.cpan.org/dist/CPAN-Meta/lib/CPAN/Meta/Spec.pm"
     },
-    "generated_by": "Hand 1.0",
+    "generated_by": "The Hand of Barbie 1.0",
     "keywords" : [
         "isbn",
         "books",
@@ -24,8 +24,8 @@
                 "perl": "5.006",
                 "JSON": "0",
                 "WWW::Mechanize": "1.60",
-                "WWW::Scraper::ISBN": "0.25",
-                "WWW::Scraper::ISBN::Driver": "0.18"
+                "WWW::Scraper::ISBN": "1.00",
+                "WWW::Scraper::ISBN::Driver": "1.00"
             }
         },
         "test" : {
@@ -44,13 +44,17 @@
     },
 
     "provides": {
+        "WWW::Scraper::ISBN::Amazon_Driver": {
+            "file": "lib/WWW/Scraper/ISBN/Amazon_Driver.pm",
+            "version": "0.41"
+        },
         "WWW::Scraper::ISBN::AmazonUK_Driver": {
             "file": "lib/WWW/Scraper/ISBN/AmazonUK_Driver.pm",
-            "version": "0.32"
+            "version": "0.41"
         },
         "WWW::Scraper::ISBN::AmazonUS_Driver": {
             "file": "lib/WWW/Scraper/ISBN/AmazonUS_Driver.pm",
-            "version": "0.32"
+            "version": "0.41"
         }
     },
     "no_index": {
@@ -58,7 +62,7 @@
     },
 
     "resources": {
-        "license": "http://www.perlfoundation.org/artistic_license_2_0",
+        "license": [ "http://www.perlfoundation.org/artistic_license_2_0" ],
         "bugtracker": { "web": "http://rt.cpan.org/Public/Dist/Display.html?Name=WWW-Scraper-ISBN-Amazon_Driver" },
         "repository": {
             "url": "git://github.com/barbie/www-scraper-isbn-amazon_driver.git",
@@ -1,6 +1,6 @@
 --- #YAML:1.0
 name:                   WWW-Scraper-ISBN-Amazon_Driver
-version:                0.32
+version:                0.41
 abstract:               Search drivers for the Amazon online catalog.
 author:
   - Barbie <barbie@cpan.org>
@@ -13,8 +13,8 @@ requires:
   perl:                         5.006
   JSON:                         0
   WWW::Mechanize:               1.60
-  WWW::Scraper::ISBN:           0.25
-  WWW::Scraper::ISBN::Driver:   0.18
+  WWW::Scraper::ISBN:           1.00
+  WWW::Scraper::ISBN::Driver:   1.00
 recommends:
   Test::CPAN::Meta:             0
   Test::CPAN::Meta::JSON:       0
@@ -26,12 +26,15 @@ build_requires:
   Test::More:                   0.70
 
 provides:
+  WWW::Scraper::ISBN::Amazon_Driver:
+    file:     lib/WWW/Scraper/ISBN/Amazon_Driver.pm
+    version:  0.41
   WWW::Scraper::ISBN::AmazonUK_Driver:
     file:     lib/WWW/Scraper/ISBN/AmazonUK_Driver.pm
-    version:  0.32
+    version:  0.41
   WWW::Scraper::ISBN::AmazonUS_Driver:
     file:     lib/WWW/Scraper/ISBN/AmazonUS_Driver.pm
-    version:  0.32
+    version:  0.41
 no_index:
   directory:
     - t
@@ -45,5 +48,4 @@ resources:
 meta-spec:
    version:   1.4
    url:       http://module-build.sourceforge.net/META-spec-v1.4.html
-generated_by: Hand 1.0
-
+generated_by: The Hand of Barbie 1.0
@@ -16,9 +16,9 @@ WriteMakefile(
 
         # prereqs
         'JSON'                          => '0',
-        'WWW::Scraper::ISBN'            => '0.25',
-        'WWW::Scraper::ISBN::Driver'    => '0.18',
         'WWW::Mechanize'                => '1.60',
+        'WWW::Scraper::ISBN'            => '1.00',
+        'WWW::Scraper::ISBN::Driver'    => '1.00',
 
         # build/test prereqs
         'Data::Dumper'                  => '0',
@@ -1,5 +1,5 @@
-WWW::Scraper::ISBN::Amazon_Driver
-=================================
+WWW-Scraper-ISBN-Amazon_Driver
+==============================
 
 This distribution contains two Perl extensions for the ISBN search collection 
 that is provide by WWW::Scraper::ISBN.
@@ -40,7 +40,7 @@ For optional testing the module would like these modules:
 
 COPYRIGHT AND LICENSE
 
-  Copyright (C) 2004-2013 Barbie for Miss Barbell Productions
+  Copyright (C) 2004-2014 Barbie for Miss Barbell Productions
 
   This distribution is free software; you can redistribute it and/or
   modify it under the Artistic Licence v2.
diff --git a/var/tmp/source/BARBIE/WWW-Scraper-ISBN-Amazon_Driver-0.32/WWW-Scraper-ISBN-Amazon_Driver-0.32/examples/isbn-check.pl b/var/tmp/source/BARBIE/WWW-Scraper-ISBN-Amazon_Driver-0.41/WWW-Scraper-ISBN-Amazon_Driver-0.41/examples/isbn-check.pl
old mode 100755
new mode 100644
@@ -4,7 +4,7 @@ use strict;
 use warnings;
 
 use vars qw($VERSION);
-$VERSION = '0.32';
+$VERSION = '0.41';
 
 #--------------------------------------------------------------------------
 
@@ -55,7 +55,7 @@ my $OZ2G  = 0.035274;       # number of ounces (oz) in a gram
 
 =item C<search()>
 
-Creates a query string, then passes the appropriate form fields to the 
+Creates a query string, then passes the appropriate form fields to the
 Amazon (UK) server.
 
 The returned page should be the correct catalog page for that ISBN. If not the
@@ -63,7 +63,7 @@ function returns zero and allows the next driver in the chain to have a go. If
 a valid page is returned, the following fields are returned via the book hash:
 
   isbn          (now returns isbn13)
-  isbn10        
+  isbn10
   isbn13
   ean13         (industry name)
   author
@@ -92,10 +92,16 @@ sub search {
 	$self->found(0);
 	$self->book(undef);
 
+    # validate and convert into EAN13 format
+    my $ean = $self->convert_to_ean13($isbn);
+    return $self->handler("Invalid ISBN specified [$isbn]")
+        if(!$ean || (length $isbn == 13 && $isbn ne $ean)
+                 || (length $isbn == 10 && $isbn ne $self->convert_to_isbn10($ean)));
+
 	my $mech = WWW::Mechanize->new();
     $mech->agent_alias( 'Linux Mozilla' );
 
-    my $search = $AMA_SEARCH . $isbn;
+    my $search = $AMA_SEARCH . $ean;
 
 	eval { $mech->get( $search ) };
     return $self->handler("Amazon UK website appears to be unavailable.")
@@ -111,6 +117,13 @@ sub search {
     return $self->handler("Amazon UK website appears to be unavailable.")
 	    if($@ || !$mech->success() || !$mech->content());
 
+    return $self->_parse($mech);
+}
+
+sub _parse {
+    my $self = shift;
+    my $mech = shift;
+
 	# The Book page
     my $html = $mech->content;
     my $data = {};
@@ -119,21 +132,26 @@ sub search {
 
     my @size                            = $html =~ m!<li><b>\s*Product Dimensions:\s*</b>\s*([\d.]+) x ([\d.]+) x ([\d.]+) (cm)\s*</li>!si;
     @size                               = $html =~ m!<li><b>\s*Product Dimensions:\s*</b>\s*([\d.]+) x ([\d.]+) x ([\d.]+) (inches)\s*</li>!si unless(@size);
-    my $type = pop @size;
-    ($data->{depth},$data->{width},$data->{height}) = sort @size;    
-    if($type eq 'cm') {
-        $data->{$_}  = int($data->{$_} * 10)  for(qw( height width depth ));
-    } elsif($type eq 'inches') {
-        $data->{$_}  = int($data->{$_} / $IN2MM)  for(qw( height width depth ));
+    if(@size) {
+        my $type = pop @size;
+        ($data->{depth},$data->{width},$data->{height}) = sort @size;
+        if($type eq 'cm') {
+            $data->{$_}  = int($data->{$_} * 10)  for(qw( height width depth ));
+        } elsif($type eq 'inches') {
+            $data->{$_}  = int($data->{$_} / $IN2MM)  for(qw( height width depth ));
+        }
     }
-    
+
     ($data->{binding},$data->{pages})   = $html =~ m!<li><b>(Paperback|Hardcover):</b>\s*([\d.]+)\s*pages</li>!si;
     ($data->{weight})                   = $html =~ m!<li><b>Shipping Weight:</b>\s*([\d.]+)\s*ounces</li>!si;
     ($data->{published})                = $html =~ m!<li><b>Publisher:</b>\s*(.*?)</li>!si;
     ($data->{isbn10})                   = $html =~ m!<li><b>ISBN-10:</b>\s*(.*?)</li>!si;
     ($data->{isbn13})                   = $html =~ m!<li><b>ISBN-13:</b>\s*(.*?)</li>!si;
     ($data->{content})                  = $html =~ m!<meta name="description" content="([^"]+)"!si;
-    ($data->{description})              = $html =~ m!From the Back Cover</h3>\s*<div class="productDescriptionWrapper"\s*>\s*<P>(.*?)<div!si;  
+    ($data->{description})              = $html =~ m!From the Back Cover</h3>\s*<div class="productDescriptionWrapper"\s*>\s*<P>(.*?)<div!si;
+    ($data->{description})              = $html =~ m!<div id="bookDescription_feature_div"[^>]*>.*?<noscript>(.*?)</noscript!si unless($data->{description});
+
+    $data->{weight} = int($data->{weight} / $OZ2G)  if($data->{weight});
 
     if($data->{description}) {
         $data->{description} =~ s!<[^>]+>!!g;
@@ -142,32 +160,49 @@ sub search {
 
     # The images
     my ($json) = $html =~ /var colorImages = ([^;]+);/si;
-    my $code = decode_json($json);
-    my @order = grep {$_} $code->{initial}[0]{thumb}, $code->{initial}[0]{landing}, @{$code->{initial}[0]{main}}, $code->{initial}[0]{large};
-    $data->{thumb_link} = $order[0]     if(@order);
-    $data->{image_link} = $order[-1]    if(@order);
+    if($json) {
+        my $code = decode_json($json);
+        my @order = grep {$_} $code->{initial}[0]{thumb}, $code->{initial}[0]{landing}, @{$code->{initial}[0]{main}}, $code->{initial}[0]{large};
+        $data->{thumb_link} = $order[0]     if(@order);
+        $data->{image_link} = $order[-1]    if(@order);
 
 #use Data::Dumper;
 #print STDERR "\n# code=[".Dumper($code)."]\n";
+    } else {
+        my ($code) = $html =~ /'imageGalleryData'\s*:\s*([^;]+);/si;
+        if($code) {
+            ($data->{thumb_link}) = $code =~ /"thumbUrl":\s*"([^+]+)"/;
+            ($data->{image_link}) = $code =~ /"mainUrl":\s*"([^+]+)"/;
+        }
+#use Data::Dumper;
+#print STDERR "\n# code=[".Dumper($code)."]\n";
+    }
+
 
 #    {\"initial\":[{\"large\":\"http://ecx.images-amazon.com/images/I/31cLTIXHKgL.jpg\",\"landing\":[\"http://ecx.images-amazon.com/images/I/31cLTIXHKgL._SY300_.jpg\"],\"thumb\":\"http://ecx.images-amazon.com/images/I/31cLTIXHKgL._SS40_.jpg\",\"main\":[\"http://ecx.images-amazon.com/images/I/31cLTIXHKgL._SX342_.jpg\",\"http://ecx.images-amazon.com/images/I/31cLTIXHKgL._SX385_.jpg\"]}]};
 
-    $data->{content} =~ s/Amazon\.co\.uk.*?://i;
-    $data->{content} =~ s/: Books.*//i;
-	($data->{title},$data->{author}) = ($data->{content} =~ /\s*(.*?)(?:\s+by|,|:)\s+([^:]+)\s*$/);
+    if($data->{content}) {
+        $data->{content} =~ s/Amazon\.co\.uk.*?://i;
+        $data->{content} =~ s/: Books.*//i;
+        ($data->{title},$data->{author}) = split(/\s+by\s+/,$data->{content});
+        $data->{title}  =~ s/^Buy\s+//  if($data->{title});
+        $data->{author} =~ s/\s*\(.*//  if($data->{author});
+    }
 
     ($data->{publisher},$data->{pubdate}) = ($data->{published} =~ /\s*(.*?)(?:;.*?)?\s+\((.*?)\)/) if($data->{published});
     $data->{isbn10}  =~ s/[^\dX]+//g    if($data->{isbn10});
     $data->{isbn13}  =~ s/\D+//g        if($data->{isbn13});
 	$data->{pubdate} =~ s/^.*?\(//      if($data->{pubdate});
 
-
 	return $self->handler("Could not extract data from Amazon UK result page.")
 		unless(defined $data->{isbn13});
 
     # trim top and tail
 	foreach (keys %$data) { next unless(defined $data->{$_});$data->{$_} =~ s/^\s+//;$data->{$_} =~ s/\s+$//; }
 
+#use Data::Dumper;
+#print STDERR "\n# data=[".Dumper($data)."]\n";
+
 	my $bk = {
 		'ean13'		    => $data->{isbn13},
 		'isbn13'		=> $data->{isbn13},
@@ -195,7 +230,7 @@ sub search {
 	return $self->book;
 }
 
-q{currently reading: Nation by Terry Pratchett};
+q{currently reading: 'Torn Apart: The Life of Ian Curtis' by Mick Middles and Lindsay Reade};
 
 __END__
 
@@ -231,7 +266,7 @@ be forthcoming, please feel free to (politely) remind me.
 
 =head1 COPYRIGHT & LICENSE
 
-  Copyright (C) 2004-2013 Barbie for Miss Barbell Productions
+  Copyright (C) 2004-2014 Barbie for Miss Barbell Productions
 
   This distribution is free software; you can redistribute it and/or
   modify it under the Artistic Licence v2.
@@ -4,7 +4,7 @@ use strict;
 use warnings;
 
 use vars qw($VERSION);
-$VERSION = '0.32';
+$VERSION = '0.41';
 
 #--------------------------------------------------------------------------
 
@@ -55,7 +55,7 @@ my $OZ2G  = 0.035274;       # number of ounces (oz) in a gram
 
 =item C<search()>
 
-Creates a query string, then passes the appropriate form fields to the 
+Creates a query string, then passes the appropriate form fields to the
 Amazon (US) server.
 
 The returned page should be the correct catalog page for that ISBN. If not the
@@ -63,7 +63,7 @@ function returns zero and allows the next driver in the chain to have a go. If
 a valid page is returned, the following fields are returned via the book hash:
 
   isbn          (now returns isbn13)
-  isbn10        
+  isbn10
   isbn13
   ean13         (industry name)
   author
@@ -92,10 +92,16 @@ sub search {
     $self->found(0);
     $self->book(undef);
 
+    # validate and convert into EAN13 format
+    my $ean = $self->convert_to_ean13($isbn);
+    return $self->handler("Invalid ISBN specified [$isbn]")
+        if(!$ean || (length $isbn == 13 && $isbn ne $ean)
+                 || (length $isbn == 10 && $isbn ne $self->convert_to_isbn10($ean)));
+
     my $mech = WWW::Mechanize->new();
     $mech->agent_alias( 'Linux Mozilla' );
 
-    my $search = sprintf $AMA_SEARCH, $isbn;
+    my $search = sprintf $AMA_SEARCH, $ean;
 
     eval { $mech->get( $search ) };
     return $self->handler("Amazon US website appears to be unavailable.")
@@ -110,22 +116,21 @@ sub search {
     return $self->handler("Amazon US website appears to be unavailable.")
         if($@ || !$mech->success() || !$mech->content());
 
+    return $self->_parse($mech);
+}
+
+sub _parse {
+    my $self = shift;
+    my $mech = shift;
+
     # The Book page
     my $html = $mech->content;
     my $data = {};
 
 #print STDERR "\n# html=[$html]\n";
 
-    $data->{title} = $1                                                     
-        if    ( $html =~ m{<h2   \s+ class="quorus-product-name" \s* > \s*     (.+?) (?= </h2>)    }six && $1 )                                               
-           || ( $html =~ m{<span \s+    id="btAsinTitle"         \s* > \s*     (.+?) (?= </?span>) }six && $1 )                                               
-           || ( $html =~ m{<td   \s+    id="prodImageCell" .+?                 alt="([^"]+)"}six && $1 )
-    ;    
-    
-    # Note: as the page changes, the older matches are now retained in the
-    # event that these are ever reused.
-
     my @patterns = (
+        qr/<meta name="description" content="(.*?) \[(.*?)\] on Amazon.com/si,
         qr/<meta name="description" content="(.*?): (.*?): (\d+): Amazon.com: Books/si,
         qr/<meta name="description" content="(?:Amazon.com:)?\s*(.*?).\d+.:\s+([^:]+): Books/si,
         qr/<meta name="description" content="(?:Amazon.com: Books: )?\s*(.*?)(?:\s+by|,)\s+(.*)/si,
@@ -136,6 +141,7 @@ sub search {
         my ($title,$author) = $html =~ $pattern;
         $data->{title}  ||= $title;
         $data->{author} ||= $author;
+#print STDERR "\n# title=[$data->{title}], author=[$data->{author}] pattern=[$pattern]\n";
 
         last    if($data->{title} && $data->{author});
     }
@@ -145,10 +151,27 @@ sub search {
     ($data->{isbn10})                   = $html =~ m!<li><b>ISBN-10:</b>\s*(.*?)</li>!si;
     ($data->{isbn13})                   = $html =~ m!<li><b>ISBN-13:</b>\s*(.*?)</li>!si;
     ($data->{content})                  = $html =~ m!<meta name="description" content="([^"]+)"!si;
-    ($data->{description})              = $html =~ m!<h2>Book Description</h2>.*?<div id="postBodyPS"[^>]+>\s*<div[^>]*>\s*<p>\s*(.*?)\s*</p>\s*</div!si;
-    ($data->{description})              = $html =~ m!<h2>Book Description</h2>.*?<div id="postBodyPS"[^>]+>\s*<div[^>]*>\s*(.*?)\s*</div!si                                                             unless($data->{description});  
-    ($data->{description})              = $html =~ m!<h3 class="productDescriptionSource">(?:Product Description|From the Back Cover)</h3>\s*<div class="productDescriptionWrapper">\s*<p>([^<]+)!si    unless($data->{description});  
-    ($data->{description})              = $html =~ m!<h3 class="productDescriptionSource">(?:Product Description|From the Back Cover)</h3>\s*<div class="productDescriptionWrapper">\s*(.*?)<div!si     unless($data->{description});  
+
+    @patterns = (
+        qr!<h2>Book Description</h2>.*?<div id="postBodyPS"[^>]+>\s*<div[^>]*>\s*<p>\s*(.*?)\s*</p>\s*</div!si,
+        qr!<h2>Book Description</h2>.*?<div id="postBodyPS"[^>]+>\s*<div[^>]*>\s*(.*?)\s*</div!si,
+        qr!<h3 class="productDescriptionSource">(?:Product Description|From the Back Cover)</h3>\s*<div class="productDescriptionWrapper">\s*<p>([^<]+)!si,
+        qr!<h3 class="productDescriptionSource">(?:Product Description|From the Back Cover)</h3>\s*<div class="productDescriptionWrapper">\s*(.*?)<div!si,
+        qr!<div id="bookDescription_feature_div"[^>]+>\s*<script[^>]*>.*?</script>\s*<noscript>(.*?)</noscript>!si
+    );
+
+    for my $pattern (@patterns) {
+        my ($desc) = $html =~ $pattern;
+        $desc =~ s/\s+$//s   if($desc);
+        $data->{description}  ||= $desc;
+
+        last    if($data->{description});
+    }
+
+    for my $key (qw(description)) {
+        next unless($data->{$key});
+        $data->{$key} =~ s/<[^>]*>//gs;
+    }
 
     # amazon use both ounces and pounds
     my $weight;
@@ -159,20 +182,27 @@ sub search {
     # amazon change this regularly
     my @size                            = $html =~ m!<li><b>\s*Product Dimensions:\s*</b>\s*([\d.]+) x ([\d.]+) x ([\d.]+) (cm)\s*</li>!si;
     @size                               = $html =~ m!<li><b>\s*Product Dimensions:\s*</b>\s*([\d.]+) x ([\d.]+) x ([\d.]+) (inches)\s*</li>!si unless(@size);
-    my $type = pop @size;
-    ($data->{depth},$data->{width},$data->{height}) = sort @size;    
-    if($type eq 'cm') {
-        $data->{$_}  = int($data->{$_} * 10)  for(qw( height width depth ));
-    } elsif($type eq 'inches') {
-        $data->{$_}  = int($data->{$_} / $IN2MM)  for(qw( height width depth ));
+    if(@size) {
+        my $type = pop @size;
+        ($data->{depth},$data->{width},$data->{height}) = sort @size;
+        if($type eq 'cm') {
+            $data->{$_}  = int($data->{$_} * 10)  for(qw( height width depth ));
+        } elsif($type eq 'inches') {
+            $data->{$_}  = int($data->{$_} / $IN2MM)  for(qw( height width depth ));
+        }
     }
 
     # The images
     my ($json) = $html =~ /var colorImages = ([^;]+);/si;
-    my $code = decode_json($json);
-    my @order = grep {$_} $code->{initial}[0]{thumb}, $code->{initial}[0]{landing}, @{$code->{initial}[0]{main}}, $code->{initial}[0]{large};
-    $data->{thumb_link} = $order[0]     if(@order);
-    $data->{image_link} = $order[-1]    if(@order);
+    if($json) {
+        my $code = decode_json($json);
+        my @order = grep {$_} $code->{initial}[0]{thumb}, $code->{initial}[0]{landing}, @{$code->{initial}[0]{main}}, $code->{initial}[0]{large};
+        $data->{thumb_link} = $order[0]     if(@order);
+        $data->{image_link} = $order[-1]    if(@order);
+    } else {
+        ($data->{thumb_link}) = $html =~ m!imageGalleryData.*?thumbUrl":"([^"]+)"!;
+        ($data->{image_link}) = $html =~ m!imageGalleryData.*?mainUrl":"([^"]+)"!;
+    }
 
     ($data->{publisher},$data->{pubdate}) = ($data->{published} =~ /\s*(.*?)(?:;.*?)?\s+\((.*?)\)/) if($data->{published});
     $data->{isbn10} =~ s/[^\dX]+//g if($data->{isbn10});
@@ -212,7 +242,7 @@ sub search {
     return $self->book;
 }
 
-q{currently reading: Red Rabbit by Tom Clancy};
+q{currently reading: 'Soul Music' by Terry Pratchett};
 
 __END__
 
@@ -248,7 +278,7 @@ be forthcoming, please feel free to (politely) remind me.
 
 =head1 COPYRIGHT & LICENSE
 
-  Copyright (C) 2004-2013 Barbie for Miss Barbell Productions
+  Copyright (C) 2004-2014 Barbie for Miss Barbell Productions
 
   This distribution is free software; you can redistribute it and/or
   modify it under the Artistic Licence v2.
@@ -0,0 +1,63 @@
+package WWW::Scraper::ISBN::Amazon_Driver;
+
+use strict;
+use warnings;
+
+use vars qw($VERSION);
+$VERSION = '0.41';
+
+#--------------------------------------------------------------------------
+
+=head1 NAME
+
+WWW::Scraper::ISBN::Amazon_Driver - A collection of search drivers for Amazon.
+
+=head1 SYNOPSIS
+
+See parent class documentation (L<WWW::Scraper::ISBN::Driver>)
+
+=head1 DESCRIPTION
+
+Searches for book information from the UK & US Amazon online catalogs.
+
+For specific usability of the drivers, please see the documentation for the
+respective driver you require.
+
+=head1 REQUIRES
+
+Requires the following modules be installed:
+
+L<WWW::Scraper::ISBN::Driver>,
+L<WWW::Mechanize>,
+
+=head1 SEE ALSO
+
+L<WWW::Scraper::ISBN>,
+L<WWW::Scraper::ISBN::Record>,
+L<WWW::Scraper::ISBN::Driver>
+
+=head1 BUGS, PATCHES & FIXES
+
+There are no known bugs at the time of this release. However, if you spot a
+bug or are experiencing difficulties that are not explained within the POD
+documentation, please send an email to barbie@cpan.org or submit a bug to the
+RT system (http://rt.cpan.org/Public/Dist/Display.html?Name=WWW-Scraper-ISBN-Amazon_Driver).
+However, it would help greatly if you are able to pinpoint problems or even
+supply a patch.
+
+Fixes are dependent upon their severity and my availability. Should a fix not
+be forthcoming, please feel free to (politely) remind me.
+
+=head1 AUTHOR
+
+  Barbie, <barbie@cpan.org>
+  for Miss Barbell Productions <http://www.missbarbell.co.uk>.
+
+=head1 COPYRIGHT & LICENSE
+
+  Copyright (C) 2004-2014 Barbie for Miss Barbell Productions
+
+  This distribution is free software; you can redistribute it and/or
+  modify it under the Artistic Licence v2.
+
+=cut
@@ -3,9 +3,10 @@ use strict;
 
 #########################
 
-use Test::More tests => 2;
+use Test::More tests => 3;
 
 BEGIN {
+	use_ok "WWW::Scraper::ISBN::Amazon_Driver";
 	use_ok "WWW::Scraper::ISBN::AmazonUS_Driver";
 	use_ok "WWW::Scraper::ISBN::AmazonUK_Driver";
 }
@@ -45,7 +45,7 @@ my %tests = (
         [ 'like',   'width',        qr/^\d+/                        ],
         [ 'like',   'height',       qr/^\d+/                        ],
         [ 'like',   'depth',        qr/^\d+/                        ],
-        [ 'is',     'weight',       1043                            ],
+        [ 'like',   'weight',       qr/10\d+/                       ],
         [ 'like',   'image_link',   qr!^http://ecx.images-amazon.co!],
         [ 'like',   'thumb_link',   qr!^http://ecx.images-amazon.co!],
         [ 'like',   'description',  qr|Perl Developer's Dictionary is a complete|                            ],
@@ -87,13 +87,11 @@ SKIP: {
             my $fail = 0;
             my $book = $record->book;
             for my $test (@{ $tests{$isbn} }) {
-                if($test->[0] eq 'ok')          { ok(       $book->{$test->[1]},             ".. '$test->[1]' found [$isbn]"); } 
-                elsif($test->[0] eq 'is')       { is(       $book->{$test->[1]}, $test->[2], ".. '$test->[1]' found [$isbn]"); } 
-                elsif($test->[0] eq 'isnt')     { isnt(     $book->{$test->[1]}, $test->[2], ".. '$test->[1]' found [$isbn]"); } 
-                elsif($test->[0] eq 'like')     { like(     $book->{$test->[1]}, $test->[2], ".. '$test->[1]' found [$isbn]"); } 
-                elsif($test->[0] eq 'unlike')   { unlike(   $book->{$test->[1]}, $test->[2], ".. '$test->[1]' found [$isbn]"); }
-
-                $fail = 1   unless(defined $book->{$test->[1]} || ($test->[0] ne 'ok' && !defined $test->[2]));
+                if($test->[0] eq 'ok')          { $fail += ! ok(       $book->{$test->[1]},             ".. '$test->[1]' found [$isbn]"); } 
+                elsif($test->[0] eq 'is')       { $fail += ! is(       $book->{$test->[1]}, $test->[2], ".. '$test->[1]' found [$isbn]"); } 
+                elsif($test->[0] eq 'isnt')     { $fail += ! isnt(     $book->{$test->[1]}, $test->[2], ".. '$test->[1]' found [$isbn]"); } 
+                elsif($test->[0] eq 'like')     { $fail += ! like(     $book->{$test->[1]}, $test->[2], ".. '$test->[1]' found [$isbn]"); } 
+                elsif($test->[0] eq 'unlike')   { $fail += ! unlike(   $book->{$test->[1]}, $test->[2], ".. '$test->[1]' found [$isbn]"); }
             }
 
             diag("book=[".Dumper($book)."]")    if($fail);
@@ -107,7 +105,8 @@ SKIP: {
 sub pingtest {
     my $domain = shift or return 0;
     my $cmd =   $^O =~ /solaris/i                           ? "ping -s $domain 56 1" :
-                $^O =~ /dos|os2|mswin32|netware|cygwin/i    ? "ping -n 1 $domain "
+                $^O =~ /cygwin/i                            ? "ping $domain 56 1" : # ping [ -dfqrv ] host [ packetsize [ count [ preload ]]]
+                $^O =~ /dos|os2|mswin32|netware/i           ? "ping -n 1 $domain "
                                                             : "ping -c 1 $domain >/dev/null 2>&1";
 
     eval { system($cmd) }; 
@@ -95,13 +95,11 @@ SKIP: {
             my $fail = 0;
             my $book = $record->book;
             for my $test (@{ $tests{$isbn} }) {
-                if($test->[0] eq 'ok')          { ok(       $book->{$test->[1]},             ".. '$test->[1]' found [$isbn]"); } 
-                elsif($test->[0] eq 'is')       { is(       $book->{$test->[1]}, $test->[2], ".. '$test->[1]' found [$isbn]"); } 
-                elsif($test->[0] eq 'isnt')     { isnt(     $book->{$test->[1]}, $test->[2], ".. '$test->[1]' found [$isbn]"); } 
-                elsif($test->[0] eq 'like')     { like(     $book->{$test->[1]}, $test->[2], ".. '$test->[1]' found [$isbn]"); } 
-                elsif($test->[0] eq 'unlike')   { unlike(   $book->{$test->[1]}, $test->[2], ".. '$test->[1]' found [$isbn]"); }
-
-                $fail = 1   unless(defined $book->{$test->[1]} || ($test->[0] ne 'ok' && !defined $test->[2]));
+                if($test->[0] eq 'ok')          { $fail += ! ok(       $book->{$test->[1]},             ".. '$test->[1]' found [$isbn]"); } 
+                elsif($test->[0] eq 'is')       { $fail += ! is(       $book->{$test->[1]}, $test->[2], ".. '$test->[1]' found [$isbn]"); } 
+                elsif($test->[0] eq 'isnt')     { $fail += ! isnt(     $book->{$test->[1]}, $test->[2], ".. '$test->[1]' found [$isbn]"); } 
+                elsif($test->[0] eq 'like')     { $fail += ! like(     $book->{$test->[1]}, $test->[2], ".. '$test->[1]' found [$isbn]"); } 
+                elsif($test->[0] eq 'unlike')   { $fail += ! unlike(   $book->{$test->[1]}, $test->[2], ".. '$test->[1]' found [$isbn]"); }
             }
 
             diag("book=[".Dumper($book)."]")    if($fail);
@@ -115,7 +113,8 @@ SKIP: {
 sub pingtest {
     my $domain = shift or return 0;
     my $cmd =   $^O =~ /solaris/i                           ? "ping -s $domain 56 1" :
-                $^O =~ /dos|os2|mswin32|netware|cygwin/i    ? "ping -n 1 $domain "
+                $^O =~ /cygwin/i                            ? "ping $domain 56 1" : # ping [ -dfqrv ] host [ packetsize [ count [ preload ]]]
+                $^O =~ /dos|os2|mswin32|netware/i           ? "ping -n 1 $domain "
                                                             : "ping -c 1 $domain >/dev/null 2>&1";
 
     eval { system($cmd) }; 
@@ -0,0 +1,70 @@
+#!/usr/bin/perl -w
+use strict;
+
+use Data::Dumper;
+use Test::More tests => 20;
+use WWW::Scraper::ISBN::AmazonUS_Driver;
+
+use lib qw(t/lib);
+use Fake::Mechanize;
+
+###########################################################
+
+my $DRIVER          = 'AmazonUS';
+
+my %tests = (
+    'empty-fields.html' => [
+        [ 'is',     'isbn',         undef                           ],
+    ],
+    'all-fields-us.html' => [
+        [ 'is',     'isbn',         '9780672320675'                 ],
+        [ 'like',   'isbn10',       qr!067232067!                   ],  # Amazon have a broken ISBN-10 field!
+        [ 'is',     'isbn13',       '9780672320675'                 ],
+        [ 'is',     'ean13',        '9780672320675'                 ],
+        [ 'is',     'author',       'Clinton Pierce'                ],
+        [ 'like',   'title',        qr!Perl Developer.*?Dictionary! ],
+        [ 'like',   'publisher',    qr/^Sams/                       ],  # publisher name changes!
+        [ 'like',   'pubdate',      qr/2001$/                       ],  # this dates fluctuates throughout Jul 2001!
+        [ 'is',     'binding',      'Paperback'                     ],
+        [ 'is',     'pages',        640                             ],
+        [ 'like',   'width',        qr/^\d+/                        ],
+        [ 'like',   'height',       qr/^\d+/                        ],
+        [ 'like',   'depth',        qr/^\d+/                        ],
+        [ 'is',     'weight',       453                             ],
+        [ 'like',   'image_link',   qr!^http://ecx.images-amazon.co!],
+        [ 'like',   'thumb_link',   qr!^http://ecx.images-amazon.co!],
+        [ 'like',   'description',  qr|Perl Developer's Dictionary is a complete|                            ],
+        [ 'like',   'book_link',    qr!all-fields-us!               ]
+    ]
+);
+
+###########################################################
+
+my $tests = 0;
+for my $isbn (keys %tests) { $tests += scalar( @{ $tests{$isbn} } ) + 2}
+
+###########################################################
+
+my $scraper = WWW::Scraper::ISBN::AmazonUS_Driver->new();
+isa_ok($scraper,'WWW::Scraper::ISBN::AmazonUS_Driver');
+
+{
+    for my $file (keys %tests) {
+        my $mech = Fake::Mechanize->new({ file => $file });
+
+        my $book = $scraper->_parse($mech);
+
+        if($file eq 'empty-fields.html') {
+            is($book,0,'.. no book data returned');
+
+        } else {
+            for my $test (@{ $tests{$file} }) {
+                if($test->[0] eq 'ok')          { ok(       $book->{$test->[1]},             ".. '$test->[1]' found [$file]"); } 
+                elsif($test->[0] eq 'is')       { is(       $book->{$test->[1]}, $test->[2], ".. '$test->[1]' found [$file]"); } 
+                elsif($test->[0] eq 'isnt')     { isnt(     $book->{$test->[1]}, $test->[2], ".. '$test->[1]' found [$file]"); } 
+                elsif($test->[0] eq 'like')     { like(     $book->{$test->[1]}, $test->[2], ".. '$test->[1]' found [$file]"); } 
+                elsif($test->[0] eq 'unlike')   { unlike(   $book->{$test->[1]}, $test->[2], ".. '$test->[1]' found [$file]"); }
+            }
+        }
+    }
+}
@@ -0,0 +1,70 @@
+#!/usr/bin/perl -w
+use strict;
+
+use Data::Dumper;
+use Test::More tests => 20;
+use WWW::Scraper::ISBN::AmazonUK_Driver;
+
+use lib qw(t/lib);
+use Fake::Mechanize;
+
+###########################################################
+
+my $DRIVER          = 'AmazonUK';
+
+my %tests = (
+    'empty-fields.html' => [
+        [ 'is',     'isbn',         undef                           ],
+    ],
+    'all-fields-uk.html' => [
+        [ 'is',     'isbn',         '9780672320675'                 ],
+        [ 'like',   'isbn10',       qr!067232067!                   ],  # Amazon have a broken ISBN-10 field!
+        [ 'is',     'isbn13',       '9780672320675'                 ],
+        [ 'is',     'ean13',        '9780672320675'                 ],
+        [ 'is',     'author',       'Clinton Pierce'                ],
+        [ 'like',   'title',        qr!Perl Developer.*?Dictionary! ],
+        [ 'like',   'publisher',    qr/^Sams/                       ],  # publisher name changes!
+        [ 'like',   'pubdate',      qr/2001$/                       ],  # this dates fluctuates throughout Jul 2001!
+        [ 'is',     'binding',      'Paperback'                     ],
+        [ 'is',     'pages',        640                             ],
+        [ 'like',   'width',        qr/^\d+/                        ],
+        [ 'like',   'height',       qr/^\d+/                        ],
+        [ 'like',   'depth',        qr/^\d+/                        ],
+        [ 'is',     'weight',       453                             ],
+        [ 'like',   'image_link',   qr!^http://ecx.images-amazon.co!],
+        [ 'like',   'thumb_link',   qr!^http://ecx.images-amazon.co!],
+        [ 'like',   'description',  qr|Perl Developer's Dictionary is a complete|                            ],
+        [ 'like',   'book_link',    qr!all-fields-uk!               ]
+    ]
+);
+
+###########################################################
+
+my $tests = 0;
+for my $isbn (keys %tests) { $tests += scalar( @{ $tests{$isbn} } ) + 2 }
+
+###########################################################
+
+my $scraper = WWW::Scraper::ISBN::AmazonUK_Driver->new();
+isa_ok($scraper,'WWW::Scraper::ISBN::AmazonUK_Driver');
+
+{
+    for my $file (keys %tests) {
+        my $mech = Fake::Mechanize->new({ file => $file });
+
+        my $book = $scraper->_parse($mech);
+
+        if($file eq 'empty-fields.html') {
+            is($book,0,'.. no book data returned');
+
+        } else {
+            for my $test (@{ $tests{$file} }) {
+                if($test->[0] eq 'ok')          { ok(       $book->{$test->[1]},             ".. '$test->[1]' found [$file]"); } 
+                elsif($test->[0] eq 'is')       { is(       $book->{$test->[1]}, $test->[2], ".. '$test->[1]' found [$file]"); } 
+                elsif($test->[0] eq 'isnt')     { isnt(     $book->{$test->[1]}, $test->[2], ".. '$test->[1]' found [$file]"); } 
+                elsif($test->[0] eq 'like')     { like(     $book->{$test->[1]}, $test->[2], ".. '$test->[1]' found [$file]"); } 
+                elsif($test->[0] eq 'unlike')   { unlike(   $book->{$test->[1]}, $test->[2], ".. '$test->[1]' found [$file]"); }
+            }
+        }
+    }
+}
@@ -24,5 +24,13 @@ if($meta->{provides}) {
     for my $mod (keys %{$meta->{provides}}) {
         is($meta->{provides}{$mod}{version},$version,
             "META.yml entry [$mod] version matches");
+
+        eval "require $mod";
+        my $VERSION = '$' . $mod . '::VERSION';
+        my $v = eval "$VERSION";
+        is($meta->{provides}{$mod}{version},$v,
+            "META.json entry [$mod] version matches module version");
+
+        isnt($meta->{provides}{$mod}{version},0);
     }
 }
@@ -23,6 +23,14 @@ is($meta->{version},$version,
 if($meta->{provides}) {
     for my $mod (keys %{$meta->{provides}}) {
         is($meta->{provides}{$mod}{version},$version,
-            "META.json entry [$mod] version matches");
+            "META.json entry [$mod] version matches distribution version");
+
+        eval "require $mod";
+        my $VERSION = '$' . $mod . '::VERSION';
+        my $v = eval "$VERSION";
+        is($meta->{provides}{$mod}{version},$v,
+            "META.json entry [$mod] version matches module version");
+
+        isnt($meta->{provides}{$mod}{version},0);
     }
 }
@@ -0,0 +1,109 @@
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
+<link rel="canonical" href="http://www.amazon.co.uk/Perl-Developers-Dictionary-Library/dp/0672320673" />
+<link rel="alternate" media="handheld" href="http://www.amazon.co.uk/gp/aw/d/0672320673" />
+<meta name="description" content="Buy Perl Developer&#39;s Dictionary (Developer&#39;s Library) by Clinton Pierce (ISBN: 0752063320679) from Amazon&#39;s Book Store. Free UK delivery on eligible orders." />
+<meta name="title" content="Perl Developer&#39;s Dictionary (Developer&#39;s Library): Amazon.co.uk: Clinton Pierce: Books" />
+<meta name="keywords" content="Clinton Pierce,Perl Developer&#39;s Dictionary (Developer&#39;s Library),Sams,0672320673,Web programming,Programming &amp; scripting languages: general,Programming languages,Dictionaries,Perl (Computer program language),Computer Books: General,Computer Programming Languages,Computers,Computers (Software),Computers - Languages / Programming,Computers / Programming Languages / Perl,Computing: Professional &amp; Programming,Programming Languages - General,Programming Languages - Perl" />
+<title>Perl Developer&#39;s Dictionary (Developer&#39;s Library): Amazon.co.uk: Clinton Pierce: Books</title>
+</head>
+    <body id="dp" class="book en_GB"><div id="a-page">
+<script type="text/javascript">
+P.when('A').register("ImageBlockATF", function(A){
+	var audibleData = {};
+	if(false){
+		audibleData = {
+			'audioSampleSrc' : "",
+		    'flashPlayerUrl' : ""
+		}
+	}
+	var data = {
+	    'litbData' : {
+	    	'hasLitb' : false,
+	    	'litbReftag' : "sib_dp_pt"
+	    },
+	    'audibleData' : audibleData,
+	    'windowWidthThreshold' : 1150,
+	    'configWidths' : [200, 260],
+	    'holderRatio' : 0.75,
+	    'containerMargin' : 15,
+	    'flipLinkMinHeight' : 0,
+	    'frontImageWidth' : 260,
+	    'frontImageHeight' : 321,
+	    'frontImageAspectRatio' : 0.8099688473520249,
+	    'imageGalleryData' : [{"mainUrl":"http://ecx.images-amazon.com/images/I/31cLTIXHKgL.jpg","dimensions":[404,500],"thumbUrl":"http://ecx.images-amazon.com/images/I/31cLTIXHKgL._SX75_CR,0,0,75,75_.jpg"}],
+	    'centerColMargin' : 40
+	};
+	return data;
+});
+</script>
+    <div id="bookDescription_feature_div" class="feature" data-feature-name="bookDescription">
+<script id="bookDesc_override_CSS" type="text/undefined">
+body {
+    font-size: 14px;
+    line-height: 1.6em;
+}
+.aplus {
+	min-width: inherit;
+}
+</script>
+ <noscript>
+ 	<div> <P>Perl Developer's Dictionary is a complete, well-organized reference to the Perl language and environment, including core syntax as well as Perl modules. Designed specifically for the experienced developer who needs a reference readily available on his or her desk to refer to on a daily basis, the book is extensively cross-referenced and indexed for optimal usability. In addition to providing a complete syntax reference for all core Perl functions, the book also provides quick access to language syntax, constructs, and other language issues. Each major section of the book is prefaced with a short introduction to provide background material on the subject at hand, and then is followed by a series of "dictionary" entries that cover exactly one topic, carefully cross-referenced and indexed with the rest of the book. </P></div>
+ 	<em></em>
+ </noscript>
+<div id="ps-content" class="bucket">
+  <h2>Book Description</h2>
+<div class="buying"><span class="byLinePipe">Publication Date: </span><span style="font-weight: bold;">18 July 2001</span> <span class="byLinePipe"> | ISBN-10:</span><span style="font-weight: bold;"> 0672320673 </span> <span class="byLinePipe"> | ISBN-13:</span><span style="font-weight: bold;"> 978-0672320675</span> <span class="byLinePipe"> | Edition: </span><span style="font-weight: bold;">1</span>  </div>
+  <div class="content">
+    <div id="outer_postBodyPS" style="overflow:hidden; z-index: 1; height: 200px;">
+      <div id="postBodyPS" style="overflow: hidden;">
+         <div><P>Perl Developer's Dictionary is a complete, well-organized reference to the Perl language and environment, including core syntax as well as Perl modules. Designed specifically for the experienced developer who needs a reference readily available on his or her desk to refer to on a daily basis, the book is extensively cross-referenced and indexed for optimal usability. In addition to providing a complete syntax reference for all core Perl functions, the book also provides quick access to language syntax, constructs, and other language issues. Each major section of the book is prefaced with a short introduction to provide background material on the subject at hand, and then is followed by a series of "dictionary" entries that cover exactly one topic, carefully cross-referenced and indexed with the rest of the book. </P></div>
+      </div>
+    </div>
+<noscript>
+    <div id="postBodyPS"><P>Perl Developer's Dictionary is a complete, well-organized reference to the Perl language and environment, including core syntax as well as Perl modules. Designed specifically for the experienced developer who needs a reference readily available on his or her desk to refer to on a daily basis, the book is extensively cross-referenced and indexed for optimal usability. In addition to providing a complete syntax reference for all core Perl functions, the book also provides quick access to language syntax, constructs, and other language issues. Each major section of the book is prefaced with a short introduction to provide background material on the subject at hand, and then is followed by a series of "dictionary" entries that cover exactly one topic, carefully cross-referenced and indexed with the rest of the book. </P></div>
+</noscript>
+  </div>
+</div>
+    <div id="detail_bullets_id">
+<table cellpadding="0" cellspacing="0" border="0">
+  <tr>
+    <td class="bucket">
+      <h2>Product details</h2>
+      <div class="content">
+<ul>
+<li><b>Paperback:</b> 640 pages</li>
+<li><b>Shipping Weight:</b>16 ounces</li>
+<li><b>Publisher:</b> Sams; 1 edition (18 July 2001)</li>
+<li><b>Language:</b> English</li>
+<li><b>ISBN-10:</b> 0672320673</li>
+<li><b>ISBN-13:</b> 978-0672320675</li>
+    <li><b>
+    Product Dimensions:
+    </b>
+    3.6 x 18.5 x 22.7 cm
+    </li>
+</ul>
+</div>
+    </td>
+  </tr>
+</table>
+</div>
+<div class="bucket" id="productDescription">
+ <h2>Product Description</h2>
+<div class="content">
+       <h3 class="productDescriptionSource">From the Back Cover</h3>
+       <div class="productDescriptionWrapper">
+       <P>Perl Developer's Dictionary is a complete, well-organized reference to the Perl language and environment, including core syntax as well as Perl modules. Designed specifically for the experienced developer who needs a reference readily available on his or her desk to refer to on a daily basis, the book is extensively cross-referenced and indexed for optimal usability. In addition to providing a complete syntax reference for all core Perl functions, the book also provides quick access to language syntax, constructs, and other language issues. Each major section of the book is prefaced with a short introduction to provide background material on the subject at hand, and then is followed by a series of "dictionary" entries that cover exactly one topic, carefully cross-referenced and indexed with the rest of the book. </P>
+      <div class="emptyClear"> </div>
+      </div>
+       <h3 class="productDescriptionSource">About the Author</h3>
+       <div class="productDescriptionWrapper">
+       <P><B>Clinton Pierce</B> is a software engineer, freelance programmer, and instructor. He has programmed almost every kind of software imaginable: financial applications, games, embedded systems, device drivers, OS utilities, and all this under a dozen or so operating systems. He spends his free time preaching the gospels of Unix, Perl, and open-source software to anyone within earshot.</P><P>He's currently serving time as a Web architect for Decision Consultants in southeast Michigan. You can visit his Web site at http://geeksalad.org or write to him at clintp@geeksalad.org</P>
+      <div class="emptyClear"> </div>
+      </div>
+  </div>
+</div>
+</body>
+</html>
@@ -0,0 +1,68 @@
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
+<meta name="description" content="Perl Developer&#39;s Dictionary [Clinton Pierce] on Amazon.com. *FREE* shipping on qualifying offers. &lt;P&gt;Perl Developer&#39;s Dictionary is a complete, well-organized reference to the Perl language and environment" />
+<meta name="title" content="Perl Developer&#39;s Dictionary: Clinton Pierce: 0752063320679: Amazon.com: Books" />
+<meta name="keywords" content="9780672320675" />
+<title>Perl Developer&#39;s Dictionary: Clinton Pierce: 0752063320679: Amazon.com: Books</title>
+</head>
+ <body class="dp">
+<form method="post" id="handleBuy" name="handleBuy" action="http://www.amazon.com/gp/product/handle-buy-box/ref=dp_start-bbf_1_glance" style="margin: 0pt;" autocomplete="off">
+<script type="text/javascript">
+    var imageSrc = "http://ecx.images-amazon.com/images/I/31cLTIXHKgL._SY300_.jpg";
+    var colorImages = {"initial":[{"large":"http://ecx.images-amazon.com/images/I/31cLTIXHKgL.jpg","landing":["http://ecx.images-amazon.com/images/I/31cLTIXHKgL._SY300_.jpg"],"thumb":"http://ecx.images-amazon.com/images/I/31cLTIXHKgL._SS30_.jpg","main":["http://ecx.images-amazon.com/images/I/31cLTIXHKgL._SY300_.jpg","http://ecx.images-amazon.com/images/I/31cLTIXHKgL._SY300_.jpg"]}]};
+</script>
+<div id="ps-content" class="bucket">
+  <h2>Book Description</h2>
+<div class="buying"><span class="byLinePipe">Publication Date: </span><span style="font-weight: bold;">July 28, 2001</span> <span class="byLinePipe"> | ISBN-10:</span><span style="font-weight: bold;"> 0672320673 </span> <span class="byLinePipe"> | ISBN-13:</span><span style="font-weight: bold;"> 978-0672320675</span> <span class="byLinePipe"> | Edition: </span><span style="font-weight: bold;">1</span>  </div>
+  <div class="content">
+    <div id="outer_postBodyPS" style="overflow:hidden; z-index: 1; height: 200px;">
+      <div id="postBodyPS" style="overflow: hidden;">
+         <div><P>Perl Developer's Dictionary is a complete, well-organized reference to the Perl language and environment, including core syntax as well as Perl modules.     Designed specifically for the experienced developer who needs a reference readily available on his or her desk to refer to on a daily basis, the book is extensively cross-referenced and indexed for optimal usability.     In addition to providing a complete syntax reference for all core Perl functions, the book also provides quick access to language syntax, constructs, and other language issues. Each major section of the book is prefaced with a short introduction to provide background material on the subject at hand, and then is followed by a series of "dictionary" entries that cover exactly one topic, carefully cross-referenced and indexed with the rest of the book.         </P></div>
+      </div>
+    </div>
+<noscript>
+    <div id="postBodyPS"><P>Perl Developer's Dictionary is a complete, well-organized reference to the Perl language and environment, including core syntax as well as Perl modules.     Designed specifically for the experienced developer who needs a reference readily available on his or her desk to refer to on a daily basis, the book is extensively cross-referenced and indexed for optimal usability.     In addition to providing a complete syntax reference for all core Perl functions, the book also provides quick access to language syntax, constructs, and other language issues. Each major section of the book is prefaced with a short introduction to provide background material on the subject at hand, and then is followed by a series of "dictionary" entries that cover exactly one topic, carefully cross-referenced and indexed with the rest of the book.         </P></div>
+</noscript>
+  </div>
+</div>
+ <tbody>
+       <tr>
+            <td>
+                <div class="SponsoredLinkDescriptionDIV">
+                    <span class="SponsoredLinkDescriptionText">Perl Developer&#39;s Dictionary By Clinton Pierce</span>
+                </div>
+            </td>
+        </tr>
+</tbody>
+</table>
+</div>
+</div>
+</div>
+            </ul>
+        </div>
+  <div id="detail-bullets">
+<a name="productDetails" id="productDetails"></a>
+<hr noshade="noshade" size="1" class="bucketDivider" />
+<table cellpadding="0" cellspacing="0" border="0" id="productDetailsTable">
+  <tr>
+    <td class="bucket">
+<h2>Product Details</h2>
+  <div class="content">
+<ul>
+<li><b>Paperback:</b> 640 pages</li>
+<li><b>Shipping Weight:</b>16 ounces</li>
+<li><b>Publisher:</b> Sams Publishing; 1 edition (July 28, 2001)</li>
+<li><b>Language:</b> English</li>
+<li><b>ISBN-10:</b> 0672320673</li>
+<li><b>ISBN-13:</b> 978-0672320675</li>
+<li><b>Product Dimensions:</b> 9.1 x 7.4 x 1.4 inches</li>
+<li><b>Shipping Weight:</b> 2.3 pounds (<a href="http://www.amazon.com/gp/help/seller/shipping.html/ref=dp_pd_shipping?ie=UTF8&amp;asin=0672320673&amp;seller=ATVPDKIKX0DER">View shipping rates and policies</a>)</li>
+</ul>
+  </div>
+    </td>
+  </tr>
+</table>
+</div>
+</body>
+</html>
@@ -0,0 +1,8 @@
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
+<title>Title</title>
+</head>
+<body>
+</body>
+</html>
@@ -0,0 +1,41 @@
+package Fake::Mechanize;
+
+use strict;
+use warnings;
+
+use IO::File;
+
+# -----------------------------------------------------------------------------
+# Object methods
+
+sub new {
+	my $class = shift;
+    my $self  = shift;
+
+    return  unless($self->{file});
+
+	# create the object
+	bless $self, $class;
+
+    return $self;
+}
+
+sub content {
+    my $self = shift;
+
+    unless($self->{path}) {
+        $self->{path} = sprintf "t/data/%s", $self->{file};
+        my $fh = IO::File->new($self->{path},'r') or die "Failed to open file [$self->{path}]: $!\n";
+        while(<$fh>) { $self->{content} .= $_ }
+    }
+
+    return $self->{content};
+}
+
+sub uri {
+    my $self = shift;
+
+    return $self->{path};
+}
+
+1;