The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
Changes 015
MANIFEST 01
META.yml 22
Makefile.PL 094
lib/Geo/ReadGRIB/Place.pm 194194
lib/Geo/ReadGRIB/PlaceIterator.pm 360360
lib/Geo/ReadGRIB.pm 89154
t/11-Geo-ReadGRIB-times.t 069
t/3-Geo-ReadGRIB-Data-LaLo.t 317
9 files changed (This is a version diff) 648906
@@ -74,3 +74,18 @@ Revision history for Perl extension Geo::ReadGRIB.
         - Add and improve range testing methods in accord with DRY 
           principle and to remove range test from lalo2offset which 
           is called many times when using extractLaLo()
+
+1.3  Jan 2010
+
+        - Bug fix release for rt.cpan.org ticket #53494 where CMC gribs
+          require a different interpretation of PDS octets 19 and 20
+        - Added fix to cover changes made for fix
+
+1.4  March 2010
+
+        - extractLaLo() no longer saves extracted data to the object by
+          default. The new method backflip() turns this behavior back on.
+        - A test was added for backflip()
+        - Changes made to Makefile.PL to support the cc compiler on Solaris
+          and give a helpful message for those with a different compiler 
+          than Perl was built with.
@@ -13,6 +13,7 @@ t/7-Geo-ReadGRIB-Iter-CMS.t
 t/8-Geo-ReadGRIB-Dateline-CMS.t
 t/9-Geo-ReadGRIB-offset-CMS.t
 t/10-Geo-ReadGRIB-LaLoRange.t
+t/11-Geo-ReadGRIB-times.t
 t/pod.t
 t/pod-coverage.t
 lib/Geo/ReadGRIB.pm
@@ -1,6 +1,6 @@
 --- #YAML:1.0
 name:               Geo-ReadGRIB
-version:            1.21
+version:            1.4
 abstract:           Perl extension that gives read access to GRIB weather data files
 author:
     - Frank Cox <frank.l.cox@gmail.com>
@@ -15,7 +15,7 @@ no_index:
     directory:
         - t
         - inc
-generated_by:       ExtUtils::MakeMaker version 6.55_02
+generated_by:       ExtUtils::MakeMaker version 6.56
 meta-spec:
     url:      http://module-build.sourceforge.net/META-spec-v1.4.html
     version:  1.4
@@ -1,5 +1,7 @@
+use strict;
 use 5.6.1;
 use ExtUtils::MakeMaker;
+use Config;
 # See lib/ExtUtils/MakeMaker.pm for details of how to influence
 # the contents of the Makefile that is written.
 
@@ -12,6 +14,84 @@ if ($] >= 5.00503) {
   );
 }
 
+## check to see if they called for an alternate compiler on the command line
+my $ALT_CC = 0;
+foreach ( @ARGV ) {
+    if ( m/cc=(\w*)/ ) {
+        $ALT_CC = $1;
+        last;
+    }
+}
+
+# Used to check for a 'C' compiler
+# code stolen from 'threads' module, thank you J Hedden!
+sub check_cc {
+    require File::Spec;
+
+    my $cmd = $_[0];
+    if (-x $cmd or MM->maybe_command($cmd)) {
+        return (1);       # CC command found
+    }
+    for my $dir (File::Spec->path(), '.') {
+        my $abs = File::Spec->catfile($dir, $cmd);
+        if (-x $abs or MM->maybe_command($abs)) {
+            return (1);   # CC command found
+        }
+    }
+    return;
+}
+
+sub have_cc {
+    eval { require Config_m; };     # ExtUtils::FakeConfig (+ ActivePerl)
+    if ($@) {
+        eval { require Config; };   # Everyone else
+    }
+    my @chunks = split(/ /, $Config::Config{cc});
+
+    # $Config{cc} may contain args; try to find out the program part
+    while (@chunks) {
+        if (check_cc("@chunks")) {
+            return (1);   # CC command found
+        }
+        pop(@chunks);
+    }
+    return;
+}
+
+if (  not have_cc and not $ALT_CC ) {
+    print STDERR <<EOF;
+    #--------------------------- shucks! ---------------------------------
+    #
+    # A C compiler is required by this installer. Your Perl was built with
+    # the '$Config::Config{cc}' compiler but I can't find it in your path.
+    #
+    # Sorry about that.
+    #
+    # If you use another compiler you can try running Makfile.PL again 
+    # like this:
+    #
+    #     perl Makefile.PL cc=My_Compiler
+    #
+    #     where "My_Compiler" is the name of your compiler.
+    #
+    # If this dosn't work, you can post a bug by sending email to: 
+    #
+    #     bug-Geo-ReadGRIB\@rt.cpan.org
+    #
+    # Please mention the compiler you use and the options required to 
+    # compile a simple, single file, C program if you know them. It would 
+    # also be helpful if you are able to help with testing. Particularly 
+    # if your compiler isn't free and/or the maintainers don't have easy
+    # access to your OS.
+    #
+    #---------------------------------------------------------------------
+
+EOF
+
+    print "//\$Config{cc}: $Config{cc} : ALT_CC: $ALT_CC//\n";
+    die "OS unsupported";
+}
+
 
 WriteMakefile(
     NAME         => 'Geo::ReadGRIB',
@@ -24,6 +104,18 @@ WriteMakefile(
 );
 
 sub MY::dynamic {
+    if ( $Config{cc} eq 'cc' or  $Config{cc} =~ m|/cc$| or $ALT_CC eq 'cc' ) {
+    return
+'
+dynamic :: $(INST_LIB)/Geo/wgrib.exe
+	@$(NOOP)
+
+$(INST_LIB)/Geo/wgrib.exe: $(C_FILES)
+	$(CC) -o $(INST_LIB)/Geo/wgrib.exe wgrib.c -lm
+';
+    }
+    else {
+        return
 '
 dynamic :: $(INST_LIB)/Geo/wgrib.exe
 	@$(NOOP)
@@ -31,6 +123,8 @@ dynamic :: $(INST_LIB)/Geo/wgrib.exe
 $(INST_LIB)/Geo/wgrib.exe: $(C_FILES)
 	$(CC) -o $(INST_LIB)/Geo/wgrib.exe wgrib.c
 ';
+    }
+
 }
 
 sub MY::libscan {
@@ -1,194 +1,194 @@
-#
-#===============================================================================
-#
-#         FILE:  Place.pm
-#
-#  DESCRIPTION:  creates Geo::ReadGRIB::Place objects
-#
-#        FILES:  ---
-#         BUGS:  ---
-#        NOTES:  ---
-#       AUTHOR:  Frank Lyon Cox (Dr), <frank@pwizardry.com>
-#      COMPANY:  Practial Wizardry
-#      VERSION:  1.0
-#      CREATED:  2/3/2009 10:42:57 PM Pacific Standard Time
-#     REVISION:  ---
-#===============================================================================
-
-package Geo::ReadGRIB::Place;
-
-use strict;
-use warnings;
-
-our $VERSION = 1.0;
-
-#--------------------------------------------------------------------------
-#  new( )
-#--------------------------------------------------------------------------
-sub new {
-    my $class = shift;
-    my $self = {};
-    bless $self, $class;
-    return $self;
-}
-
-#--------------------------------------------------------------------------
-#  thisTime( )
-#--------------------------------------------------------------------------
-sub thisTime {
-    my $self = shift;
-    my $arg  = shift;
-    $self->{time} = $arg if defined $arg;
-    return $self->{time};
-}
-
-#--------------------------------------------------------------------------
-#  lat( )
-#--------------------------------------------------------------------------
-sub lat {
-    my $self = shift;
-    my $arg  = shift;
-    $self->{lat} = $arg if defined $arg;
-    return $self->{lat};
-}
-
-#--------------------------------------------------------------------------
-#  long( )
-#--------------------------------------------------------------------------
-sub long {
-    my $self = shift;
-    my $arg  = shift;
-    $self->{long} = $arg if defined $arg;
-    return $self->{long};
-}
-
-#--------------------------------------------------------------------------
-#  types( )
-#
-#  returns an array ref of type names
-#--------------------------------------------------------------------------
-sub types {
-    my $self = shift;
-    my $arg  = shift;
-    push @{$self->{types}}, $arg if defined $arg;
-    return $self->{types};
-}
-
-#--------------------------------------------------------------------------
-#  data( type_name )
-#
-#  takes a type_name and returns the associated data
-#--------------------------------------------------------------------------
-sub data {
-    my $self = shift;
-    my $type = shift;
-    my $data = shift;
-
-    $self->{data}->{$type} = $data if defined $data;
-
-    if ( not defined $self->{data}->{$type} ) {
-        warn "Place: Not a valid type: $type\n";
-    }
-
-    return $self->{data}->{$type};
-}
-
-
-=head1 NAME
-
-Geo::ReadGRIB::Place - Contains the value of a one or more data type at a given 
-time and geographic location.
-
-=head1 VERSION
-
-This documentation refers to Geo::ReadGRIB::Place version 1.0 as returned by 
-a call to Geo::ReadGRIB::PlaceIterator::Current()
-
-
-=head1 SYNOPSIS
-
-    use Geo::ReadGRIB;
-
-    $w = new Geo::ReadGRIB "grib-file";
-    $w->getFullCatalog;
-
-    print $w->show,"\n";
-  
-    $plit = $w->extractLaLo(data_type, lat1, long1, lat2, long2, time);
-    die $w->getError if $w->getError;
-
-    # $plit is a Geo::ReadGRIB::PlaceIterator
-
-    while ( $place = $plit->current() and $plit->next ) {
-
-        # $place is a Geo::ReadGRIB::Place object
-
-        $time       = $place->thisTime;
-        $latitude   = $place->lat;
-        $longitude  = $place->long;
-        $data_types = $place->types; # an array ref of type names
-
-        $data       = $place->data( data_type );
-
-        # process data...
-    }
-
-
-=head1 DESCRIPTION
-
-Objects of this class are returned by the current() method of a 
-PlaceIterator object which itself has been returned by the 
-extractLaLo() or extract() methods of a Geo::ReadGRIB object. A place 
-object has a unique latitude and longitude for one time and has data 
-for one or more data types. 
-
-=head1 METHODS
-
-Objects of this class are read only and all parameters may be
-accessed by the following methods.
-
-=over 4
-
-=item $object->new;
-
-=item $object->thisTime;
-
-=item $object->lat;
-
-=item $object->long;
-
-=item $object->types;
-
-=item $object->data(type);
-
-=back
-
-=head1 BUGS AND LIMITATIONS
-
-There are no known bugs in this module. Please report problems through
-
-http://rt.cpan.org
-
-or contact Frank Cox, <frank.l.cox@gmail.com> Patches are welcome.
-
-=head1 AUTHOR
-
-Frank Cox, E<lt>frank.l.cox@gmail.comE<gt>
-
-=head1 COPYRIGHT AND LICENSE
-
-Copyright (C) 2009 by Frank Cox
-
-This library is free software; you can redistribute it and/or modify
-it under the same terms as Perl itself, either Perl version 5.8.4 or,
-at your option, any later version of Perl 5 you may have available.
-
-
-
-=cut
-
-
-
-1;
-
-
+#
+#===============================================================================
+#
+#         FILE:  Place.pm
+#
+#  DESCRIPTION:  creates Geo::ReadGRIB::Place objects
+#
+#        FILES:  ---
+#         BUGS:  ---
+#        NOTES:  ---
+#       AUTHOR:  Frank Lyon Cox (Dr), <frank@pwizardry.com>
+#      COMPANY:  Practial Wizardry
+#      VERSION:  1.0
+#      CREATED:  2/3/2009 10:42:57 PM Pacific Standard Time
+#     REVISION:  ---
+#===============================================================================
+
+package Geo::ReadGRIB::Place;
+
+use strict;
+use warnings;
+
+our $VERSION = 1.0;
+
+#--------------------------------------------------------------------------
+#  new( )
+#--------------------------------------------------------------------------
+sub new {
+    my $class = shift;
+    my $self = {};
+    bless $self, $class;
+    return $self;
+}
+
+#--------------------------------------------------------------------------
+#  thisTime( )
+#--------------------------------------------------------------------------
+sub thisTime {
+    my $self = shift;
+    my $arg  = shift;
+    $self->{time} = $arg if defined $arg;
+    return $self->{time};
+}
+
+#--------------------------------------------------------------------------
+#  lat( )
+#--------------------------------------------------------------------------
+sub lat {
+    my $self = shift;
+    my $arg  = shift;
+    $self->{lat} = $arg if defined $arg;
+    return $self->{lat};
+}
+
+#--------------------------------------------------------------------------
+#  long( )
+#--------------------------------------------------------------------------
+sub long {
+    my $self = shift;
+    my $arg  = shift;
+    $self->{long} = $arg if defined $arg;
+    return $self->{long};
+}
+
+#--------------------------------------------------------------------------
+#  types( )
+#
+#  returns an array ref of type names
+#--------------------------------------------------------------------------
+sub types {
+    my $self = shift;
+    my $arg  = shift;
+    push @{$self->{types}}, $arg if defined $arg;
+    return $self->{types};
+}
+
+#--------------------------------------------------------------------------
+#  data( type_name )
+#
+#  takes a type_name and returns the associated data
+#--------------------------------------------------------------------------
+sub data {
+    my $self = shift;
+    my $type = shift;
+    my $data = shift;
+
+    $self->{data}->{$type} = $data if defined $data;
+
+    if ( not defined $self->{data}->{$type} ) {
+        warn "Place: Not a valid type: $type\n";
+    }
+
+    return $self->{data}->{$type};
+}
+
+
+=head1 NAME
+
+Geo::ReadGRIB::Place - Contains the value of a one or more data type at a given 
+time and geographic location.
+
+=head1 VERSION
+
+This documentation refers to Geo::ReadGRIB::Place version 1.0 as returned by 
+a call to Geo::ReadGRIB::PlaceIterator::Current()
+
+
+=head1 SYNOPSIS
+
+    use Geo::ReadGRIB;
+
+    $w = new Geo::ReadGRIB "grib-file";
+    $w->getFullCatalog;
+
+    print $w->show,"\n";
+  
+    $plit = $w->extractLaLo(data_type, lat1, long1, lat2, long2, time);
+    die $w->getError if $w->getError;
+
+    # $plit is a Geo::ReadGRIB::PlaceIterator
+
+    while ( $place = $plit->current() and $plit->next ) {
+
+        # $place is a Geo::ReadGRIB::Place object
+
+        $time       = $place->thisTime;
+        $latitude   = $place->lat;
+        $longitude  = $place->long;
+        $data_types = $place->types; # an array ref of type names
+
+        $data       = $place->data( data_type );
+
+        # process data...
+    }
+
+
+=head1 DESCRIPTION
+
+Objects of this class are returned by the current() method of a 
+PlaceIterator object which itself has been returned by the 
+extractLaLo() or extract() methods of a Geo::ReadGRIB object. A place 
+object has a unique latitude and longitude for one time and has data 
+for one or more data types. 
+
+=head1 METHODS
+
+Objects of this class are read only and all parameters may be
+accessed by the following methods.
+
+=over 4
+
+=item $object->new;
+
+=item $object->thisTime;
+
+=item $object->lat;
+
+=item $object->long;
+
+=item $object->types;
+
+=item $object->data(type);
+
+=back
+
+=head1 BUGS AND LIMITATIONS
+
+There are no known bugs in this module. Please report problems through
+
+http://rt.cpan.org
+
+or contact Frank Cox, <frank.l.cox@gmail.com> Patches are welcome.
+
+=head1 AUTHOR
+
+Frank Cox, E<lt>frank.l.cox@gmail.comE<gt>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2009 by Frank Cox
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself, either Perl version 5.8.4 or,
+at your option, any later version of Perl 5 you may have available.
+
+
+
+=cut
+
+
+
+1;
+
+
@@ -1,360 +1,360 @@
-#
-#===============================================================================
-#
-#         FILE:  PlaceIterator.pm
-#
-#  DESCRIPTION: A Geo::ReadGRIB::PlaceIterator object contains a collection of
-#               Geo::ReadGRIB data for a regular area and has methods to return
-#               Geo::ReadGRIB::Place in sorted sequence of locations
-#
-#        FILES:  ---
-#         BUGS:  ---
-#        NOTES:  ---
-#       AUTHOR:  Frank Lyon Cox (Dr), <frank@pwizardry.com>
-#      COMPANY:  Practial Wizardry
-#      VERSION:  1.0
-#      CREATED:  2/2/2009 12:15:57 PM Pacific Standard Time
-#     REVISION:  ---
-#===============================================================================
-
-package Geo::ReadGRIB::PlaceIterator;
-
-use strict;
-use warnings;
-use Geo::ReadGRIB::Place;
-
-our $VERSION = 1.0;
-
-#--------------------------------------------------------------------------
-#  new( )
-#--------------------------------------------------------------------------
-sub new {
-    my $class = shift;
-
-    my $self = {};
-    bless $self, $class;
-    $self->_init;
-    return $self;
-}
-
-
-#--------------------------------------------------------------------------
-#  _init( )
-#--------------------------------------------------------------------------
-sub _init {
-    my $self = shift;
-
-    $self->{shifted_west_by}   = 0;
-    $self->isSorted( undef );
-    $self->{place_index}  = 0;
-    $self->{place_sorted} = [];
-    $self->{x_y} = [];
-    $self->{count_of_places}   = 0;
-    return;
-}
-
-#--------------------------------------------------------------------------
-#  first( )
-#--------------------------------------------------------------------------
-sub first {
-    my $self = shift;
-    $self->_indexData() if not $self->isSorted;
-    $self->_setIndex( 0 );
-    return;
-}
-
-
-#--------------------------------------------------------------------------
-#  next( )
-#--------------------------------------------------------------------------
-sub next {
-    my $self = shift;
-    $self->_indexData() if not $self->isSorted;
-    if ( $self->_setIndex == $self->{count_of_places} ) {
-        return;
-    }
-    return $self->_setIndex('+');
-}
-
-#--------------------------------------------------------------------------
-#  current( )
-#
-#  returns a Geo::ReadGRIB::Place object
-#--------------------------------------------------------------------------
-sub current {
-    my $self = shift;
-
-    $self->_indexData() if not $self->isSorted;
-
-    my $index = $self->_setIndex;
-
-    my $p = Geo::ReadGRIB::Place->new;
-
-    $p->thisTime( $self->{place_sorted}->[ $index ]->[0] );
-    $p->lat( $self->{place_sorted}->[ $index ]->[1] );
-    $p->long( $self->{place_sorted}->[ $index ]->[2] );
-
-    if ( not defined $p->thisTime ) {
-        return;
-    }
-
-    for my $type ( keys %{ $self->{data}->{$p->thisTime}->{$p->lat}->{$p->long} } ) {
-        $p->types( $type );
-        $p->data( $type, $self->{data}->{$p->thisTime}->{$p->lat}->{$p->long}->{$type} );
-    }
-
-    return $p;
-}
-
-
-#--------------------------------------------------------------------------
-#  numLong( )
-#--------------------------------------------------------------------------
-sub numLong {
-    my $self = shift;
-    $self->_indexData() if not $self->isSorted;
-    return $self->{x_y}->[0];
-}
-
-#--------------------------------------------------------------------------
-#  numLat( )
-#--------------------------------------------------------------------------
-sub numLat {
-    my $self = shift;
-    $self->_indexData() if not $self->isSorted;
-    return $self->{x_y}->[1];
-}
-
-#--------------------------------------------------------------------------
-#  _setIndex( )
-#--------------------------------------------------------------------------
-sub _setIndex {
-    my $self  = shift;
-    my $index = shift;
-
-    if ( defined $index ) {
-        if ( $index eq '+' ) {
-            $self->{place_index} = $self->{place_index} + 1;
-        }
-        else {
-            $self->{place_index} = $index;
-        }
-    }
-
-    if (  $self->{place_index} > $self->{count_of_places} ) {
-        return;
-    }
-
-    return $self->{place_index};
-}
-
-#--------------------------------------------------------------------------
-#  isSorted( )
-#--------------------------------------------------------------------------
-sub isSorted {
-    my $self = shift;
-    my $bool = shift;
-    if ( $bool ) {
-        $self->{is_sorted} = 1;
-    }
-    return $self->{is_sorted};
-}
-
-#--------------------------------------------------------------------------
-#  _indexData( )
-#
-#  Inspect the data section and prepare a sorted list of
-#  [time, lat, long] 
-#
-#  -- we also count the number of lats and longs
-#
-#  Object data is updated
-#--------------------------------------------------------------------------
-sub _indexData {
-    my $self = shift;
-
-    #  Inspect the data section and prepare a sorted list of
-    #  [time, lat, long] and an array of times
-    #  -- we also count the number of lats and longs
-
-    my ( @tm, $these, $dataType );
-
-    my ( $thisTime ) = keys %{ $self->{data} }; 
-
-    my ( $laC, $loC );
-    while ( my ( $time, $laf ) = each %{ $self->{data} } ) {
-        $laC = 0;
-        while ( my ( $la, $lof ) = each %$laf ) {
-            while ( my ( $lo, $dtf ) = each %$lof ) {
-                $loC++;
-                push @$these, [ $time, $la, $lo ];
-                ($dataType) = each %$dtf;
-            }
-        }
-    }
-
-    $self->{x_y} = [  $loC / scalar keys %{ $self->{data}->{$thisTime} },
-                      scalar keys %{ $self->{data}->{$thisTime} } ];
-
-    $self->{place_sorted} = $self->_sortThese($these);
-    $self->{count_of_places} = $loC;
-    $self->isSorted( 1 );
-    $self->first;
-
-    return;
-}
-
-#--------------------------------------------------------------------------
-#  _sortThese( )
-#--------------------------------------------------------------------------
-sub _sortThese {
-    my $self    = shift;
-    my $coArray = shift;
-
-    # sort by lat and then by long
-    my @psort = sort { 
-        $a->[0] <=> $b->[0] || $b->[1] <=> $a->[1] || $a->[2] <=> $b->[2] 
-    } @$coArray;
-
-    return \@psort;
-}
-
-#--------------------------------------------------------------------------
-#  addData( time, la, lo, type, data )
-#  
-#  Add a unit of data to internal structure
-#--------------------------------------------------------------------------
-sub addData {
-    my $self = shift;
-    my $time = shift;
-    my $la   = shift;
-    my $lo   = shift;
-    my $type = shift;
-    my $data = shift;
-
-    $self->{data}->{$time}->{$la}->{$lo}->{$type} = $data if defined $data;
-    $self->{is_sorted} = undef;
-
-    return $self->{data};
-}
-
-
-
-1;
-
-
-
-#--------------------------------------------------------------------------- 
-#  Module Documentation
-#---------------------------------------------------------------------------
-
-=head1 NAME
-
-Geo::ReadGRIB::PlaceIterator - Provides methods to iterate through GRIB data
-in geographic order and to return Geo::ReadGRIB::Place objects for each location.
-
-=head1 VERSION
-
-This documentation refers to Geo::ReadGRIB::PlaceIterator version 1.0
-
-=head1 SYNOPSIS
-
-    use Geo::ReadGRIB;
-
-    $w = new Geo::ReadGRIB "grib-file";
-    $w->getFullCatalog;
-
-    print $w->show,"\n";
-  
-    $plit = $w->extractLaLo(data_type, lat1, long1, lat2, long2, time);
-    die $w->getError if $w->getError;
-
-    # $plit is a Geo::ReadGRIB::PlaceIterator
-
-    for $y ( 0 .. $plit->numLat -1 ) {
-        for $x ( 0 .. $plit->numLong -1 ) {
-        
-            my $place = $plit->current;
-            
-            # $place is a Geo::ReadGRIB::Place object
-
-            $time       = $place->thisTime;
-            $latitude   = $place->lat;
-            $longitude  = $place->long;
-            $data_types = $place->types; # an array ref of type names
-            $data = $place->data(data_type);
-
-            # process data for $x, $y
-
-            $plit->next;
-        }
-    }
-
-
-=head1 DESCRIPTION
-
-A PlaceIterator objects let you iterate through places.
-
-Objects of this class are returned by the extractLaLo() or extract() method of a 
-Geo::ReadGRIB object. It contains data for one or more data types at one or more 
-times for the area extracted. The locations are sorted first by time
-then latitude and then by longitude. Methods are provided for sequential access 
-to this data.
-
-The first() method sets the iterator index to the most northwest (lat, long) 
-pair. The current() method returns a Place object for the current location.
-The next() method advances the current location one place in rows from west to 
-east and north to south starting in the northwest corner and ending in the 
-southeast. After the last item in the southeast corner of the extracted region, 
-another call to next() returns B<undef>. 
-
-The convenience methods numLat() and numLong() return the number of latitude and
-longitude points respectively. This is handy to, for example, provide the x, y
-dimensions for a GD::Image new() method.
-
-=head1 METHODS
-
-=over 4
-
-=item $object->new;
-
-=item $object->first;
-
-=item $object->next;
-
-=item $place = $object->current;
-
-=item $y = $object->numLat;
-
-=item $y = $object->numLong;
-
-=item $y = $object->addData;
-
-=item $y = $object->isSorted;
-
-=back
-
-=head1 BUGS AND LIMITATIONS
-
-There are no known bugs in this module. Please report problems through
-
-http://rt.cpan.org
-
-or contact Frank Cox, <frank.l.cox@gmail.com> Patches are welcome.
-
-=head1 AUTHOR
-
-Frank Cox, E<lt>frank.l.cox@gmail.comE<gt>
-
-
-=head1 LICENCE AND COPYRIGHT
-
-2009 by Frank Cox
-
-This library is free software; you can redistribute it and/or modify
-it under the same terms as Perl itself, either Perl version 5.8.4 or,
-at your option, any later version of Perl 5 you may have available.
-
-
-=cut
-
+#
+#===============================================================================
+#
+#         FILE:  PlaceIterator.pm
+#
+#  DESCRIPTION: A Geo::ReadGRIB::PlaceIterator object contains a collection of
+#               Geo::ReadGRIB data for a regular area and has methods to return
+#               Geo::ReadGRIB::Place in sorted sequence of locations
+#
+#        FILES:  ---
+#         BUGS:  ---
+#        NOTES:  ---
+#       AUTHOR:  Frank Lyon Cox (Dr), <frank@pwizardry.com>
+#      COMPANY:  Practial Wizardry
+#      VERSION:  1.0
+#      CREATED:  2/2/2009 12:15:57 PM Pacific Standard Time
+#     REVISION:  ---
+#===============================================================================
+
+package Geo::ReadGRIB::PlaceIterator;
+
+use strict;
+use warnings;
+use Geo::ReadGRIB::Place;
+
+our $VERSION = 1.0;
+
+#--------------------------------------------------------------------------
+#  new( )
+#--------------------------------------------------------------------------
+sub new {
+    my $class = shift;
+
+    my $self = {};
+    bless $self, $class;
+    $self->_init;
+    return $self;
+}
+
+
+#--------------------------------------------------------------------------
+#  _init( )
+#--------------------------------------------------------------------------
+sub _init {
+    my $self = shift;
+
+    $self->{shifted_west_by}   = 0;
+    $self->isSorted( undef );
+    $self->{place_index}  = 0;
+    $self->{place_sorted} = [];
+    $self->{x_y} = [];
+    $self->{count_of_places}   = 0;
+    return;
+}
+
+#--------------------------------------------------------------------------
+#  first( )
+#--------------------------------------------------------------------------
+sub first {
+    my $self = shift;
+    $self->_indexData() if not $self->isSorted;
+    $self->_setIndex( 0 );
+    return;
+}
+
+
+#--------------------------------------------------------------------------
+#  next( )
+#--------------------------------------------------------------------------
+sub next {
+    my $self = shift;
+    $self->_indexData() if not $self->isSorted;
+    if ( $self->_setIndex == $self->{count_of_places} ) {
+        return;
+    }
+    return $self->_setIndex('+');
+}
+
+#--------------------------------------------------------------------------
+#  current( )
+#
+#  returns a Geo::ReadGRIB::Place object
+#--------------------------------------------------------------------------
+sub current {
+    my $self = shift;
+
+    $self->_indexData() if not $self->isSorted;
+
+    my $index = $self->_setIndex;
+
+    my $p = Geo::ReadGRIB::Place->new;
+
+    $p->thisTime( $self->{place_sorted}->[ $index ]->[0] );
+    $p->lat( $self->{place_sorted}->[ $index ]->[1] );
+    $p->long( $self->{place_sorted}->[ $index ]->[2] );
+
+    if ( not defined $p->thisTime ) {
+        return;
+    }
+
+    for my $type ( keys %{ $self->{data}->{$p->thisTime}->{$p->lat}->{$p->long} } ) {
+        $p->types( $type );
+        $p->data( $type, $self->{data}->{$p->thisTime}->{$p->lat}->{$p->long}->{$type} );
+    }
+
+    return $p;
+}
+
+
+#--------------------------------------------------------------------------
+#  numLong( )
+#--------------------------------------------------------------------------
+sub numLong {
+    my $self = shift;
+    $self->_indexData() if not $self->isSorted;
+    return $self->{x_y}->[0];
+}
+
+#--------------------------------------------------------------------------
+#  numLat( )
+#--------------------------------------------------------------------------
+sub numLat {
+    my $self = shift;
+    $self->_indexData() if not $self->isSorted;
+    return $self->{x_y}->[1];
+}
+
+#--------------------------------------------------------------------------
+#  _setIndex( )
+#--------------------------------------------------------------------------
+sub _setIndex {
+    my $self  = shift;
+    my $index = shift;
+
+    if ( defined $index ) {
+        if ( $index eq '+' ) {
+            $self->{place_index} = $self->{place_index} + 1;
+        }
+        else {
+            $self->{place_index} = $index;
+        }
+    }
+
+    if (  $self->{place_index} > $self->{count_of_places} ) {
+        return;
+    }
+
+    return $self->{place_index};
+}
+
+#--------------------------------------------------------------------------
+#  isSorted( )
+#--------------------------------------------------------------------------
+sub isSorted {
+    my $self = shift;
+    my $bool = shift;
+    if ( $bool ) {
+        $self->{is_sorted} = 1;
+    }
+    return $self->{is_sorted};
+}
+
+#--------------------------------------------------------------------------
+#  _indexData( )
+#
+#  Inspect the data section and prepare a sorted list of
+#  [time, lat, long] 
+#
+#  -- we also count the number of lats and longs
+#
+#  Object data is updated
+#--------------------------------------------------------------------------
+sub _indexData {
+    my $self = shift;
+
+    #  Inspect the data section and prepare a sorted list of
+    #  [time, lat, long] and an array of times
+    #  -- we also count the number of lats and longs
+
+    my ( @tm, $these, $dataType );
+
+    my ( $thisTime ) = keys %{ $self->{data} }; 
+
+    my ( $laC, $loC );
+    while ( my ( $time, $laf ) = each %{ $self->{data} } ) {
+        $laC = 0;
+        while ( my ( $la, $lof ) = each %$laf ) {
+            while ( my ( $lo, $dtf ) = each %$lof ) {
+                $loC++;
+                push @$these, [ $time, $la, $lo ];
+                ($dataType) = each %$dtf;
+            }
+        }
+    }
+
+    $self->{x_y} = [  $loC / scalar keys %{ $self->{data}->{$thisTime} },
+                      scalar keys %{ $self->{data}->{$thisTime} } ];
+
+    $self->{place_sorted} = $self->_sortThese($these);
+    $self->{count_of_places} = $loC;
+    $self->isSorted( 1 );
+    $self->first;
+
+    return;
+}
+
+#--------------------------------------------------------------------------
+#  _sortThese( )
+#--------------------------------------------------------------------------
+sub _sortThese {
+    my $self    = shift;
+    my $coArray = shift;
+
+    # sort by lat and then by long
+    my @psort = sort { 
+        $a->[0] <=> $b->[0] || $b->[1] <=> $a->[1] || $a->[2] <=> $b->[2] 
+    } @$coArray;
+
+    return \@psort;
+}
+
+#--------------------------------------------------------------------------
+#  addData( time, la, lo, type, data )
+#  
+#  Add a unit of data to internal structure
+#--------------------------------------------------------------------------
+sub addData {
+    my $self = shift;
+    my $time = shift;
+    my $la   = shift;
+    my $lo   = shift;
+    my $type = shift;
+    my $data = shift;
+
+    $self->{data}->{$time}->{$la}->{$lo}->{$type} = $data if defined $data;
+    $self->{is_sorted} = undef;
+
+    return $self->{data};
+}
+
+
+
+1;
+
+
+
+#--------------------------------------------------------------------------- 
+#  Module Documentation
+#---------------------------------------------------------------------------
+
+=head1 NAME
+
+Geo::ReadGRIB::PlaceIterator - Provides methods to iterate through GRIB data
+in geographic order and to return Geo::ReadGRIB::Place objects for each location.
+
+=head1 VERSION
+
+This documentation refers to Geo::ReadGRIB::PlaceIterator version 1.0
+
+=head1 SYNOPSIS
+
+    use Geo::ReadGRIB;
+
+    $w = new Geo::ReadGRIB "grib-file";
+    $w->getFullCatalog;
+
+    print $w->show,"\n";
+  
+    $plit = $w->extractLaLo(data_type, lat1, long1, lat2, long2, time);
+    die $w->getError if $w->getError;
+
+    # $plit is a Geo::ReadGRIB::PlaceIterator
+
+    for $y ( 0 .. $plit->numLat -1 ) {
+        for $x ( 0 .. $plit->numLong -1 ) {
+        
+            my $place = $plit->current;
+            
+            # $place is a Geo::ReadGRIB::Place object
+
+            $time       = $place->thisTime;
+            $latitude   = $place->lat;
+            $longitude  = $place->long;
+            $data_types = $place->types; # an array ref of type names
+            $data = $place->data(data_type);
+
+            # process data for $x, $y
+
+            $plit->next;
+        }
+    }
+
+
+=head1 DESCRIPTION
+
+A PlaceIterator objects let you iterate through places.
+
+Objects of this class are returned by the extractLaLo() or extract() method of a 
+Geo::ReadGRIB object. It contains data for one or more data types at one or more 
+times for the area extracted. The locations are sorted first by time
+then latitude and then by longitude. Methods are provided for sequential access 
+to this data.
+
+The first() method sets the iterator index to the most northwest (lat, long) 
+pair. The current() method returns a Place object for the current location.
+The next() method advances the current location one place in rows from west to 
+east and north to south starting in the northwest corner and ending in the 
+southeast. After the last item in the southeast corner of the extracted region, 
+another call to next() returns B<undef>. 
+
+The convenience methods numLat() and numLong() return the number of latitude and
+longitude points respectively. This is handy to, for example, provide the x, y
+dimensions for a GD::Image new() method.
+
+=head1 METHODS
+
+=over 4
+
+=item $object->new;
+
+=item $object->first;
+
+=item $object->next;
+
+=item $place = $object->current;
+
+=item $y = $object->numLat;
+
+=item $y = $object->numLong;
+
+=item $y = $object->addData;
+
+=item $y = $object->isSorted;
+
+=back
+
+=head1 BUGS AND LIMITATIONS
+
+There are no known bugs in this module. Please report problems through
+
+http://rt.cpan.org
+
+or contact Frank Cox, <frank.l.cox@gmail.com> Patches are welcome.
+
+=head1 AUTHOR
+
+Frank Cox, E<lt>frank.l.cox@gmail.comE<gt>
+
+
+=head1 LICENCE AND COPYRIGHT
+
+2009 by Frank Cox
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself, either Perl version 5.8.4 or,
+at your option, any later version of Perl 5 you may have available.
+
+
+=cut
+
@@ -15,7 +15,8 @@ use warnings;
 use IO::File;
 use Carp;
 
-our $VERSION = 1.21;
+our $VERSION = 1.4;
+
 use Geo::ReadGRIB::PlaceIterator;
 
 my $LIB_DIR = "./";
@@ -59,6 +60,7 @@ sub new {
 
     $self->{fileName} = $gFile;
     $self->{DEBUG}    = 0;
+    $self->backflip( 0 );
 
     $self->openGrib();
 
@@ -113,16 +115,10 @@ sub openGrib {
     }
 
     foreach ( sort keys %head ) {
-
         #     print " $_: $head{$_}\n";
         $self->{$_} = $head{$_};
     }
 
-    foreach ( keys %head ) {
-
-        #     $self->{$_} = $head{$_};
-    }
-
 
     # reduce date string to 'time' format
     my ( $yr, $mo, $day, $hr ) = unpack 'A4A2A2A2', $self->{d};
@@ -188,13 +184,26 @@ sub _getCatalog {
         croak "Error in \$cmd: $?";
     }
 
-    my @line;
+    my $timeRange = $self->TR;
+
+    my ( @line, $offset );
     foreach (@cat) {
         @line = split /:/;
         $line[8] =~ s/P1=//;
-        $line[8] = $line[8] * 3600 + $self->{TIME};
-        $self->{LAST_TIME} = $line[8] if $line[8] > $self->{LAST_TIME};
-        $self->{catalog}->{ $line[8] }->{ $line[3] } = $line[0];
+        $line[9] =~ s/P2=//;
+        if ( $timeRange == 0 ) {
+            $offset = $line[8];
+        }
+        elsif ( $timeRange == 10 ) {
+            $offset = ($line[8] * 256) + $line[9];
+        }
+        else {
+            croak "Time Range flag $timeRange not yet supported. Please ask the Geo::ReadGRIB maintainer to add support for GRIB files like this";
+        }
+
+        $offset = $offset * 3600 + $self->{TIME};
+        $self->{LAST_TIME} = $offset if $offset > $self->{LAST_TIME};
+        $self->{catalog}->{ $offset }->{ $line[3] } = $line[0];
     }
 
     return;
@@ -310,121 +319,100 @@ sub parseGDS {
 }
 
 #--------------------------------------------------------------------------
-# sn_scan_flag( [flag] )
-# Getter/setter for flag
+# sn_scan_flag( [flag] ) - getter/setter
 #--------------------------------------------------------------------------
 sub sn_scan_flag {
-    my $self = shift;
-    my $flag = shift;
-
+    my ( $self, $flag ) = @_;
     $self->{SN_SCAN_FLAG} = $flag if defined $flag;
     return  $self->{SN_SCAN_FLAG};
 }
 
 #--------------------------------------------------------------------------
-# error( [error message] )
-# Getter/setter for errors
+# error( [error message] ) - getter/setter for errors
 #--------------------------------------------------------------------------
 sub error {
-    my $self = shift;
-    my $error = shift;
-
+    my ( $self, $error ) = @_;
     $self->{ERROR} = $error if defined $error;
     return  $self->{ERROR};
 }
 
 #--------------------------------------------------------------------------
-# Lo1( [val] )
-# Getter/setter for Lo1
+# Lo1( [val] ) - Getter/setter for Lo1
 #--------------------------------------------------------------------------
 sub Lo1 {
-    my $self = shift;
-    my $flag = shift;
-
+    my ( $self, $flag ) = @_;
     $self->{Lo1} = $flag if defined $flag;
     return  $self->{Lo1};
 }
 
 #--------------------------------------------------------------------------
-# Lo2( [flag] )
-# Getter/setter for Lo2
+# Lo2( [flag] ) - Getter/setter for Lo2
 #--------------------------------------------------------------------------
 sub Lo2 {
-    my $self = shift;
-    my $flag = shift;
-
+    my ( $self, $flag ) = @_;
     $self->{Lo2} = $flag if defined $flag;
     return  $self->{Lo2};
 }
 
 #--------------------------------------------------------------------------
-# LoInc( [flag] )
-# Getter/setter for LoInc
+# LoInc( [flag] ) - Getter/setter for LoInc
 #--------------------------------------------------------------------------
 sub LoInc {
-    my $self = shift;
-    my $flag = shift;
-
+    my ( $self, $flag ) = @_;
     $self->{LoInc} = $flag if defined $flag;
     return  $self->{LoInc};
 }
 
 #--------------------------------------------------------------------------
-# La1( [flag] )
-# Getter/setter for La1
+# La1( [flag] ) - Getter/setter for La1
 #--------------------------------------------------------------------------
 sub La1 {
-    my $self = shift;
-    my $flag = shift;
-
+    my ( $self, $flag ) = @_;
     $self->{La1} = $flag if defined $flag;
     return  $self->{La1};
 }
 
 #--------------------------------------------------------------------------
-# La2( [flag] )
-# Getter/setter for La2
+# TR( [flag] ) - Getter/setter for TR
 #--------------------------------------------------------------------------
-sub La2 {
-    my $self = shift;
-    my $flag = shift;
+sub TR {
+    my ( $self, $flag ) = @_;
+    $self->{TR} = $flag if defined $flag;
+    return  $self->{TR};
+}
 
+#--------------------------------------------------------------------------
+# La2( [flag] ) - Getter/setter for La2
+#--------------------------------------------------------------------------
+sub La2 {
+    my ( $self, $flag ) = @_;
     $self->{La2} = $flag if defined $flag;
     return  $self->{La2};
 }
 
 #--------------------------------------------------------------------------
-# LaInc( [flag] )
-# Getter/setter for LaInc
+# LaInc( [flag] )-  Getter/setter for LaInc
 #--------------------------------------------------------------------------
 sub LaInc {
-    my $self = shift;
-    my $flag = shift;
-
+    my ( $self, $flag ) = @_;
     $self->{LaInc} = $flag if defined $flag;
     return  $self->{LaInc};
 }
 
 #--------------------------------------------------------------------------
-# Ni( [flag] )
-# Getter/setter for Ni
+# Ni( [flag] ) - Getter/setter for Ni
 #--------------------------------------------------------------------------
 sub Ni {
-    my $self = shift;
-    my $flag = shift;
-
+    my ( $self, $flag ) = @_;
     $self->{Ni} = $flag if defined $flag;
     return  $self->{Ni};
 }
 
 #--------------------------------------------------------------------------
-# Nj( [flag] )
-# Getter/setter for Nj
+# Nj( [flag] ) - Getter/setter for Nj
 #--------------------------------------------------------------------------
 sub Nj {
-    my $self = shift;
-    my $flag = shift;
-
+    my ( $self, $flag ) = @_;
     $self->{Nj} = $flag if defined $flag;
     return  $self->{Nj};
 }
@@ -627,8 +615,11 @@ sub lalo2offset {
 # This will be much faster than repeated calls to extract() because only one
 # call to wgrib and just one file open are required.
 #
-# Returns a Geo::ReadGRIB::PlaceIterator object. All data extracted is also
-# stored in the current object.
+# Returns a Geo::ReadGRIB::PlaceIterator object.
+#
+# Data is no longer stored in the current object by default as of version 
+# 1.4. To turn this behavior back on use the backflip() method;
+#
 #
 # require: lat1 >= lat2 and long1 <= long2 - that is, lat1 is north or lat2
 #          and long1 is west of long2 (or is the same as)
@@ -644,6 +635,10 @@ sub extractLaLo {
     my $long2  = shift;
     my $time   = shift;
 
+    my $flipBack = $self->backflip() ? 1 : 0;
+    my $DEBUG = $self->{DEBUG} ? 1 : 0;
+    my $LoInc = $self->LoInc;
+
     my @types;
     if ( ref $type_s eq 'ARRAY' ) {
         push @types, @$type_s;
@@ -714,22 +709,25 @@ sub extractLaLo {
         # Make sure first offset is smallest for any scanning order 
         my ( $offsetFst, $offsetLst ) = sort {$a <=> $b} ( 
             $self->lalo2offset($lat1, $long1),  $self->lalo2offset($lat2, $long2) );
-        
         $dtaLength = ($offsetLst - $offsetFst +1) * 4;        
         seek $F, $offsetFst * 4, 0;
         read $F, $fileDump, $dtaLength; 
 
+        my ($x, $y);
         $dump = "";
-        for ( $lo = $long1 ; $lo <= $long2 ; $lo += $self->LoInc ) {
-            for ( $la = $lat1 ; $la >= $lat2 ; $la -= $self->LaInc ) {
-                $offset = $self->lalo2offset( $la, $lo ) - $offsetFst;
-                $dump = substr $fileDump, $offset * 4, 4;
-                $dump = sprintf "%.2f", unpack "f", $dump;
+        for ( $la = $lat1, $x = 0 ; $la >= $lat2 ; $la -= $self->LaInc, $x++ ) {
+                my $num_lo = sprintf "%d", (($long2 - $long1) / $LoInc) +1;
+                $offset = $self->lalo2offset( $la, $long1 ) - $offsetFst;
+                my @luck = unpack "f*", substr $fileDump, $offset * 4, 4 * $num_lo;
+            for ( $lo = $long1, $y = 0 ; $lo <= $long2 ; $lo += $LoInc, $y++ ) {
+                my $dump = shift @luck;
+                $dump = defined $dump ? sprintf "%.2f", $dump : 0.00;
                 $dump = 0 if $dump eq '';
                 $dump = "UNDEF" if $dump > 999900000000000000000;
-                print gmtime($tm) . ": $self->{v_catalog}->{$type}  $dump\n"
-                  if $self->{DEBUG};
-                $self->{data}->{$tm}->{$la}->{$lo}->{$type} = $dump;
+                print gmtime($tm) . ": $self->{v_catalog}->{$type}  $dump\n" if $DEBUG;
+                $self->{data}->{$tm}->{$la}->{$lo}->{$type} = $dump if $flipBack;
+                # TODO look into the negative lats with CMS data 
+#               $self->{matrix}->{$tm}->{$type}->[$x]->[$y] = $dump if $la >= 0 and $lo >= 0;
                 $plit->addData( $tm, $la, $lo, $type, $dump );
             }
         }
@@ -742,6 +740,31 @@ sub extractLaLo {
 }
 
 #--------------------------------------------------------------------------
+# backflip( [flag] ) - Getter/setter for the backflip() state.
+#
+# When true, certain older behaviors return. In version 1.4 this is only the
+# storage in the current object of data extracted by extractLaLo(). 
+#
+# default false 
+#--------------------------------------------------------------------------
+sub backflip {
+    my ( $self, $flag ) = @_;
+    $self->{backflip} = $flag if defined $flag;
+    return  $self->{backflip};
+}
+
+#--------------------------------------------------------------------------- 
+# getMatrix({ time => time, type => type }) 
+#
+# return the array of the extracted region for type and time 
+# POSSIBLE FUTURE FUNCTION
+#--------------------------------------------------------------------------- 
+#sub getMatrix {
+#    my	( $self, $r ) = @_;
+#    return $self->{matrix}->{ $r->{time} }->{ $r->{type} };
+#}
+
+#--------------------------------------------------------------------------
 # $plit = extract(data_type, lat, long, [time])
 #
 # Extracts forecast data for given type and location. Ectracts data for all
@@ -775,7 +798,7 @@ sub extract {
     my $offset = $self->lalo2offset( $lat, $long );
 
     if ( $offset < 0 ) {
-        # do not reset error, there will be one from lalo2offset()
+        $self->error( "extract(): offset less than zero" );
         return 1;
     }
 
@@ -892,6 +915,16 @@ sub getDataHash {
     return $self->{data};
 }
 
+
+#--------------------------------------------------------------------------
+#  clearData( )
+#--------------------------------------------------------------------------
+sub clearData {
+    my $self = shift;
+    undef $self->{data};
+    return ;
+}
+
 #--------------------------------------------------------------------------
 # getError()
 #
@@ -1020,7 +1053,9 @@ sub show {
 
 1;
 
-__END__
+__DATA__
+
+=pod
 
 =head1 NAME
 
@@ -1067,7 +1102,11 @@ Binary" format Weather data files.
   $data = $w->getDataHash();
   
   # $data contains a hash reference to all grib data extracted
-  # by the object in its lifetime.
+  # by extract() the object in its lifetime.
+  #
+  # As of Version 1.4 extractLaLo() does not save extracted data to 
+  # the object by default and so it will not be returned by getDataHash().
+  # Use the backflip() method to bring back this older behavior.
   #  
   # $data->{time}->{lat}->{long}->{data_type} now contains data 
   # for data_type at lat,long and time unless there was an error
@@ -1126,22 +1165,22 @@ calling wgrib.exe
 
 =over 4
 
-=item $object = new Geo::ReadGRIB "grib_file";
+=item $O = new Geo::ReadGRIB "grib_file";
 
 Returns a Geo::ReadGRIB object that can open GRIB format file "grib_file".
 wgrib.exe is used to extract full header info from the "self describing" GRIB
 file. 
 
-=item $object->getFullCatalog();
+=item $O->getFullCatalog();
 
 getFullCatalog() will extract the full text descriptions of data items in the GRIB 
 file and store them in the object.
 
-=item $object->getParam("show");
+=item $O->getParam("show");
 
 I<getParam(show)> Returns a string listing the names of all published parameters.
 
-=item $object->getParam(param);
+=item $O->getParam(param);
 
 I<getParam(param)> returns a scalar with the value of param where param is one
 of TIME, LAST_TIME, La1, La2, LaInc, Lo1, Lo2, LoInc, fileName.
@@ -1180,13 +1219,13 @@ data.
 =back
 
 
-=item $object->show();
+=item $O->show();
 
 Returns a formatted text string description of the data in the GRIB file.
 This includes latitude, longitude, and time ranges, and data type text 
 descriptions (if getFullCatalog() has been run).
 
-=item $plit = $object->extractLaLo([data_type, ...], lat1, long1, lat2, long2, time);
+=item $plit = $O->extractLaLo([data_type, ...], lat1, long1, lat2, long2, time);
 
 Extracts forecast data for a given time and data type(s) for a range of 
 locations. The locations will be all (lat, long) points in the GRIB file inside the 
@@ -1194,7 +1233,7 @@ rectangular area defined by (lat1, long1) and (lat2, long2) where lat1 >= lat2
 and long1 <= long2. That is, lat1 is north or lat2 and long1 is west of long2
 (or equal to...)
 
-data_type is either a data type name as a string of a list of data name strings
+data_type is either a data type name as a string or a list of data name strings
 as an array reference. 
 
 Time will be in epoch seconds as returned, for example, by 
@@ -1205,12 +1244,14 @@ error will be set if time is out of range.
 Returns a L<Geo::ReadGRIB::PlaceIterator> object containing the extracted data
 which can be used to iterate through the data in order sorted by lat and then long.
 
-Extracted data is also retained in the ReadGRIB object data structure.
+Extracted data is not retained in the ReadGRIB object data structure by default
+as of ReadGRIB version 1.4. Use the backflip() method to turn this behavior 
+back on.
 
 Since extractLaLo() needs only one call to wgrib and one temp file open,
 this is faster than using extract() to get the same data points one at a time.
 
-=item $plit = $object->extract(data_type, lat, long, I<time>);
+=item $plit = $O->extract(data_type, lat, long, I<time>);
 
 Extracts forecast data for given type and location. I<time> is optional.
 Extracts data for all times in file unless a specific time is given 
@@ -1232,16 +1273,27 @@ which can be used to iterate through the data in order sorted by lat and then lo
 
 Extracted data is also retained in the ReadGRIB object data structure.
 
-=item $object->getError();
+=item $O->getError();
 
 Returns string messages for the last error set. If no error is set getError()
 returns undef. Only the most recent error will be show. It's good practice to 
 check errors after actions, especially while developing applications.
 
-=item $object->getDataHash();
+=item $bfFlag = $O->backflip();
+
+When true, certain older behaviors return. In version 1.4 this is only the
+storage in the current object of data extracted by extractLaLo().
+
+backflip() returns false by default
+
+=item $O->getDataHash();
 
 Returns a hash ref with all the data items in the object. This will be all the 
 data extracted from the GRIB file for in the life of the object.
+
+As of Version 1.4 extractLaLo() does not save extracted data to the object by 
+default and so it will not be returned by getDataHash(). Use the backflip() 
+method to bring back this older behavior.
  
 The hash structure is
 
@@ -1253,9 +1305,9 @@ The hash structure is
 
 =over
 
-=item $object->getCatalog() DEPRECATED; 
+=item $O->getCatalog() DEPRECATED; 
 
-=item $object->getCatalogVerbose() DEPRECATED;
+=item $O->getCatalogVerbose() DEPRECATED;
 
 getCatalog() is DEPRECATED and no longer does anything but set an error. 
 It's function of Getting the critical offset index for each data type and time 
@@ -1289,12 +1341,16 @@ future releases. Do not use these in production code.
 
 =item Nj()
 
+=item TR()
+
 =item adjustLong()
 
 =item calInc()
 
 =item clearError()
 
+=item clearData()
+
 =item dumpit()
 
 =item error()
@@ -1326,7 +1382,13 @@ future releases. Do not use these in production code.
 There are no known bugs in this module version. Geo::ReadGRIB versions before
 1.1 are known to give results that are sometimes off by one LoInc west or 
 east, only on 64bit Perl where nvtype='long double'. Geo::ReadGRIB 1.1 and 
-above will not exhibit this bug. Please report problems through
+above will not exhibit this bug. 
+
+Versions between 0.98_1 and 1.21 may not parse the time headers correctly for some
+forecast records in CMC grib files.  Geo::ReadGRIB 1.3 and above will not exhibit 
+this bug. 
+
+Please report problems through
 
 http://rt.cpan.org
 
@@ -1357,3 +1419,6 @@ at your option, any later version of Perl 5 you may have available.
 
 
 =cut
+
+__C__
+
@@ -0,0 +1,69 @@
+#
+#===============================================================================
+#
+#         FILE:  11-Geo-ReadGRIB-times.t
+#
+#  DESCRIPTION:  test for correct start and end dates
+#
+#        FILES:  ---
+#         BUGS:  ---
+#        NOTES:  ---
+#       AUTHOR:  Frank Lyon Cox (Dr), <frank@pwizardry.com>
+#      COMPANY:  Practial Wizardry
+#      VERSION:  1.0
+#      CREATED:  11/18/2009 4:45:49 PM Pacific Standard Time
+#     REVISION:  ---
+#===============================================================================
+
+use strict;
+use warnings;
+
+use Test::More tests => 6;                      # last test to print
+
+use Geo::ReadGRIB;
+
+## Find path to test file
+my $TEST_FILE;
+foreach my $inc (@INC) {
+   if (-e "$inc/Geo/Sample-GRIB/akw.HTSGW.grb") {
+      $TEST_FILE = "$inc/Geo/Sample-GRIB/akw.HTSGW.grb";
+      last;
+   }  
+}
+
+ok(-e "$TEST_FILE") or
+   diag("Path to sample GRIB file not found");
+
+my $w = Geo::ReadGRIB->new("$TEST_FILE");
+
+
+#print STDERR "first time: ", $w->{TIME};
+#print STDERR "last time: ", $w->{LAST_TIME};
+
+ok( $w->{TIME} == 1142078400 ) or
+   diag("base time should be 1142078400");
+
+ok( $w->{LAST_TIME} == 1142726400 ) or
+   diag("last time should be 1142726400");
+
+foreach my $inc (@INC) {
+   if (-e "$inc/Geo/Sample-GRIB/2009100900_P000.grib") {
+      $TEST_FILE = "$inc/Geo/Sample-GRIB/2009100900_P000.grib";
+      last;
+   }  
+}
+
+ok(-e "$TEST_FILE") or
+   diag("Path to sample GRIB file not found");
+
+$w = Geo::ReadGRIB->new("$TEST_FILE");
+
+
+#print STDERR "first time: ", $w->{TIME};
+#print STDERR "last time: ", $w->{LAST_TIME};
+   
+ok( $w->{TIME} == 1255046400 ) or
+   diag("base time should be 1142078400");
+
+ok( $w->{TIME} == 1255046400 ) or
+   diag("last time should be 1255046400");
@@ -3,9 +3,11 @@
 # 
 # For this to work there needs to be a specific sample GRIB file
 # and the module has to be able to find wgrib.exe 
+#
+# 3/18/2010 - added test for backflip()
 
 
-use Test::More tests => 6;
+use Test::More tests => 7;
 
 ###########################################################################
 # Object create test
@@ -42,9 +44,21 @@ diag("ERRORx: $err") if defined $err;
 
 my $data = $w->getDataHash();
 
-ok(defined $data->{$time}->{$lat2}->{$long2}->{$type})
-   or diag("\$data->{$time}->{$lat2}->{$long2}->{$type} is not defined");
+ok( not defined $data->{$time}->{$lat2}->{$long2}->{$type})
+   or diag("\$data->{$time}->{$lat2}->{$long2}->{$type} should not be defined");
 
+$w->backflip(1);
+
+$w->extractLaLo($type, $lat1, $long1, $lat2, $long2, $time); 
+
+$err = $w->getError();
+
+diag("ERRORx: $err") if defined $err;
+
+$data = $w->getDataHash();
+
+ok( defined $data->{$time}->{$lat2}->{$long2}->{$type})
+   or diag("\$data->{$time}->{$lat2}->{$long2}->{$type} not defined");
 
 ok($data->{$time}->{$lat2}->{$long2}->{$type} == 3.71)
  or diag("\$data->{$time}->{$lat2}->{$long2}->{$type}: