line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Text::HistogramChart;
|
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
## no critic (Subroutines::RequireArgUnpacking)
|
4
|
|
|
|
|
|
|
## no critic (RequirePodAtEnd)
|
5
|
|
|
|
|
|
|
# By using =encoding utf8 this module would require perl 5.10. No need for that!
|
6
|
|
|
|
|
|
|
## no critic (Documentation::RequirePODUseEncodingUTF8 )
|
7
|
|
|
|
|
|
|
|
8
|
1
|
|
|
1
|
|
24318
|
use 5.008_001;
|
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
41
|
|
9
|
1
|
|
|
1
|
|
5
|
use strict;
|
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
28
|
|
10
|
1
|
|
|
1
|
|
6
|
use warnings;
|
|
1
|
|
|
|
|
5
|
|
|
1
|
|
|
|
|
79
|
|
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
=head1 NAME
|
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
Text::HistogramChart - Make Text Histogram (Upright Bars) Charts
|
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
=head1 VERSION
|
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
Version 0.005
|
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
=cut
|
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
#use version 0.77 (); our $VERSION = 0.003; # Require version 0.77 of module "version". Even for Perl v.5.10.0, get latest bug-fixes and API
|
24
|
|
|
|
|
|
|
our $VERSION = 0.005;
|
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
=head1 SYNOPSIS
|
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
Text::HistogramChart creates graphical charts for terminal displays or any other display device where bitmap graphics is not available!
|
30
|
|
|
|
|
|
|
You can supply the Y axel legend (vertical) values or Text::HistogramChart can calculate them from the input values.
|
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
require Text::HistogramChart;
|
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
my $chart = Text::HistogramChart->new();
|
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
@values = (1, 2, 3, 4, 5, 4, 3, 2, 1, 0, -1, -2, -3, -4, -5, -4, -3, -2, -1, 0);
|
37
|
|
|
|
|
|
|
@legend_values = (4, 3, 2, 1, 0, -1, -2, -3, -4);
|
38
|
|
|
|
|
|
|
$chart->{'values'} = \@values;
|
39
|
|
|
|
|
|
|
$chart->{'legend_values'} = \@legend_values;
|
40
|
|
|
|
|
|
|
$chart->{'screen_height'} = 9; # (height reserved for the graph.)
|
41
|
|
|
|
|
|
|
$chart->{'roof_value'} = 0; # (active if != 0), # Arbitrarily squeeze or extend the size (height) of bars (not screen)
|
42
|
|
|
|
|
|
|
$chart->{'floor_value'} = 0; # (the "floor" of the chart, default: 0)
|
43
|
|
|
|
|
|
|
$chart->{'write_floor'} = 1; # (make floor visible)
|
44
|
|
|
|
|
|
|
$chart->{'use_floor'} = 1; # (use the floor value)
|
45
|
|
|
|
|
|
|
$chart->{'write_floor_value'} = 1; # If value == floor_value, then write value (mostly "0").
|
46
|
|
|
|
|
|
|
$chart->{'write_legend'} = 1; # (Prepend legend to each row.)
|
47
|
|
|
|
|
|
|
$chart->{'legend_horizontal_width'} = 4; # width of the space left for legend (left edge of chart)
|
48
|
|
|
|
|
|
|
$chart->{'horizontal_width'} = 2; # Horizontal width of one bar. This parameter directly influences the width of the screen (i.e. chart).
|
49
|
|
|
|
|
|
|
$chart->{'write_value'} = 1; # (YES = 1, NO = 0, default: no; write the value on the end of the bar),
|
50
|
|
|
|
|
|
|
$chart->{'write_always_over_value'} = 0; # (YES = 1, NO = 0, default: yes; write the value only if it is too high for the graph),
|
51
|
|
|
|
|
|
|
$chart->{'write_always_under_value'} = 0; # (YES = 1, NO = 0, default: yes; write the value only if it is too low for the graph),
|
52
|
|
|
|
|
|
|
$chart->{'bar_char'} = '|'; # (default: '|')
|
53
|
|
|
|
|
|
|
$chart->{'floor_char'} = '-'; # (default '-' )
|
54
|
|
|
|
|
|
|
$chart->{'over_value_char'} = '+'; # (default: '+')
|
55
|
|
|
|
|
|
|
$chart->{'under_value_char'} = '_'; # (default: '-' )
|
56
|
|
|
|
|
|
|
$rval = $chart->chart();
|
57
|
|
|
|
|
|
|
if($rval >= 1) {
|
58
|
|
|
|
|
|
|
my @ready_chart = @{$chart->{'screen'}};
|
59
|
|
|
|
|
|
|
print (join '\n', @ready_chart) . "\n";
|
60
|
|
|
|
|
|
|
} else {
|
61
|
|
|
|
|
|
|
print "Error in creating chart: " . $chart->error_string . "\n";
|
62
|
|
|
|
|
|
|
}
|
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
# Result:
|
65
|
|
|
|
|
|
|
# 4 4 5 4
|
66
|
|
|
|
|
|
|
# 3 3 | | | 3
|
67
|
|
|
|
|
|
|
# 2 2 | | | | | 2
|
68
|
|
|
|
|
|
|
# 1 1 | | | | | | | 1
|
69
|
|
|
|
|
|
|
# 0 ------------------0 ------------------0
|
70
|
|
|
|
|
|
|
# -1 -1| | | | | | | -1
|
71
|
|
|
|
|
|
|
# -2 -2| | | | | -2
|
72
|
|
|
|
|
|
|
# -3 -3| | | -3
|
73
|
|
|
|
|
|
|
# -4 -4-5-4
|
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
=head1 DESCRIPTION
|
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
Text::HistogramChart creates graphical charts for terminal displays or any other display device where bitmap graphics is not available or desired!
|
79
|
|
|
|
|
|
|
You can supply the Y axel legend (vertical) values or Text::HistogramChart can calculate them from the input values.
|
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
=head1 USAGE
|
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
The following variables are available to fine tune the chart
|
85
|
|
|
|
|
|
|
(see SYNOPSIS for an example of usage):
|
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
=over 4
|
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
=item B, B, B
|
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
The 'screen' is the area in which the chart is drawn. The size is defined with three variables.
|
92
|
|
|
|
|
|
|
B is the absolute Y-axis height in character rows.
|
93
|
|
|
|
|
|
|
B is the number of characters used for one bar (one value). If you have 10 values and
|
94
|
|
|
|
|
|
|
B is 3, then the length of the screen (the X-axis) is 10 * 3 = 30 characters (without legend).
|
95
|
|
|
|
|
|
|
Use B to define the legend width. The default for both is 5 characters.
|
96
|
|
|
|
|
|
|
Screen height defaults to 10 characters.
|
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
=item B
|
99
|
|
|
|
|
|
|
Set this to 1 if you want the legend values prepended to the left edge of the chart.
|
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
=item B, B, B, B
|
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
Set B to 1 if you want the value of each bar written to the top (or bottom if the value is negative).
|
104
|
|
|
|
|
|
|
Set B and B to 1 if you only want want the value written when
|
105
|
|
|
|
|
|
|
the value is greater than the maximum given legend value (or less than the minimum).
|
106
|
|
|
|
|
|
|
Set B to 1 if you want the value written when it equals to 'floor', normally when the value is 0.
|
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
=item B, B, B, B
|
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
These variables define the characters used for writing the chart
|
111
|
|
|
|
|
|
|
B and B are used when the value is off the scale (too big or too small).
|
112
|
|
|
|
|
|
|
B is the horizontal line usually at 0.
|
113
|
|
|
|
|
|
|
B is the normal 'bar'.
|
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
Any of these charaters can be more than one character is size.
|
116
|
|
|
|
|
|
|
If you want "fatter" vertical bars, just set bar_char to '||'.
|
117
|
|
|
|
|
|
|
Remember to set the other values to double digits as well.
|
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
=item B, B, B, B, B
|
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
With B and B you can restrict the chart into a certain 'height'.
|
122
|
|
|
|
|
|
|
E.g. you are measuring the CPU performance of a server. The performance is usually between 70% and 95% of total capacity.
|
123
|
|
|
|
|
|
|
To show the occasional drops to 0%-70% is a waste of (terminal) space. So you set
|
124
|
|
|
|
|
|
|
B to 95 and B to 70.
|
125
|
|
|
|
|
|
|
This feature not yet implemented.
|
126
|
|
|
|
|
|
|
Set B to 1 if you want a horizontal bar across the screen at 0.
|
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
=back
|
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
=head1 DEPENDENCIES
|
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
Requires Perl version 5.008.001.
|
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
Requires the following modules:
|
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
=over 4
|
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
=item Hash::Util
|
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
=back
|
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
=cut
|
146
|
|
|
|
|
|
|
|
147
|
1
|
|
|
1
|
|
925
|
use utf8;
|
|
1
|
|
|
|
|
10
|
|
|
1
|
|
|
|
|
5
|
|
148
|
1
|
|
|
1
|
|
944
|
use Hash::Util qw{lock_keys unlock_keys};
|
|
1
|
|
|
|
|
3005
|
|
|
1
|
|
|
|
|
6
|
|
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
# Global creator
|
151
|
|
|
|
|
|
|
BEGIN {
|
152
|
1
|
|
|
1
|
|
107
|
use Exporter ();
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
70
|
|
153
|
1
|
|
|
1
|
|
2
|
our (@ISA, @EXPORT_OK, %EXPORT_TAGS);
|
154
|
|
|
|
|
|
|
|
155
|
1
|
|
|
|
|
16
|
@ISA = qw(Exporter DynaLoader);
|
156
|
1
|
|
|
|
|
3
|
%EXPORT_TAGS = ( ); # eg: TAG => [ qw!name1 name2! ],
|
157
|
1
|
|
|
|
|
2417
|
@EXPORT_OK = qw();
|
158
|
|
|
|
|
|
|
}
|
159
|
|
|
|
|
|
|
our @EXPORT_OK;
|
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
# Global destructor
|
162
|
1
|
|
|
1
|
|
6802
|
END {
|
163
|
|
|
|
|
|
|
}
|
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
# CONSTANTS for this module
|
166
|
|
|
|
|
|
|
my $TRUE = 1;
|
167
|
|
|
|
|
|
|
my $FALSE = 0;
|
168
|
|
|
|
|
|
|
my $EMPTY_STR = q{};
|
169
|
|
|
|
|
|
|
my @EMPTY_ARRAY = (); ## no critic (ProhibitUselessInitialization)
|
170
|
|
|
|
|
|
|
my $SPACE = q{ };
|
171
|
|
|
|
|
|
|
my $HALF_ROW = 0.5; ## no critic (ValuesAndExpressions::ProhibitMagicNumbers)
|
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
# DEFAULTS
|
174
|
|
|
|
|
|
|
my $DEFAULT_SCREEN_HEIGHT = 10; ## no critic (ProhibitMagicNumbers)
|
175
|
|
|
|
|
|
|
my $DEFAULT_ROOF_VALUE = 0;
|
176
|
|
|
|
|
|
|
my $DEFAULT_BOTTOM_VALUE = 0;
|
177
|
|
|
|
|
|
|
my $DEFAULT_FLOOR_VALUE = 0;
|
178
|
|
|
|
|
|
|
my $DEFAULT_WRITE_FLOOR = 0; # FALSE
|
179
|
|
|
|
|
|
|
my $DEFAULT_USE_FLOOR = 0; # FALSE
|
180
|
|
|
|
|
|
|
my $DEFAULT_WRITE_FLOOR_VALUE = 0; # FALSE
|
181
|
|
|
|
|
|
|
my $DEFAULT_WRITE_LEGEND = 0;
|
182
|
|
|
|
|
|
|
my $DEFAULT_LEGEND_HORIZONTAL_WIDTH = 5; ## no critic (ProhibitMagicNumbers)
|
183
|
|
|
|
|
|
|
my $DEFAULT_HORIZONTAL_WIDTH = 5; ## no critic (ProhibitMagicNumbers)
|
184
|
|
|
|
|
|
|
my $DEFAULT_WRITE_VALUE = 0; # FALSE
|
185
|
|
|
|
|
|
|
my $DEFAULT_WRITE_ALWAYS_OVER_VALUE = 0; # FALSE
|
186
|
|
|
|
|
|
|
my $DEFAULT_WRITE_ALWAYS_UNDER_VALUE = 0; # FALSE
|
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
my $DEFAULT_BAR_CHAR = q{|};
|
189
|
|
|
|
|
|
|
my $DEFAULT_FLOOR_CHAR = q{-};
|
190
|
|
|
|
|
|
|
my $DEFAULT_OVER_VALUE_CHAR = q{+};
|
191
|
|
|
|
|
|
|
my $DEFAULT_UNDER_VALUE_CHAR = q{-};
|
192
|
|
|
|
|
|
|
my $DEFAULT_LEGEND_VALUES = \@EMPTY_ARRAY;
|
193
|
|
|
|
|
|
|
my $DEFAULT_VALUES = \@EMPTY_ARRAY;
|
194
|
|
|
|
|
|
|
my $DEFAULT_SCREEN = q{};
|
195
|
|
|
|
|
|
|
my $DEFAULT_ERROR_STRING = q{};
|
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
# GLOBALS
|
198
|
|
|
|
|
|
|
# No global variables
|
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
=head1 EXPORT
|
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
Text::HistogramChart is a purely object-oriented module.
|
205
|
|
|
|
|
|
|
No exported functions.
|
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
=head1 SUBROUTINES/METHODS
|
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
=head2 new
|
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
Creator function.
|
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
=cut
|
215
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
sub new {
|
217
|
1
|
|
|
1
|
1
|
252
|
my $class = shift;
|
218
|
1
|
|
|
|
|
3
|
my $self;
|
219
|
1
|
|
|
|
|
8
|
my @self_keys = (
|
220
|
|
|
|
|
|
|
'screen_height', # (height reserved for the chart.)
|
221
|
|
|
|
|
|
|
'roof_value', # (active if != 0), # Arbitrarily squeeze or extend the size (height) of bars (not screen)
|
222
|
|
|
|
|
|
|
'bottom_value', # (below floor, active if != 0), # Not yet implemented.
|
223
|
|
|
|
|
|
|
'floor_value', # (the "floor" of the chart, default: 0)
|
224
|
|
|
|
|
|
|
'write_floor', # (make floor visible)
|
225
|
|
|
|
|
|
|
'use_floor', # (use the floor value)
|
226
|
|
|
|
|
|
|
'write_floor_value', # If value == floor_value, then write value (mostly "0").
|
227
|
|
|
|
|
|
|
'write_legend', # (Prepend legend to each row.)
|
228
|
|
|
|
|
|
|
'legend_horizontal_width', # width of the space left for legend (left edge of chart)
|
229
|
|
|
|
|
|
|
'horizontal_width', # Horizontal width of one bar. This parameter directly influences the width of the screen (i.e. chart).
|
230
|
|
|
|
|
|
|
'write_value', # (YES = 1, NO = 0, default: no; write the value on the end of the bar),
|
231
|
|
|
|
|
|
|
'write_always_over_value', # (YES = 1, NO = 0, default: yes; write the value only if it is too high for the graph),
|
232
|
|
|
|
|
|
|
'write_always_under_value', # (YES = 1, NO = 0, default: yes; write the value only if it is too low for the graph),
|
233
|
|
|
|
|
|
|
'bar_char', # (default: '|')
|
234
|
|
|
|
|
|
|
'floor_char', # (default: '-' )
|
235
|
|
|
|
|
|
|
'over_value_char', # (default: '+'; overruled by write_value and write_always_over_value)
|
236
|
|
|
|
|
|
|
'under_value_char', # (default: '-'; overruled by write_value and write_always_under_value)
|
237
|
|
|
|
|
|
|
'legend_values', # array of legend values (numbers). Pointer to.
|
238
|
|
|
|
|
|
|
'values', # array of values (numbers). Pointer to.
|
239
|
|
|
|
|
|
|
'screen', # The result: array of strings. Pointer to.
|
240
|
|
|
|
|
|
|
'error_string', # A meaningful error!
|
241
|
|
|
|
|
|
|
);
|
242
|
1
|
|
|
|
|
3
|
lock_keys(%{$self}, @self_keys);
|
|
1
|
|
|
|
|
10
|
|
243
|
1
|
|
|
|
|
147
|
$self->{'screen_height'} = $DEFAULT_SCREEN_HEIGHT;
|
244
|
1
|
|
|
|
|
3
|
$self->{'roof_value'} = $DEFAULT_ROOF_VALUE;
|
245
|
1
|
|
|
|
|
2
|
$self->{'bottom_value'} = $DEFAULT_BOTTOM_VALUE;
|
246
|
1
|
|
|
|
|
3
|
$self->{'floor_value'} = $DEFAULT_FLOOR_VALUE;
|
247
|
1
|
|
|
|
|
3
|
$self->{'write_floor'} = $DEFAULT_WRITE_FLOOR;
|
248
|
1
|
|
|
|
|
2
|
$self->{'use_floor'} = $DEFAULT_USE_FLOOR;
|
249
|
1
|
|
|
|
|
3
|
$self->{'write_floor_value'} = $DEFAULT_WRITE_FLOOR_VALUE;
|
250
|
1
|
|
|
|
|
1
|
$self->{'write_legend'} = $DEFAULT_WRITE_LEGEND;
|
251
|
1
|
|
|
|
|
2
|
$self->{'legend_horizontal_width'} = $DEFAULT_LEGEND_HORIZONTAL_WIDTH;
|
252
|
1
|
|
|
|
|
3
|
$self->{'horizontal_width'} = $DEFAULT_HORIZONTAL_WIDTH;
|
253
|
1
|
|
|
|
|
1
|
$self->{'write_value'} = $DEFAULT_WRITE_VALUE;
|
254
|
1
|
|
|
|
|
468
|
$self->{'write_always_over_value'} = $DEFAULT_WRITE_ALWAYS_OVER_VALUE;
|
255
|
1
|
|
|
|
|
3
|
$self->{'write_always_under_value'} = $DEFAULT_WRITE_ALWAYS_UNDER_VALUE;
|
256
|
|
|
|
|
|
|
|
257
|
1
|
|
|
|
|
15
|
$self->{'bar_char'} = $DEFAULT_BAR_CHAR;
|
258
|
1
|
|
|
|
|
2
|
$self->{'floor_char'} = $DEFAULT_FLOOR_CHAR;
|
259
|
1
|
|
|
|
|
3
|
$self->{'over_value_char'} = $DEFAULT_OVER_VALUE_CHAR;
|
260
|
1
|
|
|
|
|
1
|
$self->{'under_value_char'} = $DEFAULT_UNDER_VALUE_CHAR;
|
261
|
1
|
|
|
|
|
2
|
$self->{'legend_values'} = $DEFAULT_LEGEND_VALUES;
|
262
|
1
|
|
|
|
|
1
|
$self->{'values'} = $DEFAULT_VALUES;
|
263
|
1
|
|
|
|
|
2
|
$self->{'screen'} = $DEFAULT_SCREEN;
|
264
|
1
|
|
|
|
|
1
|
$self->{'error_string'} = $DEFAULT_ERROR_STRING;
|
265
|
|
|
|
|
|
|
|
266
|
1
|
|
|
|
|
2
|
unlock_keys(%{$self});
|
|
1
|
|
|
|
|
5
|
|
267
|
1
|
|
|
|
|
8
|
my $blessed_ref = bless $self, $class;
|
268
|
1
|
|
|
|
|
2
|
lock_keys(%{$self}, @self_keys);
|
|
1
|
|
|
|
|
10
|
|
269
|
1
|
|
|
|
|
138
|
return $blessed_ref;
|
270
|
|
|
|
|
|
|
}
|
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
=head2 chart
|
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
Create the chart. Writes the ready chart into $self->{'screen'}.
|
275
|
|
|
|
|
|
|
The ready chart is an array of strings without linefeed.
|
276
|
|
|
|
|
|
|
Returns >= 1, if successful, else $self->{'error_string'} contains the error.
|
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
=cut
|
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
sub chart {
|
281
|
7
|
|
|
7
|
1
|
24044
|
my $return_value = 1;
|
282
|
|
|
|
|
|
|
|
283
|
7
|
|
|
|
|
11
|
my $self = shift;
|
284
|
|
|
|
|
|
|
|
285
|
7
|
|
|
|
|
8
|
my @values = @{$self->{'values'}};
|
|
7
|
|
|
|
|
23
|
|
286
|
7
|
|
|
|
|
9
|
my @legend_values;
|
287
|
7
|
|
|
|
|
8
|
my $horizontal_width_empty = $EMPTY_STR;
|
288
|
7
|
|
|
|
|
23
|
while(length $horizontal_width_empty < $self->{'horizontal_width'}) {
|
289
|
27
|
|
|
|
|
55
|
$horizontal_width_empty .= $SPACE;
|
290
|
|
|
|
|
|
|
}
|
291
|
|
|
|
|
|
|
|
292
|
7
|
|
|
|
|
7
|
my @output_rows;
|
293
|
|
|
|
|
|
|
# If user wants, write only the legend.
|
294
|
|
|
|
|
|
|
# Always create the legend first so you know which rows have which values!
|
295
|
|
|
|
|
|
|
# If user gives the legend values (parameter LEGEND_VALUES)
|
296
|
|
|
|
|
|
|
# then all the better for you (no need to calculate the legend yourself).
|
297
|
|
|
|
|
|
|
# But only write the legend if user demands it (parameter WRITE_LEGEND).
|
298
|
|
|
|
|
|
|
# Even without writing the legend, the legend values define the distance between rows.
|
299
|
7
|
|
|
|
|
16
|
my $sprf_format = q{%-} . $self->{'legend_horizontal_width'} . q{s};
|
300
|
7
|
100
|
66
|
|
|
22
|
if(defined $self->{'legend_values'} && scalar @{$self->{'legend_values'}} > 0) {
|
|
7
|
|
|
|
|
32
|
|
301
|
4
|
|
|
|
|
5
|
@legend_values = @{$self->{'legend_values'}};
|
|
4
|
|
|
|
|
11
|
|
302
|
4
|
50
|
|
|
|
15
|
if(scalar(@legend_values) != $self->{'screen_height'}) {
|
303
|
0
|
|
|
|
|
0
|
$self->{'error_string'} = 'Screen height must be equal to the number of legend values!';
|
304
|
0
|
|
|
|
|
0
|
return 0;
|
305
|
|
|
|
|
|
|
}
|
306
|
4
|
|
|
|
|
18
|
@legend_values = sort {$a <=> $b} @legend_values; # Sort them to be sure
|
|
73
|
|
|
|
|
74
|
|
307
|
|
|
|
|
|
|
}
|
308
|
|
|
|
|
|
|
else {
|
309
|
3
|
|
|
|
|
4
|
my $highest_value = 0;
|
310
|
3
|
50
|
|
|
|
8
|
if($self->{'roof_value'} != 0) {
|
311
|
0
|
|
|
|
|
0
|
$highest_value = $self->{'roof_value'};
|
312
|
|
|
|
|
|
|
}
|
313
|
|
|
|
|
|
|
else {
|
314
|
3
|
|
|
|
|
7
|
foreach my $value (@values) {
|
315
|
43
|
100
|
|
|
|
76
|
if($value > $highest_value) {
|
316
|
26
|
|
|
|
|
33
|
$highest_value = $value;
|
317
|
|
|
|
|
|
|
}
|
318
|
|
|
|
|
|
|
}
|
319
|
|
|
|
|
|
|
}
|
320
|
3
|
|
|
|
|
5
|
my $lowest_value = 0;
|
321
|
3
|
50
|
|
|
|
8
|
if($self->{'bottom_value'} != 0) {
|
322
|
0
|
|
|
|
|
0
|
$lowest_value = $self->{'bottom_value'};
|
323
|
|
|
|
|
|
|
}
|
324
|
|
|
|
|
|
|
else {
|
325
|
3
|
|
|
|
|
5
|
foreach my $value (@values) {
|
326
|
43
|
50
|
|
|
|
81
|
if($value < $lowest_value) {
|
327
|
0
|
|
|
|
|
0
|
$lowest_value = $value;
|
328
|
|
|
|
|
|
|
}
|
329
|
|
|
|
|
|
|
}
|
330
|
|
|
|
|
|
|
}
|
331
|
3
|
|
|
|
|
9
|
my $rows_for_one = $self->{'screen_height'} / $highest_value;
|
332
|
3
|
|
|
|
|
6
|
my $amount_per_row = $highest_value / $self->{'screen_height'};
|
333
|
|
|
|
|
|
|
#my $rows_for_one = $self->{'screen_height'} / ($highest_value - $lowest_value + 1); //TODO
|
334
|
|
|
|
|
|
|
#my $amount_per_row = ($highest_value - $lowest_value + 1) / $self->{'screen_height'}; //TODO
|
335
|
|
|
|
|
|
|
|
336
|
|
|
|
|
|
|
# Make a legend based on lowest and highest value in @values
|
337
|
3
|
|
|
|
|
4
|
my $screen_top_row = $self->{'screen_height'} - 1;
|
338
|
3
|
|
|
|
|
3
|
my $screen_bottom_row = 0;
|
339
|
|
|
|
|
|
|
#my $screen_top_row = $highest_value - $lowest_value; //TODO
|
340
|
|
|
|
|
|
|
#my $screen_bottom_row = 0; //TODO
|
341
|
3
|
|
|
|
|
11
|
for(my $i_row = $screen_bottom_row; $i_row <= $screen_top_row; $i_row++) {
|
342
|
40
|
|
|
|
|
124
|
push @legend_values, (sprintf $sprf_format, int(($i_row + 1) * $amount_per_row + $HALF_ROW));
|
343
|
|
|
|
|
|
|
#push @legend_values, (sprintf $sprf_format, int(($i_row + $lowest_value) * $amount_per_row + 0.5)); //TODO
|
344
|
|
|
|
|
|
|
}
|
345
|
|
|
|
|
|
|
}
|
346
|
7
|
100
|
|
|
|
19
|
if($self->{'write_legend'} == 1) {
|
347
|
6
|
|
|
|
|
20
|
for(my $i_row = $self->{'screen_height'} - 1; $i_row >= 0; $i_row--) { ## no critic (ControlStructures::ProhibitCStyleForLoops)
|
348
|
74
|
|
|
|
|
200
|
$output_rows[$i_row] .= sprintf $sprf_format, int $legend_values[$i_row];
|
349
|
|
|
|
|
|
|
}
|
350
|
|
|
|
|
|
|
}
|
351
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
# Now the values
|
353
|
|
|
|
|
|
|
# We write one pillar at a time: one value = one pillar!
|
354
|
|
|
|
|
|
|
# So, we write from left to right, one pillar at a time!
|
355
|
|
|
|
|
|
|
# We write the pillar starting from the bottom.
|
356
|
7
|
|
|
|
|
9
|
my $screen_top_row = $self->{'screen_height'} - 1;
|
357
|
7
|
|
|
|
|
8
|
my $screen_bottom_row = 0;
|
358
|
7
|
|
|
|
|
9
|
my $screen_floor_row = $screen_bottom_row;
|
359
|
7
|
100
|
|
|
|
17
|
if($self->{'use_floor'} == 1) {
|
360
|
3
|
|
|
|
|
7
|
for(0..@legend_values-1) {
|
361
|
34
|
100
|
|
|
|
68
|
if($legend_values[$_] == $self->{'floor_value'}) {
|
362
|
3
|
|
|
|
|
6
|
$screen_floor_row = $_;
|
363
|
|
|
|
|
|
|
}
|
364
|
|
|
|
|
|
|
}
|
365
|
|
|
|
|
|
|
}
|
366
|
7
|
|
|
|
|
13
|
foreach my $value (@values) {
|
367
|
108
|
|
|
|
|
238
|
for(my $i_row = $screen_bottom_row; $i_row <= $screen_top_row; $i_row++) {
|
368
|
1298
|
100
|
|
|
|
2265
|
if($value != $self->{'floor_value'}) { # If value == 0, just write spaces.
|
369
|
1194
|
100
|
66
|
|
|
5923
|
if($i_row == $screen_bottom_row) { ## no critic (ControlStructures::ProhibitCascadingIfElse)
|
|
|
100
|
66
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
370
|
99
|
100
|
|
|
|
181
|
if($i_row < $screen_floor_row) {
|
|
|
50
|
|
|
|
|
|
371
|
47
|
100
|
|
|
|
85
|
if($value > $legend_values[$i_row]) { # Write empty space
|
|
|
50
|
|
|
|
|
|
372
|
43
|
|
|
|
|
111
|
$output_rows[$i_row] .= $horizontal_width_empty;
|
373
|
|
|
|
|
|
|
}
|
374
|
|
|
|
|
|
|
elsif($value <= $legend_values[$i_row]) { # Write value
|
375
|
4
|
50
|
|
|
|
18
|
if(length($value) > $self->{'horizontal_width'}) { # Doesn't fit on the row.
|
376
|
0
|
0
|
|
|
|
0
|
$output_rows[$i_row] .= center_text(
|
|
|
0
|
|
|
|
|
|
377
|
|
|
|
|
|
|
$self->{'write_always_under_value'} ? $self->{'under_value_char'} : ($self->{'write_value'} ? $value : $self->{'bar_char'}),
|
378
|
|
|
|
|
|
|
$self->{'horizontal_width'}, $SPACE, 'right');
|
379
|
|
|
|
|
|
|
}
|
380
|
|
|
|
|
|
|
else {
|
381
|
4
|
100
|
|
|
|
16
|
$output_rows[$i_row] .= center_text(
|
|
|
50
|
|
|
|
|
|
382
|
|
|
|
|
|
|
$self->{'write_always_under_value'} ? $value : ($self->{'write_value'} ? $value : $self->{'bar_char'}),
|
383
|
|
|
|
|
|
|
$self->{'horizontal_width'}, $SPACE, 'right');
|
384
|
|
|
|
|
|
|
}
|
385
|
|
|
|
|
|
|
}
|
386
|
|
|
|
|
|
|
else {
|
387
|
|
|
|
|
|
|
}
|
388
|
|
|
|
|
|
|
}
|
389
|
|
|
|
|
|
|
elsif($i_row >= $screen_floor_row) {
|
390
|
52
|
100
|
66
|
|
|
138
|
if($value >= $legend_values[$i_row + 1]) { # Write bar char
|
|
|
100
|
33
|
|
|
|
|
|
|
50
|
0
|
|
|
|
|
|
|
0
|
|
|
|
|
|
391
|
43
|
|
|
|
|
89
|
$output_rows[$i_row] .= center_text($self->{'bar_char'}, $self->{'horizontal_width'}, $SPACE, 'right');
|
392
|
|
|
|
|
|
|
}
|
393
|
|
|
|
|
|
|
elsif($value >= $legend_values[$i_row] && $value < $legend_values[$i_row + 1]) { # Write value
|
394
|
7
|
100
|
|
|
|
30
|
$output_rows[$i_row] .= center_text($self->{'write_value'} ? $value : $self->{'bar_char'}, $self->{'horizontal_width'}, $SPACE, 'right');
|
395
|
|
|
|
|
|
|
}
|
396
|
|
|
|
|
|
|
elsif($value < $legend_values[$i_row] && $value >= $self->{'floor_value'}) { # Write value maybe
|
397
|
2
|
50
|
|
|
|
8
|
$output_rows[$i_row] .= center_text(
|
398
|
|
|
|
|
|
|
$self->{'write_always_under_value'} ? $value : '',
|
399
|
|
|
|
|
|
|
$self->{'horizontal_width'}, $SPACE, 'right');
|
400
|
|
|
|
|
|
|
}
|
401
|
|
|
|
|
|
|
elsif($value < $legend_values[$i_row] && $value < $self->{'floor_value'}) { # Write value
|
402
|
0
|
0
|
|
|
|
0
|
$output_rows[$i_row] .= center_text($self->{'write_value'} ? $value : $self->{'bar_char'}, $self->{'horizontal_width'}, $SPACE, 'right');
|
403
|
|
|
|
|
|
|
}
|
404
|
|
|
|
|
|
|
else {
|
405
|
|
|
|
|
|
|
}
|
406
|
|
|
|
|
|
|
}
|
407
|
|
|
|
|
|
|
else {
|
408
|
|
|
|
|
|
|
}
|
409
|
|
|
|
|
|
|
}
|
410
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
# (Possible) middle rows (floor down)
|
412
|
|
|
|
|
|
|
elsif($i_row < $screen_floor_row && $i_row > $screen_bottom_row) {
|
413
|
203
|
100
|
66
|
|
|
677
|
if($value <= $legend_values[$i_row - 1]) { # Write bar char
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
414
|
47
|
|
|
|
|
91
|
$output_rows[$i_row] .= center_text($self->{'bar_char'}, $self->{'horizontal_width'}, $SPACE, 'right');
|
415
|
|
|
|
|
|
|
}
|
416
|
|
|
|
|
|
|
elsif($value <= $legend_values[$i_row] && $value > $legend_values[$i_row - 1]) { # Write value
|
417
|
20
|
100
|
|
|
|
61
|
$output_rows[$i_row] .= center_text($self->{'write_value'} ? $value : $self->{'bar_char'}, $self->{'horizontal_width'}, $SPACE, 'right');
|
418
|
|
|
|
|
|
|
}
|
419
|
|
|
|
|
|
|
elsif($value > $legend_values[$i_row]) { # Write white space
|
420
|
136
|
|
|
|
|
337
|
$output_rows[$i_row] .= $horizontal_width_empty;
|
421
|
|
|
|
|
|
|
}
|
422
|
|
|
|
|
|
|
else {
|
423
|
|
|
|
|
|
|
}
|
424
|
|
|
|
|
|
|
}
|
425
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
# Floor row
|
427
|
|
|
|
|
|
|
elsif($i_row == $screen_floor_row) {
|
428
|
47
|
50
|
|
|
|
81
|
if($self->{'write_floor'} == 1) {
|
429
|
47
|
|
|
|
|
103
|
$output_rows[$i_row] .= center_text('-', $self->{'horizontal_width'}, "-", 'right');
|
430
|
|
|
|
|
|
|
}
|
431
|
|
|
|
|
|
|
else {
|
432
|
0
|
0
|
0
|
|
|
0
|
if($value > $legend_values[$i_row - 1] && $value < $legend_values[$i_row + 1]) { # Write value
|
433
|
0
|
0
|
|
|
|
0
|
$output_rows[$i_row] .= center_text($self->{'write_value'} ? $value : $self->{'bar_char'}, $self->{'horizontal_width'}, $SPACE, 'right');
|
434
|
|
|
|
|
|
|
}
|
435
|
|
|
|
|
|
|
else { # Write bar char
|
436
|
0
|
|
|
|
|
0
|
$output_rows[$i_row] .= center_text($self->{'bar_char'}, $self->{'horizontal_width'}, $SPACE, 'right');
|
437
|
|
|
|
|
|
|
}
|
438
|
|
|
|
|
|
|
}
|
439
|
|
|
|
|
|
|
}
|
440
|
|
|
|
|
|
|
|
441
|
|
|
|
|
|
|
# (Possible) middle rows (floor up)
|
442
|
|
|
|
|
|
|
elsif($i_row > $screen_floor_row && $i_row < $screen_top_row) {
|
443
|
746
|
100
|
66
|
|
|
2333
|
if($value >= $legend_values[$i_row + 1]) { # Write bar char
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
444
|
231
|
|
|
|
|
498
|
$output_rows[$i_row] .= center_text($self->{'bar_char'}, $self->{'horizontal_width'}, $SPACE, 'right');
|
445
|
|
|
|
|
|
|
}
|
446
|
|
|
|
|
|
|
elsif($value >= $legend_values[$i_row] && $value < $legend_values[$i_row + 1]) { # Write value
|
447
|
59
|
100
|
|
|
|
172
|
$output_rows[$i_row] .= center_text($self->{'write_value'} ? $value : $self->{'bar_char'}, $self->{'horizontal_width'}, $SPACE, 'right');
|
448
|
|
|
|
|
|
|
}
|
449
|
|
|
|
|
|
|
elsif($value < $legend_values[$i_row]) { # Write white space
|
450
|
456
|
|
|
|
|
1190
|
$output_rows[$i_row] .= $horizontal_width_empty;
|
451
|
|
|
|
|
|
|
}
|
452
|
|
|
|
|
|
|
else {
|
453
|
|
|
|
|
|
|
}
|
454
|
|
|
|
|
|
|
}
|
455
|
|
|
|
|
|
|
|
456
|
|
|
|
|
|
|
# Top row, here value is only >= or
|
457
|
|
|
|
|
|
|
elsif($i_row == $screen_top_row) {
|
458
|
99
|
100
|
|
|
|
217
|
if($value >= $legend_values[$i_row]) { # Write value or bar char
|
|
|
50
|
|
|
|
|
|
459
|
6
|
50
|
|
|
|
17
|
if(length($value) > $self->{'horizontal_width'}) { # Doesn't fit on the row.
|
460
|
0
|
0
|
|
|
|
0
|
$output_rows[$i_row] .= center_text(
|
|
|
0
|
|
|
|
|
|
461
|
|
|
|
|
|
|
$self->{'write_always_over_value'} ? $self->{'over_value_char'} : ($self->{'write_value'} ? $value : $self->{'bar_char'}),
|
462
|
|
|
|
|
|
|
$self->{'horizontal_width'}, $SPACE, 'right');
|
463
|
|
|
|
|
|
|
}
|
464
|
|
|
|
|
|
|
else {
|
465
|
6
|
100
|
|
|
|
28
|
$output_rows[$i_row] .= center_text(
|
|
|
50
|
|
|
|
|
|
466
|
|
|
|
|
|
|
$self->{'write_always_over_value'} ? $value : ($self->{'write_value'} ? $value : $self->{'bar_char'}),
|
467
|
|
|
|
|
|
|
$self->{'horizontal_width'}, $SPACE, 'right');
|
468
|
|
|
|
|
|
|
}
|
469
|
|
|
|
|
|
|
}
|
470
|
|
|
|
|
|
|
elsif($value < $legend_values[$i_row]) { # Write white space
|
471
|
93
|
|
|
|
|
320
|
$output_rows[$i_row] .= $horizontal_width_empty;
|
472
|
|
|
|
|
|
|
}
|
473
|
|
|
|
|
|
|
else {
|
474
|
|
|
|
|
|
|
}
|
475
|
|
|
|
|
|
|
}
|
476
|
|
|
|
|
|
|
else {
|
477
|
|
|
|
|
|
|
}
|
478
|
|
|
|
|
|
|
}
|
479
|
|
|
|
|
|
|
else { # $value is same as $self->{'floor_value'}
|
480
|
104
|
100
|
|
|
|
177
|
if($self->{'floor_value'} == $legend_values[$i_row]) { # This is the floor row, the "0" row.
|
481
|
6
|
50
|
|
|
|
13
|
if($self->{'write_floor_value'} == 1) {
|
|
|
0
|
|
|
|
|
|
482
|
6
|
|
|
|
|
13
|
$output_rows[$i_row] .= center_text($value, $self->{'horizontal_width'}, $SPACE, 'right');
|
483
|
|
|
|
|
|
|
}
|
484
|
|
|
|
|
|
|
elsif($self->{'write_floor'}) {
|
485
|
0
|
|
|
|
|
0
|
$output_rows[$i_row] .= center_text($self->{'floor_char'}, $self->{'horizontal_width'}, $SPACE, 'right');
|
486
|
|
|
|
|
|
|
}
|
487
|
|
|
|
|
|
|
else {
|
488
|
0
|
|
|
|
|
0
|
$output_rows[$i_row] .= $horizontal_width_empty;
|
489
|
|
|
|
|
|
|
}
|
490
|
|
|
|
|
|
|
}
|
491
|
|
|
|
|
|
|
else {
|
492
|
98
|
|
|
|
|
220
|
$output_rows[$i_row] .= $horizontal_width_empty;
|
493
|
|
|
|
|
|
|
}
|
494
|
|
|
|
|
|
|
}
|
495
|
|
|
|
|
|
|
}
|
496
|
|
|
|
|
|
|
}
|
497
|
|
|
|
|
|
|
# Now we have to flip the order!
|
498
|
7
|
|
|
|
|
11
|
my @reversed_rows;
|
499
|
7
|
|
|
|
|
14
|
foreach my $screen_row (@output_rows) {
|
500
|
84
|
|
|
|
|
166
|
unshift @reversed_rows, $screen_row;
|
501
|
|
|
|
|
|
|
}
|
502
|
7
|
|
|
|
|
15
|
$self->{'screen'} = \@reversed_rows;
|
503
|
|
|
|
|
|
|
|
504
|
|
|
|
|
|
|
# Clean up
|
505
|
7
|
|
|
|
|
50
|
return $return_value;
|
506
|
|
|
|
|
|
|
}
|
507
|
|
|
|
|
|
|
|
508
|
|
|
|
|
|
|
=head1 INTERNAL SUBROUTINES
|
509
|
|
|
|
|
|
|
|
510
|
|
|
|
|
|
|
=head2 center_text
|
511
|
|
|
|
|
|
|
|
512
|
|
|
|
|
|
|
Center a string into a string buffer. Return the buffer.
|
513
|
|
|
|
|
|
|
Parameters: text to be centered, field width, fill character (default: " "), start direction (default: left).
|
514
|
|
|
|
|
|
|
If text is longer than field width, it is not truncated!
|
515
|
|
|
|
|
|
|
|
516
|
|
|
|
|
|
|
=cut
|
517
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
sub center_text {
|
519
|
472
|
|
|
472
|
1
|
538
|
my $text = $_[0];
|
520
|
472
|
|
|
|
|
455
|
my $field_width = $_[1];
|
521
|
472
|
50
|
|
|
|
688
|
my $fill_character = ($_[2] ? $_[2] : $SPACE);
|
522
|
472
|
50
|
|
|
|
704
|
my $start_direction = ($_[3] ? $_[3] : 'left'); ## no critic (ProhibitMagicNumbers)
|
523
|
472
|
|
|
|
|
447
|
my $next_add_direction = $start_direction;
|
524
|
|
|
|
|
|
|
# MODIFY BUFFER
|
525
|
472
|
|
|
|
|
935
|
while(length($text) < $field_width) {
|
526
|
1248
|
100
|
|
|
|
1873
|
if($next_add_direction eq 'left') {
|
527
|
475
|
|
|
|
|
603
|
$text = $fill_character . $text;
|
528
|
475
|
|
|
|
|
976
|
$next_add_direction = 'right'
|
529
|
|
|
|
|
|
|
}
|
530
|
|
|
|
|
|
|
else {
|
531
|
773
|
|
|
|
|
740
|
$text = $text . $fill_character;
|
532
|
773
|
|
|
|
|
1533
|
$next_add_direction = 'left'
|
533
|
|
|
|
|
|
|
}
|
534
|
|
|
|
|
|
|
}
|
535
|
|
|
|
|
|
|
|
536
|
472
|
|
|
|
|
1757
|
return $text;
|
537
|
|
|
|
|
|
|
}
|
538
|
|
|
|
|
|
|
|
539
|
|
|
|
|
|
|
=head1 AUTHOR
|
540
|
|
|
|
|
|
|
|
541
|
|
|
|
|
|
|
Mikko Koivunalho, C<< >>
|
542
|
|
|
|
|
|
|
|
543
|
|
|
|
|
|
|
=head1 BUGS
|
544
|
|
|
|
|
|
|
|
545
|
|
|
|
|
|
|
Please report any bugs or feature requests to C, or through
|
546
|
|
|
|
|
|
|
the web interface at L. I will be notified, and then you'll
|
547
|
|
|
|
|
|
|
automatically be notified of progress on your bug as I make changes.
|
548
|
|
|
|
|
|
|
|
549
|
|
|
|
|
|
|
|
550
|
|
|
|
|
|
|
|
551
|
|
|
|
|
|
|
|
552
|
|
|
|
|
|
|
=head1 SUPPORT
|
553
|
|
|
|
|
|
|
|
554
|
|
|
|
|
|
|
You can find documentation for this module with the perldoc command.
|
555
|
|
|
|
|
|
|
|
556
|
|
|
|
|
|
|
perldoc Text::HistogramChart
|
557
|
|
|
|
|
|
|
|
558
|
|
|
|
|
|
|
|
559
|
|
|
|
|
|
|
You can also look for information at:
|
560
|
|
|
|
|
|
|
|
561
|
|
|
|
|
|
|
=over 4
|
562
|
|
|
|
|
|
|
|
563
|
|
|
|
|
|
|
=item * RT: CPAN's request tracker (report bugs here)
|
564
|
|
|
|
|
|
|
|
565
|
|
|
|
|
|
|
L
|
566
|
|
|
|
|
|
|
|
567
|
|
|
|
|
|
|
=item * AnnoCPAN: Annotated CPAN documentation
|
568
|
|
|
|
|
|
|
|
569
|
|
|
|
|
|
|
L
|
570
|
|
|
|
|
|
|
|
571
|
|
|
|
|
|
|
=item * CPAN Ratings
|
572
|
|
|
|
|
|
|
|
573
|
|
|
|
|
|
|
L
|
574
|
|
|
|
|
|
|
|
575
|
|
|
|
|
|
|
=item * Search CPAN
|
576
|
|
|
|
|
|
|
|
577
|
|
|
|
|
|
|
L
|
578
|
|
|
|
|
|
|
|
579
|
|
|
|
|
|
|
=back
|
580
|
|
|
|
|
|
|
|
581
|
|
|
|
|
|
|
|
582
|
|
|
|
|
|
|
=head1 ACKNOWLEDGEMENTS
|
583
|
|
|
|
|
|
|
|
584
|
|
|
|
|
|
|
None.
|
585
|
|
|
|
|
|
|
|
586
|
|
|
|
|
|
|
|
587
|
|
|
|
|
|
|
=head1 DIAGNOSTICS
|
588
|
|
|
|
|
|
|
|
589
|
|
|
|
|
|
|
None.
|
590
|
|
|
|
|
|
|
|
591
|
|
|
|
|
|
|
|
592
|
|
|
|
|
|
|
=head1 CONFIGURATION AND ENVIRONMENT
|
593
|
|
|
|
|
|
|
|
594
|
|
|
|
|
|
|
Please see the examples.
|
595
|
|
|
|
|
|
|
|
596
|
|
|
|
|
|
|
|
597
|
|
|
|
|
|
|
=head1 INCOMPATIBILITIES
|
598
|
|
|
|
|
|
|
|
599
|
|
|
|
|
|
|
None known.
|
600
|
|
|
|
|
|
|
|
601
|
|
|
|
|
|
|
|
602
|
|
|
|
|
|
|
=head1 BUGS AND LIMITATIONS
|
603
|
|
|
|
|
|
|
|
604
|
|
|
|
|
|
|
Plenty I'm sure.
|
605
|
|
|
|
|
|
|
Using roof_value and bottom_value together to restrict the bars into a certain scope is not yet implemented.
|
606
|
|
|
|
|
|
|
|
607
|
|
|
|
|
|
|
|
608
|
|
|
|
|
|
|
=head1 LICENSE AND COPYRIGHT
|
609
|
|
|
|
|
|
|
|
610
|
|
|
|
|
|
|
Copyright 2012 Mikko Koivunalho.
|
611
|
|
|
|
|
|
|
|
612
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it
|
613
|
|
|
|
|
|
|
under the terms of either: the GNU General Public License as published
|
614
|
|
|
|
|
|
|
by the Free Software Foundation; or the Artistic License.
|
615
|
|
|
|
|
|
|
|
616
|
|
|
|
|
|
|
See http://dev.perl.org/licenses/ for more information.
|
617
|
|
|
|
|
|
|
|
618
|
|
|
|
|
|
|
|
619
|
|
|
|
|
|
|
=cut
|
620
|
|
|
|
|
|
|
|
621
|
|
|
|
|
|
|
1; # End of Text::HistogramChart
|