{"thread":{"id":"3465","subject":"[PATCH] annotate: Handle dirty state and arbitrary revisions.","startedAt":"2006-02-26T01:48:33Z","lastAt":"2006-02-26T21:09:12Z","messageCount":3,"participants":["Ryan Anderson"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"16736","messageId":"11409185133616-git-send-email-ryan@michonline.com","threadId":"3465","inReplyTo":null,"subject":"[PATCH] annotate: Handle dirty state and arbitrary revisions.","fromName":"Ryan Anderson","fromEmail":"ryan@michonline.com","sentAt":"2006-02-26T01:48:33Z","receivedAt":"2006-02-26T01:48:33Z","isPatch":true,"sender":{"key":"ryan@michonline.com","avatar":null},"body":"Also, use Getopt::Long and only process each rev once.\n\n(Thanks to Morten Welinder for spotting the performance problems.)\n\nSigned-off-by: Ryan Anderson <ryan@michonline.com>\n\n---\n\nOr pull from http://h4x0r5.com/~ryan/git/ryan.git/ annotate-upstream\n\n git-annotate.perl |  150 ++++++++++++++++++++++++++++++++++++++++-------------\n 1 files changed, 113 insertions(+), 37 deletions(-)\n\n9ca393b055b53df4eb9284b39f38c5b42b7f93b1\ndiff --git a/git-annotate.perl b/git-annotate.perl\nindex 3800c46..91da6d5 100755\n--- a/git-annotate.perl\n+++ b/git-annotate.perl\n@@ -8,44 +8,62 @@\n \n use warnings;\n use strict;\n-use Getopt::Std;\n+use Getopt::Long;\n use POSIX qw(strftime gmtime);\n \n sub usage() {\n-\tprint STDERR 'Usage: ${\\basename $0} [-s] [-S revs-file] file\n-\n-\t-l\t\tshow long rev\n-\t-r\t\tfollow renames\n-\t-S commit\tuse revs from revs-file instead of calling git-rev-list\n+\tprint STDERR 'Usage: ${\\basename $0} [-s] [-S revs-file] file [ revision ]\n+\t-l, --long\n+\t\t\tShow long rev (Defaults off)\n+\t-r, --rename\n+\t\t\tFollow renames (Defaults on).\n+\t-S, --rev-file revs-file\n+\t\t\tuse revs from revs-file instead of calling git-rev-list\n+\t-h, --help\n+\t\t\tThis message.\n ';\n \n \texit(1);\n }\n \n-our ($opt_h, $opt_l, $opt_r, $opt_S);\n-getopts(\"hlrS:\") or usage();\n-$opt_h && usage();\n+our ($help, $longrev, $rename, $starting_rev, $rev_file) = (0, 0, 1);\n+\n+my $rc = GetOptions(\t\"long|l\" => \\$longrev,\n+\t\t\t\"help|h\" => \\$help,\n+\t\t\t\"rename|r\" => \\$rename,\n+\t\t\t\"rev-file|S\" => \\$rev_file);\n+if (!$rc or $help) {\n+\tusage();\n+}\n \n my $filename = shift @ARGV;\n+if (@ARGV) {\n+\t$starting_rev = shift @ARGV;\n+}\n \n my @stack = (\n \t{\n-\t\t'rev' => \"HEAD\",\n+\t\t'rev' => defined $starting_rev ? $starting_rev : \"HEAD\",\n \t\t'filename' => $filename,\n \t},\n );\n \n-our (@lineoffsets, @pendinglineoffsets);\n our @filelines = ();\n-open(F,\"<\",$filename)\n-\tor die \"Failed to open filename: $!\";\n \n-while(<F>) {\n-\tchomp;\n-\tpush @filelines, $_;\n+if (defined $starting_rev) {\n+\t@filelines = git_cat_file($starting_rev, $filename);\n+} else {\n+\topen(F,\"<\",$filename)\n+\t\tor die \"Failed to open filename: $!\";\n+\n+\twhile(<F>) {\n+\t\tchomp;\n+\t\tpush @filelines, $_;\n+\t}\n+\tclose(F);\n+\n }\n-close(F);\n-our $leftover_lines = @filelines;\n+\n our %revs;\n our @revqueue;\n our $head;\n@@ -66,7 +84,7 @@ while (my $bound = pop @stack) {\n \t\t\tnext;\n \t\t}\n \n-\t\tif (!$opt_r) {\n+\t\tif (!$rename) {\n \t\t\tnext;\n \t\t}\n \n@@ -78,8 +96,18 @@ while (my $bound = pop @stack) {\n \t}\n }\n push @revqueue, $head;\n-init_claim($head);\n-$revs{$head}{'lineoffsets'} = {};\n+init_claim( defined $starting_rev ? $starting_rev : 'dirty');\n+unless (defined $starting_rev) {\n+\topen(DIFF,\"-|\",\"git\",\"diff\",\"-R\", \"HEAD\", \"--\",$filename)\n+\t\tor die \"Failed to call git diff to check for dirty state: $!\";\n+\n+\t_git_diff_parse(*DIFF, $head, \"dirty\", (\n+\t\t\t\t'author' => gitvar_name(\"GIT_AUTHOR_IDENT\"),\n+\t\t\t\t'author_date' => sprintf(\"%s +0000\",time()),\n+\t\t\t\t)\n+\t\t\t);\n+\tclose(DIFF);\n+}\n handle_rev();\n \n \n@@ -88,7 +116,7 @@ foreach my $l (@filelines) {\n \tmy ($output, $rev, $committer, $date);\n \tif (ref $l eq 'ARRAY') {\n \t\t($output, $rev, $committer, $date) = @$l;\n-\t\tif (!$opt_l && length($rev) > 8) {\n+\t\tif (!$longrev && length($rev) > 8) {\n \t\t\t$rev = substr($rev,0,8);\n \t\t}\n \t} else {\n@@ -102,7 +130,6 @@ foreach my $l (@filelines) {\n \n sub init_claim {\n \tmy ($rev) = @_;\n-\tmy %revinfo = git_commit_info($rev);\n \tfor (my $i = 0; $i < @filelines; $i++) {\n \t\t$filelines[$i] = [ $filelines[$i], '', '', '', 1];\n \t\t\t# line,\n@@ -117,7 +144,9 @@ sub init_claim {\n \n sub handle_rev {\n \tmy $i = 0;\n+\tmy %seen;\n \twhile (my $rev = shift @revqueue) {\n+\t\tnext if $seen{$rev}++;\n \n \t\tmy %revinfo = git_commit_info($rev);\n \n@@ -143,8 +172,8 @@ sub handle_rev {\n sub git_rev_list {\n \tmy ($rev, $file) = @_;\n \n-\tif ($opt_S) {\n-\t\topen(P, '<' . $opt_S);\n+\tif ($rev_file) {\n+\t\topen(P, '<' . $rev_file);\n \t} else {\n \t\topen(P,\"-|\",\"git-rev-list\",\"--parents\",\"--remove-empty\",$rev,\"--\",$file)\n \t\t\tor die \"Failed to exec git-rev-list: $!\";\n@@ -216,24 +245,31 @@ sub git_find_parent {\n sub git_diff_parse {\n \tmy ($parent, $rev, %revinfo) = @_;\n \n-\tmy ($ri, $pi) = (0,0);\n \topen(DIFF,\"-|\",\"git-diff-tree\",\"-M\",\"-p\",$rev,$parent,\"--\",\n \t\t\t$revs{$rev}{'filename'}, $revs{$parent}{'filename'})\n \t\tor die \"Failed to call git-diff for annotation: $!\";\n \n+\t_git_diff_parse(*DIFF, $parent, $rev, %revinfo);\n+\n+\tclose(DIFF);\n+}\n+\n+sub _git_diff_parse {\n+\tmy ($diff, $parent, $rev, %revinfo) = @_;\n+\n+\tmy ($ri, $pi) = (0,0);\n \tmy $slines = $revs{$rev}{'lines'};\n \tmy @plines;\n \n \tmy $gotheader = 0;\n-\tmy ($remstart, $remlength, $addstart, $addlength);\n-\tmy ($hunk_start, $hunk_index, $hunk_adds);\n+\tmy ($remstart);\n+\tmy ($hunk_start, $hunk_index);\n \twhile(<DIFF>) {\n \t\tchomp;\n \t\tif (m/^@@ -(\\d+),(\\d+) \\+(\\d+),(\\d+)/) {\n-\t\t\t($remstart, $remlength, $addstart, $addlength) = ($1, $2, $3, $4);\n+\t\t\t$remstart = $1;\n \t\t\t# Adjust for 0-based arrays\n \t\t\t$remstart--;\n-\t\t\t$addstart--;\n \t\t\t# Reinit hunk tracking.\n \t\t\t$hunk_start = $remstart;\n \t\t\t$hunk_index = 0;\n@@ -279,7 +315,6 @@ sub git_diff_parse {\n \t\t}\n \t\t$hunk_index++;\n \t}\n-\tclose(DIFF);\n \tfor (my $i = $ri; $i < @{$slines} ; $i++) {\n \t\tpush @plines, $slines->[$ri++];\n \t}\n@@ -295,13 +330,13 @@ sub get_line {\n }\n \n sub git_cat_file {\n-\tmy ($parent, $filename) = @_;\n-\treturn () unless defined $parent && defined $filename;\n-\tmy $blobline = `git-ls-tree $parent $filename`;\n-\tmy ($mode, $type, $blob, $tfilename) = split(/\\s+/, $blobline, 4);\n+\tmy ($rev, $filename) = @_;\n+\treturn () unless defined $rev && defined $filename;\n \n-\topen(C,\"-|\",\"git-cat-file\", \"blob\", $blob)\n-\t\tor die \"Failed to git-cat-file blob $blob (rev $parent, file $filename): \" . $!;\n+\tmy $blob = git_ls_tree($rev, $filename);\n+\n+\topen(C,\"-|\",\"git\",\"cat-file\", \"blob\", $blob)\n+\t\tor die \"Failed to git-cat-file blob $blob (rev $rev, file $filename): \" . $!;\n \n \tmy @lines;\n \twhile(<C>) {\n@@ -313,6 +348,25 @@ sub git_cat_file {\n \treturn @lines;\n }\n \n+sub git_ls_tree {\n+\tmy ($rev, $filename) = @_;\n+\n+\topen(T,\"-|\",\"git\",\"ls-tree\",$rev,$filename)\n+\t\tor die \"Failed to call git ls-tree: $!\";\n+\n+\tmy ($mode, $type, $blob, $tfilename);\n+\twhile(<T>) {\n+\t\t($mode, $type, $blob, $tfilename) = split(/\\s+/, $_, 4);\n+\t\tlast if ($tfilename eq $filename);\n+\t}\n+\tclose(T);\n+\n+\treturn $blob if $filename eq $filename;\n+\tdie \"git-ls-tree failed to find blob for $filename\";\n+\n+}\n+\n+\n \n sub claim_line {\n \tmy ($floffset, $rev, $lines, %revinfo) = @_;\n@@ -354,3 +408,25 @@ sub format_date {\n \treturn strftime(\"%Y-%m-%d %H:%M:%S \" . $timezone, gmtime($timestamp));\n }\n \n+# Copied from git-send-email.perl - We need a Git.pm module..\n+sub gitvar {\n+    my ($var) = @_;\n+    my $fh;\n+    my $pid = open($fh, '-|');\n+    die \"$!\" unless defined $pid;\n+    if (!$pid) {\n+\texec('git-var', $var) or die \"$!\";\n+    }\n+    my ($val) = <$fh>;\n+    close $fh or die \"$!\";\n+    chomp($val);\n+    return $val;\n+}\n+\n+sub gitvar_name {\n+    my ($name) = @_;\n+    my $val = gitvar($name);\n+    my @field = split(/\\s+/, $val);\n+    return join(' ', @field[0...(@field-4)]);\n+}\n+\n-- \n1.2.3.g9ca3\n"},{"id":"16737","messageId":"1140922925166-git-send-email-ryan@michonline.com","threadId":"3465","inReplyTo":"11409185133616-git-send-email-ryan@michonline.com","subject":"[PATCH] annotate: Convert all -| calls to use a helper open_pipe().","fromName":"Ryan Anderson","fromEmail":"ryan@michonline.com","sentAt":"2006-02-26T03:02:05Z","receivedAt":"2006-02-26T03:02:05Z","isPatch":true,"sender":{"key":"ryan@michonline.com","avatar":null},"body":"When we settle on a solution for ActiveState's forking issues, all\ncompatibility checks can be handled inside this one function.\n\nAlso, fixed an abuse of global variables in the process of cleaning this up.\n\nSigned-off-by: Ryan Anderson <ryan@michonline.com>\n\n---\n\n I should have done this before I sent the other patch out, sorry about\n that.  This one will also be in my annotate-upstream branch, but I'm a\n bit less sure where we stand on this kind of fixup at the moment.  Even\n if this is the wrong place to start, this at least flags all the spots\n that need fixing in a nice way.\n\n git-annotate.perl |   73 ++++++++++++++++++++++++++++++++---------------------\n 1 files changed, 44 insertions(+), 29 deletions(-)\n\n3e72e9de7ece2b9c2c9447e761ee721bdd94a33f\ndiff --git a/git-annotate.perl b/git-annotate.perl\nindex 91da6d5..ee8ff15 100755\n--- a/git-annotate.perl\n+++ b/git-annotate.perl\n@@ -98,15 +98,15 @@ while (my $bound = pop @stack) {\n push @revqueue, $head;\n init_claim( defined $starting_rev ? $starting_rev : 'dirty');\n unless (defined $starting_rev) {\n-\topen(DIFF,\"-|\",\"git\",\"diff\",\"-R\", \"HEAD\", \"--\",$filename)\n+\tmy $diff = open_pipe(\"git\",\"diff\",\"-R\", \"HEAD\", \"--\",$filename)\n \t\tor die \"Failed to call git diff to check for dirty state: $!\";\n \n-\t_git_diff_parse(*DIFF, $head, \"dirty\", (\n+\t_git_diff_parse($diff, $head, \"dirty\", (\n \t\t\t\t'author' => gitvar_name(\"GIT_AUTHOR_IDENT\"),\n \t\t\t\t'author_date' => sprintf(\"%s +0000\",time()),\n \t\t\t\t)\n \t\t\t);\n-\tclose(DIFF);\n+\tclose($diff);\n }\n handle_rev();\n \n@@ -172,20 +172,21 @@ sub handle_rev {\n sub git_rev_list {\n \tmy ($rev, $file) = @_;\n \n+\tmy $revlist;\n \tif ($rev_file) {\n-\t\topen(P, '<' . $rev_file);\n+\t\topen($revlist, '<' . $rev_file);\n \t} else {\n-\t\topen(P,\"-|\",\"git-rev-list\",\"--parents\",\"--remove-empty\",$rev,\"--\",$file)\n+\t\t$revlist = open_pipe(\"git-rev-list\",\"--parents\",\"--remove-empty\",$rev,\"--\",$file)\n \t\t\tor die \"Failed to exec git-rev-list: $!\";\n \t}\n \n \tmy @revs;\n-\twhile(my $line = <P>) {\n+\twhile(my $line = <$revlist>) {\n \t\tchomp $line;\n \t\tmy ($rev, @parents) = split /\\s+/, $line;\n \t\tpush @revs, [ $rev, @parents ];\n \t}\n-\tclose(P);\n+\tclose($revlist);\n \n \tprintf(\"0 revs found for rev %s (%s)\\n\", $rev, $file) if (@revs == 0);\n \treturn @revs;\n@@ -194,22 +195,22 @@ sub git_rev_list {\n sub find_parent_renames {\n \tmy ($rev, $file) = @_;\n \n-\topen(P,\"-|\",\"git-diff-tree\", \"-M50\", \"-r\",\"--name-status\", \"-z\",\"$rev\")\n+\tmy $patch = open_pipe(\"git-diff-tree\", \"-M50\", \"-r\",\"--name-status\", \"-z\",\"$rev\")\n \t\tor die \"Failed to exec git-diff: $!\";\n \n \tlocal $/ = \"\\0\";\n \tmy %bound;\n-\tmy $junk = <P>;\n-\twhile (my $change = <P>) {\n+\tmy $junk = <$patch>;\n+\twhile (my $change = <$patch>) {\n \t\tchomp $change;\n-\t\tmy $filename = <P>;\n+\t\tmy $filename = <$patch>;\n \t\tchomp $filename;\n \n \t\tif ($change =~ m/^[AMD]$/ ) {\n \t\t\tnext;\n \t\t} elsif ($change =~ m/^R/ ) {\n \t\t\tmy $oldfilename = $filename;\n-\t\t\t$filename = <P>;\n+\t\t\t$filename = <$patch>;\n \t\t\tchomp $filename;\n \t\t\tif ( $file eq $filename ) {\n \t\t\t\tmy $parent = git_find_parent($rev, $oldfilename);\n@@ -218,7 +219,7 @@ sub find_parent_renames {\n \t\t\t}\n \t\t}\n \t}\n-\tclose(P);\n+\tclose($patch);\n \n \treturn \\%bound;\n }\n@@ -227,14 +228,14 @@ sub find_parent_renames {\n sub git_find_parent {\n \tmy ($rev, $filename) = @_;\n \n-\topen(REVPARENT,\"-|\",\"git-rev-list\",\"--remove-empty\", \"--parents\",\"--max-count=1\",\"$rev\",\"--\",$filename)\n+\tmy $revparent = open_pipe(\"git-rev-list\",\"--remove-empty\", \"--parents\",\"--max-count=1\",\"$rev\",\"--\",$filename)\n \t\tor die \"Failed to open git-rev-list to find a single parent: $!\";\n \n-\tmy $parentline = <REVPARENT>;\n+\tmy $parentline = <$revparent>;\n \tchomp $parentline;\n \tmy ($revfound,$parent) = split m/\\s+/, $parentline;\n \n-\tclose(REVPARENT);\n+\tclose($revparent);\n \n \treturn $parent;\n }\n@@ -245,13 +246,13 @@ sub git_find_parent {\n sub git_diff_parse {\n \tmy ($parent, $rev, %revinfo) = @_;\n \n-\topen(DIFF,\"-|\",\"git-diff-tree\",\"-M\",\"-p\",$rev,$parent,\"--\",\n+\tmy $diff = open_pipe(\"git-diff-tree\",\"-M\",\"-p\",$rev,$parent,\"--\",\n \t\t\t$revs{$rev}{'filename'}, $revs{$parent}{'filename'})\n \t\tor die \"Failed to call git-diff for annotation: $!\";\n \n-\t_git_diff_parse(*DIFF, $parent, $rev, %revinfo);\n+\t_git_diff_parse($diff, $parent, $rev, %revinfo);\n \n-\tclose(DIFF);\n+\tclose($diff);\n }\n \n sub _git_diff_parse {\n@@ -264,7 +265,7 @@ sub _git_diff_parse {\n \tmy $gotheader = 0;\n \tmy ($remstart);\n \tmy ($hunk_start, $hunk_index);\n-\twhile(<DIFF>) {\n+\twhile(<$diff>) {\n \t\tchomp;\n \t\tif (m/^@@ -(\\d+),(\\d+) \\+(\\d+),(\\d+)/) {\n \t\t\t$remstart = $1;\n@@ -335,15 +336,15 @@ sub git_cat_file {\n \n \tmy $blob = git_ls_tree($rev, $filename);\n \n-\topen(C,\"-|\",\"git\",\"cat-file\", \"blob\", $blob)\n+\tmy $catfile = open_pipe(\"git\",\"cat-file\", \"blob\", $blob)\n \t\tor die \"Failed to git-cat-file blob $blob (rev $rev, file $filename): \" . $!;\n \n \tmy @lines;\n-\twhile(<C>) {\n+\twhile(<$catfile>) {\n \t\tchomp;\n \t\tpush @lines, $_;\n \t}\n-\tclose(C);\n+\tclose($catfile);\n \n \treturn @lines;\n }\n@@ -351,15 +352,15 @@ sub git_cat_file {\n sub git_ls_tree {\n \tmy ($rev, $filename) = @_;\n \n-\topen(T,\"-|\",\"git\",\"ls-tree\",$rev,$filename)\n+\tmy $lstree = open_pipe(\"git\",\"ls-tree\",$rev,$filename)\n \t\tor die \"Failed to call git ls-tree: $!\";\n \n \tmy ($mode, $type, $blob, $tfilename);\n-\twhile(<T>) {\n+\twhile(<$lstree>) {\n \t\t($mode, $type, $blob, $tfilename) = split(/\\s+/, $_, 4);\n \t\tlast if ($tfilename eq $filename);\n \t}\n-\tclose(T);\n+\tclose($lstree);\n \n \treturn $blob if $filename eq $filename;\n \tdie \"git-ls-tree failed to find blob for $filename\";\n@@ -379,11 +380,11 @@ sub claim_line {\n \n sub git_commit_info {\n \tmy ($rev) = @_;\n-\topen(COMMIT, \"-|\",\"git-cat-file\", \"commit\", $rev)\n+\tmy $commit = open_pipe(\"git-cat-file\", \"commit\", $rev)\n \t\tor die \"Failed to call git-cat-file: $!\";\n \n \tmy %info;\n-\twhile(<COMMIT>) {\n+\twhile(<$commit>) {\n \t\tchomp;\n \t\tlast if (length $_ == 0);\n \n@@ -397,7 +398,7 @@ sub git_commit_info {\n \t\t\t$info{'committer_date'} = $3;\n \t\t}\n \t}\n-\tclose(COMMIT);\n+\tclose($commit);\n \n \treturn %info;\n }\n@@ -430,3 +431,17 @@ sub gitvar_name {\n     return join(' ', @field[0...(@field-4)]);\n }\n \n+\n+sub open_pipe {\n+\tmy (@execlist) = @_;\n+\n+\tmy $pid = open my $kid, \"-|\";\n+\tdefined $pid or die \"Cannot fork: $!\";\n+\n+\tunless ($pid) {\n+\t\texec @execlist;\n+\t\tdie \"Cannot exec @execlist: $!\";\n+\t}\n+\n+\treturn $kid;\n+}\n-- \n1.2.3.g9ca3\n"},{"id":"16769","messageId":"11409881522219-git-send-email-ryan@michonline.com","threadId":"3465","inReplyTo":"1140922925166-git-send-email-ryan@michonline.com","subject":"[PATCH] annotate: Use qx{} for pipes on activestate.","fromName":"Ryan Anderson","fromEmail":"ryan@michonline.com","sentAt":"2006-02-26T21:09:12Z","receivedAt":"2006-02-26T21:09:12Z","isPatch":true,"sender":{"key":"ryan@michonline.com","avatar":null},"body":"Note: This needs someone to tell me what the value of $^O is on ActiveState.\n\nSigned-off-by: Ryan Anderson <ryan@michonline.com>\n\n---\n\nAs always, available in\n\thttp://h4x0r5.com/~ryan/git/ryan.git/ annotate-upstream\n\nRandal, does this look basically the right approach here?\n(I would like to make that glob I use not a global, but I can't\nseem to figure out how at the moment.)\n\n git-annotate.perl |   43 ++++++++++++++++++++++++++++++++++++++++++-\n 1 files changed, 42 insertions(+), 1 deletions(-)\n\na927bb08b9b319cc3832fcf354a75e3760af593c\ndiff --git a/git-annotate.perl b/git-annotate.perl\nindex ee8ff15..f9c2c6c 100755\n--- a/git-annotate.perl\n+++ b/git-annotate.perl\n@@ -431,8 +431,20 @@ sub gitvar_name {\n     return join(' ', @field[0...(@field-4)]);\n }\n \n-\n sub open_pipe {\n+\tif ($^O eq '##INSERT_ACTIVESTATE_STRING_HERE##') {\n+\t\treturn open_pipe_activestate(@_);\n+\t} else {\n+\t\treturn open_pipe_normal(@_);\n+\t}\n+}\n+\n+sub open_pipe_activestate {\n+\ttie *fh, \"Git::ActiveStatePipe\", @_;\n+\treturn *fh;\n+}\n+\n+sub open_pipe_normal {\n \tmy (@execlist) = @_;\n \n \tmy $pid = open my $kid, \"-|\";\n@@ -445,3 +457,32 @@ sub open_pipe {\n \n \treturn $kid;\n }\n+\n+package Git::ActiveStatePipe;\n+use strict;\n+\n+sub TIEHANDLE {\n+\tmy ($class, @params) = @_;\n+\tmy $cmdline = join \" \", @params;\n+\tmy  @data = qx{$cmdline};\n+\tbless { i => 0, data => \\@data }, $class;\n+}\n+\n+sub READLINE {\n+\tmy $self = shift;\n+\tif ($self->{i} >= scalar @{$self->{data}}) {\n+\t\treturn undef;\n+\t}\n+\treturn $self->{'data'}->[ $self->{i}++ ];\n+}\n+\n+sub CLOSE {\n+\tmy $self = shift;\n+\tdelete $self->{data};\n+\tdelete $self->{i};\n+}\n+\n+sub EOF {\n+\tmy $self = shift;\n+\treturn ($self->{i} >= scalar @{$self->{data}});\n+}\n-- \n1.2.3.g9ca3\n"}]}