diff options
Diffstat (limited to 'Master/tlpkg/tlperl/site/lib/Digest/SHA.pm')
-rw-r--r-- | Master/tlpkg/tlperl/site/lib/Digest/SHA.pm | 820 |
1 files changed, 820 insertions, 0 deletions
diff --git a/Master/tlpkg/tlperl/site/lib/Digest/SHA.pm b/Master/tlpkg/tlperl/site/lib/Digest/SHA.pm new file mode 100644 index 00000000000..dccc0e7aeb3 --- /dev/null +++ b/Master/tlpkg/tlperl/site/lib/Digest/SHA.pm @@ -0,0 +1,820 @@ +package Digest::SHA; + +require 5.003000; + +use strict; +use warnings; +use vars qw($VERSION @ISA @EXPORT_OK $errmsg); +use Fcntl qw(O_RDONLY O_RDWR); +use integer; + +$VERSION = '6.02'; + +require Exporter; +@ISA = qw(Exporter); +@EXPORT_OK = qw( + $errmsg + hmac_sha1 hmac_sha1_base64 hmac_sha1_hex + hmac_sha224 hmac_sha224_base64 hmac_sha224_hex + hmac_sha256 hmac_sha256_base64 hmac_sha256_hex + hmac_sha384 hmac_sha384_base64 hmac_sha384_hex + hmac_sha512 hmac_sha512_base64 hmac_sha512_hex + hmac_sha512224 hmac_sha512224_base64 hmac_sha512224_hex + hmac_sha512256 hmac_sha512256_base64 hmac_sha512256_hex + sha1 sha1_base64 sha1_hex + sha224 sha224_base64 sha224_hex + sha256 sha256_base64 sha256_hex + sha384 sha384_base64 sha384_hex + sha512 sha512_base64 sha512_hex + sha512224 sha512224_base64 sha512224_hex + sha512256 sha512256_base64 sha512256_hex); + +# Inherit from Digest::base if possible + +eval { + require Digest::base; + push(@ISA, 'Digest::base'); +}; + +# The following routines aren't time-critical, so they can be left in Perl + +sub new { + my($class, $alg) = @_; + $alg =~ s/\D+//g if defined $alg; + if (ref($class)) { # instance method + if (!defined($alg) || ($alg == $class->algorithm)) { + sharewind($class); + return($class); + } + return shainit($class, $alg) ? $class : undef; + } + $alg = 1 unless defined $alg; + return $class->newSHA($alg); +} + +BEGIN { *reset = \&new } + +sub add_bits { + my($self, $data, $nbits) = @_; + unless (defined $nbits) { + $nbits = length($data); + $data = pack("B*", $data); + } + $nbits = length($data) * 8 if $nbits > length($data) * 8; + shawrite($data, $nbits, $self); + return($self); +} + +sub _bail { + my $msg = shift; + + $errmsg = $!; + $msg .= ": $!"; + require Carp; + Carp::croak($msg); +} + +{ + my $_can_T_filehandle; + + sub _istext { + local *FH = shift; + my $file = shift; + + if (! defined $_can_T_filehandle) { + local $^W = 0; + my $istext = eval { -T FH }; + $_can_T_filehandle = $@ ? 0 : 1; + return $_can_T_filehandle ? $istext : -T $file; + } + return $_can_T_filehandle ? -T FH : -T $file; + } +} + +sub _addfile { + my ($self, $handle) = @_; + + my $n; + my $buf = ""; + + while (($n = read($handle, $buf, 4096))) { + $self->add($buf); + } + _bail("Read failed") unless defined $n; + + $self; +} + +sub addfile { + my ($self, $file, $mode) = @_; + + return(_addfile($self, $file)) unless ref(\$file) eq 'SCALAR'; + + $mode = defined($mode) ? $mode : ""; + my ($binary, $UNIVERSAL, $BITS) = + map { $_ eq $mode } ("b", "U", "0"); + + ## Always interpret "-" to mean STDIN; otherwise use + ## sysopen to handle full range of POSIX file names. + ## If $file is a directory, force an EISDIR error + ## by attempting to open with mode O_RDWR + + local *FH; + $file eq '-' and open(FH, '< -') + or sysopen(FH, $file, -d $file ? O_RDWR : O_RDONLY) + or _bail('Open failed'); + + if ($BITS) { + my ($n, $buf) = (0, ""); + while (($n = read(FH, $buf, 4096))) { + $buf =~ tr/01//cd; + $self->add_bits($buf); + } + _bail("Read failed") unless defined $n; + close(FH); + return($self); + } + + binmode(FH) if $binary || $UNIVERSAL; + if ($UNIVERSAL && _istext(*FH, $file)) { + $self->_addfileuniv(*FH); + } + else { $self->_addfilebin(*FH) } + close(FH); + + $self; +} + +sub getstate { + my $self = shift; + + my $alg = $self->algorithm or return; + my $state = $self->_getstate or return; + my $nD = $alg <= 256 ? 8 : 16; + my $nH = $alg <= 256 ? 32 : 64; + my $nB = $alg <= 256 ? 64 : 128; + my($H, $block, $blockcnt, $lenhh, $lenhl, $lenlh, $lenll) = + $state =~ /^(.{$nH})(.{$nB})(.{4})(.{4})(.{4})(.{4})(.{4})$/s; + for ($alg, $H, $block, $blockcnt, $lenhh, $lenhl, $lenlh, $lenll) { + return unless defined $_; + } + + my @s = (); + push(@s, "alg:" . $alg); + push(@s, "H:" . join(":", unpack("H*", $H) =~ /.{$nD}/g)); + push(@s, "block:" . join(":", unpack("H*", $block) =~ /.{2}/g)); + push(@s, "blockcnt:" . unpack("N", $blockcnt)); + push(@s, "lenhh:" . unpack("N", $lenhh)); + push(@s, "lenhl:" . unpack("N", $lenhl)); + push(@s, "lenlh:" . unpack("N", $lenlh)); + push(@s, "lenll:" . unpack("N", $lenll)); + join("\n", @s) . "\n"; +} + +sub putstate { + my($class, $state) = @_; + + my %s = (); + for (split(/\n/, $state)) { + s/^\s+//; + s/\s+$//; + next if (/^(#|$)/); + my @f = split(/[:\s]+/); + my $tag = shift(@f); + $s{$tag} = join('', @f); + } + + # H and block may contain arbitrary values, but check everything else + grep { $_ == $s{'alg'} } (1,224,256,384,512,512224,512256) or return; + length($s{'H'}) == ($s{'alg'} <= 256 ? 64 : 128) or return; + length($s{'block'}) == ($s{'alg'} <= 256 ? 128 : 256) or return; + { + no integer; + for (qw(blockcnt lenhh lenhl lenlh lenll)) { + 0 <= $s{$_} or return; + $s{$_} <= 4294967295 or return; + } + $s{'blockcnt'} < ($s{'alg'} <= 256 ? 512 : 1024) or return; + } + + my $packed_state = ( + pack("H*", $s{'H'}) . + pack("H*", $s{'block'}) . + pack("N", $s{'blockcnt'}) . + pack("N", $s{'lenhh'}) . + pack("N", $s{'lenhl'}) . + pack("N", $s{'lenlh'}) . + pack("N", $s{'lenll'}) + ); + + return $class->new($s{'alg'})->_putstate($packed_state); +} + +sub dump { + my $self = shift; + my $file = shift; + + my $state = $self->getstate or return; + $file = "-" if (!defined($file) || $file eq ""); + + local *FH; + open(FH, "> $file") or return; + print FH $state; + close(FH); + + return($self); +} + +sub load { + my $class = shift; + my $file = shift; + + $file = "-" if (!defined($file) || $file eq ""); + + local *FH; + open(FH, "< $file") or return; + my $str = join('', <FH>); + close(FH); + + $class->putstate($str); +} + +eval { + require XSLoader; + XSLoader::load('Digest::SHA', $VERSION); + 1; +} or do { + require DynaLoader; + push @ISA, 'DynaLoader'; + Digest::SHA->bootstrap($VERSION); +}; + +1; +__END__ + +=head1 NAME + +Digest::SHA - Perl extension for SHA-1/224/256/384/512 + +=head1 SYNOPSIS + +In programs: + + # Functional interface + + use Digest::SHA qw(sha1 sha1_hex sha1_base64 ...); + + $digest = sha1($data); + $digest = sha1_hex($data); + $digest = sha1_base64($data); + + $digest = sha256($data); + $digest = sha384_hex($data); + $digest = sha512_base64($data); + + # Object-oriented + + use Digest::SHA; + + $sha = Digest::SHA->new($alg); + + $sha->add($data); # feed data into stream + + $sha->addfile(*F); + $sha->addfile($filename); + + $sha->add_bits($bits); + $sha->add_bits($data, $nbits); + + $sha_copy = $sha->clone; # make copy of digest object + $state = $sha->getstate; # save current state to string + $sha->putstate($state); # restore previous $state + + $digest = $sha->digest; # compute digest + $digest = $sha->hexdigest; + $digest = $sha->b64digest; + +From the command line: + + $ shasum files + + $ shasum --help + +=head1 SYNOPSIS (HMAC-SHA) + + # Functional interface only + + use Digest::SHA qw(hmac_sha1 hmac_sha1_hex ...); + + $digest = hmac_sha1($data, $key); + $digest = hmac_sha224_hex($data, $key); + $digest = hmac_sha256_base64($data, $key); + +=head1 ABSTRACT + +Digest::SHA is a complete implementation of the NIST Secure Hash Standard. +It gives Perl programmers a convenient way to calculate SHA-1, SHA-224, +SHA-256, SHA-384, SHA-512, SHA-512/224, and SHA-512/256 message digests. +The module can handle all types of input, including partial-byte data. + +=head1 DESCRIPTION + +Digest::SHA is written in C for speed. If your platform lacks a +C compiler, you can install the functionally equivalent (but much +slower) L<Digest::SHA::PurePerl> module. + +The programming interface is easy to use: it's the same one found +in CPAN's L<Digest> module. So, if your applications currently +use L<Digest::MD5> and you'd prefer the stronger security of SHA, +it's a simple matter to convert them. + +The interface provides two ways to calculate digests: all-at-once, +or in stages. To illustrate, the following short program computes +the SHA-256 digest of "hello world" using each approach: + + use Digest::SHA qw(sha256_hex); + + $data = "hello world"; + @frags = split(//, $data); + + # all-at-once (Functional style) + $digest1 = sha256_hex($data); + + # in-stages (OOP style) + $state = Digest::SHA->new(256); + for (@frags) { $state->add($_) } + $digest2 = $state->hexdigest; + + print $digest1 eq $digest2 ? + "whew!\n" : "oops!\n"; + +To calculate the digest of an n-bit message where I<n> is not a +multiple of 8, use the I<add_bits()> method. For example, consider +the 446-bit message consisting of the bit-string "110" repeated +148 times, followed by "11". Here's how to display its SHA-1 +digest: + + use Digest::SHA; + $bits = "110" x 148 . "11"; + $sha = Digest::SHA->new(1)->add_bits($bits); + print $sha->hexdigest, "\n"; + +Note that for larger bit-strings, it's more efficient to use the +two-argument version I<add_bits($data, $nbits)>, where I<$data> is +in the customary packed binary format used for Perl strings. + +The module also lets you save intermediate SHA states to a string. The +I<getstate()> method generates portable, human-readable text describing +the current state of computation. You can subsequently restore that +state with I<putstate()> to resume where the calculation left off. + +To see what a state description looks like, just run the following: + + use Digest::SHA; + print Digest::SHA->new->add("Shaw" x 1962)->getstate; + +As an added convenience, the Digest::SHA module offers routines to +calculate keyed hashes using the HMAC-SHA-1/224/256/384/512 +algorithms. These services exist in functional form only, and +mimic the style and behavior of the I<sha()>, I<sha_hex()>, and +I<sha_base64()> functions. + + # Test vector from draft-ietf-ipsec-ciph-sha-256-01.txt + + use Digest::SHA qw(hmac_sha256_hex); + print hmac_sha256_hex("Hi There", chr(0x0b) x 32), "\n"; + +=head1 UNICODE AND SIDE EFFECTS + +Perl supports Unicode strings as of version 5.6. Such strings may +contain wide characters, namely, characters whose ordinal values are +greater than 255. This can cause problems for digest algorithms such +as SHA that are specified to operate on sequences of bytes. + +The rule by which Digest::SHA handles a Unicode string is easy +to state, but potentially confusing to grasp: the string is interpreted +as a sequence of byte values, where each byte value is equal to the +ordinal value (viz. code point) of its corresponding Unicode character. +That way, the Unicode string 'abc' has exactly the same digest value as +the ordinary string 'abc'. + +Since a wide character does not fit into a byte, the Digest::SHA +routines croak if they encounter one. Whereas if a Unicode string +contains no wide characters, the module accepts it quite happily. +The following code illustrates the two cases: + + $str1 = pack('U*', (0..255)); + print sha1_hex($str1); # ok + + $str2 = pack('U*', (0..256)); + print sha1_hex($str2); # croaks + +Be aware that the digest routines silently convert UTF-8 input into its +equivalent byte sequence in the native encoding (cf. utf8::downgrade). +This side effect influences only the way Perl stores the data internally, +but otherwise leaves the actual value of the data intact. + +=head1 NIST STATEMENT ON SHA-1 + +NIST acknowledges that the work of Prof. Xiaoyun Wang constitutes a +practical collision attack on SHA-1. Therefore, NIST encourages the +rapid adoption of the SHA-2 hash functions (e.g. SHA-256) for applications +requiring strong collision resistance, such as digital signatures. + +ref. L<http://csrc.nist.gov/groups/ST/hash/statement.html> + +=head1 PADDING OF BASE64 DIGESTS + +By convention, CPAN Digest modules do B<not> pad their Base64 output. +Problems can occur when feeding such digests to other software that +expects properly padded Base64 encodings. + +For the time being, any necessary padding must be done by the user. +Fortunately, this is a simple operation: if the length of a Base64-encoded +digest isn't a multiple of 4, simply append "=" characters to the end +of the digest until it is: + + while (length($b64_digest) % 4) { + $b64_digest .= '='; + } + +To illustrate, I<sha256_base64("abc")> is computed to be + + ungWv48Bz+pBQUDeXa4iI7ADYaOWF3qctBD/YfIAFa0 + +which has a length of 43. So, the properly padded version is + + ungWv48Bz+pBQUDeXa4iI7ADYaOWF3qctBD/YfIAFa0= + +=head1 EXPORT + +None by default. + +=head1 EXPORTABLE FUNCTIONS + +Provided your C compiler supports a 64-bit type (e.g. the I<long +long> of C99, or I<__int64> used by Microsoft C/C++), all of these +functions will be available for use. Otherwise, you won't be able +to perform the SHA-384 and SHA-512 transforms, both of which require +64-bit operations. + +I<Functional style> + +=over 4 + +=item B<sha1($data, ...)> + +=item B<sha224($data, ...)> + +=item B<sha256($data, ...)> + +=item B<sha384($data, ...)> + +=item B<sha512($data, ...)> + +=item B<sha512224($data, ...)> + +=item B<sha512256($data, ...)> + +Logically joins the arguments into a single string, and returns +its SHA-1/224/256/384/512 digest encoded as a binary string. + +=item B<sha1_hex($data, ...)> + +=item B<sha224_hex($data, ...)> + +=item B<sha256_hex($data, ...)> + +=item B<sha384_hex($data, ...)> + +=item B<sha512_hex($data, ...)> + +=item B<sha512224_hex($data, ...)> + +=item B<sha512256_hex($data, ...)> + +Logically joins the arguments into a single string, and returns +its SHA-1/224/256/384/512 digest encoded as a hexadecimal string. + +=item B<sha1_base64($data, ...)> + +=item B<sha224_base64($data, ...)> + +=item B<sha256_base64($data, ...)> + +=item B<sha384_base64($data, ...)> + +=item B<sha512_base64($data, ...)> + +=item B<sha512224_base64($data, ...)> + +=item B<sha512256_base64($data, ...)> + +Logically joins the arguments into a single string, and returns +its SHA-1/224/256/384/512 digest encoded as a Base64 string. + +It's important to note that the resulting string does B<not> contain +the padding characters typical of Base64 encodings. This omission is +deliberate, and is done to maintain compatibility with the family of +CPAN Digest modules. See L</"PADDING OF BASE64 DIGESTS"> for details. + +=back + +I<OOP style> + +=over 4 + +=item B<new($alg)> + +Returns a new Digest::SHA object. Allowed values for I<$alg> are 1, +224, 256, 384, 512, 512224, or 512256. It's also possible to use +common string representations of the algorithm (e.g. "sha256", +"SHA-384"). If the argument is missing, SHA-1 will be used by +default. + +Invoking I<new> as an instance method will reset the object to the +initial state associated with I<$alg>. If the argument is missing, +the object will continue using the same algorithm that was selected +at creation. + +=item B<reset($alg)> + +This method has exactly the same effect as I<new($alg)>. In fact, +I<reset> is just an alias for I<new>. + +=item B<hashsize> + +Returns the number of digest bits for this object. The values are +160, 224, 256, 384, 512, 224, and 256 for SHA-1, SHA-224, SHA-256, +SHA-384, SHA-512, SHA-512/224 and SHA-512/256, respectively. + +=item B<algorithm> + +Returns the digest algorithm for this object. The values are 1, +224, 256, 384, 512, 512224, and 512256 for SHA-1, SHA-224, SHA-256, +SHA-384, SHA-512, SHA-512/224, and SHA-512/256, respectively. + +=item B<clone> + +Returns a duplicate copy of the object. + +=item B<add($data, ...)> + +Logically joins the arguments into a single string, and uses it to +update the current digest state. In other words, the following +statements have the same effect: + + $sha->add("a"); $sha->add("b"); $sha->add("c"); + $sha->add("a")->add("b")->add("c"); + $sha->add("a", "b", "c"); + $sha->add("abc"); + +The return value is the updated object itself. + +=item B<add_bits($data, $nbits)> + +=item B<add_bits($bits)> + +Updates the current digest state by appending bits to it. The +return value is the updated object itself. + +The first form causes the most-significant I<$nbits> of I<$data> +to be appended to the stream. The I<$data> argument is in the +customary binary format used for Perl strings. + +The second form takes an ASCII string of "0" and "1" characters as +its argument. It's equivalent to + + $sha->add_bits(pack("B*", $bits), length($bits)); + +So, the following two statements do the same thing: + + $sha->add_bits("111100001010"); + $sha->add_bits("\xF0\xA0", 12); + +Note that SHA-1 and SHA-2 use I<most-significant-bit ordering> +for their internal state. This means that + + $sha3->add_bits("110"); + +is equivalent to + + $sha3->add_bits("1")->add_bits("1")->add_bits("0"); + +=item B<addfile(*FILE)> + +Reads from I<FILE> until EOF, and appends that data to the current +state. The return value is the updated object itself. + +=item B<addfile($filename [, $mode])> + +Reads the contents of I<$filename>, and appends that data to the current +state. The return value is the updated object itself. + +By default, I<$filename> is simply opened and read; no special modes +or I/O disciplines are used. To change this, set the optional I<$mode> +argument to one of the following values: + + "b" read file in binary mode + + "U" use universal newlines + + "0" use BITS mode + +The "U" mode is modeled on Python's "Universal Newlines" concept, whereby +DOS and Mac OS line terminators are converted internally to UNIX newlines +before processing. This ensures consistent digest values when working +simultaneously across multiple file systems. B<The "U" mode influences +only text files>, namely those passing Perl's I<-T> test; binary files +are processed with no translation whatsoever. + +The BITS mode ("0") interprets the contents of I<$filename> as a logical +stream of bits, where each ASCII '0' or '1' character represents a 0 or +1 bit, respectively. All other characters are ignored. This provides +a convenient way to calculate the digest values of partial-byte data +by using files, rather than having to write separate programs employing +the I<add_bits> method. + +=item B<getstate> + +Returns a string containing a portable, human-readable representation +of the current SHA state. + +=item B<putstate($str)> + +Returns a Digest::SHA object representing the SHA state contained +in I<$str>. The format of I<$str> matches the format of the output +produced by method I<getstate>. If called as a class method, a new +object is created; if called as an instance method, the object is reset +to the state contained in I<$str>. + +=item B<dump($filename)> + +Writes the output of I<getstate> to I<$filename>. If the argument is +missing, or equal to the empty string, the state information will be +written to STDOUT. + +=item B<load($filename)> + +Returns a Digest::SHA object that results from calling I<putstate> on +the contents of I<$filename>. If the argument is missing, or equal to +the empty string, the state information will be read from STDIN. + +=item B<digest> + +Returns the digest encoded as a binary string. + +Note that the I<digest> method is a read-once operation. Once it +has been performed, the Digest::SHA object is automatically reset +in preparation for calculating another digest value. Call +I<$sha-E<gt>clone-E<gt>digest> if it's necessary to preserve the +original digest state. + +=item B<hexdigest> + +Returns the digest encoded as a hexadecimal string. + +Like I<digest>, this method is a read-once operation. Call +I<$sha-E<gt>clone-E<gt>hexdigest> if it's necessary to preserve +the original digest state. + +=item B<b64digest> + +Returns the digest encoded as a Base64 string. + +Like I<digest>, this method is a read-once operation. Call +I<$sha-E<gt>clone-E<gt>b64digest> if it's necessary to preserve +the original digest state. + +It's important to note that the resulting string does B<not> contain +the padding characters typical of Base64 encodings. This omission is +deliberate, and is done to maintain compatibility with the family of +CPAN Digest modules. See L</"PADDING OF BASE64 DIGESTS"> for details. + +=back + +I<HMAC-SHA-1/224/256/384/512> + +=over 4 + +=item B<hmac_sha1($data, $key)> + +=item B<hmac_sha224($data, $key)> + +=item B<hmac_sha256($data, $key)> + +=item B<hmac_sha384($data, $key)> + +=item B<hmac_sha512($data, $key)> + +=item B<hmac_sha512224($data, $key)> + +=item B<hmac_sha512256($data, $key)> + +Returns the HMAC-SHA-1/224/256/384/512 digest of I<$data>/I<$key>, +with the result encoded as a binary string. Multiple I<$data> +arguments are allowed, provided that I<$key> is the last argument +in the list. + +=item B<hmac_sha1_hex($data, $key)> + +=item B<hmac_sha224_hex($data, $key)> + +=item B<hmac_sha256_hex($data, $key)> + +=item B<hmac_sha384_hex($data, $key)> + +=item B<hmac_sha512_hex($data, $key)> + +=item B<hmac_sha512224_hex($data, $key)> + +=item B<hmac_sha512256_hex($data, $key)> + +Returns the HMAC-SHA-1/224/256/384/512 digest of I<$data>/I<$key>, +with the result encoded as a hexadecimal string. Multiple I<$data> +arguments are allowed, provided that I<$key> is the last argument +in the list. + +=item B<hmac_sha1_base64($data, $key)> + +=item B<hmac_sha224_base64($data, $key)> + +=item B<hmac_sha256_base64($data, $key)> + +=item B<hmac_sha384_base64($data, $key)> + +=item B<hmac_sha512_base64($data, $key)> + +=item B<hmac_sha512224_base64($data, $key)> + +=item B<hmac_sha512256_base64($data, $key)> + +Returns the HMAC-SHA-1/224/256/384/512 digest of I<$data>/I<$key>, +with the result encoded as a Base64 string. Multiple I<$data> +arguments are allowed, provided that I<$key> is the last argument +in the list. + +It's important to note that the resulting string does B<not> contain +the padding characters typical of Base64 encodings. This omission is +deliberate, and is done to maintain compatibility with the family of +CPAN Digest modules. See L</"PADDING OF BASE64 DIGESTS"> for details. + +=back + +=head1 SEE ALSO + +L<Digest>, L<Digest::SHA::PurePerl> + +The Secure Hash Standard (Draft FIPS PUB 180-4) can be found at: + +L<http://csrc.nist.gov/publications/drafts/fips180-4/Draft-FIPS180-4_Feb2011.pdf> + +The Keyed-Hash Message Authentication Code (HMAC): + +L<http://csrc.nist.gov/publications/fips/fips198/fips-198a.pdf> + +=head1 AUTHOR + + Mark Shelor <mshelor@cpan.org> + +=head1 ACKNOWLEDGMENTS + +The author is particularly grateful to + + Gisle Aas + H. Merijn Brand + Sean Burke + Chris Carey + Alexandr Ciornii + Chris David + Jim Doble + Thomas Drugeon + Julius Duque + Jeffrey Friedl + Robert Gilmour + Brian Gladman + Jarkko Hietaniemi + Adam Kennedy + Mark Lawrence + Andy Lester + Alex Muntada + Steve Peters + Chris Skiscim + Martin Thurn + Gunnar Wolf + Adam Woodbury + +"who by trained skill rescued life from such great billows and such thick +darkness and moored it in so perfect a calm and in so brilliant a light" +- Lucretius + +=head1 COPYRIGHT AND LICENSE + +Copyright (C) 2003-2018 Mark Shelor + +This library is free software; you can redistribute it and/or modify +it under the same terms as Perl itself. + +L<perlartistic> + +=cut |