line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Term::ProgressBar; |
2
|
|
|
|
|
|
|
|
3
|
12
|
|
|
12
|
|
233295
|
use strict; |
|
12
|
|
|
|
|
46
|
|
|
12
|
|
|
|
|
322
|
|
4
|
12
|
|
|
12
|
|
55
|
use warnings; |
|
12
|
|
|
|
|
20
|
|
|
12
|
|
|
|
|
1166
|
|
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
our $VERSION = '2.23'; |
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
#XXX TODO Redo original test with count=20 |
9
|
|
|
|
|
|
|
# Amount Output |
10
|
|
|
|
|
|
|
# Amount Prefix/Suffix |
11
|
|
|
|
|
|
|
# Tinker with $0? |
12
|
|
|
|
|
|
|
# Test use of last_update (with update(*undef*)) with scales |
13
|
|
|
|
|
|
|
# Choice of FH other than STDERR |
14
|
|
|
|
|
|
|
# If no term, output no progress bar; just progress so far |
15
|
|
|
|
|
|
|
# Use of simple term with v2.0 bar |
16
|
|
|
|
|
|
|
# If name is wider than term, trim name |
17
|
|
|
|
|
|
|
# Don't update progress bar on new? |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
=head1 NAME |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
Term::ProgressBar - provide a progress meter on a standard terminal |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
=head1 VERSION |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
Version 2.23 |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
=head1 SYNOPSIS |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
use Term::ProgressBar; |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
my $progress = Term::ProgressBar->new ({count => 10_000}); |
32
|
|
|
|
|
|
|
$progress->update(5_000); |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
=head1 DESCRIPTION |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
Term::ProgressBar provides a simple progress bar on the terminal, to let the |
37
|
|
|
|
|
|
|
user know that something is happening, roughly how much stuff has been done, |
38
|
|
|
|
|
|
|
and maybe an estimate at how long remains. |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
A typical use sets up the progress bar with a number of items to do, and then |
41
|
|
|
|
|
|
|
calls L to update the bar whenever an item is processed. |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
Often, this would involve updating the progress bar many times with no |
44
|
|
|
|
|
|
|
user-visible change. To avoid unnecessary work, the update method returns a |
45
|
|
|
|
|
|
|
value, being the update value at which the user will next see a change. By |
46
|
|
|
|
|
|
|
only calling update when the current value exceeds the next update value, the |
47
|
|
|
|
|
|
|
call overhead is reduced. |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
Remember to call the C<< $progress->update($max_value) >> when the job is done |
50
|
|
|
|
|
|
|
to get a nice 100% done bar. |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
A progress bar by default is simple; it just goes from left-to-right, filling |
53
|
|
|
|
|
|
|
the bar with '=' characters. These are called B characters. For |
54
|
|
|
|
|
|
|
long-running jobs, this may be too slow, so two additional features are |
55
|
|
|
|
|
|
|
available: a linear completion time estimator, and/or a B character: |
56
|
|
|
|
|
|
|
this is a character that I from left-to-right on the progress bar (it |
57
|
|
|
|
|
|
|
does not fill it as the major character does), traversing once for each |
58
|
|
|
|
|
|
|
major-character added. This exponentially increases the granularity of the |
59
|
|
|
|
|
|
|
bar for the same width. |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
=head1 EXAMPLES |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
=head2 A really simple use |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
#!/usr/bin/perl |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
use Term::ProgressBar 2.00; |
68
|
|
|
|
|
|
|
use constant MAX => 100_000; |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
my $progress = Term::ProgressBar->new(MAX); |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
for (0..MAX) { |
73
|
|
|
|
|
|
|
my $is_power = 0; |
74
|
|
|
|
|
|
|
for (my $i = 0; 2**$i <= $_; $i++) { |
75
|
|
|
|
|
|
|
$is_power = 1 if 2**$i == $_; |
76
|
|
|
|
|
|
|
} |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
if ($is_power) { |
79
|
|
|
|
|
|
|
$progress->update($_); |
80
|
|
|
|
|
|
|
} |
81
|
|
|
|
|
|
|
} |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
see eg/simle_use.pl |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
Here is a simple example. The process considers all the numbers between 0 and |
86
|
|
|
|
|
|
|
MAX, and updates the progress bar whenever it finds one. Note that the |
87
|
|
|
|
|
|
|
progress bar update will be very erratic. See below for a smoother example. |
88
|
|
|
|
|
|
|
Note also that the progress bar will never complete; see below to solve this. |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
The complete text of this example is in F in the |
91
|
|
|
|
|
|
|
distribution set (it is not installed as part of the module). |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
=head2 A smoother bar update |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
my $progress = Term::ProgressBar->new($max); |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
for (0..$max) { |
98
|
|
|
|
|
|
|
my $is_power = 0; |
99
|
|
|
|
|
|
|
for (my $i = 0; 2**$i <= $_; $i++) { |
100
|
|
|
|
|
|
|
$is_power = 1 if 2**$i == $_; |
101
|
|
|
|
|
|
|
} |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
$progress->update($_) |
104
|
|
|
|
|
|
|
} |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
See eg/smooth_bar.pl |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
This example calls update for each value considered. This will result in a |
109
|
|
|
|
|
|
|
much smoother progress update, but more program time is spent updating the bar |
110
|
|
|
|
|
|
|
than doing the "real" work. See below to remedy this. This example does |
111
|
|
|
|
|
|
|
I call C<< $progress->update($max); >> at the end, since it is |
112
|
|
|
|
|
|
|
unnecessary, and ProgressBar will throw an exception at an attempt to update a |
113
|
|
|
|
|
|
|
finished bar. |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
The complete text of this example is in F in the |
116
|
|
|
|
|
|
|
distribution set (it is not installed as part of the module. |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
=head2 A (much) more efficient update |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
my $progress = Term::ProgressBar->new({name => 'Powers', count => $max, remove => 1}); |
121
|
|
|
|
|
|
|
$progress->minor(0); |
122
|
|
|
|
|
|
|
my $next_update = 0; |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
for (0..$max) { |
125
|
|
|
|
|
|
|
my $is_power = 0; |
126
|
|
|
|
|
|
|
for (my $i = 0; 2**$i <= $_; $i++) { |
127
|
|
|
|
|
|
|
$is_power = 1 if 2**$i == $_; |
128
|
|
|
|
|
|
|
} |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
$next_update = $progress->update($_) if $_ >= $next_update; |
131
|
|
|
|
|
|
|
} |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
$progress->update($max) if $max >= $next_update; |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
This example does two things to improve efficiency: firstly, it uses the value |
136
|
|
|
|
|
|
|
returned by L to only call it again when needed; secondly, it |
137
|
|
|
|
|
|
|
switches off the use of minor characters to update a lot less frequently (C<< |
138
|
|
|
|
|
|
|
$progress->minor(0); >>. The use of the return value of L |
139
|
|
|
|
|
|
|
means that the call of C<< $progress->update($max); >> at the end is required |
140
|
|
|
|
|
|
|
to ensure that the bar ends on 100%, which gives the user a nice feeling. |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
This example also sets the name of the progress bar. |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
This example also demonstrates the use of the 'remove' flag, which removes the |
145
|
|
|
|
|
|
|
progress bar from the terminal when done. |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
The complete text of this example is in F in the |
148
|
|
|
|
|
|
|
distribution set (it is not installed as part of the module. |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
=head2 When the maximum number of items is sometimes unknown |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
Sometimes you may wish to use the progress bar when the number of items may or |
153
|
|
|
|
|
|
|
may not be known. One common example is when you write a script that can take |
154
|
|
|
|
|
|
|
input piped from the output of another command, and then pipe the output to yet |
155
|
|
|
|
|
|
|
another command. eg: |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
some_command --arg value | my_script.pl | some_other_command |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
Or ... |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
my_script.pl input_file output_file |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
This example shows how you can iterate over a file specified on the command line |
164
|
|
|
|
|
|
|
with the progress bar. Since the input file may be read from STDIN, the number |
165
|
|
|
|
|
|
|
of lines may not be known. Term::ProgressBar handles this by just taking '-1' as |
166
|
|
|
|
|
|
|
the count value and with no further changes to the code. By calling update |
167
|
|
|
|
|
|
|
with the same count value, you ensure the progress bar is removed afterwards. |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
my $input_file = shift; |
170
|
|
|
|
|
|
|
my $output_file = shift; |
171
|
|
|
|
|
|
|
my $in_fh = \*STDIN; |
172
|
|
|
|
|
|
|
my $out_fh = \*STDOUT; |
173
|
|
|
|
|
|
|
my $message_fh = \*STDERR; |
174
|
|
|
|
|
|
|
my $num_lines = -1; |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
if (defined($input_file) and $input_file ne '-') { |
177
|
|
|
|
|
|
|
open($in_fh, $input_file) or die "Couldn't open file, '$input_file': $!"; |
178
|
|
|
|
|
|
|
my $wc_output = `wc -l $input_file`; |
179
|
|
|
|
|
|
|
chomp($wc_output); |
180
|
|
|
|
|
|
|
$wc_output =~ /^\s*(\d+)(\D.*)?/ or die "Couldn't parse wc output: $wc_output"; |
181
|
|
|
|
|
|
|
$num_lines = $1; |
182
|
|
|
|
|
|
|
} |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
if(defined($output_file)) { |
185
|
|
|
|
|
|
|
!-f $output_file or die "Specified output file, '$output_file', already exists"; |
186
|
|
|
|
|
|
|
open($out_fh, '>', $output_file) or die "Couldn't open output file, '$output_file': $!"; |
187
|
|
|
|
|
|
|
} |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
my $progress = Term::ProgressBar->new({ |
190
|
|
|
|
|
|
|
name => 'file processor', |
191
|
|
|
|
|
|
|
count => $num_lines, |
192
|
|
|
|
|
|
|
remove => 1, |
193
|
|
|
|
|
|
|
fh => $message_fh, |
194
|
|
|
|
|
|
|
}); |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
while (my $line = <$in_fh>) { |
197
|
|
|
|
|
|
|
chomp($line); |
198
|
|
|
|
|
|
|
print $out_fh "I found a line: $line\n"; |
199
|
|
|
|
|
|
|
$progress->message("Found 10000!") if($line =~ /10000/); |
200
|
|
|
|
|
|
|
$progress->update(); |
201
|
|
|
|
|
|
|
} |
202
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
$progress->update($num_lines); |
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
print $message_fh "Finished\n"; |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
When the file is defined explicitly, the progress bar displays the linewise |
208
|
|
|
|
|
|
|
progress through the file. Since the progress bar by default prints output to |
209
|
|
|
|
|
|
|
stderr, your scripts output to STDOUT will not be affected. |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
=head2 Using Completion Time Estimation |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
my $progress = Term::ProgressBar->new({ |
214
|
|
|
|
|
|
|
name => 'Powers', |
215
|
|
|
|
|
|
|
count => $max, |
216
|
|
|
|
|
|
|
ETA => 'linear', |
217
|
|
|
|
|
|
|
}); |
218
|
|
|
|
|
|
|
$progress->max_update_rate(1); |
219
|
|
|
|
|
|
|
my $next_update = 0; |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
for (0..$max) { |
222
|
|
|
|
|
|
|
my $is_power = 0; |
223
|
|
|
|
|
|
|
for (my $i = 0; 2**$i <= $_; $i++) { |
224
|
|
|
|
|
|
|
if ( 2**$i == $_ ) { |
225
|
|
|
|
|
|
|
$is_power = 1; |
226
|
|
|
|
|
|
|
$progress->message(sprintf "Found %8d to be 2 ** %2d", $_, $i); |
227
|
|
|
|
|
|
|
} |
228
|
|
|
|
|
|
|
} |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
$next_update = $progress->update($_) |
231
|
|
|
|
|
|
|
if $_ > $next_update; |
232
|
|
|
|
|
|
|
} |
233
|
|
|
|
|
|
|
$progress->update($max) |
234
|
|
|
|
|
|
|
if $max >= $next_update; |
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
This example uses the L option to switch on completion estimation. |
237
|
|
|
|
|
|
|
Also, the update return is tuned to try to update the bar approximately once |
238
|
|
|
|
|
|
|
per second, with the L call. See the |
239
|
|
|
|
|
|
|
documentation for the L method for details of the format(s) used. |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
This example also provides an example of the use of the L |
242
|
|
|
|
|
|
|
function to output messages to the same filehandle whilst keeping the progress bar intact |
243
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
The complete text of this example is in F in the |
245
|
|
|
|
|
|
|
distribution set (it is not installed as part of the module. |
246
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
=cut |
248
|
|
|
|
|
|
|
|
249
|
12
|
|
|
12
|
|
85
|
use Carp qw( croak ); |
|
12
|
|
|
|
|
23
|
|
|
12
|
|
|
|
|
649
|
|
250
|
12
|
|
|
12
|
|
5629
|
use Class::MethodMaker 1.02 qw( ); |
|
12
|
|
|
|
|
183526
|
|
|
12
|
|
|
|
|
361
|
|
251
|
12
|
|
|
12
|
|
6771
|
use Fatal qw( open sysopen close seek ); |
|
12
|
|
|
|
|
150672
|
|
|
12
|
|
|
|
|
56
|
|
252
|
12
|
|
|
12
|
|
28084
|
use POSIX qw( ceil strftime ); |
|
12
|
|
|
|
|
54207
|
|
|
12
|
|
|
|
|
76
|
|
253
|
|
|
|
|
|
|
|
254
|
12
|
|
|
12
|
|
14820
|
use constant MINUTE => 60; |
|
12
|
|
|
|
|
24
|
|
|
12
|
|
|
|
|
862
|
|
255
|
12
|
|
|
12
|
|
68
|
use constant HOUR => 60 * MINUTE; |
|
12
|
|
|
|
|
22
|
|
|
12
|
|
|
|
|
593
|
|
256
|
12
|
|
|
12
|
|
62
|
use constant DAY => 24 * HOUR; |
|
12
|
|
|
|
|
22
|
|
|
12
|
|
|
|
|
573
|
|
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
# The point past which to give ETA of just date, rather than time |
259
|
12
|
|
|
12
|
|
73
|
use constant ETA_DATE_CUTOFF => 3 * DAY; |
|
12
|
|
|
|
|
20
|
|
|
12
|
|
|
|
|
663
|
|
260
|
|
|
|
|
|
|
# The point past which to give ETA of time, rather time left |
261
|
12
|
|
|
12
|
|
64
|
use constant ETA_TIME_CUTOFF => 10 * MINUTE; |
|
12
|
|
|
|
|
20
|
|
|
12
|
|
|
|
|
571
|
|
262
|
|
|
|
|
|
|
# The ratio prior to which to not dare any estimates |
263
|
12
|
|
|
12
|
|
62
|
use constant PREDICT_RATIO => 0.01; |
|
12
|
|
|
|
|
23
|
|
|
12
|
|
|
|
|
961
|
|
264
|
|
|
|
|
|
|
|
265
|
12
|
|
|
|
|
1026
|
use constant DEFAULTS => { |
266
|
|
|
|
|
|
|
lbrack => '[', |
267
|
|
|
|
|
|
|
rbrack => ']', |
268
|
|
|
|
|
|
|
minor_char => '*', |
269
|
|
|
|
|
|
|
major_char => '=', |
270
|
|
|
|
|
|
|
fh => \*STDERR, |
271
|
|
|
|
|
|
|
name => undef, |
272
|
|
|
|
|
|
|
ETA => undef, |
273
|
|
|
|
|
|
|
max_update_rate => 0.5, |
274
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
# The following defaults are never used, but the keys |
276
|
|
|
|
|
|
|
# are valuable for error checking |
277
|
|
|
|
|
|
|
count => undef, |
278
|
|
|
|
|
|
|
bar_width => undef, |
279
|
|
|
|
|
|
|
term_width => undef, |
280
|
|
|
|
|
|
|
term => undef, |
281
|
|
|
|
|
|
|
remove => 0, |
282
|
|
|
|
|
|
|
silent => 0, |
283
|
12
|
|
|
12
|
|
69
|
}; |
|
12
|
|
|
|
|
102
|
|
284
|
|
|
|
|
|
|
|
285
|
12
|
|
|
12
|
|
72
|
use constant ETA_TYPES => { map { $_ => 1 } qw( linear ) }; |
|
12
|
|
|
|
|
33
|
|
|
12
|
|
|
|
|
26
|
|
|
12
|
|
|
|
|
716
|
|
286
|
|
|
|
|
|
|
|
287
|
12
|
|
|
12
|
|
78
|
use constant ALREADY_FINISHED => 'progress bar already finished'; |
|
12
|
|
|
|
|
28
|
|
|
12
|
|
|
|
|
31414
|
|
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
# This is here to allow testing to redirect away from the terminal but still |
291
|
|
|
|
|
|
|
# see terminal output, IYSWIM |
292
|
|
|
|
|
|
|
my $__FORCE_TERM = 0; |
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
# ---------------------------------- |
295
|
|
|
|
|
|
|
# CLASS HIGHER-LEVEL FUNCTIONS |
296
|
|
|
|
|
|
|
# ---------------------------------- |
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
# ---------------------------------- |
299
|
|
|
|
|
|
|
# CLASS HIGHER-LEVEL PROCEDURES |
300
|
|
|
|
|
|
|
# ---------------------------------- |
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
sub __force_term { |
303
|
9
|
|
|
9
|
|
5595
|
my $class = shift; |
304
|
9
|
|
|
|
|
30
|
($__FORCE_TERM) = @_; |
305
|
|
|
|
|
|
|
} |
306
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
# ---------------------------------- |
308
|
|
|
|
|
|
|
# CLASS UTILITY FUNCTIONS |
309
|
|
|
|
|
|
|
# ---------------------------------- |
310
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
sub term_size { |
312
|
0
|
|
|
0
|
0
|
0
|
my ( $self, $fh ) = @_; |
313
|
0
|
0
|
|
|
|
0
|
return if $self->silent; |
314
|
|
|
|
|
|
|
|
315
|
0
|
|
|
|
|
0
|
eval { |
316
|
0
|
|
|
|
|
0
|
require Term::ReadKey; |
317
|
0
|
0
|
|
|
|
0
|
}; if ($@) { |
318
|
0
|
|
|
|
|
0
|
warn "Guessing terminal width due to problem with Term::ReadKey\n"; |
319
|
0
|
|
|
|
|
0
|
return 50; |
320
|
|
|
|
|
|
|
} |
321
|
|
|
|
|
|
|
|
322
|
0
|
|
|
|
|
0
|
my $result; |
323
|
0
|
|
|
|
|
0
|
eval { |
324
|
0
|
|
|
|
|
0
|
$result = (Term::ReadKey::GetTerminalSize($fh))[0]; |
325
|
0
|
0
|
0
|
|
|
0
|
$result-- if ($^O eq "MSWin32" or $^O eq "cygwin"); |
326
|
0
|
0
|
|
|
|
0
|
}; if ( $@ ) { |
327
|
0
|
|
|
|
|
0
|
warn "error from Term::ReadKey::GetTerminalSize(): $@"; |
328
|
|
|
|
|
|
|
} |
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
# If GetTerminalSize() failed it should (according to its docs) |
331
|
|
|
|
|
|
|
# return an empty list. It doesn't - that's why we have the eval {} |
332
|
|
|
|
|
|
|
# above - but also it may appear to succeed and return a width of |
333
|
|
|
|
|
|
|
# zero. |
334
|
|
|
|
|
|
|
# |
335
|
0
|
0
|
|
|
|
0
|
if ( ! $result ) { |
336
|
0
|
|
|
|
|
0
|
$result = 50; |
337
|
0
|
|
|
|
|
0
|
warn "guessing terminal width $result\n"; |
338
|
|
|
|
|
|
|
} |
339
|
|
|
|
|
|
|
|
340
|
0
|
|
|
|
|
0
|
return $result; |
341
|
|
|
|
|
|
|
} |
342
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
# Don't document hash keys until tested that the give the desired affect! |
344
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
=head1 INSTANCE CONSTRUCTION |
346
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
=head2 new |
348
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
Create & return a new Term::ProgressBar instance. |
350
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
=over 4 |
352
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
=item ARGUMENTS |
354
|
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
If one argument is provided, and it is a hashref, then the hash is treated as |
356
|
|
|
|
|
|
|
a set of key/value pairs, with the following keys; otherwise, it is treated as |
357
|
|
|
|
|
|
|
a number, being equivalent to the C key. |
358
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
=over 4 |
360
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
=item count |
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
The item count. The progress is marked at 100% when update I is |
364
|
|
|
|
|
|
|
invoked, and proportionally until then. |
365
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
If you specify a count less than zero, just the name (if specified) will be |
367
|
|
|
|
|
|
|
displayed and (if the remove flag is set) removed when the progress bar is |
368
|
|
|
|
|
|
|
updated with a number lower than zero. This allows you to use the progress bar |
369
|
|
|
|
|
|
|
when the count is sometimes known and sometimes not without making multiple |
370
|
|
|
|
|
|
|
changes throughout your code. |
371
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
=item name |
373
|
|
|
|
|
|
|
|
374
|
|
|
|
|
|
|
A name to prefix the progress bar with. |
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
=item fh |
377
|
|
|
|
|
|
|
|
378
|
|
|
|
|
|
|
The filehandle to output to. Defaults to stderr. Do not try to use |
379
|
|
|
|
|
|
|
*foo{THING} syntax if you want Term capabilities; it does not work. Pass in a |
380
|
|
|
|
|
|
|
globref instead. |
381
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
=item term_width |
383
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
Sometimes we can't correctly determine the terminal width. You can use this |
385
|
|
|
|
|
|
|
parameter to force a term width of a particular size. Use a positive integer, |
386
|
|
|
|
|
|
|
please :) |
387
|
|
|
|
|
|
|
|
388
|
|
|
|
|
|
|
=item silent |
389
|
|
|
|
|
|
|
|
390
|
|
|
|
|
|
|
If passed a true value, Term::ProgressBar will do nothing at all. Useful in |
391
|
|
|
|
|
|
|
scripts where the progress bar is optional (or just plain doesn't work due to |
392
|
|
|
|
|
|
|
issues with modules it relies on). |
393
|
|
|
|
|
|
|
|
394
|
|
|
|
|
|
|
Instead, tell the constructor you want it to be silent and you don't need to |
395
|
|
|
|
|
|
|
change the rest of your program: |
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
my $progress = Term::ProgressBar->new( { count => $count, silent => $silent } ); |
398
|
|
|
|
|
|
|
# later |
399
|
|
|
|
|
|
|
$progress->update; # does nothing |
400
|
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
=item ETA |
402
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
A total time estimation to use. If enabled, a time finished estimation is |
404
|
|
|
|
|
|
|
printed on the RHS (once sufficient updates have been performed to make such |
405
|
|
|
|
|
|
|
an estimation feasible). Naturally, this is an I; no guarantees are |
406
|
|
|
|
|
|
|
made. The format of the estimate |
407
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
Note that the format is intended to be as compact as possible while giving |
409
|
|
|
|
|
|
|
over the relevant information. Depending upon the time remaining, the format |
410
|
|
|
|
|
|
|
is selected to provide some resolution whilst remaining compact. Since the |
411
|
|
|
|
|
|
|
time remaining decreases, the format typically changes over time. |
412
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
As the ETA approaches, the format will state minutes & seconds left. This is |
414
|
|
|
|
|
|
|
identifiable by the word C<'Left'> at the RHS of the line. If the ETA is |
415
|
|
|
|
|
|
|
further away, then an estimate time of completion (rather than time left) is |
416
|
|
|
|
|
|
|
given, and is identifiable by C<'ETA'> at the LHS of the ETA box (on the right |
417
|
|
|
|
|
|
|
of the progress bar). A time or date may be presented; these are of the form |
418
|
|
|
|
|
|
|
of a 24 hour clock, e.g. C<'13:33'>, a time plus days (e.g., C<' 7PM+3'> for |
419
|
|
|
|
|
|
|
around in over 3 days time) or a day/date, e.g. C<' 1Jan'> or C<'27Feb'>. |
420
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
If ETA is switched on, the return value of L is also |
422
|
|
|
|
|
|
|
affected: the idea here is that if the progress bar seems to be moving quicker |
423
|
|
|
|
|
|
|
than the eye would normally care for (and thus a great deal of time is spent |
424
|
|
|
|
|
|
|
doing progress updates rather than "real" work), the next value is increased |
425
|
|
|
|
|
|
|
to slow it. The maximum rate aimed for is tunable via the |
426
|
|
|
|
|
|
|
L component. |
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
The available values for this are: |
429
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
=over 4 |
431
|
|
|
|
|
|
|
|
432
|
|
|
|
|
|
|
=item undef |
433
|
|
|
|
|
|
|
|
434
|
|
|
|
|
|
|
Do not do estimation. The default. |
435
|
|
|
|
|
|
|
|
436
|
|
|
|
|
|
|
=item linear |
437
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
Perform linear estimation. This is simply that the amount of time between the |
439
|
|
|
|
|
|
|
creation of the progress bar and now is divided by the current amount done, |
440
|
|
|
|
|
|
|
and completion estimated linearly. |
441
|
|
|
|
|
|
|
|
442
|
|
|
|
|
|
|
=back |
443
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
=back |
445
|
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
=item EXAMPLES |
447
|
|
|
|
|
|
|
|
448
|
|
|
|
|
|
|
my $progress = Term::ProgressBar->new(100); # count from 1 to 100 |
449
|
|
|
|
|
|
|
my $progress = Term::ProgressBar->new({ count => 100 }); # same |
450
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
# Count to 200 thingies, outputting to stdout instead of stderr, |
452
|
|
|
|
|
|
|
# prefix bar with 'thingy' |
453
|
|
|
|
|
|
|
my $progress = Term::ProgressBar->new({ count => 200, |
454
|
|
|
|
|
|
|
fh => \*STDOUT, |
455
|
|
|
|
|
|
|
name => 'thingy' }); |
456
|
|
|
|
|
|
|
|
457
|
|
|
|
|
|
|
=back |
458
|
|
|
|
|
|
|
|
459
|
|
|
|
|
|
|
=cut |
460
|
|
|
|
|
|
|
|
461
|
|
|
|
|
|
|
Class::MethodMaker->import (new_with_init => 'new', |
462
|
|
|
|
|
|
|
new_hash_init => 'hash_init',); |
463
|
|
|
|
|
|
|
|
464
|
|
|
|
|
|
|
sub init { |
465
|
26
|
|
|
26
|
0
|
43210
|
my $self = shift; |
466
|
|
|
|
|
|
|
|
467
|
|
|
|
|
|
|
# V1 Compatibility |
468
|
26
|
100
|
|
|
|
153
|
return $self->init({count => $_[1], name => $_[0], |
469
|
|
|
|
|
|
|
term_width => 50, bar_width => 50, |
470
|
|
|
|
|
|
|
major_char => '#', minor_char => '', |
471
|
|
|
|
|
|
|
lbrack => '', rbrack => '', |
472
|
|
|
|
|
|
|
term => '0 but true', |
473
|
|
|
|
|
|
|
silent => 0,}) |
474
|
|
|
|
|
|
|
if @_ == 2; |
475
|
|
|
|
|
|
|
|
476
|
21
|
|
|
|
|
37
|
my $target; |
477
|
|
|
|
|
|
|
|
478
|
21
|
50
|
|
|
|
64
|
croak |
479
|
|
|
|
|
|
|
sprintf("Term::ProgressBar::new We don't handle this many arguments: %d", |
480
|
|
|
|
|
|
|
scalar @_) |
481
|
|
|
|
|
|
|
if @_ != 1; |
482
|
|
|
|
|
|
|
|
483
|
21
|
|
|
|
|
36
|
my %config; |
484
|
|
|
|
|
|
|
|
485
|
21
|
100
|
|
|
|
95
|
if ( UNIVERSAL::isa ($_[0], 'HASH') ) { |
486
|
15
|
|
|
|
|
27
|
($target) = @{$_[0]}{qw(count)}; |
|
15
|
|
|
|
|
36
|
|
487
|
15
|
|
|
|
|
26
|
%config = %{$_[0]}; # Copy in, so later playing does not tinker externally |
|
15
|
|
|
|
|
70
|
|
488
|
|
|
|
|
|
|
} else { |
489
|
6
|
|
|
|
|
14
|
($target) = @_; |
490
|
|
|
|
|
|
|
} |
491
|
|
|
|
|
|
|
|
492
|
21
|
50
|
|
|
|
133
|
if ( my @bad = grep ! exists DEFAULTS->{$_}, keys %config ) { |
493
|
0
|
|
|
|
|
0
|
croak sprintf("Input parameters (%s) to %s not recognized\n", |
494
|
|
|
|
|
|
|
join(':', @bad), 'Term::ProgressBar::new'); |
495
|
|
|
|
|
|
|
} |
496
|
|
|
|
|
|
|
|
497
|
21
|
50
|
|
|
|
67
|
croak "Target count required for Term::ProgressBar new\n" |
498
|
|
|
|
|
|
|
unless defined $target; |
499
|
|
|
|
|
|
|
|
500
|
|
|
|
|
|
|
$config{$_} = DEFAULTS->{$_} |
501
|
21
|
|
|
|
|
45
|
for grep ! exists $config{$_}, keys %{DEFAULTS()}; |
|
21
|
|
|
|
|
324
|
|
502
|
21
|
|
|
|
|
62
|
delete $config{count}; |
503
|
|
|
|
|
|
|
|
504
|
|
|
|
|
|
|
$config{term} = -t $config{fh} |
505
|
21
|
100
|
|
|
|
173
|
unless defined $config{term}; |
506
|
|
|
|
|
|
|
|
507
|
21
|
100
|
66
|
|
|
93
|
if ( $__FORCE_TERM ) { |
|
|
50
|
|
|
|
|
|
508
|
16
|
|
|
|
|
32
|
$config{term} = 1; |
509
|
16
|
|
|
|
|
27
|
$config{term_width} = $__FORCE_TERM; |
510
|
|
|
|
|
|
|
die "term width $config{term_width} (from __force_term) too small" |
511
|
16
|
50
|
|
|
|
52
|
if $config{term_width} < 5; |
512
|
|
|
|
|
|
|
} elsif ( $config{term} and ! defined $config{term_width}) { |
513
|
0
|
|
|
|
|
0
|
$config{term_width} = $self->term_size($config{fh}); |
514
|
0
|
0
|
|
|
|
0
|
die if $config{term_width} < 5; |
515
|
|
|
|
|
|
|
} |
516
|
|
|
|
|
|
|
|
517
|
21
|
100
|
|
|
|
82
|
unless ( defined $config{bar_width} ) { |
518
|
16
|
100
|
|
|
|
44
|
if ( defined $config{term_width} ) { |
519
|
|
|
|
|
|
|
# 5 for the % marker |
520
|
12
|
|
|
|
|
32
|
$config{bar_width} = $config{term_width} - 5; |
521
|
|
|
|
|
|
|
$config{bar_width} -= $_ |
522
|
12
|
100
|
|
|
|
111
|
for map(( defined $config{$_} ? length($config{$_}) : 0), |
523
|
|
|
|
|
|
|
qw( lbrack rbrack name )); |
524
|
|
|
|
|
|
|
$config{bar_width} -= 2 # Extra for ': ' |
525
|
12
|
100
|
|
|
|
46
|
if defined $config{name}; |
526
|
|
|
|
|
|
|
$config{bar_width} -= 10 |
527
|
12
|
100
|
|
|
|
32
|
if defined $config{ETA}; |
528
|
12
|
50
|
|
|
|
35
|
if ( $config{bar_width} < 1 ) { |
529
|
0
|
|
|
|
|
0
|
warn "terminal width $config{term_width} too small for bar; defaulting to 10\n"; |
530
|
0
|
|
|
|
|
0
|
$config{bar_width} = 10; |
531
|
|
|
|
|
|
|
} |
532
|
|
|
|
|
|
|
# } elsif ( ! $config{term} ) { |
533
|
|
|
|
|
|
|
# $config{bar_width} = 1; |
534
|
|
|
|
|
|
|
# $config{term_width} = defined $config{ETA} ? 12 : 5; |
535
|
|
|
|
|
|
|
} else { |
536
|
4
|
|
|
|
|
6
|
$config{bar_width} = $target; |
537
|
|
|
|
|
|
|
die "configured bar_width $config{bar_width} < 1" |
538
|
4
|
50
|
|
|
|
9
|
if $config{bar_width} < 1; |
539
|
|
|
|
|
|
|
} |
540
|
|
|
|
|
|
|
} |
541
|
|
|
|
|
|
|
|
542
|
21
|
|
|
|
|
103
|
$config{start} = time; |
543
|
|
|
|
|
|
|
|
544
|
21
|
|
|
|
|
166
|
select(((select $config{fh}), $| = 1)[0]); |
545
|
|
|
|
|
|
|
|
546
|
21
|
|
|
|
|
108
|
$self->ETA(delete $config{ETA}); |
547
|
|
|
|
|
|
|
|
548
|
21
|
|
|
|
|
541
|
$self->hash_init (%config, |
549
|
|
|
|
|
|
|
|
550
|
|
|
|
|
|
|
offset => 0, |
551
|
|
|
|
|
|
|
scale => 1, |
552
|
|
|
|
|
|
|
|
553
|
|
|
|
|
|
|
last_update => 0, |
554
|
|
|
|
|
|
|
last_position => 0, |
555
|
|
|
|
|
|
|
); |
556
|
21
|
|
|
|
|
8411
|
$self->target($target); |
557
|
21
|
|
100
|
|
|
608
|
$self->minor($config{term} && $target > $config{bar_width} ** 1.5); |
558
|
|
|
|
|
|
|
|
559
|
21
|
|
|
|
|
271
|
$self->update(0); # Initialize the progress bar |
560
|
|
|
|
|
|
|
} |
561
|
|
|
|
|
|
|
|
562
|
|
|
|
|
|
|
|
563
|
|
|
|
|
|
|
# ---------------------------------- |
564
|
|
|
|
|
|
|
# INSTANCE FINALIZATION |
565
|
|
|
|
|
|
|
# ---------------------------------- |
566
|
|
|
|
|
|
|
|
567
|
|
|
|
|
|
|
# ---------------------------------- |
568
|
|
|
|
|
|
|
# INSTANCE COMPONENTS |
569
|
|
|
|
|
|
|
# ---------------------------------- |
570
|
|
|
|
|
|
|
|
571
|
|
|
|
|
|
|
=head1 INSTANCE COMPONENTS |
572
|
|
|
|
|
|
|
|
573
|
|
|
|
|
|
|
=cut |
574
|
|
|
|
|
|
|
|
575
|
|
|
|
|
|
|
=head2 Scalar Components. |
576
|
|
|
|
|
|
|
|
577
|
|
|
|
|
|
|
See L for usage. |
578
|
|
|
|
|
|
|
|
579
|
|
|
|
|
|
|
=over 4 |
580
|
|
|
|
|
|
|
|
581
|
|
|
|
|
|
|
=item target |
582
|
|
|
|
|
|
|
|
583
|
|
|
|
|
|
|
The final target. Updates are measured in terms of this. Changes will have |
584
|
|
|
|
|
|
|
no effect until the next update, but the next update value should be relative |
585
|
|
|
|
|
|
|
to the new target. So |
586
|
|
|
|
|
|
|
|
587
|
|
|
|
|
|
|
$p = Term::ProgressBar({count => 20}); |
588
|
|
|
|
|
|
|
# Halfway |
589
|
|
|
|
|
|
|
$p->update(10); |
590
|
|
|
|
|
|
|
# Double scale |
591
|
|
|
|
|
|
|
$p->target(40) |
592
|
|
|
|
|
|
|
$p->update(21); |
593
|
|
|
|
|
|
|
|
594
|
|
|
|
|
|
|
will cause the progress bar to update to 52.5% |
595
|
|
|
|
|
|
|
|
596
|
|
|
|
|
|
|
=item max_update_rate |
597
|
|
|
|
|
|
|
|
598
|
|
|
|
|
|
|
This value is taken as being the maximum speed between updates to aim for. |
599
|
|
|
|
|
|
|
B It defaults to 0.5, being the |
600
|
|
|
|
|
|
|
number of seconds between updates. |
601
|
|
|
|
|
|
|
|
602
|
|
|
|
|
|
|
=back |
603
|
|
|
|
|
|
|
|
604
|
|
|
|
|
|
|
=head2 Boolean Components |
605
|
|
|
|
|
|
|
|
606
|
|
|
|
|
|
|
See L for usage. |
607
|
|
|
|
|
|
|
|
608
|
|
|
|
|
|
|
=over 4 |
609
|
|
|
|
|
|
|
|
610
|
|
|
|
|
|
|
=item minor |
611
|
|
|
|
|
|
|
|
612
|
|
|
|
|
|
|
Default: set. If unset, no minor scale will be calculated or updated. |
613
|
|
|
|
|
|
|
|
614
|
|
|
|
|
|
|
Minor characters are used on the progress bar to give the user the idea of |
615
|
|
|
|
|
|
|
progress even when there are so many more tasks than the terminal is wide that |
616
|
|
|
|
|
|
|
the granularity would be too great. By default, Term::ProgressBar makes a |
617
|
|
|
|
|
|
|
guess as to when minor characters would be valuable. However, it may not |
618
|
|
|
|
|
|
|
always guess right, so this method may be called to force it one way or the |
619
|
|
|
|
|
|
|
other. Of course, the efficiency saving is minimal unless the client is |
620
|
|
|
|
|
|
|
utilizing the return value of L. |
621
|
|
|
|
|
|
|
|
622
|
|
|
|
|
|
|
See F and F to see minor characters in |
623
|
|
|
|
|
|
|
action, and not in action, respectively. |
624
|
|
|
|
|
|
|
|
625
|
|
|
|
|
|
|
=back |
626
|
|
|
|
|
|
|
|
627
|
|
|
|
|
|
|
=head2 Configuration |
628
|
|
|
|
|
|
|
|
629
|
|
|
|
|
|
|
=over 4 |
630
|
|
|
|
|
|
|
|
631
|
|
|
|
|
|
|
=item lbrack |
632
|
|
|
|
|
|
|
|
633
|
|
|
|
|
|
|
Left bracket ( defaults to [ ) |
634
|
|
|
|
|
|
|
|
635
|
|
|
|
|
|
|
$progress->lbrack('<'); |
636
|
|
|
|
|
|
|
|
637
|
|
|
|
|
|
|
=item rbrack |
638
|
|
|
|
|
|
|
|
639
|
|
|
|
|
|
|
Right bracket ( defaults to ] ) |
640
|
|
|
|
|
|
|
|
641
|
|
|
|
|
|
|
$progress->rbrack('>'); |
642
|
|
|
|
|
|
|
|
643
|
|
|
|
|
|
|
=back |
644
|
|
|
|
|
|
|
|
645
|
|
|
|
|
|
|
=cut |
646
|
|
|
|
|
|
|
|
647
|
|
|
|
|
|
|
# Private Scalar Components |
648
|
|
|
|
|
|
|
# offset ) Default: 0. Added to any value supplied to update. |
649
|
|
|
|
|
|
|
# scale ) Default: 1. Any value supplied to update is multiplied by |
650
|
|
|
|
|
|
|
# this. |
651
|
|
|
|
|
|
|
# major_char) Default: '='. The character printed for the major scale. |
652
|
|
|
|
|
|
|
# minor_char) Default: '*'. The character printed for the minor scale. |
653
|
|
|
|
|
|
|
# name ) Default: undef. The name to print to the side of the bar. |
654
|
|
|
|
|
|
|
# fh ) Default: STDERR. The filehandle to output progress to. |
655
|
|
|
|
|
|
|
|
656
|
|
|
|
|
|
|
# Private Counter Components |
657
|
|
|
|
|
|
|
# last_update ) Default: 0. The so_far value last time update was invoked. |
658
|
|
|
|
|
|
|
# last_position) Default: 0. The number of the last progress mark printed. |
659
|
|
|
|
|
|
|
|
660
|
|
|
|
|
|
|
# Private Boolean Components |
661
|
|
|
|
|
|
|
# term ) Default: detected (by C). |
662
|
|
|
|
|
|
|
# If unset, we assume that we are not connected to a terminal (or |
663
|
|
|
|
|
|
|
# at least, not a suitably intelligent one). Then, we attempt |
664
|
|
|
|
|
|
|
# minimal functionality. |
665
|
|
|
|
|
|
|
|
666
|
|
|
|
|
|
|
Class::MethodMaker->import |
667
|
|
|
|
|
|
|
( |
668
|
|
|
|
|
|
|
get_set => [qw/ major_units major_char |
669
|
|
|
|
|
|
|
minor_units minor_char |
670
|
|
|
|
|
|
|
lbrack rbrack |
671
|
|
|
|
|
|
|
name |
672
|
|
|
|
|
|
|
offset scale |
673
|
|
|
|
|
|
|
fh start |
674
|
|
|
|
|
|
|
max_update_rate |
675
|
|
|
|
|
|
|
silent |
676
|
|
|
|
|
|
|
/], |
677
|
|
|
|
|
|
|
counter => [qw/ last_position last_update /], |
678
|
|
|
|
|
|
|
boolean => [qw/ minor name_printed pb_ended remove /], |
679
|
|
|
|
|
|
|
# let it be boolean to handle 0 but true |
680
|
|
|
|
|
|
|
get_set => [qw/ term /], |
681
|
|
|
|
|
|
|
); |
682
|
|
|
|
|
|
|
|
683
|
|
|
|
|
|
|
# We generate these by hand since we want to check the values. |
684
|
|
|
|
|
|
|
sub bar_width { |
685
|
1006
|
|
|
1006
|
0
|
12469
|
my $self = shift; |
686
|
1006
|
100
|
|
|
|
4693
|
return $self->{bar_width} if not @_; |
687
|
21
|
50
|
|
|
|
73
|
croak 'wrong number of arguments' if @_ != 1; |
688
|
21
|
50
|
|
|
|
79
|
croak 'bar_width < 1' if $_[0] < 1; |
689
|
21
|
|
|
|
|
430
|
$self->{bar_width} = $_[0]; |
690
|
|
|
|
|
|
|
} |
691
|
|
|
|
|
|
|
sub term_width { |
692
|
167
|
|
|
167
|
1
|
9093
|
my $self = shift; |
693
|
167
|
100
|
|
|
|
2423
|
return $self->{term_width} if not @_; |
694
|
21
|
50
|
|
|
|
58
|
croak 'wrong number of arguments' if @_ != 1; |
695
|
21
|
50
|
66
|
|
|
429
|
croak 'term_width must be at least 5' if $self->term and $_[0] < 5; |
696
|
21
|
|
|
|
|
687
|
$self->{term_width} = $_[0]; |
697
|
|
|
|
|
|
|
} |
698
|
|
|
|
|
|
|
|
699
|
|
|
|
|
|
|
sub target { |
700
|
599
|
|
|
599
|
1
|
3763
|
my $self = shift; |
701
|
|
|
|
|
|
|
|
702
|
599
|
100
|
|
|
|
995
|
if ( @_ ) { |
703
|
22
|
|
|
|
|
45
|
my ($target) = @_; |
704
|
|
|
|
|
|
|
|
705
|
22
|
100
|
|
|
|
69
|
if ( $target ) { |
706
|
20
|
|
|
|
|
51
|
$self->major_units($self->bar_width / $target); |
707
|
20
|
|
|
|
|
211
|
$self->minor_units($self->bar_width ** 2 / $target); |
708
|
20
|
|
100
|
|
|
227
|
$self->minor ( defined $self->term_width and |
709
|
|
|
|
|
|
|
$self->term_width < $target ); |
710
|
|
|
|
|
|
|
} |
711
|
22
|
|
|
|
|
286
|
$self->{target} = $target; |
712
|
|
|
|
|
|
|
} |
713
|
|
|
|
|
|
|
|
714
|
599
|
|
|
|
|
1060
|
return $self->{target}; |
715
|
|
|
|
|
|
|
} |
716
|
|
|
|
|
|
|
|
717
|
|
|
|
|
|
|
sub ETA { |
718
|
331
|
|
|
331
|
1
|
436
|
my $self = shift; |
719
|
331
|
50
|
|
|
|
6460
|
return if $self->silent; |
720
|
331
|
100
|
|
|
|
2953
|
if (@_) { |
721
|
21
|
|
|
|
|
48
|
my ($type) = @_; |
722
|
|
|
|
|
|
|
croak "Invalid ETA type: $type\n" |
723
|
21
|
50
|
66
|
|
|
94
|
if defined $type and ! exists ETA_TYPES->{$type}; |
724
|
21
|
|
|
|
|
51
|
$self->{ETA} = $type; |
725
|
|
|
|
|
|
|
} |
726
|
|
|
|
|
|
|
|
727
|
331
|
|
|
|
|
497
|
return $self->{ETA}; |
728
|
|
|
|
|
|
|
} |
729
|
|
|
|
|
|
|
|
730
|
|
|
|
|
|
|
# ---------------------------------- |
731
|
|
|
|
|
|
|
# INSTANCE HIGHER-LEVEL FUNCTIONS |
732
|
|
|
|
|
|
|
# ---------------------------------- |
733
|
|
|
|
|
|
|
|
734
|
|
|
|
|
|
|
# ---------------------------------- |
735
|
|
|
|
|
|
|
# INSTANCE HIGHER-LEVEL PROCEDURES |
736
|
|
|
|
|
|
|
# ---------------------------------- |
737
|
|
|
|
|
|
|
|
738
|
|
|
|
|
|
|
=head1 INSTANCE HIGHER-LEVEL PROCEDURES |
739
|
|
|
|
|
|
|
|
740
|
|
|
|
|
|
|
Z<> |
741
|
|
|
|
|
|
|
|
742
|
|
|
|
|
|
|
=cut |
743
|
|
|
|
|
|
|
|
744
|
|
|
|
|
|
|
sub no_minor { |
745
|
0
|
|
|
0
|
0
|
0
|
warn sprintf("%s: This method is deprecated. Please use %s instead\n", |
746
|
|
|
|
|
|
|
(caller (0))[3], '$x->minor (0)',); |
747
|
0
|
|
|
|
|
0
|
$_[0]->clear_minor (0); |
748
|
|
|
|
|
|
|
} |
749
|
|
|
|
|
|
|
|
750
|
|
|
|
|
|
|
# ------------------------------------- |
751
|
|
|
|
|
|
|
|
752
|
|
|
|
|
|
|
=head2 update |
753
|
|
|
|
|
|
|
|
754
|
|
|
|
|
|
|
Update the progress bar. |
755
|
|
|
|
|
|
|
|
756
|
|
|
|
|
|
|
=over 4 |
757
|
|
|
|
|
|
|
|
758
|
|
|
|
|
|
|
=item ARGUMENTS |
759
|
|
|
|
|
|
|
|
760
|
|
|
|
|
|
|
=over 4 |
761
|
|
|
|
|
|
|
|
762
|
|
|
|
|
|
|
=item so_far |
763
|
|
|
|
|
|
|
|
764
|
|
|
|
|
|
|
Current progress point, in whatever units were passed to C. |
765
|
|
|
|
|
|
|
|
766
|
|
|
|
|
|
|
If not defined, assumed to be 1+ whatever was the value last time C |
767
|
|
|
|
|
|
|
was called (starting at 0). |
768
|
|
|
|
|
|
|
|
769
|
|
|
|
|
|
|
=back |
770
|
|
|
|
|
|
|
|
771
|
|
|
|
|
|
|
=item RETURNS |
772
|
|
|
|
|
|
|
|
773
|
|
|
|
|
|
|
=over 4 |
774
|
|
|
|
|
|
|
|
775
|
|
|
|
|
|
|
=item next_call |
776
|
|
|
|
|
|
|
|
777
|
|
|
|
|
|
|
The next value of so_far at which to call C. |
778
|
|
|
|
|
|
|
|
779
|
|
|
|
|
|
|
=back |
780
|
|
|
|
|
|
|
|
781
|
|
|
|
|
|
|
=back |
782
|
|
|
|
|
|
|
|
783
|
|
|
|
|
|
|
=cut |
784
|
|
|
|
|
|
|
|
785
|
|
|
|
|
|
|
sub update { |
786
|
575
|
|
|
575
|
1
|
8024470
|
my $self = shift; |
787
|
|
|
|
|
|
|
# returning target+1 as next value should avoid calling update |
788
|
|
|
|
|
|
|
# method in the smooth form of using the progress bar |
789
|
575
|
100
|
|
|
|
11331
|
return $self->target+1 if $self->silent; |
790
|
|
|
|
|
|
|
|
791
|
460
|
|
|
|
|
4141
|
my ($so_far) = @_; |
792
|
|
|
|
|
|
|
|
793
|
460
|
100
|
|
|
|
764
|
if ( ! defined $so_far ) { |
794
|
101
|
|
|
|
|
1802
|
$so_far = $self->last_update + 1; |
795
|
|
|
|
|
|
|
} |
796
|
|
|
|
|
|
|
|
797
|
460
|
|
|
|
|
3476
|
my $input_so_far = $so_far; |
798
|
460
|
50
|
|
|
|
8393
|
$so_far *= $self->scale |
799
|
|
|
|
|
|
|
unless $self->scale == 1; |
800
|
460
|
|
|
|
|
11704
|
$so_far += $self->offset; |
801
|
|
|
|
|
|
|
|
802
|
460
|
|
|
|
|
3643
|
my $target = my $next = $self->target; |
803
|
460
|
|
|
|
|
8394
|
my $name = $self->name; |
804
|
460
|
|
|
|
|
11489
|
my $fh = $self->fh; |
805
|
|
|
|
|
|
|
|
806
|
|
|
|
|
|
|
|
807
|
460
|
100
|
|
|
|
3838
|
if ( $target < 0 ) { |
|
|
100
|
|
|
|
|
|
808
|
24
|
100
|
66
|
|
|
376
|
if($input_so_far <= 0 or $input_so_far == $self->last_update) { |
809
|
4
|
|
|
|
|
21
|
print $fh "\r", ' ' x $self->term_width, "\r"; |
810
|
|
|
|
|
|
|
|
811
|
4
|
50
|
|
|
|
18
|
if(defined $name) { |
812
|
4
|
100
|
100
|
|
|
106
|
if(!$self->remove or $input_so_far >= 0) { |
813
|
3
|
|
|
|
|
69
|
print $fh "$name..."; |
814
|
|
|
|
|
|
|
} |
815
|
4
|
50
|
66
|
|
|
100
|
if(!$self->remove and $input_so_far < 0) { |
816
|
0
|
|
|
|
|
0
|
print $fh "\n"; |
817
|
|
|
|
|
|
|
} |
818
|
|
|
|
|
|
|
} |
819
|
|
|
|
|
|
|
} |
820
|
24
|
|
|
|
|
1061
|
$self->last_update($input_so_far); |
821
|
24
|
|
|
|
|
1502
|
return 2**32-1; |
822
|
|
|
|
|
|
|
} elsif ( $target == 0 ) { |
823
|
22
|
|
|
|
|
319
|
print $fh "\r"; |
824
|
22
|
50
|
|
|
|
270
|
printf $fh "$name: " |
825
|
|
|
|
|
|
|
if defined $name; |
826
|
22
|
|
|
|
|
206
|
print $fh "(nothing to do)\n"; |
827
|
22
|
|
|
|
|
133
|
return 2**32-1; |
828
|
|
|
|
|
|
|
} |
829
|
|
|
|
|
|
|
|
830
|
414
|
|
|
|
|
871
|
my @chars = (' ') x $self->bar_width; |
831
|
414
|
100
|
|
|
|
777
|
if ( $so_far >= $target ) { |
832
|
12
|
|
|
|
|
246
|
@chars = ($self->major_char) x $self->bar_width; |
833
|
|
|
|
|
|
|
} |
834
|
|
|
|
|
|
|
else { |
835
|
402
|
|
|
|
|
7594
|
my $biggies = $self->major_units * $so_far; |
836
|
|
|
|
|
|
|
$chars[$_] = $self->major_char |
837
|
402
|
|
|
|
|
10402
|
for 0..$biggies-1; |
838
|
|
|
|
|
|
|
} |
839
|
|
|
|
|
|
|
|
840
|
414
|
100
|
|
|
|
194632
|
if ( $self->minor ) { |
841
|
3
|
|
|
|
|
73
|
my $smally = $self->minor_units * $so_far % $self->bar_width; |
842
|
3
|
50
|
|
|
|
57
|
$chars[$smally] = $self->minor_char |
843
|
|
|
|
|
|
|
unless $so_far == $target; |
844
|
3
|
|
|
|
|
73
|
$next *= ($self->minor_units * $so_far + 1) / ($self->bar_width ** 2); |
845
|
|
|
|
|
|
|
} else { |
846
|
411
|
|
|
|
|
10372
|
$next *= ($self->major_units * $so_far + 1) / $self->bar_width; |
847
|
|
|
|
|
|
|
} |
848
|
|
|
|
|
|
|
|
849
|
414
|
|
|
|
|
1182
|
local $\ = undef; |
850
|
|
|
|
|
|
|
|
851
|
414
|
100
|
|
|
|
7962
|
if ( $self->term > 0 ) { |
852
|
310
|
|
|
|
|
2728
|
local $\ = undef; |
853
|
310
|
|
|
|
|
406
|
my $to_print = "\r"; |
854
|
310
|
100
|
|
|
|
561
|
$to_print .= "$name: " |
855
|
|
|
|
|
|
|
if defined $name; |
856
|
310
|
|
|
|
|
385
|
my $ratio = $so_far / $target; |
857
|
|
|
|
|
|
|
# Rounds down % |
858
|
310
|
|
|
|
|
5912
|
$to_print .= (sprintf ("%3d%% %s%s%s", |
859
|
|
|
|
|
|
|
$ratio * 100, |
860
|
|
|
|
|
|
|
$self->lbrack, join ('', @chars), $self->rbrack)); |
861
|
310
|
|
|
|
|
5561
|
my $ETA = $self->ETA; |
862
|
310
|
100
|
100
|
|
|
586
|
if ( defined $ETA and $ratio > 0 ) { |
863
|
11
|
50
|
|
|
|
36
|
if ( $ETA eq 'linear' ) { |
864
|
11
|
100
|
|
|
|
40
|
if ( $ratio == 1 ) { |
|
|
50
|
|
|
|
|
|
865
|
1
|
|
|
|
|
23
|
my $taken = time - $self->start; |
866
|
1
|
|
|
|
|
10
|
my $ss = $taken % 60; |
867
|
1
|
|
|
|
|
3
|
my $mm = int(($taken % 3600) / 60); |
868
|
1
|
|
|
|
|
3
|
my $hh = int($taken / 3600); |
869
|
1
|
50
|
|
|
|
4
|
if ( $hh > 99 ) { |
870
|
0
|
|
|
|
|
0
|
$to_print .= sprintf('D %2dh%02dm', $hh, $mm, $ss); |
871
|
|
|
|
|
|
|
} else { |
872
|
1
|
|
|
|
|
5
|
$to_print .= sprintf('D%2dh%02dm%02ds', $hh, $mm, $ss); |
873
|
|
|
|
|
|
|
} |
874
|
|
|
|
|
|
|
} elsif ( $ratio < PREDICT_RATIO ) { |
875
|
|
|
|
|
|
|
# No safe prediction yet |
876
|
0
|
|
|
|
|
0
|
$to_print .= 'ETA ------'; |
877
|
|
|
|
|
|
|
} else { |
878
|
10
|
|
|
|
|
22
|
my $time = time; |
879
|
10
|
|
|
|
|
210
|
my $left = (($time - $self->start) * ((1 - $ratio) / $ratio)); |
880
|
10
|
50
|
|
|
|
108
|
if ( $left < ETA_TIME_CUTOFF ) { |
881
|
10
|
|
|
|
|
46
|
$to_print .= sprintf '%1dm%02ds Left', int($left / 60), $left % 60; |
882
|
|
|
|
|
|
|
} else { |
883
|
0
|
|
|
|
|
0
|
my $eta = $time + $left; |
884
|
0
|
|
|
|
|
0
|
my $format; |
885
|
0
|
0
|
|
|
|
0
|
if ( $left < DAY ) { |
|
|
0
|
|
|
|
|
|
886
|
0
|
|
|
|
|
0
|
$format = 'ETA %H:%M'; |
887
|
|
|
|
|
|
|
} elsif ( $left < ETA_DATE_CUTOFF ) { |
888
|
0
|
|
|
|
|
0
|
$format = sprintf('ETA %%l%%p+%d',$left/DAY); |
889
|
|
|
|
|
|
|
} else { |
890
|
0
|
|
|
|
|
0
|
$format = 'ETA %e%b'; |
891
|
|
|
|
|
|
|
} |
892
|
0
|
|
|
|
|
0
|
$to_print .= strftime($format, localtime $eta); |
893
|
|
|
|
|
|
|
} |
894
|
|
|
|
|
|
|
# Calculate next to be at least SEC_PER_UPDATE seconds away |
895
|
10
|
100
|
|
|
|
29
|
if ( $left > 0 ) { |
896
|
9
|
|
|
|
|
257
|
my $incr = ($target - $so_far) / ($left / $self->max_update_rate); |
897
|
9
|
50
|
|
|
|
101
|
$next = $so_far + $incr |
898
|
|
|
|
|
|
|
if $so_far + $incr > $next; |
899
|
|
|
|
|
|
|
} |
900
|
|
|
|
|
|
|
} |
901
|
|
|
|
|
|
|
} else { |
902
|
0
|
|
|
|
|
0
|
croak "Bad ETA type: $ETA\n"; |
903
|
|
|
|
|
|
|
} |
904
|
|
|
|
|
|
|
} |
905
|
310
|
|
|
|
|
516
|
for ($self->{last_printed}) { |
906
|
310
|
100
|
100
|
|
|
899
|
unless (defined and $_ eq $to_print) { |
907
|
305
|
|
|
|
|
5448
|
print $fh $to_print; |
908
|
|
|
|
|
|
|
} |
909
|
310
|
|
|
|
|
1043
|
$_ = $to_print; |
910
|
|
|
|
|
|
|
} |
911
|
|
|
|
|
|
|
|
912
|
310
|
|
|
|
|
7844
|
$next -= $self->offset; |
913
|
310
|
50
|
|
|
|
8290
|
$next /= $self->scale |
914
|
|
|
|
|
|
|
unless $self->scale == 1; |
915
|
|
|
|
|
|
|
|
916
|
310
|
50
|
66
|
|
|
3288
|
if ( $so_far >= $target and $self->remove and ! $self->pb_ended) { |
|
|
|
33
|
|
|
|
|
917
|
0
|
|
|
|
|
0
|
print $fh "\r", ' ' x $self->term_width, "\r"; |
918
|
0
|
|
|
|
|
0
|
$self->pb_ended; |
919
|
|
|
|
|
|
|
} |
920
|
|
|
|
|
|
|
|
921
|
|
|
|
|
|
|
} else { |
922
|
104
|
|
|
|
|
957
|
local $\ = undef; |
923
|
|
|
|
|
|
|
|
924
|
104
|
100
|
|
|
|
1860
|
if ( $self->term ) { # special case for backwards compat. |
925
|
102
|
50
|
66
|
|
|
832
|
if ( $so_far == 0 and defined $name and ! $self->name_printed ) { |
|
|
|
66
|
|
|
|
|
926
|
1
|
|
|
|
|
61
|
print $fh "$name: "; |
927
|
1
|
|
|
|
|
29
|
$self->set_name_printed; |
928
|
|
|
|
|
|
|
} |
929
|
|
|
|
|
|
|
|
930
|
102
|
|
|
|
|
182
|
my $position = int($self->bar_width * ($input_so_far / $target)); |
931
|
102
|
|
|
|
|
1918
|
my $add = $position - $self->last_position; |
932
|
102
|
100
|
|
|
|
4062
|
$self->last_position_incr ($add) |
933
|
|
|
|
|
|
|
if $add; |
934
|
|
|
|
|
|
|
|
935
|
102
|
|
|
|
|
6381
|
print $fh $self->major_char x $add; |
936
|
|
|
|
|
|
|
|
937
|
102
|
|
|
|
|
3738
|
$next -= $self->offset; |
938
|
102
|
50
|
|
|
|
2597
|
$next /= $self->scale |
939
|
|
|
|
|
|
|
unless $self->scale == 1; |
940
|
|
|
|
|
|
|
} else { |
941
|
2
|
|
|
|
|
19
|
my $pc = int(100*$input_so_far/$target); |
942
|
2
|
|
50
|
|
|
151
|
printf $fh "[%s] %s: %3d%%\n", scalar(localtime), ($name || ''), $pc; |
943
|
|
|
|
|
|
|
|
944
|
2
|
|
|
|
|
17
|
$next = ceil($target * ($pc+1)/100); |
945
|
|
|
|
|
|
|
} |
946
|
|
|
|
|
|
|
|
947
|
104
|
100
|
|
|
|
950
|
if ( $input_so_far >= $target ) { |
948
|
2
|
100
|
|
|
|
40
|
if ( $self->pb_ended ) { |
949
|
1
|
|
|
|
|
163
|
croak ALREADY_FINISHED; |
950
|
|
|
|
|
|
|
} else { |
951
|
1
|
50
|
|
|
|
31
|
if ( $self->term ) { |
952
|
1
|
|
|
|
|
21
|
print $fh "\n" |
953
|
|
|
|
|
|
|
} |
954
|
1
|
|
|
|
|
27
|
$self->set_pb_ended; |
955
|
|
|
|
|
|
|
} |
956
|
|
|
|
|
|
|
} |
957
|
|
|
|
|
|
|
} |
958
|
|
|
|
|
|
|
|
959
|
|
|
|
|
|
|
|
960
|
413
|
100
|
|
|
|
844
|
$next = $target if $next > $target; |
961
|
|
|
|
|
|
|
|
962
|
413
|
|
|
|
|
8005
|
$self->last_update($input_so_far); |
963
|
413
|
|
|
|
|
27084
|
return $next; |
964
|
|
|
|
|
|
|
} |
965
|
|
|
|
|
|
|
|
966
|
|
|
|
|
|
|
# ------------------------------------- |
967
|
|
|
|
|
|
|
|
968
|
|
|
|
|
|
|
=head2 message |
969
|
|
|
|
|
|
|
|
970
|
|
|
|
|
|
|
Output a message. This is very much like print, but we try not to disturb the |
971
|
|
|
|
|
|
|
terminal. |
972
|
|
|
|
|
|
|
|
973
|
|
|
|
|
|
|
=over 4 |
974
|
|
|
|
|
|
|
|
975
|
|
|
|
|
|
|
=item ARGUMENTS |
976
|
|
|
|
|
|
|
|
977
|
|
|
|
|
|
|
=over 4 |
978
|
|
|
|
|
|
|
|
979
|
|
|
|
|
|
|
=item string |
980
|
|
|
|
|
|
|
|
981
|
|
|
|
|
|
|
The message to output. |
982
|
|
|
|
|
|
|
|
983
|
|
|
|
|
|
|
=back |
984
|
|
|
|
|
|
|
|
985
|
|
|
|
|
|
|
=back |
986
|
|
|
|
|
|
|
|
987
|
|
|
|
|
|
|
=cut |
988
|
|
|
|
|
|
|
|
989
|
|
|
|
|
|
|
sub message { |
990
|
209
|
|
|
209
|
1
|
1008417
|
my $self = shift; |
991
|
209
|
100
|
|
|
|
3864
|
return if $self->silent; |
992
|
106
|
|
|
|
|
976
|
my ($string) = @_; |
993
|
106
|
|
|
|
|
157
|
chomp ($string); |
994
|
|
|
|
|
|
|
|
995
|
106
|
|
|
|
|
1957
|
my $fh = $self->fh; |
996
|
106
|
|
|
|
|
901
|
local $\ = undef; |
997
|
106
|
50
|
|
|
|
1933
|
if ( $self->term ) { |
998
|
106
|
|
|
|
|
949
|
print $fh "\r", ' ' x $self->term_width; |
999
|
106
|
|
|
|
|
1129
|
print $fh "\r$string\n"; |
1000
|
|
|
|
|
|
|
} else { |
1001
|
0
|
|
|
|
|
0
|
print $fh "\n$string\n"; |
1002
|
0
|
|
|
|
|
0
|
print $fh $self->major_char x $self->last_position; |
1003
|
|
|
|
|
|
|
} |
1004
|
106
|
|
|
|
|
339
|
undef $self->{last_printed}; |
1005
|
106
|
|
|
|
|
2613
|
$self->update($self->last_update); |
1006
|
|
|
|
|
|
|
} |
1007
|
|
|
|
|
|
|
|
1008
|
|
|
|
|
|
|
|
1009
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
1010
|
|
|
|
|
|
|
|
1011
|
|
|
|
|
|
|
=head1 REPORTING BUGS |
1012
|
|
|
|
|
|
|
|
1013
|
|
|
|
|
|
|
via RT: L |
1014
|
|
|
|
|
|
|
|
1015
|
|
|
|
|
|
|
=head1 COMPATIBILITY |
1016
|
|
|
|
|
|
|
|
1017
|
|
|
|
|
|
|
If exactly two arguments are provided, then L operates in v1 |
1018
|
|
|
|
|
|
|
compatibility mode: the arguments are considered to be name, and item count. |
1019
|
|
|
|
|
|
|
Various other defaults are set to emulate version one (e.g., the major output |
1020
|
|
|
|
|
|
|
character is '#', the bar width is set to 50 characters and the output |
1021
|
|
|
|
|
|
|
filehandle is not treated as a terminal). This mode is deprecated. |
1022
|
|
|
|
|
|
|
|
1023
|
|
|
|
|
|
|
=head1 AUTHOR |
1024
|
|
|
|
|
|
|
|
1025
|
|
|
|
|
|
|
Martyn J. Pearce fluffy@cpan.org |
1026
|
|
|
|
|
|
|
|
1027
|
|
|
|
|
|
|
Significant contributions from Ed Avis, amongst others. |
1028
|
|
|
|
|
|
|
|
1029
|
|
|
|
|
|
|
=head1 MAINTAINER |
1030
|
|
|
|
|
|
|
|
1031
|
|
|
|
|
|
|
Gabor Szabo L L |
1032
|
|
|
|
|
|
|
|
1033
|
|
|
|
|
|
|
=head1 LICENSE AND COPYRIGHT |
1034
|
|
|
|
|
|
|
|
1035
|
|
|
|
|
|
|
Copyright (c) 2001, 2002, 2003, 2004, 2005 Martyn J. Pearce. This program is |
1036
|
|
|
|
|
|
|
free software; you can redistribute it and/or modify it under the same terms |
1037
|
|
|
|
|
|
|
as Perl itself. |
1038
|
|
|
|
|
|
|
|
1039
|
|
|
|
|
|
|
=cut |
1040
|
|
|
|
|
|
|
|
1041
|
|
|
|
|
|
|
1; |
1042
|
|
|
|
|
|
|
|
1043
|
|
|
|
|
|
|
__END__ |