1package Statistics::Descriptive::Sparse;
2$Statistics::Descriptive::Sparse::VERSION = '3.0800';
3use strict;
4use warnings;
5
6use vars qw(%fields);
7use Carp qw/ carp /;
8require Statistics::Descriptive;
9use Statistics::Descriptive::Smoother ();
10
11## no critic (ProhibitExplicitReturnUndef)
12
13sub _make_accessors
14{
15    my ( $pkg, $methods ) = @_;
16
17    ## no critic
18    no strict 'refs';
19    ## use critic
20    foreach my $method (@$methods)
21    {
22        *{ $pkg . "::" . $method } = do
23        {
24            my $m = $method;
25            sub {
26                my $self = shift;
27
28                if (@_)
29                {
30                    $self->{$m} = shift;
31                }
32                return $self->{$m};
33            };
34        };
35    }
36
37    return;
38}
39
40sub _make_private_accessors
41{
42    my ( $pkg, $methods ) = @_;
43
44    ## no critic
45    no strict 'refs';
46    ## use critic
47    foreach my $method (@$methods)
48    {
49        *{ $pkg . "::_" . $method } = do
50        {
51            my $m = $method;
52            sub {
53                my $self = shift;
54
55                if (@_)
56                {
57                    $self->{$m} = shift;
58                }
59                return $self->{$m};
60            };
61        };
62    }
63
64    return;
65}
66
67##Define the fields to be used as methods
68%fields = (
69    count        => 0,
70    mean         => undef,
71    sum          => undef,
72    sumsq        => undef,
73    min          => undef,
74    max          => undef,
75    mindex       => undef,
76    maxdex       => undef,
77    sample_range => undef,
78    variance     => undef,
79);
80
81__PACKAGE__->_make_accessors( [ grep { $_ ne "variance" } keys(%fields) ] );
82__PACKAGE__->_make_accessors( ["_permitted"] );
83__PACKAGE__->_make_private_accessors( ["variance"] );
84
85sub new
86{
87    my $proto = shift;
88    my $class = ref($proto) || $proto;
89    my $self  = { %fields, };
90    bless( $self, $class );
91    $self->_permitted( \%fields );
92    return $self;
93}
94
95sub _is_permitted
96{
97    my $self = shift;
98    my $key  = shift;
99
100    return exists( $self->_permitted()->{$key} );
101}
102
103sub add_data
104{
105    my $self = shift;    ##Myself
106    my $oldmean;
107    my ( $min, $mindex, $max, $maxdex, $sum, $sumsq, $count );
108    my $aref;
109
110    if ( ref $_[0] eq 'ARRAY' )
111    {
112        $aref = $_[0];
113    }
114    else
115    {
116        $aref = \@_;
117    }
118
119    ##If we were given no data, we do nothing.
120    return 1 if ( !@{$aref} );
121
122    ##Take care of appending to an existing data set
123
124    if ( !defined( $min = $self->min() ) )
125    {
126        $min = $aref->[ $mindex = 0 ];
127    }
128    else
129    {
130        $mindex = $self->mindex();
131    }
132
133    if ( !defined( $max = $self->max() ) )
134    {
135        $max = $aref->[ $maxdex = 0 ];
136    }
137    else
138    {
139        $maxdex = $self->maxdex();
140    }
141
142    $sum   = $self->sum();
143    $sumsq = $self->sumsq();
144    $count = $self->count();
145
146    ##Calculate new mean, sumsq, min and max;
147    foreach ( @{$aref} )
148    {
149        $sum   += $_;
150        $sumsq += $_**2;
151        ++$count;
152        if ( $_ >= $max )
153        {
154            $max    = $_;
155            $maxdex = $count - 1;
156        }
157        if ( $_ <= $min )
158        {
159            $min    = $_;
160            $mindex = $count - 1;
161        }
162    }
163
164    $self->min($min);
165    $self->mindex($mindex);
166    $self->max($max);
167    $self->maxdex($maxdex);
168    $self->sample_range( $max - $min );
169    $self->sum($sum);
170    $self->sumsq($sumsq);
171    $self->mean( $sum / $count );
172    $self->count($count);
173    ##indicator the value is not cached.  Variance isn't commonly enough
174    ##used to recompute every single data add.
175    $self->_variance(undef);
176    return 1;
177}
178
179sub standard_deviation
180{
181    my $self = shift;    ##Myself
182    return undef if ( !$self->count() );
183    return sqrt( $self->variance() );
184}
185
186##Return variance; if needed, compute and cache it.
187sub variance
188{
189    my $self = shift;    ##Myself
190
191    my $count = $self->count();
192
193    return undef if !$count;
194
195    return 0 if $count == 1;
196
197    if ( !defined( $self->_variance() ) )
198    {
199        my $variance = ( $self->sumsq() - $count * $self->mean()**2 );
200
201        # Sometimes due to rounding errors we get a number below 0.
202        # This makes sure this is handled as gracefully as possible.
203        #
204        # See:
205        #
206        # https://rt.cpan.org/Public/Bug/Display.html?id=46026
207
208        $variance = $variance < 0 ? 0 : $variance / ( $count - 1 );
209
210        $self->_variance($variance);
211
212        #  Return now to avoid re-entering this sub
213        #  (and therefore save time when many objects are used).
214        return $variance;
215    }
216
217    return $self->_variance();
218}
219
220##Clear a stat.  More efficient than destroying an object and calling
221##new.
222sub clear
223{
224    my $self = shift;    ##Myself
225    my $key;
226
227    return if ( !$self->count() );
228    while ( my ( $field, $value ) = each %fields )
229    {                    #  could use a slice assignment here
230        $self->{$field} = $value;
231    }
232}
233
2341;
235
236__END__
237
238=pod
239
240=encoding UTF-8
241
242=head1 NAME
243
244Statistics::Descriptive - Module of basic descriptive statistical functions.
245
246=head1 VERSION
247
248version 3.0800
249
250=head1 SYNOPSIS
251
252    use Statistics::Descriptive;
253    my $stat = Statistics::Descriptive::Full->new();
254    $stat->add_data(1,2,3,4);
255    my $mean = $stat->mean();
256    my $var = $stat->variance();
257    my $tm = $stat->trimmed_mean(.25);
258    $Statistics::Descriptive::Tolerance = 1e-10;
259
260=head1 DESCRIPTION
261
262This module provides basic functions used in descriptive statistics.
263It has an object oriented design and supports two different types of
264data storage and calculation objects: sparse and full. With the sparse
265method, none of the data is stored and only a few statistical measures
266are available. Using the full method, the entire data set is retained
267and additional functions are available.
268
269Whenever a division by zero may occur, the denominator is checked to be
270greater than the value C<$Statistics::Descriptive::Tolerance>, which
271defaults to 0.0. You may want to change this value to some small
272positive value such as 1e-24 in order to obtain error messages in case
273of very small denominators.
274
275Many of the methods (both Sparse and Full) cache values so that subsequent
276calls with the same arguments are faster.
277
278=head1 METHODS
279
280=head2 Sparse Methods
281
282=over 5
283
284=item $stat = Statistics::Descriptive::Sparse->new();
285
286Create a new sparse statistics object.
287
288=item $stat->clear();
289
290Effectively the same as
291
292  my $class = ref($stat);
293  undef $stat;
294  $stat = new $class;
295
296except more efficient.
297
298=item $stat->add_data(1,2,3);
299
300Adds data to the statistics variable. The cached statistical values are
301updated automatically.
302
303=item $stat->count();
304
305Returns the number of data items.
306
307=item $stat->mean();
308
309Returns the mean of the data.
310
311=item $stat->sum();
312
313Returns the sum of the data.
314
315=item $stat->variance();
316
317Returns the variance of the data.  Division by n-1 is used.
318
319=item $stat->standard_deviation();
320
321Returns the standard deviation of the data. Division by n-1 is used.
322
323=item $stat->min();
324
325Returns the minimum value of the data set.
326
327=item $stat->mindex();
328
329Returns the index of the minimum value of the data set.
330
331=item $stat->max();
332
333Returns the maximum value of the data set.
334
335=item $stat->maxdex();
336
337Returns the index of the maximum value of the data set.
338
339=item $stat->sample_range();
340
341Returns the sample range (max - min) of the data set.
342
343=back
344
345=head2 Full Methods
346
347Similar to the Sparse Methods above, any Full Method that is called caches
348the current result so that it doesn't have to be recalculated.  In some
349cases, several values can be cached at the same time.
350
351=over 5
352
353=item $stat = Statistics::Descriptive::Full->new();
354
355Create a new statistics object that inherits from
356Statistics::Descriptive::Sparse so that it contains all the methods
357described above.
358
359=item $stat->add_data(1,2,4,5);
360
361Adds data to the statistics variable.  All of the sparse statistical
362values are updated and cached.  Cached values from Full methods are
363deleted since they are no longer valid.
364
365I<Note:  Calling add_data with an empty array will delete all of your
366Full method cached values!  Cached values for the sparse methods are
367not changed>
368
369=item $stat->add_data_with_samples([{1 => 10}, {2 => 20}, {3 => 30},]);
370
371Add data to the statistics variable and set the number of samples each value
372has been built with. The data is the key of each element of the input array
373ref, while the value is the number of samples: [{data1 => smaples1}, {data2 =>
374samples2}, ...].
375
376B<NOTE:> The number of samples is only used by the smoothing function and is
377ignored otherwise. It is not equivalent to repeat count. In order to repeat
378a certain datum more than one time call add_data() like this:
379
380    my $value = 5;
381    my $repeat_count = 10;
382    $stat->add_data(
383        [ ($value) x $repeat_count ]
384    );
385
386=item $stat->get_data();
387
388Returns a copy of the data array.
389
390=item $stat->get_data_without_outliers();
391
392Returns a copy of the data array without outliers. The number minimum of
393samples to apply the outlier filtering is C<$Statistics::Descriptive::Min_samples_number>,
3944 by default.
395
396A function to detect outliers need to be defined (see C<set_outlier_filter>),
397otherwise the function will return an undef value.
398
399The filtering will act only on the most extreme value of the data set
400(i.e.: value with the highest absolute standard deviation from the mean).
401
402If there is the need to remove more than one outlier, the filtering
403need to be re-run for the next most extreme value with the initial outlier removed.
404
405This is not always needed since the test (for example Grubb's test) usually can only detect
406the most exreme value. If there is more than one extreme case in a set,
407then the standard deviation will be high enough to make neither case an outlier.
408
409=item $stat->set_outlier_filter($code_ref);
410
411Set the function to filter out the outlier.
412
413C<$code_ref> is the reference to the subroutine implementing the filtering
414function.
415
416Returns C<undef> for invalid values of C<$code_ref> (i.e.: not defined or not a
417code reference), C<1> otherwise.
418
419=over 4
420
421=item
422
423Example #1: Undefined code reference
424
425    my $stat = Statistics::Descriptive::Full->new();
426    $stat->add_data(1, 2, 3, 4, 5);
427
428    print $stat->set_outlier_filter(); # => undef
429
430=item
431
432Example #2: Valid code reference
433
434    sub outlier_filter { return $_[1] > 1; }
435
436    my $stat = Statistics::Descriptive::Full->new();
437    $stat->add_data( 1, 1, 1, 100, 1, );
438
439    print $stat->set_outlier_filter( \&outlier_filter ); # => 1
440    my @filtered_data = $stat->get_data_without_outliers();
441    # @filtered_data is (1, 1, 1, 1)
442
443In this example the series is really simple and the outlier filter function as well.
444For more complex series the outlier filter function might be more complex
445(see Grubbs' test for outliers).
446
447The outlier filter function will receive as first parameter the Statistics::Descriptive::Full object,
448as second the value of the candidate outlier. Having the object in the function
449might be useful for complex filters where statistics property are needed (again see Grubbs' test for outlier).
450
451=back
452
453=item $stat->set_smoother({ method => 'exponential', coeff => 0, });
454
455Set the method used to smooth the data and the smoothing coefficient.
456See C<Statistics::Smoother> for more details.
457
458=item $stat->get_smoothed_data();
459
460Returns a copy of the smoothed data array.
461
462The smoothing method and coefficient need to be defined (see C<set_smoother>),
463otherwise the function will return an undef value.
464
465=item $stat->sort_data();
466
467Sort the stored data and update the mindex and maxdex methods.  This
468method uses perl's internal sort.
469
470=item $stat->presorted(1);
471
472=item $stat->presorted();
473
474If called with a non-zero argument, this method sets a flag that says
475the data is already sorted and need not be sorted again.  Since some of
476the methods in this class require sorted data, this saves some time.
477If you supply sorted data to the object, call this method to prevent
478the data from being sorted again. The flag is cleared whenever add_data
479is called.  Calling the method without an argument returns the value of
480the flag.
481
482=item $stat->skewness();
483
484Returns the skewness of the data.
485A value of zero is no skew, negative is a left skewed tail,
486positive is a right skewed tail.
487This is consistent with Excel.
488
489=item $stat->kurtosis();
490
491Returns the kurtosis of the data.
492Positive is peaked, negative is flattened.
493
494=item $x = $stat->percentile(25);
495
496=item ($x, $index) = $stat->percentile(25);
497
498Sorts the data and returns the value that corresponds to the
499percentile as defined in RFC2330:
500
501=over 4
502
503=item
504
505For example, given the 6 measurements:
506
507-2, 7, 7, 4, 18, -5
508
509Then F(-8) = 0, F(-5) = 1/6, F(-5.0001) = 0, F(-4.999) = 1/6, F(7) =
5105/6, F(18) = 1, F(239) = 1.
511
512Note that we can recover the different measured values and how many
513times each occurred from F(x) -- no information regarding the range
514in values is lost.  Summarizing measurements using histograms, on the
515other hand, in general loses information about the different values
516observed, so the EDF is preferred.
517
518Using either the EDF or a histogram, however, we do lose information
519regarding the order in which the values were observed.  Whether this
520loss is potentially significant will depend on the metric being
521measured.
522
523We will use the term "percentile" to refer to the smallest value of x
524for which F(x) >= a given percentage.  So the 50th percentile of the
525example above is 4, since F(4) = 3/6 = 50%; the 25th percentile is
526-2, since F(-5) = 1/6 < 25%, and F(-2) = 2/6 >= 25%; the 100th
527percentile is 18; and the 0th percentile is -infinity, as is the 15th
528percentile, which for ease of handling and backward compatibility is returned
529as undef() by the function.
530
531Care must be taken when using percentiles to summarize a sample,
532because they can lend an unwarranted appearance of more precision
533than is really available.  Any such summary must include the sample
534size N, because any percentile difference finer than 1/N is below the
535resolution of the sample.
536
537=back
538
539(Taken from:
540I<RFC2330 - Framework for IP Performance Metrics>,
541Section 11.3.  Defining Statistical Distributions.
542RFC2330 is available from:
543L<http://www.ietf.org/rfc/rfc2330.txt> .)
544
545If the percentile method is called in a list context then it will
546also return the index of the percentile.
547
548=item $x = $stat->quantile($Type);
549
550Sorts the data and returns estimates of underlying distribution quantiles based on one
551or two order statistics from the supplied elements.
552
553This method use the same algorithm as Excel and R language (quantile B<type 7>).
554
555The generic function quantile produces sample quantiles corresponding to the given probabilities.
556
557B<$Type> is an integer value between 0 to 4 :
558
559  0 => zero quartile (Q0) : minimal value
560  1 => first quartile (Q1) : lower quartile = lowest cut off (25%) of data = 25th percentile
561  2 => second quartile (Q2) : median = it cuts data set in half = 50th percentile
562  3 => third quartile (Q3) : upper quartile = highest cut off (25%) of data, or lowest 75% = 75th percentile
563  4 => fourth quartile (Q4) : maximal value
564
565Example :
566
567  my @data = (1..10);
568  my $stat = Statistics::Descriptive::Full->new();
569  $stat->add_data(@data);
570  print $stat->quantile(0); # => 1
571  print $stat->quantile(1); # => 3.25
572  print $stat->quantile(2); # => 5.5
573  print $stat->quantile(3); # => 7.75
574  print $stat->quantile(4); # => 10
575
576=item $stat->median();
577
578Sorts the data and returns the median value of the data.
579
580=item $stat->harmonic_mean();
581
582Returns the harmonic mean of the data.  Since the mean is undefined
583if any of the data are zero or if the sum of the reciprocals is zero,
584it will return undef for both of those cases.
585
586=item $stat->geometric_mean();
587
588Returns the geometric mean of the data.
589
590=item my $mode = $stat->mode();
591
592Returns the mode of the data. The mode is the most commonly occurring datum.
593See L<http://en.wikipedia.org/wiki/Mode_%28statistics%29> . If all values
594occur only once, then mode() will return undef.
595
596=item $stat->sumsq()
597
598The sum of squares.
599
600=item $stat->trimmed_mean(ltrim[,utrim]);
601
602C<trimmed_mean(ltrim)> returns the mean with a fraction C<ltrim>
603of entries at each end dropped. C<trimmed_mean(ltrim,utrim)>
604returns the mean after a fraction C<ltrim> has been removed from the
605lower end of the data and a fraction C<utrim> has been removed from the
606upper end of the data.  This method sorts the data before beginning
607to analyze it.
608
609All calls to trimmed_mean() are cached so that they don't have to be
610calculated a second time.
611
612=item $stat->frequency_distribution_ref($partitions);
613
614=item $stat->frequency_distribution_ref(\@bins);
615
616=item $stat->frequency_distribution_ref();
617
618C<frequency_distribution_ref($partitions)> slices the data into
619C<$partition> sets (where $partition is greater than 1) and counts the
620number of items that fall into each partition. It returns a reference to
621a hash where the keys are the numerical values of the
622partitions used. The minimum value of the data set is not a key and the
623maximum value of the data set is always a key. The number of entries
624for a particular partition key are the number of items which are
625greater than the previous partition key and less then or equal to the
626current partition key. As an example,
627
628   $stat->add_data(1,1.5,2,2.5,3,3.5,4);
629   $f = $stat->frequency_distribution_ref(2);
630   for (sort {$a <=> $b} keys %$f) {
631      print "key = $_, count = $f->{$_}\n";
632   }
633
634prints
635
636   key = 2.5, count = 4
637   key = 4, count = 3
638
639since there are four items less than or equal to 2.5, and 3 items
640greater than 2.5 and less than 4.
641
642C<frequency_distribution_refs(\@bins)> provides the bins that are to be used
643for the distribution.  This allows for non-uniform distributions as
644well as trimmed or sample distributions to be found.  C<@bins> must
645be monotonic and contain at least one element.  Note that unless the
646set of bins contains the range that the total counts returned will
647be less than the sample size.
648
649Calling C<frequency_distribution_ref()> with no arguments returns the last
650distribution calculated, if such exists.
651
652=item my %hash = $stat->frequency_distribution($partitions);
653
654=item my %hash = $stat->frequency_distribution(\@bins);
655
656=item my %hash = $stat->frequency_distribution();
657
658Same as C<frequency_distribution_ref()> except that returns the hash clobbered
659into the return list. Kept for compatibility reasons with previous
660versions of Statistics::Descriptive and using it is discouraged.
661
662=item $stat->least_squares_fit();
663
664=item $stat->least_squares_fit(@x);
665
666C<least_squares_fit()> performs a least squares fit on the data,
667assuming a domain of C<@x> or a default of 1..$stat->count().  It
668returns an array of four elements C<($q, $m, $r, $rms)> where
669
670=over 4
671
672=item C<$q and $m>
673
674satisfy the equation C($y = $m*$x + $q).
675
676=item C<$r>
677
678is the Pearson linear correlation cofficient.
679
680=item C<$rms>
681
682is the root-mean-square error.
683
684=back
685
686If case of error or division by zero, the empty list is returned.
687
688The array that is returned can be "coerced" into a hash structure
689by doing the following:
690
691  my %hash = ();
692  @hash{'q', 'm', 'r', 'err'} = $stat->least_squares_fit();
693
694Because calling C<least_squares_fit()> with no arguments defaults
695to using the current range, there is no caching of the results.
696
697=back
698
699=head1 REPORTING ERRORS
700
701I read my email frequently, but since adopting this module I've added 2
702children and 1 dog to my family, so please be patient about my response
703times.  When reporting errors, please include the following to help
704me out:
705
706=over 4
707
708=item *
709
710Your version of perl.  This can be obtained by typing perl C<-v> at
711the command line.
712
713=item *
714
715Which version of Statistics::Descriptive you're using.  As you can
716see below, I do make mistakes.  Unfortunately for me, right now
717there are thousands of CD's with the version of this module with
718the bugs in it.  Fortunately for you, I'm a very patient module
719maintainer.
720
721=item *
722
723Details about what the error is.  Try to narrow down the scope
724of the problem and send me code that I can run to verify and
725track it down.
726
727=back
728
729=head1 AUTHOR
730
731Current maintainer:
732
733Shlomi Fish, L<http://www.shlomifish.org/> , C<shlomif@cpan.org>
734
735Previously:
736
737Colin Kuskie
738
739My email address can be found at http://www.perl.com under Who's Who
740or at: https://metacpan.org/author/COLINK .
741
742=head1 CONTRIBUTORS
743
744Fabio Ponciroli & Adzuna Ltd. team (outliers handling)
745
746=head1 REFERENCES
747
748RFC2330, Framework for IP Performance Metrics
749
750The Art of Computer Programming, Volume 2, Donald Knuth.
751
752Handbook of Mathematica Functions, Milton Abramowitz and Irene Stegun.
753
754Probability and Statistics for Engineering and the Sciences, Jay Devore.
755
756=head1 COPYRIGHT
757
758Copyright (c) 1997,1998 Colin Kuskie. All rights reserved.  This
759program is free software; you can redistribute it and/or modify it
760under the same terms as Perl itself.
761
762Copyright (c) 1998 Andrea Spinelli. All rights reserved.  This program
763is free software; you can redistribute it and/or modify it under the
764same terms as Perl itself.
765
766Copyright (c) 1994,1995 Jason Kastner. All rights
767reserved.  This program is free software; you can redistribute it
768and/or modify it under the same terms as Perl itself.
769
770=head1 LICENSE
771
772This program is free software; you can redistribute it and/or modify it
773under the same terms as Perl itself.
774
775=for :stopwords cpan testmatrix url bugtracker rt cpants kwalitee diff irc mailto metadata placeholders metacpan
776
777=head1 SUPPORT
778
779=head2 Websites
780
781The following websites have more information about this module, and may be of help to you. As always,
782in addition to those websites please use your favorite search engine to discover more resources.
783
784=over 4
785
786=item *
787
788MetaCPAN
789
790A modern, open-source CPAN search engine, useful to view POD in HTML format.
791
792L<https://metacpan.org/release/Statistics-Descriptive>
793
794=item *
795
796RT: CPAN's Bug Tracker
797
798The RT ( Request Tracker ) website is the default bug/issue tracking system for CPAN.
799
800L<https://rt.cpan.org/Public/Dist/Display.html?Name=Statistics-Descriptive>
801
802=item *
803
804CPANTS
805
806The CPANTS is a website that analyzes the Kwalitee ( code metrics ) of a distribution.
807
808L<http://cpants.cpanauthors.org/dist/Statistics-Descriptive>
809
810=item *
811
812CPAN Testers
813
814The CPAN Testers is a network of smoke testers who run automated tests on uploaded CPAN distributions.
815
816L<http://www.cpantesters.org/distro/S/Statistics-Descriptive>
817
818=item *
819
820CPAN Testers Matrix
821
822The CPAN Testers Matrix is a website that provides a visual overview of the test results for a distribution on various Perls/platforms.
823
824L<http://matrix.cpantesters.org/?dist=Statistics-Descriptive>
825
826=item *
827
828CPAN Testers Dependencies
829
830The CPAN Testers Dependencies is a website that shows a chart of the test results of all dependencies for a distribution.
831
832L<http://deps.cpantesters.org/?module=Statistics::Descriptive>
833
834=back
835
836=head2 Bugs / Feature Requests
837
838Please report any bugs or feature requests by email to C<bug-statistics-descriptive at rt.cpan.org>, or through
839the web interface at L<https://rt.cpan.org/Public/Bug/Report.html?Queue=Statistics-Descriptive>. You will be automatically notified of any
840progress on the request by the system.
841
842=head2 Source Code
843
844The code is open to the world, and available for you to hack on. Please feel free to browse it and play
845with it, or whatever. If you want to contribute patches, please send me a diff or prod me to pull
846from your repository :)
847
848L<https://github.com/shlomif/perl-Statistics-Descriptive>
849
850  git clone git://github.com/shlomif/perl-Statistics-Descriptive.git
851
852=head1 AUTHOR
853
854Shlomi Fish <shlomif@cpan.org>
855
856=head1 BUGS
857
858Please report any bugs or feature requests on the bugtracker website
859L<https://github.com/shlomif/perl-Statistics-Descriptive/issues>
860
861When submitting a bug or request, please include a test-file or a
862patch to an existing test-file that illustrates the bug or desired
863feature.
864
865=head1 COPYRIGHT AND LICENSE
866
867This software is copyright (c) 1997 by Jason Kastner, Andrea Spinelli, Colin Kuskie, and others.
868
869This is free software; you can redistribute it and/or modify it under
870the same terms as the Perl 5 programming language system itself.
871
872=cut
873