summaryrefslogtreecommitdiff
path: root/README.md
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2015-06-10 13:07:28 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2015-06-10 13:07:28 +0000
commit7f3c4eb624730bcc71e75500f295d193b9375fbc (patch)
treed32421911d2531642810e464183757eb485d9a09 /README.md
downloadList-MoreUtils-tarball-7f3c4eb624730bcc71e75500f295d193b9375fbc.tar.gz
List-MoreUtils-0.413HEADList-MoreUtils-0.413master
Diffstat (limited to 'README.md')
-rw-r--r--README.md722
1 files changed, 722 insertions, 0 deletions
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..7bbe8ca
--- /dev/null
+++ b/README.md
@@ -0,0 +1,722 @@
+# NAME
+
+List::MoreUtils - Provide the stuff missing in List::Util
+
+# SYNOPSIS
+
+ # import specific functions
+
+ use List::MoreUtils qw(any uniq);
+
+ if ( any { /foo/ } uniq @has_duplicates ) {
+ # do stuff
+ }
+
+ # import everything
+
+ use List::MoreUtils ':all';
+
+ # import by API
+
+ # has "original" any/all/none/notall behavior
+ use List::MoreUtils ':like_0.22';
+ # 0.22 + bsearch
+ use List::MoreUtils ':like_0.24';
+ # has "simplified" any/all/none/notall behavior + (n)sort_by
+ use List::MoreUtils ':like_0.33';
+
+# DESCRIPTION
+
+__List::MoreUtils__ provides some trivial but commonly needed functionality on
+lists which is not going to go into [List::Util](https://metacpan.org/pod/List::Util).
+
+All of the below functions are implementable in only a couple of lines of Perl
+code. Using the functions from this module however should give slightly better
+performance as everything is implemented in C. The pure-Perl implementation of
+these functions only serves as a fallback in case the C portions of this module
+couldn't be compiled on this machine.
+
+# EXPORTS
+
+## Default behavior
+
+Nothing by default. To import all of this module's symbols use the `:all` tag.
+Otherwise functions can be imported by name as usual:
+
+ use List::MoreUtils ':all';
+
+ use List::MoreUtils qw{ any firstidx };
+
+Because historical changes to the API might make upgrading List::MoreUtils
+difficult for some projects, the legacy API is available via special import
+tags.
+
+## Like version 0.22 (last release with original API)
+
+This API was available from 2006 to 2009, returning undef for empty lists on
+`all`/`any`/`none`/`notall`:
+
+ use List::MoreUtils ':like_0.22';
+
+This import tag will import all functions available as of version 0.22.
+However, it will import `any_u` as `any`, `all_u` as `all`, `none_u` as
+`none`, and `notall_u` as `notall`.
+
+## Like version 0.24 (first incompatible change)
+
+This API was available from 2010 to 2011. It changed the return value of `none`
+and added the `bsearch` function.
+
+ use List::MoreUtils ':like_0.24';
+
+This import tag will import all functions available as of version 0.24.
+However it will import `any_u` as `any`, `all_u` as `all`, and
+`notall_u` as `notall`. It will import `none` as described in
+the documentation below (true for empty list).
+
+## Like version 0.33 (second incompatible change)
+
+This API was available from 2011 to 2014. It is widely used in several CPAN
+modules and thus it's closest to the current API. It changed the return values
+of `any`, `all`, and `notall`. It added the `sort_by` and `nsort_by` functions
+and the `distinct` alias for `uniq`. It omitted `bsearch`.
+
+ use List::MoreUtils ':like_0.33';
+
+This import tag will import all functions available as of version 0.33. Note:
+it will not import `bsearch` for consistency with the 0.33 API.
+
+# FUNCTIONS
+
+## Junctions
+
+### _Treatment of an empty list_
+
+There are two schools of thought for how to evaluate a junction on an
+empty list:
+
+- Reduction to an identity (boolean)
+- Result is undefined (three-valued)
+
+In the first case, the result of the junction applied to the empty list is
+determined by a mathematical reduction to an identity depending on whether
+the underlying comparison is "or" or "and". Conceptually:
+
+ "any are true" "all are true"
+ -------------- --------------
+ 2 elements: A || B || 0 A && B && 1
+ 1 element: A || 0 A && 1
+ 0 elements: 0 1
+
+In the second case, three-value logic is desired, in which a junction
+applied to an empty list returns `undef` rather than true or false
+
+Junctions with a `_u` suffix implement three-valued logic. Those
+without are boolean.
+
+### all BLOCK LIST
+
+### all\_u BLOCK LIST
+
+Returns a true value if all items in LIST meet the criterion given through
+BLOCK. Sets `$_` for each item in LIST in turn:
+
+ print "All values are non-negative"
+ if all { $_ >= 0 } ($x, $y, $z);
+
+For an empty LIST, `all` returns true (i.e. no values failed the condition)
+and `all_u` returns `undef`.
+
+Thus, `all_u(@list)` is equivalent to `@list ? all(@list) : undef`.
+
+__Note__: because Perl treats `undef` as false, you must check the return value
+of `all_u` with `defined` or you will get the opposite result of what you
+expect.
+
+### any BLOCK LIST
+
+### any\_u BLOCK LIST
+
+Returns a true value if any item in LIST meets the criterion given through
+BLOCK. Sets `$_` for each item in LIST in turn:
+
+ print "At least one non-negative value"
+ if any { $_ >= 0 } ($x, $y, $z);
+
+For an empty LIST, `any` returns false and `any_u` returns `undef`.
+
+Thus, `any_u(@list)` is equivalent to `@list ? any(@list) : undef`.
+
+### none BLOCK LIST
+
+### none\_u BLOCK LIST
+
+Logically the negation of `any`. Returns a true value if no item in LIST meets
+the criterion given through BLOCK. Sets `$_` for each item in LIST in turn:
+
+ print "No non-negative values"
+ if none { $_ >= 0 } ($x, $y, $z);
+
+For an empty LIST, `none` returns true (i.e. no values failed the condition)
+and `none_u` returns `undef`.
+
+Thus, `none_u(@list)` is equivalent to `@list ? none(@list) : undef`.
+
+__Note__: because Perl treats `undef` as false, you must check the return value
+of `none_u` with `defined` or you will get the opposite result of what you
+expect.
+
+### notall BLOCK LIST
+
+### notall\_u BLOCK LIST
+
+Logically the negation of `all`. Returns a true value if not all items in LIST
+meet the criterion given through BLOCK. Sets `$_` for each item in LIST in
+turn:
+
+ print "Not all values are non-negative"
+ if notall { $_ >= 0 } ($x, $y, $z);
+
+For an empty LIST, `notall` returns false and `notall_u` returns `undef`.
+
+Thus, `notall_u(@list)` is equivalent to `@list ? notall(@list) : undef`.
+
+## Transformation
+
+### apply BLOCK LIST
+
+Applies BLOCK to each item in LIST and returns a list of the values after BLOCK
+has been applied. In scalar context, the last element is returned. This
+function is similar to `map` but will not modify the elements of the input
+list:
+
+ my @list = (1 .. 4);
+ my @mult = apply { $_ *= 2 } @list;
+ print "\@list = @list\n";
+ print "\@mult = @mult\n";
+ __END__
+ @list = 1 2 3 4
+ @mult = 2 4 6 8
+
+Think of it as syntactic sugar for
+
+ for (my @mult = @list) { $_ *= 2 }
+
+### insert\_after BLOCK VALUE LIST
+
+Inserts VALUE after the first item in LIST for which the criterion in BLOCK is
+true. Sets `$_` for each item in LIST in turn.
+
+ my @list = qw/This is a list/;
+ insert_after { $_ eq "a" } "longer" => @list;
+ print "@list";
+ __END__
+ This is a longer list
+
+### insert\_after\_string STRING VALUE LIST
+
+Inserts VALUE after the first item in LIST which is equal to STRING.
+
+ my @list = qw/This is a list/;
+ insert_after_string "a", "longer" => @list;
+ print "@list";
+ __END__
+ This is a longer list
+
+### pairwise BLOCK ARRAY1 ARRAY2
+
+Evaluates BLOCK for each pair of elements in ARRAY1 and ARRAY2 and returns a
+new list consisting of BLOCK's return values. The two elements are set to `$a`
+and `$b`. Note that those two are aliases to the original value so changing
+them will modify the input arrays.
+
+ @a = (1 .. 5);
+ @b = (11 .. 15);
+ @x = pairwise { $a + $b } @a, @b; # returns 12, 14, 16, 18, 20
+
+ # mesh with pairwise
+ @a = qw/a b c/;
+ @b = qw/1 2 3/;
+ @x = pairwise { ($a, $b) } @a, @b; # returns a, 1, b, 2, c, 3
+
+### mesh ARRAY1 ARRAY2 \[ ARRAY3 ... \]
+
+### zip ARRAY1 ARRAY2 \[ ARRAY3 ... \]
+
+Returns a list consisting of the first elements of each array, then
+the second, then the third, etc, until all arrays are exhausted.
+
+Examples:
+
+ @x = qw/a b c d/;
+ @y = qw/1 2 3 4/;
+ @z = mesh @x, @y; # returns a, 1, b, 2, c, 3, d, 4
+
+ @a = ('x');
+ @b = ('1', '2');
+ @c = qw/zip zap zot/;
+ @d = mesh @a, @b, @c; # x, 1, zip, undef, 2, zap, undef, undef, zot
+
+`zip` is an alias for `mesh`.
+
+### uniq LIST
+
+### distinct LIST
+
+Returns a new list by stripping duplicate values in LIST. The order of
+elements in the returned list is the same as in LIST. In scalar context,
+returns the number of unique elements in LIST.
+
+ my @x = uniq 1, 1, 2, 2, 3, 5, 3, 4; # returns 1 2 3 5 4
+ my $x = uniq 1, 1, 2, 2, 3, 5, 3, 4; # returns 5
+
+`distinct` is an alias for `uniq`.
+
+## Partitioning
+
+### after BLOCK LIST
+
+Returns a list of the values of LIST after (and not including) the point
+where BLOCK returns a true value. Sets `$_` for each element in LIST in turn.
+
+ @x = after { $_ % 5 == 0 } (1..9); # returns 6, 7, 8, 9
+
+### after\_incl BLOCK LIST
+
+Same as `after` but also includes the element for which BLOCK is true.
+
+### before BLOCK LIST
+
+Returns a list of values of LIST up to (and not including) the point where BLOCK
+returns a true value. Sets `$_` for each element in LIST in turn.
+
+### before\_incl BLOCK LIST
+
+Same as `before` but also includes the element for which BLOCK is true.
+
+### part BLOCK LIST
+
+Partitions LIST based on the return value of BLOCK which denotes into which
+partition the current value is put.
+
+Returns a list of the partitions thusly created. Each partition created is a
+reference to an array.
+
+ my $i = 0;
+ my @part = part { $i++ % 2 } 1 .. 8; # returns [1, 3, 5, 7], [2, 4, 6, 8]
+
+You can have a sparse list of partitions as well where non-set partitions will
+be undef:
+
+ my @part = part { 2 } 1 .. 10; # returns undef, undef, [ 1 .. 10 ]
+
+Be careful with negative values, though:
+
+ my @part = part { -1 } 1 .. 10;
+ __END__
+ Modification of non-creatable array value attempted, subscript -1 ...
+
+Negative values are only ok when they refer to a partition previously created:
+
+ my @idx = ( 0, 1, -1 );
+ my $i = 0;
+ my @part = part { $idx[$++ % 3] } 1 .. 8; # [1, 4, 7], [2, 3, 5, 6, 8]
+
+## Iteration
+
+### each\_array ARRAY1 ARRAY2 ...
+
+Creates an array iterator to return the elements of the list of arrays ARRAY1,
+ARRAY2 throughout ARRAYn in turn. That is, the first time it is called, it
+returns the first element of each array. The next time, it returns the second
+elements. And so on, until all elements are exhausted.
+
+This is useful for looping over more than one array at once:
+
+ my $ea = each_array(@a, @b, @c);
+ while ( my ($a, $b, $c) = $ea->() ) { .... }
+
+The iterator returns the empty list when it reached the end of all arrays.
+
+If the iterator is passed an argument of '`index`', then it returns
+the index of the last fetched set of values, as a scalar.
+
+### each\_arrayref LIST
+
+Like each\_array, but the arguments are references to arrays, not the
+plain arrays.
+
+### natatime EXPR, LIST
+
+Creates an array iterator, for looping over an array in chunks of
+`$n` items at a time. (n at a time, get it?). An example is
+probably a better explanation than I could give in words.
+
+Example:
+
+ my @x = ('a' .. 'g');
+ my $it = natatime 3, @x;
+ while (my @vals = $it->())
+ {
+ print "@vals\n";
+ }
+
+This prints
+
+ a b c
+ d e f
+ g
+
+## Searching
+
+### bsearch BLOCK LIST
+
+Performs a binary search on LIST which must be a sorted list of values. BLOCK
+must return a negative value if the current element (stored in `$_`) is smaller,
+a positive value if it is bigger and zero if it matches.
+
+Returns a boolean value in scalar context. In list context, it returns the element
+if it was found, otherwise the empty list.
+
+### firstval BLOCK LIST
+
+### first\_value BLOCK LIST
+
+Returns the first element in LIST for which BLOCK evaluates to true. Each
+element of LIST is set to `$_` in turn. Returns `undef` if no such element
+has been found.
+
+`first_value` is an alias for `firstval`.
+
+### lastval BLOCK LIST
+
+### last\_value BLOCK LIST
+
+Returns the last value in LIST for which BLOCK evaluates to true. Each element
+of LIST is set to `$_` in turn. Returns `undef` if no such element has been
+found.
+
+`last_value` is an alias for `lastval`.
+
+### indexes BLOCK LIST
+
+Evaluates BLOCK for each element in LIST (assigned to `$_`) and returns a list
+of the indices of those elements for which BLOCK returned a true value. This is
+just like `grep` only that it returns indices instead of values:
+
+ @x = indexes { $_ % 2 == 0 } (1..10); # returns 1, 3, 5, 7, 9
+
+### firstidx BLOCK LIST
+
+### first\_index BLOCK LIST
+
+Returns the index of the first element in LIST for which the criterion in BLOCK
+is true. Sets `$_` for each item in LIST in turn:
+
+ my @list = (1, 4, 3, 2, 4, 6);
+ printf "item with index %i in list is 4", firstidx { $_ == 4 } @list;
+ __END__
+ item with index 1 in list is 4
+
+
+Returns `-1` if no such item could be found.
+
+`first_index` is an alias for `firstidx`.
+
+### lastidx BLOCK LIST
+
+### last\_index BLOCK LIST
+
+Returns the index of the last element in LIST for which the criterion in BLOCK
+is true. Sets `$_` for each item in LIST in turn:
+
+ my @list = (1, 4, 3, 2, 4, 6);
+ printf "item with index %i in list is 4", lastidx { $_ == 4 } @list;
+ __END__
+ item with index 4 in list is 4
+
+Returns `-1` if no such item could be found.
+
+`last_index` is an alias for `lastidx`.
+
+## Sorting
+
+### sort\_by BLOCK LIST
+
+Returns the list of values sorted according to the string values returned by the
+KEYFUNC block or function. A typical use of this may be to sort objects according
+to the string value of some accessor, such as
+
+ sort_by { $_->name } @people
+
+The key function is called in scalar context, being passed each value in turn as
+both $\_ and the only argument in the parameters, @\_. The values are then sorted
+according to string comparisons on the values returned.
+This is equivalent to
+
+ sort { $a->name cmp $b->name } @people
+
+except that it guarantees the name accessor will be executed only once per value.
+One interesting use-case is to sort strings which may have numbers embedded in them
+"naturally", rather than lexically.
+
+ sort_by { s/(\d+)/sprintf "%09d", $1/eg; $_ } @strings
+
+This sorts strings by generating sort keys which zero-pad the embedded numbers to
+some level (9 digits in this case), helping to ensure the lexical sort puts them
+in the correct order.
+
+### nsort\_by BLOCK LIST
+
+Similar to sort\_by but compares its key values numerically.
+
+## Counting and calculation
+
+### true BLOCK LIST
+
+Counts the number of elements in LIST for which the criterion in BLOCK is true.
+Sets `$_` for each item in LIST in turn:
+
+ printf "%i item(s) are defined", true { defined($_) } @list;
+
+### false BLOCK LIST
+
+Counts the number of elements in LIST for which the criterion in BLOCK is false.
+Sets `$_` for each item in LIST in turn:
+
+ printf "%i item(s) are not defined", false { defined($_) } @list;
+
+### minmax LIST
+
+Calculates the minimum and maximum of LIST and returns a two element list with
+the first element being the minimum and the second the maximum. Returns the
+empty list if LIST was empty.
+
+The `minmax` algorithm differs from a naive iteration over the list where each
+element is compared to two values being the so far calculated min and max value
+in that it only requires 3n/2 - 2 comparisons. Thus it is the most efficient
+possible algorithm.
+
+However, the Perl implementation of it has some overhead simply due to the fact
+that there are more lines of Perl code involved. Therefore, LIST needs to be
+fairly big in order for `minmax` to win over a naive implementation. This
+limitation does not apply to the XS version.
+
+# ENVIRONMENT
+
+When `LIST_MOREUTILS_PP` is set, the module will always use the pure-Perl
+implementation and not the XS one. This environment variable is really just
+there for the test-suite to force testing the Perl implementation, and possibly
+for reporting of bugs. I don't see any reason to use it in a production
+environment.
+
+# MAINTENANCE
+
+The maintenance goal is to preserve the documented semantics of the API;
+bug fixes that bring actual behavior in line with semantics are allowed.
+New API functions may be added over time. If a backwards incompatible
+change is unavoidable, we will attempt to provide support for the legacy
+API using the same export tag mechanism currently in place.
+
+This module attempts to use few non-core dependencies. Non-core
+configuration and testing modules will be bundled when reasonable;
+run-time dependencies will be added only if they deliver substantial
+benefit.
+
+# BUGS
+
+There is a problem with a bug in 5.6.x perls. It is a syntax error to write
+things like:
+
+ my @x = apply { s/foo/bar/ } qw{ foo bar baz };
+
+It has to be written as either
+
+ my @x = apply { s/foo/bar/ } 'foo', 'bar', 'baz';
+
+or
+
+ my @x = apply { s/foo/bar/ } my @dummy = qw/foo bar baz/;
+
+Perl 5.5.x and Perl 5.8.x don't suffer from this limitation.
+
+If you have a functionality that you could imagine being in this module, please
+drop me a line. This module's policy will be less strict than [List::Util](https://metacpan.org/pod/List::Util)'s
+when it comes to additions as it isn't a core module.
+
+When you report bugs, it would be nice if you could additionally give me the
+output of your program with the environment variable `LIST_MOREUTILS_PP` set
+to a true value. That way I know where to look for the problem (in XS,
+pure-Perl or possibly both).
+
+# SUPPORT
+
+Bugs should always be submitted via the CPAN bug tracker.
+
+You can find documentation for this module with the perldoc command.
+
+ perldoc List::MoreUtils
+
+You can also look for information at:
+
+- RT: CPAN's request tracker
+
+ [http://rt.cpan.org/NoAuth/Bugs.html?Dist=List-MoreUtils](http://rt.cpan.org/NoAuth/Bugs.html?Dist=List-MoreUtils)
+
+- AnnoCPAN: Annotated CPAN documentation
+
+ [http://annocpan.org/dist/List-MoreUtils](http://annocpan.org/dist/List-MoreUtils)
+
+- CPAN Ratings
+
+ [http://cpanratings.perl.org/l/List-MoreUtils](http://cpanratings.perl.org/l/List-MoreUtils)
+
+- CPAN Search
+
+ [http://search.cpan.org/dist/List-MoreUtils/](http://search.cpan.org/dist/List-MoreUtils/)
+
+- Git Repository
+
+ [https://github.com/perl5-utils/List-MoreUtils](https://github.com/perl5-utils/List-MoreUtils)
+
+## Where can I go for help?
+
+If you have a bug report, a patch or a suggestion, please open a new
+report ticket at CPAN (but please check previous reports first in case
+your issue has already been addressed) or open an issue on GitHub.
+
+Report tickets should contain a detailed description of the bug or
+enhancement request and at least an easily verifiable way of
+reproducing the issue or fix. Patches are always welcome, too - and
+it's cheap to send pull-requests on GitHub. Please keep in mind that
+code changes are more likely accepted when they're bundled with an
+approving test.
+
+If you think you've found a bug then please read
+"How to Report Bugs Effectively" by Simon Tatham:
+[http://www.chiark.greenend.org.uk/~sgtatham/bugs.html](http://www.chiark.greenend.org.uk/~sgtatham/bugs.html).
+
+## Where can I go for help with a concrete version?
+
+Bugs and feature requests are accepted against the latest version
+only. To get patches for earlier versions, you need to get an
+agreement with a developer of your choice - who may or not report the
+issue and a suggested fix upstream (depends on the license you have
+chosen).
+
+## Business support and maintenance
+
+Generally, in volunteered projects, there is no right for support.
+While every maintainer is happy to improve the provided software,
+spare time is limited.
+
+For those who have a use case which requires guaranteed support, one of
+the maintainers should be hired or contracted. For business support you
+can contact Jens via his CPAN email address rehsackATcpan.org. Please
+keep in mind that business support is neither available for free nor
+are you eligible to receive any support based on the license distributed
+with this package.
+
+# THANKS
+
+## Tassilo von Parseval
+
+Credits go to a number of people: Steve Purkis for giving me namespace advice
+and James Keenan and Terrence Branno for their effort of keeping the CPAN
+tidier by making [List::Utils](https://metacpan.org/pod/List::Utils) obsolete.
+
+Brian McCauley suggested the inclusion of apply() and provided the pure-Perl
+implementation for it.
+
+Eric J. Roode asked me to add all functions from his module `List::MoreUtil`
+into this one. With minor modifications, the pure-Perl implementations of those
+are by him.
+
+The bunch of people who almost immediately pointed out the many problems with
+the glitchy 0.07 release (Slaven Rezic, Ron Savage, CPAN testers).
+
+A particularly nasty memory leak was spotted by Thomas A. Lowery.
+
+Lars Thegler made me aware of problems with older Perl versions.
+
+Anno Siegel de-orphaned each\_arrayref().
+
+David Filmer made me aware of a problem in each\_arrayref that could ultimately
+lead to a segfault.
+
+Ricardo Signes suggested the inclusion of part() and provided the
+Perl-implementation.
+
+Robin Huston kindly fixed a bug in perl's MULTICALL API to make the
+XS-implementation of part() work.
+
+## Jens Rehsack
+
+Credits goes to all people contributing feedback during the v0.400
+development releases.
+
+Special thanks goes to David Golden who spent a lot of effort to develop
+a design to support current state of CPAN as well as ancient software
+somewhere in the dark. He also contributed a lot of patches to refactor
+the API frontend to welcome any user of List::MoreUtils - from ancient
+past to recently last used.
+
+Toby Inkster provided a lot of useful feedback for sane importer code
+and was a nice sounding board for API discussions.
+
+Peter Rabbitson provided a sane git repository setup containing entire
+package history.
+
+# TODO
+
+A pile of requests from other people is still pending further processing in
+my mailbox. This includes:
+
+- List::Util export pass-through
+
+ Allow __List::MoreUtils__ to pass-through the regular [List::Util](https://metacpan.org/pod/List::Util)
+ functions to end users only need to `use` the one module.
+
+- uniq\_by(&@)
+
+ Use code-reference to extract a key based on which the uniqueness is
+ determined. Suggested by Aaron Crane.
+
+- delete\_index
+- random\_item
+- random\_item\_delete\_index
+- list\_diff\_hash
+- list\_diff\_inboth
+- list\_diff\_infirst
+- list\_diff\_insecond
+
+ These were all suggested by Dan Muey.
+
+- listify
+
+ Always return a flat list when either a simple scalar value was passed or an
+ array-reference. Suggested by Mark Summersault.
+
+# SEE ALSO
+
+[List::Util](https://metacpan.org/pod/List::Util), [List::AllUtils](https://metacpan.org/pod/List::AllUtils), [List::UtilsBy](https://metacpan.org/pod/List::UtilsBy)
+
+# AUTHOR
+
+Jens Rehsack <rehsack AT cpan.org>
+
+Adam Kennedy <adamk@cpan.org>
+
+Tassilo von Parseval <tassilo.von.parseval@rwth-aachen.de>
+
+# COPYRIGHT AND LICENSE
+
+Some parts copyright 2011 Aaron Crane.
+
+Copyright 2004 - 2010 by Tassilo von Parseval
+
+Copyright 2013 - 2015 by Jens Rehsack
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself, either Perl version 5.8.4 or,
+at your option, any later version of Perl 5 you may have available.