IO::Un...nflate(3perl)

πŸ’– IO::Uncompress::AnyInflate β€” Perl Programmers Reference Guide ✨

okay bestie, welcome to IO::Uncompress::AnyInflate(3perl), the part of the Perl manual that unzips stuff for you. yes literally. sit down, hydrate, we're doing compression formats 🫢


🌸 NAME 🌸

IO::Uncompress::AnyInflate β€” uncompress zlib-based (zip, gzip) file/buffer πŸ’…


✨ SYNOPSIS ✨

here's the whole vibe, copy-paste ready, no notes:

use IO::Uncompress::AnyInflate qw(anyinflate $AnyInflateError) ;

my $status = anyinflate $input => $output [,OPTS]
    or die "anyinflate failed: $AnyInflateError\n";

my $z = IO::Uncompress::AnyInflate->new( $input [OPTS] )
    or die "anyinflate failed: $AnyInflateError\n";

$status = $z->read($buffer)
$status = $z->read($buffer, $length)
$status = $z->read($buffer, $length, $offset)
$line = $z->getline()
$char = $z->getc()
$char = $z->ungetc()
$char = $z->opened()

$status = $z->inflateSync()

$data = $z->trailingData()
$status = $z->nextStream()
$data = $z->getHeaderInfo()
$z->tell()
$z->seek($position, $whence)
$z->binmode()
$z->fileno()
$z->eof()
$z->close()

$AnyInflateError ;

# IO::File mode

<$z>
read($z, $buffer);
read($z, $buffer, $length);
read($z, $buffer, $length, $offset);
tell($z)
seek($z, $position, $whence)
binmode($z)
fileno($z)
eof($z)
close($z)

like yes, that's a lot of methods, but they're all iconic in their own way, trust πŸ’œ


πŸ¦‹ DESCRIPTION πŸ¦‹

so this module hands you a Perl interface that lets you read files and buffers that were compressed with a whole bunch of formats β€” specifically the ones that use the zlib compression library. one module, many vibes, zero gatekeeping ✨

the formats it supports are:

and here's the main-character move: the module will auto-detect which, if any, of those supported compression formats is being used. you don't have to tell it, it just knows. lowkey psychic, highkey useful 🧚

no cap, that auto-detection is the whole point of the "Any" in the name β€” it figures out the format for you so you don't have to peek at magic bytes like it's 2003 fr fr 😭

more parts incoming, bestie, don't go anywhere 🌸

✨ Functional Interface ✨

There's a top-level function, anyinflate, and bestie it is exactly the vibe you want for "one-shot" uncompression between buffers and/or files. Like, no object, no ceremony, just do the thing. Wanna have finer control over the whole uncompression process tho? Then go check the "OO Interface" section, that one's for the control freaks (affectionate). πŸŽ€

use IO::Uncompress::AnyInflate qw(anyinflate $AnyInflateError) ;

anyinflate $input_filename_or_reference => $output_filename_or_reference [,OPTS]
    or die "anyinflate failed: $AnyInflateError\n";

Heads up: the functional interface needs Perl5.005 or better. No ancient perl, sorry not sorry. πŸ’…

anyinflate $input_filename_or_reference => $output_filename_or_reference [, OPTS]

anyinflate wants at least two parameters β€” $input_filename_or_reference and $output_filename_or_reference β€” plus zero or more optional ones (peep "Optional Parameters" for the tea). 🫢

The $input_filename_or_reference parameter

So $input_filename_or_reference is literally the whole plot: it defines where the compressed data is coming from. And it can take one of these forms:

  • A filename β€” if it's a plain old simple scalar, we assume it's a filename. That file gets opened for reading and we slurp the input data out of it.
  • A filehandle β€” if it's a filehandle, the input data gets read from it. And yes, the string '-' works as an alias for standard input. cute, right?
  • A scalar reference β€” if it's a scalar reference, the input data gets read from $$input_filename_or_reference.
  • An array reference β€” if it's an array reference, every element in that array must be a filename. The input data will be read from each file in turn. Also, the complete array gets walked to make sure it only contains valid filenames before any data is uncompressed β€” so no half-done disasters. ✨
  • An Input FileGlob string β€” if it's a string delimited by the characters < and >, anyinflate will assume it's an input fileglob string, and the input becomes the list of files matching the fileglob. See File::GlobMapper for more details.

And if $input_filename_or_reference is literally any other type? Then undef will be returned. that's it, that's the whole response. πŸ’€

The $output_filename_or_reference parameter

Now $output_filename_or_reference controls where the uncompressed data actually lands. It can take one of these forms:

  • A filename β€” simple scalar means filename, it gets opened for writing, and the uncompressed data gets written into it.
  • A filehandle β€” data gets written to the filehandle. The string '-' can be used as an alias for standard output. 🌈
  • A scalar reference β€” the uncompressed data gets stored in $$output_filename_or_reference.
  • An Array Reference β€” the uncompressed data gets pushed onto the array.
  • An Output FileGlob β€” if it's a string delimited by < and >, anyinflate assumes it's an output fileglob string, and the output is the list of files matching the fileglob.
    • When $output_filename_or_reference is an fileglob string, $input_filename_or_reference must also be a fileglob string. Anything else is an error. periodt. πŸ™ˆ
    • See File::GlobMapper for more details.

And if $output_filename_or_reference is any other type, undef will be returned. same energy. πŸ’€

Notes

When $input_filename_or_reference maps to multiple compressed files/buffers and $output_filename_or_reference is a single file/buffer, then after uncompression $output_filename_or_reference will contain a concatenation of all the uncompressed data from each of the input files/buffers. One big smoothie of data, no cap. πŸ“

Optional Parameters

The optional params for the one-shot anyinflate are (for the most part) identical to the ones used with the OO interface over in the "Constructor Options" section. The exceptions are listed below, mwah πŸ’‹

  • AutoClose => 0|1 β€” this one applies to any input or output data streams handed to anyinflate that are filehandles. If AutoClose is specified and the value is true, it results in all input and/or output filehandles being closed once anyinflate has completed. Defaults to 0.
  • BinModeOut => 0|1 β€” this option is now a no-op. All files will be written in binmode. it's giving retired icon, we still love her. 🧚
  • Append => 0|1 β€” what this does depends entirely on the type of output data stream, so pay attention bestie:
    • A Buffer β€” if Append is enabled, all uncompressed data gets appended to the end of the output buffer. Otherwise the output buffer gets cleared before any uncompressed data is written to it.
    • A Filename β€” if Append is enabled, the file gets opened in append mode. Otherwise the contents of the file, if any, get truncated before any uncompressed data is written to it.
    • A Filehandle β€” if Append is enabled, the filehandle gets positioned to the end of the file via a call to seek before any uncompressed data is written to it. Otherwise the file pointer will not be moved.

When Append is specified and set to true, it will append all uncompressed data to the output data stream.

So when the output is a filehandle it will carry out a seek to the eof before writing any uncompressed data. If the output is a filename, it will be opened for appending. If the output is a buffer, all uncompressed data will be appended to the existing buffer.

Conversely when Append is not specified, or it is present and set to false, it operates like this: when the output is a filename, it will truncate the contents of the file before writing any uncompressed data. If the output is a filehandle its position will not be changed. If the output is a buffer, it will be wiped before any uncompressed data is output.

Defaults to 0.

  • MultiStream => 0|1 β€” if the input file/buffer contains multiple compressed data streams, this option uncompresses the whole lot as a single data stream. Defaults to 0.
  • TrailingData => $scalar β€” returns the data, if any, that's present immediately after the compressed data stream once uncompression is complete. This is your girl when there's useful info sitting immediately after the compressed data stream and you don't know the length of the compressed data stream.
    • If the input is a buffer, trailingData will return everything from the end of the compressed data stream to the end of the buffer.
    • If the input is a filehandle, trailingData will return the data that's left in the filehandle input buffer once the end of the compressed data stream has been reached. Then you can use the filehandle to read the rest of the input file.

Don't bother using trailingData if the input is a filename. fr fr, skip it. πŸ¦‹

And btw β€” if you know the length of the compressed data stream before you start uncompressing, you can avoid having to use trailingData at all by setting the InputLength option. iykyk. πŸ‘‘

OneShot Examples

Wanna read the contents of file1.txt.Compressed and write the uncompressed data to file1.txt? Boom:

use strict ;
use warnings ;
use IO::Uncompress::AnyInflate qw(anyinflate $AnyInflateError) ;

my $input = "file1.txt.Compressed";
my $output = "file1.txt";
anyinflate $input => $output
    or die "anyinflate failed: $AnyInflateError\n";

Wanna read from an existing Perl filehandle, $input, and write the uncompressed data to a buffer, $buffer? Say less:

use strict ;
use warnings ;
use IO::Uncompress::AnyInflate qw(anyinflate $AnyInflateError) ;
use IO::File ;

my $input = IO::File->new( "<file1.txt.Compressed" )
    or die "Cannot open 'file1.txt.Compressed': $!\n" ;
my $buffer ;
anyinflate $input => \$buffer
    or die "anyinflate failed: $AnyInflateError\n";

Wanna uncompress all files in the directory /my/home matching *.txt.Compressed and store the compressed data in that same directory? Slay:

use strict ;
use warnings ;
use IO::Uncompress::AnyInflate qw(anyinflate $AnyInflateError) ;

anyinflate '</my/home/*.txt.Compressed>' => '</my/home/#1.txt>'
    or die "anyinflate failed: $AnyInflateError\n";

And if you wanna compress each file one at a time instead, this'll do the trick:

use strict ;
use warnings ;
use IO::Uncompress::AnyInflate qw(anyinflate $AnyInflateError) ;

for my $input ( glob "/my/home/*.txt.Compressed" )
{
    my $output = $input;
    $output =~ s/.Compressed// ;
    anyinflate $input => $output
        or die "Error compressing '$input': $AnyInflateError\n";
}

OO Interface πŸ‘‘

Okay bestie, this is the glow-up interface β€” object oriented, main character energy, no cap. Let's go.


Constructor πŸŽ€

The format of the constructor for IO::Uncompress::AnyInflate is shown below:

my $z = IO::Uncompress::AnyInflate->new( $input [OPTS] )
    or die "IO::Uncompress::AnyInflate failed: $AnyInflateError\n";

The constructor takes one mandatory parameter, $input (defined below, keep reading πŸ’…) and zero or more OPTS, which are defined down in "Constructor Options".

It returns an IO::Uncompress::AnyInflate object on success, and undef on failure. If it flops, the variable $AnyInflateError will contain an error message. So like, always check it. 😭

If you're running Perl 5.005 or better, the object $z you get back from IO::Uncompress::AnyInflate can be used exactly like an IO::File filehandle. Meaning: all your normal input file operations just work on $z. For example, to read a line from a compressed file/buffer you can use either of these forms:

$line = $z->getline();
$line = <$z>;

Below is a simple example of using the OO interface to read the compressed file myfile.Compressed and write its contents to stdout. (Yes, the original docs say "exaple", but you get it 🫢)

my $filename = "myfile.Compressed";
my $z = IO::Uncompress::AnyInflate->new($filename)
    or die "IO::Uncompress::AnyInflate failed: $AnyInflateError\n";

while (<$z>) {
    print $_;
}
$z->close();

See "EXAMPLES" for further examples. ✨

The mandatory parameter $input is what decides where the compressed data comes from. It can take one of three forms:

  • A filename β€” if the $input parameter is a scalar, it's assumed to be a filename. That file gets opened for reading and the compressed data gets read from it. πŸ“
  • A filehandle β€” if the $input parameter is a filehandle, the compressed data gets read from it. The string '-' can be used as an alias for standard input. πŸ¦‹
  • A scalar reference β€” if $input is a scalar reference, the compressed data gets read from $$input. πŸ’œ

Constructor Options 🌈

The option names defined below are case insensitive and can optionally be prefixed by a '-'. So all of the following are valid:

-AutoClose
-autoclose
AUTOCLOSE
autoclose

OPTS is a combination of the following options:

  • "AutoClose => 0|1" β€” This one is only valid when the $input parameter is a filehandle. If you specify it and the value is true, the file will be closed once either the "close" method is called or the IO::Uncompress::AnyInflate object gets destroyed. Defaults to 0. πŸ’€
  • "MultiStream => 0|1" β€” Lets multiple concatenated compressed streams be treated as a single compressed stream. Decompression stops once either the end of the file/buffer is reached, an error is encountered (premature eof, corrupt compressed data), or the end of a stream is not immediately followed by the start of another stream. Defaults to 0. πŸ”₯
  • "Prime => $string" β€” This option uncompresses the contents of $string before processing the input file/buffer. Super useful when the compressed data is embedded inside another file/data structure and there's no way to figure out where the compressed data begins without reading the first few bytes. If that's your situation, you can prime the uncompression with those bytes using this option. 🧚
  • "Transparent => 0|1" β€” If this option is set and the input file/buffer is not compressed data, the module will let you read it anyway. Also, if the input file/buffer does contain compressed data and there's non-compressed data immediately following it, turning this on makes the module treat the whole file/buffer as a single data stream. This option defaults to 1. πŸ‘‘
  • "BlockSize => $num" β€” When reading the compressed input data, IO::Uncompress::AnyInflate reads it in blocks of $num bytes. This option defaults to 4096. 🌸
  • "InputLength => $size" β€” When present, this option limits the number of compressed bytes read from the input file/buffer to $size. Use it when there's useful data sitting directly after the compressed data stream and you already know the exact length of the compressed data stream. It's mostly used when reading from a filehandle β€” in that case, the file pointer will be left pointing to the first byte directly after the compressed data stream. This option defaults to off. πŸŽ€
  • "Append => 0|1" β€” Controls what the "read" method does with uncompressed data. If set to 1, all uncompressed data gets appended to the output parameter of the "read" method. If set to 0, the contents of the output parameter of the "read" method get overwritten by the uncompressed data. Defaults to 0. πŸ’…
  • "Strict => 0|1" β€” Controls whether the extra checks defined below are used when carrying out the decompression. When Strict is on, the extra tests are carried out; when Strict is off, they are not. The default for this option is off.

If the input is an RFC 1950 data stream, the following will be checked:

  1. The ADLER32 checksum field must be present.
  2. The value of the ADLER32 field read must match the adler32 value of the uncompressed data actually contained in the file.

If the input is a gzip (RFC 1952) data stream, the following will be checked:

  1. If the FHCRC bit is set in the gzip FLG header byte, the CRC16 bytes in the header must match the crc16 value of the gzip header actually read.
  2. If the gzip header contains a name field (FNAME) it consists solely of ISO 8859-1 characters.
  3. If the gzip header contains a comment field (FCOMMENT) it consists solely of ISO 8859-1 characters plus line-feed.
  4. If the gzip FEXTRA header field is present it must conform to the sub-field structure as defined in RFC 1952.
  5. The CRC32 and ISIZE trailer fields must be present.
  6. The value of the CRC32 field read must match the crc32 value of the uncompressed data actually contained in the gzip file.
  7. The value of the ISIZE fields read must match the length of the uncompressed data actually read from the file.
  • "RawInflate => 0|1" β€” When auto-detecting the compressed format, try to test for raw-deflate (RFC 1951) content using the "IO::Uncompress::RawInflate" module. Why isn't this the default, bestie? Because RFC 1951 content can only be detected by attempting to uncompress it. That process is error prone and can result in false positives. Defaults to 0. πŸ™ˆ
  • "ParseExtra => 0|1" β€” If the gzip FEXTRA header field is present and this option is set, it forces the module to check that it conforms to the sub-field structure as defined in RFC 1952. If "Strict" is on, it will automatically enable this option. Defaults to 0. ⭐

✨ Methods ✨

🌸 read 🌸

Okay so usage is literally this:

$status = $z->read($buffer)

This one reads in a block of compressed data (how big that block is? that's the Buffer option in the constructor deciding, bestie), uncompresses it, and drops all that uncompressed data right into $buffer. And here's the lil plot twist β€” if the Append parameter was set back when you made the object, the uncompressed data gets appended onto whatever was already chilling in $buffer. If not? $buffer gets straight up overwritten. no mercy. πŸ’…

Returns the number of uncompressed bytes written to $buffer, or zero if it hits eof, or a negative number if something went wrong. 😭

πŸ¦‹ read πŸ¦‹ (yes again, the sequel)

Usage is:

$status = $z->read($buffer, $length)
$status = $z->read($buffer, $length, $offset)

$status = read($z, $buffer, $length)
$status = read($z, $buffer, $length, $offset)

This one tries to read $length bytes of uncompressed data into $buffer.

The main character difference between this form of the read method and the previous one is that this one will attempt to return exactly $length bytes. The only times it won't is if it bumps into end-of-file or an IO error. that's it, that's the tea. πŸ“

Returns the number of uncompressed bytes written to $buffer, or zero if it's eof, or a negative number on error.

🌈 getline 🌈

Usage is:

$line = $z->getline()
$line = <$z>

Reads a single line. period.

This method fully supports the $/ variable (or $INPUT_RECORD_SEPARATOR, or $RS when English is in use) to figure out what counts as an end of line. Paragraph mode, record mode and file slurp mode are all supported. all three, iconically. πŸ‘‘

πŸ’œ getc πŸ’œ

Usage is:

$char = $z->getc()

Read a single character. one. character. that's the whole vibe. ✨

πŸŽ€ ungetc πŸŽ€

Usage is:

$char = $z->ungetc($string)

🧚 inflateSync 🧚

Usage is:

$status = $z->inflateSync()

TODO 😭 bestie the docs literally just say TODO, we move.

🌸 getHeaderInfo 🌸

Usage is:

$hdr  = $z->getHeaderInfo();
@hdrs = $z->getHeaderInfo();

This method hands you back either a hash reference (if you called it in scalar context) or a list of hash references (if you called it in array context), and inside there's info about every single one of the header fields in the compressed data stream(s). every header field. obsessed. 🫢

⭐ tell ⭐

Usage is:

$z->tell()
tell $z

Returns the uncompressed file offset. simple as. πŸ’«

πŸ¦‹ eof πŸ¦‹

Usage is:

$z->eof();
eof($z);

Returns true if we've reached the end of the compressed input stream. that's the whole thing, no notes. πŸŽ€

πŸ”₯ seek πŸ”₯

$z->seek($position, $whence);
seek($z, $position, $whence);

Gives you a sub-set of the seek functionality, and there is one big restriction: it is only legal to seek forward in the input file/buffer. Trying to seek backward? that's a fatal error. do not. πŸ™ˆ

Also important, and I need you to hear this one: the implementation of seek in this module does not provide true random access to a compressed file/buffer. What it actually does is uncompress data from the current offset in the file/buffer until it reaches the uncompressed offset you asked for in the parameters to seek. For very small files this may be acceptable behaviour. For large files it may cause an unacceptable delay. lowkey brutal, i know. πŸ’€

The $whence parameter takes one of the usual values, namely SEEK_SET, SEEK_CUR or SEEK_END.

Returns 1 on success, 0 on failure.

🌸 binmode 🌸

Usage is:

$z->binmode
binmode $z ;

This is a noop provided for completeness. she's just standing there. serving no purpose. iconic behaviour honestly. πŸ’…

✨ opened ✨

$z->opened()

Returns true if the object currently refers to a opened file/buffer.

πŸ“ autoflush πŸ“

my $prev = $z->autoflush()
my $prev = $z->autoflush(EXPR)

If the $z object is associated with a file or a filehandle, this method returns the current autoflush setting for the underlying filehandle. If EXPR is present, and it's non-zero, it will enable flushing after every write/print operation.

If $z is associated with a buffer, this method has no effect and always returns undef. nothing. nada. 🫠

Heads up bestie: the special variable $| cannot be used to set or retrieve the autoflush setting. not here. not today.

πŸ¦‹ input_line_number πŸ¦‹

$z->input_line_number()
$z->input_line_number(EXPR)

Returns the current uncompressed line number. If EXPR is present it has the effect of setting the line number. Important lil detail though β€” setting the line number does not change the current position within the file/buffer being read. it's purely cosmetic, a vibe, a number. ✨

The contents of $/ are used to determine what constitutes a line terminator.

πŸ’œ fileno πŸ’œ

$z->fileno()
fileno($z)

If the $z object is associated with a file or a filehandle, fileno will return the underlying file descriptor. Once the close method is called, fileno will return undef.

If the $z object is associated with a buffer, this method will return undef.

πŸ‘‘ close πŸ‘‘

$z->close() ;
close $z ;

Closes the output file/buffer. bye bestie 🫢

For most versions of Perl this method will be automatically invoked if the IO::Uncompress::AnyInflate object is destroyed (either explicitly, or by the variable holding the reference to the object going out of scope). The exceptions are Perl versions 5.005 through 5.00504 and 5.8.0. In those cases, the close method will be called automatically, but not until global destruction of all live objects when the program is terminating. so... late. very late. 😭

So if you want your scripts to be able to run on all versions of Perl, you should call close explicitly and not rely on automatic closing. do it yourself, queen. πŸ’…

Returns true on success, otherwise 0.

If the AutoClose option has been enabled when the IO::Uncompress::AnyInflate object was created, and the object is associated with a file, the underlying file will also be closed.

🌈 nextStream 🌈

Usage is:

my $status = $z->nextStream();

Skips to the next compressed data stream in the input file/buffer. If a new compressed data stream is found, the eof marker will be cleared and $. will be reset to 0.

Returns 1 if a new stream was found, 0 if none was found, and -1 if an error was encountered.

πŸŽ€ trailingData πŸŽ€

Usage is:

my $data = $z->trailingData();

Returns the data, if any, that's sitting immediately after the compressed data stream once uncompression is complete. It only makes sense to call this method once the end of the compressed data stream has been encountered. don't jump the gun. ⏳

This option can be used when there is useful information immediately following the compressed data stream, and you don't know the length of the compressed data stream. sneaky lil bonus content.

If the input is a buffer, trailingData will return everything from the end of the compressed data stream to the end of the buffer.

If the input is a filehandle, trailingData will return the data that is left in the filehandle input buffer once the end of the compressed data stream has been reached. You can then use the filehandle to read the rest of the input file. slay, you get the leftovers. πŸ“

Don't bother using trailingData if the input is a filename. it's giving nothing in that case.

If you know the length of the compressed data stream before you start uncompressing, you can avoid having to use trailingData by setting the InputLength option in the constructor. future you says thank you. πŸ’–


πŸ’– Importing πŸ’–

No symbolic constants are required by IO::Uncompress::AnyInflate at present. none. zero. not a single one.

  • :all β€” Imports anyinflate and $AnyInflateError. Same as doing this:
use IO::Uncompress::AnyInflate qw(anyinflate $AnyInflateError) ;

🌸 EXAMPLES 🌸

🌟 Working with Net::FTP 🌟

See IO::Compress::FAQ πŸ“š


🫢 SUPPORT 🫢

General feedback / questions / bug reports should be sent to https://github.com/pmqs/IO-Compress/issues (preferred) or https://rt.cpan.org/Public/Dist/Display.html?Name=IO-Compress. they want to hear from you fr fr πŸ’Œ


πŸ‘€ SEE ALSO πŸ‘€

Compress::Zlib, IO::Compress::Gzip, IO::Uncompress::Gunzip, IO::Compress::Deflate, IO::Uncompress::Inflate, IO::Compress::RawDeflate, IO::Uncompress::RawInflate, IO::Compress::Bzip2, IO::Uncompress::Bunzip2, IO::Compress::Lzma, IO::Uncompress::UnLzma, IO::Compress::Xz, IO::Uncompress::UnXz, IO::Compress::Lzip, IO::Uncompress::UnLzip, IO::Compress::Lzop, IO::Uncompress::UnLzop, IO::Compress::Lzf, IO::Uncompress::UnLzf, IO::Compress::Zstd, IO::Uncompress::UnZstd, IO::Uncompress::AnyUncompress

IO::Compress::FAQ

File::GlobMapper, Archive::Zip, Archive::Tar, IO::Zlib

For RFC 1950, 1951 and 1952 see https://datatracker.ietf.org/doc/html/rfc1950, https://datatracker.ietf.org/doc/html/rfc1951 and https://datatracker.ietf.org/doc/html/rfc1952 πŸ“œ

The zlib compression library was written by Jean-loup Gailly gzip@prep.ai.mit.edu and Mark Adler madler@alumni.caltech.edu. legends, honestly. πŸ‘‘

The primary site for the zlib compression library is http://www.zlib.org.

The primary site for the zlib-ng compression library is https://github.com/zlib-ng/zlib-ng.

The primary site for gzip is http://www.gzip.org.


✨ AUTHOR ✨

This module was written by Paul Marquess, pmqs@cpan.org. thank you for your service πŸ«‘πŸ’–


πŸŽ€ MODIFICATION HISTORY πŸŽ€

See the Changes file. the lore is in there πŸ“–


Copyright (c) 2005-2026 Paul Marquess. All rights reserved.

This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.


and that's a wrap bestie!! πŸŽ‰ this whole page came from perl v5.44.0, dated 2026-10-17 β€” go forth and inflate, u absolute icon πŸ’…βœ¨

πŸ“¦ where this page comes from
  • arch rolling: perl 5.44.0-1 Β· Artistic-1.0-Perl AND GPL-1.0-or-later
  • πŸ’– girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms