/home/fresvfqn/waterdamagerestorationandrepairsmithtown.com/Compressed/share.zip
PK�%[&�����doc/alt-libzip/LICENSEnu�[���Copyright (C) 1999-2020 Dieter Baron and Thomas Klausner

The authors can be contacted at <info@libzip.org>

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

1. Redistributions of source code must retain the above copyright
  notice, this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright
  notice, this list of conditions and the following disclaimer in
  the documentation and/or other materials provided with the
  distribution.

3. The names of the authors may not be used to endorse or promote
  products derived from this software without specific prior
  written permission.

THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
PK�%[���s%%licenses/alt-libdav1d/COPYINGnu�[���Copyright © 2018-2019, VideoLAN and dav1d authors
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
PK�%[_�H	bblicenses/alt-libdav1d/PATENTSnu�[���Alliance for Open Media Patent License 1.0

1. License Terms.

1.1. Patent License. Subject to the terms and conditions of this License, each
     Licensor, on behalf of itself and successors in interest and assigns,
     grants Licensee a non-sublicensable, perpetual, worldwide, non-exclusive,
     no-charge, royalty-free, irrevocable (except as expressly stated in this
     License) patent license to its Necessary Claims to make, use, sell, offer
     for sale, import or distribute any Implementation.

1.2. Conditions.

1.2.1. Availability. As a condition to the grant of rights to Licensee to make,
       sell, offer for sale, import or distribute an Implementation under
       Section 1.1, Licensee must make its Necessary Claims available under
       this License, and must reproduce this License with any Implementation
       as follows:

       a. For distribution in source code, by including this License in the
          root directory of the source code with its Implementation.

       b. For distribution in any other form (including binary, object form,
          and/or hardware description code (e.g., HDL, RTL, Gate Level Netlist,
          GDSII, etc.)), by including this License in the documentation, legal
          notices, and/or other written materials provided with the
          Implementation.

1.2.2. Additional Conditions. This license is directly from Licensor to
       Licensee.  Licensee acknowledges as a condition of benefiting from it
       that no rights from Licensor are received from suppliers, distributors,
       or otherwise in connection with this License.

1.3. Defensive Termination. If any Licensee, its Affiliates, or its agents
     initiates patent litigation or files, maintains, or voluntarily
     participates in a lawsuit against another entity or any person asserting
     that any Implementation infringes Necessary Claims, any patent licenses
     granted under this License directly to the Licensee are immediately
     terminated as of the date of the initiation of action unless 1) that suit
     was in response to a corresponding suit regarding an Implementation first
     brought against an initiating entity, or 2) that suit was brought to
     enforce the terms of this License (including intervention in a third-party
     action by a Licensee).

1.4. Disclaimers. The Reference Implementation and Specification are provided
     "AS IS" and without warranty. The entire risk as to implementing or
     otherwise using the Reference Implementation or Specification is assumed
     by the implementer and user. Licensor expressly disclaims any warranties
     (express, implied, or otherwise), including implied warranties of
     merchantability, non-infringement, fitness for a particular purpose, or
     title, related to the material. IN NO EVENT WILL LICENSOR BE LIABLE TO
     ANY OTHER PARTY FOR LOST PROFITS OR ANY FORM OF INDIRECT, SPECIAL,
     INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER FROM ANY CAUSES OF
     ACTION OF ANY KIND WITH RESPECT TO THIS LICENSE, WHETHER BASED ON BREACH
     OF CONTRACT, TORT (INCLUDING NEGLIGENCE), OR OTHERWISE, AND WHETHER OR
     NOT THE OTHER PARTRY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

2. Definitions.

2.1. Affiliate.  “Affiliate” means an entity that directly or indirectly
     Controls, is Controlled by, or is under common Control of that party.

2.2. Control. “Control” means direct or indirect control of more than 50% of
     the voting power to elect directors of that corporation, or for any other
     entity, the power to direct management of such entity.

2.3. Decoder.  "Decoder" means any decoder that conforms fully with all
     non-optional portions of the Specification.

2.4. Encoder.  "Encoder" means any encoder that produces a bitstream that can
     be decoded by a Decoder only to the extent it produces such a bitstream.

2.5. Final Deliverable.  “Final Deliverable” means the final version of a
     deliverable approved by the Alliance for Open Media as a Final
     Deliverable.

2.6. Implementation.  "Implementation" means any implementation, including the
     Reference Implementation, that is an Encoder and/or a Decoder. An
     Implementation also includes components of an Implementation only to the
     extent they are used as part of an Implementation.

2.7. License. “License” means this license.

2.8. Licensee. “Licensee” means any person or entity who exercises patent
     rights granted under this License.

2.9. Licensor.  "Licensor" means (i) any Licensee that makes, sells, offers
     for sale, imports or distributes any Implementation, or (ii) a person
     or entity that has a licensing obligation to the Implementation as a
     result of its membership and/or participation in the Alliance for Open
     Media working group that developed the Specification.

2.10. Necessary Claims.  "Necessary Claims" means all claims of patents or
      patent applications, (a) that currently or at any time in the future,
      are owned or controlled by the Licensor, and (b) (i) would be an
      Essential Claim as defined by the W3C Policy as of February 5, 2004
      (https://www.w3.org/Consortium/Patent-Policy-20040205/#def-essential)
      as if the Specification was a W3C Recommendation; or (ii) are infringed
      by the Reference Implementation.

2.11. Reference Implementation. “Reference Implementation” means an Encoder
      and/or Decoder released by the Alliance for Open Media as a Final
      Deliverable.

2.12. Specification. “Specification” means the specification designated by
      the Alliance for Open Media as a Final Deliverable for which this
      License was issued.

PK� %[�_Nvnndoc/alt-pcre/LICENCEnu�[���PCRE LICENCE
------------

PCRE is a library of functions to support regular expressions whose syntax
and semantics are as close as possible to those of the Perl 5 language.

Release 8 of PCRE is distributed under the terms of the "BSD" licence, as
specified below. The documentation for PCRE, supplied in the "doc"
directory, is distributed under the same terms as the software itself. The data
in the testdata directory is not copyrighted and is in the public domain.

The basic library functions are written in C and are freestanding. Also
included in the distribution is a set of C++ wrapper functions, and a
just-in-time compiler that can be used to optimize pattern matching. These
are both optional features that can be omitted when the library is built.


THE BASIC LIBRARY FUNCTIONS
---------------------------

Written by:       Philip Hazel
Email local part: ph10
Email domain:     cam.ac.uk

University of Cambridge Computing Service,
Cambridge, England.

Copyright (c) 1997-2017 University of Cambridge
All rights reserved.


PCRE JUST-IN-TIME COMPILATION SUPPORT
-------------------------------------

Written by:       Zoltan Herczeg
Email local part: hzmester
Emain domain:     freemail.hu

Copyright(c) 2010-2017 Zoltan Herczeg
All rights reserved.


STACK-LESS JUST-IN-TIME COMPILER
--------------------------------

Written by:       Zoltan Herczeg
Email local part: hzmester
Emain domain:     freemail.hu

Copyright(c) 2009-2017 Zoltan Herczeg
All rights reserved.


THE C++ WRAPPER FUNCTIONS
-------------------------

Contributed by:   Google Inc.

Copyright (c) 2007-2012, Google Inc.
All rights reserved.


THE "BSD" LICENCE
-----------------

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.

    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.

    * Neither the name of the University of Cambridge nor the name of Google
      Inc. nor the names of their contributors may be used to endorse or
      promote products derived from this software without specific prior
      written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

End
PK� %[�al��doc/alt-pcre/READMEnu�[���README file for PCRE (Perl-compatible regular expression library)
-----------------------------------------------------------------

NOTE: This set of files relates to PCRE releases that use the original API,
with library names libpcre, libpcre16, and libpcre32. January 2015 saw the
first release of a new API, known as PCRE2, with release numbers starting at
10.00 and library names libpcre2-8, libpcre2-16, and libpcre2-32. The old
libraries (now called PCRE1) are still being maintained for bug fixes, but
there will be no new development. New projects are advised to use the new PCRE2
libraries.


The latest release of PCRE1 is always available in three alternative formats
from:

  ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-xxx.tar.gz
  ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-xxx.tar.bz2
  ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-xxx.zip

There is a mailing list for discussion about the development of PCRE at
pcre-dev@exim.org. You can access the archives and subscribe or manage your
subscription here:

   https://lists.exim.org/mailman/listinfo/pcre-dev

Please read the NEWS file if you are upgrading from a previous release.
The contents of this README file are:

  The PCRE APIs
  Documentation for PCRE
  Contributions by users of PCRE
  Building PCRE on non-Unix-like systems
  Building PCRE without using autotools
  Building PCRE using autotools
  Retrieving configuration information
  Shared libraries
  Cross-compiling using autotools
  Using HP's ANSI C++ compiler (aCC)
  Compiling in Tru64 using native compilers
  Using Sun's compilers for Solaris
  Using PCRE from MySQL
  Making new tarballs
  Testing PCRE
  Character tables
  File manifest


The PCRE APIs
-------------

PCRE is written in C, and it has its own API. There are three sets of
functions, one for the 8-bit library, which processes strings of bytes, one for
the 16-bit library, which processes strings of 16-bit values, and one for the
32-bit library, which processes strings of 32-bit values. The distribution also
includes a set of C++ wrapper functions (see the pcrecpp man page for details),
courtesy of Google Inc., which can be used to call the 8-bit PCRE library from
C++. Other C++ wrappers have been created from time to time. See, for example:
https://github.com/YasserAsmi/regexp, which aims to be simple and similar in
style to the C API.

The distribution also contains a set of C wrapper functions (again, just for
the 8-bit library) that are based on the POSIX regular expression API (see the
pcreposix man page). These end up in the library called libpcreposix. Note that
this just provides a POSIX calling interface to PCRE; the regular expressions
themselves still follow Perl syntax and semantics. The POSIX API is restricted,
and does not give full access to all of PCRE's facilities.

The header file for the POSIX-style functions is called pcreposix.h. The
official POSIX name is regex.h, but I did not want to risk possible problems
with existing files of that name by distributing it that way. To use PCRE with
an existing program that uses the POSIX API, pcreposix.h will have to be
renamed or pointed at by a link.

If you are using the POSIX interface to PCRE and there is already a POSIX regex
library installed on your system, as well as worrying about the regex.h header
file (as mentioned above), you must also take care when linking programs to
ensure that they link with PCRE's libpcreposix library. Otherwise they may pick
up the POSIX functions of the same name from the other library.

One way of avoiding this confusion is to compile PCRE with the addition of
-Dregcomp=PCREregcomp (and similarly for the other POSIX functions) to the
compiler flags (CFLAGS if you are using "configure" -- see below). This has the
effect of renaming the functions so that the names no longer clash. Of course,
you have to do the same thing for your applications, or write them using the
new names.


Documentation for PCRE
----------------------

If you install PCRE in the normal way on a Unix-like system, you will end up
with a set of man pages whose names all start with "pcre". The one that is just
called "pcre" lists all the others. In addition to these man pages, the PCRE
documentation is supplied in two other forms:

  1. There are files called doc/pcre.txt, doc/pcregrep.txt, and
     doc/pcretest.txt in the source distribution. The first of these is a
     concatenation of the text forms of all the section 3 man pages except
     the listing of pcredemo.c and those that summarize individual functions.
     The other two are the text forms of the section 1 man pages for the
     pcregrep and pcretest commands. These text forms are provided for ease of
     scanning with text editors or similar tools. They are installed in
     <prefix>/share/doc/pcre, where <prefix> is the installation prefix
     (defaulting to /usr/local).

  2. A set of files containing all the documentation in HTML form, hyperlinked
     in various ways, and rooted in a file called index.html, is distributed in
     doc/html and installed in <prefix>/share/doc/pcre/html.

Users of PCRE have contributed files containing the documentation for various
releases in CHM format. These can be found in the Contrib directory of the FTP
site (see next section).


Contributions by users of PCRE
------------------------------

You can find contributions from PCRE users in the directory

  ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/Contrib

There is a README file giving brief descriptions of what they are. Some are
complete in themselves; others are pointers to URLs containing relevant files.
Some of this material is likely to be well out-of-date. Several of the earlier
contributions provided support for compiling PCRE on various flavours of
Windows (I myself do not use Windows). Nowadays there is more Windows support
in the standard distribution, so these contibutions have been archived.

A PCRE user maintains downloadable Windows binaries of the pcregrep and
pcretest programs here:

  http://www.rexegg.com/pcregrep-pcretest.html


Building PCRE on non-Unix-like systems
--------------------------------------

For a non-Unix-like system, please read the comments in the file
NON-AUTOTOOLS-BUILD, though if your system supports the use of "configure" and
"make" you may be able to build PCRE using autotools in the same way as for
many Unix-like systems.

PCRE can also be configured using the GUI facility provided by CMake's
cmake-gui command. This creates Makefiles, solution files, etc. The file
NON-AUTOTOOLS-BUILD has information about CMake.

PCRE has been compiled on many different operating systems. It should be
straightforward to build PCRE on any system that has a Standard C compiler and
library, because it uses only Standard C functions.


Building PCRE without using autotools
-------------------------------------

The use of autotools (in particular, libtool) is problematic in some
environments, even some that are Unix or Unix-like. See the NON-AUTOTOOLS-BUILD
file for ways of building PCRE without using autotools.


Building PCRE using autotools
-----------------------------

If you are using HP's ANSI C++ compiler (aCC), please see the special note
in the section entitled "Using HP's ANSI C++ compiler (aCC)" below.

The following instructions assume the use of the widely used "configure; make;
make install" (autotools) process.

To build PCRE on system that supports autotools, first run the "configure"
command from the PCRE distribution directory, with your current directory set
to the directory where you want the files to be created. This command is a
standard GNU "autoconf" configuration script, for which generic instructions
are supplied in the file INSTALL.

Most commonly, people build PCRE within its own distribution directory, and in
this case, on many systems, just running "./configure" is sufficient. However,
the usual methods of changing standard defaults are available. For example:

CFLAGS='-O2 -Wall' ./configure --prefix=/opt/local

This command specifies that the C compiler should be run with the flags '-O2
-Wall' instead of the default, and that "make install" should install PCRE
under /opt/local instead of the default /usr/local.

If you want to build in a different directory, just run "configure" with that
directory as current. For example, suppose you have unpacked the PCRE source
into /source/pcre/pcre-xxx, but you want to build it in /build/pcre/pcre-xxx:

cd /build/pcre/pcre-xxx
/source/pcre/pcre-xxx/configure

PCRE is written in C and is normally compiled as a C library. However, it is
possible to build it as a C++ library, though the provided building apparatus
does not have any features to support this.

There are some optional features that can be included or omitted from the PCRE
library. They are also documented in the pcrebuild man page.

. By default, both shared and static libraries are built. You can change this
  by adding one of these options to the "configure" command:

  --disable-shared
  --disable-static

  (See also "Shared libraries on Unix-like systems" below.)

. By default, only the 8-bit library is built. If you add --enable-pcre16 to
  the "configure" command, the 16-bit library is also built. If you add
  --enable-pcre32 to the "configure" command, the 32-bit library is also built.
  If you want only the 16-bit or 32-bit library, use --disable-pcre8 to disable
  building the 8-bit library.

. If you are building the 8-bit library and want to suppress the building of
  the C++ wrapper library, you can add --disable-cpp to the "configure"
  command. Otherwise, when "configure" is run without --disable-pcre8, it will
  try to find a C++ compiler and C++ header files, and if it succeeds, it will
  try to build the C++ wrapper.

. If you want to include support for just-in-time compiling, which can give
  large performance improvements on certain platforms, add --enable-jit to the
  "configure" command. This support is available only for certain hardware
  architectures. If you try to enable it on an unsupported architecture, there
  will be a compile time error.

. When JIT support is enabled, pcregrep automatically makes use of it, unless
  you add --disable-pcregrep-jit to the "configure" command.

. If you want to make use of the support for UTF-8 Unicode character strings in
  the 8-bit library, or UTF-16 Unicode character strings in the 16-bit library,
  or UTF-32 Unicode character strings in the 32-bit library, you must add
  --enable-utf to the "configure" command. Without it, the code for handling
  UTF-8, UTF-16 and UTF-8 is not included in the relevant library. Even
  when --enable-utf is included, the use of a UTF encoding still has to be
  enabled by an option at run time. When PCRE is compiled with this option, its
  input can only either be ASCII or UTF-8/16/32, even when running on EBCDIC
  platforms. It is not possible to use both --enable-utf and --enable-ebcdic at
  the same time.

. There are no separate options for enabling UTF-8, UTF-16 and UTF-32
  independently because that would allow ridiculous settings such as requesting
  UTF-16 support while building only the 8-bit library. However, the option
  --enable-utf8 is retained for backwards compatibility with earlier releases
  that did not support 16-bit or 32-bit character strings. It is synonymous with
  --enable-utf. It is not possible to configure one library with UTF support
  and the other without in the same configuration.

. If, in addition to support for UTF-8/16/32 character strings, you want to
  include support for the \P, \p, and \X sequences that recognize Unicode
  character properties, you must add --enable-unicode-properties to the
  "configure" command. This adds about 30K to the size of the library (in the
  form of a property table); only the basic two-letter properties such as Lu
  are supported.

. You can build PCRE to recognize either CR or LF or the sequence CRLF or any
  of the preceding, or any of the Unicode newline sequences as indicating the
  end of a line. Whatever you specify at build time is the default; the caller
  of PCRE can change the selection at run time. The default newline indicator
  is a single LF character (the Unix standard). You can specify the default
  newline indicator by adding --enable-newline-is-cr or --enable-newline-is-lf
  or --enable-newline-is-crlf or --enable-newline-is-anycrlf or
  --enable-newline-is-any to the "configure" command, respectively.

  If you specify --enable-newline-is-cr or --enable-newline-is-crlf, some of
  the standard tests will fail, because the lines in the test files end with
  LF. Even if the files are edited to change the line endings, there are likely
  to be some failures. With --enable-newline-is-anycrlf or
  --enable-newline-is-any, many tests should succeed, but there may be some
  failures.

. By default, the sequence \R in a pattern matches any Unicode line ending
  sequence. This is independent of the option specifying what PCRE considers to
  be the end of a line (see above). However, the caller of PCRE can restrict \R
  to match only CR, LF, or CRLF. You can make this the default by adding
  --enable-bsr-anycrlf to the "configure" command (bsr = "backslash R").

. When called via the POSIX interface, PCRE uses malloc() to get additional
  storage for processing capturing parentheses if there are more than 10 of
  them in a pattern. You can increase this threshold by setting, for example,

  --with-posix-malloc-threshold=20

  on the "configure" command.

. PCRE has a counter that limits the depth of nesting of parentheses in a
  pattern. This limits the amount of system stack that a pattern uses when it
  is compiled. The default is 250, but you can change it by setting, for
  example,

  --with-parens-nest-limit=500

. PCRE has a counter that can be set to limit the amount of resources it uses
  when matching a pattern. If the limit is exceeded during a match, the match
  fails. The default is ten million. You can change the default by setting, for
  example,

  --with-match-limit=500000

  on the "configure" command. This is just the default; individual calls to
  pcre_exec() can supply their own value. There is more discussion on the
  pcreapi man page.

. There is a separate counter that limits the depth of recursive function calls
  during a matching process. This also has a default of ten million, which is
  essentially "unlimited". You can change the default by setting, for example,

  --with-match-limit-recursion=500000

  Recursive function calls use up the runtime stack; running out of stack can
  cause programs to crash in strange ways. There is a discussion about stack
  sizes in the pcrestack man page.

. The default maximum compiled pattern size is around 64K. You can increase
  this by adding --with-link-size=3 to the "configure" command. In the 8-bit
  library, PCRE then uses three bytes instead of two for offsets to different
  parts of the compiled pattern. In the 16-bit library, --with-link-size=3 is
  the same as --with-link-size=4, which (in both libraries) uses four-byte
  offsets. Increasing the internal link size reduces performance. In the 32-bit
  library, the only supported link size is 4.

. You can build PCRE so that its internal match() function that is called from
  pcre_exec() does not call itself recursively. Instead, it uses memory blocks
  obtained from the heap via the special functions pcre_stack_malloc() and
  pcre_stack_free() to save data that would otherwise be saved on the stack. To
  build PCRE like this, use

  --disable-stack-for-recursion

  on the "configure" command. PCRE runs more slowly in this mode, but it may be
  necessary in environments with limited stack sizes. This applies only to the
  normal execution of the pcre_exec() function; if JIT support is being
  successfully used, it is not relevant. Equally, it does not apply to
  pcre_dfa_exec(), which does not use deeply nested recursion. There is a
  discussion about stack sizes in the pcrestack man page.

. For speed, PCRE uses four tables for manipulating and identifying characters
  whose code point values are less than 256. By default, it uses a set of
  tables for ASCII encoding that is part of the distribution. If you specify

  --enable-rebuild-chartables

  a program called dftables is compiled and run in the default C locale when
  you obey "make". It builds a source file called pcre_chartables.c. If you do
  not specify this option, pcre_chartables.c is created as a copy of
  pcre_chartables.c.dist. See "Character tables" below for further information.

. It is possible to compile PCRE for use on systems that use EBCDIC as their
  character code (as opposed to ASCII/Unicode) by specifying

  --enable-ebcdic

  This automatically implies --enable-rebuild-chartables (see above). However,
  when PCRE is built this way, it always operates in EBCDIC. It cannot support
  both EBCDIC and UTF-8/16/32. There is a second option, --enable-ebcdic-nl25,
  which specifies that the code value for the EBCDIC NL character is 0x25
  instead of the default 0x15.

. In environments where valgrind is installed, if you specify

  --enable-valgrind

  PCRE will use valgrind annotations to mark certain memory regions as
  unaddressable. This allows it to detect invalid memory accesses, and is
  mostly useful for debugging PCRE itself.

. In environments where the gcc compiler is used and lcov version 1.6 or above
  is installed, if you specify

  --enable-coverage

  the build process implements a code coverage report for the test suite. The
  report is generated by running "make coverage". If ccache is installed on
  your system, it must be disabled when building PCRE for coverage reporting.
  You can do this by setting the environment variable CCACHE_DISABLE=1 before
  running "make" to build PCRE. There is more information about coverage
  reporting in the "pcrebuild" documentation.

. The pcregrep program currently supports only 8-bit data files, and so
  requires the 8-bit PCRE library. It is possible to compile pcregrep to use
  libz and/or libbz2, in order to read .gz and .bz2 files (respectively), by
  specifying one or both of

  --enable-pcregrep-libz
  --enable-pcregrep-libbz2

  Of course, the relevant libraries must be installed on your system.

. The default size (in bytes) of the internal buffer used by pcregrep can be
  set by, for example:

  --with-pcregrep-bufsize=51200

  The value must be a plain integer. The default is 20480.

. It is possible to compile pcretest so that it links with the libreadline
  or libedit libraries, by specifying, respectively,

  --enable-pcretest-libreadline or --enable-pcretest-libedit

  If this is done, when pcretest's input is from a terminal, it reads it using
  the readline() function. This provides line-editing and history facilities.
  Note that libreadline is GPL-licenced, so if you distribute a binary of
  pcretest linked in this way, there may be licensing issues. These can be
  avoided by linking with libedit (which has a BSD licence) instead.

  Enabling libreadline causes the -lreadline option to be added to the pcretest
  build. In many operating environments with a sytem-installed readline
  library this is sufficient. However, in some environments (e.g. if an
  unmodified distribution version of readline is in use), it may be necessary
  to specify something like LIBS="-lncurses" as well. This is because, to quote
  the readline INSTALL, "Readline uses the termcap functions, but does not link
  with the termcap or curses library itself, allowing applications which link
  with readline the to choose an appropriate library." If you get error
  messages about missing functions tgetstr, tgetent, tputs, tgetflag, or tgoto,
  this is the problem, and linking with the ncurses library should fix it.

The "configure" script builds the following files for the basic C library:

. Makefile             the makefile that builds the library
. config.h             build-time configuration options for the library
. pcre.h               the public PCRE header file
. pcre-config          script that shows the building settings such as CFLAGS
                         that were set for "configure"
. libpcre.pc         ) data for the pkg-config command
. libpcre16.pc       )
. libpcre32.pc       )
. libpcreposix.pc    )
. libtool              script that builds shared and/or static libraries

Versions of config.h and pcre.h are distributed in the PCRE tarballs under the
names config.h.generic and pcre.h.generic. These are provided for those who
have to built PCRE without using "configure" or CMake. If you use "configure"
or CMake, the .generic versions are not used.

When building the 8-bit library, if a C++ compiler is found, the following
files are also built:

. libpcrecpp.pc        data for the pkg-config command
. pcrecpparg.h         header file for calling PCRE via the C++ wrapper
. pcre_stringpiece.h   header for the C++ "stringpiece" functions

The "configure" script also creates config.status, which is an executable
script that can be run to recreate the configuration, and config.log, which
contains compiler output from tests that "configure" runs.

Once "configure" has run, you can run "make". This builds the the libraries
libpcre, libpcre16 and/or libpcre32, and a test program called pcretest. If you
enabled JIT support with --enable-jit, a test program called pcre_jit_test is
built as well.

If the 8-bit library is built, libpcreposix and the pcregrep command are also
built, and if a C++ compiler was found on your system, and you did not disable
it with --disable-cpp, "make" builds the C++ wrapper library, which is called
libpcrecpp, as well as some test programs called pcrecpp_unittest,
pcre_scanner_unittest, and pcre_stringpiece_unittest.

The command "make check" runs all the appropriate tests. Details of the PCRE
tests are given below in a separate section of this document.

You can use "make install" to install PCRE into live directories on your
system. The following are installed (file names are all relative to the
<prefix> that is set when "configure" is run):

  Commands (bin):
    pcretest
    pcregrep (if 8-bit support is enabled)
    pcre-config

  Libraries (lib):
    libpcre16     (if 16-bit support is enabled)
    libpcre32     (if 32-bit support is enabled)
    libpcre       (if 8-bit support is enabled)
    libpcreposix  (if 8-bit support is enabled)
    libpcrecpp    (if 8-bit and C++ support is enabled)

  Configuration information (lib/pkgconfig):
    libpcre16.pc
    libpcre32.pc
    libpcre.pc
    libpcreposix.pc
    libpcrecpp.pc (if C++ support is enabled)

  Header files (include):
    pcre.h
    pcreposix.h
    pcre_scanner.h      )
    pcre_stringpiece.h  ) if C++ support is enabled
    pcrecpp.h           )
    pcrecpparg.h        )

  Man pages (share/man/man{1,3}):
    pcregrep.1
    pcretest.1
    pcre-config.1
    pcre.3
    pcre*.3 (lots more pages, all starting "pcre")

  HTML documentation (share/doc/pcre/html):
    index.html
    *.html (lots more pages, hyperlinked from index.html)

  Text file documentation (share/doc/pcre):
    AUTHORS
    COPYING
    ChangeLog
    LICENCE
    NEWS
    README
    pcre.txt         (a concatenation of the man(3) pages)
    pcretest.txt     the pcretest man page
    pcregrep.txt     the pcregrep man page
    pcre-config.txt  the pcre-config man page

If you want to remove PCRE from your system, you can run "make uninstall".
This removes all the files that "make install" installed. However, it does not
remove any directories, because these are often shared with other programs.


Retrieving configuration information
------------------------------------

Running "make install" installs the command pcre-config, which can be used to
recall information about the PCRE configuration and installation. For example:

  pcre-config --version

prints the version number, and

  pcre-config --libs

outputs information about where the library is installed. This command can be
included in makefiles for programs that use PCRE, saving the programmer from
having to remember too many details.

The pkg-config command is another system for saving and retrieving information
about installed libraries. Instead of separate commands for each library, a
single command is used. For example:

  pkg-config --cflags pcre

The data is held in *.pc files that are installed in a directory called
<prefix>/lib/pkgconfig.


Shared libraries
----------------

The default distribution builds PCRE as shared libraries and static libraries,
as long as the operating system supports shared libraries. Shared library
support relies on the "libtool" script which is built as part of the
"configure" process.

The libtool script is used to compile and link both shared and static
libraries. They are placed in a subdirectory called .libs when they are newly
built. The programs pcretest and pcregrep are built to use these uninstalled
libraries (by means of wrapper scripts in the case of shared libraries). When
you use "make install" to install shared libraries, pcregrep and pcretest are
automatically re-built to use the newly installed shared libraries before being
installed themselves. However, the versions left in the build directory still
use the uninstalled libraries.

To build PCRE using static libraries only you must use --disable-shared when
configuring it. For example:

./configure --prefix=/usr/gnu --disable-shared

Then run "make" in the usual way. Similarly, you can use --disable-static to
build only shared libraries.


Cross-compiling using autotools
-------------------------------

You can specify CC and CFLAGS in the normal way to the "configure" command, in
order to cross-compile PCRE for some other host. However, you should NOT
specify --enable-rebuild-chartables, because if you do, the dftables.c source
file is compiled and run on the local host, in order to generate the inbuilt
character tables (the pcre_chartables.c file). This will probably not work,
because dftables.c needs to be compiled with the local compiler, not the cross
compiler.

When --enable-rebuild-chartables is not specified, pcre_chartables.c is created
by making a copy of pcre_chartables.c.dist, which is a default set of tables
that assumes ASCII code. Cross-compiling with the default tables should not be
a problem.

If you need to modify the character tables when cross-compiling, you should
move pcre_chartables.c.dist out of the way, then compile dftables.c by hand and
run it on the local host to make a new version of pcre_chartables.c.dist.
Then when you cross-compile PCRE this new version of the tables will be used.


Using HP's ANSI C++ compiler (aCC)
----------------------------------

Unless C++ support is disabled by specifying the "--disable-cpp" option of the
"configure" script, you must include the "-AA" option in the CXXFLAGS
environment variable in order for the C++ components to compile correctly.

Also, note that the aCC compiler on PA-RISC platforms may have a defect whereby
needed libraries fail to get included when specifying the "-AA" compiler
option. If you experience unresolved symbols when linking the C++ programs,
use the workaround of specifying the following environment variable prior to
running the "configure" script:

  CXXLDFLAGS="-lstd_v2 -lCsup_v2"


Compiling in Tru64 using native compilers
-----------------------------------------

The following error may occur when compiling with native compilers in the Tru64
operating system:

  CXX    libpcrecpp_la-pcrecpp.lo
cxx: Error: /usr/lib/cmplrs/cxx/V7.1-006/include/cxx/iosfwd, line 58: #error
          directive: "cannot include iosfwd -- define __USE_STD_IOSTREAM to
          override default - see section 7.1.2 of the C++ Using Guide"
#error "cannot include iosfwd -- define __USE_STD_IOSTREAM to override default
- see section 7.1.2 of the C++ Using Guide"

This may be followed by other errors, complaining that 'namespace "std" has no
member'. The solution to this is to add the line

#define __USE_STD_IOSTREAM 1

to the config.h file.


Using Sun's compilers for Solaris
---------------------------------

A user reports that the following configurations work on Solaris 9 sparcv9 and
Solaris 9 x86 (32-bit):

  Solaris 9 sparcv9: ./configure --disable-cpp CC=/bin/cc CFLAGS="-m64 -g"
  Solaris 9 x86:     ./configure --disable-cpp CC=/bin/cc CFLAGS="-g"


Using PCRE from MySQL
---------------------

On systems where both PCRE and MySQL are installed, it is possible to make use
of PCRE from within MySQL, as an alternative to the built-in pattern matching.
There is a web page that tells you how to do this:

  http://www.mysqludf.org/lib_mysqludf_preg/index.php


Making new tarballs
-------------------

The command "make dist" creates three PCRE tarballs, in tar.gz, tar.bz2, and
zip formats. The command "make distcheck" does the same, but then does a trial
build of the new distribution to ensure that it works.

If you have modified any of the man page sources in the doc directory, you
should first run the PrepareRelease script before making a distribution. This
script creates the .txt and HTML forms of the documentation from the man pages.


Testing PCRE
------------

To test the basic PCRE library on a Unix-like system, run the RunTest script.
There is another script called RunGrepTest that tests the options of the
pcregrep command. If the C++ wrapper library is built, three test programs
called pcrecpp_unittest, pcre_scanner_unittest, and pcre_stringpiece_unittest
are also built. When JIT support is enabled, another test program called
pcre_jit_test is built.

Both the scripts and all the program tests are run if you obey "make check" or
"make test". For other environments, see the instructions in
NON-AUTOTOOLS-BUILD.

The RunTest script runs the pcretest test program (which is documented in its
own man page) on each of the relevant testinput files in the testdata
directory, and compares the output with the contents of the corresponding
testoutput files. RunTest uses a file called testtry to hold the main output
from pcretest. Other files whose names begin with "test" are used as working
files in some tests.

Some tests are relevant only when certain build-time options were selected. For
example, the tests for UTF-8/16/32 support are run only if --enable-utf was
used. RunTest outputs a comment when it skips a test.

Many of the tests that are not skipped are run up to three times. The second
run forces pcre_study() to be called for all patterns except for a few in some
tests that are marked "never study" (see the pcretest program for how this is
done). If JIT support is available, the non-DFA tests are run a third time,
this time with a forced pcre_study() with the PCRE_STUDY_JIT_COMPILE option.
This testing can be suppressed by putting "nojit" on the RunTest command line.

The entire set of tests is run once for each of the 8-bit, 16-bit and 32-bit
libraries that are enabled. If you want to run just one set of tests, call
RunTest with either the -8, -16 or -32 option.

If valgrind is installed, you can run the tests under it by putting "valgrind"
on the RunTest command line. To run pcretest on just one or more specific test
files, give their numbers as arguments to RunTest, for example:

  RunTest 2 7 11

You can also specify ranges of tests such as 3-6 or 3- (meaning 3 to the
end), or a number preceded by ~ to exclude a test. For example:

  Runtest 3-15 ~10

This runs tests 3 to 15, excluding test 10, and just ~13 runs all the tests
except test 13. Whatever order the arguments are in, the tests are always run
in numerical order.

You can also call RunTest with the single argument "list" to cause it to output
a list of tests.

The first test file can be fed directly into the perltest.pl script to check
that Perl gives the same results. The only difference you should see is in the
first few lines, where the Perl version is given instead of the PCRE version.

The second set of tests check pcre_fullinfo(), pcre_study(),
pcre_copy_substring(), pcre_get_substring(), pcre_get_substring_list(), error
detection, and run-time flags that are specific to PCRE, as well as the POSIX
wrapper API. It also uses the debugging flags to check some of the internals of
pcre_compile().

If you build PCRE with a locale setting that is not the standard C locale, the
character tables may be different (see next paragraph). In some cases, this may
cause failures in the second set of tests. For example, in a locale where the
isprint() function yields TRUE for characters in the range 128-255, the use of
[:isascii:] inside a character class defines a different set of characters, and
this shows up in this test as a difference in the compiled code, which is being
listed for checking. Where the comparison test output contains [\x00-\x7f] the
test will contain [\x00-\xff], and similarly in some other cases. This is not a
bug in PCRE.

The third set of tests checks pcre_maketables(), the facility for building a
set of character tables for a specific locale and using them instead of the
default tables. The tests make use of the "fr_FR" (French) locale. Before
running the test, the script checks for the presence of this locale by running
the "locale" command. If that command fails, or if it doesn't include "fr_FR"
in the list of available locales, the third test cannot be run, and a comment
is output to say why. If running this test produces instances of the error

  ** Failed to set locale "fr_FR"

in the comparison output, it means that locale is not available on your system,
despite being listed by "locale". This does not mean that PCRE is broken.

[If you are trying to run this test on Windows, you may be able to get it to
work by changing "fr_FR" to "french" everywhere it occurs. Alternatively, use
RunTest.bat. The version of RunTest.bat included with PCRE 7.4 and above uses
Windows versions of test 2. More info on using RunTest.bat is included in the
document entitled NON-UNIX-USE.]

The fourth and fifth tests check the UTF-8/16/32 support and error handling and
internal UTF features of PCRE that are not relevant to Perl, respectively. The
sixth and seventh tests do the same for Unicode character properties support.

The eighth, ninth, and tenth tests check the pcre_dfa_exec() alternative
matching function, in non-UTF-8/16/32 mode, UTF-8/16/32 mode, and UTF-8/16/32
mode with Unicode property support, respectively.

The eleventh test checks some internal offsets and code size features; it is
run only when the default "link size" of 2 is set (in other cases the sizes
change) and when Unicode property support is enabled.

The twelfth test is run only when JIT support is available, and the thirteenth
test is run only when JIT support is not available. They test some JIT-specific
features such as information output from pcretest about JIT compilation.

The fourteenth, fifteenth, and sixteenth tests are run only in 8-bit mode, and
the seventeenth, eighteenth, and nineteenth tests are run only in 16/32-bit
mode. These are tests that generate different output in the two modes. They are
for general cases, UTF-8/16/32 support, and Unicode property support,
respectively.

The twentieth test is run only in 16/32-bit mode. It tests some specific
16/32-bit features of the DFA matching engine.

The twenty-first and twenty-second tests are run only in 16/32-bit mode, when
the link size is set to 2 for the 16-bit library. They test reloading
pre-compiled patterns.

The twenty-third and twenty-fourth tests are run only in 16-bit mode. They are
for general cases, and UTF-16 support, respectively.

The twenty-fifth and twenty-sixth tests are run only in 32-bit mode. They are
for general cases, and UTF-32 support, respectively.


Character tables
----------------

For speed, PCRE uses four tables for manipulating and identifying characters
whose code point values are less than 256. The final argument of the
pcre_compile() function is a pointer to a block of memory containing the
concatenated tables. A call to pcre_maketables() can be used to generate a set
of tables in the current locale. If the final argument for pcre_compile() is
passed as NULL, a set of default tables that is built into the binary is used.

The source file called pcre_chartables.c contains the default set of tables. By
default, this is created as a copy of pcre_chartables.c.dist, which contains
tables for ASCII coding. However, if --enable-rebuild-chartables is specified
for ./configure, a different version of pcre_chartables.c is built by the
program dftables (compiled from dftables.c), which uses the ANSI C character
handling functions such as isalnum(), isalpha(), isupper(), islower(), etc. to
build the table sources. This means that the default C locale which is set for
your system will control the contents of these default tables. You can change
the default tables by editing pcre_chartables.c and then re-building PCRE. If
you do this, you should take care to ensure that the file does not get
automatically re-generated. The best way to do this is to move
pcre_chartables.c.dist out of the way and replace it with your customized
tables.

When the dftables program is run as a result of --enable-rebuild-chartables,
it uses the default C locale that is set on your system. It does not pay
attention to the LC_xxx environment variables. In other words, it uses the
system's default locale rather than whatever the compiling user happens to have
set. If you really do want to build a source set of character tables in a
locale that is specified by the LC_xxx variables, you can run the dftables
program by hand with the -L option. For example:

  ./dftables -L pcre_chartables.c.special

The first two 256-byte tables provide lower casing and case flipping functions,
respectively. The next table consists of three 32-byte bit maps which identify
digits, "word" characters, and white space, respectively. These are used when
building 32-byte bit maps that represent character classes for code points less
than 256.

The final 256-byte table has bits indicating various character types, as
follows:

    1   white space character
    2   letter
    4   decimal digit
    8   hexadecimal digit
   16   alphanumeric or '_'
  128   regular expression metacharacter or binary zero

You should not alter the set of characters that contain the 128 bit, as that
will cause PCRE to malfunction.


File manifest
-------------

The distribution should contain the files listed below. Where a file name is
given as pcre[16|32]_xxx it means that there are three files, one with the name
pcre_xxx, one with the name pcre16_xx, and a third with the name pcre32_xxx.

(A) Source files of the PCRE library functions and their headers:

  dftables.c              auxiliary program for building pcre_chartables.c
                          when --enable-rebuild-chartables is specified

  pcre_chartables.c.dist  a default set of character tables that assume ASCII
                          coding; used, unless --enable-rebuild-chartables is
                          specified, by copying to pcre[16]_chartables.c

  pcreposix.c                )
  pcre[16|32]_byte_order.c   )
  pcre[16|32]_compile.c      )
  pcre[16|32]_config.c       )
  pcre[16|32]_dfa_exec.c     )
  pcre[16|32]_exec.c         )
  pcre[16|32]_fullinfo.c     )
  pcre[16|32]_get.c          ) sources for the functions in the library,
  pcre[16|32]_globals.c      )   and some internal functions that they use
  pcre[16|32]_jit_compile.c  )
  pcre[16|32]_maketables.c   )
  pcre[16|32]_newline.c      )
  pcre[16|32]_refcount.c     )
  pcre[16|32]_string_utils.c )
  pcre[16|32]_study.c        )
  pcre[16|32]_tables.c       )
  pcre[16|32]_ucd.c          )
  pcre[16|32]_version.c      )
  pcre[16|32]_xclass.c       )
  pcre_ord2utf8.c            )
  pcre_valid_utf8.c          )
  pcre16_ord2utf16.c         )
  pcre16_utf16_utils.c       )
  pcre16_valid_utf16.c       )
  pcre32_utf32_utils.c       )
  pcre32_valid_utf32.c       )

  pcre[16|32]_printint.c     ) debugging function that is used by pcretest,
                             )   and can also be #included in pcre_compile()

  pcre.h.in               template for pcre.h when built by "configure"
  pcreposix.h             header for the external POSIX wrapper API
  pcre_internal.h         header for internal use
  sljit/*                 16 files that make up the JIT compiler
  ucp.h                   header for Unicode property handling

  config.h.in             template for config.h, which is built by "configure"

  pcrecpp.h               public header file for the C++ wrapper
  pcrecpparg.h.in         template for another C++ header file
  pcre_scanner.h          public header file for C++ scanner functions
  pcrecpp.cc              )
  pcre_scanner.cc         ) source for the C++ wrapper library

  pcre_stringpiece.h.in   template for pcre_stringpiece.h, the header for the
                            C++ stringpiece functions
  pcre_stringpiece.cc     source for the C++ stringpiece functions

(B) Source files for programs that use PCRE:

  pcredemo.c              simple demonstration of coding calls to PCRE
  pcregrep.c              source of a grep utility that uses PCRE
  pcretest.c              comprehensive test program

(C) Auxiliary files:

  132html                 script to turn "man" pages into HTML
  AUTHORS                 information about the author of PCRE
  ChangeLog               log of changes to the code
  CleanTxt                script to clean nroff output for txt man pages
  Detrail                 script to remove trailing spaces
  HACKING                 some notes about the internals of PCRE
  INSTALL                 generic installation instructions
  LICENCE                 conditions for the use of PCRE
  COPYING                 the same, using GNU's standard name
  Makefile.in             ) template for Unix Makefile, which is built by
                          )   "configure"
  Makefile.am             ) the automake input that was used to create
                          )   Makefile.in
  NEWS                    important changes in this release
  NON-UNIX-USE            the previous name for NON-AUTOTOOLS-BUILD
  NON-AUTOTOOLS-BUILD     notes on building PCRE without using autotools
  PrepareRelease          script to make preparations for "make dist"
  README                  this file
  RunTest                 a Unix shell script for running tests
  RunGrepTest             a Unix shell script for pcregrep tests
  aclocal.m4              m4 macros (generated by "aclocal")
  config.guess            ) files used by libtool,
  config.sub              )   used only when building a shared library
  configure               a configuring shell script (built by autoconf)
  configure.ac            ) the autoconf input that was used to build
                          )   "configure" and config.h
  depcomp                 ) script to find program dependencies, generated by
                          )   automake
  doc/*.3                 man page sources for PCRE
  doc/*.1                 man page sources for pcregrep and pcretest
  doc/index.html.src      the base HTML page
  doc/html/*              HTML documentation
  doc/pcre.txt            plain text version of the man pages
  doc/pcretest.txt        plain text documentation of test program
  doc/perltest.txt        plain text documentation of Perl test program
  install-sh              a shell script for installing files
  libpcre16.pc.in         template for libpcre16.pc for pkg-config
  libpcre32.pc.in         template for libpcre32.pc for pkg-config
  libpcre.pc.in           template for libpcre.pc for pkg-config
  libpcreposix.pc.in      template for libpcreposix.pc for pkg-config
  libpcrecpp.pc.in        template for libpcrecpp.pc for pkg-config
  ltmain.sh               file used to build a libtool script
  missing                 ) common stub for a few missing GNU programs while
                          )   installing, generated by automake
  mkinstalldirs           script for making install directories
  perltest.pl             Perl test program
  pcre-config.in          source of script which retains PCRE information
  pcre_jit_test.c         test program for the JIT compiler
  pcrecpp_unittest.cc          )
  pcre_scanner_unittest.cc     ) test programs for the C++ wrapper
  pcre_stringpiece_unittest.cc )
  testdata/testinput*     test data for main library tests
  testdata/testoutput*    expected test results
  testdata/grep*          input and output for pcregrep tests
  testdata/*              other supporting test files

(D) Auxiliary files for cmake support

  cmake/COPYING-CMAKE-SCRIPTS
  cmake/FindPackageHandleStandardArgs.cmake
  cmake/FindEditline.cmake
  cmake/FindReadline.cmake
  CMakeLists.txt
  config-cmake.h.in

(E) Auxiliary files for VPASCAL

  makevp.bat
  makevp_c.txt
  makevp_l.txt
  pcregexp.pas

(F) Auxiliary files for building PCRE "by hand"

  pcre.h.generic          ) a version of the public PCRE header file
                          )   for use in non-"configure" environments
  config.h.generic        ) a version of config.h for use in non-"configure"
                          )   environments

(F) Miscellaneous

  RunTest.bat            a script for running tests under Windows

Philip Hazel
Email local part: ph10
Email domain: cam.ac.uk
Last updated: 10 February 2015
PK� %[�m^�qqdoc/alt-pcre/NEWSnu�[���News about PCRE releases
------------------------

Release 8.41 13-June-2017
-------------------------

This is a bug-fix release.


Release 8.40 11-January-2017
----------------------------

This is a bug-fix release.


Release 8.39 14-June-2016
-------------------------

Some appropriate PCRE2 JIT improvements have been retro-fitted to PCRE1. Apart
from that, this is another bug-fix release. Note that this library (now called
PCRE1) is now being maintained for bug fixes only. New projects are advised to
use the new PCRE2 libraries.


Release 8.38 23-November-2015
-----------------------------

This is bug-fix release. Note that this library (now called PCRE1) is now being
maintained for bug fixes only. New projects are advised to use the new PCRE2
libraries.


Release 8.37 28-April-2015
--------------------------

This is bug-fix release. Note that this library (now called PCRE1) is now being
maintained for bug fixes only. New projects are advised to use the new PCRE2
libraries.


Release 8.36 26-September-2014
------------------------------

This is primarily a bug-fix release. However, in addition, the Unicode data
tables have been updated to Unicode 7.0.0.


Release 8.35 04-April-2014
--------------------------

There have been performance improvements for classes containing non-ASCII
characters and the "auto-possessification" feature has been extended. Other
minor improvements have been implemented and bugs fixed. There is a new callout
feature to enable applications to do detailed stack checks at compile time, to
avoid running out of stack for deeply nested parentheses. The JIT compiler has
been extended with experimental support for ARM-64, MIPS-64, and PPC-LE.


Release 8.34 15-December-2013
-----------------------------

As well as fixing the inevitable bugs, performance has been improved by
refactoring and extending the amount of "auto-possessification" that PCRE does.
Other notable changes:

.  Implemented PCRE_INFO_MATCH_EMPTY, which yields 1 if the pattern can match
   an empty string. If it can, pcretest shows this in its information output.

.  A back reference to a named subpattern when there is more than one of the
   same name now checks them in the order in which they appear in the pattern.
   The first one that is set is used for the reference. Previously only the
   first one was inspected. This change makes PCRE more compatible with Perl.

.  Unicode character properties were updated from Unicode 6.3.0.

.  The character VT has been added to the set of characters that match \s and
   are generally treated as white space, following this same change in Perl
   5.18. There is now no difference between "Perl space" and "POSIX space".

.  Perl has changed its handling of \8 and \9. If there is no previously
   encountered capturing group of those numbers, they are treated as the
   literal characters 8 and 9 instead of a binary zero followed by the
   literals. PCRE now does the same.

.  Following Perl, added \o{} to specify codepoints in octal, making it
   possible to specify values greater than 0777 and also making them
   unambiguous.

.  In UCP mode, \s was not matching two of the characters that Perl matches,
   namely NEL (U+0085) and MONGOLIAN VOWEL SEPARATOR (U+180E), though they
   were matched by \h.

.  Add JIT support for the 64 bit TileGX architecture.

.  Upgraded the handling of the POSIX classes [:graph:], [:print:], and
   [:punct:] when PCRE_UCP is set so as to include the same characters as Perl
   does in Unicode mode.

.  Perl no longer allows group names to start with digits, so I have made this
   change also in PCRE.

.  Added support for [[:<:]] and [[:>:]] as used in the BSD POSIX library to
   mean "start of word" and "end of word", respectively, as a transition aid.


Release 8.33 28-May-2013
--------------------------

A number of bugs are fixed, and some performance improvements have been made.
There are also some new features, of which these are the most important:

.  The behaviour of the backtracking verbs has been rationalized and
   documented in more detail.

.  JIT now supports callouts and all of the backtracking verbs.

.  Unicode validation has been updated in the light of Unicode Corrigendum #9,
   which points out that "non characters" are not "characters that may not
   appear in Unicode strings" but rather "characters that are reserved for
   internal use and have only local meaning".

.  (*LIMIT_MATCH=d) and (*LIMIT_RECURSION=d) have been added so that the
   creator of a pattern can specify lower (but not higher) limits for the
   matching process.

.  The PCRE_NEVER_UTF option is available to prevent pattern-writers from using
   the (*UTF) feature, as this could be a security issue.


Release 8.32 30-November-2012
-----------------------------

This release fixes a number of bugs, but also has some new features. These are
the highlights:

.  There is now support for 32-bit character strings and UTF-32. Like the
   16-bit support, this is done by compiling a separate 32-bit library.

.  \X now matches a Unicode extended grapheme cluster.

.  Case-independent matching of Unicode characters that have more than one
   "other case" now makes all three (or more) characters equivalent. This
   applies, for example, to Greek Sigma, which has two lowercase versions.

.  Unicode character properties are updated to Unicode 6.2.0.

.  The EBCDIC support, which had decayed, has had a spring clean.

.  A number of JIT optimizations have been added, which give faster JIT
   execution speed. In addition, a new direct interface to JIT execution is
   available. This bypasses some of the sanity checks of pcre_exec() to give a
   noticeable speed-up.

.  A number of issues in pcregrep have been fixed, making it more compatible
   with GNU grep. In particular, --exclude and --include (and variants) apply
   to all files now, not just those obtained from scanning a directory
   recursively. In Windows environments, the default action for directories is
   now "skip" instead of "read" (which provokes an error).

.  If the --only-matching (-o) option in pcregrep is specified multiple
   times, each one causes appropriate output. For example, -o1 -o2 outputs the
   substrings matched by the 1st and 2nd capturing parentheses. A separating
   string can be specified by --om-separator (default empty).

.  When PCRE is built via Autotools using a version of gcc that has the
   "visibility" feature, it is used to hide internal library functions that are
   not part of the public API.


Release 8.31 06-July-2012
-------------------------

This is mainly a bug-fixing release, with a small number of developments:

. The JIT compiler now supports partial matching and the (*MARK) and
  (*COMMIT) verbs.

. PCRE_INFO_MAXLOOKBEHIND can be used to find the longest lookbehind in a
  pattern.

. There should be a performance improvement when using the heap instead of the
  stack for recursion.

. pcregrep can now be linked with libedit as an alternative to libreadline.

. pcregrep now has a --file-list option where the list of files to scan is
  given as a file.

. pcregrep now recognizes binary files and there are related options.

. The Unicode tables have been updated to 6.1.0.

As always, the full list of changes is in the ChangeLog file.


Release 8.30 04-February-2012
-----------------------------

Release 8.30 introduces a major new feature: support for 16-bit character
strings, compiled as a separate library. There are a few changes to the
8-bit library, in addition to some bug fixes.

. The pcre_info() function, which has been obsolete for over 10 years, has
  been removed.

. When a compiled pattern was saved to a file and later reloaded on a host
  with different endianness, PCRE used automatically to swap the bytes in some
  of the data fields. With the advent of the 16-bit library, where more of this
  swapping is needed, it is no longer done automatically. Instead, the bad
  endianness is detected and a specific error is given. The user can then call
  a new function called pcre_pattern_to_host_byte_order() (or an equivalent
  16-bit function) to do the swap.

. In UTF-8 mode, the values 0xd800 to 0xdfff are not legal Unicode
  code points and are now faulted. (They are the so-called "surrogates"
  that are reserved for coding high values in UTF-16.)


Release 8.21 12-Dec-2011
------------------------

This is almost entirely a bug-fix release. The only new feature is the ability
to obtain the size of the memory used by the JIT compiler.


Release 8.20 21-Oct-2011
------------------------

The main change in this release is the inclusion of Zoltan Herczeg's
just-in-time compiler support, which can be accessed by building PCRE with
--enable-jit. Large performance benefits can be had in many situations. 8.20
also fixes an unfortunate bug that was introduced in 8.13 as well as tidying up
a number of infelicities and differences from Perl.


Release 8.13 16-Aug-2011
------------------------

This is mainly a bug-fix release. There has been a lot of internal refactoring.
The Unicode tables have been updated. The only new feature in the library is
the passing of *MARK information to callouts. Some additions have been made to
pcretest to make testing easier and more comprehensive. There is a new option
for pcregrep to adjust its internal buffer size.


Release 8.12 15-Jan-2011
------------------------

This release fixes some bugs in pcregrep, one of which caused the tests to fail
on 64-bit big-endian systems. There are no changes to the code of the library.


Release 8.11 10-Dec-2010
------------------------

A number of bugs in the library and in pcregrep have been fixed. As always, see
ChangeLog for details. The following are the non-bug-fix changes:

. Added --match-limit and --recursion-limit to pcregrep.

. Added an optional parentheses number to the -o and --only-matching options
  of pcregrep.

. Changed the way PCRE_PARTIAL_HARD affects the matching of $, \z, \Z, \b, and
  \B.

. Added PCRE_ERROR_SHORTUTF8 to make it possible to distinguish between a
  bad UTF-8 sequence and one that is incomplete when using PCRE_PARTIAL_HARD.

. Recognize (*NO_START_OPT) at the start of a pattern to set the PCRE_NO_
  START_OPTIMIZE option, which is now allowed at compile time


Release 8.10 25-Jun-2010
------------------------

There are two major additions: support for (*MARK) and friends, and the option
PCRE_UCP, which changes the behaviour of \b, \d, \s, and \w (and their
opposites) so that they make use of Unicode properties. There are also a number
of lesser new features, and several bugs have been fixed. A new option,
--line-buffered, has been added to pcregrep, for use when it is connected to
pipes.


Release 8.02 19-Mar-2010
------------------------

Another bug-fix release.


Release 8.01 19-Jan-2010
------------------------

This is a bug-fix release. Several bugs in the code itself and some bugs and
infelicities in the build system have been fixed.


Release 8.00 19-Oct-09
----------------------

Bugs have been fixed in the library and in pcregrep. There are also some
enhancements. Restrictions on patterns used for partial matching have been
removed, extra information is given for partial matches, the partial matching
process has been improved, and an option to make a partial match override a
full match is available. The "study" process has been enhanced by finding a
lower bound matching length. Groups with duplicate numbers may now have
duplicated names without the use of PCRE_DUPNAMES. However, they may not have
different names. The documentation has been revised to reflect these changes.
The version number has been expanded to 3 digits as it is clear that the rate
of change is not slowing down.


Release 7.9 11-Apr-09
---------------------

Mostly bugfixes and tidies with just a couple of minor functional additions.


Release 7.8 05-Sep-08
---------------------

More bug fixes, plus a performance improvement in Unicode character property
lookup.


Release 7.7 07-May-08
---------------------

This is once again mainly a bug-fix release, but there are a couple of new
features.


Release 7.6 28-Jan-08
---------------------

The main reason for having this release so soon after 7.5 is because it fixes a
potential buffer overflow problem in pcre_compile() when run in UTF-8 mode. In
addition, the CMake configuration files have been brought up to date.


Release 7.5 10-Jan-08
---------------------

This is mainly a bug-fix release. However the ability to link pcregrep with
libz or libbz2 and the ability to link pcretest with libreadline have been
added. Also the --line-offsets and --file-offsets options were added to
pcregrep.


Release 7.4 21-Sep-07
---------------------

The only change of specification is the addition of options to control whether
\R matches any Unicode line ending (the default) or just CR, LF, and CRLF.
Otherwise, the changes are bug fixes and a refactoring to reduce the number of
relocations needed in a shared library. There have also been some documentation
updates, in particular, some more information about using CMake to build PCRE
has been added to the NON-UNIX-USE file.


Release 7.3 28-Aug-07
---------------------

Most changes are bug fixes. Some that are not:

1. There is some support for Perl 5.10's experimental "backtracking control
   verbs" such as (*PRUNE).

2. UTF-8 checking is now as per RFC 3629 instead of RFC 2279; this is more
   restrictive in the strings it accepts.

3. Checking for potential integer overflow has been made more dynamic, and as a
   consequence there is no longer a hard limit on the size of a subpattern that
   has a limited repeat count.

4. When CRLF is a valid line-ending sequence, pcre_exec() and pcre_dfa_exec()
   no longer advance by two characters instead of one when an unanchored match
   fails at CRLF if there are explicit CR or LF matches within the pattern.
   This gets rid of some anomalous effects that previously occurred.

5. Some PCRE-specific settings for varying the newline options at the start of
   a pattern have been added.


Release 7.2 19-Jun-07
---------------------

WARNING: saved patterns that were compiled by earlier versions of PCRE must be
recompiled for use with 7.2 (necessitated by the addition of \K, \h, \H, \v,
and \V).

Correction to the notes for 7.1: the note about shared libraries for Windows is
wrong. Previously, three libraries were built, but each could function
independently. For example, the pcreposix library also included all the
functions from the basic pcre library. The change is that the three libraries
are no longer independent. They are like the Unix libraries. To use the
pcreposix functions, for example, you need to link with both the pcreposix and
the basic pcre library.

Some more features from Perl 5.10 have been added:

  (?-n) and (?+n) relative references for recursion and subroutines.

  (?(-n) and (?(+n) relative references as conditions.

  \k{name} and \g{name} are synonyms for \k<name>.

  \K to reset the start of the matched string; for example, (foo)\Kbar
  matches bar preceded by foo, but only sets bar as the matched string.

  (?| introduces a group where the capturing parentheses in each alternative
  start from the same number; for example, (?|(abc)|(xyz)) sets capturing
  parentheses number 1 in both cases.

  \h, \H, \v, \V match horizontal and vertical whitespace, respectively.


Release 7.1 24-Apr-07
---------------------

There is only one new feature in this release: a linebreak setting of
PCRE_NEWLINE_ANYCRLF. It is a cut-down version of PCRE_NEWLINE_ANY, which
recognizes only CRLF, CR, and LF as linebreaks.

A few bugs are fixed (see ChangeLog for details), but the major change is a
complete re-implementation of the build system. This now has full Autotools
support and so is now "standard" in some sense. It should help with compiling
PCRE in a wide variety of environments.

NOTE: when building shared libraries for Windows, three dlls are now built,
called libpcre, libpcreposix, and libpcrecpp. Previously, everything was
included in a single dll.

Another important change is that the dftables auxiliary program is no longer
compiled and run at "make" time by default. Instead, a default set of character
tables (assuming ASCII coding) is used. If you want to use dftables to generate
the character tables as previously, add --enable-rebuild-chartables to the
"configure" command. You must do this if you are compiling PCRE to run on a
system that uses EBCDIC code.

There is a discussion about character tables in the README file. The default is
not to use dftables so that that there is no problem when cross-compiling.


Release 7.0 19-Dec-06
---------------------

This release has a new major number because there have been some internal
upheavals to facilitate the addition of new optimizations and other facilities,
and to make subsequent maintenance and extension easier. Compilation is likely
to be a bit slower, but there should be no major effect on runtime performance.
Previously compiled patterns are NOT upwards compatible with this release. If
you have saved compiled patterns from a previous release, you will have to
re-compile them. Important changes that are visible to users are:

1. The Unicode property tables have been updated to Unicode 5.0.0, which adds
   some more scripts.

2. The option PCRE_NEWLINE_ANY causes PCRE to recognize any Unicode newline
   sequence as a newline.

3. The \R escape matches a single Unicode newline sequence as a single unit.

4. New features that will appear in Perl 5.10 are now in PCRE. These include
   alternative Perl syntax for named parentheses, and Perl syntax for
   recursion.

5. The C++ wrapper interface has been extended by the addition of a
   QuoteMeta function and the ability to allow copy construction and
   assignment.

For a complete list of changes, see the ChangeLog file.


Release 6.7 04-Jul-06
---------------------

The main additions to this release are the ability to use the same name for
multiple sets of parentheses, and support for CRLF line endings in both the
library and pcregrep (and in pcretest for testing).

Thanks to Ian Taylor, the stack usage for many kinds of pattern has been
significantly reduced for certain subject strings.


Release 6.5 01-Feb-06
---------------------

Important changes in this release:

1. A number of new features have been added to pcregrep.

2. The Unicode property tables have been updated to Unicode 4.1.0, and the
   supported properties have been extended with script names such as "Arabic",
   and the derived properties "Any" and "L&". This has necessitated a change to
   the interal format of compiled patterns. Any saved compiled patterns that
   use \p or \P must be recompiled.

3. The specification of recursion in patterns has been changed so that all
   recursive subpatterns are automatically treated as atomic groups. Thus, for
   example, (?R) is treated as if it were (?>(?R)). This is necessary because
   otherwise there are situations where recursion does not work.

See the ChangeLog for a complete list of changes, which include a number of bug
fixes and tidies.


Release 6.0 07-Jun-05
---------------------

The release number has been increased to 6.0 because of the addition of several
major new pieces of functionality.

A new function, pcre_dfa_exec(), which implements pattern matching using a DFA
algorithm, has been added. This has a number of advantages for certain cases,
though it does run more slowly, and lacks the ability to capture substrings. On
the other hand, it does find all matches, not just the first, and it works
better for partial matching. The pcrematching man page discusses the
differences.

The pcretest program has been enhanced so that it can make use of the new
pcre_dfa_exec() matching function and the extra features it provides.

The distribution now includes a C++ wrapper library. This is built
automatically if a C++ compiler is found. The pcrecpp man page discusses this
interface.

The code itself has been re-organized into many more files, one for each
function, so it no longer requires everything to be linked in when static
linkage is used. As a consequence, some internal functions have had to have
their names exposed. These functions all have names starting with _pcre_. They
are undocumented, and are not intended for use by outside callers.

The pcregrep program has been enhanced with new functionality such as
multiline-matching and options for output more matching context. See the
ChangeLog for a complete list of changes to the library and the utility
programs.


Release 5.0 13-Sep-04
---------------------

The licence under which PCRE is released has been changed to the more
conventional "BSD" licence.

In the code, some bugs have been fixed, and there are also some major changes
in this release (which is why I've increased the number to 5.0). Some changes
are internal rearrangements, and some provide a number of new facilities. The
new features are:

1. There's an "automatic callout" feature that inserts callouts before every
   item in the regex, and there's a new callout field that gives the position
   in the pattern - useful for debugging and tracing.

2. The extra_data structure can now be used to pass in a set of character
   tables at exec time. This is useful if compiled regex are saved and re-used
   at a later time when the tables may not be at the same address. If the
   default internal tables are used, the pointer saved with the compiled
   pattern is now set to NULL, which means that you don't need to do anything
   special unless you are using custom tables.

3. It is possible, with some restrictions on the content of the regex, to
   request "partial" matching. A special return code is given if all of the
   subject string matched part of the regex. This could be useful for testing
   an input field as it is being typed.

4. There is now some optional support for Unicode character properties, which
   means that the patterns items such as \p{Lu} and \X can now be used. Only
   the general category properties are supported. If PCRE is compiled with this
   support, an additional 90K data structure is include, which increases the
   size of the library dramatically.

5. There is support for saving compiled patterns and re-using them later.

6. There is support for running regular expressions that were compiled on a
   different host with the opposite endianness.

7. The pcretest program has been extended to accommodate the new features.

The main internal rearrangement is that sequences of literal characters are no
longer handled as strings. Instead, each character is handled on its own. This
makes some UTF-8 handling easier, and makes the support of partial matching
possible. Compiled patterns containing long literal strings will be larger as a
result of this change; I hope that performance will not be much affected.


Release 4.5 01-Dec-03
---------------------

Again mainly a bug-fix and tidying release, with only a couple of new features:

1. It's possible now to compile PCRE so that it does not use recursive
function calls when matching. Instead it gets memory from the heap. This slows
things down, but may be necessary on systems with limited stacks.

2. UTF-8 string checking has been tightened to reject overlong sequences and to
check that a starting offset points to the start of a character. Failure of the
latter returns a new error code: PCRE_ERROR_BADUTF8_OFFSET.

3. PCRE can now be compiled for systems that use EBCDIC code.


Release 4.4 21-Aug-03
---------------------

This is mainly a bug-fix and tidying release. The only new feature is that PCRE
checks UTF-8 strings for validity by default. There is an option to suppress
this, just in case anybody wants that teeny extra bit of performance.


Releases 4.1 - 4.3
------------------

Sorry, I forgot about updating the NEWS file for these releases. Please take a
look at ChangeLog.


Release 4.0 17-Feb-03
---------------------

There have been a lot of changes for the 4.0 release, adding additional
functionality and mending bugs. Below is a list of the highlights of the new
functionality. For full details of these features, please consult the
documentation. For a complete list of changes, see the ChangeLog file.

1. Support for Perl's \Q...\E escapes.

2. "Possessive quantifiers" ?+, *+, ++, and {,}+ which come from Sun's Java
package. They provide some syntactic sugar for simple cases of "atomic
grouping".

3. Support for the \G assertion. It is true when the current matching position
is at the start point of the match.

4. A new feature that provides some of the functionality that Perl provides
with (?{...}). The facility is termed a "callout". The way it is done in PCRE
is for the caller to provide an optional function, by setting pcre_callout to
its entry point. To get the function called, the regex must include (?C) at
appropriate points.

5. Support for recursive calls to individual subpatterns. This makes it really
easy to get totally confused.

6. Support for named subpatterns. The Python syntax (?P<name>...) is used to
name a group.

7. Several extensions to UTF-8 support; it is now fairly complete. There is an
option for pcregrep to make it operate in UTF-8 mode.

8. The single man page has been split into a number of separate man pages.
These also give rise to individual HTML pages which are put in a separate
directory. There is an index.html page that lists them all. Some hyperlinking
between the pages has been installed.


Release 3.5 15-Aug-01
---------------------

1. The configuring system has been upgraded to use later versions of autoconf
and libtool. By default it builds both a shared and a static library if the OS
supports it. You can use --disable-shared or --disable-static on the configure
command if you want only one of them.

2. The pcretest utility is now installed along with pcregrep because it is
useful for users (to test regexs) and by doing this, it automatically gets
relinked by libtool. The documentation has been turned into a man page, so
there are now .1, .txt, and .html versions in /doc.

3. Upgrades to pcregrep:
   (i)   Added long-form option names like gnu grep.
   (ii)  Added --help to list all options with an explanatory phrase.
   (iii) Added -r, --recursive to recurse into sub-directories.
   (iv)  Added -f, --file to read patterns from a file.

4. Added --enable-newline-is-cr and --enable-newline-is-lf to the configure
script, to force use of CR or LF instead of \n in the source. On non-Unix
systems, the value can be set in config.h.

5. The limit of 200 on non-capturing parentheses is a _nesting_ limit, not an
absolute limit. Changed the text of the error message to make this clear, and
likewise updated the man page.

6. The limit of 99 on the number of capturing subpatterns has been removed.
The new limit is 65535, which I hope will not be a "real" limit.


Release 3.3 01-Aug-00
---------------------

There is some support for UTF-8 character strings. This is incomplete and
experimental. The documentation describes what is and what is not implemented.
Otherwise, this is just a bug-fixing release.


Release 3.0 01-Feb-00
---------------------

1. A "configure" script is now used to configure PCRE for Unix systems. It
builds a Makefile, a config.h file, and the pcre-config script.

2. PCRE is built as a shared library by default.

3. There is support for POSIX classes such as [:alpha:].

5. There is an experimental recursion feature.

----------------------------------------------------------------------------
          IMPORTANT FOR THOSE UPGRADING FROM VERSIONS BEFORE 2.00

Please note that there has been a change in the API such that a larger
ovector is required at matching time, to provide some additional workspace.
The new man page has details. This change was necessary in order to support
some of the new functionality in Perl 5.005.

          IMPORTANT FOR THOSE UPGRADING FROM VERSION 2.00

Another (I hope this is the last!) change has been made to the API for the
pcre_compile() function. An additional argument has been added to make it
possible to pass over a pointer to character tables built in the current
locale by pcre_maketables(). To use the default tables, this new argument
should be passed as NULL.

          IMPORTANT FOR THOSE UPGRADING FROM VERSION 2.05

Yet another (and again I hope this really is the last) change has been made
to the API for the pcre_exec() function. An additional argument has been
added to make it possible to start the match other than at the start of the
subject string. This is important if there are lookbehinds. The new man
page has the details, but you just want to convert existing programs, all
you need to do is to stick in a new fifth argument to pcre_exec(), with a
value of zero. For example, change

  pcre_exec(pattern, extra, subject, length, options, ovec, ovecsize)
to
  pcre_exec(pattern, extra, subject, length, 0, options, ovec, ovecsize)

****
PK� %[�*��z�zdoc/alt-pcre/ChangeLognu�[���ChangeLog for PCRE
------------------

Note that the PCRE 8.xx series (PCRE1) is now in a bugfix-only state. All
development is happening in the PCRE2 10.xx series.

Version 8.41 05-July-2017
-------------------------

1.  Fixed typo in CMakeLists.txt (wrong number of arguments for
PCRE_STATIC_RUNTIME (affects MSVC only).

2.  Issue 1 for 8.40 below was not correctly fixed. If pcregrep in multiline
mode with --only-matching matched several lines, it restarted scanning at the
next line instead of moving on to the end of the matched string, which can be
several lines after the start.

3.  Fix a missing else in the JIT compiler reported by 'idaifish'.

4.  A (?# style comment is now ignored between a basic quantifier and a
following '+' or '?' (example: /X+(?#comment)?Y/.

5.  Avoid use of a potentially overflowing buffer in pcregrep (patch by Petr
Pisar).

6.  Fuzzers have reported issues in pcretest. These are NOT serious (it is,
after all, just a test program). However, to stop the reports, some easy ones
are fixed:

    (a) Check for values < 256 when calling isprint() in pcretest.
    (b) Give an error for too big a number after \O.

7.  In the 32-bit library in non-UTF mode, an attempt to find a Unicode
property for a character with a code point greater than 0x10ffff (the Unicode
maximum) caused a crash.

8. The alternative matching function, pcre_dfa_exec() misbehaved if it
encountered a character class with a possessive repeat, for example [a-f]{3}+.

9. When pcretest called pcre_copy_substring() in 32-bit mode, it set the buffer
length incorrectly, which could result in buffer overflow.

10. Remove redundant line of code (accidentally left in ages ago).

11. Applied C++ patch from Irfan Adilovic to guard 'using std::' directives
with namespace pcrecpp (Bugzilla #2084).

12. Remove a duplication typo in pcre_tables.c.

13. Fix returned offsets from regexec() when REG_STARTEND is used with a
starting offset greater than zero.


Version 8.40 11-January-2017
----------------------------

1.  Using -o with -M in pcregrep could cause unnecessary repeated output when
    the match extended over a line boundary.

2.  Applied Chris Wilson's second patch (Bugzilla #1681) to CMakeLists.txt for
    MSVC static compilation, putting the first patch under a new option.

3.  Fix register overwite in JIT when SSE2 acceleration is enabled.

4.  Ignore "show all captures" (/=) for DFA matching.

5.  Fix JIT unaligned accesses on x86. Patch by Marc Mutz.

6.  In any wide-character mode (8-bit UTF or any 16-bit or 32-bit mode),
    without PCRE_UCP set, a negative character type such as \D in a positive
    class should cause all characters greater than 255 to match, whatever else
    is in the class. There was a bug that caused this not to happen if a
    Unicode property item was added to such a class, for example [\D\P{Nd}] or
    [\W\pL].

7.  When pcretest was outputing information from a callout, the caret indicator
    for the current position in the subject line was incorrect if it was after
    an escape sequence for a character whose code point was greater than
    \x{ff}.

8.  A pattern such as (?<RA>abc)(?(R)xyz) was incorrectly compiled such that
    the conditional was interpreted as a reference to capturing group 1 instead
    of a test for recursion. Any group whose name began with R was
    misinterpreted in this way. (The reference interpretation should only
    happen if the group's name is precisely "R".)

9.  A number of bugs have been mended relating to match start-up optimizations
    when the first thing in a pattern is a positive lookahead. These all
    applied only when PCRE_NO_START_OPTIMIZE was *not* set:

    (a) A pattern such as (?=.*X)X$ was incorrectly optimized as if it needed
        both an initial 'X' and a following 'X'.
    (b) Some patterns starting with an assertion that started with .* were
        incorrectly optimized as having to match at the start of the subject or
        after a newline. There are cases where this is not true, for example,
        (?=.*[A-Z])(?=.{8,16})(?!.*[\s]) matches after the start in lines that
        start with spaces. Starting .* in an assertion is no longer taken as an
        indication of matching at the start (or after a newline).


Version 8.39 14-June-2016
-------------------------

1.  If PCRE_AUTO_CALLOUT was set on a pattern that had a (?# comment between
    an item and its qualifier (for example, A(?#comment)?B) pcre_compile()
    misbehaved. This bug was found by the LLVM fuzzer.

2.  Similar to the above, if an isolated \E was present between an item and its
    qualifier when PCRE_AUTO_CALLOUT was set, pcre_compile() misbehaved. This
    bug was found by the LLVM fuzzer.

3.  Further to 8.38/46, negated classes such as [^[:^ascii:]\d] were also not
    working correctly in UCP mode.

4.  The POSIX wrapper function regexec() crashed if the option REG_STARTEND
    was set when the pmatch argument was NULL. It now returns REG_INVARG.

5.  Allow for up to 32-bit numbers in the ordin() function in pcregrep.

6.  An empty \Q\E sequence between an item and its qualifier caused
    pcre_compile() to misbehave when auto callouts were enabled. This bug was
    found by the LLVM fuzzer.

7.  If a pattern that was compiled with PCRE_EXTENDED started with white
    space or a #-type comment that was followed by (?-x), which turns off
    PCRE_EXTENDED, and there was no subsequent (?x) to turn it on again,
    pcre_compile() assumed that (?-x) applied to the whole pattern and
    consequently mis-compiled it. This bug was found by the LLVM fuzzer.

8.  A call of pcre_copy_named_substring() for a named substring whose number
    was greater than the space in the ovector could cause a crash.

9.  Yet another buffer overflow bug involved duplicate named groups with a
    group that reset capture numbers (compare 8.38/7 below). Once again, I have
    just allowed for more memory, even if not needed. (A proper fix is
    implemented in PCRE2, but it involves a lot of refactoring.)

10. pcre_get_substring_list() crashed if the use of \K in a match caused the
    start of the match to be earlier than the end.

11. Migrating appropriate PCRE2 JIT improvements to PCRE.

12. A pattern such as /(?<=((?C)0))/, which has a callout inside a lookbehind
    assertion, caused pcretest to generate incorrect output, and also to read
    uninitialized memory (detected by ASAN or valgrind).

13. A pattern that included (*ACCEPT) in the middle of a sufficiently deeply
    nested set of parentheses of sufficient size caused an overflow of the
    compiling workspace (which was diagnosed, but of course is not desirable).

14. And yet another buffer overflow bug involving duplicate named groups, this
    time nested, with a nested back reference. Yet again, I have just allowed
    for more memory, because anything more needs all the refactoring that has
    been done for PCRE2. An example pattern that provoked this bug is:
    /((?J)(?'R'(?'R'(?'R'(?'R'(?'R'(?|(\k'R'))))))))/ and the bug was
    registered as CVE-2016-1283.

15. pcretest went into a loop if global matching was requested with an ovector
    size less than 2. It now gives an error message. This bug was found by
    afl-fuzz.

16. An invalid pattern fragment such as (?(?C)0 was not diagnosing an error
    ("assertion expected") when (?(?C) was not followed by an opening
    parenthesis.

17. Fixed typo ("&&" for "&") in pcre_study(). Fortunately, this could not
    actually affect anything, by sheer luck.

18. Applied Chris Wilson's patch (Bugzilla #1681) to CMakeLists.txt for MSVC
    static compilation.

19. Modified the RunTest script to incorporate a valgrind suppressions file so
    that certain errors, provoked by the SSE2 instruction set when JIT is used,
    are ignored.

20. A racing condition is fixed in JIT reported by Mozilla.

21. Minor code refactor to avoid "array subscript is below array bounds"
    compiler warning.

22. Minor code refactor to avoid "left shift of negative number" warning.

23. Fix typo causing compile error when 16- or 32-bit JIT is compiled without
    UCP support.

24. Refactor to avoid compiler warnings in pcrecpp.cc.

25. Refactor to fix a typo in pcre_jit_test.c

26. Patch to support compiling pcrecpp.cc with Intel compiler.


Version 8.38 23-November-2015
-----------------------------

1.  If a group that contained a recursive back reference also contained a
    forward reference subroutine call followed by a non-forward-reference
    subroutine call, for example /.((?2)(?R)\1)()/, pcre_compile() failed to
    compile correct code, leading to undefined behaviour or an internally
    detected error. This bug was discovered by the LLVM fuzzer.

2.  Quantification of certain items (e.g. atomic back references) could cause
    incorrect code to be compiled when recursive forward references were
    involved. For example, in this pattern: /(?1)()((((((\1++))\x85)+)|))/.
    This bug was discovered by the LLVM fuzzer.

3.  A repeated conditional group whose condition was a reference by name caused
    a buffer overflow if there was more than one group with the given name.
    This bug was discovered by the LLVM fuzzer.

4.  A recursive back reference by name within a group that had the same name as
    another group caused a buffer overflow. For example:
    /(?J)(?'d'(?'d'\g{d}))/. This bug was discovered by the LLVM fuzzer.

5.  A forward reference by name to a group whose number is the same as the
    current group, for example in this pattern: /(?|(\k'Pm')|(?'Pm'))/, caused
    a buffer overflow at compile time. This bug was discovered by the LLVM
    fuzzer.

6.  A lookbehind assertion within a set of mutually recursive subpatterns could
    provoke a buffer overflow. This bug was discovered by the LLVM fuzzer.

7.  Another buffer overflow bug involved duplicate named groups with a
    reference between their definition, with a group that reset capture
    numbers, for example: /(?J:(?|(?'R')(\k'R')|((?'R'))))/. This has been
    fixed by always allowing for more memory, even if not needed. (A proper fix
    is implemented in PCRE2, but it involves more refactoring.)

8.  There was no check for integer overflow in subroutine calls such as (?123).

9.  The table entry for \l in EBCDIC environments was incorrect, leading to its
    being treated as a literal 'l' instead of causing an error.

10. There was a buffer overflow if pcre_exec() was called with an ovector of
    size 1. This bug was found by american fuzzy lop.

11. If a non-capturing group containing a conditional group that could match
    an empty string was repeated, it was not identified as matching an empty
    string itself. For example: /^(?:(?(1)x|)+)+$()/.

12. In an EBCDIC environment, pcretest was mishandling the escape sequences
    \a and \e in test subject lines.

13. In an EBCDIC environment, \a in a pattern was converted to the ASCII
    instead of the EBCDIC value.

14. The handling of \c in an EBCDIC environment has been revised so that it is
    now compatible with the specification in Perl's perlebcdic page.

15. The EBCDIC character 0x41 is a non-breaking space, equivalent to 0xa0 in
    ASCII/Unicode. This has now been added to the list of characters that are
    recognized as white space in EBCDIC.

16. When PCRE was compiled without UCP support, the use of \p and \P gave an
    error (correctly) when used outside a class, but did not give an error
    within a class.

17. \h within a class was incorrectly compiled in EBCDIC environments.

18. A pattern with an unmatched closing parenthesis that contained a backward
    assertion which itself contained a forward reference caused buffer
    overflow. And example pattern is: /(?=di(?<=(?1))|(?=(.))))/.

19. JIT should return with error when the compiled pattern requires more stack
    space than the maximum.

20. A possessively repeated conditional group that could match an empty string,
    for example, /(?(R))*+/, was incorrectly compiled.

21. Fix infinite recursion in the JIT compiler when certain patterns such as
    /(?:|a|){100}x/ are analysed.

22. Some patterns with character classes involving [: and \\ were incorrectly
    compiled and could cause reading from uninitialized memory or an incorrect
    error diagnosis.

23. Pathological patterns containing many nested occurrences of [: caused
    pcre_compile() to run for a very long time.

24. A conditional group with only one branch has an implicit empty alternative
    branch and must therefore be treated as potentially matching an empty
    string.

25. If (?R was followed by - or + incorrect behaviour happened instead of a
    diagnostic.

26. Arrange to give up on finding the minimum matching length for overly
    complex patterns.

27. Similar to (4) above: in a pattern with duplicated named groups and an
    occurrence of (?| it is possible for an apparently non-recursive back
    reference to become recursive if a later named group with the relevant
    number is encountered. This could lead to a buffer overflow. Wen Guanxing
    from Venustech ADLAB discovered this bug.

28. If pcregrep was given the -q option with -c or -l, or when handling a
    binary file, it incorrectly wrote output to stdout.

29. The JIT compiler did not restore the control verb head in case of *THEN
    control verbs. This issue was found by Karl Skomski with a custom LLVM
    fuzzer.

30. Error messages for syntax errors following \g and \k were giving inaccurate
    offsets in the pattern.

31. Added a check for integer overflow in conditions (?(<digits>) and
    (?(R<digits>). This omission was discovered by Karl Skomski with the LLVM
    fuzzer.

32. Handling recursive references such as (?2) when the reference is to a group
    later in the pattern uses code that is very hacked about and error-prone.
    It has been re-written for PCRE2. Here in PCRE1, a check has been added to
    give an internal error if it is obvious that compiling has gone wrong.

33. The JIT compiler should not check repeats after a {0,1} repeat byte code.
    This issue was found by Karl Skomski with a custom LLVM fuzzer.

34. The JIT compiler should restore the control chain for empty possessive
    repeats. This issue was found by Karl Skomski with a custom LLVM fuzzer.

35. Match limit check added to JIT recursion. This issue was found by Karl
    Skomski with a custom LLVM fuzzer.

36. Yet another case similar to 27 above has been circumvented by an
    unconditional allocation of extra memory. This issue is fixed "properly" in
    PCRE2 by refactoring the way references are handled. Wen Guanxing
    from Venustech ADLAB discovered this bug.

37. Fix two assertion fails in JIT. These issues were found by Karl Skomski
    with a custom LLVM fuzzer.

38. Fixed a corner case of range optimization in JIT.

39. An incorrect error "overran compiling workspace" was given if there were
    exactly enough group forward references such that the last one extended
    into the workspace safety margin. The next one would have expanded the
    workspace. The test for overflow was not including the safety margin.

40. A match limit issue is fixed in JIT which was found by Karl Skomski
    with a custom LLVM fuzzer.

41. Remove the use of /dev/null in testdata/testinput2, because it doesn't
    work under Windows. (Why has it taken so long for anyone to notice?)

42. In a character class such as [\W\p{Any}] where both a negative-type escape
    ("not a word character") and a property escape were present, the property
    escape was being ignored.

43. Fix crash caused by very long (*MARK) or (*THEN) names.

44. A sequence such as [[:punct:]b] that is, a POSIX character class followed
    by a single ASCII character in a class item, was incorrectly compiled in
    UCP mode. The POSIX class got lost, but only if the single character
    followed it.

45. [:punct:] in UCP mode was matching some characters in the range 128-255
    that should not have been matched.

46. If [:^ascii:] or [:^xdigit:] or [:^cntrl:] are present in a non-negated
    class, all characters with code points greater than 255 are in the class.
    When a Unicode property was also in the class (if PCRE_UCP is set, escapes
    such as \w are turned into Unicode properties), wide characters were not
    correctly handled, and could fail to match.


Version 8.37 28-April-2015
--------------------------

1.  When an (*ACCEPT) is triggered inside capturing parentheses, it arranges
    for those parentheses to be closed with whatever has been captured so far.
    However, it was failing to mark any other groups between the hightest
    capture so far and the currrent group as "unset". Thus, the ovector for
    those groups contained whatever was previously there. An example is the
    pattern /(x)|((*ACCEPT))/ when matched against "abcd".

2.  If an assertion condition was quantified with a minimum of zero (an odd
    thing to do, but it happened), SIGSEGV or other misbehaviour could occur.

3.  If a pattern in pcretest input had the P (POSIX) modifier followed by an
    unrecognized modifier, a crash could occur.

4.  An attempt to do global matching in pcretest with a zero-length ovector
    caused a crash.

5.  Fixed a memory leak during matching that could occur for a subpattern
    subroutine call (recursive or otherwise) if the number of captured groups
    that had to be saved was greater than ten.

6.  Catch a bad opcode during auto-possessification after compiling a bad UTF
    string with NO_UTF_CHECK. This is a tidyup, not a bug fix, as passing bad
    UTF with NO_UTF_CHECK is documented as having an undefined outcome.

7.  A UTF pattern containing a "not" match of a non-ASCII character and a
    subroutine reference could loop at compile time. Example: /[^\xff]((?1))/.

8. When a pattern is compiled, it remembers the highest back reference so that
   when matching, if the ovector is too small, extra memory can be obtained to
   use instead. A conditional subpattern whose condition is a check on a
   capture having happened, such as, for example in the pattern
   /^(?:(a)|b)(?(1)A|B)/, is another kind of back reference, but it was not
   setting the highest backreference number. This mattered only if pcre_exec()
   was called with an ovector that was too small to hold the capture, and there
   was no other kind of back reference (a situation which is probably quite
   rare). The effect of the bug was that the condition was always treated as
   FALSE when the capture could not be consulted, leading to a incorrect
   behaviour by pcre_exec(). This bug has been fixed.

9. A reference to a duplicated named group (either a back reference or a test
   for being set in a conditional) that occurred in a part of the pattern where
   PCRE_DUPNAMES was not set caused the amount of memory needed for the pattern
   to be incorrectly calculated, leading to overwriting.

10. A mutually recursive set of back references such as (\2)(\1) caused a
    segfault at study time (while trying to find the minimum matching length).
    The infinite loop is now broken (with the minimum length unset, that is,
    zero).

11. If an assertion that was used as a condition was quantified with a minimum
    of zero, matching went wrong. In particular, if the whole group had
    unlimited repetition and could match an empty string, a segfault was
    likely. The pattern (?(?=0)?)+ is an example that caused this. Perl allows
    assertions to be quantified, but not if they are being used as conditions,
    so the above pattern is faulted by Perl. PCRE has now been changed so that
    it also rejects such patterns.

12. A possessive capturing group such as (a)*+ with a minimum repeat of zero
    failed to allow the zero-repeat case if pcre2_exec() was called with an
    ovector too small to capture the group.

13. Fixed two bugs in pcretest that were discovered by fuzzing and reported by
    Red Hat Product Security:

    (a) A crash if /K and /F were both set with the option to save the compiled
    pattern.

    (b) Another crash if the option to print captured substrings in a callout
    was combined with setting a null ovector, for example \O\C+ as a subject
    string.

14. A pattern such as "((?2){0,1999}())?", which has a group containing a
    forward reference repeated a large (but limited) number of times within a
    repeated outer group that has a zero minimum quantifier, caused incorrect
    code to be compiled, leading to the error "internal error:
    previously-checked referenced subpattern not found" when an incorrect
    memory address was read. This bug was reported as "heap overflow",
    discovered by Kai Lu of Fortinet's FortiGuard Labs and given the CVE number
    CVE-2015-2325.

23. A pattern such as "((?+1)(\1))/" containing a forward reference subroutine
    call within a group that also contained a recursive back reference caused
    incorrect code to be compiled. This bug was reported as "heap overflow",
    discovered by Kai Lu of Fortinet's FortiGuard Labs, and given the CVE
    number CVE-2015-2326.

24. Computing the size of the JIT read-only data in advance has been a source
    of various issues, and new ones are still appear unfortunately. To fix
    existing and future issues, size computation is eliminated from the code,
    and replaced by on-demand memory allocation.

25. A pattern such as /(?i)[A-`]/, where characters in the other case are
    adjacent to the end of the range, and the range contained characters with
    more than one other case, caused incorrect behaviour when compiled in UTF
    mode. In that example, the range a-j was left out of the class.

26. Fix JIT compilation of conditional blocks, which assertion
    is converted to (*FAIL). E.g: /(?(?!))/.

27. The pattern /(?(?!)^)/ caused references to random memory. This bug was
    discovered by the LLVM fuzzer.

28. The assertion (?!) is optimized to (*FAIL). This was not handled correctly
    when this assertion was used as a condition, for example (?(?!)a|b). In
    pcre2_match() it worked by luck; in pcre2_dfa_match() it gave an incorrect
    error about an unsupported item.

29. For some types of pattern, for example /Z*(|d*){216}/, the auto-
    possessification code could take exponential time to complete. A recursion
    depth limit of 1000 has been imposed to limit the resources used by this
    optimization.

30. A pattern such as /(*UTF)[\S\V\H]/, which contains a negated special class
    such as \S in non-UCP mode, explicit wide characters (> 255) can be ignored
    because \S ensures they are all in the class. The code for doing this was
    interacting badly with the code for computing the amount of space needed to
    compile the pattern, leading to a buffer overflow. This bug was discovered
    by the LLVM fuzzer.

31. A pattern such as /((?2)+)((?1))/ which has mutual recursion nested inside
    other kinds of group caused stack overflow at compile time. This bug was
    discovered by the LLVM fuzzer.

32. A pattern such as /(?1)(?#?'){8}(a)/ which had a parenthesized comment
    between a subroutine call and its quantifier was incorrectly compiled,
    leading to buffer overflow or other errors. This bug was discovered by the
    LLVM fuzzer.

33. The illegal pattern /(?(?<E>.*!.*)?)/ was not being diagnosed as missing an
    assertion after (?(. The code was failing to check the character after
    (?(?< for the ! or = that would indicate a lookbehind assertion. This bug
    was discovered by the LLVM fuzzer.

34. A pattern such as /X((?2)()*+){2}+/ which has a possessive quantifier with
    a fixed maximum following a group that contains a subroutine reference was
    incorrectly compiled and could trigger buffer overflow. This bug was
    discovered by the LLVM fuzzer.

35. A mutual recursion within a lookbehind assertion such as (?<=((?2))((?1)))
    caused a stack overflow instead of the diagnosis of a non-fixed length
    lookbehind assertion. This bug was discovered by the LLVM fuzzer.

36. The use of \K in a positive lookbehind assertion in a non-anchored pattern
    (e.g. /(?<=\Ka)/) could make pcregrep loop.

37. There was a similar problem to 36 in pcretest for global matches.

38. If a greedy quantified \X was preceded by \C in UTF mode (e.g. \C\X*),
    and a subsequent item in the pattern caused a non-match, backtracking over
    the repeated \X did not stop, but carried on past the start of the subject,
    causing reference to random memory and/or a segfault. There were also some
    other cases where backtracking after \C could crash. This set of bugs was
    discovered by the LLVM fuzzer.

39. The function for finding the minimum length of a matching string could take
    a very long time if mutual recursion was present many times in a pattern,
    for example, /((?2){73}(?2))((?1))/. A better mutual recursion detection
    method has been implemented. This infelicity was discovered by the LLVM
    fuzzer.

40. Static linking against the PCRE library using the pkg-config module was
    failing on missing pthread symbols.


Version 8.36 26-September-2014
------------------------------

1.  Got rid of some compiler warnings in the C++ modules that were shown up by
    -Wmissing-field-initializers and -Wunused-parameter.

2.  The tests for quantifiers being too big (greater than 65535) were being
    applied after reading the number, and stupidly assuming that integer
    overflow would give a negative number. The tests are now applied as the
    numbers are read.

3.  Tidy code in pcre_exec.c where two branches that used to be different are
    now the same.

4.  The JIT compiler did not generate match limit checks for certain
    bracketed expressions with quantifiers. This may lead to exponential
    backtracking, instead of returning with PCRE_ERROR_MATCHLIMIT. This
    issue should be resolved now.

5.  Fixed an issue, which occures when nested alternatives are optimized
    with table jumps.

6.  Inserted two casts and changed some ints to size_t in the light of some
    reported 64-bit compiler warnings (Bugzilla 1477).

7.  Fixed a bug concerned with zero-minimum possessive groups that could match
    an empty string, which sometimes were behaving incorrectly in the
    interpreter (though correctly in the JIT matcher). This pcretest input is
    an example:

      '\A(?:[^"]++|"(?:[^"]*+|"")*+")++'
      NON QUOTED "QUOT""ED" AFTER "NOT MATCHED

    the interpreter was reporting a match of 'NON QUOTED ' only, whereas the
    JIT matcher and Perl both matched 'NON QUOTED "QUOT""ED" AFTER '. The test
    for an empty string was breaking the inner loop and carrying on at a lower
    level, when possessive repeated groups should always return to a higher
    level as they have no backtrack points in them. The empty string test now
    occurs at the outer level.

8.  Fixed a bug that was incorrectly auto-possessifying \w+ in the pattern
    ^\w+(?>\s*)(?<=\w) which caused it not to match "test test".

9.  Give a compile-time error for \o{} (as Perl does) and for \x{} (which Perl
    doesn't).

10. Change 8.34/15 introduced a bug that caused the amount of memory needed
    to hold a pattern to be incorrectly computed (too small) when there were
    named back references to duplicated names. This could cause "internal
    error: code overflow" or "double free or corruption" or other memory
    handling errors.

11. When named subpatterns had the same prefixes, back references could be
    confused. For example, in this pattern:

      /(?P<Name>a)?(?P<Name2>b)?(?(<Name>)c|d)*l/

    the reference to 'Name' was incorrectly treated as a reference to a
    duplicate name.

12. A pattern such as /^s?c/mi8 where the optional character has more than
    one "other case" was incorrectly compiled such that it would only try to
    match starting at "c".

13. When a pattern starting with \s was studied, VT was not included in the
    list of possible starting characters; this should have been part of the
    8.34/18 patch.

14. If a character class started [\Qx]... where x is any character, the class
    was incorrectly terminated at the ].

15. If a pattern that started with a caseless match for a character with more
    than one "other case" was studied, PCRE did not set up the starting code
    unit bit map for the list of possible characters. Now it does. This is an
    optimization improvement, not a bug fix.

16. The Unicode data tables have been updated to Unicode 7.0.0.

17. Fixed a number of memory leaks in pcregrep.

18. Avoid a compiler warning (from some compilers) for a function call with
    a cast that removes "const" from an lvalue by using an intermediate
    variable (to which the compiler does not object).

19. Incorrect code was compiled if a group that contained an internal recursive
    back reference was optional (had quantifier with a minimum of zero). This
    example compiled incorrect code: /(((a\2)|(a*)\g<-1>))*/ and other examples
    caused segmentation faults because of stack overflows at compile time.

20. A pattern such as /((?(R)a|(?1)))+/, which contains a recursion within a
    group that is quantified with an indefinite repeat, caused a compile-time
    loop which used up all the system stack and provoked a segmentation fault.
    This was not the same bug as 19 above.

21. Add PCRECPP_EXP_DECL declaration to operator<< in pcre_stringpiece.h.
    Patch by Mike Frysinger.


Version 8.35 04-April-2014
--------------------------

1.  A new flag is set, when property checks are present in an XCLASS.
    When this flag is not set, PCRE can perform certain optimizations
    such as studying these XCLASS-es.

2.  The auto-possessification of character sets were improved: a normal
    and an extended character set can be compared now. Furthermore
    the JIT compiler optimizes more character set checks.

3.  Got rid of some compiler warnings for potentially uninitialized variables
    that show up only when compiled with -O2.

4.  A pattern such as (?=ab\K) that uses \K in an assertion can set the start
    of a match later then the end of the match. The pcretest program was not
    handling the case sensibly - it was outputting from the start to the next
    binary zero. It now reports this situation in a message, and outputs the
    text from the end to the start.

5.  Fast forward search is improved in JIT. Instead of the first three
    characters, any three characters with fixed position can be searched.
    Search order: first, last, middle.

6.  Improve character range checks in JIT. Characters are read by an inprecise
    function now, which returns with an unknown value if the character code is
    above a certain threshold (e.g: 256). The only limitation is that the value
    must be bigger than the threshold as well. This function is useful when
    the characters above the threshold are handled in the same way.

7.  The macros whose names start with RAWUCHAR are placeholders for a future
    mode in which only the bottom 21 bits of 32-bit data items are used. To
    make this more memorable for those maintaining the code, the names have
    been changed to start with UCHAR21, and an extensive comment has been added
    to their definition.

8.  Add missing (new) files sljitNativeTILEGX.c and sljitNativeTILEGX-encoder.c
    to the export list in Makefile.am (they were accidentally omitted from the
    8.34 tarball).

9.  The informational output from pcretest used the phrase "starting byte set"
    which is inappropriate for the 16-bit and 32-bit libraries. As the output
    for "first char" and "need char" really means "non-UTF-char", I've changed
    "byte" to "char", and slightly reworded the output. The documentation about
    these values has also been (I hope) clarified.

10. Another JIT related optimization: use table jumps for selecting the correct
    backtracking path, when more than four alternatives are present inside a
    bracket.

11. Empty match is not possible, when the minimum length is greater than zero,
    and there is no \K in the pattern. JIT should avoid empty match checks in
    such cases.

12. In a caseless character class with UCP support, when a character with more
    than one alternative case was not the first character of a range, not all
    the alternative cases were added to the class. For example, s and \x{17f}
    are both alternative cases for S: the class [RST] was handled correctly,
    but [R-T] was not.

13. The configure.ac file always checked for pthread support when JIT was
    enabled. This is not used in Windows, so I have put this test inside a
    check for the presence of windows.h (which was already tested for).

14. Improve pattern prefix search by a simplified Boyer-Moore algorithm in JIT.
    The algorithm provides a way to skip certain starting offsets, and usually
    faster than linear prefix searches.

15. Change 13 for 8.20 updated RunTest to check for the 'fr' locale as well
    as for 'fr_FR' and 'french'. For some reason, however, it then used the
    Windows-specific input and output files, which have 'french' screwed in.
    So this could never have worked. One of the problems with locales is that
    they aren't always the same. I have now updated RunTest so that it checks
    the output of the locale test (test 3) against three different output
    files, and it allows the test to pass if any one of them matches. With luck
    this should make the test pass on some versions of Solaris where it was
    failing. Because of the uncertainty, the script did not used to stop if
    test 3 failed; it now does. If further versions of a French locale ever
    come to light, they can now easily be added.

16. If --with-pcregrep-bufsize was given a non-integer value such as "50K",
    there was a message during ./configure, but it did not stop. This now
    provokes an error. The invalid example in README has been corrected.
    If a value less than the minimum is given, the minimum value has always
    been used, but now a warning is given.

17. If --enable-bsr-anycrlf was set, the special 16/32-bit test failed. This
    was a bug in the test system, which is now fixed. Also, the list of various
    configurations that are tested for each release did not have one with both
    16/32 bits and --enable-bar-anycrlf. It now does.

18. pcretest was missing "-C bsr" for displaying the \R default setting.

19. Little endian PowerPC systems are supported now by the JIT compiler.

20. The fast forward newline mechanism could enter to an infinite loop on
    certain invalid UTF-8 input. Although we don't support these cases
    this issue can be fixed by a performance optimization.

21. Change 33 of 8.34 is not sufficient to ensure stack safety because it does
    not take account if existing stack usage. There is now a new global
    variable called pcre_stack_guard that can be set to point to an external
    function to check stack availability. It is called at the start of
    processing every parenthesized group.

22. A typo in the code meant that in ungreedy mode the max/min qualifier
    behaved like a min-possessive qualifier, and, for example, /a{1,3}b/U did
    not match "ab".

23. When UTF was disabled, the JIT program reported some incorrect compile
    errors. These messages are silenced now.

24. Experimental support for ARM-64 and MIPS-64 has been added to the JIT
    compiler.

25. Change all the temporary files used in RunGrepTest to be different to those
    used by RunTest so that the tests can be run simultaneously, for example by
    "make -j check".


Version 8.34 15-December-2013
-----------------------------

1.  Add pcre[16|32]_jit_free_unused_memory to forcibly free unused JIT
    executable memory. Patch inspired by Carsten Klein.

2.  ./configure --enable-coverage defined SUPPORT_GCOV in config.h, although
    this macro is never tested and has no effect, because the work to support
    coverage involves only compiling and linking options and special targets in
    the Makefile. The comment in config.h implied that defining the macro would
    enable coverage support, which is totally false. There was also support for
    setting this macro in the CMake files (my fault, I just copied it from
    configure). SUPPORT_GCOV has now been removed.

3.  Make a small performance improvement in strlen16() and strlen32() in
    pcretest.

4.  Change 36 for 8.33 left some unreachable statements in pcre_exec.c,
    detected by the Solaris compiler (gcc doesn't seem to be able to diagnose
    these cases). There was also one in pcretest.c.

5.  Cleaned up a "may be uninitialized" compiler warning in pcre_exec.c.

6.  In UTF mode, the code for checking whether a group could match an empty
    string (which is used for indefinitely repeated groups to allow for
    breaking an infinite loop) was broken when the group contained a repeated
    negated single-character class with a character that occupied more than one
    data item and had a minimum repetition of zero (for example, [^\x{100}]* in
    UTF-8 mode). The effect was undefined: the group might or might not be
    deemed as matching an empty string, or the program might have crashed.

7.  The code for checking whether a group could match an empty string was not
    recognizing that \h, \H, \v, \V, and \R must match a character.

8.  Implemented PCRE_INFO_MATCH_EMPTY, which yields 1 if the pattern can match
    an empty string. If it can, pcretest shows this in its information output.

9.  Fixed two related bugs that applied to Unicode extended grapheme clusters
    that were repeated with a maximizing qualifier (e.g. \X* or \X{2,5}) when
    matched by pcre_exec() without using JIT:

    (a) If the rest of the pattern did not match after a maximal run of
        grapheme clusters, the code for backing up to try with fewer of them
        did not always back up over a full grapheme when characters that do not
        have the modifier quality were involved, e.g. Hangul syllables.

    (b) If the match point in a subject started with modifier character, and
        there was no match, the code could incorrectly back up beyond the match
        point, and potentially beyond the first character in the subject,
        leading to a segfault or an incorrect match result.

10. A conditional group with an assertion condition could lead to PCRE
    recording an incorrect first data item for a match if no other first data
    item was recorded. For example, the pattern (?(?=ab)ab) recorded "a" as a
    first data item, and therefore matched "ca" after "c" instead of at the
    start.

11. Change 40 for 8.33 (allowing pcregrep to find empty strings) showed up a
    bug that caused the command "echo a | ./pcregrep -M '|a'" to loop.

12. The source of pcregrep now includes z/OS-specific code so that it can be
    compiled for z/OS as part of the special z/OS distribution.

13. Added the -T and -TM options to pcretest.

14. The code in pcre_compile.c for creating the table of named capturing groups
    has been refactored. Instead of creating the table dynamically during the
    actual compiling pass, the information is remembered during the pre-compile
    pass (on the stack unless there are more than 20 named groups, in which
    case malloc() is used) and the whole table is created before the actual
    compile happens. This has simplified the code (it is now nearly 150 lines
    shorter) and prepared the way for better handling of references to groups
    with duplicate names.

15. A back reference to a named subpattern when there is more than one of the
    same name now checks them in the order in which they appear in the pattern.
    The first one that is set is used for the reference. Previously only the
    first one was inspected. This change makes PCRE more compatible with Perl.

16. Unicode character properties were updated from Unicode 6.3.0.

17. The compile-time code for auto-possessification has been refactored, based
    on a patch by Zoltan Herczeg. It now happens after instead of during
    compilation. The code is cleaner, and more cases are handled. The option
    PCRE_NO_AUTO_POSSESS is added for testing purposes, and the -O and /O
    options in pcretest are provided to set it. It can also be set by
    (*NO_AUTO_POSSESS) at the start of a pattern.

18. The character VT has been added to the default ("C" locale) set of
    characters that match \s and are generally treated as white space,
    following this same change in Perl 5.18. There is now no difference between
    "Perl space" and "POSIX space". Whether VT is treated as white space in
    other locales depends on the locale.

19. The code for checking named groups as conditions, either for being set or
    for being recursed, has been refactored (this is related to 14 and 15
    above). Processing unduplicated named groups should now be as fast at
    numerical groups, and processing duplicated groups should be faster than
    before.

20. Two patches to the CMake build system, by Alexander Barkov:

      (1) Replace the "source" command by "." in CMakeLists.txt because
          "source" is a bash-ism.

      (2) Add missing HAVE_STDINT_H and HAVE_INTTYPES_H to config-cmake.h.in;
          without these the CMake build does not work on Solaris.

21. Perl has changed its handling of \8 and \9. If there is no previously
    encountered capturing group of those numbers, they are treated as the
    literal characters 8 and 9 instead of a binary zero followed by the
    literals. PCRE now does the same.

22. Following Perl, added \o{} to specify codepoints in octal, making it
    possible to specify values greater than 0777 and also making them
    unambiguous.

23. Perl now gives an error for missing closing braces after \x{... instead of
    treating the string as literal. PCRE now does the same.

24. RunTest used to grumble if an inappropriate test was selected explicitly,
    but just skip it when running all tests. This make it awkward to run ranges
    of tests when one of them was inappropriate. Now it just skips any
    inappropriate tests, as it always did when running all tests.

25. If PCRE_AUTO_CALLOUT and PCRE_UCP were set for a pattern that contained
    character types such as \d or \w, too many callouts were inserted, and the
    data that they returned was rubbish.

26. In UCP mode, \s was not matching two of the characters that Perl matches,
    namely NEL (U+0085) and MONGOLIAN VOWEL SEPARATOR (U+180E), though they
    were matched by \h. The code has now been refactored so that the lists of
    the horizontal and vertical whitespace characters used for \h and \v (which
    are defined only in one place) are now also used for \s.

27. Add JIT support for the 64 bit TileGX architecture.
    Patch by Jiong Wang (Tilera Corporation).

28. Possessive quantifiers for classes (both explicit and automatically
    generated) now use special opcodes instead of wrapping in ONCE brackets.

29. Whereas an item such as A{4}+ ignored the possessivenes of the quantifier
    (because it's meaningless), this was not happening when PCRE_CASELESS was
    set. Not wrong, but inefficient.

30. Updated perltest.pl to add /u (force Unicode mode) when /W (use Unicode
    properties for \w, \d, etc) is present in a test regex. Otherwise if the
    test contains no characters greater than 255, Perl doesn't realise it
    should be using Unicode semantics.

31. Upgraded the handling of the POSIX classes [:graph:], [:print:], and
    [:punct:] when PCRE_UCP is set so as to include the same characters as Perl
    does in Unicode mode.

32. Added the "forbid" facility to pcretest so that putting tests into the
    wrong test files can sometimes be quickly detected.

33. There is now a limit (default 250) on the depth of nesting of parentheses.
    This limit is imposed to control the amount of system stack used at compile
    time. It can be changed at build time by --with-parens-nest-limit=xxx or
    the equivalent in CMake.

34. Character classes such as [A-\d] or [a-[:digit:]] now cause compile-time
    errors. Perl warns for these when in warning mode, but PCRE has no facility
    for giving warnings.

35. Change 34 for 8.13 allowed quantifiers on assertions, because Perl does.
    However, this was not working for (?!) because it is optimized to (*FAIL),
    for which PCRE does not allow quantifiers. The optimization is now disabled
    when a quantifier follows (?!). I can't see any use for this, but it makes
    things uniform.

36. Perl no longer allows group names to start with digits, so I have made this
    change also in PCRE. It simplifies the code a bit.

37. In extended mode, Perl ignores spaces before a + that indicates a
    possessive quantifier. PCRE allowed a space before the quantifier, but not
    before the possessive +. It now does.

38. The use of \K (reset reported match start) within a repeated possessive
    group such as (a\Kb)*+ was not working.

40. Document that the same character tables must be used at compile time and
    run time, and that the facility to pass tables to pcre_exec() and
    pcre_dfa_exec() is for use only with saved/restored patterns.

41. Applied Jeff Trawick's patch CMakeLists.txt, which "provides two new
    features for Builds with MSVC:

    1. Support pcre.rc and/or pcreposix.rc (as is already done for MinGW
       builds). The .rc files can be used to set FileDescription and many other
       attributes.

    2. Add an option (-DINSTALL_MSVC_PDB) to enable installation of .pdb files.
       This allows higher-level build scripts which want .pdb files to avoid
       hard-coding the exact files needed."

42. Added support for [[:<:]] and [[:>:]] as used in the BSD POSIX library to
    mean "start of word" and "end of word", respectively, as a transition aid.

43. A minimizing repeat of a class containing codepoints greater than 255 in
    non-UTF 16-bit or 32-bit modes caused an internal error when PCRE was
    compiled to use the heap for recursion.

44. Got rid of some compiler warnings for unused variables when UTF but not UCP
    is configured.


Version 8.33 28-May-2013
------------------------

1.  Added 'U' to some constants that are compared to unsigned integers, to
    avoid compiler signed/unsigned warnings. Added (int) casts to unsigned
    variables that are added to signed variables, to ensure the result is
    signed and can be negated.

2.  Applied patch by Daniel Richard G for quashing MSVC warnings to the
    CMake config files.

3.  Revise the creation of config.h.generic so that all boolean macros are
    #undefined, whereas non-boolean macros are #ifndef/#endif-ed. This makes
    overriding via -D on the command line possible.

4.  Changing the definition of the variable "op" in pcre_exec.c from pcre_uchar
    to unsigned int is reported to make a quite noticeable speed difference in
    a specific Windows environment. Testing on Linux did also appear to show
    some benefit (and it is clearly not harmful). Also fixed the definition of
    Xop which should be unsigned.

5.  Related to (4), changing the definition of the intermediate variable cc
    in repeated character loops from pcre_uchar to pcre_uint32 also gave speed
    improvements.

6.  Fix forward search in JIT when link size is 3 or greater. Also removed some
    unnecessary spaces.

7.  Adjust autogen.sh and configure.ac to lose warnings given by automake 1.12
    and later.

8.  Fix two buffer over read issues in 16 and 32 bit modes. Affects JIT only.

9.  Optimizing fast_forward_start_bits in JIT.

10. Adding support for callouts in JIT, and fixing some issues revealed
    during this work. Namely:

    (a) Unoptimized capturing brackets incorrectly reset on backtrack.

    (b) Minimum length was not checked before the matching is started.

11. The value of capture_last that is passed to callouts was incorrect in some
    cases when there was a capture on one path that was subsequently abandoned
    after a backtrack. Also, the capture_last value is now reset after a
    recursion, since all captures are also reset in this case.

12. The interpreter no longer returns the "too many substrings" error in the
    case when an overflowing capture is in a branch that is subsequently
    abandoned after a backtrack.

13. In the pathological case when an offset vector of size 2 is used, pcretest
    now prints out the matched string after a yield of 0 or 1.

14. Inlining subpatterns in recursions, when certain conditions are fulfilled.
    Only supported by the JIT compiler at the moment.

15. JIT compiler now supports 32 bit Macs thanks to Lawrence Velazquez.

16. Partial matches now set offsets[2] to the "bumpalong" value, that is, the
    offset of the starting point of the matching process, provided the offsets
    vector is large enough.

17. The \A escape now records a lookbehind value of 1, though its execution
    does not actually inspect the previous character. This is to ensure that,
    in partial multi-segment matching, at least one character from the old
    segment is retained when a new segment is processed. Otherwise, if there
    are no lookbehinds in the pattern, \A might match incorrectly at the start
    of a new segment.

18. Added some #ifdef __VMS code into pcretest.c to help VMS implementations.

19. Redefined some pcre_uchar variables in pcre_exec.c as pcre_uint32; this
    gives some modest performance improvement in 8-bit mode.

20. Added the PCRE-specific property \p{Xuc} for matching characters that can
    be expressed in certain programming languages using Universal Character
    Names.

21. Unicode validation has been updated in the light of Unicode Corrigendum #9,
    which points out that "non characters" are not "characters that may not
    appear in Unicode strings" but rather "characters that are reserved for
    internal use and have only local meaning".

22. When a pattern was compiled with automatic callouts (PCRE_AUTO_CALLOUT) and
    there was a conditional group that depended on an assertion, if the
    assertion was false, the callout that immediately followed the alternation
    in the condition was skipped when pcre_exec() was used for matching.

23. Allow an explicit callout to be inserted before an assertion that is the
    condition for a conditional group, for compatibility with automatic
    callouts, which always insert a callout at this point.

24. In 8.31, (*COMMIT) was confined to within a recursive subpattern. Perl also
    confines (*SKIP) and (*PRUNE) in the same way, and this has now been done.

25. (*PRUNE) is now supported by the JIT compiler.

26. Fix infinite loop when /(?<=(*SKIP)ac)a/ is matched against aa.

27. Fix the case where there are two or more SKIPs with arguments that may be
    ignored.

28. (*SKIP) is now supported by the JIT compiler.

29. (*THEN) is now supported by the JIT compiler.

30. Update RunTest with additional test selector options.

31. The way PCRE handles backtracking verbs has been changed in two ways.

    (1) Previously, in something like (*COMMIT)(*SKIP), COMMIT would override
    SKIP. Now, PCRE acts on whichever backtracking verb is reached first by
    backtracking. In some cases this makes it more Perl-compatible, but Perl's
    rather obscure rules do not always do the same thing.

    (2) Previously, backtracking verbs were confined within assertions. This is
    no longer the case for positive assertions, except for (*ACCEPT). Again,
    this sometimes improves Perl compatibility, and sometimes does not.

32. A number of tests that were in test 2 because Perl did things differently
    have been moved to test 1, because either Perl or PCRE has changed, and
    these tests are now compatible.

32. Backtracking control verbs are now handled in the same way in JIT and
    interpreter.

33. An opening parenthesis in a MARK/PRUNE/SKIP/THEN name in a pattern that
    contained a forward subroutine reference caused a compile error.

34. Auto-detect and optimize limited repetitions in JIT.

35. Implement PCRE_NEVER_UTF to lock out the use of UTF, in particular,
    blocking (*UTF) etc.

36. In the interpreter, maximizing pattern repetitions for characters and
    character types now use tail recursion, which reduces stack usage.

37. The value of the max lookbehind was not correctly preserved if a compiled
    and saved regex was reloaded on a host of different endianness.

38. Implemented (*LIMIT_MATCH) and (*LIMIT_RECURSION). As part of the extension
    of the compiled pattern block, expand the flags field from 16 to 32 bits
    because it was almost full.

39. Try madvise first before posix_madvise.

40. Change 7 for PCRE 7.9 made it impossible for pcregrep to find empty lines
    with a pattern such as ^$. It has taken 4 years for anybody to notice! The
    original change locked out all matches of empty strings. This has been
    changed so that one match of an empty string per line is recognized.
    Subsequent searches on the same line (for colouring or for --only-matching,
    for example) do not recognize empty strings.

41. Applied a user patch to fix a number of spelling mistakes in comments.

42. Data lines longer than 65536 caused pcretest to crash.

43. Clarified the data type for length and startoffset arguments for pcre_exec
    and pcre_dfa_exec in the function-specific man pages, where they were
    explicitly stated to be in bytes, never having been updated. I also added
    some clarification to the pcreapi man page.

44. A call to pcre_dfa_exec() with an output vector size less than 2 caused
    a segmentation fault.


Version 8.32 30-November-2012
-----------------------------

1.  Improved JIT compiler optimizations for first character search and single
    character iterators.

2.  Supporting IBM XL C compilers for PPC architectures in the JIT compiler.
    Patch by Daniel Richard G.

3.  Single character iterator optimizations in the JIT compiler.

4.  Improved JIT compiler optimizations for character ranges.

5.  Rename the "leave" variable names to "quit" to improve WinCE compatibility.
    Reported by Giuseppe D'Angelo.

6.  The PCRE_STARTLINE bit, indicating that a match can occur only at the start
    of a line, was being set incorrectly in cases where .* appeared inside
    atomic brackets at the start of a pattern, or where there was a subsequent
    *PRUNE or *SKIP.

7.  Improved instruction cache flush for POWER/PowerPC.
    Patch by Daniel Richard G.

8.  Fixed a number of issues in pcregrep, making it more compatible with GNU
    grep:

    (a) There is now no limit to the number of patterns to be matched.

    (b) An error is given if a pattern is too long.

    (c) Multiple uses of --exclude, --exclude-dir, --include, and --include-dir
        are now supported.

    (d) --exclude-from and --include-from (multiple use) have been added.

    (e) Exclusions and inclusions now apply to all files and directories, not
        just to those obtained from scanning a directory recursively.

    (f) Multiple uses of -f and --file-list are now supported.

    (g) In a Windows environment, the default for -d has been changed from
        "read" (the GNU grep default) to "skip", because otherwise the presence
        of a directory in the file list provokes an error.

    (h) The documentation has been revised and clarified in places.

9.  Improve the matching speed of capturing brackets.

10. Changed the meaning of \X so that it now matches a Unicode extended
    grapheme cluster.

11. Patch by Daniel Richard G to the autoconf files to add a macro for sorting
    out POSIX threads when JIT support is configured.

12. Added support for PCRE_STUDY_EXTRA_NEEDED.

13. In the POSIX wrapper regcomp() function, setting re_nsub field in the preg
    structure could go wrong in environments where size_t is not the same size
    as int.

14. Applied user-supplied patch to pcrecpp.cc to allow PCRE_NO_UTF8_CHECK to be
    set.

15. The EBCDIC support had decayed; later updates to the code had included
    explicit references to (e.g.) \x0a instead of CHAR_LF. There has been a
    general tidy up of EBCDIC-related issues, and the documentation was also
    not quite right. There is now a test that can be run on ASCII systems to
    check some of the EBCDIC-related things (but is it not a full test).

16. The new PCRE_STUDY_EXTRA_NEEDED option is now used by pcregrep, resulting
    in a small tidy to the code.

17. Fix JIT tests when UTF is disabled and both 8 and 16 bit mode are enabled.

18. If the --only-matching (-o) option in pcregrep is specified multiple
    times, each one causes appropriate output. For example, -o1 -o2 outputs the
    substrings matched by the 1st and 2nd capturing parentheses. A separating
    string can be specified by --om-separator (default empty).

19. Improving the first n character searches.

20. Turn case lists for horizontal and vertical white space into macros so that
    they are defined only once.

21. This set of changes together give more compatible Unicode case-folding
    behaviour for characters that have more than one other case when UCP
    support is available.

    (a) The Unicode property table now has offsets into a new table of sets of
        three or more characters that are case-equivalent. The MultiStage2.py
        script that generates these tables (the pcre_ucd.c file) now scans
        CaseFolding.txt instead of UnicodeData.txt for character case
        information.

    (b) The code for adding characters or ranges of characters to a character
        class has been abstracted into a generalized function that also handles
        case-independence. In UTF-mode with UCP support, this uses the new data
        to handle characters with more than one other case.

    (c) A bug that is fixed as a result of (b) is that codepoints less than 256
        whose other case is greater than 256 are now correctly matched
        caselessly. Previously, the high codepoint matched the low one, but not
        vice versa.

    (d) The processing of \h, \H, \v, and \ in character classes now makes use
        of the new class addition function, using character lists defined as
        macros alongside the case definitions of 20 above.

    (e) Caseless back references now work with characters that have more than
        one other case.

    (f) General caseless matching of characters with more than one other case
        is supported.

22. Unicode character properties were updated from Unicode 6.2.0

23. Improved CMake support under Windows. Patch by Daniel Richard G.

24. Add support for 32-bit character strings, and UTF-32

25. Major JIT compiler update (code refactoring and bugfixing).
    Experimental Sparc 32 support is added.

26. Applied a modified version of Daniel Richard G's patch to create
    pcre.h.generic and config.h.generic by "make" instead of in the
    PrepareRelease script.

27. Added a definition for CHAR_NULL (helpful for the z/OS port), and use it in
    pcre_compile.c when checking for a zero character.

28. Introducing a native interface for JIT. Through this interface, the compiled
    machine code can be directly executed. The purpose of this interface is to
    provide fast pattern matching, so several sanity checks are not performed.
    However, feature tests are still performed. The new interface provides
    1.4x speedup compared to the old one.

29. If pcre_exec() or pcre_dfa_exec() was called with a negative value for
    the subject string length, the error given was PCRE_ERROR_BADOFFSET, which
    was confusing. There is now a new error PCRE_ERROR_BADLENGTH for this case.

30. In 8-bit UTF-8 mode, pcretest failed to give an error for data codepoints
    greater than 0x7fffffff (which cannot be represented in UTF-8, even under
    the "old" RFC 2279). Instead, it ended up passing a negative length to
    pcre_exec().

31. Add support for GCC's visibility feature to hide internal functions.

32. Running "pcretest -C pcre8" or "pcretest -C pcre16" gave a spurious error
    "unknown -C option" after outputting 0 or 1.

33. There is now support for generating a code coverage report for the test
    suite in environments where gcc is the compiler and lcov is installed. This
    is mainly for the benefit of the developers.

34. If PCRE is built with --enable-valgrind, certain memory regions are marked
    unaddressable using valgrind annotations, allowing valgrind to detect
    invalid memory accesses. This is mainly for the benefit of the developers.

25. (*UTF) can now be used to start a pattern in any of the three libraries.

26. Give configure error if --enable-cpp but no C++ compiler found.


Version 8.31 06-July-2012
-------------------------

1.  Fixing a wrong JIT test case and some compiler warnings.

2.  Removed a bashism from the RunTest script.

3.  Add a cast to pcre_exec.c to fix the warning "unary minus operator applied
    to unsigned type, result still unsigned" that was given by an MS compiler
    on encountering the code "-sizeof(xxx)".

4.  Partial matching support is added to the JIT compiler.

5.  Fixed several bugs concerned with partial matching of items that consist
    of more than one character:

    (a) /^(..)\1/ did not partially match "aba" because checking references was
        done on an "all or nothing" basis. This also applied to repeated
        references.

    (b) \R did not give a hard partial match if \r was found at the end of the
        subject.

    (c) \X did not give a hard partial match after matching one or more
        characters at the end of the subject.

    (d) When newline was set to CRLF, a pattern such as /a$/ did not recognize
        a partial match for the string "\r".

    (e) When newline was set to CRLF, the metacharacter "." did not recognize
        a partial match for a CR character at the end of the subject string.

6.  If JIT is requested using /S++ or -s++ (instead of just /S+ or -s+) when
    running pcretest, the text "(JIT)" added to the output whenever JIT is
    actually used to run the match.

7.  Individual JIT compile options can be set in pcretest by following -s+[+]
    or /S+[+] with a digit between 1 and 7.

8.  OP_NOT now supports any UTF character not just single-byte ones.

9.  (*MARK) control verb is now supported by the JIT compiler.

10. The command "./RunTest list" lists the available tests without actually
    running any of them. (Because I keep forgetting what they all are.)

11. Add PCRE_INFO_MAXLOOKBEHIND.

12. Applied a (slightly modified) user-supplied patch that improves performance
    when the heap is used for recursion (compiled with --disable-stack-for-
    recursion). Instead of malloc and free for each heap frame each time a
    logical recursion happens, frames are retained on a chain and re-used where
    possible. This sometimes gives as much as 30% improvement.

13. As documented, (*COMMIT) is now confined to within a recursive subpattern
    call.

14. As documented, (*COMMIT) is now confined to within a positive assertion.

15. It is now possible to link pcretest with libedit as an alternative to
    libreadline.

16. (*COMMIT) control verb is now supported by the JIT compiler.

17. The Unicode data tables have been updated to Unicode 6.1.0.

18. Added --file-list option to pcregrep.

19. Added binary file support to pcregrep, including the -a, --binary-files,
    -I, and --text options.

20. The madvise function is renamed for posix_madvise for QNX compatibility
    reasons. Fixed by Giuseppe D'Angelo.

21. Fixed a bug for backward assertions with REVERSE 0 in the JIT compiler.

22. Changed the option for creating symbolic links for 16-bit man pages from
    -s to -sf so that re-installing does not cause issues.

23. Support PCRE_NO_START_OPTIMIZE in JIT as (*MARK) support requires it.

24. Fixed a very old bug in pcretest that caused errors with restarted DFA
    matches in certain environments (the workspace was not being correctly
    retained). Also added to pcre_dfa_exec() a simple plausibility check on
    some of the workspace data at the beginning of a restart.

25. \s*\R was auto-possessifying the \s* when it should not, whereas \S*\R
    was not doing so when it should - probably a typo introduced by SVN 528
    (change 8.10/14).

26. When PCRE_UCP was not set, \w+\x{c4} was incorrectly auto-possessifying the
    \w+ when the character tables indicated that \x{c4} was a word character.
    There were several related cases, all because the tests for doing a table
    lookup were testing for characters less than 127 instead of 255.

27. If a pattern contains capturing parentheses that are not used in a match,
    their slots in the ovector are set to -1. For those that are higher than
    any matched groups, this happens at the end of processing. In the case when
    there were back references that the ovector was too small to contain
    (causing temporary malloc'd memory to be used during matching), and the
    highest capturing number was not used, memory off the end of the ovector
    was incorrectly being set to -1. (It was using the size of the temporary
    memory instead of the true size.)

28. To catch bugs like 27 using valgrind, when pcretest is asked to specify an
    ovector size, it uses memory at the end of the block that it has got.

29. Check for an overlong MARK name and give an error at compile time. The
    limit is 255 for the 8-bit library and 65535 for the 16-bit library.

30. JIT compiler update.

31. JIT is now supported on jailbroken iOS devices. Thanks for Ruiger
    Rill for the patch.

32. Put spaces around SLJIT_PRINT_D in the JIT compiler. Required by CXX11.

33. Variable renamings in the PCRE-JIT compiler. No functionality change.

34. Fixed typos in pcregrep: in two places there was SUPPORT_LIBZ2 instead of
    SUPPORT_LIBBZ2. This caused a build problem when bzip2 but not gzip (zlib)
    was enabled.

35. Improve JIT code generation for greedy plus quantifier.

36. When /((?:a?)*)*c/ or /((?>a?)*)*c/ was matched against "aac", it set group
    1 to "aa" instead of to an empty string. The bug affected repeated groups
    that could potentially match an empty string.

37. Optimizing single character iterators in JIT.

38. Wide characters specified with \uxxxx in JavaScript mode are now subject to
    the same checks as \x{...} characters in non-JavaScript mode. Specifically,
    codepoints that are too big for the mode are faulted, and in a UTF mode,
    disallowed codepoints are also faulted.

39. If PCRE was compiled with UTF support, in three places in the DFA
    matcher there was code that should only have been obeyed in UTF mode, but
    was being obeyed unconditionally. In 8-bit mode this could cause incorrect
    processing when bytes with values greater than 127 were present. In 16-bit
    mode the bug would be provoked by values in the range 0xfc00 to 0xdc00. In
    both cases the values are those that cannot be the first data item in a UTF
    character. The three items that might have provoked this were recursions,
    possessively repeated groups, and atomic groups.

40. Ensure that libpcre is explicitly listed in the link commands for pcretest
    and pcregrep, because some OS require shared objects to be explicitly
    passed to ld, causing the link step to fail if they are not.

41. There were two incorrect #ifdefs in pcre_study.c, meaning that, in 16-bit
    mode, patterns that started with \h* or \R* might be incorrectly matched.


Version 8.30 04-February-2012
-----------------------------

1.  Renamed "isnumber" as "is_a_number" because in some Mac environments this
    name is defined in ctype.h.

2.  Fixed a bug in fixed-length calculation for lookbehinds that would show up
    only in quite long subpatterns.

3.  Removed the function pcre_info(), which has been obsolete and deprecated
    since it was replaced by pcre_fullinfo() in February 2000.

4.  For a non-anchored pattern, if (*SKIP) was given with a name that did not
    match a (*MARK), and the match failed at the start of the subject, a
    reference to memory before the start of the subject could occur. This bug
    was introduced by fix 17 of release 8.21.

5.  A reference to an unset group with zero minimum repetition was giving
    totally wrong answers (in non-JavaScript-compatibility mode). For example,
    /(another)?(\1?)test/ matched against "hello world test". This bug was
    introduced in release 8.13.

6.  Add support for 16-bit character strings (a large amount of work involving
    many changes and refactorings).

7.  RunGrepTest failed on msys because \r\n was replaced by whitespace when the
    command "pattern=`printf 'xxx\r\njkl'`" was run. The pattern is now taken
    from a file.

8.  Ovector size of 2 is also supported by JIT based pcre_exec (the ovector size
    rounding is not applied in this particular case).

9.  The invalid Unicode surrogate codepoints U+D800 to U+DFFF are now rejected
    if they appear, or are escaped, in patterns.

10. Get rid of a number of -Wunused-but-set-variable warnings.

11. The pattern /(?=(*:x))(q|)/ matches an empty string, and returns the mark
    "x". The similar pattern /(?=(*:x))((*:y)q|)/ did not return a mark at all.
    Oddly, Perl behaves the same way. PCRE has been fixed so that this pattern
    also returns the mark "x". This bug applied to capturing parentheses,
    non-capturing parentheses, and atomic parentheses. It also applied to some
    assertions.

12. Stephen Kelly's patch to CMakeLists.txt allows it to parse the version
    information out of configure.ac instead of relying on pcre.h.generic, which
    is not stored in the repository.

13. Applied Dmitry V. Levin's patch for a more portable method for linking with
    -lreadline.

14. ZH added PCRE_CONFIG_JITTARGET; added its output to pcretest -C.

15. Applied Graycode's patch to put the top-level frame on the stack rather
    than the heap when not using the stack for recursion. This gives a
    performance improvement in many cases when recursion is not deep.

16. Experimental code added to "pcretest -C" to output the stack frame size.


Version 8.21 12-Dec-2011
------------------------

1.  Updating the JIT compiler.

2.  JIT compiler now supports OP_NCREF, OP_RREF and OP_NRREF. New test cases
    are added as well.

3.  Fix cache-flush issue on PowerPC (It is still an experimental JIT port).
    PCRE_EXTRA_TABLES is not suported by JIT, and should be checked before
    calling _pcre_jit_exec. Some extra comments are added.

4.  (*MARK) settings inside atomic groups that do not contain any capturing
    parentheses, for example, (?>a(*:m)), were not being passed out. This bug
    was introduced by change 18 for 8.20.

5.  Supporting of \x, \U and \u in JavaScript compatibility mode based on the
    ECMA-262 standard.

6.  Lookbehinds such as (?<=a{2}b) that contained a fixed repetition were
    erroneously being rejected as "not fixed length" if PCRE_CASELESS was set.
    This bug was probably introduced by change 9 of 8.13.

7.  While fixing 6 above, I noticed that a number of other items were being
    incorrectly rejected as "not fixed length". This arose partly because newer
    opcodes had not been added to the fixed-length checking code. I have (a)
    corrected the bug and added tests for these items, and (b) arranged for an
    error to occur if an unknown opcode is encountered while checking for fixed
    length instead of just assuming "not fixed length". The items that were
    rejected were: (*ACCEPT), (*COMMIT), (*FAIL), (*MARK), (*PRUNE), (*SKIP),
    (*THEN), \h, \H, \v, \V, and single character negative classes with fixed
    repetitions, e.g. [^a]{3}, with and without PCRE_CASELESS.

8.  A possessively repeated conditional subpattern such as (?(?=c)c|d)++ was
    being incorrectly compiled and would have given unpredicatble results.

9.  A possessively repeated subpattern with minimum repeat count greater than
    one behaved incorrectly. For example, (A){2,}+ behaved as if it was
    (A)(A)++ which meant that, after a subsequent mismatch, backtracking into
    the first (A) could occur when it should not.

10. Add a cast and remove a redundant test from the code.

11. JIT should use pcre_malloc/pcre_free for allocation.

12. Updated pcre-config so that it no longer shows -L/usr/lib, which seems
    best practice nowadays, and helps with cross-compiling. (If the exec_prefix
    is anything other than /usr, -L is still shown).

13. In non-UTF-8 mode, \C is now supported in lookbehinds and DFA matching.

14. Perl does not support \N without a following name in a [] class; PCRE now
    also gives an error.

15. If a forward reference was repeated with an upper limit of around 2000,
    it caused the error "internal error: overran compiling workspace". The
    maximum number of forward references (including repeats) was limited by the
    internal workspace, and dependent on the LINK_SIZE. The code has been
    rewritten so that the workspace expands (via pcre_malloc) if necessary, and
    the default depends on LINK_SIZE. There is a new upper limit (for safety)
    of around 200,000 forward references. While doing this, I also speeded up
    the filling in of repeated forward references.

16. A repeated forward reference in a pattern such as (a)(?2){2}(.) was
    incorrectly expecting the subject to contain another "a" after the start.

17. When (*SKIP:name) is activated without a corresponding (*MARK:name) earlier
    in the match, the SKIP should be ignored. This was not happening; instead
    the SKIP was being treated as NOMATCH. For patterns such as
    /A(*MARK:A)A+(*SKIP:B)Z|AAC/ this meant that the AAC branch was never
    tested.

18. The behaviour of (*MARK), (*PRUNE), and (*THEN) has been reworked and is
    now much more compatible with Perl, in particular in cases where the result
    is a non-match for a non-anchored pattern. For example, if
    /b(*:m)f|a(*:n)w/ is matched against "abc", the non-match returns the name
    "m", where previously it did not return a name. A side effect of this
    change is that for partial matches, the last encountered mark name is
    returned, as for non matches. A number of tests that were previously not
    Perl-compatible have been moved into the Perl-compatible test files. The
    refactoring has had the pleasing side effect of removing one argument from
    the match() function, thus reducing its stack requirements.

19. If the /S+ option was used in pcretest to study a pattern using JIT,
    subsequent uses of /S (without +) incorrectly behaved like /S+.

21. Retrieve executable code size support for the JIT compiler and fixing
    some warnings.

22. A caseless match of a UTF-8 character whose other case uses fewer bytes did
    not work when the shorter character appeared right at the end of the
    subject string.

23. Added some (int) casts to non-JIT modules to reduce warnings on 64-bit
    systems.

24. Added PCRE_INFO_JITSIZE to pass on the value from (21) above, and also
    output it when the /M option is used in pcretest.

25. The CheckMan script was not being included in the distribution. Also, added
    an explicit "perl" to run Perl scripts from the PrepareRelease script
    because this is reportedly needed in Windows.

26. If study data was being save in a file and studying had not found a set of
    "starts with" bytes for the pattern, the data written to the file (though
    never used) was taken from uninitialized memory and so caused valgrind to
    complain.

27. Updated RunTest.bat as provided by Sheri Pierce.

28. Fixed a possible uninitialized memory bug in pcre_jit_compile.c.

29. Computation of memory usage for the table of capturing group names was
    giving an unnecessarily large value.


Version 8.20 21-Oct-2011
------------------------

1.  Change 37 of 8.13 broke patterns like [:a]...[b:] because it thought it had
    a POSIX class. After further experiments with Perl, which convinced me that
    Perl has bugs and confusions, a closing square bracket is no longer allowed
    in a POSIX name. This bug also affected patterns with classes that started
    with full stops.

2.  If a pattern such as /(a)b|ac/ is matched against "ac", there is no
    captured substring, but while checking the failing first alternative,
    substring 1 is temporarily captured. If the output vector supplied to
    pcre_exec() was not big enough for this capture, the yield of the function
    was still zero ("insufficient space for captured substrings"). This cannot
    be totally fixed without adding another stack variable, which seems a lot
    of expense for a edge case. However, I have improved the situation in cases
    such as /(a)(b)x|abc/ matched against "abc", where the return code
    indicates that fewer than the maximum number of slots in the ovector have
    been set.

3.  Related to (2) above: when there are more back references in a pattern than
    slots in the output vector, pcre_exec() uses temporary memory during
    matching, and copies in the captures as far as possible afterwards. It was
    using the entire output vector, but this conflicts with the specification
    that only 2/3 is used for passing back captured substrings. Now it uses
    only the first 2/3, for compatibility. This is, of course, another edge
    case.

4.  Zoltan Herczeg's just-in-time compiler support has been integrated into the
    main code base, and can be used by building with --enable-jit. When this is
    done, pcregrep automatically uses it unless --disable-pcregrep-jit or the
    runtime --no-jit option is given.

5.  When the number of matches in a pcre_dfa_exec() run exactly filled the
    ovector, the return from the function was zero, implying that there were
    other matches that did not fit. The correct "exactly full" value is now
    returned.

6.  If a subpattern that was called recursively or as a subroutine contained
    (*PRUNE) or any other control that caused it to give a non-standard return,
    invalid errors such as "Error -26 (nested recursion at the same subject
    position)" or even infinite loops could occur.

7.  If a pattern such as /a(*SKIP)c|b(*ACCEPT)|/ was studied, it stopped
    computing the minimum length on reaching *ACCEPT, and so ended up with the
    wrong value of 1 rather than 0. Further investigation indicates that
    computing a minimum subject length in the presence of *ACCEPT is difficult
    (think back references, subroutine calls), and so I have changed the code
    so that no minimum is registered for a pattern that contains *ACCEPT.

8.  If (*THEN) was present in the first (true) branch of a conditional group,
    it was not handled as intended. [But see 16 below.]

9.  Replaced RunTest.bat and CMakeLists.txt with improved versions provided by
    Sheri Pierce.

10. A pathological pattern such as /(*ACCEPT)a/ was miscompiled, thinking that
    the first byte in a match must be "a".

11. Change 17 for 8.13 increased the recursion depth for patterns like
    /a(?:.)*?a/ drastically. I've improved things by remembering whether a
    pattern contains any instances of (*THEN). If it does not, the old
    optimizations are restored. It would be nice to do this on a per-group
    basis, but at the moment that is not feasible.

12. In some environments, the output of pcretest -C is CRLF terminated. This
    broke RunTest's code that checks for the link size. A single white space
    character after the value is now allowed for.

13. RunTest now checks for the "fr" locale as well as for "fr_FR" and "french".
    For "fr", it uses the Windows-specific input and output files.

14. If (*THEN) appeared in a group that was called recursively or as a
    subroutine, it did not work as intended. [But see next item.]

15. Consider the pattern /A (B(*THEN)C) | D/ where A, B, C, and D are complex
    pattern fragments (but not containing any | characters). If A and B are
    matched, but there is a failure in C so that it backtracks to (*THEN), PCRE
    was behaving differently to Perl. PCRE backtracked into A, but Perl goes to
    D. In other words, Perl considers parentheses that do not contain any |
    characters to be part of a surrounding alternative, whereas PCRE was
    treading (B(*THEN)C) the same as (B(*THEN)C|(*FAIL)) -- which Perl handles
    differently. PCRE now behaves in the same way as Perl, except in the case
    of subroutine/recursion calls such as (?1) which have in any case always
    been different (but PCRE had them first :-).

16. Related to 15 above: Perl does not treat the | in a conditional group as
    creating alternatives. Such a group is treated in the same way as an
    ordinary group without any | characters when processing (*THEN). PCRE has
    been changed to match Perl's behaviour.

17. If a user had set PCREGREP_COLO(U)R to something other than 1:31, the
    RunGrepTest script failed.

18. Change 22 for version 13 caused atomic groups to use more stack. This is
    inevitable for groups that contain captures, but it can lead to a lot of
    stack use in large patterns. The old behaviour has been restored for atomic
    groups that do not contain any capturing parentheses.

19. If the PCRE_NO_START_OPTIMIZE option was set for pcre_compile(), it did not
    suppress the check for a minimum subject length at run time. (If it was
    given to pcre_exec() or pcre_dfa_exec() it did work.)

20. Fixed an ASCII-dependent infelicity in pcretest that would have made it
    fail to work when decoding hex characters in data strings in EBCDIC
    environments.

21. It appears that in at least one Mac OS environment, the isxdigit() function
    is implemented as a macro that evaluates to its argument more than once,
    contravening the C 90 Standard (I haven't checked a later standard). There
    was an instance in pcretest which caused it to go wrong when processing
    \x{...} escapes in subject strings. The has been rewritten to avoid using
    things like p++ in the argument of isxdigit().


Version 8.13 16-Aug-2011
------------------------

1.  The Unicode data tables have been updated to Unicode 6.0.0.

2.  Two minor typos in pcre_internal.h have been fixed.

3.  Added #include <string.h> to pcre_scanner_unittest.cc, pcrecpp.cc, and
    pcrecpp_unittest.cc. They are needed for strcmp(), memset(), and strchr()
    in some environments (e.g. Solaris 10/SPARC using Sun Studio 12U2).

4.  There were a number of related bugs in the code for matching backrefences
    caselessly in UTF-8 mode when codes for the characters concerned were
    different numbers of bytes. For example, U+023A and U+2C65 are an upper
    and lower case pair, using 2 and 3 bytes, respectively. The main bugs were:
    (a) A reference to 3 copies of a 2-byte code matched only 2 of a 3-byte
    code. (b) A reference to 2 copies of a 3-byte code would not match 2 of a
    2-byte code at the end of the subject (it thought there wasn't enough data
    left).

5.  Comprehensive information about what went wrong is now returned by
    pcre_exec() and pcre_dfa_exec() when the UTF-8 string check fails, as long
    as the output vector has at least 2 elements. The offset of the start of
    the failing character and a reason code are placed in the vector.

6.  When the UTF-8 string check fails for pcre_compile(), the offset that is
    now returned is for the first byte of the failing character, instead of the
    last byte inspected. This is an incompatible change, but I hope it is small
    enough not to be a problem. It makes the returned offset consistent with
    pcre_exec() and pcre_dfa_exec().

7.  pcretest now gives a text phrase as well as the error number when
    pcre_exec() or pcre_dfa_exec() fails; if the error is a UTF-8 check
    failure, the offset and reason code are output.

8.  When \R was used with a maximizing quantifier it failed to skip backwards
    over a \r\n pair if the subsequent match failed. Instead, it just skipped
    back over a single character (\n). This seems wrong (because it treated the
    two characters as a single entity when going forwards), conflicts with the
    documentation that \R is equivalent to (?>\r\n|\n|...etc), and makes the
    behaviour of \R* different to (\R)*, which also seems wrong. The behaviour
    has been changed.

9.  Some internal refactoring has changed the processing so that the handling
    of the PCRE_CASELESS and PCRE_MULTILINE options is done entirely at compile
    time (the PCRE_DOTALL option was changed this way some time ago: version
    7.7 change 16). This has made it possible to abolish the OP_OPT op code,
    which was always a bit of a fudge. It also means that there is one less
    argument for the match() function, which reduces its stack requirements
    slightly. This change also fixes an incompatibility with Perl: the pattern
    (?i:([^b]))(?1) should not match "ab", but previously PCRE gave a match.

10. More internal refactoring has drastically reduced the number of recursive
    calls to match() for possessively repeated groups such as (abc)++ when
    using pcre_exec().

11. While implementing 10, a number of bugs in the handling of groups were
    discovered and fixed:

    (?<=(a)+) was not diagnosed as invalid (non-fixed-length lookbehind).
    (a|)*(?1) gave a compile-time internal error.
    ((a|)+)+  did not notice that the outer group could match an empty string.
    (^a|^)+   was not marked as anchored.
    (.*a|.*)+ was not marked as matching at start or after a newline.

12. Yet more internal refactoring has removed another argument from the match()
    function. Special calls to this function are now indicated by setting a
    value in a variable in the "match data" data block.

13. Be more explicit in pcre_study() instead of relying on "default" for
    opcodes that mean there is no starting character; this means that when new
    ones are added and accidentally left out of pcre_study(), testing should
    pick them up.

14. The -s option of pcretest has been documented for ages as being an old
    synonym of -m (show memory usage). I have changed it to mean "force study
    for every regex", that is, assume /S for every regex. This is similar to -i
    and -d etc. It's slightly incompatible, but I'm hoping nobody is still
    using it. It makes it easier to run collections of tests with and without
    study enabled, and thereby test pcre_study() more easily. All the standard
    tests are now run with and without -s (but some patterns can be marked as
    "never study" - see 20 below).

15. When (*ACCEPT) was used in a subpattern that was called recursively, the
    restoration of the capturing data to the outer values was not happening
    correctly.

16. If a recursively called subpattern ended with (*ACCEPT) and matched an
    empty string, and PCRE_NOTEMPTY was set, pcre_exec() thought the whole
    pattern had matched an empty string, and so incorrectly returned a no
    match.

17. There was optimizing code for the last branch of non-capturing parentheses,
    and also for the obeyed branch of a conditional subexpression, which used
    tail recursion to cut down on stack usage. Unfortunately, now that there is
    the possibility of (*THEN) occurring in these branches, tail recursion is
    no longer possible because the return has to be checked for (*THEN). These
    two optimizations have therefore been removed. [But see 8.20/11 above.]

18. If a pattern containing \R was studied, it was assumed that \R always
    matched two bytes, thus causing the minimum subject length to be
    incorrectly computed because \R can also match just one byte.

19. If a pattern containing (*ACCEPT) was studied, the minimum subject length
    was incorrectly computed.

20. If /S is present twice on a test pattern in pcretest input, it now
    *disables* studying, thereby overriding the use of -s on the command line
    (see 14 above). This is necessary for one or two tests to keep the output
    identical in both cases.

21. When (*ACCEPT) was used in an assertion that matched an empty string and
    PCRE_NOTEMPTY was set, PCRE applied the non-empty test to the assertion.

22. When an atomic group that contained a capturing parenthesis was
    successfully matched, but the branch in which it appeared failed, the
    capturing was not being forgotten if a higher numbered group was later
    captured. For example, /(?>(a))b|(a)c/ when matching "ac" set capturing
    group 1 to "a", when in fact it should be unset. This applied to multi-
    branched capturing and non-capturing groups, repeated or not, and also to
    positive assertions (capturing in negative assertions does not happen
    in PCRE) and also to nested atomic groups.

23. Add the ++ qualifier feature to pcretest, to show the remainder of the
    subject after a captured substring, to make it easier to tell which of a
    number of identical substrings has been captured.

24. The way atomic groups are processed by pcre_exec() has been changed so that
    if they are repeated, backtracking one repetition now resets captured
    values correctly. For example, if ((?>(a+)b)+aabab) is matched against
    "aaaabaaabaabab" the value of captured group 2 is now correctly recorded as
    "aaa". Previously, it would have been "a". As part of this code
    refactoring, the way recursive calls are handled has also been changed.

25. If an assertion condition captured any substrings, they were not passed
    back unless some other capturing happened later. For example, if
    (?(?=(a))a) was matched against "a", no capturing was returned.

26. When studying a pattern that contained subroutine calls or assertions,
    the code for finding the minimum length of a possible match was handling
    direct recursions such as (xxx(?1)|yyy) but not mutual recursions (where
    group 1 called group 2 while simultaneously a separate group 2 called group
    1). A stack overflow occurred in this case. I have fixed this by limiting
    the recursion depth to 10.

27. Updated RunTest.bat in the distribution to the version supplied by Tom
    Fortmann. This supports explicit test numbers on the command line, and has
    argument validation and error reporting.

28. An instance of \X with an unlimited repeat could fail if at any point the
    first character it looked at was a mark character.

29. Some minor code refactoring concerning Unicode properties and scripts
    should reduce the stack requirement of match() slightly.

30. Added the '=' option to pcretest to check the setting of unused capturing
    slots at the end of the pattern, which are documented as being -1, but are
    not included in the return count.

31. If \k was not followed by a braced, angle-bracketed, or quoted name, PCRE
    compiled something random. Now it gives a compile-time error (as does
    Perl).

32. A *MARK encountered during the processing of a positive assertion is now
    recorded and passed back (compatible with Perl).

33. If --only-matching or --colour was set on a pcregrep call whose pattern
    had alternative anchored branches, the search for a second match in a line
    was done as if at the line start. Thus, for example, /^01|^02/ incorrectly
    matched the line "0102" twice. The same bug affected patterns that started
    with a backwards assertion. For example /\b01|\b02/ also matched "0102"
    twice.

34. Previously, PCRE did not allow quantification of assertions. However, Perl
    does, and because of capturing effects, quantifying parenthesized
    assertions may at times be useful. Quantifiers are now allowed for
    parenthesized assertions.

35. A minor code tidy in pcre_compile() when checking options for \R usage.

36. \g was being checked for fancy things in a character class, when it should
    just be a literal "g".

37. PCRE was rejecting [:a[:digit:]] whereas Perl was not. It seems that the
    appearance of a nested POSIX class supersedes an apparent external class.
    For example, [:a[:digit:]b:] matches "a", "b", ":", or a digit. Also,
    unescaped square brackets may also appear as part of class names. For
    example, [:a[:abc]b:] gives unknown class "[:abc]b:]". PCRE now behaves
    more like Perl. (But see 8.20/1 above.)

38. PCRE was giving an error for \N with a braced quantifier such as {1,} (this
    was because it thought it was \N{name}, which is not supported).

39. Add minix to OS list not supporting the -S option in pcretest.

40. PCRE tries to detect cases of infinite recursion at compile time, but it
    cannot analyze patterns in sufficient detail to catch mutual recursions
    such as ((?1))((?2)). There is now a runtime test that gives an error if a
    subgroup is called recursively as a subpattern for a second time at the
    same position in the subject string. In previous releases this might have
    been caught by the recursion limit, or it might have run out of stack.

41. A pattern such as /(?(R)a+|(?R)b)/ is quite safe, as the recursion can
    happen only once. PCRE was, however incorrectly giving a compile time error
    "recursive call could loop indefinitely" because it cannot analyze the
    pattern in sufficient detail. The compile time test no longer happens when
    PCRE is compiling a conditional subpattern, but actual runaway loops are
    now caught at runtime (see 40 above).

42. It seems that Perl allows any characters other than a closing parenthesis
    to be part of the NAME in (*MARK:NAME) and other backtracking verbs. PCRE
    has been changed to be the same.

43. Updated configure.ac to put in more quoting round AC_LANG_PROGRAM etc. so
    as not to get warnings when autogen.sh is called. Also changed
    AC_PROG_LIBTOOL (deprecated) to LT_INIT (the current macro).

44. To help people who use pcregrep to scan files containing exceedingly long
    lines, the following changes have been made:

    (a) The default value of the buffer size parameter has been increased from
        8K to 20K. (The actual buffer used is three times this size.)

    (b) The default can be changed by ./configure --with-pcregrep-bufsize when
        PCRE is built.

    (c) A --buffer-size=n option has been added to pcregrep, to allow the size
        to be set at run time.

    (d) Numerical values in pcregrep options can be followed by K or M, for
        example --buffer-size=50K.

    (e) If a line being scanned overflows pcregrep's buffer, an error is now
        given and the return code is set to 2.

45. Add a pointer to the latest mark to the callout data block.

46. The pattern /.(*F)/, when applied to "abc" with PCRE_PARTIAL_HARD, gave a
    partial match of an empty string instead of no match. This was specific to
    the use of ".".

47. The pattern /f.*/8s, when applied to "for" with PCRE_PARTIAL_HARD, gave a
    complete match instead of a partial match. This bug was dependent on both
    the PCRE_UTF8 and PCRE_DOTALL options being set.

48. For a pattern such as /\babc|\bdef/ pcre_study() was failing to set up the
    starting byte set, because \b was not being ignored.


Version 8.12 15-Jan-2011
------------------------

1.  Fixed some typos in the markup of the man pages, and wrote a script that
    checks for such things as part of the documentation building process.

2.  On a big-endian 64-bit system, pcregrep did not correctly process the
    --match-limit and --recursion-limit options (added for 8.11). In
    particular, this made one of the standard tests fail. (The integer value
    went into the wrong half of a long int.)

3.  If the --colour option was given to pcregrep with -v (invert match), it
    did strange things, either producing crazy output, or crashing. It should,
    of course, ignore a request for colour when reporting lines that do not
    match.

4.  Another pcregrep bug caused similar problems if --colour was specified with
    -M (multiline) and the pattern match finished with a line ending.

5.  In pcregrep, when a pattern that ended with a literal newline sequence was
    matched in multiline mode, the following line was shown as part of the
    match. This seems wrong, so I have changed it.

6.  Another pcregrep bug in multiline mode, when --colour was specified, caused
    the check for further matches in the same line (so they could be coloured)
    to overrun the end of the current line. If another match was found, it was
    incorrectly shown (and then shown again when found in the next line).

7.  If pcregrep was compiled under Windows, there was a reference to the
    function pcregrep_exit() before it was defined. I am assuming this was
    the cause of the "error C2371: 'pcregrep_exit' : redefinition;" that was
    reported by a user. I've moved the definition above the reference.


Version 8.11 10-Dec-2010
------------------------

1.  (*THEN) was not working properly if there were untried alternatives prior
    to it in the current branch. For example, in ((a|b)(*THEN)(*F)|c..) it
    backtracked to try for "b" instead of moving to the next alternative branch
    at the same level (in this case, to look for "c"). The Perl documentation
    is clear that when (*THEN) is backtracked onto, it goes to the "next
    alternative in the innermost enclosing group".

2.  (*COMMIT) was not overriding (*THEN), as it does in Perl. In a pattern
    such as   (A(*COMMIT)B(*THEN)C|D)  any failure after matching A should
    result in overall failure. Similarly, (*COMMIT) now overrides (*PRUNE) and
    (*SKIP), (*SKIP) overrides (*PRUNE) and (*THEN), and (*PRUNE) overrides
    (*THEN).

3.  If \s appeared in a character class, it removed the VT character from
    the class, even if it had been included by some previous item, for example
    in [\x00-\xff\s]. (This was a bug related to the fact that VT is not part
    of \s, but is part of the POSIX "space" class.)

4.  A partial match never returns an empty string (because you can always
    match an empty string at the end of the subject); however the checking for
    an empty string was starting at the "start of match" point. This has been
    changed to the "earliest inspected character" point, because the returned
    data for a partial match starts at this character. This means that, for
    example, /(?<=abc)def/ gives a partial match for the subject "abc"
    (previously it gave "no match").

5.  Changes have been made to the way PCRE_PARTIAL_HARD affects the matching
    of $, \z, \Z, \b, and \B. If the match point is at the end of the string,
    previously a full match would be given. However, setting PCRE_PARTIAL_HARD
    has an implication that the given string is incomplete (because a partial
    match is preferred over a full match). For this reason, these items now
    give a partial match in this situation. [Aside: previously, the one case
    /t\b/ matched against "cat" with PCRE_PARTIAL_HARD set did return a partial
    match rather than a full match, which was wrong by the old rules, but is
    now correct.]

6.  There was a bug in the handling of #-introduced comments, recognized when
    PCRE_EXTENDED is set, when PCRE_NEWLINE_ANY and PCRE_UTF8 were also set.
    If a UTF-8 multi-byte character included the byte 0x85 (e.g. +U0445, whose
    UTF-8 encoding is 0xd1,0x85), this was misinterpreted as a newline when
    scanning for the end of the comment. (*Character* 0x85 is an "any" newline,
    but *byte* 0x85 is not, in UTF-8 mode). This bug was present in several
    places in pcre_compile().

7.  Related to (6) above, when pcre_compile() was skipping #-introduced
    comments when looking ahead for named forward references to subpatterns,
    the only newline sequence it recognized was NL. It now handles newlines
    according to the set newline convention.

8.  SunOS4 doesn't have strerror() or strtoul(); pcregrep dealt with the
    former, but used strtoul(), whereas pcretest avoided strtoul() but did not
    cater for a lack of strerror(). These oversights have been fixed.

9.  Added --match-limit and --recursion-limit to pcregrep.

10. Added two casts needed to build with Visual Studio when NO_RECURSE is set.

11. When the -o option was used, pcregrep was setting a return code of 1, even
    when matches were found, and --line-buffered was not being honoured.

12. Added an optional parentheses number to the -o and --only-matching options
    of pcregrep.

13. Imitating Perl's /g action for multiple matches is tricky when the pattern
    can match an empty string. The code to do it in pcretest and pcredemo
    needed fixing:

    (a) When the newline convention was "crlf", pcretest got it wrong, skipping
        only one byte after an empty string match just before CRLF (this case
        just got forgotten; "any" and "anycrlf" were OK).

    (b) The pcretest code also had a bug, causing it to loop forever in UTF-8
        mode when an empty string match preceded an ASCII character followed by
        a non-ASCII character. (The code for advancing by one character rather
        than one byte was nonsense.)

    (c) The pcredemo.c sample program did not have any code at all to handle
        the cases when CRLF is a valid newline sequence.

14. Neither pcre_exec() nor pcre_dfa_exec() was checking that the value given
    as a starting offset was within the subject string. There is now a new
    error, PCRE_ERROR_BADOFFSET, which is returned if the starting offset is
    negative or greater than the length of the string. In order to test this,
    pcretest is extended to allow the setting of negative starting offsets.

15. In both pcre_exec() and pcre_dfa_exec() the code for checking that the
    starting offset points to the beginning of a UTF-8 character was
    unnecessarily clumsy. I tidied it up.

16. Added PCRE_ERROR_SHORTUTF8 to make it possible to distinguish between a
    bad UTF-8 sequence and one that is incomplete when using PCRE_PARTIAL_HARD.

17. Nobody had reported that the --include_dir option, which was added in
    release 7.7 should have been called --include-dir (hyphen, not underscore)
    for compatibility with GNU grep. I have changed it to --include-dir, but
    left --include_dir as an undocumented synonym, and the same for
    --exclude-dir, though that is not available in GNU grep, at least as of
    release 2.5.4.

18. At a user's suggestion, the macros GETCHAR and friends (which pick up UTF-8
    characters from a string of bytes) have been redefined so as not to use
    loops, in order to improve performance in some environments. At the same
    time, I abstracted some of the common code into auxiliary macros to save
    repetition (this should not affect the compiled code).

19. If \c was followed by a multibyte UTF-8 character, bad things happened. A
    compile-time error is now given if \c is not followed by an ASCII
    character, that is, a byte less than 128. (In EBCDIC mode, the code is
    different, and any byte value is allowed.)

20. Recognize (*NO_START_OPT) at the start of a pattern to set the PCRE_NO_
    START_OPTIMIZE option, which is now allowed at compile time - but just
    passed through to pcre_exec() or pcre_dfa_exec(). This makes it available
    to pcregrep and other applications that have no direct access to PCRE
    options. The new /Y option in pcretest sets this option when calling
    pcre_compile().

21. Change 18 of release 8.01 broke the use of named subpatterns for recursive
    back references. Groups containing recursive back references were forced to
    be atomic by that change, but in the case of named groups, the amount of
    memory required was incorrectly computed, leading to "Failed: internal
    error: code overflow". This has been fixed.

22. Some patches to pcre_stringpiece.h, pcre_stringpiece_unittest.cc, and
    pcretest.c, to avoid build problems in some Borland environments.


Version 8.10 25-Jun-2010
------------------------

1.  Added support for (*MARK:ARG) and for ARG additions to PRUNE, SKIP, and
    THEN.

2.  (*ACCEPT) was not working when inside an atomic group.

3.  Inside a character class, \B is treated as a literal by default, but
    faulted if PCRE_EXTRA is set. This mimics Perl's behaviour (the -w option
    causes the error). The code is unchanged, but I tidied the documentation.

4.  Inside a character class, PCRE always treated \R and \X as literals,
    whereas Perl faults them if its -w option is set. I have changed PCRE so
    that it faults them when PCRE_EXTRA is set.

5.  Added support for \N, which always matches any character other than
    newline. (It is the same as "." when PCRE_DOTALL is not set.)

6.  When compiling pcregrep with newer versions of gcc which may have
    FORTIFY_SOURCE set, several warnings "ignoring return value of 'fwrite',
    declared with attribute warn_unused_result" were given. Just casting the
    result to (void) does not stop the warnings; a more elaborate fudge is
    needed. I've used a macro to implement this.

7.  Minor change to pcretest.c to avoid a compiler warning.

8.  Added four artifical Unicode properties to help with an option to make
    \s etc use properties (see next item). The new properties are: Xan
    (alphanumeric), Xsp (Perl space), Xps (POSIX space), and Xwd (word).

9.  Added PCRE_UCP to make \b, \d, \s, \w, and certain POSIX character classes
    use Unicode properties. (*UCP) at the start of a pattern can be used to set
    this option. Modified pcretest to add /W to test this facility. Added
    REG_UCP to make it available via the POSIX interface.

10. Added --line-buffered to pcregrep.

11. In UTF-8 mode, if a pattern that was compiled with PCRE_CASELESS was
    studied, and the match started with a letter with a code point greater than
    127 whose first byte was different to the first byte of the other case of
    the letter, the other case of this starting letter was not recognized
    (#976).

12. If a pattern that was studied started with a repeated Unicode property
    test, for example, \p{Nd}+, there was the theoretical possibility of
    setting up an incorrect bitmap of starting bytes, but fortunately it could
    not have actually happened in practice until change 8 above was made (it
    added property types that matched character-matching opcodes).

13. pcre_study() now recognizes \h, \v, and \R when constructing a bit map of
    possible starting bytes for non-anchored patterns.

14. Extended the "auto-possessify" feature of pcre_compile(). It now recognizes
    \R, and also a number of cases that involve Unicode properties, both
    explicit and implicit when PCRE_UCP is set.

15. If a repeated Unicode property match (e.g. \p{Lu}*) was used with non-UTF-8
    input, it could crash or give wrong results if characters with values
    greater than 0xc0 were present in the subject string. (Detail: it assumed
    UTF-8 input when processing these items.)

16. Added a lot of (int) casts to avoid compiler warnings in systems where
    size_t is 64-bit (#991).

17. Added a check for running out of memory when PCRE is compiled with
    --disable-stack-for-recursion (#990).

18. If the last data line in a file for pcretest does not have a newline on
    the end, a newline was missing in the output.

19. The default pcre_chartables.c file recognizes only ASCII characters (values
    less than 128) in its various bitmaps. However, there is a facility for
    generating tables according to the current locale when PCRE is compiled. It
    turns out that in some environments, 0x85 and 0xa0, which are Unicode space
    characters, are recognized by isspace() and therefore were getting set in
    these tables, and indeed these tables seem to approximate to ISO 8859. This
    caused a problem in UTF-8 mode when pcre_study() was used to create a list
    of bytes that can start a match. For \s, it was including 0x85 and 0xa0,
    which of course cannot start UTF-8 characters. I have changed the code so
    that only real ASCII characters (less than 128) and the correct starting
    bytes for UTF-8 encodings are set for characters greater than 127 when in
    UTF-8 mode. (When PCRE_UCP is set - see 9 above - the code is different
    altogether.)

20. Added the /T option to pcretest so as to be able to run tests with non-
    standard character tables, thus making it possible to include the tests
    used for 19 above in the standard set of tests.

21. A pattern such as (?&t)(?#()(?(DEFINE)(?<t>a)) which has a forward
    reference to a subpattern the other side of a comment that contains an
    opening parenthesis caused either an internal compiling error, or a
    reference to the wrong subpattern.


Version 8.02 19-Mar-2010
------------------------

1.  The Unicode data tables have been updated to Unicode 5.2.0.

2.  Added the option --libs-cpp to pcre-config, but only when C++ support is
    configured.

3.  Updated the licensing terms in the pcregexp.pas file, as agreed with the
    original author of that file, following a query about its status.

4.  On systems that do not have stdint.h (e.g. Solaris), check for and include
    inttypes.h instead. This fixes a bug that was introduced by change 8.01/8.

5.  A pattern such as (?&t)*+(?(DEFINE)(?<t>.)) which has a possessive
    quantifier applied to a forward-referencing subroutine call, could compile
    incorrect code or give the error "internal error: previously-checked
    referenced subpattern not found".

6.  Both MS Visual Studio and Symbian OS have problems with initializing
    variables to point to external functions. For these systems, therefore,
    pcre_malloc etc. are now initialized to local functions that call the
    relevant global functions.

7.  There were two entries missing in the vectors called coptable and poptable
    in pcre_dfa_exec.c. This could lead to memory accesses outsize the vectors.
    I've fixed the data, and added a kludgy way of testing at compile time that
    the lengths are correct (equal to the number of opcodes).

8.  Following on from 7, I added a similar kludge to check the length of the
    eint vector in pcreposix.c.

9.  Error texts for pcre_compile() are held as one long string to avoid too
    much relocation at load time. To find a text, the string is searched,
    counting zeros. There was no check for running off the end of the string,
    which could happen if a new error number was added without updating the
    string.

10. \K gave a compile-time error if it appeared in a lookbehind assersion.

11. \K was not working if it appeared in an atomic group or in a group that
    was called as a "subroutine", or in an assertion. Perl 5.11 documents that
    \K is "not well defined" if used in an assertion. PCRE now accepts it if
    the assertion is positive, but not if it is negative.

12. Change 11 fortuitously reduced the size of the stack frame used in the
    "match()" function of pcre_exec.c by one pointer. Forthcoming
    implementation of support for (*MARK) will need an extra pointer on the
    stack; I have reserved it now, so that the stack frame size does not
    decrease.

13. A pattern such as (?P<L1>(?P<L2>0)|(?P>L2)(?P>L1)) in which the only other
    item in branch that calls a recursion is a subroutine call - as in the
    second branch in the above example - was incorrectly given the compile-
    time error "recursive call could loop indefinitely" because pcre_compile()
    was not correctly checking the subroutine for matching a non-empty string.

14. The checks for overrunning compiling workspace could trigger after an
    overrun had occurred. This is a "should never occur" error, but it can be
    triggered by pathological patterns such as hundreds of nested parentheses.
    The checks now trigger 100 bytes before the end of the workspace.

15. Fix typo in configure.ac: "srtoq" should be "strtoq".


Version 8.01 19-Jan-2010
------------------------

1.  If a pattern contained a conditional subpattern with only one branch (in
    particular, this includes all (*DEFINE) patterns), a call to pcre_study()
    computed the wrong minimum data length (which is of course zero for such
    subpatterns). This could cause incorrect "no match" results.

2.  For patterns such as (?i)a(?-i)b|c where an option setting at the start of
    the pattern is reset in the first branch, pcre_compile() failed with
    "internal error: code overflow at offset...". This happened only when
    the reset was to the original external option setting. (An optimization
    abstracts leading options settings into an external setting, which was the
    cause of this.)

3.  A pattern such as ^(?!a(*SKIP)b) where a negative assertion contained one
    of the verbs SKIP, PRUNE, or COMMIT, did not work correctly. When the
    assertion pattern did not match (meaning that the assertion was true), it
    was incorrectly treated as false if the SKIP had been reached during the
    matching. This also applied to assertions used as conditions.

4.  If an item that is not supported by pcre_dfa_exec() was encountered in an
    assertion subpattern, including such a pattern used as a condition,
    unpredictable results occurred, instead of the error return
    PCRE_ERROR_DFA_UITEM.

5.  The C++ GlobalReplace function was not working like Perl for the special
    situation when an empty string is matched. It now does the fancy magic
    stuff that is necessary.

6.  In pcre_internal.h, obsolete includes to setjmp.h and stdarg.h have been
    removed. (These were left over from very, very early versions of PCRE.)

7.  Some cosmetic changes to the code to make life easier when compiling it
    as part of something else:

    (a) Change DEBUG to PCRE_DEBUG.

    (b) In pcre_compile(), rename the member of the "branch_chain" structure
        called "current" as "current_branch", to prevent a collision with the
        Linux macro when compiled as a kernel module.

    (c) In pcre_study(), rename the function set_bit() as set_table_bit(), to
        prevent a collision with the Linux macro when compiled as a kernel
        module.

8.  In pcre_compile() there are some checks for integer overflows that used to
    cast potentially large values to (double). This has been changed to that
    when building, a check for int64_t is made, and if it is found, it is used
    instead, thus avoiding the use of floating point arithmetic. (There is no
    other use of FP in PCRE.) If int64_t is not found, the fallback is to
    double.

9.  Added two casts to avoid signed/unsigned warnings from VS Studio Express
    2005 (difference between two addresses compared to an unsigned value).

10. Change the standard AC_CHECK_LIB test for libbz2 in configure.ac to a
    custom one, because of the following reported problem in Windows:

      - libbz2 uses the Pascal calling convention (WINAPI) for the functions
          under Win32.
      - The standard autoconf AC_CHECK_LIB fails to include "bzlib.h",
          therefore missing the function definition.
      - The compiler thus generates a "C" signature for the test function.
      - The linker fails to find the "C" function.
      - PCRE fails to configure if asked to do so against libbz2.

11. When running libtoolize from libtool-2.2.6b as part of autogen.sh, these
    messages were output:

      Consider adding `AC_CONFIG_MACRO_DIR([m4])' to configure.ac and
      rerunning libtoolize, to keep the correct libtool macros in-tree.
      Consider adding `-I m4' to ACLOCAL_AMFLAGS in Makefile.am.

    I have done both of these things.

12. Although pcre_dfa_exec() does not use nearly as much stack as pcre_exec()
    most of the time, it *can* run out if it is given a pattern that contains a
    runaway infinite recursion. I updated the discussion in the pcrestack man
    page.

13. Now that we have gone to the x.xx style of version numbers, the minor
    version may start with zero. Using 08 or 09 is a bad idea because users
    might check the value of PCRE_MINOR in their code, and 08 or 09 may be
    interpreted as invalid octal numbers. I've updated the previous comment in
    configure.ac, and also added a check that gives an error if 08 or 09 are
    used.

14. Change 8.00/11 was not quite complete: code had been accidentally omitted,
    causing partial matching to fail when the end of the subject matched \W
    in a UTF-8 pattern where \W was quantified with a minimum of 3.

15. There were some discrepancies between the declarations in pcre_internal.h
    of _pcre_is_newline(), _pcre_was_newline(), and _pcre_valid_utf8() and
    their definitions. The declarations used "const uschar *" and the
    definitions used USPTR. Even though USPTR is normally defined as "const
    unsigned char *" (and uschar is typedeffed as "unsigned char"), it was
    reported that: "This difference in casting confuses some C++ compilers, for
    example, SunCC recognizes above declarations as different functions and
    generates broken code for hbpcre." I have changed the declarations to use
    USPTR.

16. GNU libtool is named differently on some systems. The autogen.sh script now
    tries several variants such as glibtoolize (MacOSX) and libtoolize1x
    (FreeBSD).

17. Applied Craig's patch that fixes an HP aCC compile error in pcre 8.00
    (strtoXX undefined when compiling pcrecpp.cc). The patch contains this
    comment: "Figure out how to create a longlong from a string: strtoll and
    equivalent. It's not enough to call AC_CHECK_FUNCS: hpux has a strtoll, for
    instance, but it only takes 2 args instead of 3!"

18. A subtle bug concerned with back references has been fixed by a change of
    specification, with a corresponding code fix. A pattern such as
    ^(xa|=?\1a)+$ which contains a back reference inside the group to which it
    refers, was giving matches when it shouldn't. For example, xa=xaaa would
    match that pattern. Interestingly, Perl (at least up to 5.11.3) has the
    same bug. Such groups have to be quantified to be useful, or contained
    inside another quantified group. (If there's no repetition, the reference
    can never match.) The problem arises because, having left the group and
    moved on to the rest of the pattern, a later failure that backtracks into
    the group uses the captured value from the final iteration of the group
    rather than the correct earlier one. I have fixed this in PCRE by forcing
    any group that contains a reference to itself to be an atomic group; that
    is, there cannot be any backtracking into it once it has completed. This is
    similar to recursive and subroutine calls.


Version 8.00 19-Oct-09
----------------------

1.  The table for translating pcre_compile() error codes into POSIX error codes
    was out-of-date, and there was no check on the pcre_compile() error code
    being within the table. This could lead to an OK return being given in
    error.

2.  Changed the call to open a subject file in pcregrep from fopen(pathname,
    "r") to fopen(pathname, "rb"), which fixed a problem with some of the tests
    in a Windows environment.

3.  The pcregrep --count option prints the count for each file even when it is
    zero, as does GNU grep. However, pcregrep was also printing all files when
    --files-with-matches was added. Now, when both options are given, it prints
    counts only for those files that have at least one match. (GNU grep just
    prints the file name in this circumstance, but including the count seems
    more useful - otherwise, why use --count?) Also ensured that the
    combination -clh just lists non-zero counts, with no names.

4.  The long form of the pcregrep -F option was incorrectly implemented as
    --fixed_strings instead of --fixed-strings. This is an incompatible change,
    but it seems right to fix it, and I didn't think it was worth preserving
    the old behaviour.

5.  The command line items --regex=pattern and --regexp=pattern were not
    recognized by pcregrep, which required --regex pattern or --regexp pattern
    (with a space rather than an '='). The man page documented the '=' forms,
    which are compatible with GNU grep; these now work.

6.  No libpcreposix.pc file was created for pkg-config; there was just
    libpcre.pc and libpcrecpp.pc. The omission has been rectified.

7.  Added #ifndef SUPPORT_UCP into the pcre_ucd.c module, to reduce its size
    when UCP support is not needed, by modifying the Python script that
    generates it from Unicode data files. This should not matter if the module
    is correctly used as a library, but I received one complaint about 50K of
    unwanted data. My guess is that the person linked everything into his
    program rather than using a library. Anyway, it does no harm.

8.  A pattern such as /\x{123}{2,2}+/8 was incorrectly compiled; the trigger
    was a minimum greater than 1 for a wide character in a possessive
    repetition. The same bug could also affect patterns like /(\x{ff}{0,2})*/8
    which had an unlimited repeat of a nested, fixed maximum repeat of a wide
    character. Chaos in the form of incorrect output or a compiling loop could
    result.

9.  The restrictions on what a pattern can contain when partial matching is
    requested for pcre_exec() have been removed. All patterns can now be
    partially matched by this function. In addition, if there are at least two
    slots in the offset vector, the offset of the earliest inspected character
    for the match and the offset of the end of the subject are set in them when
    PCRE_ERROR_PARTIAL is returned.

10. Partial matching has been split into two forms: PCRE_PARTIAL_SOFT, which is
    synonymous with PCRE_PARTIAL, for backwards compatibility, and
    PCRE_PARTIAL_HARD, which causes a partial match to supersede a full match,
    and may be more useful for multi-segment matching.

11. Partial matching with pcre_exec() is now more intuitive. A partial match
    used to be given if ever the end of the subject was reached; now it is
    given only if matching could not proceed because another character was
    needed. This makes a difference in some odd cases such as Z(*FAIL) with the
    string "Z", which now yields "no match" instead of "partial match". In the
    case of pcre_dfa_exec(), "no match" is given if every matching path for the
    final character ended with (*FAIL).

12. Restarting a match using pcre_dfa_exec() after a partial match did not work
    if the pattern had a "must contain" character that was already found in the
    earlier partial match, unless partial matching was again requested. For
    example, with the pattern /dog.(body)?/, the "must contain" character is
    "g". If the first part-match was for the string "dog", restarting with
    "sbody" failed. This bug has been fixed.

13. The string returned by pcre_dfa_exec() after a partial match has been
    changed so that it starts at the first inspected character rather than the
    first character of the match. This makes a difference only if the pattern
    starts with a lookbehind assertion or \b or \B (\K is not supported by
    pcre_dfa_exec()). It's an incompatible change, but it makes the two
    matching functions compatible, and I think it's the right thing to do.

14. Added a pcredemo man page, created automatically from the pcredemo.c file,
    so that the demonstration program is easily available in environments where
    PCRE has not been installed from source.

15. Arranged to add -DPCRE_STATIC to cflags in libpcre.pc, libpcreposix.cp,
    libpcrecpp.pc and pcre-config when PCRE is not compiled as a shared
    library.

16. Added REG_UNGREEDY to the pcreposix interface, at the request of a user.
    It maps to PCRE_UNGREEDY. It is not, of course, POSIX-compatible, but it
    is not the first non-POSIX option to be added. Clearly some people find
    these options useful.

17. If a caller to the POSIX matching function regexec() passes a non-zero
    value for nmatch with a NULL value for pmatch, the value of
    nmatch is forced to zero.

18. RunGrepTest did not have a test for the availability of the -u option of
    the diff command, as RunTest does. It now checks in the same way as
    RunTest, and also checks for the -b option.

19. If an odd number of negated classes containing just a single character
    interposed, within parentheses, between a forward reference to a named
    subpattern and the definition of the subpattern, compilation crashed with
    an internal error, complaining that it could not find the referenced
    subpattern. An example of a crashing pattern is /(?&A)(([^m])(?<A>))/.
    [The bug was that it was starting one character too far in when skipping
    over the character class, thus treating the ] as data rather than
    terminating the class. This meant it could skip too much.]

20. Added PCRE_NOTEMPTY_ATSTART in order to be able to correctly implement the
    /g option in pcretest when the pattern contains \K, which makes it possible
    to have an empty string match not at the start, even when the pattern is
    anchored. Updated pcretest and pcredemo to use this option.

21. If the maximum number of capturing subpatterns in a recursion was greater
    than the maximum at the outer level, the higher number was returned, but
    with unset values at the outer level. The correct (outer level) value is
    now given.

22. If (*ACCEPT) appeared inside capturing parentheses, previous releases of
    PCRE did not set those parentheses (unlike Perl). I have now found a way to
    make it do so. The string so far is captured, making this feature
    compatible with Perl.

23. The tests have been re-organized, adding tests 11 and 12, to make it
    possible to check the Perl 5.10 features against Perl 5.10.

24. Perl 5.10 allows subroutine calls in lookbehinds, as long as the subroutine
    pattern matches a fixed length string. PCRE did not allow this; now it
    does. Neither allows recursion.

25. I finally figured out how to implement a request to provide the minimum
    length of subject string that was needed in order to match a given pattern.
    (It was back references and recursion that I had previously got hung up
    on.) This code has now been added to pcre_study(); it finds a lower bound
    to the length of subject needed. It is not necessarily the greatest lower
    bound, but using it to avoid searching strings that are too short does give
    some useful speed-ups. The value is available to calling programs via
    pcre_fullinfo().

26. While implementing 25, I discovered to my embarrassment that pcretest had
    not been passing the result of pcre_study() to pcre_dfa_exec(), so the
    study optimizations had never been tested with that matching function.
    Oops. What is worse, even when it was passed study data, there was a bug in
    pcre_dfa_exec() that meant it never actually used it. Double oops. There
    were also very few tests of studied patterns with pcre_dfa_exec().

27. If (?| is used to create subpatterns with duplicate numbers, they are now
    allowed to have the same name, even if PCRE_DUPNAMES is not set. However,
    on the other side of the coin, they are no longer allowed to have different
    names, because these cannot be distinguished in PCRE, and this has caused
    confusion. (This is a difference from Perl.)

28. When duplicate subpattern names are present (necessarily with different
    numbers, as required by 27 above), and a test is made by name in a
    conditional pattern, either for a subpattern having been matched, or for
    recursion in such a pattern, all the associated numbered subpatterns are
    tested, and the overall condition is true if the condition is true for any
    one of them. This is the way Perl works, and is also more like the way
    testing by number works.


Version 7.9 11-Apr-09
---------------------

1.  When building with support for bzlib/zlib (pcregrep) and/or readline
    (pcretest), all targets were linked against these libraries. This included
    libpcre, libpcreposix, and libpcrecpp, even though they do not use these
    libraries. This caused unwanted dependencies to be created. This problem
    has been fixed, and now only pcregrep is linked with bzlib/zlib and only
    pcretest is linked with readline.

2.  The "typedef int BOOL" in pcre_internal.h that was included inside the
    "#ifndef FALSE" condition by an earlier change (probably 7.8/18) has been
    moved outside it again, because FALSE and TRUE are already defined in AIX,
    but BOOL is not.

3.  The pcre_config() function was treating the PCRE_MATCH_LIMIT and
    PCRE_MATCH_LIMIT_RECURSION values as ints, when they should be long ints.

4.  The pcregrep documentation said spaces were inserted as well as colons (or
    hyphens) following file names and line numbers when outputting matching
    lines. This is not true; no spaces are inserted. I have also clarified the
    wording for the --colour (or --color) option.

5.  In pcregrep, when --colour was used with -o, the list of matching strings
    was not coloured; this is different to GNU grep, so I have changed it to be
    the same.

6.  When --colo(u)r was used in pcregrep, only the first matching substring in
    each matching line was coloured. Now it goes on to look for further matches
    of any of the test patterns, which is the same behaviour as GNU grep.

7.  A pattern that could match an empty string could cause pcregrep to loop; it
    doesn't make sense to accept an empty string match in pcregrep, so I have
    locked it out (using PCRE's PCRE_NOTEMPTY option). By experiment, this
    seems to be how GNU grep behaves. [But see later change 40 for release
    8.33.]

8.  The pattern (?(?=.*b)b|^) was incorrectly compiled as "match must be at
    start or after a newline", because the conditional assertion was not being
    correctly handled. The rule now is that both the assertion and what follows
    in the first alternative must satisfy the test.

9.  If auto-callout was enabled in a pattern with a conditional group whose
    condition was an assertion, PCRE could crash during matching, both with
    pcre_exec() and pcre_dfa_exec().

10. The PCRE_DOLLAR_ENDONLY option was not working when pcre_dfa_exec() was
    used for matching.

11. Unicode property support in character classes was not working for
    characters (bytes) greater than 127 when not in UTF-8 mode.

12. Added the -M command line option to pcretest.

14. Added the non-standard REG_NOTEMPTY option to the POSIX interface.

15. Added the PCRE_NO_START_OPTIMIZE match-time option.

16. Added comments and documentation about mis-use of no_arg in the C++
    wrapper.

17. Implemented support for UTF-8 encoding in EBCDIC environments, a patch
    from Martin Jerabek that uses macro names for all relevant character and
    string constants.

18. Added to pcre_internal.h two configuration checks: (a) If both EBCDIC and
    SUPPORT_UTF8 are set, give an error; (b) If SUPPORT_UCP is set without
    SUPPORT_UTF8, define SUPPORT_UTF8. The "configure" script handles both of
    these, but not everybody uses configure.

19. A conditional group that had only one branch was not being correctly
    recognized as an item that could match an empty string. This meant that an
    enclosing group might also not be so recognized, causing infinite looping
    (and probably a segfault) for patterns such as ^"((?(?=[a])[^"])|b)*"$
    with the subject "ab", where knowledge that the repeated group can match
    nothing is needed in order to break the loop.

20. If a pattern that was compiled with callouts was matched using pcre_dfa_
    exec(), but without supplying a callout function, matching went wrong.

21. If PCRE_ERROR_MATCHLIMIT occurred during a recursion, there was a memory
    leak if the size of the offset vector was greater than 30. When the vector
    is smaller, the saved offsets during recursion go onto a local stack
    vector, but for larger vectors malloc() is used. It was failing to free
    when the recursion yielded PCRE_ERROR_MATCH_LIMIT (or any other "abnormal"
    error, in fact).

22. There was a missing #ifdef SUPPORT_UTF8 round one of the variables in the
    heapframe that is used only when UTF-8 support is enabled. This caused no
    problem, but was untidy.

23. Steven Van Ingelgem's patch to CMakeLists.txt to change the name
    CMAKE_BINARY_DIR to PROJECT_BINARY_DIR so that it works when PCRE is
    included within another project.

24. Steven Van Ingelgem's patches to add more options to the CMake support,
    slightly modified by me:

      (a) PCRE_BUILD_TESTS can be set OFF not to build the tests, including
          not building pcregrep.

      (b) PCRE_BUILD_PCREGREP can be see OFF not to build pcregrep, but only
          if PCRE_BUILD_TESTS is also set OFF, because the tests use pcregrep.

25. Forward references, both numeric and by name, in patterns that made use of
    duplicate group numbers, could behave incorrectly or give incorrect errors,
    because when scanning forward to find the reference group, PCRE was not
    taking into account the duplicate group numbers. A pattern such as
    ^X(?3)(a)(?|(b)|(q))(Y) is an example.

26. Changed a few more instances of "const unsigned char *" to USPTR, making
    the feature of a custom pointer more persuasive (as requested by a user).

27. Wrapped the definitions of fileno and isatty for Windows, which appear in
    pcretest.c, inside #ifndefs, because it seems they are sometimes already
    pre-defined.

28. Added support for (*UTF8) at the start of a pattern.

29. Arrange for flags added by the "release type" setting in CMake to be shown
    in the configuration summary.


Version 7.8 05-Sep-08
---------------------

1.  Replaced UCP searching code with optimized version as implemented for Ad
    Muncher (http://www.admuncher.com/) by Peter Kankowski. This uses a two-
    stage table and inline lookup instead of a function, giving speed ups of 2
    to 5 times on some simple patterns that I tested. Permission was given to
    distribute the MultiStage2.py script that generates the tables (it's not in
    the tarball, but is in the Subversion repository).

2.  Updated the Unicode datatables to Unicode 5.1.0. This adds yet more
    scripts.

3.  Change 12 for 7.7 introduced a bug in pcre_study() when a pattern contained
    a group with a zero qualifier. The result of the study could be incorrect,
    or the function might crash, depending on the pattern.

4.  Caseless matching was not working for non-ASCII characters in back
    references. For example, /(\x{de})\1/8i was not matching \x{de}\x{fe}.
    It now works when Unicode Property Support is available.

5.  In pcretest, an escape such as \x{de} in the data was always generating
    a UTF-8 string, even in non-UTF-8 mode. Now it generates a single byte in
    non-UTF-8 mode. If the value is greater than 255, it gives a warning about
    truncation.

6.  Minor bugfix in pcrecpp.cc (change "" == ... to NULL == ...).

7.  Added two (int) casts to pcregrep when printing the difference of two
    pointers, in case they are 64-bit values.

8.  Added comments about Mac OS X stack usage to the pcrestack man page and to
    test 2 if it fails.

9.  Added PCRE_CALL_CONVENTION just before the names of all exported functions,
    and a #define of that name to empty if it is not externally set. This is to
    allow users of MSVC to set it if necessary.

10. The PCRE_EXP_DEFN macro which precedes exported functions was missing from
    the convenience functions in the pcre_get.c source file.

11. An option change at the start of a pattern that had top-level alternatives
    could cause overwriting and/or a crash. This command provoked a crash in
    some environments:

      printf "/(?i)[\xc3\xa9\xc3\xbd]|[\xc3\xa9\xc3\xbdA]/8\n" | pcretest

    This potential security problem was recorded as CVE-2008-2371.

12. For a pattern where the match had to start at the beginning or immediately
    after a newline (e.g /.*anything/ without the DOTALL flag), pcre_exec() and
    pcre_dfa_exec() could read past the end of the passed subject if there was
    no match. To help with detecting such bugs (e.g. with valgrind), I modified
    pcretest so that it places the subject at the end of its malloc-ed buffer.

13. The change to pcretest in 12 above threw up a couple more cases when pcre_
    exec() might read past the end of the data buffer in UTF-8 mode.

14. A similar bug to 7.3/2 existed when the PCRE_FIRSTLINE option was set and
    the data contained the byte 0x85 as part of a UTF-8 character within its
    first line. This applied both to normal and DFA matching.

15. Lazy qualifiers were not working in some cases in UTF-8 mode. For example,
    /^[^d]*?$/8 failed to match "abc".

16. Added a missing copyright notice to pcrecpp_internal.h.

17. Make it more clear in the documentation that values returned from
    pcre_exec() in ovector are byte offsets, not character counts.

18. Tidied a few places to stop certain compilers from issuing warnings.

19. Updated the Virtual Pascal + BCC files to compile the latest v7.7, as
    supplied by Stefan Weber. I made a further small update for 7.8 because
    there is a change of source arrangements: the pcre_searchfuncs.c module is
    replaced by pcre_ucd.c.


Version 7.7 07-May-08
---------------------

1.  Applied Craig's patch to sort out a long long problem: "If we can't convert
    a string to a long long, pretend we don't even have a long long." This is
    done by checking for the strtoq, strtoll, and _strtoi64 functions.

2.  Applied Craig's patch to pcrecpp.cc to restore ABI compatibility with
    pre-7.6 versions, which defined a global no_arg variable instead of putting
    it in the RE class. (See also #8 below.)

3.  Remove a line of dead code, identified by coverity and reported by Nuno
    Lopes.

4.  Fixed two related pcregrep bugs involving -r with --include or --exclude:

    (1) The include/exclude patterns were being applied to the whole pathnames
        of files, instead of just to the final components.

    (2) If there was more than one level of directory, the subdirectories were
        skipped unless they satisfied the include/exclude conditions. This is
        inconsistent with GNU grep (and could even be seen as contrary to the
        pcregrep specification - which I improved to make it absolutely clear).
        The action now is always to scan all levels of directory, and just
        apply the include/exclude patterns to regular files.

5.  Added the --include_dir and --exclude_dir patterns to pcregrep, and used
    --exclude_dir in the tests to avoid scanning .svn directories.

6.  Applied Craig's patch to the QuoteMeta function so that it escapes the
    NUL character as backslash + 0 rather than backslash + NUL, because PCRE
    doesn't support NULs in patterns.

7.  Added some missing "const"s to declarations of static tables in
    pcre_compile.c and pcre_dfa_exec.c.

8.  Applied Craig's patch to pcrecpp.cc to fix a problem in OS X that was
    caused by fix #2  above. (Subsequently also a second patch to fix the
    first patch. And a third patch - this was a messy problem.)

9.  Applied Craig's patch to remove the use of push_back().

10. Applied Alan Lehotsky's patch to add REG_STARTEND support to the POSIX
    matching function regexec().

11. Added support for the Oniguruma syntax \g<name>, \g<n>, \g'name', \g'n',
    which, however, unlike Perl's \g{...}, are subroutine calls, not back
    references. PCRE supports relative numbers with this syntax (I don't think
    Oniguruma does).

12. Previously, a group with a zero repeat such as (...){0} was completely
    omitted from the compiled regex. However, this means that if the group
    was called as a subroutine from elsewhere in the pattern, things went wrong
    (an internal error was given). Such groups are now left in the compiled
    pattern, with a new opcode that causes them to be skipped at execution
    time.

13. Added the PCRE_JAVASCRIPT_COMPAT option. This makes the following changes
    to the way PCRE behaves:

    (a) A lone ] character is dis-allowed (Perl treats it as data).

    (b) A back reference to an unmatched subpattern matches an empty string
        (Perl fails the current match path).

    (c) A data ] in a character class must be notated as \] because if the
        first data character in a class is ], it defines an empty class. (In
        Perl it is not possible to have an empty class.) The empty class []
        never matches; it forces failure and is equivalent to (*FAIL) or (?!).
        The negative empty class [^] matches any one character, independently
        of the DOTALL setting.

14. A pattern such as /(?2)[]a()b](abc)/ which had a forward reference to a
    non-existent subpattern following a character class starting with ']' and
    containing () gave an internal compiling error instead of "reference to
    non-existent subpattern". Fortunately, when the pattern did exist, the
    compiled code was correct. (When scanning forwards to check for the
    existence of the subpattern, it was treating the data ']' as terminating
    the class, so got the count wrong. When actually compiling, the reference
    was subsequently set up correctly.)

15. The "always fail" assertion (?!) is optimzed to (*FAIL) by pcre_compile;
    it was being rejected as not supported by pcre_dfa_exec(), even though
    other assertions are supported. I have made pcre_dfa_exec() support
    (*FAIL).

16. The implementation of 13c above involved the invention of a new opcode,
    OP_ALLANY, which is like OP_ANY but doesn't check the /s flag. Since /s
    cannot be changed at match time, I realized I could make a small
    improvement to matching performance by compiling OP_ALLANY instead of
    OP_ANY for "." when DOTALL was set, and then removing the runtime tests
    on the OP_ANY path.

17. Compiling pcretest on Windows with readline support failed without the
    following two fixes: (1) Make the unistd.h include conditional on
    HAVE_UNISTD_H; (2) #define isatty and fileno as _isatty and _fileno.

18. Changed CMakeLists.txt and cmake/FindReadline.cmake to arrange for the
    ncurses library to be included for pcretest when ReadLine support is
    requested, but also to allow for it to be overridden. This patch came from
    Daniel Bergström.

19. There was a typo in the file ucpinternal.h where f0_rangeflag was defined
    as 0x00f00000 instead of 0x00800000. Luckily, this would not have caused
    any errors with the current Unicode tables. Thanks to Peter Kankowski for
    spotting this.


Version 7.6 28-Jan-08
---------------------

1.  A character class containing a very large number of characters with
    codepoints greater than 255 (in UTF-8 mode, of course) caused a buffer
    overflow.

2.  Patch to cut out the "long long" test in pcrecpp_unittest when
    HAVE_LONG_LONG is not defined.

3.  Applied Christian Ehrlicher's patch to update the CMake build files to
    bring them up to date and include new features. This patch includes:

    - Fixed PH's badly added libz and libbz2 support.
    - Fixed a problem with static linking.
    - Added pcredemo. [But later removed - see 7 below.]
    - Fixed dftables problem and added an option.
    - Added a number of HAVE_XXX tests, including HAVE_WINDOWS_H and
        HAVE_LONG_LONG.
    - Added readline support for pcretest.
    - Added an listing of the option settings after cmake has run.

4.  A user submitted a patch to Makefile that makes it easy to create
    "pcre.dll" under mingw when using Configure/Make. I added stuff to
    Makefile.am that cause it to include this special target, without
    affecting anything else. Note that the same mingw target plus all
    the other distribution libraries and programs are now supported
    when configuring with CMake (see 6 below) instead of with
    Configure/Make.

5.  Applied Craig's patch that moves no_arg into the RE class in the C++ code.
    This is an attempt to solve the reported problem "pcrecpp::no_arg is not
    exported in the Windows port". It has not yet been confirmed that the patch
    solves the problem, but it does no harm.

6.  Applied Sheri's patch to CMakeLists.txt to add NON_STANDARD_LIB_PREFIX and
    NON_STANDARD_LIB_SUFFIX for dll names built with mingw when configured
    with CMake, and also correct the comment about stack recursion.

7.  Remove the automatic building of pcredemo from the ./configure system and
    from CMakeLists.txt. The whole idea of pcredemo.c is that it is an example
    of a program that users should build themselves after PCRE is installed, so
    building it automatically is not really right. What is more, it gave
    trouble in some build environments.

8.  Further tidies to CMakeLists.txt from Sheri and Christian.


Version 7.5 10-Jan-08
---------------------

1.  Applied a patch from Craig: "This patch makes it possible to 'ignore'
    values in parens when parsing an RE using the C++ wrapper."

2.  Negative specials like \S did not work in character classes in UTF-8 mode.
    Characters greater than 255 were excluded from the class instead of being
    included.

3.  The same bug as (2) above applied to negated POSIX classes such as
    [:^space:].

4.  PCRECPP_STATIC was referenced in pcrecpp_internal.h, but nowhere was it
    defined or documented. It seems to have been a typo for PCRE_STATIC, so
    I have changed it.

5.  The construct (?&) was not diagnosed as a syntax error (it referenced the
    first named subpattern) and a construct such as (?&a) would reference the
    first named subpattern whose name started with "a" (in other words, the
    length check was missing). Both these problems are fixed. "Subpattern name
    expected" is now given for (?&) (a zero-length name), and this patch also
    makes it give the same error for \k'' (previously it complained that that
    was a reference to a non-existent subpattern).

6.  The erroneous patterns (?+-a) and (?-+a) give different error messages;
    this is right because (?- can be followed by option settings as well as by
    digits. I have, however, made the messages clearer.

7.  Patterns such as (?(1)a|b) (a pattern that contains fewer subpatterns
    than the number used in the conditional) now cause a compile-time error.
    This is actually not compatible with Perl, which accepts such patterns, but
    treats the conditional as always being FALSE (as PCRE used to), but it
    seems to me that giving a diagnostic is better.

8.  Change "alphameric" to the more common word "alphanumeric" in comments
    and messages.

9.  Fix two occurrences of "backslash" in comments that should have been
    "backspace".

10. Remove two redundant lines of code that can never be obeyed (their function
    was moved elsewhere).

11. The program that makes PCRE's Unicode character property table had a bug
    which caused it to generate incorrect table entries for sequences of
    characters that have the same character type, but are in different scripts.
    It amalgamated them into a single range, with the script of the first of
    them. In other words, some characters were in the wrong script. There were
    thirteen such cases, affecting characters in the following ranges:

      U+002b0 - U+002c1
      U+0060c - U+0060d
      U+0061e - U+00612
      U+0064b - U+0065e
      U+0074d - U+0076d
      U+01800 - U+01805
      U+01d00 - U+01d77
      U+01d9b - U+01dbf
      U+0200b - U+0200f
      U+030fc - U+030fe
      U+03260 - U+0327f
      U+0fb46 - U+0fbb1
      U+10450 - U+1049d

12. The -o option (show only the matching part of a line) for pcregrep was not
    compatible with GNU grep in that, if there was more than one match in a
    line, it showed only the first of them. It now behaves in the same way as
    GNU grep.

13. If the -o and -v options were combined for pcregrep, it printed a blank
    line for every non-matching line. GNU grep prints nothing, and pcregrep now
    does the same. The return code can be used to tell if there were any
    non-matching lines.

14. Added --file-offsets and --line-offsets to pcregrep.

15. The pattern (?=something)(?R) was not being diagnosed as a potentially
    infinitely looping recursion. The bug was that positive lookaheads were not
    being skipped when checking for a possible empty match (negative lookaheads
    and both kinds of lookbehind were skipped).

16. Fixed two typos in the Windows-only code in pcregrep.c, and moved the
    inclusion of <windows.h> to before rather than after the definition of
    INVALID_FILE_ATTRIBUTES (patch from David Byron).

17. Specifying a possessive quantifier with a specific limit for a Unicode
    character property caused pcre_compile() to compile bad code, which led at
    runtime to PCRE_ERROR_INTERNAL (-14). Examples of patterns that caused this
    are: /\p{Zl}{2,3}+/8 and /\p{Cc}{2}+/8. It was the possessive "+" that
    caused the error; without that there was no problem.

18. Added --enable-pcregrep-libz and --enable-pcregrep-libbz2.

19. Added --enable-pcretest-libreadline.

20. In pcrecpp.cc, the variable 'count' was incremented twice in
    RE::GlobalReplace(). As a result, the number of replacements returned was
    double what it should be. I removed one of the increments, but Craig sent a
    later patch that removed the other one (the right fix) and added unit tests
    that check the return values (which was not done before).

21. Several CMake things:

    (1) Arranged that, when cmake is used on Unix, the libraries end up with
        the names libpcre and libpcreposix, not just pcre and pcreposix.

    (2) The above change means that pcretest and pcregrep are now correctly
        linked with the newly-built libraries, not previously installed ones.

    (3) Added PCRE_SUPPORT_LIBREADLINE, PCRE_SUPPORT_LIBZ, PCRE_SUPPORT_LIBBZ2.

22. In UTF-8 mode, with newline set to "any", a pattern such as .*a.*=.b.*
    crashed when matching a string such as a\x{2029}b (note that \x{2029} is a
    UTF-8 newline character). The key issue is that the pattern starts .*;
    this means that the match must be either at the beginning, or after a
    newline. The bug was in the code for advancing after a failed match and
    checking that the new position followed a newline. It was not taking
    account of UTF-8 characters correctly.

23. PCRE was behaving differently from Perl in the way it recognized POSIX
    character classes. PCRE was not treating the sequence [:...:] as a
    character class unless the ... were all letters. Perl, however, seems to
    allow any characters between [: and :], though of course it rejects as
    unknown any "names" that contain non-letters, because all the known class
    names consist only of letters. Thus, Perl gives an error for [[:1234:]],
    for example, whereas PCRE did not - it did not recognize a POSIX character
    class. This seemed a bit dangerous, so the code has been changed to be
    closer to Perl. The behaviour is not identical to Perl, because PCRE will
    diagnose an unknown class for, for example, [[:l\ower:]] where Perl will
    treat it as [[:lower:]]. However, PCRE does now give "unknown" errors where
    Perl does, and where it didn't before.

24. Rewrite so as to remove the single use of %n from pcregrep because in some
    Windows environments %n is disabled by default.


Version 7.4 21-Sep-07
---------------------

1.  Change 7.3/28 was implemented for classes by looking at the bitmap. This
    means that a class such as [\s] counted as "explicit reference to CR or
    LF". That isn't really right - the whole point of the change was to try to
    help when there was an actual mention of one of the two characters. So now
    the change happens only if \r or \n (or a literal CR or LF) character is
    encountered.

2.  The 32-bit options word was also used for 6 internal flags, but the numbers
    of both had grown to the point where there were only 3 bits left.
    Fortunately, there was spare space in the data structure, and so I have
    moved the internal flags into a new 16-bit field to free up more option
    bits.

3.  The appearance of (?J) at the start of a pattern set the DUPNAMES option,
    but did not set the internal JCHANGED flag - either of these is enough to
    control the way the "get" function works - but the PCRE_INFO_JCHANGED
    facility is supposed to tell if (?J) was ever used, so now (?J) at the
    start sets both bits.

4.  Added options (at build time, compile time, exec time) to change \R from
    matching any Unicode line ending sequence to just matching CR, LF, or CRLF.

5.  doc/pcresyntax.html was missing from the distribution.

6.  Put back the definition of PCRE_ERROR_NULLWSLIMIT, for backward
    compatibility, even though it is no longer used.

7.  Added macro for snprintf to pcrecpp_unittest.cc and also for strtoll and
    strtoull to pcrecpp.cc to select the available functions in WIN32 when the
    windows.h file is present (where different names are used). [This was
    reversed later after testing - see 16 below.]

8.  Changed all #include <config.h> to #include "config.h". There were also
    some further <pcre.h> cases that I changed to "pcre.h".

9.  When pcregrep was used with the --colour option, it missed the line ending
    sequence off the lines that it output.

10. It was pointed out to me that arrays of string pointers cause lots of
    relocations when a shared library is dynamically loaded. A technique of
    using a single long string with a table of offsets can drastically reduce
    these. I have refactored PCRE in four places to do this. The result is
    dramatic:

      Originally:                          290
      After changing UCP table:            187
      After changing error message table:   43
      After changing table of "verbs"       36
      After changing table of Posix names   22

    Thanks to the folks working on Gregex for glib for this insight.

11. --disable-stack-for-recursion caused compiling to fail unless -enable-
    unicode-properties was also set.

12. Updated the tests so that they work when \R is defaulted to ANYCRLF.

13. Added checks for ANY and ANYCRLF to pcrecpp.cc where it previously
    checked only for CRLF.

14. Added casts to pcretest.c to avoid compiler warnings.

15. Added Craig's patch to various pcrecpp modules to avoid compiler warnings.

16. Added Craig's patch to remove the WINDOWS_H tests, that were not working,
    and instead check for _strtoi64 explicitly, and avoid the use of snprintf()
    entirely. This removes changes made in 7 above.

17. The CMake files have been updated, and there is now more information about
    building with CMake in the NON-UNIX-USE document.


Version 7.3 28-Aug-07
---------------------

 1. In the rejigging of the build system that eventually resulted in 7.1, the
    line "#include <pcre.h>" was included in pcre_internal.h. The use of angle
    brackets there is not right, since it causes compilers to look for an
    installed pcre.h, not the version that is in the source that is being
    compiled (which of course may be different). I have changed it back to:

      #include "pcre.h"

    I have a vague recollection that the change was concerned with compiling in
    different directories, but in the new build system, that is taken care of
    by the VPATH setting the Makefile.

 2. The pattern .*$ when run in not-DOTALL UTF-8 mode with newline=any failed
    when the subject happened to end in the byte 0x85 (e.g. if the last
    character was \x{1ec5}). *Character* 0x85 is one of the "any" newline
    characters but of course it shouldn't be taken as a newline when it is part
    of another character. The bug was that, for an unlimited repeat of . in
    not-DOTALL UTF-8 mode, PCRE was advancing by bytes rather than by
    characters when looking for a newline.

 3. A small performance improvement in the DOTALL UTF-8 mode .* case.

 4. Debugging: adjusted the names of opcodes for different kinds of parentheses
    in debug output.

 5. Arrange to use "%I64d" instead of "%lld" and "%I64u" instead of "%llu" for
    long printing in the pcrecpp unittest when running under MinGW.

 6. ESC_K was left out of the EBCDIC table.

 7. Change 7.0/38 introduced a new limit on the number of nested non-capturing
    parentheses; I made it 1000, which seemed large enough. Unfortunately, the
    limit also applies to "virtual nesting" when a pattern is recursive, and in
    this case 1000 isn't so big. I have been able to remove this limit at the
    expense of backing off one optimization in certain circumstances. Normally,
    when pcre_exec() would call its internal match() function recursively and
    immediately return the result unconditionally, it uses a "tail recursion"
    feature to save stack. However, when a subpattern that can match an empty
    string has an unlimited repetition quantifier, it no longer makes this
    optimization. That gives it a stack frame in which to save the data for
    checking that an empty string has been matched. Previously this was taken
    from the 1000-entry workspace that had been reserved. So now there is no
    explicit limit, but more stack is used.

 8. Applied Daniel's patches to solve problems with the import/export magic
    syntax that is required for Windows, and which was going wrong for the
    pcreposix and pcrecpp parts of the library. These were overlooked when this
    problem was solved for the main library.

 9. There were some crude static tests to avoid integer overflow when computing
    the size of patterns that contain repeated groups with explicit upper
    limits. As the maximum quantifier is 65535, the maximum group length was
    set at 30,000 so that the product of these two numbers did not overflow a
    32-bit integer. However, it turns out that people want to use groups that
    are longer than 30,000 bytes (though not repeat them that many times).
    Change 7.0/17 (the refactoring of the way the pattern size is computed) has
    made it possible to implement the integer overflow checks in a much more
    dynamic way, which I have now done. The artificial limitation on group
    length has been removed - we now have only the limit on the total length of
    the compiled pattern, which depends on the LINK_SIZE setting.

10. Fixed a bug in the documentation for get/copy named substring when
    duplicate names are permitted. If none of the named substrings are set, the
    functions return PCRE_ERROR_NOSUBSTRING (7); the doc said they returned an
    empty string.

11. Because Perl interprets \Q...\E at a high level, and ignores orphan \E
    instances, patterns such as [\Q\E] or [\E] or even [^\E] cause an error,
    because the ] is interpreted as the first data character and the
    terminating ] is not found. PCRE has been made compatible with Perl in this
    regard. Previously, it interpreted [\Q\E] as an empty class, and [\E] could
    cause memory overwriting.

10. Like Perl, PCRE automatically breaks an unlimited repeat after an empty
    string has been matched (to stop an infinite loop). It was not recognizing
    a conditional subpattern that could match an empty string if that
    subpattern was within another subpattern. For example, it looped when
    trying to match  (((?(1)X|))*)  but it was OK with  ((?(1)X|)*)  where the
    condition was not nested. This bug has been fixed.

12. A pattern like \X?\d or \P{L}?\d in non-UTF-8 mode could cause a backtrack
    past the start of the subject in the presence of bytes with the top bit
    set, for example "\x8aBCD".

13. Added Perl 5.10 experimental backtracking controls (*FAIL), (*F), (*PRUNE),
    (*SKIP), (*THEN), (*COMMIT), and (*ACCEPT).

14. Optimized (?!) to (*FAIL).

15. Updated the test for a valid UTF-8 string to conform to the later RFC 3629.
    This restricts code points to be within the range 0 to 0x10FFFF, excluding
    the "low surrogate" sequence 0xD800 to 0xDFFF. Previously, PCRE allowed the
    full range 0 to 0x7FFFFFFF, as defined by RFC 2279. Internally, it still
    does: it's just the validity check that is more restrictive.

16. Inserted checks for integer overflows during escape sequence (backslash)
    processing, and also fixed erroneous offset values for syntax errors during
    backslash processing.

17. Fixed another case of looking too far back in non-UTF-8 mode (cf 12 above)
    for patterns like [\PPP\x8a]{1,}\x80 with the subject "A\x80".

18. An unterminated class in a pattern like (?1)\c[ with a "forward reference"
    caused an overrun.

19. A pattern like (?:[\PPa*]*){8,} which had an "extended class" (one with
    something other than just ASCII characters) inside a group that had an
    unlimited repeat caused a loop at compile time (while checking to see
    whether the group could match an empty string).

20. Debugging a pattern containing \p or \P could cause a crash. For example,
    [\P{Any}] did so. (Error in the code for printing property names.)

21. An orphan \E inside a character class could cause a crash.

22. A repeated capturing bracket such as (A)? could cause a wild memory
    reference during compilation.

23. There are several functions in pcre_compile() that scan along a compiled
    expression for various reasons (e.g. to see if it's fixed length for look
    behind). There were bugs in these functions when a repeated \p or \P was
    present in the pattern. These operators have additional parameters compared
    with \d, etc, and these were not being taken into account when moving along
    the compiled data. Specifically:

    (a) A item such as \p{Yi}{3} in a lookbehind was not treated as fixed
        length.

    (b) An item such as \pL+ within a repeated group could cause crashes or
        loops.

    (c) A pattern such as \p{Yi}+(\P{Yi}+)(?1) could give an incorrect
        "reference to non-existent subpattern" error.

    (d) A pattern like (\P{Yi}{2}\277)? could loop at compile time.

24. A repeated \S or \W in UTF-8 mode could give wrong answers when multibyte
    characters were involved (for example /\S{2}/8g with "A\x{a3}BC").

25. Using pcregrep in multiline, inverted mode (-Mv) caused it to loop.

26. Patterns such as [\P{Yi}A] which include \p or \P and just one other
    character were causing crashes (broken optimization).

27. Patterns such as (\P{Yi}*\277)* (group with possible zero repeat containing
    \p or \P) caused a compile-time loop.

28. More problems have arisen in unanchored patterns when CRLF is a valid line
    break. For example, the unstudied pattern [\r\n]A does not match the string
    "\r\nA" because change 7.0/46 below moves the current point on by two
    characters after failing to match at the start. However, the pattern \nA
    *does* match, because it doesn't start till \n, and if [\r\n]A is studied,
    the same is true. There doesn't seem any very clean way out of this, but
    what I have chosen to do makes the common cases work: PCRE now takes note
    of whether there can be an explicit match for \r or \n anywhere in the
    pattern, and if so, 7.0/46 no longer applies. As part of this change,
    there's a new PCRE_INFO_HASCRORLF option for finding out whether a compiled
    pattern has explicit CR or LF references.

29. Added (*CR) etc for changing newline setting at start of pattern.


Version 7.2 19-Jun-07
---------------------

 1. If the fr_FR locale cannot be found for test 3, try the "french" locale,
    which is apparently normally available under Windows.

 2. Re-jig the pcregrep tests with different newline settings in an attempt
    to make them independent of the local environment's newline setting.

 3. Add code to configure.ac to remove -g from the CFLAGS default settings.

 4. Some of the "internals" tests were previously cut out when the link size
    was not 2, because the output contained actual offsets. The recent new
    "Z" feature of pcretest means that these can be cut out, making the tests
    usable with all link sizes.

 5. Implemented Stan Switzer's goto replacement for longjmp() when not using
    stack recursion. This gives a massive performance boost under BSD, but just
    a small improvement under Linux. However, it saves one field in the frame
    in all cases.

 6. Added more features from the forthcoming Perl 5.10:

    (a) (?-n) (where n is a string of digits) is a relative subroutine or
        recursion call. It refers to the nth most recently opened parentheses.

    (b) (?+n) is also a relative subroutine call; it refers to the nth next
        to be opened parentheses.

    (c) Conditions that refer to capturing parentheses can be specified
        relatively, for example, (?(-2)... or (?(+3)...

    (d) \K resets the start of the current match so that everything before
        is not part of it.

    (e) \k{name} is synonymous with \k<name> and \k'name' (.NET compatible).

    (f) \g{name} is another synonym - part of Perl 5.10's unification of
        reference syntax.

    (g) (?| introduces a group in which the numbering of parentheses in each
        alternative starts with the same number.

    (h) \h, \H, \v, and \V match horizontal and vertical whitespace.

 7. Added two new calls to pcre_fullinfo(): PCRE_INFO_OKPARTIAL and
    PCRE_INFO_JCHANGED.

 8. A pattern such as  (.*(.)?)*  caused pcre_exec() to fail by either not
    terminating or by crashing. Diagnosed by Viktor Griph; it was in the code
    for detecting groups that can match an empty string.

 9. A pattern with a very large number of alternatives (more than several
    hundred) was running out of internal workspace during the pre-compile
    phase, where pcre_compile() figures out how much memory will be needed. A
    bit of new cunning has reduced the workspace needed for groups with
    alternatives. The 1000-alternative test pattern now uses 12 bytes of
    workspace instead of running out of the 4096 that are available.

10. Inserted some missing (unsigned int) casts to get rid of compiler warnings.

11. Applied patch from Google to remove an optimization that didn't quite work.
    The report of the bug said:

      pcrecpp::RE("a*").FullMatch("aaa") matches, while
      pcrecpp::RE("a*?").FullMatch("aaa") does not, and
      pcrecpp::RE("a*?\\z").FullMatch("aaa") does again.

12. If \p or \P was used in non-UTF-8 mode on a character greater than 127
    it matched the wrong number of bytes.


Version 7.1 24-Apr-07
---------------------

 1. Applied Bob Rossi and Daniel G's patches to convert the build system to one
    that is more "standard", making use of automake and other Autotools. There
    is some re-arrangement of the files and adjustment of comments consequent
    on this.

 2. Part of the patch fixed a problem with the pcregrep tests. The test of -r
    for recursive directory scanning broke on some systems because the files
    are not scanned in any specific order and on different systems the order
    was different. A call to "sort" has been inserted into RunGrepTest for the
    approprate test as a short-term fix. In the longer term there may be an
    alternative.

 3. I had an email from Eric Raymond about problems translating some of PCRE's
    man pages to HTML (despite the fact that I distribute HTML pages, some
    people do their own conversions for various reasons). The problems
    concerned the use of low-level troff macros .br and .in. I have therefore
    removed all such uses from the man pages (some were redundant, some could
    be replaced by .nf/.fi pairs). The 132html script that I use to generate
    HTML has been updated to handle .nf/.fi and to complain if it encounters
    .br or .in.

 4. Updated comments in configure.ac that get placed in config.h.in and also
    arranged for config.h to be included in the distribution, with the name
    config.h.generic, for the benefit of those who have to compile without
    Autotools (compare pcre.h, which is now distributed as pcre.h.generic).

 5. Updated the support (such as it is) for Virtual Pascal, thanks to Stefan
    Weber: (1) pcre_internal.h was missing some function renames; (2) updated
    makevp.bat for the current PCRE, using the additional files
    makevp_c.txt, makevp_l.txt, and pcregexp.pas.

 6. A Windows user reported a minor discrepancy with test 2, which turned out
    to be caused by a trailing space on an input line that had got lost in his
    copy. The trailing space was an accident, so I've just removed it.

 7. Add -Wl,-R... flags in pcre-config.in for *BSD* systems, as I'm told
    that is needed.

 8. Mark ucp_table (in ucptable.h) and ucp_gentype (in pcre_ucp_searchfuncs.c)
    as "const" (a) because they are and (b) because it helps the PHP
    maintainers who have recently made a script to detect big data structures
    in the php code that should be moved to the .rodata section. I remembered
    to update Builducptable as well, so it won't revert if ucptable.h is ever
    re-created.

 9. Added some extra #ifdef SUPPORT_UTF8 conditionals into pcretest.c,
    pcre_printint.src, pcre_compile.c, pcre_study.c, and pcre_tables.c, in
    order to be able to cut out the UTF-8 tables in the latter when UTF-8
    support is not required. This saves 1.5-2K of code, which is important in
    some applications.

    Later: more #ifdefs are needed in pcre_ord2utf8.c and pcre_valid_utf8.c
    so as not to refer to the tables, even though these functions will never be
    called when UTF-8 support is disabled. Otherwise there are problems with a
    shared library.

10. Fixed two bugs in the emulated memmove() function in pcre_internal.h:

    (a) It was defining its arguments as char * instead of void *.

    (b) It was assuming that all moves were upwards in memory; this was true
        a long time ago when I wrote it, but is no longer the case.

    The emulated memove() is provided for those environments that have neither
    memmove() nor bcopy(). I didn't think anyone used it these days, but that
    is clearly not the case, as these two bugs were recently reported.

11. The script PrepareRelease is now distributed: it calls 132html, CleanTxt,
    and Detrail to create the HTML documentation, the .txt form of the man
    pages, and it removes trailing spaces from listed files. It also creates
    pcre.h.generic and config.h.generic from pcre.h and config.h. In the latter
    case, it wraps all the #defines with #ifndefs. This script should be run
    before "make dist".

12. Fixed two fairly obscure bugs concerned with quantified caseless matching
    with Unicode property support.

    (a) For a maximizing quantifier, if the two different cases of the
        character were of different lengths in their UTF-8 codings (there are
        some cases like this - I found 11), and the matching function had to
        back up over a mixture of the two cases, it incorrectly assumed they
        were both the same length.

    (b) When PCRE was configured to use the heap rather than the stack for
        recursion during matching, it was not correctly preserving the data for
        the other case of a UTF-8 character when checking ahead for a match
        while processing a minimizing repeat. If the check also involved
        matching a wide character, but failed, corruption could cause an
        erroneous result when trying to check for a repeat of the original
        character.

13. Some tidying changes to the testing mechanism:

    (a) The RunTest script now detects the internal link size and whether there
        is UTF-8 and UCP support by running ./pcretest -C instead of relying on
        values substituted by "configure". (The RunGrepTest script already did
        this for UTF-8.) The configure.ac script no longer substitutes the
        relevant variables.

    (b) The debugging options /B and /D in pcretest show the compiled bytecode
        with length and offset values. This means that the output is different
        for different internal link sizes. Test 2 is skipped for link sizes
        other than 2 because of this, bypassing the problem. Unfortunately,
        there was also a test in test 3 (the locale tests) that used /B and
        failed for link sizes other than 2. Rather than cut the whole test out,
        I have added a new /Z option to pcretest that replaces the length and
        offset values with spaces. This is now used to make test 3 independent
        of link size. (Test 2 will be tidied up later.)

14. If erroroffset was passed as NULL to pcre_compile, it provoked a
    segmentation fault instead of returning the appropriate error message.

15. In multiline mode when the newline sequence was set to "any", the pattern
    ^$ would give a match between the \r and \n of a subject such as "A\r\nB".
    This doesn't seem right; it now treats the CRLF combination as the line
    ending, and so does not match in that case. It's only a pattern such as ^$
    that would hit this one: something like ^ABC$ would have failed after \r
    and then tried again after \r\n.

16. Changed the comparison command for RunGrepTest from "diff -u" to "diff -ub"
    in an attempt to make files that differ only in their line terminators
    compare equal. This works on Linux.

17. Under certain error circumstances pcregrep might try to free random memory
    as it exited. This is now fixed, thanks to valgrind.

19. In pcretest, if the pattern /(?m)^$/g<any> was matched against the string
    "abc\r\n\r\n", it found an unwanted second match after the second \r. This
    was because its rules for how to advance for /g after matching an empty
    string at the end of a line did not allow for this case. They now check for
    it specially.

20. pcretest is supposed to handle patterns and data of any length, by
    extending its buffers when necessary. It was getting this wrong when the
    buffer for a data line had to be extended.

21. Added PCRE_NEWLINE_ANYCRLF which is like ANY, but matches only CR, LF, or
    CRLF as a newline sequence.

22. Code for handling Unicode properties in pcre_dfa_exec() wasn't being cut
    out by #ifdef SUPPORT_UCP. This did no harm, as it could never be used, but
    I have nevertheless tidied it up.

23. Added some casts to kill warnings from HP-UX ia64 compiler.

24. Added a man page for pcre-config.


Version 7.0 19-Dec-06
---------------------

 1. Fixed a signed/unsigned compiler warning in pcre_compile.c, shown up by
    moving to gcc 4.1.1.

 2. The -S option for pcretest uses setrlimit(); I had omitted to #include
    sys/time.h, which is documented as needed for this function. It doesn't
    seem to matter on Linux, but it showed up on some releases of OS X.

 3. It seems that there are systems where bytes whose values are greater than
    127 match isprint() in the "C" locale. The "C" locale should be the
    default when a C program starts up. In most systems, only ASCII printing
    characters match isprint(). This difference caused the output from pcretest
    to vary, making some of the tests fail. I have changed pcretest so that:

    (a) When it is outputting text in the compiled version of a pattern, bytes
        other than 32-126 are always shown as hex escapes.

    (b) When it is outputting text that is a matched part of a subject string,
        it does the same, unless a different locale has been set for the match
        (using the /L modifier). In this case, it uses isprint() to decide.

 4. Fixed a major bug that caused incorrect computation of the amount of memory
    required for a compiled pattern when options that changed within the
    pattern affected the logic of the preliminary scan that determines the
    length. The relevant options are -x, and -i in UTF-8 mode. The result was
    that the computed length was too small. The symptoms of this bug were
    either the PCRE error "internal error: code overflow" from pcre_compile(),
    or a glibc crash with a message such as "pcretest: free(): invalid next
    size (fast)". Examples of patterns that provoked this bug (shown in
    pcretest format) are:

      /(?-x: )/x
      /(?x)(?-x: \s*#\s*)/
      /((?i)[\x{c0}])/8
      /(?i:[\x{c0}])/8

    HOWEVER: Change 17 below makes this fix obsolete as the memory computation
    is now done differently.

 5. Applied patches from Google to: (a) add a QuoteMeta function to the C++
    wrapper classes; (b) implement a new function in the C++ scanner that is
    more efficient than the old way of doing things because it avoids levels of
    recursion in the regex matching; (c) add a paragraph to the documentation
    for the FullMatch() function.

 6. The escape sequence \n was being treated as whatever was defined as
    "newline". Not only was this contrary to the documentation, which states
    that \n is character 10 (hex 0A), but it also went horribly wrong when
    "newline" was defined as CRLF. This has been fixed.

 7. In pcre_dfa_exec.c the value of an unsigned integer (the variable called c)
    was being set to -1 for the "end of line" case (supposedly a value that no
    character can have). Though this value is never used (the check for end of
    line is "zero bytes in current character"), it caused compiler complaints.
    I've changed it to 0xffffffff.

 8. In pcre_version.c, the version string was being built by a sequence of
    C macros that, in the event of PCRE_PRERELEASE being defined as an empty
    string (as it is for production releases) called a macro with an empty
    argument. The C standard says the result of this is undefined. The gcc
    compiler treats it as an empty string (which was what was wanted) but it is
    reported that Visual C gives an error. The source has been hacked around to
    avoid this problem.

 9. On the advice of a Windows user, included <io.h> and <fcntl.h> in Windows
    builds of pcretest, and changed the call to _setmode() to use _O_BINARY
    instead of 0x8000. Made all the #ifdefs test both _WIN32 and WIN32 (not all
    of them did).

10. Originally, pcretest opened its input and output without "b"; then I was
    told that "b" was needed in some environments, so it was added for release
    5.0 to both the input and output. (It makes no difference on Unix-like
    systems.) Later I was told that it is wrong for the input on Windows. I've
    now abstracted the modes into two macros, to make it easier to fiddle with
    them, and removed "b" from the input mode under Windows.

11. Added pkgconfig support for the C++ wrapper library, libpcrecpp.

12. Added -help and --help to pcretest as an official way of being reminded
    of the options.

13. Removed some redundant semicolons after macro calls in pcrecpparg.h.in
    and pcrecpp.cc because they annoy compilers at high warning levels.

14. A bit of tidying/refactoring in pcre_exec.c in the main bumpalong loop.

15. Fixed an occurrence of == in configure.ac that should have been = (shell
    scripts are not C programs :-) and which was not noticed because it works
    on Linux.

16. pcretest is supposed to handle any length of pattern and data line (as one
    line or as a continued sequence of lines) by extending its input buffer if
    necessary. This feature was broken for very long pattern lines, leading to
    a string of junk being passed to pcre_compile() if the pattern was longer
    than about 50K.

17. I have done a major re-factoring of the way pcre_compile() computes the
    amount of memory needed for a compiled pattern. Previously, there was code
    that made a preliminary scan of the pattern in order to do this. That was
    OK when PCRE was new, but as the facilities have expanded, it has become
    harder and harder to keep it in step with the real compile phase, and there
    have been a number of bugs (see for example, 4 above). I have now found a
    cunning way of running the real compile function in a "fake" mode that
    enables it to compute how much memory it would need, while actually only
    ever using a few hundred bytes of working memory and without too many
    tests of the mode. This should make future maintenance and development
    easier. A side effect of this work is that the limit of 200 on the nesting
    depth of parentheses has been removed (though this was never a serious
    limitation, I suspect). However, there is a downside: pcre_compile() now
    runs more slowly than before (30% or more, depending on the pattern). I
    hope this isn't a big issue. There is no effect on runtime performance.

18. Fixed a minor bug in pcretest: if a pattern line was not terminated by a
    newline (only possible for the last line of a file) and it was a
    pattern that set a locale (followed by /Lsomething), pcretest crashed.

19. Added additional timing features to pcretest. (1) The -tm option now times
    matching only, not compiling. (2) Both -t and -tm can be followed, as a
    separate command line item, by a number that specifies the number of
    repeats to use when timing. The default is 50000; this gives better
    precision, but takes uncomfortably long for very large patterns.

20. Extended pcre_study() to be more clever in cases where a branch of a
    subpattern has no definite first character. For example, (a*|b*)[cd] would
    previously give no result from pcre_study(). Now it recognizes that the
    first character must be a, b, c, or d.

21. There was an incorrect error "recursive call could loop indefinitely" if
    a subpattern (or the entire pattern) that was being tested for matching an
    empty string contained only one non-empty item after a nested subpattern.
    For example, the pattern (?>\x{100}*)\d(?R) provoked this error
    incorrectly, because the \d was being skipped in the check.

22. The pcretest program now has a new pattern option /B and a command line
    option -b, which is equivalent to adding /B to every pattern. This causes
    it to show the compiled bytecode, without the additional information that
    -d shows. The effect of -d is now the same as -b with -i (and similarly, /D
    is the same as /B/I).

23. A new optimization is now able automatically to treat some sequences such
    as a*b as a*+b. More specifically, if something simple (such as a character
    or a simple class like \d) has an unlimited quantifier, and is followed by
    something that cannot possibly match the quantified thing, the quantifier
    is automatically "possessified".

24. A recursive reference to a subpattern whose number was greater than 39
    went wrong under certain circumstances in UTF-8 mode. This bug could also
    have affected the operation of pcre_study().

25. Realized that a little bit of performance could be had by replacing
    (c & 0xc0) == 0xc0 with c >= 0xc0 when processing UTF-8 characters.

26. Timing data from pcretest is now shown to 4 decimal places instead of 3.

27. Possessive quantifiers such as a++ were previously implemented by turning
    them into atomic groups such as ($>a+). Now they have their own opcodes,
    which improves performance. This includes the automatically created ones
    from 23 above.

28. A pattern such as (?=(\w+))\1: which simulates an atomic group using a
    lookahead was broken if it was not anchored. PCRE was mistakenly expecting
    the first matched character to be a colon. This applied both to named and
    numbered groups.

29. The ucpinternal.h header file was missing its idempotency #ifdef.

30. I was sent a "project" file called libpcre.a.dev which I understand makes
    building PCRE on Windows easier, so I have included it in the distribution.

31. There is now a check in pcretest against a ridiculously large number being
    returned by pcre_exec() or pcre_dfa_exec(). If this happens in a /g or /G
    loop, the loop is abandoned.

32. Forward references to subpatterns in conditions such as (?(2)...) where
    subpattern 2 is defined later cause pcre_compile() to search forwards in
    the pattern for the relevant set of parentheses. This search went wrong
    when there were unescaped parentheses in a character class, parentheses
    escaped with \Q...\E, or parentheses in a #-comment in /x mode.

33. "Subroutine" calls and backreferences were previously restricted to
    referencing subpatterns earlier in the regex. This restriction has now
    been removed.

34. Added a number of extra features that are going to be in Perl 5.10. On the
    whole, these are just syntactic alternatives for features that PCRE had
    previously implemented using the Python syntax or my own invention. The
    other formats are all retained for compatibility.

    (a) Named groups can now be defined as (?<name>...) or (?'name'...) as well
        as (?P<name>...). The new forms, as well as being in Perl 5.10, are
        also .NET compatible.

    (b) A recursion or subroutine call to a named group can now be defined as
        (?&name) as well as (?P>name).

    (c) A backreference to a named group can now be defined as \k<name> or
        \k'name' as well as (?P=name). The new forms, as well as being in Perl
        5.10, are also .NET compatible.

    (d) A conditional reference to a named group can now use the syntax
        (?(<name>) or (?('name') as well as (?(name).

    (e) A "conditional group" of the form (?(DEFINE)...) can be used to define
        groups (named and numbered) that are never evaluated inline, but can be
        called as "subroutines" from elsewhere. In effect, the DEFINE condition
        is always false. There may be only one alternative in such a group.

    (f) A test for recursion can be given as (?(R1).. or (?(R&name)... as well
        as the simple (?(R). The condition is true only if the most recent
        recursion is that of the given number or name. It does not search out
        through the entire recursion stack.

    (g) The escape \gN or \g{N} has been added, where N is a positive or
        negative number, specifying an absolute or relative reference.

35. Tidied to get rid of some further signed/unsigned compiler warnings and
    some "unreachable code" warnings.

36. Updated the Unicode property tables to Unicode version 5.0.0. Amongst other
    things, this adds five new scripts.

37. Perl ignores orphaned \E escapes completely. PCRE now does the same.
    There were also incompatibilities regarding the handling of \Q..\E inside
    character classes, for example with patterns like [\Qa\E-\Qz\E] where the
    hyphen was adjacent to \Q or \E. I hope I've cleared all this up now.

38. Like Perl, PCRE detects when an indefinitely repeated parenthesized group
    matches an empty string, and forcibly breaks the loop. There were bugs in
    this code in non-simple cases. For a pattern such as  ^(a()*)*  matched
    against  aaaa  the result was just "a" rather than "aaaa", for example. Two
    separate and independent bugs (that affected different cases) have been
    fixed.

39. Refactored the code to abolish the use of different opcodes for small
    capturing bracket numbers. This is a tidy that I avoided doing when I
    removed the limit on the number of capturing brackets for 3.5 back in 2001.
    The new approach is not only tidier, it makes it possible to reduce the
    memory needed to fix the previous bug (38).

40. Implemented PCRE_NEWLINE_ANY to recognize any of the Unicode newline
    sequences (http://unicode.org/unicode/reports/tr18/) as "newline" when
    processing dot, circumflex, or dollar metacharacters, or #-comments in /x
    mode.

41. Add \R to match any Unicode newline sequence, as suggested in the Unicode
    report.

42. Applied patch, originally from Ari Pollak, modified by Google, to allow
    copy construction and assignment in the C++ wrapper.

43. Updated pcregrep to support "--newline=any". In the process, I fixed a
    couple of bugs that could have given wrong results in the "--newline=crlf"
    case.

44. Added a number of casts and did some reorganization of signed/unsigned int
    variables following suggestions from Dair Grant. Also renamed the variable
    "this" as "item" because it is a C++ keyword.

45. Arranged for dftables to add

      #include "pcre_internal.h"

    to pcre_chartables.c because without it, gcc 4.x may remove the array
    definition from the final binary if PCRE is built into a static library and
    dead code stripping is activated.

46. For an unanchored pattern, if a match attempt fails at the start of a
    newline sequence, and the newline setting is CRLF or ANY, and the next two
    characters are CRLF, advance by two characters instead of one.


Version 6.7 04-Jul-06
---------------------

 1. In order to handle tests when input lines are enormously long, pcretest has
    been re-factored so that it automatically extends its buffers when
    necessary. The code is crude, but this _is_ just a test program. The
    default size has been increased from 32K to 50K.

 2. The code in pcre_study() was using the value of the re argument before
    testing it for NULL. (Of course, in any sensible call of the function, it
    won't be NULL.)

 3. The memmove() emulation function in pcre_internal.h, which is used on
    systems that lack both memmove() and bcopy() - that is, hardly ever -
    was missing a "static" storage class specifier.

 4. When UTF-8 mode was not set, PCRE looped when compiling certain patterns
    containing an extended class (one that cannot be represented by a bitmap
    because it contains high-valued characters or Unicode property items, e.g.
    [\pZ]). Almost always one would set UTF-8 mode when processing such a
    pattern, but PCRE should not loop if you do not (it no longer does).
    [Detail: two cases were found: (a) a repeated subpattern containing an
    extended class; (b) a recursive reference to a subpattern that followed a
    previous extended class. It wasn't skipping over the extended class
    correctly when UTF-8 mode was not set.]

 5. A negated single-character class was not being recognized as fixed-length
    in lookbehind assertions such as (?<=[^f]), leading to an incorrect
    compile error "lookbehind assertion is not fixed length".

 6. The RunPerlTest auxiliary script was showing an unexpected difference
    between PCRE and Perl for UTF-8 tests. It turns out that it is hard to
    write a Perl script that can interpret lines of an input file either as
    byte characters or as UTF-8, which is what "perltest" was being required to
    do for the non-UTF-8 and UTF-8 tests, respectively. Essentially what you
    can't do is switch easily at run time between having the "use utf8;" pragma
    or not. In the end, I fudged it by using the RunPerlTest script to insert
    "use utf8;" explicitly for the UTF-8 tests.

 7. In multiline (/m) mode, PCRE was matching ^ after a terminating newline at
    the end of the subject string, contrary to the documentation and to what
    Perl does. This was true of both matching functions. Now it matches only at
    the start of the subject and immediately after *internal* newlines.

 8. A call of pcre_fullinfo() from pcretest to get the option bits was passing
    a pointer to an int instead of a pointer to an unsigned long int. This
    caused problems on 64-bit systems.

 9. Applied a patch from the folks at Google to pcrecpp.cc, to fix "another
    instance of the 'standard' template library not being so standard".

10. There was no check on the number of named subpatterns nor the maximum
    length of a subpattern name. The product of these values is used to compute
    the size of the memory block for a compiled pattern. By supplying a very
    long subpattern name and a large number of named subpatterns, the size
    computation could be caused to overflow. This is now prevented by limiting
    the length of names to 32 characters, and the number of named subpatterns
    to 10,000.

11. Subpatterns that are repeated with specific counts have to be replicated in
    the compiled pattern. The size of memory for this was computed from the
    length of the subpattern and the repeat count. The latter is limited to
    65535, but there was no limit on the former, meaning that integer overflow
    could in principle occur. The compiled length of a repeated subpattern is
    now limited to 30,000 bytes in order to prevent this.

12. Added the optional facility to have named substrings with the same name.

13. Added the ability to use a named substring as a condition, using the
    Python syntax: (?(name)yes|no). This overloads (?(R)... and names that
    are numbers (not recommended). Forward references are permitted.

14. Added forward references in named backreferences (if you see what I mean).

15. In UTF-8 mode, with the PCRE_DOTALL option set, a quantified dot in the
    pattern could run off the end of the subject. For example, the pattern
    "(?s)(.{1,5})"8 did this with the subject "ab".

16. If PCRE_DOTALL or PCRE_MULTILINE were set, pcre_dfa_exec() behaved as if
    PCRE_CASELESS was set when matching characters that were quantified with ?
    or *.

17. A character class other than a single negated character that had a minimum
    but no maximum quantifier - for example [ab]{6,} - was not handled
    correctly by pce_dfa_exec(). It would match only one character.

18. A valid (though odd) pattern that looked like a POSIX character
    class but used an invalid character after [ (for example [[,abc,]]) caused
    pcre_compile() to give the error "Failed: internal error: code overflow" or
    in some cases to crash with a glibc free() error. This could even happen if
    the pattern terminated after [[ but there just happened to be a sequence of
    letters, a binary zero, and a closing ] in the memory that followed.

19. Perl's treatment of octal escapes in the range \400 to \777 has changed
    over the years. Originally (before any Unicode support), just the bottom 8
    bits were taken. Thus, for example, \500 really meant \100. Nowadays the
    output from "man perlunicode" includes this:

      The regular expression compiler produces polymorphic opcodes.  That
      is, the pattern adapts to the data and automatically switches to
      the Unicode character scheme when presented with Unicode data--or
      instead uses a traditional byte scheme when presented with byte
      data.

    Sadly, a wide octal escape does not cause a switch, and in a string with
    no other multibyte characters, these octal escapes are treated as before.
    Thus, in Perl, the pattern  /\500/ actually matches \100 but the pattern
    /\500|\x{1ff}/ matches \500 or \777 because the whole thing is treated as a
    Unicode string.

    I have not perpetrated such confusion in PCRE. Up till now, it took just
    the bottom 8 bits, as in old Perl. I have now made octal escapes with
    values greater than \377 illegal in non-UTF-8 mode. In UTF-8 mode they
    translate to the appropriate multibyte character.

29. Applied some refactoring to reduce the number of warnings from Microsoft
    and Borland compilers. This has included removing the fudge introduced
    seven years ago for the OS/2 compiler (see 2.02/2 below) because it caused
    a warning about an unused variable.

21. PCRE has not included VT (character 0x0b) in the set of whitespace
    characters since release 4.0, because Perl (from release 5.004) does not.
    [Or at least, is documented not to: some releases seem to be in conflict
    with the documentation.] However, when a pattern was studied with
    pcre_study() and all its branches started with \s, PCRE still included VT
    as a possible starting character. Of course, this did no harm; it just
    caused an unnecessary match attempt.

22. Removed a now-redundant internal flag bit that recorded the fact that case
    dependency changed within the pattern. This was once needed for "required
    byte" processing, but is no longer used. This recovers a now-scarce options
    bit. Also moved the least significant internal flag bit to the most-
    significant bit of the word, which was not previously used (hangover from
    the days when it was an int rather than a uint) to free up another bit for
    the future.

23. Added support for CRLF line endings as well as CR and LF. As well as the
    default being selectable at build time, it can now be changed at runtime
    via the PCRE_NEWLINE_xxx flags. There are now options for pcregrep to
    specify that it is scanning data with non-default line endings.

24. Changed the definition of CXXLINK to make it agree with the definition of
    LINK in the Makefile, by replacing LDFLAGS to CXXFLAGS.

25. Applied Ian Taylor's patches to avoid using another stack frame for tail
    recursions. This makes a big different to stack usage for some patterns.

26. If a subpattern containing a named recursion or subroutine reference such
    as (?P>B) was quantified, for example (xxx(?P>B)){3}, the calculation of
    the space required for the compiled pattern went wrong and gave too small a
    value. Depending on the environment, this could lead to "Failed: internal
    error: code overflow at offset 49" or "glibc detected double free or
    corruption" errors.

27. Applied patches from Google (a) to support the new newline modes and (b) to
    advance over multibyte UTF-8 characters in GlobalReplace.

28. Change free() to pcre_free() in pcredemo.c. Apparently this makes a
    difference for some implementation of PCRE in some Windows version.

29. Added some extra testing facilities to pcretest:

    \q<number>   in a data line sets the "match limit" value
    \Q<number>   in a data line sets the "match recursion limt" value
    -S <number>  sets the stack size, where <number> is in megabytes

    The -S option isn't available for Windows.


Version 6.6 06-Feb-06
---------------------

 1. Change 16(a) for 6.5 broke things, because PCRE_DATA_SCOPE was not defined
    in pcreposix.h. I have copied the definition from pcre.h.

 2. Change 25 for 6.5 broke compilation in a build directory out-of-tree
    because pcre.h is no longer a built file.

 3. Added Jeff Friedl's additional debugging patches to pcregrep. These are
    not normally included in the compiled code.


Version 6.5 01-Feb-06
---------------------

 1. When using the partial match feature with pcre_dfa_exec(), it was not
    anchoring the second and subsequent partial matches at the new starting
    point. This could lead to incorrect results. For example, with the pattern
    /1234/, partially matching against "123" and then "a4" gave a match.

 2. Changes to pcregrep:

    (a) All non-match returns from pcre_exec() were being treated as failures
        to match the line. Now, unless the error is PCRE_ERROR_NOMATCH, an
        error message is output. Some extra information is given for the
        PCRE_ERROR_MATCHLIMIT and PCRE_ERROR_RECURSIONLIMIT errors, which are
        probably the only errors that are likely to be caused by users (by
        specifying a regex that has nested indefinite repeats, for instance).
        If there are more than 20 of these errors, pcregrep is abandoned.

    (b) A binary zero was treated as data while matching, but terminated the
        output line if it was written out. This has been fixed: binary zeroes
        are now no different to any other data bytes.

    (c) Whichever of the LC_ALL or LC_CTYPE environment variables is set is
        used to set a locale for matching. The --locale=xxxx long option has
        been added (no short equivalent) to specify a locale explicitly on the
        pcregrep command, overriding the environment variables.

    (d) When -B was used with -n, some line numbers in the output were one less
        than they should have been.

    (e) Added the -o (--only-matching) option.

    (f) If -A or -C was used with -c (count only), some lines of context were
        accidentally printed for the final match.

    (g) Added the -H (--with-filename) option.

    (h) The combination of options -rh failed to suppress file names for files
        that were found from directory arguments.

    (i) Added the -D (--devices) and -d (--directories) options.

    (j) Added the -F (--fixed-strings) option.

    (k) Allow "-" to be used as a file name for -f as well as for a data file.

    (l) Added the --colo(u)r option.

    (m) Added Jeffrey Friedl's -S testing option, but within #ifdefs so that it
        is not present by default.

 3. A nasty bug was discovered in the handling of recursive patterns, that is,
    items such as (?R) or (?1), when the recursion could match a number of
    alternatives. If it matched one of the alternatives, but subsequently,
    outside the recursion, there was a failure, the code tried to back up into
    the recursion. However, because of the way PCRE is implemented, this is not
    possible, and the result was an incorrect result from the match.

    In order to prevent this happening, the specification of recursion has
    been changed so that all such subpatterns are automatically treated as
    atomic groups. Thus, for example, (?R) is treated as if it were (?>(?R)).

 4. I had overlooked the fact that, in some locales, there are characters for
    which isalpha() is true but neither isupper() nor islower() are true. In
    the fr_FR locale, for instance, the \xAA and \xBA characters (ordmasculine
    and ordfeminine) are like this. This affected the treatment of \w and \W
    when they appeared in character classes, but not when they appeared outside
    a character class. The bit map for "word" characters is now created
    separately from the results of isalnum() instead of just taking it from the
    upper, lower, and digit maps. (Plus the underscore character, of course.)

 5. The above bug also affected the handling of POSIX character classes such as
    [[:alpha:]] and [[:alnum:]]. These do not have their own bit maps in PCRE's
    permanent tables. Instead, the bit maps for such a class were previously
    created as the appropriate unions of the upper, lower, and digit bitmaps.
    Now they are created by subtraction from the [[:word:]] class, which has
    its own bitmap.

 6. The [[:blank:]] character class matches horizontal, but not vertical space.
    It is created by subtracting the vertical space characters (\x09, \x0a,
    \x0b, \x0c) from the [[:space:]] bitmap. Previously, however, the
    subtraction was done in the overall bitmap for a character class, meaning
    that a class such as [\x0c[:blank:]] was incorrect because \x0c would not
    be recognized. This bug has been fixed.

 7. Patches from the folks at Google:

      (a) pcrecpp.cc: "to handle a corner case that may or may not happen in
      real life, but is still worth protecting against".

      (b) pcrecpp.cc: "corrects a bug when negative radixes are used with
      regular expressions".

      (c) pcre_scanner.cc: avoid use of std::count() because not all systems
      have it.

      (d) Split off pcrecpparg.h from pcrecpp.h and had the former built by
      "configure" and the latter not, in order to fix a problem somebody had
      with compiling the Arg class on HP-UX.

      (e) Improve the error-handling of the C++ wrapper a little bit.

      (f) New tests for checking recursion limiting.

 8. The pcre_memmove() function, which is used only if the environment does not
    have a standard memmove() function (and is therefore rarely compiled),
    contained two bugs: (a) use of int instead of size_t, and (b) it was not
    returning a result (though PCRE never actually uses the result).

 9. In the POSIX regexec() interface, if nmatch is specified as a ridiculously
    large number - greater than INT_MAX/(3*sizeof(int)) - REG_ESPACE is
    returned instead of calling malloc() with an overflowing number that would
    most likely cause subsequent chaos.

10. The debugging option of pcretest was not showing the NO_AUTO_CAPTURE flag.

11. The POSIX flag REG_NOSUB is now supported. When a pattern that was compiled
    with this option is matched, the nmatch and pmatch options of regexec() are
    ignored.

12. Added REG_UTF8 to the POSIX interface. This is not defined by POSIX, but is
    provided in case anyone wants to the the POSIX interface with UTF-8
    strings.

13. Added CXXLDFLAGS to the Makefile parameters to provide settings only on the
    C++ linking (needed for some HP-UX environments).

14. Avoid compiler warnings in get_ucpname() when compiled without UCP support
    (unused parameter) and in the pcre_printint() function (omitted "default"
    switch label when the default is to do nothing).

15. Added some code to make it possible, when PCRE is compiled as a C++
    library, to replace subject pointers for pcre_exec() with a smart pointer
    class, thus making it possible to process discontinuous strings.

16. The two macros PCRE_EXPORT and PCRE_DATA_SCOPE are confusing, and perform
    much the same function. They were added by different people who were trying
    to make PCRE easy to compile on non-Unix systems. It has been suggested
    that PCRE_EXPORT be abolished now that there is more automatic apparatus
    for compiling on Windows systems. I have therefore replaced it with
    PCRE_DATA_SCOPE. This is set automatically for Windows; if not set it
    defaults to "extern" for C or "extern C" for C++, which works fine on
    Unix-like systems. It is now possible to override the value of PCRE_DATA_
    SCOPE with something explicit in config.h. In addition:

    (a) pcreposix.h still had just "extern" instead of either of these macros;
        I have replaced it with PCRE_DATA_SCOPE.

    (b) Functions such as _pcre_xclass(), which are internal to the library,
        but external in the C sense, all had PCRE_EXPORT in their definitions.
        This is apparently wrong for the Windows case, so I have removed it.
        (It makes no difference on Unix-like systems.)

17. Added a new limit, MATCH_LIMIT_RECURSION, which limits the depth of nesting
    of recursive calls to match(). This is different to MATCH_LIMIT because
    that limits the total number of calls to match(), not all of which increase
    the depth of recursion. Limiting the recursion depth limits the amount of
    stack (or heap if NO_RECURSE is set) that is used. The default can be set
    when PCRE is compiled, and changed at run time. A patch from Google adds
    this functionality to the C++ interface.

18. Changes to the handling of Unicode character properties:

    (a) Updated the table to Unicode 4.1.0.

    (b) Recognize characters that are not in the table as "Cn" (undefined).

    (c) I revised the way the table is implemented to a much improved format
        which includes recognition of ranges. It now supports the ranges that
        are defined in UnicodeData.txt, and it also amalgamates other
        characters into ranges. This has reduced the number of entries in the
        table from around 16,000 to around 3,000, thus reducing its size
        considerably. I realized I did not need to use a tree structure after
        all - a binary chop search is just as efficient. Having reduced the
        number of entries, I extended their size from 6 bytes to 8 bytes to
        allow for more data.

    (d) Added support for Unicode script names via properties such as \p{Han}.

19. In UTF-8 mode, a backslash followed by a non-Ascii character was not
    matching that character.

20. When matching a repeated Unicode property with a minimum greater than zero,
    (for example \pL{2,}), PCRE could look past the end of the subject if it
    reached it while seeking the minimum number of characters. This could
    happen only if some of the characters were more than one byte long, because
    there is a check for at least the minimum number of bytes.

21. Refactored the implementation of \p and \P so as to be more general, to
    allow for more different types of property in future. This has changed the
    compiled form incompatibly. Anybody with saved compiled patterns that use
    \p or \P will have to recompile them.

22. Added "Any" and "L&" to the supported property types.

23. Recognize \x{...} as a code point specifier, even when not in UTF-8 mode,
    but give a compile time error if the value is greater than 0xff.

24. The man pages for pcrepartial, pcreprecompile, and pcre_compile2 were
    accidentally not being installed or uninstalled.

25. The pcre.h file was built from pcre.h.in, but the only changes that were
    made were to insert the current release number. This seemed silly, because
    it made things harder for people building PCRE on systems that don't run
    "configure". I have turned pcre.h into a distributed file, no longer built
    by "configure", with the version identification directly included. There is
    no longer a pcre.h.in file.

    However, this change necessitated a change to the pcre-config script as
    well. It is built from pcre-config.in, and one of the substitutions was the
    release number. I have updated configure.ac so that ./configure now finds
    the release number by grepping pcre.h.

26. Added the ability to run the tests under valgrind.


Version 6.4 05-Sep-05
---------------------

 1. Change 6.0/10/(l) to pcregrep introduced a bug that caused separator lines
    "--" to be printed when multiple files were scanned, even when none of the
    -A, -B, or -C options were used. This is not compatible with Gnu grep, so I
    consider it to be a bug, and have restored the previous behaviour.

 2. A couple of code tidies to get rid of compiler warnings.

 3. The pcretest program used to cheat by referring to symbols in the library
    whose names begin with _pcre_. These are internal symbols that are not
    really supposed to be visible externally, and in some environments it is
    possible to suppress them. The cheating is now confined to including
    certain files from the library's source, which is a bit cleaner.

 4. Renamed pcre.in as pcre.h.in to go with pcrecpp.h.in; it also makes the
    file's purpose clearer.

 5. Reorganized pcre_ucp_findchar().


Version 6.3 15-Aug-05
---------------------

 1. The file libpcre.pc.in did not have general read permission in the tarball.

 2. There were some problems when building without C++ support:

    (a) If C++ support was not built, "make install" and "make test" still
        tried to test it.

    (b) There were problems when the value of CXX was explicitly set. Some
        changes have been made to try to fix these, and ...

    (c) --disable-cpp can now be used to explicitly disable C++ support.

    (d) The use of @CPP_OBJ@ directly caused a blank line preceded by a
        backslash in a target when C++ was disabled. This confuses some
        versions of "make", apparently. Using an intermediate variable solves
        this. (Same for CPP_LOBJ.)

 3. $(LINK_FOR_BUILD) now includes $(CFLAGS_FOR_BUILD) and $(LINK)
    (non-Windows) now includes $(CFLAGS) because these flags are sometimes
    necessary on certain architectures.

 4. Added a setting of -export-symbols-regex to the link command to remove
    those symbols that are exported in the C sense, but actually are local
    within the library, and not documented. Their names all begin with
    "_pcre_". This is not a perfect job, because (a) we have to except some
    symbols that pcretest ("illegally") uses, and (b) the facility isn't always
    available (and never for static libraries). I have made a note to try to
    find a way round (a) in the future.


Version 6.2 01-Aug-05
---------------------

 1. There was no test for integer overflow of quantifier values. A construction
    such as {1111111111111111} would give undefined results. What is worse, if
    a minimum quantifier for a parenthesized subpattern overflowed and became
    negative, the calculation of the memory size went wrong. This could have
    led to memory overwriting.

 2. Building PCRE using VPATH was broken. Hopefully it is now fixed.

 3. Added "b" to the 2nd argument of fopen() in dftables.c, for non-Unix-like
    operating environments where this matters.

 4. Applied Giuseppe Maxia's patch to add additional features for controlling
    PCRE options from within the C++ wrapper.

 5. Named capturing subpatterns were not being correctly counted when a pattern
    was compiled. This caused two problems: (a) If there were more than 100
    such subpatterns, the calculation of the memory needed for the whole
    compiled pattern went wrong, leading to an overflow error. (b) Numerical
    back references of the form \12, where the number was greater than 9, were
    not recognized as back references, even though there were sufficient
    previous subpatterns.

 6. Two minor patches to pcrecpp.cc in order to allow it to compile on older
    versions of gcc, e.g. 2.95.4.


Version 6.1 21-Jun-05
---------------------

 1. There was one reference to the variable "posix" in pcretest.c that was not
    surrounded by "#if !defined NOPOSIX".

 2. Make it possible to compile pcretest without DFA support, UTF8 support, or
    the cross-check on the old pcre_info() function, for the benefit of the
    cut-down version of PCRE that is currently imported into Exim.

 3. A (silly) pattern starting with (?i)(?-i) caused an internal space
    allocation error. I've done the easy fix, which wastes 2 bytes for sensible
    patterns that start (?i) but I don't think that matters. The use of (?i) is
    just an example; this all applies to the other options as well.

 4. Since libtool seems to echo the compile commands it is issuing, the output
    from "make" can be reduced a bit by putting "@" in front of each libtool
    compile command.

 5. Patch from the folks at Google for configure.in to be a bit more thorough
    in checking for a suitable C++ installation before trying to compile the
    C++ stuff. This should fix a reported problem when a compiler was present,
    but no suitable headers.

 6. The man pages all had just "PCRE" as their title. I have changed them to
    be the relevant file name. I have also arranged that these names are
    retained in the file doc/pcre.txt, which is a concatenation in text format
    of all the man pages except the little individual ones for each function.

 7. The NON-UNIX-USE file had not been updated for the different set of source
    files that come with release 6. I also added a few comments about the C++
    wrapper.


Version 6.0 07-Jun-05
---------------------

 1. Some minor internal re-organization to help with my DFA experiments.

 2. Some missing #ifdef SUPPORT_UCP conditionals in pcretest and printint that
    didn't matter for the library itself when fully configured, but did matter
    when compiling without UCP support, or within Exim, where the ucp files are
    not imported.

 3. Refactoring of the library code to split up the various functions into
    different source modules. The addition of the new DFA matching code (see
    below) to a single monolithic source would have made it really too
    unwieldy, quite apart from causing all the code to be include in a
    statically linked application, when only some functions are used. This is
    relevant even without the DFA addition now that patterns can be compiled in
    one application and matched in another.

    The downside of splitting up is that there have to be some external
    functions and data tables that are used internally in different modules of
    the library but which are not part of the API. These have all had their
    names changed to start with "_pcre_" so that they are unlikely to clash
    with other external names.

 4. Added an alternate matching function, pcre_dfa_exec(), which matches using
    a different (DFA) algorithm. Although it is slower than the original
    function, it does have some advantages for certain types of matching
    problem.

 5. Upgrades to pcretest in order to test the features of pcre_dfa_exec(),
    including restarting after a partial match.

 6. A patch for pcregrep that defines INVALID_FILE_ATTRIBUTES if it is not
    defined when compiling for Windows was sent to me. I have put it into the
    code, though I have no means of testing or verifying it.

 7. Added the pcre_refcount() auxiliary function.

 8. Added the PCRE_FIRSTLINE option. This constrains an unanchored pattern to
    match before or at the first newline in the subject string. In pcretest,
    the /f option on a pattern can be used to set this.

 9. A repeated \w when used in UTF-8 mode with characters greater than 256
    would behave wrongly. This has been present in PCRE since release 4.0.

10. A number of changes to the pcregrep command:

    (a) Refactored how -x works; insert ^(...)$ instead of setting
        PCRE_ANCHORED and checking the length, in preparation for adding
        something similar for -w.

    (b) Added the -w (match as a word) option.

    (c) Refactored the way lines are read and buffered so as to have more
        than one at a time available.

    (d) Implemented a pcregrep test script.

    (e) Added the -M (multiline match) option. This allows patterns to match
        over several lines of the subject. The buffering ensures that at least
        8K, or the rest of the document (whichever is the shorter) is available
        for matching (and similarly the previous 8K for lookbehind assertions).

    (f) Changed the --help output so that it now says

          -w, --word-regex(p)

        instead of two lines, one with "regex" and the other with "regexp"
        because that confused at least one person since the short forms are the
        same. (This required a bit of code, as the output is generated
        automatically from a table. It wasn't just a text change.)

    (g) -- can be used to terminate pcregrep options if the next thing isn't an
        option but starts with a hyphen. Could be a pattern or a path name
        starting with a hyphen, for instance.

    (h) "-" can be given as a file name to represent stdin.

    (i) When file names are being printed, "(standard input)" is used for
        the standard input, for compatibility with GNU grep. Previously
        "<stdin>" was used.

    (j) The option --label=xxx can be used to supply a name to be used for
        stdin when file names are being printed. There is no short form.

    (k) Re-factored the options decoding logic because we are going to add
        two more options that take data. Such options can now be given in four
        different ways, e.g. "-fname", "-f name", "--file=name", "--file name".

    (l) Added the -A, -B, and -C options for requesting that lines of context
        around matches be printed.

    (m) Added the -L option to print the names of files that do not contain
        any matching lines, that is, the complement of -l.

    (n) The return code is 2 if any file cannot be opened, but pcregrep does
        continue to scan other files.

    (o) The -s option was incorrectly implemented. For compatibility with other
        greps, it now suppresses the error message for a non-existent or non-
        accessible file (but not the return code). There is a new option called
        -q that suppresses the output of matching lines, which was what -s was
        previously doing.

    (p) Added --include and --exclude options to specify files for inclusion
        and exclusion when recursing.

11. The Makefile was not using the Autoconf-supported LDFLAGS macro properly.
    Hopefully, it now does.

12. Missing cast in pcre_study().

13. Added an "uninstall" target to the makefile.

14. Replaced "extern" in the function prototypes in Makefile.in with
    "PCRE_DATA_SCOPE", which defaults to 'extern' or 'extern "C"' in the Unix
    world, but is set differently for Windows.

15. Added a second compiling function called pcre_compile2(). The only
    difference is that it has an extra argument, which is a pointer to an
    integer error code. When there is a compile-time failure, this is set
    non-zero, in addition to the error test pointer being set to point to an
    error message. The new argument may be NULL if no error number is required
    (but then you may as well call pcre_compile(), which is now just a
    wrapper). This facility is provided because some applications need a
    numeric error indication, but it has also enabled me to tidy up the way
    compile-time errors are handled in the POSIX wrapper.

16. Added VPATH=.libs to the makefile; this should help when building with one
    prefix path and installing with another. (Or so I'm told by someone who
    knows more about this stuff than I do.)

17. Added a new option, REG_DOTALL, to the POSIX function regcomp(). This
    passes PCRE_DOTALL to the pcre_compile() function, making the "." character
    match everything, including newlines. This is not POSIX-compatible, but
    somebody wanted the feature. From pcretest it can be activated by using
    both the P and the s flags.

18. AC_PROG_LIBTOOL appeared twice in Makefile.in. Removed one.

19. libpcre.pc was being incorrectly installed as executable.

20. A couple of places in pcretest check for end-of-line by looking for '\n';
    it now also looks for '\r' so that it will work unmodified on Windows.

21. Added Google's contributed C++ wrapper to the distribution.

22. Added some untidy missing memory free() calls in pcretest, to keep
    Electric Fence happy when testing.



Version 5.0 13-Sep-04
---------------------

 1. Internal change: literal characters are no longer packed up into items
    containing multiple characters in a single byte-string. Each character
    is now matched using a separate opcode. However, there may be more than one
    byte in the character in UTF-8 mode.

 2. The pcre_callout_block structure has two new fields: pattern_position and
    next_item_length. These contain the offset in the pattern to the next match
    item, and its length, respectively.

 3. The PCRE_AUTO_CALLOUT option for pcre_compile() requests the automatic
    insertion of callouts before each pattern item. Added the /C option to
    pcretest to make use of this.

 4. On the advice of a Windows user, the lines

      #if defined(_WIN32) || defined(WIN32)
      _setmode( _fileno( stdout ), 0x8000 );
      #endif  /* defined(_WIN32) || defined(WIN32) */

    have been added to the source of pcretest. This apparently does useful
    magic in relation to line terminators.

 5. Changed "r" and "w" in the calls to fopen() in pcretest to "rb" and "wb"
    for the benefit of those environments where the "b" makes a difference.

 6. The icc compiler has the same options as gcc, but "configure" doesn't seem
    to know about it. I have put a hack into configure.in that adds in code
    to set GCC=yes if CC=icc. This seems to end up at a point in the
    generated configure script that is early enough to affect the setting of
    compiler options, which is what is needed, but I have no means of testing
    whether it really works. (The user who reported this had patched the
    generated configure script, which of course I cannot do.)

    LATER: After change 22 below (new libtool files), the configure script
    seems to know about icc (and also ecc). Therefore, I have commented out
    this hack in configure.in.

 7. Added support for pkg-config (2 patches were sent in).

 8. Negated POSIX character classes that used a combination of internal tables
    were completely broken. These were [[:^alpha:]], [[:^alnum:]], and
    [[:^ascii]]. Typically, they would match almost any characters. The other
    POSIX classes were not broken in this way.

 9. Matching the pattern "\b.*?" against "ab cd", starting at offset 1, failed
    to find the match, as PCRE was deluded into thinking that the match had to
    start at the start point or following a newline. The same bug applied to
    patterns with negative forward assertions or any backward assertions
    preceding ".*" at the start, unless the pattern required a fixed first
    character. This was a failing pattern: "(?!.bcd).*". The bug is now fixed.

10. In UTF-8 mode, when moving forwards in the subject after a failed match
    starting at the last subject character, bytes beyond the end of the subject
    string were read.

11. Renamed the variable "class" as "classbits" to make life easier for C++
    users. (Previously there was a macro definition, but it apparently wasn't
    enough.)

12. Added the new field "tables" to the extra data so that tables can be passed
    in at exec time, or the internal tables can be re-selected. This allows
    a compiled regex to be saved and re-used at a later time by a different
    program that might have everything at different addresses.

13. Modified the pcre-config script so that, when run on Solaris, it shows a
    -R library as well as a -L library.

14. The debugging options of pcretest (-d on the command line or D on a
    pattern) showed incorrect output for anything following an extended class
    that contained multibyte characters and which was followed by a quantifier.

15. Added optional support for general category Unicode character properties
    via the \p, \P, and \X escapes. Unicode property support implies UTF-8
    support. It adds about 90K to the size of the library. The meanings of the
    inbuilt class escapes such as \d and \s have NOT been changed.

16. Updated pcredemo.c to include calls to free() to release the memory for the
    compiled pattern.

17. The generated file chartables.c was being created in the source directory
    instead of in the building directory. This caused the build to fail if the
    source directory was different from the building directory, and was
    read-only.

18. Added some sample Win commands from Mark Tetrode into the NON-UNIX-USE
    file. No doubt somebody will tell me if they don't make sense... Also added
    Dan Mooney's comments about building on OpenVMS.

19. Added support for partial matching via the PCRE_PARTIAL option for
    pcre_exec() and the \P data escape in pcretest.

20. Extended pcretest with 3 new pattern features:

    (i)   A pattern option of the form ">rest-of-line" causes pcretest to
          write the compiled pattern to the file whose name is "rest-of-line".
          This is a straight binary dump of the data, with the saved pointer to
          the character tables forced to be NULL. The study data, if any, is
          written too. After writing, pcretest reads a new pattern.

    (ii)  If, instead of a pattern, "<rest-of-line" is given, pcretest reads a
          compiled pattern from the given file. There must not be any
          occurrences of "<" in the file name (pretty unlikely); if there are,
          pcretest will instead treat the initial "<" as a pattern delimiter.
          After reading in the pattern, pcretest goes on to read data lines as
          usual.

    (iii) The F pattern option causes pcretest to flip the bytes in the 32-bit
          and 16-bit fields in a compiled pattern, to simulate a pattern that
          was compiled on a host of opposite endianness.

21. The pcre-exec() function can now cope with patterns that were compiled on
    hosts of opposite endianness, with this restriction:

      As for any compiled expression that is saved and used later, the tables
      pointer field cannot be preserved; the extra_data field in the arguments
      to pcre_exec() should be used to pass in a tables address if a value
      other than the default internal tables were used at compile time.

22. Calling pcre_exec() with a negative value of the "ovecsize" parameter is
    now diagnosed as an error. Previously, most of the time, a negative number
    would have been treated as zero, but if in addition "ovector" was passed as
    NULL, a crash could occur.

23. Updated the files ltmain.sh, config.sub, config.guess, and aclocal.m4 with
    new versions from the libtool 1.5 distribution (the last one is a copy of
    a file called libtool.m4). This seems to have fixed the need to patch
    "configure" to support Darwin 1.3 (which I used to do). However, I still
    had to patch ltmain.sh to ensure that ${SED} is set (it isn't on my
    workstation).

24. Changed the PCRE licence to be the more standard "BSD" licence.


Version 4.5 01-Dec-03
---------------------

 1. There has been some re-arrangement of the code for the match() function so
    that it can be compiled in a version that does not call itself recursively.
    Instead, it keeps those local variables that need separate instances for
    each "recursion" in a frame on the heap, and gets/frees frames whenever it
    needs to "recurse". Keeping track of where control must go is done by means
    of setjmp/longjmp. The whole thing is implemented by a set of macros that
    hide most of the details from the main code, and operates only if
    NO_RECURSE is defined while compiling pcre.c. If PCRE is built using the
    "configure" mechanism, "--disable-stack-for-recursion" turns on this way of
    operating.

    To make it easier for callers to provide specially tailored get/free
    functions for this usage, two new functions, pcre_stack_malloc, and
    pcre_stack_free, are used. They are always called in strict stacking order,
    and the size of block requested is always the same.

    The PCRE_CONFIG_STACKRECURSE info parameter can be used to find out whether
    PCRE has been compiled to use the stack or the heap for recursion. The
    -C option of pcretest uses this to show which version is compiled.

    A new data escape \S, is added to pcretest; it causes the amounts of store
    obtained and freed by both kinds of malloc/free at match time to be added
    to the output.

 2. Changed the locale test to use "fr_FR" instead of "fr" because that's
    what's available on my current Linux desktop machine.

 3. When matching a UTF-8 string, the test for a valid string at the start has
    been extended. If start_offset is not zero, PCRE now checks that it points
    to a byte that is the start of a UTF-8 character. If not, it returns
    PCRE_ERROR_BADUTF8_OFFSET (-11). Note: the whole string is still checked;
    this is necessary because there may be backward assertions in the pattern.
    When matching the same subject several times, it may save resources to use
    PCRE_NO_UTF8_CHECK on all but the first call if the string is long.

 4. The code for checking the validity of UTF-8 strings has been tightened so
    that it rejects (a) strings containing 0xfe or 0xff bytes and (b) strings
    containing "overlong sequences".

 5. Fixed a bug (appearing twice) that I could not find any way of exploiting!
    I had written "if ((digitab[*p++] && chtab_digit) == 0)" where the "&&"
    should have been "&", but it just so happened that all the cases this let
    through by mistake were picked up later in the function.

 6. I had used a variable called "isblank" - this is a C99 function, causing
    some compilers to warn. To avoid this, I renamed it (as "blankclass").

 7. Cosmetic: (a) only output another newline at the end of pcretest if it is
    prompting; (b) run "./pcretest /dev/null" at the start of the test script
    so the version is shown; (c) stop "make test" echoing "./RunTest".

 8. Added patches from David Burgess to enable PCRE to run on EBCDIC systems.

 9. The prototype for memmove() for systems that don't have it was using
    size_t, but the inclusion of the header that defines size_t was later. I've
    moved the #includes for the C headers earlier to avoid this.

10. Added some adjustments to the code to make it easier to compiler on certain
    special systems:

      (a) Some "const" qualifiers were missing.
      (b) Added the macro EXPORT before all exported functions; by default this
          is defined to be empty.
      (c) Changed the dftables auxiliary program (that builds chartables.c) so
          that it reads its output file name as an argument instead of writing
          to the standard output and assuming this can be redirected.

11. In UTF-8 mode, if a recursive reference (e.g. (?1)) followed a character
    class containing characters with values greater than 255, PCRE compilation
    went into a loop.

12. A recursive reference to a subpattern that was within another subpattern
    that had a minimum quantifier of zero caused PCRE to crash. For example,
    (x(y(?2))z)? provoked this bug with a subject that got as far as the
    recursion. If the recursively-called subpattern itself had a zero repeat,
    that was OK.

13. In pcretest, the buffer for reading a data line was set at 30K, but the
    buffer into which it was copied (for escape processing) was still set at
    1024, so long lines caused crashes.

14. A pattern such as /[ab]{1,3}+/ failed to compile, giving the error
    "internal error: code overflow...". This applied to any character class
    that was followed by a possessive quantifier.

15. Modified the Makefile to add libpcre.la as a prerequisite for
    libpcreposix.la because I was told this is needed for a parallel build to
    work.

16. If a pattern that contained .* following optional items at the start was
    studied, the wrong optimizing data was generated, leading to matching
    errors. For example, studying /[ab]*.*c/ concluded, erroneously, that any
    matching string must start with a or b or c. The correct conclusion for
    this pattern is that a match can start with any character.


Version 4.4 13-Aug-03
---------------------

 1. In UTF-8 mode, a character class containing characters with values between
    127 and 255 was not handled correctly if the compiled pattern was studied.
    In fixing this, I have also improved the studying algorithm for such
    classes (slightly).

 2. Three internal functions had redundant arguments passed to them. Removal
    might give a very teeny performance improvement.

 3. Documentation bug: the value of the capture_top field in a callout is *one
    more than* the number of the hightest numbered captured substring.

 4. The Makefile linked pcretest and pcregrep with -lpcre, which could result
    in incorrectly linking with a previously installed version. They now link
    explicitly with libpcre.la.

 5. configure.in no longer needs to recognize Cygwin specially.

 6. A problem in pcre.in for Windows platforms is fixed.

 7. If a pattern was successfully studied, and the -d (or /D) flag was given to
    pcretest, it used to include the size of the study block as part of its
    output. Unfortunately, the structure contains a field that has a different
    size on different hardware architectures. This meant that the tests that
    showed this size failed. As the block is currently always of a fixed size,
    this information isn't actually particularly useful in pcretest output, so
    I have just removed it.

 8. Three pre-processor statements accidentally did not start in column 1.
    Sadly, there are *still* compilers around that complain, even though
    standard C has not required this for well over a decade. Sigh.

 9. In pcretest, the code for checking callouts passed small integers in the
    callout_data field, which is a void * field. However, some picky compilers
    complained about the casts involved for this on 64-bit systems. Now
    pcretest passes the address of the small integer instead, which should get
    rid of the warnings.

10. By default, when in UTF-8 mode, PCRE now checks for valid UTF-8 strings at
    both compile and run time, and gives an error if an invalid UTF-8 sequence
    is found. There is a option for disabling this check in cases where the
    string is known to be correct and/or the maximum performance is wanted.

11. In response to a bug report, I changed one line in Makefile.in from

        -Wl,--out-implib,.libs/lib@WIN_PREFIX@pcreposix.dll.a \
    to
        -Wl,--out-implib,.libs/@WIN_PREFIX@libpcreposix.dll.a \

    to look similar to other lines, but I have no way of telling whether this
    is the right thing to do, as I do not use Windows. No doubt I'll get told
    if it's wrong...


Version 4.3 21-May-03
---------------------

1. Two instances of @WIN_PREFIX@ omitted from the Windows targets in the
   Makefile.

2. Some refactoring to improve the quality of the code:

   (i)   The utf8_table... variables are now declared "const".

   (ii)  The code for \cx, which used the "case flipping" table to upper case
         lower case letters, now just substracts 32. This is ASCII-specific,
         but the whole concept of \cx is ASCII-specific, so it seems
         reasonable.

   (iii) PCRE was using its character types table to recognize decimal and
         hexadecimal digits in the pattern. This is silly, because it handles
         only 0-9, a-f, and A-F, but the character types table is locale-
         specific, which means strange things might happen. A private
         table is now used for this - though it costs 256 bytes, a table is
         much faster than multiple explicit tests. Of course, the standard
         character types table is still used for matching digits in subject
         strings against \d.

   (iv)  Strictly, the identifier ESC_t is reserved by POSIX (all identifiers
         ending in _t are). So I've renamed it as ESC_tee.

3. The first argument for regexec() in the POSIX wrapper should have been
   defined as "const".

4. Changed pcretest to use malloc() for its buffers so that they can be
   Electric Fenced for debugging.

5. There were several places in the code where, in UTF-8 mode, PCRE would try
   to read one or more bytes before the start of the subject string. Often this
   had no effect on PCRE's behaviour, but in some circumstances it could
   provoke a segmentation fault.

6. A lookbehind at the start of a pattern in UTF-8 mode could also cause PCRE
   to try to read one or more bytes before the start of the subject string.

7. A lookbehind in a pattern matched in non-UTF-8 mode on a PCRE compiled with
   UTF-8 support could misbehave in various ways if the subject string
   contained bytes with the 0x80 bit set and the 0x40 bit unset in a lookbehind
   area. (PCRE was not checking for the UTF-8 mode flag, and trying to move
   back over UTF-8 characters.)


Version 4.2 14-Apr-03
---------------------

1. Typo "#if SUPPORT_UTF8" instead of "#ifdef SUPPORT_UTF8" fixed.

2. Changes to the building process, supplied by Ronald Landheer-Cieslak
     [ON_WINDOWS]: new variable, "#" on non-Windows platforms
     [NOT_ON_WINDOWS]: new variable, "#" on Windows platforms
     [WIN_PREFIX]: new variable, "cyg" for Cygwin
     * Makefile.in: use autoconf substitution for OBJEXT, EXEEXT, BUILD_OBJEXT
       and BUILD_EXEEXT
     Note: automatic setting of the BUILD variables is not yet working
     set CPPFLAGS and BUILD_CPPFLAGS (but don't use yet) - should be used at
       compile-time but not at link-time
     [LINK]: use for linking executables only
     make different versions for Windows and non-Windows
     [LINKLIB]: new variable, copy of UNIX-style LINK, used for linking
       libraries
     [LINK_FOR_BUILD]: new variable
     [OBJEXT]: use throughout
     [EXEEXT]: use throughout
     <winshared>: new target
     <wininstall>: new target
     <dftables.o>: use native compiler
     <dftables>: use native linker
     <install>: handle Windows platform correctly
     <clean>: ditto
     <check>: ditto
     copy DLL to top builddir before testing

   As part of these changes, -no-undefined was removed again. This was reported
   to give trouble on HP-UX 11.0, so getting rid of it seems like a good idea
   in any case.

3. Some tidies to get rid of compiler warnings:

   . In the match_data structure, match_limit was an unsigned long int, whereas
     match_call_count was an int. I've made them both unsigned long ints.

   . In pcretest the fact that a const uschar * doesn't automatically cast to
     a void * provoked a warning.

   . Turning on some more compiler warnings threw up some "shadow" variables
     and a few more missing casts.

4. If PCRE was complied with UTF-8 support, but called without the PCRE_UTF8
   option, a class that contained a single character with a value between 128
   and 255 (e.g. /[\xFF]/) caused PCRE to crash.

5. If PCRE was compiled with UTF-8 support, but called without the PCRE_UTF8
   option, a class that contained several characters, but with at least one
   whose value was between 128 and 255 caused PCRE to crash.


Version 4.1 12-Mar-03
---------------------

1. Compiling with gcc -pedantic found a couple of places where casts were
needed, and a string in dftables.c that was longer than standard compilers are
required to support.

2. Compiling with Sun's compiler found a few more places where the code could
be tidied up in order to avoid warnings.

3. The variables for cross-compiling were called HOST_CC and HOST_CFLAGS; the
first of these names is deprecated in the latest Autoconf in favour of the name
CC_FOR_BUILD, because "host" is typically used to mean the system on which the
compiled code will be run. I can't find a reference for HOST_CFLAGS, but by
analogy I have changed it to CFLAGS_FOR_BUILD.

4. Added -no-undefined to the linking command in the Makefile, because this is
apparently helpful for Windows. To make it work, also added "-L. -lpcre" to the
linking step for the pcreposix library.

5. PCRE was failing to diagnose the case of two named groups with the same
name.

6. A problem with one of PCRE's optimizations was discovered. PCRE remembers a
literal character that is needed in the subject for a match, and scans along to
ensure that it is present before embarking on the full matching process. This
saves time in cases of nested unlimited repeats that are never going to match.
Problem: the scan can take a lot of time if the subject is very long (e.g.
megabytes), thus penalizing straightforward matches. It is now done only if the
amount of subject to be scanned is less than 1000 bytes.

7. A lesser problem with the same optimization is that it was recording the
first character of an anchored pattern as "needed", thus provoking a search
right along the subject, even when the first match of the pattern was going to
fail. The "needed" character is now not set for anchored patterns, unless it
follows something in the pattern that is of non-fixed length. Thus, it still
fulfils its original purpose of finding quick non-matches in cases of nested
unlimited repeats, but isn't used for simple anchored patterns such as /^abc/.


Version 4.0 17-Feb-03
---------------------

1. If a comment in an extended regex that started immediately after a meta-item
extended to the end of string, PCRE compiled incorrect data. This could lead to
all kinds of weird effects. Example: /#/ was bad; /()#/ was bad; /a#/ was not.

2. Moved to autoconf 2.53 and libtool 1.4.2.

3. Perl 5.8 no longer needs "use utf8" for doing UTF-8 things. Consequently,
the special perltest8 script is no longer needed - all the tests can be run
from a single perltest script.

4. From 5.004, Perl has not included the VT character (0x0b) in the set defined
by \s. It has now been removed in PCRE. This means it isn't recognized as
whitespace in /x regexes too, which is the same as Perl. Note that the POSIX
class [:space:] *does* include VT, thereby creating a mess.

5. Added the class [:blank:] (a GNU extension from Perl 5.8) to match only
space and tab.

6. Perl 5.005 was a long time ago. It's time to amalgamate the tests that use
its new features into the main test script, reducing the number of scripts.

7. Perl 5.8 has changed the meaning of patterns like /a(?i)b/. Earlier versions
were backward compatible, and made the (?i) apply to the whole pattern, as if
/i were given. Now it behaves more logically, and applies the option setting
only to what follows. PCRE has been changed to follow suit. However, if it
finds options settings right at the start of the pattern, it extracts them into
the global options, as before. Thus, they show up in the info data.

8. Added support for the \Q...\E escape sequence. Characters in between are
treated as literals. This is slightly different from Perl in that $ and @ are
also handled as literals inside the quotes. In Perl, they will cause variable
interpolation. Note the following examples:

    Pattern            PCRE matches      Perl matches

    \Qabc$xyz\E        abc$xyz           abc followed by the contents of $xyz
    \Qabc\$xyz\E       abc\$xyz          abc\$xyz
    \Qabc\E\$\Qxyz\E   abc$xyz           abc$xyz

For compatibility with Perl, \Q...\E sequences are recognized inside character
classes as well as outside them.

9. Re-organized 3 code statements in pcretest to avoid "overflow in
floating-point constant arithmetic" warnings from a Microsoft compiler. Added a
(size_t) cast to one statement in pcretest and one in pcreposix to avoid
signed/unsigned warnings.

10. SunOS4 doesn't have strtoul(). This was used only for unpicking the -o
option for pcretest, so I've replaced it by a simple function that does just
that job.

11. pcregrep was ending with code 0 instead of 2 for the commands "pcregrep" or
"pcregrep -".

12. Added "possessive quantifiers" ?+, *+, ++, and {,}+ which come from Sun's
Java package. This provides some syntactic sugar for simple cases of what my
documentation calls "once-only subpatterns". A pattern such as x*+ is the same
as (?>x*). In other words, if what is inside (?>...) is just a single repeated
item, you can use this simplified notation. Note that only makes sense with
greedy quantifiers. Consequently, the use of the possessive quantifier forces
greediness, whatever the setting of the PCRE_UNGREEDY option.

13. A change of greediness default within a pattern was not taking effect at
the current level for patterns like /(b+(?U)a+)/. It did apply to parenthesized
subpatterns that followed. Patterns like /b+(?U)a+/ worked because the option
was abstracted outside.

14. PCRE now supports the \G assertion. It is true when the current matching
position is at the start point of the match. This differs from \A when the
starting offset is non-zero. Used with the /g option of pcretest (or similar
code), it works in the same way as it does for Perl's /g option. If all
alternatives of a regex begin with \G, the expression is anchored to the start
match position, and the "anchored" flag is set in the compiled expression.

15. Some bugs concerning the handling of certain option changes within patterns
have been fixed. These applied to options other than (?ims). For example,
"a(?x: b c )d" did not match "XabcdY" but did match "Xa b c dY". It should have
been the other way round. Some of this was related to change 7 above.

16. PCRE now gives errors for /[.x.]/ and /[=x=]/ as unsupported POSIX
features, as Perl does. Previously, PCRE gave the warnings only for /[[.x.]]/
and /[[=x=]]/. PCRE now also gives an error for /[:name:]/ because it supports
POSIX classes only within a class (e.g. /[[:alpha:]]/).

17. Added support for Perl's \C escape. This matches one byte, even in UTF8
mode. Unlike ".", it always matches newline, whatever the setting of
PCRE_DOTALL. However, PCRE does not permit \C to appear in lookbehind
assertions. Perl allows it, but it doesn't (in general) work because it can't
calculate the length of the lookbehind. At least, that's the case for Perl
5.8.0 - I've been told they are going to document that it doesn't work in
future.

18. Added an error diagnosis for escapes that PCRE does not support: these are
\L, \l, \N, \P, \p, \U, \u, and \X.

19. Although correctly diagnosing a missing ']' in a character class, PCRE was
reading past the end of the pattern in cases such as /[abcd/.

20. PCRE was getting more memory than necessary for patterns with classes that
contained both POSIX named classes and other characters, e.g. /[[:space:]abc/.

21. Added some code, conditional on #ifdef VPCOMPAT, to make life easier for
compiling PCRE for use with Virtual Pascal.

22. Small fix to the Makefile to make it work properly if the build is done
outside the source tree.

23. Added a new extension: a condition to go with recursion. If a conditional
subpattern starts with (?(R) the "true" branch is used if recursion has
happened, whereas the "false" branch is used only at the top level.

24. When there was a very long string of literal characters (over 255 bytes
without UTF support, over 250 bytes with UTF support), the computation of how
much memory was required could be incorrect, leading to segfaults or other
strange effects.

25. PCRE was incorrectly assuming anchoring (either to start of subject or to
start of line for a non-DOTALL pattern) when a pattern started with (.*) and
there was a subsequent back reference to those brackets. This meant that, for
example, /(.*)\d+\1/ failed to match "abc123bc". Unfortunately, it isn't
possible to check for precisely this case. All we can do is abandon the
optimization if .* occurs inside capturing brackets when there are any back
references whatsoever. (See below for a better fix that came later.)

26. The handling of the optimization for finding the first character of a
non-anchored pattern, and for finding a character that is required later in the
match were failing in some cases. This didn't break the matching; it just
failed to optimize when it could. The way this is done has been re-implemented.

27. Fixed typo in error message for invalid (?R item (it said "(?p").

28. Added a new feature that provides some of the functionality that Perl
provides with (?{...}). The facility is termed a "callout". The way it is done
in PCRE is for the caller to provide an optional function, by setting
pcre_callout to its entry point. Like pcre_malloc and pcre_free, this is a
global variable. By default it is unset, which disables all calling out. To get
the function called, the regex must include (?C) at appropriate points. This
is, in fact, equivalent to (?C0), and any number <= 255 may be given with (?C).
This provides a means of identifying different callout points. When PCRE
reaches such a point in the regex, if pcre_callout has been set, the external
function is called. It is provided with data in a structure called
pcre_callout_block, which is defined in pcre.h. If the function returns 0,
matching continues; if it returns a non-zero value, the match at the current
point fails. However, backtracking will occur if possible. [This was changed
later and other features added - see item 49 below.]

29. pcretest is upgraded to test the callout functionality. It provides a
callout function that displays information. By default, it shows the start of
the match and the current position in the text. There are some new data escapes
to vary what happens:

    \C+         in addition, show current contents of captured substrings
    \C-         do not supply a callout function
    \C!n        return 1 when callout number n is reached
    \C!n!m      return 1 when callout number n is reached for the mth time

30. If pcregrep was called with the -l option and just a single file name, it
output "<stdin>" if a match was found, instead of the file name.

31. Improve the efficiency of the POSIX API to PCRE. If the number of capturing
slots is less than POSIX_MALLOC_THRESHOLD, use a block on the stack to pass to
pcre_exec(). This saves a malloc/free per call. The default value of
POSIX_MALLOC_THRESHOLD is 10; it can be changed by --with-posix-malloc-threshold
when configuring.

32. The default maximum size of a compiled pattern is 64K. There have been a
few cases of people hitting this limit. The code now uses macros to handle the
storing of links as offsets within the compiled pattern. It defaults to 2-byte
links, but this can be changed to 3 or 4 bytes by --with-link-size when
configuring. Tests 2 and 5 work only with 2-byte links because they output
debugging information about compiled patterns.

33. Internal code re-arrangements:

(a) Moved the debugging function for printing out a compiled regex into
    its own source file (printint.c) and used #include to pull it into
    pcretest.c and, when DEBUG is defined, into pcre.c, instead of having two
    separate copies.

(b) Defined the list of op-code names for debugging as a macro in
    internal.h so that it is next to the definition of the opcodes.

(c) Defined a table of op-code lengths for simpler skipping along compiled
    code. This is again a macro in internal.h so that it is next to the
    definition of the opcodes.

34. Added support for recursive calls to individual subpatterns, along the
lines of Robin Houston's patch (but implemented somewhat differently).

35. Further mods to the Makefile to help Win32. Also, added code to pcregrep to
allow it to read and process whole directories in Win32. This code was
contributed by Lionel Fourquaux; it has not been tested by me.

36. Added support for named subpatterns. The Python syntax (?P<name>...) is
used to name a group. Names consist of alphanumerics and underscores, and must
be unique. Back references use the syntax (?P=name) and recursive calls use
(?P>name) which is a PCRE extension to the Python extension. Groups still have
numbers. The function pcre_fullinfo() can be used after compilation to extract
a name/number map. There are three relevant calls:

  PCRE_INFO_NAMEENTRYSIZE        yields the size of each entry in the map
  PCRE_INFO_NAMECOUNT            yields the number of entries
  PCRE_INFO_NAMETABLE            yields a pointer to the map.

The map is a vector of fixed-size entries. The size of each entry depends on
the length of the longest name used. The first two bytes of each entry are the
group number, most significant byte first. There follows the corresponding
name, zero terminated. The names are in alphabetical order.

37. Make the maximum literal string in the compiled code 250 for the non-UTF-8
case instead of 255. Making it the same both with and without UTF-8 support
means that the same test output works with both.

38. There was a case of malloc(0) in the POSIX testing code in pcretest. Avoid
calling malloc() with a zero argument.

39. Change 25 above had to resort to a heavy-handed test for the .* anchoring
optimization. I've improved things by keeping a bitmap of backreferences with
numbers 1-31 so that if .* occurs inside capturing brackets that are not in
fact referenced, the optimization can be applied. It is unlikely that a
relevant occurrence of .* (i.e. one which might indicate anchoring or forcing
the match to follow \n) will appear inside brackets with a number greater than
31, but if it does, any back reference > 31 suppresses the optimization.

40. Added a new compile-time option PCRE_NO_AUTO_CAPTURE. This has the effect
of disabling numbered capturing parentheses. Any opening parenthesis that is
not followed by ? behaves as if it were followed by ?: but named parentheses
can still be used for capturing (and they will acquire numbers in the usual
way).

41. Redesigned the return codes from the match() function into yes/no/error so
that errors can be passed back from deep inside the nested calls. A malloc
failure while inside a recursive subpattern call now causes the
PCRE_ERROR_NOMEMORY return instead of quietly going wrong.

42. It is now possible to set a limit on the number of times the match()
function is called in a call to pcre_exec(). This facility makes it possible to
limit the amount of recursion and backtracking, though not in a directly
obvious way, because the match() function is used in a number of different
circumstances. The count starts from zero for each position in the subject
string (for non-anchored patterns). The default limit is, for compatibility, a
large number, namely 10 000 000. You can change this in two ways:

(a) When configuring PCRE before making, you can use --with-match-limit=n
    to set a default value for the compiled library.

(b) For each call to pcre_exec(), you can pass a pcre_extra block in which
    a different value is set. See 45 below.

If the limit is exceeded, pcre_exec() returns PCRE_ERROR_MATCHLIMIT.

43. Added a new function pcre_config(int, void *) to enable run-time extraction
of things that can be changed at compile time. The first argument specifies
what is wanted and the second points to where the information is to be placed.
The current list of available information is:

  PCRE_CONFIG_UTF8

The output is an integer that is set to one if UTF-8 support is available;
otherwise it is set to zero.

  PCRE_CONFIG_NEWLINE

The output is an integer that it set to the value of the code that is used for
newline. It is either LF (10) or CR (13).

  PCRE_CONFIG_LINK_SIZE

The output is an integer that contains the number of bytes used for internal
linkage in compiled expressions. The value is 2, 3, or 4. See item 32 above.

  PCRE_CONFIG_POSIX_MALLOC_THRESHOLD

The output is an integer that contains the threshold above which the POSIX
interface uses malloc() for output vectors. See item 31 above.

  PCRE_CONFIG_MATCH_LIMIT

The output is an unsigned integer that contains the default limit of the number
of match() calls in a pcre_exec() execution. See 42 above.

44. pcretest has been upgraded by the addition of the -C option. This causes it
to extract all the available output from the new pcre_config() function, and to
output it. The program then exits immediately.

45. A need has arisen to pass over additional data with calls to pcre_exec() in
order to support additional features. One way would have been to define
pcre_exec2() (for example) with extra arguments, but this would not have been
extensible, and would also have required all calls to the original function to
be mapped to the new one. Instead, I have chosen to extend the mechanism that
is used for passing in "extra" data from pcre_study().

The pcre_extra structure is now exposed and defined in pcre.h. It currently
contains the following fields:

  flags         a bitmap indicating which of the following fields are set
  study_data    opaque data from pcre_study()
  match_limit   a way of specifying a limit on match() calls for a specific
                  call to pcre_exec()
  callout_data  data for callouts (see 49 below)

The flag bits are also defined in pcre.h, and are

  PCRE_EXTRA_STUDY_DATA
  PCRE_EXTRA_MATCH_LIMIT
  PCRE_EXTRA_CALLOUT_DATA

The pcre_study() function now returns one of these new pcre_extra blocks, with
the actual study data pointed to by the study_data field, and the
PCRE_EXTRA_STUDY_DATA flag set. This can be passed directly to pcre_exec() as
before. That is, this change is entirely upwards-compatible and requires no
change to existing code.

If you want to pass in additional data to pcre_exec(), you can either place it
in a pcre_extra block provided by pcre_study(), or create your own pcre_extra
block.

46. pcretest has been extended to test the PCRE_EXTRA_MATCH_LIMIT feature. If a
data string contains the escape sequence \M, pcretest calls pcre_exec() several
times with different match limits, until it finds the minimum value needed for
pcre_exec() to complete. The value is then output. This can be instructive; for
most simple matches the number is quite small, but for pathological cases it
gets very large very quickly.

47. There's a new option for pcre_fullinfo() called PCRE_INFO_STUDYSIZE. It
returns the size of the data block pointed to by the study_data field in a
pcre_extra block, that is, the value that was passed as the argument to
pcre_malloc() when PCRE was getting memory in which to place the information
created by pcre_study(). The fourth argument should point to a size_t variable.
pcretest has been extended so that this information is shown after a successful
pcre_study() call when information about the compiled regex is being displayed.

48. Cosmetic change to Makefile: there's no need to have / after $(DESTDIR)
because what follows is always an absolute path. (Later: it turns out that this
is more than cosmetic for MinGW, because it doesn't like empty path
components.)

49. Some changes have been made to the callout feature (see 28 above):

(i)  A callout function now has three choices for what it returns:

       0  =>  success, carry on matching
     > 0  =>  failure at this point, but backtrack if possible
     < 0  =>  serious error, return this value from pcre_exec()

     Negative values should normally be chosen from the set of PCRE_ERROR_xxx
     values. In particular, returning PCRE_ERROR_NOMATCH forces a standard
     "match failed" error. The error number PCRE_ERROR_CALLOUT is reserved for
     use by callout functions. It will never be used by PCRE itself.

(ii) The pcre_extra structure (see 45 above) has a void * field called
     callout_data, with corresponding flag bit PCRE_EXTRA_CALLOUT_DATA. The
     pcre_callout_block structure has a field of the same name. The contents of
     the field passed in the pcre_extra structure are passed to the callout
     function in the corresponding field in the callout block. This makes it
     easier to use the same callout-containing regex from multiple threads. For
     testing, the pcretest program has a new data escape

       \C*n        pass the number n (may be negative) as callout_data

     If the callout function in pcretest receives a non-zero value as
     callout_data, it returns that value.

50. Makefile wasn't handling CFLAGS properly when compiling dftables. Also,
there were some redundant $(CFLAGS) in commands that are now specified as
$(LINK), which already includes $(CFLAGS).

51. Extensions to UTF-8 support are listed below. These all apply when (a) PCRE
has been compiled with UTF-8 support *and* pcre_compile() has been compiled
with the PCRE_UTF8 flag. Patterns that are compiled without that flag assume
one-byte characters throughout. Note that case-insensitive matching applies
only to characters whose values are less than 256. PCRE doesn't support the
notion of cases for higher-valued characters.

(i)   A character class whose characters are all within 0-255 is handled as
      a bit map, and the map is inverted for negative classes. Previously, a
      character > 255 always failed to match such a class; however it should
      match if the class was a negative one (e.g. [^ab]). This has been fixed.

(ii)  A negated character class with a single character < 255 is coded as
      "not this character" (OP_NOT). This wasn't working properly when the test
      character was multibyte, either singly or repeated.

(iii) Repeats of multibyte characters are now handled correctly in UTF-8
      mode, for example: \x{100}{2,3}.

(iv)  The character escapes \b, \B, \d, \D, \s, \S, \w, and \W (either
      singly or repeated) now correctly test multibyte characters. However,
      PCRE doesn't recognize any characters with values greater than 255 as
      digits, spaces, or word characters. Such characters always match \D, \S,
      and \W, and never match \d, \s, or \w.

(v)   Classes may now contain characters and character ranges with values
      greater than 255. For example: [ab\x{100}-\x{400}].

(vi)  pcregrep now has a --utf-8 option (synonym -u) which makes it call
      PCRE in UTF-8 mode.

52. The info request value PCRE_INFO_FIRSTCHAR has been renamed
PCRE_INFO_FIRSTBYTE because it is a byte value. However, the old name is
retained for backwards compatibility. (Note that LASTLITERAL is also a byte
value.)

53. The single man page has become too large. I have therefore split it up into
a number of separate man pages. These also give rise to individual HTML pages;
these are now put in a separate directory, and there is an index.html page that
lists them all. Some hyperlinking between the pages has been installed.

54. Added convenience functions for handling named capturing parentheses.

55. Unknown escapes inside character classes (e.g. [\M]) and escapes that
aren't interpreted therein (e.g. [\C]) are literals in Perl. This is now also
true in PCRE, except when the PCRE_EXTENDED option is set, in which case they
are faulted.

56. Introduced HOST_CC and HOST_CFLAGS which can be set in the environment when
calling configure. These values are used when compiling the dftables.c program
which is run to generate the source of the default character tables. They
default to the values of CC and CFLAGS. If you are cross-compiling PCRE,
you will need to set these values.

57. Updated the building process for Windows DLL, as provided by Fred Cox.


Version 3.9 02-Jan-02
---------------------

1. A bit of extraneous text had somehow crept into the pcregrep documentation.

2. If --disable-static was given, the building process failed when trying to
build pcretest and pcregrep. (For some reason it was using libtool to compile
them, which is not right, as they aren't part of the library.)


Version 3.8 18-Dec-01
---------------------

1. The experimental UTF-8 code was completely screwed up. It was packing the
bytes in the wrong order. How dumb can you get?


Version 3.7 29-Oct-01
---------------------

1. In updating pcretest to check change 1 of version 3.6, I screwed up.
This caused pcretest, when used on the test data, to segfault. Unfortunately,
this didn't happen under Solaris 8, where I normally test things.

2. The Makefile had to be changed to make it work on BSD systems, where 'make'
doesn't seem to recognize that ./xxx and xxx are the same file. (This entry
isn't in ChangeLog distributed with 3.7 because I forgot when I hastily made
this fix an hour or so after the initial 3.7 release.)


Version 3.6 23-Oct-01
---------------------

1. Crashed with /(sens|respons)e and \1ibility/ and "sense and sensibility" if
offsets passed as NULL with zero offset count.

2. The config.guess and config.sub files had not been updated when I moved to
the latest autoconf.


Version 3.5 15-Aug-01
---------------------

1. Added some missing #if !defined NOPOSIX conditionals in pcretest.c that
had been forgotten.

2. By using declared but undefined structures, we can avoid using "void"
definitions in pcre.h while keeping the internal definitions of the structures
private.

3. The distribution is now built using autoconf 2.50 and libtool 1.4. From a
user point of view, this means that both static and shared libraries are built
by default, but this can be individually controlled. More of the work of
handling this static/shared cases is now inside libtool instead of PCRE's make
file.

4. The pcretest utility is now installed along with pcregrep because it is
useful for users (to test regexs) and by doing this, it automatically gets
relinked by libtool. The documentation has been turned into a man page, so
there are now .1, .txt, and .html versions in /doc.

5. Upgrades to pcregrep:
   (i)   Added long-form option names like gnu grep.
   (ii)  Added --help to list all options with an explanatory phrase.
   (iii) Added -r, --recursive to recurse into sub-directories.
   (iv)  Added -f, --file to read patterns from a file.

6. pcre_exec() was referring to its "code" argument before testing that
argument for NULL (and giving an error if it was NULL).

7. Upgraded Makefile.in to allow for compiling in a different directory from
the source directory.

8. Tiny buglet in pcretest: when pcre_fullinfo() was called to retrieve the
options bits, the pointer it was passed was to an int instead of to an unsigned
long int. This mattered only on 64-bit systems.

9. Fixed typo (3.4/1) in pcre.h again. Sigh. I had changed pcre.h (which is
generated) instead of pcre.in, which it its source. Also made the same change
in several of the .c files.

10. A new release of gcc defines printf() as a macro, which broke pcretest
because it had an ifdef in the middle of a string argument for printf(). Fixed
by using separate calls to printf().

11. Added --enable-newline-is-cr and --enable-newline-is-lf to the configure
script, to force use of CR or LF instead of \n in the source. On non-Unix
systems, the value can be set in config.h.

12. The limit of 200 on non-capturing parentheses is a _nesting_ limit, not an
absolute limit. Changed the text of the error message to make this clear, and
likewise updated the man page.

13. The limit of 99 on the number of capturing subpatterns has been removed.
The new limit is 65535, which I hope will not be a "real" limit.


Version 3.4 22-Aug-00
---------------------

1. Fixed typo in pcre.h: unsigned const char * changed to const unsigned char *.

2. Diagnose condition (?(0) as an error instead of crashing on matching.


Version 3.3 01-Aug-00
---------------------

1. If an octal character was given, but the value was greater than \377, it
was not getting masked to the least significant bits, as documented. This could
lead to crashes in some systems.

2. Perl 5.6 (if not earlier versions) accepts classes like [a-\d] and treats
the hyphen as a literal. PCRE used to give an error; it now behaves like Perl.

3. Added the functions pcre_free_substring() and pcre_free_substring_list().
These just pass their arguments on to (pcre_free)(), but they are provided
because some uses of PCRE bind it to non-C systems that can call its functions,
but cannot call free() or pcre_free() directly.

4. Add "make test" as a synonym for "make check". Corrected some comments in
the Makefile.

5. Add $(DESTDIR)/ in front of all the paths in the "install" target in the
Makefile.

6. Changed the name of pgrep to pcregrep, because Solaris has introduced a
command called pgrep for grepping around the active processes.

7. Added the beginnings of support for UTF-8 character strings.

8. Arranged for the Makefile to pass over the settings of CC, CFLAGS, and
RANLIB to ./ltconfig so that they are used by libtool. I think these are all
the relevant ones. (AR is not passed because ./ltconfig does its own figuring
out for the ar command.)


Version 3.2 12-May-00
---------------------

This is purely a bug fixing release.

1. If the pattern /((Z)+|A)*/ was matched agained ZABCDEFG it matched Z instead
of ZA. This was just one example of several cases that could provoke this bug,
which was introduced by change 9 of version 2.00. The code for breaking
infinite loops after an iteration that matches an empty string was't working
correctly.

2. The pcretest program was not imitating Perl correctly for the pattern /a*/g
when matched against abbab (for example). After matching an empty string, it
wasn't forcing anchoring when setting PCRE_NOTEMPTY for the next attempt; this
caused it to match further down the string than it should.

3. The code contained an inclusion of sys/types.h. It isn't clear why this
was there because it doesn't seem to be needed, and it causes trouble on some
systems, as it is not a Standard C header. It has been removed.

4. Made 4 silly changes to the source to avoid stupid compiler warnings that
were reported on the Macintosh. The changes were from

  while ((c = *(++ptr)) != 0 && c != '\n');
to
  while ((c = *(++ptr)) != 0 && c != '\n') ;

Totally extraordinary, but if that's what it takes...

5. PCRE is being used in one environment where neither memmove() nor bcopy() is
available. Added HAVE_BCOPY and an autoconf test for it; if neither
HAVE_MEMMOVE nor HAVE_BCOPY is set, use a built-in emulation function which
assumes the way PCRE uses memmove() (always moving upwards).

6. PCRE is being used in one environment where strchr() is not available. There
was only one use in pcre.c, and writing it out to avoid strchr() probably gives
faster code anyway.


Version 3.1 09-Feb-00
---------------------

The only change in this release is the fixing of some bugs in Makefile.in for
the "install" target:

(1) It was failing to install pcreposix.h.

(2) It was overwriting the pcre.3 man page with the pcreposix.3 man page.


Version 3.0 01-Feb-00
---------------------

1. Add support for the /+ modifier to perltest (to output $` like it does in
pcretest).

2. Add support for the /g modifier to perltest.

3. Fix pcretest so that it behaves even more like Perl for /g when the pattern
matches null strings.

4. Fix perltest so that it doesn't do unwanted things when fed an empty
pattern. Perl treats empty patterns specially - it reuses the most recent
pattern, which is not what we want. Replace // by /(?#)/ in order to avoid this
effect.

5. The POSIX interface was broken in that it was just handing over the POSIX
captured string vector to pcre_exec(), but (since release 2.00) PCRE has
required a bigger vector, with some working space on the end. This means that
the POSIX wrapper now has to get and free some memory, and copy the results.

6. Added some simple autoconf support, placing the test data and the
documentation in separate directories, re-organizing some of the
information files, and making it build pcre-config (a GNU standard). Also added
libtool support for building PCRE as a shared library, which is now the
default.

7. Got rid of the leading zero in the definition of PCRE_MINOR because 08 and
09 are not valid octal constants. Single digits will be used for minor values
less than 10.

8. Defined REG_EXTENDED and REG_NOSUB as zero in the POSIX header, so that
existing programs that set these in the POSIX interface can use PCRE without
modification.

9. Added a new function, pcre_fullinfo() with an extensible interface. It can
return all that pcre_info() returns, plus additional data. The pcre_info()
function is retained for compatibility, but is considered to be obsolete.

10. Added experimental recursion feature (?R) to handle one common case that
Perl 5.6 will be able to do with (?p{...}).

11. Added support for POSIX character classes like [:alpha:], which Perl is
adopting.


Version 2.08 31-Aug-99
----------------------

1. When startoffset was not zero and the pattern began with ".*", PCRE was not
trying to match at the startoffset position, but instead was moving forward to
the next newline as if a previous match had failed.

2. pcretest was not making use of PCRE_NOTEMPTY when repeating for /g and /G,
and could get into a loop if a null string was matched other than at the start
of the subject.

3. Added definitions of PCRE_MAJOR and PCRE_MINOR to pcre.h so the version can
be distinguished at compile time, and for completeness also added PCRE_DATE.

5. Added Paul Sokolovsky's minor changes to make it easy to compile a Win32 DLL
in GnuWin32 environments.


Version 2.07 29-Jul-99
----------------------

1. The documentation is now supplied in plain text form and HTML as well as in
the form of man page sources.

2. C++ compilers don't like assigning (void *) values to other pointer types.
In particular this affects malloc(). Although there is no problem in Standard
C, I've put in casts to keep C++ compilers happy.

3. Typo on pcretest.c; a cast of (unsigned char *) in the POSIX regexec() call
should be (const char *).

4. If NOPOSIX is defined, pcretest.c compiles without POSIX support. This may
be useful for non-Unix systems who don't want to bother with the POSIX stuff.
However, I haven't made this a standard facility. The documentation doesn't
mention it, and the Makefile doesn't support it.

5. The Makefile now contains an "install" target, with editable destinations at
the top of the file. The pcretest program is not installed.

6. pgrep -V now gives the PCRE version number and date.

7. Fixed bug: a zero repetition after a literal string (e.g. /abcde{0}/) was
causing the entire string to be ignored, instead of just the last character.

8. If a pattern like /"([^\\"]+|\\.)*"/ is applied in the normal way to a
non-matching string, it can take a very, very long time, even for strings of
quite modest length, because of the nested recursion. PCRE now does better in
some of these cases. It does this by remembering the last required literal
character in the pattern, and pre-searching the subject to ensure it is present
before running the real match. In other words, it applies a heuristic to detect
some types of certain failure quickly, and in the above example, if presented
with a string that has no trailing " it gives "no match" very quickly.

9. A new runtime option PCRE_NOTEMPTY causes null string matches to be ignored;
other alternatives are tried instead.


Version 2.06 09-Jun-99
----------------------

1. Change pcretest's output for amount of store used to show just the code
space, because the remainder (the data block) varies in size between 32-bit and
64-bit systems.

2. Added an extra argument to pcre_exec() to supply an offset in the subject to
start matching at. This allows lookbehinds to work when searching for multiple
occurrences in a string.

3. Added additional options to pcretest for testing multiple occurrences:

   /+   outputs the rest of the string that follows a match
   /g   loops for multiple occurrences, using the new startoffset argument
   /G   loops for multiple occurrences by passing an incremented pointer

4. PCRE wasn't doing the "first character" optimization for patterns starting
with \b or \B, though it was doing it for other lookbehind assertions. That is,
it wasn't noticing that a match for a pattern such as /\bxyz/ has to start with
the letter 'x'. On long subject strings, this gives a significant speed-up.


Version 2.05 21-Apr-99
----------------------

1. Changed the type of magic_number from int to long int so that it works
properly on 16-bit systems.

2. Fixed a bug which caused patterns starting with .* not to work correctly
when the subject string contained newline characters. PCRE was assuming
anchoring for such patterns in all cases, which is not correct because .* will
not pass a newline unless PCRE_DOTALL is set. It now assumes anchoring only if
DOTALL is set at top level; otherwise it knows that patterns starting with .*
must be retried after every newline in the subject.


Version 2.04 18-Feb-99
----------------------

1. For parenthesized subpatterns with repeats whose minimum was zero, the
computation of the store needed to hold the pattern was incorrect (too large).
If such patterns were nested a few deep, this could multiply and become a real
problem.

2. Added /M option to pcretest to show the memory requirement of a specific
pattern. Made -m a synonym of -s (which does this globally) for compatibility.

3. Subpatterns of the form (regex){n,m} (i.e. limited maximum) were being
compiled in such a way that the backtracking after subsequent failure was
pessimal. Something like (a){0,3} was compiled as (a)?(a)?(a)? instead of
((a)((a)(a)?)?)? with disastrous performance if the maximum was of any size.


Version 2.03 02-Feb-99
----------------------

1. Fixed typo and small mistake in man page.

2. Added 4th condition (GPL supersedes if conflict) and created separate
LICENCE file containing the conditions.

3. Updated pcretest so that patterns such as /abc\/def/ work like they do in
Perl, that is the internal \ allows the delimiter to be included in the
pattern. Locked out the use of \ as a delimiter. If \ immediately follows
the final delimiter, add \ to the end of the pattern (to test the error).

4. Added the convenience functions for extracting substrings after a successful
match. Updated pcretest to make it able to test these functions.


Version 2.02 14-Jan-99
----------------------

1. Initialized the working variables associated with each extraction so that
their saving and restoring doesn't refer to uninitialized store.

2. Put dummy code into study.c in order to trick the optimizer of the IBM C
compiler for OS/2 into generating correct code. Apparently IBM isn't going to
fix the problem.

3. Pcretest: the timing code wasn't using LOOPREPEAT for timing execution
calls, and wasn't printing the correct value for compiling calls. Increased the
default value of LOOPREPEAT, and the number of significant figures in the
times.

4. Changed "/bin/rm" in the Makefile to "-rm" so it works on Windows NT.

5. Renamed "deftables" as "dftables" to get it down to 8 characters, to avoid
a building problem on Windows NT with a FAT file system.


Version 2.01 21-Oct-98
----------------------

1. Changed the API for pcre_compile() to allow for the provision of a pointer
to character tables built by pcre_maketables() in the current locale. If NULL
is passed, the default tables are used.


Version 2.00 24-Sep-98
----------------------

1. Since the (>?) facility is in Perl 5.005, don't require PCRE_EXTRA to enable
it any more.

2. Allow quantification of (?>) groups, and make it work correctly.

3. The first character computation wasn't working for (?>) groups.

4. Correct the implementation of \Z (it is permitted to match on the \n at the
end of the subject) and add 5.005's \z, which really does match only at the
very end of the subject.

5. Remove the \X "cut" facility; Perl doesn't have it, and (?> is neater.

6. Remove the ability to specify CASELESS, MULTILINE, DOTALL, and
DOLLAR_END_ONLY at runtime, to make it possible to implement the Perl 5.005
localized options. All options to pcre_study() were also removed.

7. Add other new features from 5.005:

   $(?<=           positive lookbehind
   $(?<!           negative lookbehind
   (?imsx-imsx)    added the unsetting capability
                   such a setting is global if at outer level; local otherwise
   (?imsx-imsx:)   non-capturing groups with option setting
   (?(cond)re|re)  conditional pattern matching

   A backreference to itself in a repeated group matches the previous
   captured string.

8. General tidying up of studying (both automatic and via "study")
consequential on the addition of new assertions.

9. As in 5.005, unlimited repeated groups that could match an empty substring
are no longer faulted at compile time. Instead, the loop is forcibly broken at
runtime if any iteration does actually match an empty substring.

10. Include the RunTest script in the distribution.

11. Added tests from the Perl 5.005_02 distribution. This showed up a few
discrepancies, some of which were old and were also with respect to 5.004. They
have now been fixed.


Version 1.09 28-Apr-98
----------------------

1. A negated single character class followed by a quantifier with a minimum
value of one (e.g.  [^x]{1,6}  ) was not compiled correctly. This could lead to
program crashes, or just wrong answers. This did not apply to negated classes
containing more than one character, or to minima other than one.


Version 1.08 27-Mar-98
----------------------

1. Add PCRE_UNGREEDY to invert the greediness of quantifiers.

2. Add (?U) and (?X) to set PCRE_UNGREEDY and PCRE_EXTRA respectively. The
latter must appear before anything that relies on it in the pattern.


Version 1.07 16-Feb-98
----------------------

1. A pattern such as /((a)*)*/ was not being diagnosed as in error (unlimited
repeat of a potentially empty string).


Version 1.06 23-Jan-98
----------------------

1. Added Markus Oberhumer's little patches for C++.

2. Literal strings longer than 255 characters were broken.


Version 1.05 23-Dec-97
----------------------

1. Negated character classes containing more than one character were failing if
PCRE_CASELESS was set at run time.


Version 1.04 19-Dec-97
----------------------

1. Corrected the man page, where some "const" qualifiers had been omitted.

2. Made debugging output print "{0,xxx}" instead of just "{,xxx}" to agree with
input syntax.

3. Fixed memory leak which occurred when a regex with back references was
matched with an offsets vector that wasn't big enough. The temporary memory
that is used in this case wasn't being freed if the match failed.

4. Tidied pcretest to ensure it frees memory that it gets.

5. Temporary memory was being obtained in the case where the passed offsets
vector was exactly big enough.

6. Corrected definition of offsetof() from change 5 below.

7. I had screwed up change 6 below and broken the rules for the use of
setjmp(). Now fixed.


Version 1.03 18-Dec-97
----------------------

1. A erroneous regex with a missing opening parenthesis was correctly
diagnosed, but PCRE attempted to access brastack[-1], which could cause crashes
on some systems.

2. Replaced offsetof(real_pcre, code) by offsetof(real_pcre, code[0]) because
it was reported that one broken compiler failed on the former because "code" is
also an independent variable.

3. The erroneous regex a[]b caused an array overrun reference.

4. A regex ending with a one-character negative class (e.g. /[^k]$/) did not
fail on data ending with that character. (It was going on too far, and checking
the next character, typically a binary zero.) This was specific to the
optimized code for single-character negative classes.

5. Added a contributed patch from the TIN world which does the following:

  + Add an undef for memmove, in case the the system defines a macro for it.

  + Add a definition of offsetof(), in case there isn't one. (I don't know
    the reason behind this - offsetof() is part of the ANSI standard - but
    it does no harm).

  + Reduce the ifdef's in pcre.c using macro DPRINTF, thereby eliminating
    most of the places where whitespace preceded '#'. I have given up and
    allowed the remaining 2 cases to be at the margin.

  + Rename some variables in pcre to eliminate shadowing. This seems very
    pedantic, but does no harm, of course.

6. Moved the call to setjmp() into its own function, to get rid of warnings
from gcc -Wall, and avoided calling it at all unless PCRE_EXTRA is used.

7. Constructs such as \d{8,} were compiling into the equivalent of
\d{8}\d{0,65527} instead of \d{8}\d* which didn't make much difference to the
outcome, but in this particular case used more store than had been allocated,
which caused the bug to be discovered because it threw up an internal error.

8. The debugging code in both pcre and pcretest for outputting the compiled
form of a regex was going wrong in the case of back references followed by
curly-bracketed repeats.


Version 1.02 12-Dec-97
----------------------

1. Typos in pcre.3 and comments in the source fixed.

2. Applied a contributed patch to get rid of places where it used to remove
'const' from variables, and fixed some signed/unsigned and uninitialized
variable warnings.

3. Added the "runtest" target to Makefile.

4. Set default compiler flag to -O2 rather than just -O.


Version 1.01 19-Nov-97
----------------------

1. PCRE was failing to diagnose unlimited repeat of empty string for patterns
like /([ab]*)*/, that is, for classes with more than one character in them.

2. Likewise, it wasn't diagnosing patterns with "once-only" subpatterns, such
as /((?>a*))*/ (a PCRE_EXTRA facility).


Version 1.00 18-Nov-97
----------------------

1. Added compile-time macros to support systems such as SunOS4 which don't have
memmove() or strerror() but have other things that can be used instead.

2. Arranged that "make clean" removes the executables.


Version 0.99 27-Oct-97
----------------------

1. Fixed bug in code for optimizing classes with only one character. It was
initializing a 32-byte map regardless, which could cause it to run off the end
of the memory it had got.

2. Added, conditional on PCRE_EXTRA, the proposed (?>REGEX) construction.


Version 0.98 22-Oct-97
----------------------

1. Fixed bug in code for handling temporary memory usage when there are more
back references than supplied space in the ovector. This could cause segfaults.


Version 0.97 21-Oct-97
----------------------

1. Added the \X "cut" facility, conditional on PCRE_EXTRA.

2. Optimized negated single characters not to use a bit map.

3. Brought error texts together as macro definitions; clarified some of them;
fixed one that was wrong - it said "range out of order" when it meant "invalid
escape sequence".

4. Changed some char * arguments to const char *.

5. Added PCRE_NOTBOL and PCRE_NOTEOL (from POSIX).

6. Added the POSIX-style API wrapper in pcreposix.a and testing facilities in
pcretest.


Version 0.96 16-Oct-97
----------------------

1. Added a simple "pgrep" utility to the distribution.

2. Fixed an incompatibility with Perl: "{" is now treated as a normal character
unless it appears in one of the precise forms "{ddd}", "{ddd,}", or "{ddd,ddd}"
where "ddd" means "one or more decimal digits".

3. Fixed serious bug. If a pattern had a back reference, but the call to
pcre_exec() didn't supply a large enough ovector to record the related
identifying subpattern, the match always failed. PCRE now remembers the number
of the largest back reference, and gets some temporary memory in which to save
the offsets during matching if necessary, in order to ensure that
backreferences always work.

4. Increased the compatibility with Perl in a number of ways:

  (a) . no longer matches \n by default; an option PCRE_DOTALL is provided
      to request this handling. The option can be set at compile or exec time.

  (b) $ matches before a terminating newline by default; an option
      PCRE_DOLLAR_ENDONLY is provided to override this (but not in multiline
      mode). The option can be set at compile or exec time.

  (c) The handling of \ followed by a digit other than 0 is now supposed to be
      the same as Perl's. If the decimal number it represents is less than 10
      or there aren't that many previous left capturing parentheses, an octal
      escape is read. Inside a character class, it's always an octal escape,
      even if it is a single digit.

  (d) An escaped but undefined alphabetic character is taken as a literal,
      unless PCRE_EXTRA is set. Currently this just reserves the remaining
      escapes.

  (e) {0} is now permitted. (The previous item is removed from the compiled
      pattern).

5. Changed all the names of code files so that the basic parts are no longer
than 10 characters, and abolished the teeny "globals.c" file.

6. Changed the handling of character classes; they are now done with a 32-byte
bit map always.

7. Added the -d and /D options to pcretest to make it possible to look at the
internals of compilation without having to recompile pcre.


Version 0.95 23-Sep-97
----------------------

1. Fixed bug in pre-pass concerning escaped "normal" characters such as \x5c or
\x20 at the start of a run of normal characters. These were being treated as
real characters, instead of the source characters being re-checked.


Version 0.94 18-Sep-97
----------------------

1. The functions are now thread-safe, with the caveat that the global variables
containing pointers to malloc() and free() or alternative functions are the
same for all threads.

2. Get pcre_study() to generate a bitmap of initial characters for non-
anchored patterns when this is possible, and use it if passed to pcre_exec().


Version 0.93 15-Sep-97
----------------------

1. /(b)|(:+)/ was computing an incorrect first character.

2. Add pcre_study() to the API and the passing of pcre_extra to pcre_exec(),
but not actually doing anything yet.

3. Treat "-" characters in classes that cannot be part of ranges as literals,
as Perl does (e.g. [-az] or [az-]).

4. Set the anchored flag if a branch starts with .* or .*? because that tests
all possible positions.

5. Split up into different modules to avoid including unneeded functions in a
compiled binary. However, compile and exec are still in one module. The "study"
function is split off.

6. The character tables are now in a separate module whose source is generated
by an auxiliary program - but can then be edited by hand if required. There are
now no calls to isalnum(), isspace(), isdigit(), isxdigit(), tolower() or
toupper() in the code.

7. Turn the malloc/free funtions variables into pcre_malloc and pcre_free and
make them global. Abolish the function for setting them, as the caller can now
set them directly.


Version 0.92 11-Sep-97
----------------------

1. A repeat with a fixed maximum and a minimum of 1 for an ordinary character
(e.g. /a{1,3}/) was broken (I mis-optimized it).

2. Caseless matching was not working in character classes if the characters in
the pattern were in upper case.

3. Make ranges like [W-c] work in the same way as Perl for caseless matching.

4. Make PCRE_ANCHORED public and accept as a compile option.

5. Add an options word to pcre_exec() and accept PCRE_ANCHORED and
PCRE_CASELESS at run time. Add escapes \A and \I to pcretest to cause it to
pass them.

6. Give an error if bad option bits passed at compile or run time.

7. Add PCRE_MULTILINE at compile and exec time, and (?m) as well. Add \M to
pcretest to cause it to pass that flag.

8. Add pcre_info(), to get the number of identifying subpatterns, the stored
options, and the first character, if set.

9. Recognize C+ or C{n,m} where n >= 1 as providing a fixed starting character.


Version 0.91 10-Sep-97
----------------------

1. PCRE was failing to diagnose unlimited repeats of subpatterns that could
match the empty string as in /(a*)*/. It was looping and ultimately crashing.

2. PCRE was looping on encountering an indefinitely repeated back reference to
a subpattern that had matched an empty string, e.g. /(a|)\1*/. It now does what
Perl does - treats the match as successful.

****
PK� %[!���__doc/alt-pcre/COPYINGnu�[���PCRE LICENCE

Please see the file LICENCE in the PCRE distribution for licensing details.

End
PK� %[ʿ��SSdoc/alt-pcre/AUTHORSnu�[���THE MAIN PCRE LIBRARY
---------------------

Written by:       Philip Hazel
Email local part: ph10
Email domain:     cam.ac.uk

University of Cambridge Computing Service,
Cambridge, England.

Copyright (c) 1997-2017 University of Cambridge
All rights reserved


PCRE JUST-IN-TIME COMPILATION SUPPORT
-------------------------------------

Written by:       Zoltan Herczeg
Email local part: hzmester
Emain domain:     freemail.hu

Copyright(c) 2010-2017 Zoltan Herczeg
All rights reserved.


STACK-LESS JUST-IN-TIME COMPILER
--------------------------------

Written by:       Zoltan Herczeg
Email local part: hzmester
Emain domain:     freemail.hu

Copyright(c) 2009-2017 Zoltan Herczeg
All rights reserved.


THE C++ WRAPPER LIBRARY
-----------------------

Written by:       Google Inc.

Copyright (c) 2007-2012 Google Inc
All rights reserved

####
PK� %[1ⱐ�
�
man/man1/pcre-config.1nu�[���.TH PCRE-CONFIG 1 "01 January 2012" "PCRE 8.30"
.SH NAME
pcre-config - program to return PCRE configuration
.SH SYNOPSIS
.rs
.sp
.nf
.B pcre-config  [--prefix] [--exec-prefix] [--version] [--libs]
.B "            [--libs16] [--libs32] [--libs-cpp] [--libs-posix]"
.B "            [--cflags] [--cflags-posix]"
.fi
.
.
.SH DESCRIPTION
.rs
.sp
\fBpcre-config\fP returns the configuration of the installed PCRE
libraries and the options required to compile a program to use them. Some of
the options apply only to the 8-bit, or 16-bit, or 32-bit libraries,
respectively, and are
not available if only one of those libraries has been built. If an unavailable
option is encountered, the "usage" information is output.
.
.
.SH OPTIONS
.rs
.TP 10
\fB--prefix\fP
Writes the directory prefix used in the PCRE installation for architecture
independent files (\fI/usr\fP on many systems, \fI/usr/local\fP on some
systems) to the standard output.
.TP 10
\fB--exec-prefix\fP
Writes the directory prefix used in the PCRE installation for architecture
dependent files (normally the same as \fB--prefix\fP) to the standard output.
.TP 10
\fB--version\fP
Writes the version number of the installed PCRE libraries to the standard
output.
.TP 10
\fB--libs\fP
Writes to the standard output the command line options required to link
with the 8-bit PCRE library (\fB-lpcre\fP on many systems).
.TP 10
\fB--libs16\fP
Writes to the standard output the command line options required to link
with the 16-bit PCRE library (\fB-lpcre16\fP on many systems).
.TP 10
\fB--libs32\fP
Writes to the standard output the command line options required to link
with the 32-bit PCRE library (\fB-lpcre32\fP on many systems).
.TP 10
\fB--libs-cpp\fP
Writes to the standard output the command line options required to link with
PCRE's C++ wrapper library (\fB-lpcrecpp\fP \fB-lpcre\fP on many
systems).
.TP 10
\fB--libs-posix\fP
Writes to the standard output the command line options required to link with
PCRE's POSIX API wrapper library (\fB-lpcreposix\fP \fB-lpcre\fP on many
systems).
.TP 10
\fB--cflags\fP
Writes to the standard output the command line options required to compile
files that use PCRE (this may include some \fB-I\fP options, but is blank on
many systems).
.TP 10
\fB--cflags-posix\fP
Writes to the standard output the command line options required to compile
files that use PCRE's POSIX API wrapper library (this may include some \fB-I\fP
options, but is blank on many systems).
.
.
.SH "SEE ALSO"
.rs
.sp
\fBpcre(3)\fP
.
.
.SH AUTHOR
.rs
.sp
This manual page was originally written by Mark Baker for the Debian GNU/Linux
system. It has been subsequently revised as a generic PCRE man page.
.
.
.SH REVISION
.rs
.sp
.nf
Last updated: 24 June 2012
.fi
PK� %[<��z�z�man/man1/pcregrep.1nu�[���.TH PCREGREP 1 "03 April 2014" "PCRE 8.35"
.SH NAME
pcregrep - a grep with Perl-compatible regular expressions.
.SH SYNOPSIS
.B pcregrep [options] [long options] [pattern] [path1 path2 ...]
.
.SH DESCRIPTION
.rs
.sp
\fBpcregrep\fP searches files for character patterns, in the same way as other
grep commands do, but it uses the PCRE regular expression library to support
patterns that are compatible with the regular expressions of Perl 5. See
.\" HREF
\fBpcresyntax\fP(3)
.\"
for a quick-reference summary of pattern syntax, or
.\" HREF
\fBpcrepattern\fP(3)
.\"
for a full description of the syntax and semantics of the regular expressions
that PCRE supports.
.P
Patterns, whether supplied on the command line or in a separate file, are given
without delimiters. For example:
.sp
  pcregrep Thursday /etc/motd
.sp
If you attempt to use delimiters (for example, by surrounding a pattern with
slashes, as is common in Perl scripts), they are interpreted as part of the
pattern. Quotes can of course be used to delimit patterns on the command line
because they are interpreted by the shell, and indeed quotes are required if a
pattern contains white space or shell metacharacters.
.P
The first argument that follows any option settings is treated as the single
pattern to be matched when neither \fB-e\fP nor \fB-f\fP is present.
Conversely, when one or both of these options are used to specify patterns, all
arguments are treated as path names. At least one of \fB-e\fP, \fB-f\fP, or an
argument pattern must be provided.
.P
If no files are specified, \fBpcregrep\fP reads the standard input. The
standard input can also be referenced by a name consisting of a single hyphen.
For example:
.sp
  pcregrep some-pattern /file1 - /file3
.sp
By default, each line that matches a pattern is copied to the standard
output, and if there is more than one file, the file name is output at the
start of each line, followed by a colon. However, there are options that can
change how \fBpcregrep\fP behaves. In particular, the \fB-M\fP option makes it
possible to search for patterns that span line boundaries. What defines a line
boundary is controlled by the \fB-N\fP (\fB--newline\fP) option.
.P
The amount of memory used for buffering files that are being scanned is
controlled by a parameter that can be set by the \fB--buffer-size\fP option.
The default value for this parameter is specified when \fBpcregrep\fP is built,
with the default default being 20K. A block of memory three times this size is
used (to allow for buffering "before" and "after" lines). An error occurs if a
line overflows the buffer.
.P
Patterns can be no longer than 8K or BUFSIZ bytes, whichever is the greater.
BUFSIZ is defined in \fB<stdio.h>\fP. When there is more than one pattern
(specified by the use of \fB-e\fP and/or \fB-f\fP), each pattern is applied to
each line in the order in which they are defined, except that all the \fB-e\fP
patterns are tried before the \fB-f\fP patterns.
.P
By default, as soon as one pattern matches a line, no further patterns are
considered. However, if \fB--colour\fP (or \fB--color\fP) is used to colour the
matching substrings, or if \fB--only-matching\fP, \fB--file-offsets\fP, or
\fB--line-offsets\fP is used to output only the part of the line that matched
(either shown literally, or as an offset), scanning resumes immediately
following the match, so that further matches on the same line can be found. If
there are multiple patterns, they are all tried on the remainder of the line,
but patterns that follow the one that matched are not tried on the earlier part
of the line.
.P
This behaviour means that the order in which multiple patterns are specified
can affect the output when one of the above options is used. This is no longer
the same behaviour as GNU grep, which now manages to display earlier matches
for later patterns (as long as there is no overlap).
.P
Patterns that can match an empty string are accepted, but empty string
matches are never recognized. An example is the pattern "(super)?(man)?", in
which all components are optional. This pattern finds all occurrences of both
"super" and "man"; the output differs from matching with "super|man" when only
the matching substrings are being shown.
.P
If the \fBLC_ALL\fP or \fBLC_CTYPE\fP environment variable is set,
\fBpcregrep\fP uses the value to set a locale when calling the PCRE library.
The \fB--locale\fP option can be used to override this.
.
.
.SH "SUPPORT FOR COMPRESSED FILES"
.rs
.sp
It is possible to compile \fBpcregrep\fP so that it uses \fBlibz\fP or
\fBlibbz2\fP to read files whose names end in \fB.gz\fP or \fB.bz2\fP,
respectively. You can find out whether your binary has support for one or both
of these file types by running it with the \fB--help\fP option. If the
appropriate support is not present, files are treated as plain text. The
standard input is always so treated.
.
.
.SH "BINARY FILES"
.rs
.sp
By default, a file that contains a binary zero byte within the first 1024 bytes
is identified as a binary file, and is processed specially. (GNU grep also
identifies binary files in this manner.) See the \fB--binary-files\fP option
for a means of changing the way binary files are handled.
.
.
.SH OPTIONS
.rs
.sp
The order in which some of the options appear can affect the output. For
example, both the \fB-h\fP and \fB-l\fP options affect the printing of file
names. Whichever comes later in the command line will be the one that takes
effect. Similarly, except where noted below, if an option is given twice, the
later setting is used. Numerical values for options may be followed by K or M,
to signify multiplication by 1024 or 1024*1024 respectively.
.TP 10
\fB--\fP
This terminates the list of options. It is useful if the next item on the
command line starts with a hyphen but is not an option. This allows for the
processing of patterns and filenames that start with hyphens.
.TP
\fB-A\fP \fInumber\fP, \fB--after-context=\fP\fInumber\fP
Output \fInumber\fP lines of context after each matching line. If filenames
and/or line numbers are being output, a hyphen separator is used instead of a
colon for the context lines. A line containing "--" is output between each
group of lines, unless they are in fact contiguous in the input file. The value
of \fInumber\fP is expected to be relatively small. However, \fBpcregrep\fP
guarantees to have up to 8K of following text available for context output.
.TP
\fB-a\fP, \fB--text\fP
Treat binary files as text. This is equivalent to
\fB--binary-files\fP=\fItext\fP.
.TP
\fB-B\fP \fInumber\fP, \fB--before-context=\fP\fInumber\fP
Output \fInumber\fP lines of context before each matching line. If filenames
and/or line numbers are being output, a hyphen separator is used instead of a
colon for the context lines. A line containing "--" is output between each
group of lines, unless they are in fact contiguous in the input file. The value
of \fInumber\fP is expected to be relatively small. However, \fBpcregrep\fP
guarantees to have up to 8K of preceding text available for context output.
.TP
\fB--binary-files=\fP\fIword\fP
Specify how binary files are to be processed. If the word is "binary" (the
default), pattern matching is performed on binary files, but the only output is
"Binary file <name> matches" when a match succeeds. If the word is "text",
which is equivalent to the \fB-a\fP or \fB--text\fP option, binary files are
processed in the same way as any other file. In this case, when a match
succeeds, the output may be binary garbage, which can have nasty effects if
sent to a terminal. If the word is "without-match", which is equivalent to the
\fB-I\fP option, binary files are not processed at all; they are assumed not to
be of interest.
.TP
\fB--buffer-size=\fP\fInumber\fP
Set the parameter that controls how much memory is used for buffering files
that are being scanned.
.TP
\fB-C\fP \fInumber\fP, \fB--context=\fP\fInumber\fP
Output \fInumber\fP lines of context both before and after each matching line.
This is equivalent to setting both \fB-A\fP and \fB-B\fP to the same value.
.TP
\fB-c\fP, \fB--count\fP
Do not output individual lines from the files that are being scanned; instead
output the number of lines that would otherwise have been shown. If no lines
are selected, the number zero is output. If several files are are being
scanned, a count is output for each of them. However, if the
\fB--files-with-matches\fP option is also used, only those files whose counts
are greater than zero are listed. When \fB-c\fP is used, the \fB-A\fP,
\fB-B\fP, and \fB-C\fP options are ignored.
.TP
\fB--colour\fP, \fB--color\fP
If this option is given without any data, it is equivalent to "--colour=auto".
If data is required, it must be given in the same shell item, separated by an
equals sign.
.TP
\fB--colour=\fP\fIvalue\fP, \fB--color=\fP\fIvalue\fP
This option specifies under what circumstances the parts of a line that matched
a pattern should be coloured in the output. By default, the output is not
coloured. The value (which is optional, see above) may be "never", "always", or
"auto". In the latter case, colouring happens only if the standard output is
connected to a terminal. More resources are used when colouring is enabled,
because \fBpcregrep\fP has to search for all possible matches in a line, not
just one, in order to colour them all.
.sp
The colour that is used can be specified by setting the environment variable
PCREGREP_COLOUR or PCREGREP_COLOR. The value of this variable should be a
string of two numbers, separated by a semicolon. They are copied directly into
the control string for setting colour on a terminal, so it is your
responsibility to ensure that they make sense. If neither of the environment
variables is set, the default is "1;31", which gives red.
.TP
\fB-D\fP \fIaction\fP, \fB--devices=\fP\fIaction\fP
If an input path is not a regular file or a directory, "action" specifies how
it is to be processed. Valid values are "read" (the default) or "skip"
(silently skip the path).
.TP
\fB-d\fP \fIaction\fP, \fB--directories=\fP\fIaction\fP
If an input path is a directory, "action" specifies how it is to be processed.
Valid values are "read" (the default in non-Windows environments, for
compatibility with GNU grep), "recurse" (equivalent to the \fB-r\fP option), or
"skip" (silently skip the path, the default in Windows environments). In the
"read" case, directories are read as if they were ordinary files. In some
operating systems the effect of reading a directory like this is an immediate
end-of-file; in others it may provoke an error.
.TP
\fB-e\fP \fIpattern\fP, \fB--regex=\fP\fIpattern\fP, \fB--regexp=\fP\fIpattern\fP
Specify a pattern to be matched. This option can be used multiple times in
order to specify several patterns. It can also be used as a way of specifying a
single pattern that starts with a hyphen. When \fB-e\fP is used, no argument
pattern is taken from the command line; all arguments are treated as file
names. There is no limit to the number of patterns. They are applied to each
line in the order in which they are defined until one matches.
.sp
If \fB-f\fP is used with \fB-e\fP, the command line patterns are matched first,
followed by the patterns from the file(s), independent of the order in which
these options are specified. Note that multiple use of \fB-e\fP is not the same
as a single pattern with alternatives. For example, X|Y finds the first
character in a line that is X or Y, whereas if the two patterns are given
separately, with X first, \fBpcregrep\fP finds X if it is present, even if it
follows Y in the line. It finds Y only if there is no X in the line. This
matters only if you are using \fB-o\fP or \fB--colo(u)r\fP to show the part(s)
of the line that matched.
.TP
\fB--exclude\fP=\fIpattern\fP
Files (but not directories) whose names match the pattern are skipped without
being processed. This applies to all files, whether listed on the command line,
obtained from \fB--file-list\fP, or by scanning a directory. The pattern is a
PCRE regular expression, and is matched against the final component of the file
name, not the entire path. The \fB-F\fP, \fB-w\fP, and \fB-x\fP options do not
apply to this pattern. The option may be given any number of times in order to
specify multiple patterns. If a file name matches both an \fB--include\fP
and an \fB--exclude\fP pattern, it is excluded. There is no short form for this
option.
.TP
\fB--exclude-from=\fP\fIfilename\fP
Treat each non-empty line of the file as the data for an \fB--exclude\fP
option. What constitutes a newline when reading the file is the operating
system's default. The \fB--newline\fP option has no effect on this option. This
option may be given more than once in order to specify a number of files to
read.
.TP
\fB--exclude-dir\fP=\fIpattern\fP
Directories whose names match the pattern are skipped without being processed,
whatever the setting of the \fB--recursive\fP option. This applies to all
directories, whether listed on the command line, obtained from
\fB--file-list\fP, or by scanning a parent directory. The pattern is a PCRE
regular expression, and is matched against the final component of the directory
name, not the entire path. The \fB-F\fP, \fB-w\fP, and \fB-x\fP options do not
apply to this pattern. The option may be given any number of times in order to
specify more than one pattern. If a directory matches both \fB--include-dir\fP
and \fB--exclude-dir\fP, it is excluded. There is no short form for this
option.
.TP
\fB-F\fP, \fB--fixed-strings\fP
Interpret each data-matching pattern as a list of fixed strings, separated by
newlines, instead of as a regular expression. What constitutes a newline for
this purpose is controlled by the \fB--newline\fP option. The \fB-w\fP (match
as a word) and \fB-x\fP (match whole line) options can be used with \fB-F\fP.
They apply to each of the fixed strings. A line is selected if any of the fixed
strings are found in it (subject to \fB-w\fP or \fB-x\fP, if present). This
option applies only to the patterns that are matched against the contents of
files; it does not apply to patterns specified by any of the \fB--include\fP or
\fB--exclude\fP options.
.TP
\fB-f\fP \fIfilename\fP, \fB--file=\fP\fIfilename\fP
Read patterns from the file, one per line, and match them against
each line of input. What constitutes a newline when reading the file is the
operating system's default. The \fB--newline\fP option has no effect on this
option. Trailing white space is removed from each line, and blank lines are
ignored. An empty file contains no patterns and therefore matches nothing. See
also the comments about multiple patterns versus a single pattern with
alternatives in the description of \fB-e\fP above.
.sp
If this option is given more than once, all the specified files are
read. A data line is output if any of the patterns match it. A filename can
be given as "-" to refer to the standard input. When \fB-f\fP is used, patterns
specified on the command line using \fB-e\fP may also be present; they are
tested before the file's patterns. However, no other pattern is taken from the
command line; all arguments are treated as the names of paths to be searched.
.TP
\fB--file-list\fP=\fIfilename\fP
Read a list of files and/or directories that are to be scanned from the given
file, one per line. Trailing white space is removed from each line, and blank
lines are ignored. These paths are processed before any that are listed on the
command line. The filename can be given as "-" to refer to the standard input.
If \fB--file\fP and \fB--file-list\fP are both specified as "-", patterns are
read first. This is useful only when the standard input is a terminal, from
which further lines (the list of files) can be read after an end-of-file
indication. If this option is given more than once, all the specified files are
read.
.TP
\fB--file-offsets\fP
Instead of showing lines or parts of lines that match, show each match as an
offset from the start of the file and a length, separated by a comma. In this
mode, no context is shown. That is, the \fB-A\fP, \fB-B\fP, and \fB-C\fP
options are ignored. If there is more than one match in a line, each of them is
shown separately. This option is mutually exclusive with \fB--line-offsets\fP
and \fB--only-matching\fP.
.TP
\fB-H\fP, \fB--with-filename\fP
Force the inclusion of the filename at the start of output lines when searching
a single file. By default, the filename is not shown in this case. For matching
lines, the filename is followed by a colon; for context lines, a hyphen
separator is used. If a line number is also being output, it follows the file
name.
.TP
\fB-h\fP, \fB--no-filename\fP
Suppress the output filenames when searching multiple files. By default,
filenames are shown when multiple files are searched. For matching lines, the
filename is followed by a colon; for context lines, a hyphen separator is used.
If a line number is also being output, it follows the file name.
.TP
\fB--help\fP
Output a help message, giving brief details of the command options and file
type support, and then exit. Anything else on the command line is
ignored.
.TP
\fB-I\fP
Treat binary files as never matching. This is equivalent to
\fB--binary-files\fP=\fIwithout-match\fP.
.TP
\fB-i\fP, \fB--ignore-case\fP
Ignore upper/lower case distinctions during comparisons.
.TP
\fB--include\fP=\fIpattern\fP
If any \fB--include\fP patterns are specified, the only files that are
processed are those that match one of the patterns (and do not match an
\fB--exclude\fP pattern). This option does not affect directories, but it
applies to all files, whether listed on the command line, obtained from
\fB--file-list\fP, or by scanning a directory. The pattern is a PCRE regular
expression, and is matched against the final component of the file name, not
the entire path. The \fB-F\fP, \fB-w\fP, and \fB-x\fP options do not apply to
this pattern. The option may be given any number of times. If a file name
matches both an \fB--include\fP and an \fB--exclude\fP pattern, it is excluded.
There is no short form for this option.
.TP
\fB--include-from=\fP\fIfilename\fP
Treat each non-empty line of the file as the data for an \fB--include\fP
option. What constitutes a newline for this purpose is the operating system's
default. The \fB--newline\fP option has no effect on this option. This option
may be given any number of times; all the files are read.
.TP
\fB--include-dir\fP=\fIpattern\fP
If any \fB--include-dir\fP patterns are specified, the only directories that
are processed are those that match one of the patterns (and do not match an
\fB--exclude-dir\fP pattern). This applies to all directories, whether listed
on the command line, obtained from \fB--file-list\fP, or by scanning a parent
directory. The pattern is a PCRE regular expression, and is matched against the
final component of the directory name, not the entire path. The \fB-F\fP,
\fB-w\fP, and \fB-x\fP options do not apply to this pattern. The option may be
given any number of times. If a directory matches both \fB--include-dir\fP and
\fB--exclude-dir\fP, it is excluded. There is no short form for this option.
.TP
\fB-L\fP, \fB--files-without-match\fP
Instead of outputting lines from the files, just output the names of the files
that do not contain any lines that would have been output. Each file name is
output once, on a separate line.
.TP
\fB-l\fP, \fB--files-with-matches\fP
Instead of outputting lines from the files, just output the names of the files
containing lines that would have been output. Each file name is output
once, on a separate line. Searching normally stops as soon as a matching line
is found in a file. However, if the \fB-c\fP (count) option is also used,
matching continues in order to obtain the correct count, and those files that
have at least one match are listed along with their counts. Using this option
with \fB-c\fP is a way of suppressing the listing of files with no matches.
.TP
\fB--label\fP=\fIname\fP
This option supplies a name to be used for the standard input when file names
are being output. If not supplied, "(standard input)" is used. There is no
short form for this option.
.TP
\fB--line-buffered\fP
When this option is given, input is read and processed line by line, and the
output is flushed after each write. By default, input is read in large chunks,
unless \fBpcregrep\fP can determine that it is reading from a terminal (which
is currently possible only in Unix-like environments). Output to terminal is
normally automatically flushed by the operating system. This option can be
useful when the input or output is attached to a pipe and you do not want
\fBpcregrep\fP to buffer up large amounts of data. However, its use will affect
performance, and the \fB-M\fP (multiline) option ceases to work.
.TP
\fB--line-offsets\fP
Instead of showing lines or parts of lines that match, show each match as a
line number, the offset from the start of the line, and a length. The line
number is terminated by a colon (as usual; see the \fB-n\fP option), and the
offset and length are separated by a comma. In this mode, no context is shown.
That is, the \fB-A\fP, \fB-B\fP, and \fB-C\fP options are ignored. If there is
more than one match in a line, each of them is shown separately. This option is
mutually exclusive with \fB--file-offsets\fP and \fB--only-matching\fP.
.TP
\fB--locale\fP=\fIlocale-name\fP
This option specifies a locale to be used for pattern matching. It overrides
the value in the \fBLC_ALL\fP or \fBLC_CTYPE\fP environment variables. If no
locale is specified, the PCRE library's default (usually the "C" locale) is
used. There is no short form for this option.
.TP
\fB--match-limit\fP=\fInumber\fP
Processing some regular expression patterns can require a very large amount of
memory, leading in some cases to a program crash if not enough is available.
Other patterns may take a very long time to search for all possible matching
strings. The \fBpcre_exec()\fP function that is called by \fBpcregrep\fP to do
the matching has two parameters that can limit the resources that it uses.
.sp
The \fB--match-limit\fP option provides a means of limiting resource usage
when processing patterns that are not going to match, but which have a very
large number of possibilities in their search trees. The classic example is a
pattern that uses nested unlimited repeats. Internally, PCRE uses a function
called \fBmatch()\fP which it calls repeatedly (sometimes recursively). The
limit set by \fB--match-limit\fP is imposed on the number of times this
function is called during a match, which has the effect of limiting the amount
of backtracking that can take place.
.sp
The \fB--recursion-limit\fP option is similar to \fB--match-limit\fP, but
instead of limiting the total number of times that \fBmatch()\fP is called, it
limits the depth of recursive calls, which in turn limits the amount of memory
that can be used. The recursion depth is a smaller number than the total number
of calls, because not all calls to \fBmatch()\fP are recursive. This limit is
of use only if it is set smaller than \fB--match-limit\fP.
.sp
There are no short forms for these options. The default settings are specified
when the PCRE library is compiled, with the default default being 10 million.
.TP
\fB-M\fP, \fB--multiline\fP
Allow patterns to match more than one line. When this option is given, patterns
may usefully contain literal newline characters and internal occurrences of ^
and $ characters. The output for a successful match may consist of more than
one line, the last of which is the one in which the match ended. If the matched
string ends with a newline sequence the output ends at the end of that line.
.sp
When this option is set, the PCRE library is called in "multiline" mode.
There is a limit to the number of lines that can be matched, imposed by the way
that \fBpcregrep\fP buffers the input file as it scans it. However,
\fBpcregrep\fP ensures that at least 8K characters or the rest of the document
(whichever is the shorter) are available for forward matching, and similarly
the previous 8K characters (or all the previous characters, if fewer than 8K)
are guaranteed to be available for lookbehind assertions. This option does not
work when input is read line by line (see \fP--line-buffered\fP.)
.TP
\fB-N\fP \fInewline-type\fP, \fB--newline\fP=\fInewline-type\fP
The PCRE library supports five different conventions for indicating
the ends of lines. They are the single-character sequences CR (carriage return)
and LF (linefeed), the two-character sequence CRLF, an "anycrlf" convention,
which recognizes any of the preceding three types, and an "any" convention, in
which any Unicode line ending sequence is assumed to end a line. The Unicode
sequences are the three just mentioned, plus VT (vertical tab, U+000B), FF
(form feed, U+000C), NEL (next line, U+0085), LS (line separator, U+2028), and
PS (paragraph separator, U+2029).
.sp
When the PCRE library is built, a default line-ending sequence is specified.
This is normally the standard sequence for the operating system. Unless
otherwise specified by this option, \fBpcregrep\fP uses the library's default.
The possible values for this option are CR, LF, CRLF, ANYCRLF, or ANY. This
makes it possible to use \fBpcregrep\fP to scan files that have come from other
environments without having to modify their line endings. If the data that is
being scanned does not agree with the convention set by this option,
\fBpcregrep\fP may behave in strange ways. Note that this option does not
apply to files specified by the \fB-f\fP, \fB--exclude-from\fP, or
\fB--include-from\fP options, which are expected to use the operating system's
standard newline sequence.
.TP
\fB-n\fP, \fB--line-number\fP
Precede each output line by its line number in the file, followed by a colon
for matching lines or a hyphen for context lines. If the filename is also being
output, it precedes the line number. This option is forced if
\fB--line-offsets\fP is used.
.TP
\fB--no-jit\fP
If the PCRE library is built with support for just-in-time compiling (which
speeds up matching), \fBpcregrep\fP automatically makes use of this, unless it
was explicitly disabled at build time. This option can be used to disable the
use of JIT at run time. It is provided for testing and working round problems.
It should never be needed in normal use.
.TP
\fB-o\fP, \fB--only-matching\fP
Show only the part of the line that matched a pattern instead of the whole
line. In this mode, no context is shown. That is, the \fB-A\fP, \fB-B\fP, and
\fB-C\fP options are ignored. If there is more than one match in a line, each
of them is shown separately. If \fB-o\fP is combined with \fB-v\fP (invert the
sense of the match to find non-matching lines), no output is generated, but the
return code is set appropriately. If the matched portion of the line is empty,
nothing is output unless the file name or line number are being printed, in
which case they are shown on an otherwise empty line. This option is mutually
exclusive with \fB--file-offsets\fP and \fB--line-offsets\fP.
.TP
\fB-o\fP\fInumber\fP, \fB--only-matching\fP=\fInumber\fP
Show only the part of the line that matched the capturing parentheses of the
given number. Up to 32 capturing parentheses are supported, and -o0 is
equivalent to \fB-o\fP without a number. Because these options can be given
without an argument (see above), if an argument is present, it must be given in
the same shell item, for example, -o3 or --only-matching=2. The comments given
for the non-argument case above also apply to this case. If the specified
capturing parentheses do not exist in the pattern, or were not set in the
match, nothing is output unless the file name or line number are being printed.
.sp
If this option is given multiple times, multiple substrings are output, in the
order the options are given. For example, -o3 -o1 -o3 causes the substrings
matched by capturing parentheses 3 and 1 and then 3 again to be output. By
default, there is no separator (but see the next option).
.TP
\fB--om-separator\fP=\fItext\fP
Specify a separating string for multiple occurrences of \fB-o\fP. The default
is an empty string. Separating strings are never coloured.
.TP
\fB-q\fP, \fB--quiet\fP
Work quietly, that is, display nothing except error messages. The exit
status indicates whether or not any matches were found.
.TP
\fB-r\fP, \fB--recursive\fP
If any given path is a directory, recursively scan the files it contains,
taking note of any \fB--include\fP and \fB--exclude\fP settings. By default, a
directory is read as a normal file; in some operating systems this gives an
immediate end-of-file. This option is a shorthand for setting the \fB-d\fP
option to "recurse".
.TP
\fB--recursion-limit\fP=\fInumber\fP
See \fB--match-limit\fP above.
.TP
\fB-s\fP, \fB--no-messages\fP
Suppress error messages about non-existent or unreadable files. Such files are
quietly skipped. However, the return code is still 2, even if matches were
found in other files.
.TP
\fB-u\fP, \fB--utf-8\fP
Operate in UTF-8 mode. This option is available only if PCRE has been compiled
with UTF-8 support. All patterns (including those for any \fB--exclude\fP and
\fB--include\fP options) and all subject lines that are scanned must be valid
strings of UTF-8 characters.
.TP
\fB-V\fP, \fB--version\fP
Write the version numbers of \fBpcregrep\fP and the PCRE library to the
standard output and then exit. Anything else on the command line is
ignored.
.TP
\fB-v\fP, \fB--invert-match\fP
Invert the sense of the match, so that lines which do \fInot\fP match any of
the patterns are the ones that are found.
.TP
\fB-w\fP, \fB--word-regex\fP, \fB--word-regexp\fP
Force the patterns to match only whole words. This is equivalent to having \eb
at the start and end of the pattern. This option applies only to the patterns
that are matched against the contents of files; it does not apply to patterns
specified by any of the \fB--include\fP or \fB--exclude\fP options.
.TP
\fB-x\fP, \fB--line-regex\fP, \fB--line-regexp\fP
Force the patterns to be anchored (each must start matching at the beginning of
a line) and in addition, require them to match entire lines. This is equivalent
to having ^ and $ characters at the start and end of each alternative branch in
every pattern. This option applies only to the patterns that are matched
against the contents of files; it does not apply to patterns specified by any
of the \fB--include\fP or \fB--exclude\fP options.
.
.
.SH "ENVIRONMENT VARIABLES"
.rs
.sp
The environment variables \fBLC_ALL\fP and \fBLC_CTYPE\fP are examined, in that
order, for a locale. The first one that is set is used. This can be overridden
by the \fB--locale\fP option. If no locale is set, the PCRE library's default
(usually the "C" locale) is used.
.
.
.SH "NEWLINES"
.rs
.sp
The \fB-N\fP (\fB--newline\fP) option allows \fBpcregrep\fP to scan files with
different newline conventions from the default. Any parts of the input files
that are written to the standard output are copied identically, with whatever
newline sequences they have in the input. However, the setting of this option
does not affect the interpretation of files specified by the \fB-f\fP,
\fB--exclude-from\fP, or \fB--include-from\fP options, which are assumed to use
the operating system's standard newline sequence, nor does it affect the way in
which \fBpcregrep\fP writes informational messages to the standard error and
output streams. For these it uses the string "\en" to indicate newlines,
relying on the C I/O library to convert this to an appropriate sequence.
.
.
.SH "OPTIONS COMPATIBILITY"
.rs
.sp
Many of the short and long forms of \fBpcregrep\fP's options are the same
as in the GNU \fBgrep\fP program. Any long option of the form
\fB--xxx-regexp\fP (GNU terminology) is also available as \fB--xxx-regex\fP
(PCRE terminology). However, the \fB--file-list\fP, \fB--file-offsets\fP,
\fB--include-dir\fP, \fB--line-offsets\fP, \fB--locale\fP, \fB--match-limit\fP,
\fB-M\fP, \fB--multiline\fP, \fB-N\fP, \fB--newline\fP, \fB--om-separator\fP,
\fB--recursion-limit\fP, \fB-u\fP, and \fB--utf-8\fP options are specific to
\fBpcregrep\fP, as is the use of the \fB--only-matching\fP option with a
capturing parentheses number.
.P
Although most of the common options work the same way, a few are different in
\fBpcregrep\fP. For example, the \fB--include\fP option's argument is a glob
for GNU \fBgrep\fP, but a regular expression for \fBpcregrep\fP. If both the
\fB-c\fP and \fB-l\fP options are given, GNU grep lists only file names,
without counts, but \fBpcregrep\fP gives the counts.
.
.
.SH "OPTIONS WITH DATA"
.rs
.sp
There are four different ways in which an option with data can be specified.
If a short form option is used, the data may follow immediately, or (with one
exception) in the next command line item. For example:
.sp
  -f/some/file
  -f /some/file
.sp
The exception is the \fB-o\fP option, which may appear with or without data.
Because of this, if data is present, it must follow immediately in the same
item, for example -o3.
.P
If a long form option is used, the data may appear in the same command line
item, separated by an equals character, or (with two exceptions) it may appear
in the next command line item. For example:
.sp
  --file=/some/file
  --file /some/file
.sp
Note, however, that if you want to supply a file name beginning with ~ as data
in a shell command, and have the shell expand ~ to a home directory, you must
separate the file name from the option, because the shell does not treat ~
specially unless it is at the start of an item.
.P
The exceptions to the above are the \fB--colour\fP (or \fB--color\fP) and
\fB--only-matching\fP options, for which the data is optional. If one of these
options does have data, it must be given in the first form, using an equals
character. Otherwise \fBpcregrep\fP will assume that it has no data.
.
.
.SH "MATCHING ERRORS"
.rs
.sp
It is possible to supply a regular expression that takes a very long time to
fail to match certain lines. Such patterns normally involve nested indefinite
repeats, for example: (a+)*\ed when matched against a line of a's with no final
digit. The PCRE matching function has a resource limit that causes it to abort
in these circumstances. If this happens, \fBpcregrep\fP outputs an error
message and the line that caused the problem to the standard error stream. If
there are more than 20 such errors, \fBpcregrep\fP gives up.
.P
The \fB--match-limit\fP option of \fBpcregrep\fP can be used to set the overall
resource limit; there is a second option called \fB--recursion-limit\fP that
sets a limit on the amount of memory (usually stack) that is used (see the
discussion of these options above).
.
.
.SH DIAGNOSTICS
.rs
.sp
Exit status is 0 if any matches were found, 1 if no matches were found, and 2
for syntax errors, overlong lines, non-existent or inaccessible files (even if
matches were found in other files) or too many matching errors. Using the
\fB-s\fP option to suppress error messages about inaccessible files does not
affect the return code.
.
.
.SH "SEE ALSO"
.rs
.sp
\fBpcrepattern\fP(3), \fBpcresyntax\fP(3), \fBpcretest\fP(1).
.
.
.SH AUTHOR
.rs
.sp
.nf
Philip Hazel
University Computing Service
Cambridge CB2 3QH, England.
.fi
.
.
.SH REVISION
.rs
.sp
.nf
Last updated: 03 April 2014
Copyright (c) 1997-2014 University of Cambridge.
.fi
PK� %[��0�0�man/man1/pcretest.1nu�[���.TH PCRETEST 1 "23 February 2017" "PCRE 8.41"
.SH NAME
pcretest - a program for testing Perl-compatible regular expressions.
.SH SYNOPSIS
.rs
.sp
.B pcretest "[options] [input file [output file]]"
.sp
\fBpcretest\fP was written as a test program for the PCRE regular expression
library itself, but it can also be used for experimenting with regular
expressions. This document describes the features of the test program; for
details of the regular expressions themselves, see the
.\" HREF
\fBpcrepattern\fP
.\"
documentation. For details of the PCRE library function calls and their
options, see the
.\" HREF
\fBpcreapi\fP
.\"
,
.\" HREF
\fBpcre16\fP
and
.\" HREF
\fBpcre32\fP
.\"
documentation.
.P
The input for \fBpcretest\fP is a sequence of regular expression patterns and
strings to be matched, as described below. The output shows the result of each
match. Options on the command line and the patterns control PCRE options and
exactly what is output.
.P
As PCRE has evolved, it has acquired many different features, and as a result,
\fBpcretest\fP now has rather a lot of obscure options for testing every
possible feature. Some of these options are specifically designed for use in
conjunction with the test script and data files that are distributed as part of
PCRE, and are unlikely to be of use otherwise. They are all documented here,
but without much justification.
.
.
.SH "INPUT DATA FORMAT"
.rs
.sp
Input to \fBpcretest\fP is processed line by line, either by calling the C
library's \fBfgets()\fP function, or via the \fBlibreadline\fP library (see
below). In Unix-like environments, \fBfgets()\fP treats any bytes other than
newline as data characters. However, in some Windows environments character 26
(hex 1A) causes an immediate end of file, and no further data is read. For
maximum portability, therefore, it is safest to use only ASCII characters in
\fBpcretest\fP input files.
.P
The input is processed using using C's string functions, so must not
contain binary zeroes, even though in Unix-like environments, \fBfgets()\fP
treats any bytes other than newline as data characters.
.
.
.SH "PCRE's 8-BIT, 16-BIT AND 32-BIT LIBRARIES"
.rs
.sp
From release 8.30, two separate PCRE libraries can be built. The original one
supports 8-bit character strings, whereas the newer 16-bit library supports
character strings encoded in 16-bit units. From release 8.32, a third library
can be built, supporting character strings encoded in 32-bit units. The
\fBpcretest\fP program can be used to test all three libraries. However, it is
itself still an 8-bit program, reading 8-bit input and writing 8-bit output.
When testing the 16-bit or 32-bit library, the patterns and data strings are
converted to 16- or 32-bit format before being passed to the PCRE library
functions. Results are converted to 8-bit for output.
.P
References to functions and structures of the form \fBpcre[16|32]_xx\fP below
mean "\fBpcre_xx\fP when using the 8-bit library, \fBpcre16_xx\fP when using
the 16-bit library, or \fBpcre32_xx\fP when using the 32-bit library".
.
.
.SH "COMMAND LINE OPTIONS"
.rs
.TP 10
\fB-8\fP
If both the 8-bit library has been built, this option causes the 8-bit library
to be used (which is the default); if the 8-bit library has not been built,
this option causes an error.
.TP 10
\fB-16\fP
If both the 8-bit or the 32-bit, and the 16-bit libraries have been built, this
option causes the 16-bit library to be used. If only the 16-bit library has been
built, this is the default (so has no effect). If only the 8-bit or the 32-bit
library has been built, this option causes an error.
.TP 10
\fB-32\fP
If both the 8-bit or the 16-bit, and the 32-bit libraries have been built, this
option causes the 32-bit library to be used. If only the 32-bit library has been
built, this is the default (so has no effect). If only the 8-bit or the 16-bit
library has been built, this option causes an error.
.TP 10
\fB-b\fP
Behave as if each pattern has the \fB/B\fP (show byte code) modifier; the
internal form is output after compilation.
.TP 10
\fB-C\fP
Output the version number of the PCRE library, and all available information
about the optional features that are included, and then exit with zero exit
code. All other options are ignored.
.TP 10
\fB-C\fP \fIoption\fP
Output information about a specific build-time option, then exit. This
functionality is intended for use in scripts such as \fBRunTest\fP. The
following options output the value and set the exit code as indicated:
.sp
  ebcdic-nl  the code for LF (= NL) in an EBCDIC environment:
               0x15 or 0x25
               0 if used in an ASCII environment
               exit code is always 0
  linksize   the configured internal link size (2, 3, or 4)
               exit code is set to the link size
  newline    the default newline setting:
               CR, LF, CRLF, ANYCRLF, or ANY
               exit code is always 0
  bsr        the default setting for what \eR matches:
               ANYCRLF or ANY
               exit code is always 0
.sp
The following options output 1 for true or 0 for false, and set the exit code
to the same value:
.sp
  ebcdic     compiled for an EBCDIC environment
  jit        just-in-time support is available
  pcre16     the 16-bit library was built
  pcre32     the 32-bit library was built
  pcre8      the 8-bit library was built
  ucp        Unicode property support is available
  utf        UTF-8 and/or UTF-16 and/or UTF-32 support
               is available
.sp
If an unknown option is given, an error message is output; the exit code is 0.
.TP 10
\fB-d\fP
Behave as if each pattern has the \fB/D\fP (debug) modifier; the internal
form and information about the compiled pattern is output after compilation;
\fB-d\fP is equivalent to \fB-b -i\fP.
.TP 10
\fB-dfa\fP
Behave as if each data line contains the \eD escape sequence; this causes the
alternative matching function, \fBpcre[16|32]_dfa_exec()\fP, to be used instead
of the standard \fBpcre[16|32]_exec()\fP function (more detail is given below).
.TP 10
\fB-help\fP
Output a brief summary these options and then exit.
.TP 10
\fB-i\fP
Behave as if each pattern has the \fB/I\fP modifier; information about the
compiled pattern is given after compilation.
.TP 10
\fB-M\fP
Behave as if each data line contains the \eM escape sequence; this causes
PCRE to discover the minimum MATCH_LIMIT and MATCH_LIMIT_RECURSION settings by
calling \fBpcre[16|32]_exec()\fP repeatedly with different limits.
.TP 10
\fB-m\fP
Output the size of each compiled pattern after it has been compiled. This is
equivalent to adding \fB/M\fP to each regular expression. The size is given in
bytes for both libraries.
.TP 10
\fB-O\fP
Behave as if each pattern has the \fB/O\fP modifier, that is disable
auto-possessification for all patterns.
.TP 10
\fB-o\fP \fIosize\fP
Set the number of elements in the output vector that is used when calling
\fBpcre[16|32]_exec()\fP or \fBpcre[16|32]_dfa_exec()\fP to be \fIosize\fP. The
default value is 45, which is enough for 14 capturing subexpressions for
\fBpcre[16|32]_exec()\fP or 22 different matches for
\fBpcre[16|32]_dfa_exec()\fP.
The vector size can be changed for individual matching calls by including \eO
in the data line (see below).
.TP 10
\fB-p\fP
Behave as if each pattern has the \fB/P\fP modifier; the POSIX wrapper API is
used to call PCRE. None of the other options has any effect when \fB-p\fP is
set. This option can be used only with the 8-bit library.
.TP 10
\fB-q\fP
Do not output the version number of \fBpcretest\fP at the start of execution.
.TP 10
\fB-S\fP \fIsize\fP
On Unix-like systems, set the size of the run-time stack to \fIsize\fP
megabytes.
.TP 10
\fB-s\fP or \fB-s+\fP
Behave as if each pattern has the \fB/S\fP modifier; in other words, force each
pattern to be studied. If \fB-s+\fP is used, all the JIT compile options are
passed to \fBpcre[16|32]_study()\fP, causing just-in-time optimization to be set
up if it is available, for both full and partial matching. Specific JIT compile
options can be selected by following \fB-s+\fP with a digit in the range 1 to
7, which selects the JIT compile modes as follows:
.sp
  1  normal match only
  2  soft partial match only
  3  normal match and soft partial match
  4  hard partial match only
  6  soft and hard partial match
  7  all three modes (default)
.sp
If \fB-s++\fP is used instead of \fB-s+\fP (with or without a following digit),
the text "(JIT)" is added to the first output line after a match or no match
when JIT-compiled code was actually used.
.sp
Note that there are pattern options that can override \fB-s\fP, either
specifying no studying at all, or suppressing JIT compilation.
.sp
If the \fB/I\fP or \fB/D\fP option is present on a pattern (requesting output
about the compiled pattern), information about the result of studying is not
included when studying is caused only by \fB-s\fP and neither \fB-i\fP nor
\fB-d\fP is present on the command line. This behaviour means that the output
from tests that are run with and without \fB-s\fP should be identical, except
when options that output information about the actual running of a match are
set.
.sp
The \fB-M\fP, \fB-t\fP, and \fB-tm\fP options, which give information about
resources used, are likely to produce different output with and without
\fB-s\fP. Output may also differ if the \fB/C\fP option is present on an
individual pattern. This uses callouts to trace the the matching process, and
this may be different between studied and non-studied patterns. If the pattern
contains (*MARK) items there may also be differences, for the same reason. The
\fB-s\fP command line option can be overridden for specific patterns that
should never be studied (see the \fB/S\fP pattern modifier below).
.TP 10
\fB-t\fP
Run each compile, study, and match many times with a timer, and output the
resulting times per compile, study, or match (in milliseconds). Do not set
\fB-m\fP with \fB-t\fP, because you will then get the size output a zillion
times, and the timing will be distorted. You can control the number of
iterations that are used for timing by following \fB-t\fP with a number (as a
separate item on the command line). For example, "-t 1000" iterates 1000 times.
The default is to iterate 500000 times.
.TP 10
\fB-tm\fP
This is like \fB-t\fP except that it times only the matching phase, not the
compile or study phases.
.TP 10
\fB-T\fP \fB-TM\fP
These behave like \fB-t\fP and \fB-tm\fP, but in addition, at the end of a run,
the total times for all compiles, studies, and matches are output.
.
.
.SH DESCRIPTION
.rs
.sp
If \fBpcretest\fP is given two filename arguments, it reads from the first and
writes to the second. If it is given only one filename argument, it reads from
that file and writes to stdout. Otherwise, it reads from stdin and writes to
stdout, and prompts for each line of input, using "re>" to prompt for regular
expressions, and "data>" to prompt for data lines.
.P
When \fBpcretest\fP is built, a configuration option can specify that it should
be linked with the \fBlibreadline\fP library. When this is done, if the input
is from a terminal, it is read using the \fBreadline()\fP function. This
provides line-editing and history facilities. The output from the \fB-help\fP
option states whether or not \fBreadline()\fP will be used.
.P
The program handles any number of sets of input on a single input file. Each
set starts with a regular expression, and continues with any number of data
lines to be matched against that pattern.
.P
Each data line is matched separately and independently. If you want to do
multi-line matches, you have to use the \en escape sequence (or \er or \er\en,
etc., depending on the newline setting) in a single line of input to encode the
newline sequences. There is no limit on the length of data lines; the input
buffer is automatically extended if it is too small.
.P
An empty line signals the end of the data lines, at which point a new regular
expression is read. The regular expressions are given enclosed in any
non-alphanumeric delimiters other than backslash, for example:
.sp
  /(a|bc)x+yz/
.sp
White space before the initial delimiter is ignored. A regular expression may
be continued over several input lines, in which case the newline characters are
included within it. It is possible to include the delimiter within the pattern
by escaping it, for example
.sp
  /abc\e/def/
.sp
If you do so, the escape and the delimiter form part of the pattern, but since
delimiters are always non-alphanumeric, this does not affect its interpretation.
If the terminating delimiter is immediately followed by a backslash, for
example,
.sp
  /abc/\e
.sp
then a backslash is added to the end of the pattern. This is done to provide a
way of testing the error condition that arises if a pattern finishes with a
backslash, because
.sp
  /abc\e/
.sp
is interpreted as the first line of a pattern that starts with "abc/", causing
pcretest to read the next line as a continuation of the regular expression.
.
.
.SH "PATTERN MODIFIERS"
.rs
.sp
A pattern may be followed by any number of modifiers, which are mostly single
characters, though some of these can be qualified by further characters.
Following Perl usage, these are referred to below as, for example, "the
\fB/i\fP modifier", even though the delimiter of the pattern need not always be
a slash, and no slash is used when writing modifiers. White space may appear
between the final pattern delimiter and the first modifier, and between the
modifiers themselves. For reference, here is a complete list of modifiers. They
fall into several groups that are described in detail in the following
sections.
.sp
  \fB/8\fP              set UTF mode
  \fB/9\fP              set PCRE_NEVER_UTF (locks out UTF mode)
  \fB/?\fP              disable UTF validity check
  \fB/+\fP              show remainder of subject after match
  \fB/=\fP              show all captures (not just those that are set)
.sp
  \fB/A\fP              set PCRE_ANCHORED
  \fB/B\fP              show compiled code
  \fB/C\fP              set PCRE_AUTO_CALLOUT
  \fB/D\fP              same as \fB/B\fP plus \fB/I\fP
  \fB/E\fP              set PCRE_DOLLAR_ENDONLY
  \fB/F\fP              flip byte order in compiled pattern
  \fB/f\fP              set PCRE_FIRSTLINE
  \fB/G\fP              find all matches (shorten string)
  \fB/g\fP              find all matches (use startoffset)
  \fB/I\fP              show information about pattern
  \fB/i\fP              set PCRE_CASELESS
  \fB/J\fP              set PCRE_DUPNAMES
  \fB/K\fP              show backtracking control names
  \fB/L\fP              set locale
  \fB/M\fP              show compiled memory size
  \fB/m\fP              set PCRE_MULTILINE
  \fB/N\fP              set PCRE_NO_AUTO_CAPTURE
  \fB/O\fP              set PCRE_NO_AUTO_POSSESS
  \fB/P\fP              use the POSIX wrapper
  \fB/Q\fP              test external stack check function
  \fB/S\fP              study the pattern after compilation
  \fB/s\fP              set PCRE_DOTALL
  \fB/T\fP              select character tables
  \fB/U\fP              set PCRE_UNGREEDY
  \fB/W\fP              set PCRE_UCP
  \fB/X\fP              set PCRE_EXTRA
  \fB/x\fP              set PCRE_EXTENDED
  \fB/Y\fP              set PCRE_NO_START_OPTIMIZE
  \fB/Z\fP              don't show lengths in \fB/B\fP output
.sp
  \fB/<any>\fP          set PCRE_NEWLINE_ANY
  \fB/<anycrlf>\fP      set PCRE_NEWLINE_ANYCRLF
  \fB/<cr>\fP           set PCRE_NEWLINE_CR
  \fB/<crlf>\fP         set PCRE_NEWLINE_CRLF
  \fB/<lf>\fP           set PCRE_NEWLINE_LF
  \fB/<bsr_anycrlf>\fP  set PCRE_BSR_ANYCRLF
  \fB/<bsr_unicode>\fP  set PCRE_BSR_UNICODE
  \fB/<JS>\fP           set PCRE_JAVASCRIPT_COMPAT
.sp
.
.
.SS "Perl-compatible modifiers"
.rs
.sp
The \fB/i\fP, \fB/m\fP, \fB/s\fP, and \fB/x\fP modifiers set the PCRE_CASELESS,
PCRE_MULTILINE, PCRE_DOTALL, or PCRE_EXTENDED options, respectively, when
\fBpcre[16|32]_compile()\fP is called. These four modifier letters have the same
effect as they do in Perl. For example:
.sp
  /caseless/i
.sp
.
.
.SS "Modifiers for other PCRE options"
.rs
.sp
The following table shows additional modifiers for setting PCRE compile-time
options that do not correspond to anything in Perl:
.sp
  \fB/8\fP              PCRE_UTF8           ) when using the 8-bit
  \fB/?\fP              PCRE_NO_UTF8_CHECK  )   library
.sp
  \fB/8\fP              PCRE_UTF16          ) when using the 16-bit
  \fB/?\fP              PCRE_NO_UTF16_CHECK )   library
.sp
  \fB/8\fP              PCRE_UTF32          ) when using the 32-bit
  \fB/?\fP              PCRE_NO_UTF32_CHECK )   library
.sp
  \fB/9\fP              PCRE_NEVER_UTF
  \fB/A\fP              PCRE_ANCHORED
  \fB/C\fP              PCRE_AUTO_CALLOUT
  \fB/E\fP              PCRE_DOLLAR_ENDONLY
  \fB/f\fP              PCRE_FIRSTLINE
  \fB/J\fP              PCRE_DUPNAMES
  \fB/N\fP              PCRE_NO_AUTO_CAPTURE
  \fB/O\fP              PCRE_NO_AUTO_POSSESS
  \fB/U\fP              PCRE_UNGREEDY
  \fB/W\fP              PCRE_UCP
  \fB/X\fP              PCRE_EXTRA
  \fB/Y\fP              PCRE_NO_START_OPTIMIZE
  \fB/<any>\fP          PCRE_NEWLINE_ANY
  \fB/<anycrlf>\fP      PCRE_NEWLINE_ANYCRLF
  \fB/<cr>\fP           PCRE_NEWLINE_CR
  \fB/<crlf>\fP         PCRE_NEWLINE_CRLF
  \fB/<lf>\fP           PCRE_NEWLINE_LF
  \fB/<bsr_anycrlf>\fP  PCRE_BSR_ANYCRLF
  \fB/<bsr_unicode>\fP  PCRE_BSR_UNICODE
  \fB/<JS>\fP           PCRE_JAVASCRIPT_COMPAT
.sp
The modifiers that are enclosed in angle brackets are literal strings as shown,
including the angle brackets, but the letters within can be in either case.
This example sets multiline matching with CRLF as the line ending sequence:
.sp
  /^abc/m<CRLF>
.sp
As well as turning on the PCRE_UTF8/16/32 option, the \fB/8\fP modifier causes
all non-printing characters in output strings to be printed using the
\ex{hh...} notation. Otherwise, those less than 0x100 are output in hex without
the curly brackets.
.P
Full details of the PCRE options are given in the
.\" HREF
\fBpcreapi\fP
.\"
documentation.
.
.
.SS "Finding all matches in a string"
.rs
.sp
Searching for all possible matches within each subject string can be requested
by the \fB/g\fP or \fB/G\fP modifier. After finding a match, PCRE is called
again to search the remainder of the subject string. The difference between
\fB/g\fP and \fB/G\fP is that the former uses the \fIstartoffset\fP argument to
\fBpcre[16|32]_exec()\fP to start searching at a new point within the entire
string (which is in effect what Perl does), whereas the latter passes over a
shortened substring. This makes a difference to the matching process if the
pattern begins with a lookbehind assertion (including \eb or \eB).
.P
If any call to \fBpcre[16|32]_exec()\fP in a \fB/g\fP or \fB/G\fP sequence matches
an empty string, the next call is done with the PCRE_NOTEMPTY_ATSTART and
PCRE_ANCHORED flags set in order to search for another, non-empty, match at the
same point. If this second match fails, the start offset is advanced, and the
normal match is retried. This imitates the way Perl handles such cases when
using the \fB/g\fP modifier or the \fBsplit()\fP function. Normally, the start
offset is advanced by one character, but if the newline convention recognizes
CRLF as a newline, and the current character is CR followed by LF, an advance
of two is used.
.
.
.SS "Other modifiers"
.rs
.sp
There are yet more modifiers for controlling the way \fBpcretest\fP
operates.
.P
The \fB/+\fP modifier requests that as well as outputting the substring that
matched the entire pattern, \fBpcretest\fP should in addition output the
remainder of the subject string. This is useful for tests where the subject
contains multiple copies of the same substring. If the \fB+\fP modifier appears
twice, the same action is taken for captured substrings. In each case the
remainder is output on the following line with a plus character following the
capture number. Note that this modifier must not immediately follow the /S
modifier because /S+ and /S++ have other meanings.
.P
The \fB/=\fP modifier requests that the values of all potential captured
parentheses be output after a match. By default, only those up to the highest
one actually used in the match are output (corresponding to the return code
from \fBpcre[16|32]_exec()\fP). Values in the offsets vector corresponding to
higher numbers should be set to -1, and these are output as "<unset>". This
modifier gives a way of checking that this is happening.
.P
The \fB/B\fP modifier is a debugging feature. It requests that \fBpcretest\fP
output a representation of the compiled code after compilation. Normally this
information contains length and offset values; however, if \fB/Z\fP is also
present, this data is replaced by spaces. This is a special feature for use in
the automatic test scripts; it ensures that the same output is generated for
different internal link sizes.
.P
The \fB/D\fP modifier is a PCRE debugging feature, and is equivalent to
\fB/BI\fP, that is, both the \fB/B\fP and the \fB/I\fP modifiers.
.P
The \fB/F\fP modifier causes \fBpcretest\fP to flip the byte order of the
2-byte and 4-byte fields in the compiled pattern. This facility is for testing
the feature in PCRE that allows it to execute patterns that were compiled on a
host with a different endianness. This feature is not available when the POSIX
interface to PCRE is being used, that is, when the \fB/P\fP pattern modifier is
specified. See also the section about saving and reloading compiled patterns
below.
.P
The \fB/I\fP modifier requests that \fBpcretest\fP output information about the
compiled pattern (whether it is anchored, has a fixed first character, and
so on). It does this by calling \fBpcre[16|32]_fullinfo()\fP after compiling a
pattern. If the pattern is studied, the results of that are also output. In
this output, the word "char" means a non-UTF character, that is, the value of a
single data item (8-bit, 16-bit, or 32-bit, depending on the library that is
being tested).
.P
The \fB/K\fP modifier requests \fBpcretest\fP to show names from backtracking
control verbs that are returned from calls to \fBpcre[16|32]_exec()\fP. It causes
\fBpcretest\fP to create a \fBpcre[16|32]_extra\fP block if one has not already
been created by a call to \fBpcre[16|32]_study()\fP, and to set the
PCRE_EXTRA_MARK flag and the \fBmark\fP field within it, every time that
\fBpcre[16|32]_exec()\fP is called. If the variable that the \fBmark\fP field
points to is non-NULL for a match, non-match, or partial match, \fBpcretest\fP
prints the string to which it points. For a match, this is shown on a line by
itself, tagged with "MK:". For a non-match it is added to the message.
.P
The \fB/L\fP modifier must be followed directly by the name of a locale, for
example,
.sp
  /pattern/Lfr_FR
.sp
For this reason, it must be the last modifier. The given locale is set,
\fBpcre[16|32]_maketables()\fP is called to build a set of character tables for
the locale, and this is then passed to \fBpcre[16|32]_compile()\fP when compiling
the regular expression. Without an \fB/L\fP (or \fB/T\fP) modifier, NULL is
passed as the tables pointer; that is, \fB/L\fP applies only to the expression
on which it appears.
.P
The \fB/M\fP modifier causes the size in bytes of the memory block used to hold
the compiled pattern to be output. This does not include the size of the
\fBpcre[16|32]\fP block; it is just the actual compiled data. If the pattern is
successfully studied with the PCRE_STUDY_JIT_COMPILE option, the size of the
JIT compiled code is also output.
.P
The \fB/Q\fP modifier is used to test the use of \fBpcre_stack_guard\fP. It
must be followed by '0' or '1', specifying the return code to be given from an
external function that is passed to PCRE and used for stack checking during
compilation (see the
.\" HREF
\fBpcreapi\fP
.\"
documentation for details).
.P
The \fB/S\fP modifier causes \fBpcre[16|32]_study()\fP to be called after the
expression has been compiled, and the results used when the expression is
matched. There are a number of qualifying characters that may follow \fB/S\fP.
They may appear in any order.
.P
If \fB/S\fP is followed by an exclamation mark, \fBpcre[16|32]_study()\fP is
called with the PCRE_STUDY_EXTRA_NEEDED option, causing it always to return a
\fBpcre_extra\fP block, even when studying discovers no useful information.
.P
If \fB/S\fP is followed by a second S character, it suppresses studying, even
if it was requested externally by the \fB-s\fP command line option. This makes
it possible to specify that certain patterns are always studied, and others are
never studied, independently of \fB-s\fP. This feature is used in the test
files in a few cases where the output is different when the pattern is studied.
.P
If the \fB/S\fP modifier is followed by a + character, the call to
\fBpcre[16|32]_study()\fP is made with all the JIT study options, requesting
just-in-time optimization support if it is available, for both normal and
partial matching. If you want to restrict the JIT compiling modes, you can
follow \fB/S+\fP with a digit in the range 1 to 7:
.sp
  1  normal match only
  2  soft partial match only
  3  normal match and soft partial match
  4  hard partial match only
  6  soft and hard partial match
  7  all three modes (default)
.sp
If \fB/S++\fP is used instead of \fB/S+\fP (with or without a following digit),
the text "(JIT)" is added to the first output line after a match or no match
when JIT-compiled code was actually used.
.P
Note that there is also an independent \fB/+\fP modifier; it must not be given
immediately after \fB/S\fP or \fB/S+\fP because this will be misinterpreted.
.P
If JIT studying is successful, the compiled JIT code will automatically be used
when \fBpcre[16|32]_exec()\fP is run, except when incompatible run-time options
are specified. For more details, see the
.\" HREF
\fBpcrejit\fP
.\"
documentation. See also the \fB\eJ\fP escape sequence below for a way of
setting the size of the JIT stack.
.P
Finally, if \fB/S\fP is followed by a minus character, JIT compilation is
suppressed, even if it was requested externally by the \fB-s\fP command line
option. This makes it possible to specify that JIT is never to be used for
certain patterns.
.P
The \fB/T\fP modifier must be followed by a single digit. It causes a specific
set of built-in character tables to be passed to \fBpcre[16|32]_compile()\fP. It
is used in the standard PCRE tests to check behaviour with different character
tables. The digit specifies the tables as follows:
.sp
  0   the default ASCII tables, as distributed in
        pcre_chartables.c.dist
  1   a set of tables defining ISO 8859 characters
.sp
In table 1, some characters whose codes are greater than 128 are identified as
letters, digits, spaces, etc.
.
.
.SS "Using the POSIX wrapper API"
.rs
.sp
The \fB/P\fP modifier causes \fBpcretest\fP to call PCRE via the POSIX wrapper
API rather than its native API. This supports only the 8-bit library. When
\fB/P\fP is set, the following modifiers set options for the \fBregcomp()\fP
function:
.sp
  /i    REG_ICASE
  /m    REG_NEWLINE
  /N    REG_NOSUB
  /s    REG_DOTALL     )
  /U    REG_UNGREEDY   ) These options are not part of
  /W    REG_UCP        )   the POSIX standard
  /8    REG_UTF8       )
.sp
The \fB/+\fP modifier works as described above. All other modifiers are
ignored.
.
.
.SS "Locking out certain modifiers"
.rs
.sp
PCRE can be compiled with or without support for certain features such as
UTF-8/16/32 or Unicode properties. Accordingly, the standard tests are split up
into a number of different files that are selected for running depending on
which features are available. When updating the tests, it is all too easy to
put a new test into the wrong file by mistake; for example, to put a test that
requires UTF support into a file that is used when it is not available. To help
detect such mistakes as early as possible, there is a facility for locking out
specific modifiers. If an input line for \fBpcretest\fP starts with the string
"< forbid " the following sequence of characters is taken as a list of
forbidden modifiers. For example, in the test files that must not use UTF or
Unicode property support, this line appears:
.sp
  < forbid 8W
.sp
This locks out the /8 and /W modifiers. An immediate error is given if they are
subsequently encountered. If the character string contains < but not >, all the
multi-character modifiers that begin with < are locked out. Otherwise, such
modifiers must be explicitly listed, for example:
.sp
  < forbid <JS><cr>
.sp
There must be a single space between < and "forbid" for this feature to be
recognised. If there is not, the line is interpreted either as a request to
re-load a pre-compiled pattern (see "SAVING AND RELOADING COMPILED PATTERNS"
below) or, if there is a another < character, as a pattern that uses < as its
delimiter.
.
.
.SH "DATA LINES"
.rs
.sp
Before each data line is passed to \fBpcre[16|32]_exec()\fP, leading and trailing
white space is removed, and it is then scanned for \e escapes. Some of these
are pretty esoteric features, intended for checking out some of the more
complicated features of PCRE. If you are just testing "ordinary" regular
expressions, you probably don't need any of these. The following escapes are
recognized:
.sp
  \ea         alarm (BEL, \ex07)
  \eb         backspace (\ex08)
  \ee         escape (\ex27)
  \ef         form feed (\ex0c)
  \en         newline (\ex0a)
.\" JOIN
  \eqdd       set the PCRE_MATCH_LIMIT limit to dd
               (any number of digits)
  \er         carriage return (\ex0d)
  \et         tab (\ex09)
  \ev         vertical tab (\ex0b)
  \ennn       octal character (up to 3 octal digits); always
               a byte unless > 255 in UTF-8 or 16-bit or 32-bit mode
  \eo{dd...}  octal character (any number of octal digits}
  \exhh       hexadecimal byte (up to 2 hex digits)
  \ex{hh...}  hexadecimal character (any number of hex digits)
.\" JOIN
  \eA         pass the PCRE_ANCHORED option to \fBpcre[16|32]_exec()\fP
               or \fBpcre[16|32]_dfa_exec()\fP
.\" JOIN
  \eB         pass the PCRE_NOTBOL option to \fBpcre[16|32]_exec()\fP
               or \fBpcre[16|32]_dfa_exec()\fP
.\" JOIN
  \eCdd       call pcre[16|32]_copy_substring() for substring dd
               after a successful match (number less than 32)
.\" JOIN
  \eCname     call pcre[16|32]_copy_named_substring() for substring
               "name" after a successful match (name terminated
               by next non alphanumeric character)
.\" JOIN
  \eC+        show the current captured substrings at callout
               time
  \eC-        do not supply a callout function
.\" JOIN
  \eC!n       return 1 instead of 0 when callout number n is
               reached
.\" JOIN
  \eC!n!m     return 1 instead of 0 when callout number n is
               reached for the nth time
.\" JOIN
  \eC*n       pass the number n (may be negative) as callout
               data; this is used as the callout return value
  \eD         use the \fBpcre[16|32]_dfa_exec()\fP match function
  \eF         only shortest match for \fBpcre[16|32]_dfa_exec()\fP
.\" JOIN
  \eGdd       call pcre[16|32]_get_substring() for substring dd
               after a successful match (number less than 32)
.\" JOIN
  \eGname     call pcre[16|32]_get_named_substring() for substring
               "name" after a successful match (name terminated
               by next non-alphanumeric character)
.\" JOIN
  \eJdd       set up a JIT stack of dd kilobytes maximum (any
               number of digits)
.\" JOIN
  \eL         call pcre[16|32]_get_substringlist() after a
               successful match
.\" JOIN
  \eM         discover the minimum MATCH_LIMIT and
               MATCH_LIMIT_RECURSION settings
.\" JOIN
  \eN         pass the PCRE_NOTEMPTY option to \fBpcre[16|32]_exec()\fP
               or \fBpcre[16|32]_dfa_exec()\fP; if used twice, pass the
               PCRE_NOTEMPTY_ATSTART option
.\" JOIN
  \eOdd       set the size of the output vector passed to
               \fBpcre[16|32]_exec()\fP to dd (any number of digits)
.\" JOIN
  \eP         pass the PCRE_PARTIAL_SOFT option to \fBpcre[16|32]_exec()\fP
               or \fBpcre[16|32]_dfa_exec()\fP; if used twice, pass the
               PCRE_PARTIAL_HARD option
.\" JOIN
  \eQdd       set the PCRE_MATCH_LIMIT_RECURSION limit to dd
               (any number of digits)
  \eR         pass the PCRE_DFA_RESTART option to \fBpcre[16|32]_dfa_exec()\fP
  \eS         output details of memory get/free calls during matching
.\" JOIN
  \eY         pass the PCRE_NO_START_OPTIMIZE option to \fBpcre[16|32]_exec()\fP
               or \fBpcre[16|32]_dfa_exec()\fP
.\" JOIN
  \eZ         pass the PCRE_NOTEOL option to \fBpcre[16|32]_exec()\fP
               or \fBpcre[16|32]_dfa_exec()\fP
.\" JOIN
  \e?         pass the PCRE_NO_UTF[8|16|32]_CHECK option to
               \fBpcre[16|32]_exec()\fP or \fBpcre[16|32]_dfa_exec()\fP
.\" JOIN
  \e>dd       start the match at offset dd (optional "-"; then
               any number of digits); this sets the \fIstartoffset\fP
               argument for \fBpcre[16|32]_exec()\fP or \fBpcre[16|32]_dfa_exec()\fP
.\" JOIN
  \e<cr>      pass the PCRE_NEWLINE_CR option to \fBpcre[16|32]_exec()\fP
               or \fBpcre[16|32]_dfa_exec()\fP
.\" JOIN
  \e<lf>      pass the PCRE_NEWLINE_LF option to \fBpcre[16|32]_exec()\fP
               or \fBpcre[16|32]_dfa_exec()\fP
.\" JOIN
  \e<crlf>    pass the PCRE_NEWLINE_CRLF option to \fBpcre[16|32]_exec()\fP
               or \fBpcre[16|32]_dfa_exec()\fP
.\" JOIN
  \e<anycrlf> pass the PCRE_NEWLINE_ANYCRLF option to \fBpcre[16|32]_exec()\fP
               or \fBpcre[16|32]_dfa_exec()\fP
.\" JOIN
  \e<any>     pass the PCRE_NEWLINE_ANY option to \fBpcre[16|32]_exec()\fP
               or \fBpcre[16|32]_dfa_exec()\fP
.sp
The use of \ex{hh...} is not dependent on the use of the \fB/8\fP modifier on
the pattern. It is recognized always. There may be any number of hexadecimal
digits inside the braces; invalid values provoke error messages.
.P
Note that \exhh specifies one byte rather than one character in UTF-8 mode;
this makes it possible to construct invalid UTF-8 sequences for testing
purposes. On the other hand, \ex{hh} is interpreted as a UTF-8 character in
UTF-8 mode, generating more than one byte if the value is greater than 127.
When testing the 8-bit library not in UTF-8 mode, \ex{hh} generates one byte
for values less than 256, and causes an error for greater values.
.P
In UTF-16 mode, all 4-digit \ex{hhhh} values are accepted. This makes it
possible to construct invalid UTF-16 sequences for testing purposes.
.P
In UTF-32 mode, all 4- to 8-digit \ex{...} values are accepted. This makes it
possible to construct invalid UTF-32 sequences for testing purposes.
.P
The escapes that specify line ending sequences are literal strings, exactly as
shown. No more than one newline setting should be present in any data line.
.P
A backslash followed by anything else just escapes the anything else. If
the very last character is a backslash, it is ignored. This gives a way of
passing an empty line as data, since a real empty line terminates the data
input.
.P
The \fB\eJ\fP escape provides a way of setting the maximum stack size that is
used by the just-in-time optimization code. It is ignored if JIT optimization
is not being used. Providing a stack that is larger than the default 32K is
necessary only for very complicated patterns.
.P
If \eM is present, \fBpcretest\fP calls \fBpcre[16|32]_exec()\fP several times,
with different values in the \fImatch_limit\fP and \fImatch_limit_recursion\fP
fields of the \fBpcre[16|32]_extra\fP data structure, until it finds the minimum
numbers for each parameter that allow \fBpcre[16|32]_exec()\fP to complete without
error. Because this is testing a specific feature of the normal interpretive
\fBpcre[16|32]_exec()\fP execution, the use of any JIT optimization that might
have been set up by the \fB/S+\fP qualifier of \fB-s+\fP option is disabled.
.P
The \fImatch_limit\fP number is a measure of the amount of backtracking
that takes place, and checking it out can be instructive. For most simple
matches, the number is quite small, but for patterns with very large numbers of
matching possibilities, it can become large very quickly with increasing length
of subject string. The \fImatch_limit_recursion\fP number is a measure of how
much stack (or, if PCRE is compiled with NO_RECURSE, how much heap) memory is
needed to complete the match attempt.
.P
When \eO is used, the value specified may be higher or lower than the size set
by the \fB-O\fP command line option (or defaulted to 45); \eO applies only to
the call of \fBpcre[16|32]_exec()\fP for the line in which it appears.
.P
If the \fB/P\fP modifier was present on the pattern, causing the POSIX wrapper
API to be used, the only option-setting sequences that have any effect are \eB,
\eN, and \eZ, causing REG_NOTBOL, REG_NOTEMPTY, and REG_NOTEOL, respectively,
to be passed to \fBregexec()\fP.
.
.
.SH "THE ALTERNATIVE MATCHING FUNCTION"
.rs
.sp
By default, \fBpcretest\fP uses the standard PCRE matching function,
\fBpcre[16|32]_exec()\fP to match each data line. PCRE also supports an
alternative matching function, \fBpcre[16|32]_dfa_test()\fP, which operates in a
different way, and has some restrictions. The differences between the two
functions are described in the
.\" HREF
\fBpcrematching\fP
.\"
documentation.
.P
If a data line contains the \eD escape sequence, or if the command line
contains the \fB-dfa\fP option, the alternative matching function is used.
This function finds all possible matches at a given point. If, however, the \eF
escape sequence is present in the data line, it stops after the first match is
found. This is always the shortest possible match.
.
.
.SH "DEFAULT OUTPUT FROM PCRETEST"
.rs
.sp
This section describes the output when the normal matching function,
\fBpcre[16|32]_exec()\fP, is being used.
.P
When a match succeeds, \fBpcretest\fP outputs the list of captured substrings
that \fBpcre[16|32]_exec()\fP returns, starting with number 0 for the string that
matched the whole pattern. Otherwise, it outputs "No match" when the return is
PCRE_ERROR_NOMATCH, and "Partial match:" followed by the partially matching
substring when \fBpcre[16|32]_exec()\fP returns PCRE_ERROR_PARTIAL. (Note that
this is the entire substring that was inspected during the partial match; it
may include characters before the actual match start if a lookbehind assertion,
\eK, \eb, or \eB was involved.) For any other return, \fBpcretest\fP outputs
the PCRE negative error number and a short descriptive phrase. If the error is
a failed UTF string check, the offset of the start of the failing character and
the reason code are also output, provided that the size of the output vector is
at least two. Here is an example of an interactive \fBpcretest\fP run.
.sp
  $ pcretest
  PCRE version 8.13 2011-04-30
.sp
    re> /^abc(\ed+)/
  data> abc123
   0: abc123
   1: 123
  data> xyz
  No match
.sp
Unset capturing substrings that are not followed by one that is set are not
returned by \fBpcre[16|32]_exec()\fP, and are not shown by \fBpcretest\fP. In the
following example, there are two capturing substrings, but when the first data
line is matched, the second, unset substring is not shown. An "internal" unset
substring is shown as "<unset>", as for the second data line.
.sp
    re> /(a)|(b)/
  data> a
   0: a
   1: a
  data> b
   0: b
   1: <unset>
   2: b
.sp
If the strings contain any non-printing characters, they are output as \exhh
escapes if the value is less than 256 and UTF mode is not set. Otherwise they
are output as \ex{hh...} escapes. See below for the definition of non-printing
characters. If the pattern has the \fB/+\fP modifier, the output for substring
0 is followed by the the rest of the subject string, identified by "0+" like
this:
.sp
    re> /cat/+
  data> cataract
   0: cat
   0+ aract
.sp
If the pattern has the \fB/g\fP or \fB/G\fP modifier, the results of successive
matching attempts are output in sequence, like this:
.sp
    re> /\eBi(\ew\ew)/g
  data> Mississippi
   0: iss
   1: ss
   0: iss
   1: ss
   0: ipp
   1: pp
.sp
"No match" is output only if the first match attempt fails. Here is an example
of a failure message (the offset 4 that is specified by \e>4 is past the end of
the subject string):
.sp
    re> /xyz/
  data> xyz\e>4
  Error -24 (bad offset value)
.P
If any of the sequences \fB\eC\fP, \fB\eG\fP, or \fB\eL\fP are present in a
data line that is successfully matched, the substrings extracted by the
convenience functions are output with C, G, or L after the string number
instead of a colon. This is in addition to the normal full list. The string
length (that is, the return from the extraction function) is given in
parentheses after each string for \fB\eC\fP and \fB\eG\fP.
.P
Note that whereas patterns can be continued over several lines (a plain ">"
prompt is used for continuations), data lines may not. However newlines can be
included in data by means of the \en escape (or \er, \er\en, etc., depending on
the newline sequence setting).
.
.
.
.SH "OUTPUT FROM THE ALTERNATIVE MATCHING FUNCTION"
.rs
.sp
When the alternative matching function, \fBpcre[16|32]_dfa_exec()\fP, is used (by
means of the \eD escape sequence or the \fB-dfa\fP command line option), the
output consists of a list of all the matches that start at the first point in
the subject where there is at least one match. For example:
.sp
    re> /(tang|tangerine|tan)/
  data> yellow tangerine\eD
   0: tangerine
   1: tang
   2: tan
.sp
(Using the normal matching function on this data finds only "tang".) The
longest matching string is always given first (and numbered zero). After a
PCRE_ERROR_PARTIAL return, the output is "Partial match:", followed by the
partially matching substring. (Note that this is the entire substring that was
inspected during the partial match; it may include characters before the actual
match start if a lookbehind assertion, \eK, \eb, or \eB was involved.)
.P
If \fB/g\fP is present on the pattern, the search for further matches resumes
at the end of the longest match. For example:
.sp
    re> /(tang|tangerine|tan)/g
  data> yellow tangerine and tangy sultana\eD
   0: tangerine
   1: tang
   2: tan
   0: tang
   1: tan
   0: tan
.sp
Since the matching function does not support substring capture, the escape
sequences that are concerned with captured substrings are not relevant.
.
.
.SH "RESTARTING AFTER A PARTIAL MATCH"
.rs
.sp
When the alternative matching function has given the PCRE_ERROR_PARTIAL return,
indicating that the subject partially matched the pattern, you can restart the
match with additional subject data by means of the \eR escape sequence. For
example:
.sp
    re> /^\ed?\ed(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)\ed\ed$/
  data> 23ja\eP\eD
  Partial match: 23ja
  data> n05\eR\eD
   0: n05
.sp
For further information about partial matching, see the
.\" HREF
\fBpcrepartial\fP
.\"
documentation.
.
.
.SH CALLOUTS
.rs
.sp
If the pattern contains any callout requests, \fBpcretest\fP's callout function
is called during matching. This works with both matching functions. By default,
the called function displays the callout number, the start and current
positions in the text at the callout time, and the next pattern item to be
tested. For example:
.sp
  --->pqrabcdef
    0    ^  ^     \ed
.sp
This output indicates that callout number 0 occurred for a match attempt
starting at the fourth character of the subject string, when the pointer was at
the seventh character of the data, and when the next pattern item was \ed. Just
one circumflex is output if the start and current positions are the same.
.P
Callouts numbered 255 are assumed to be automatic callouts, inserted as a
result of the \fB/C\fP pattern modifier. In this case, instead of showing the
callout number, the offset in the pattern, preceded by a plus, is output. For
example:
.sp
    re> /\ed?[A-E]\e*/C
  data> E*
  --->E*
   +0 ^      \ed?
   +3 ^      [A-E]
   +8 ^^     \e*
  +10 ^ ^
   0: E*
.sp
If a pattern contains (*MARK) items, an additional line is output whenever
a change of latest mark is passed to the callout function. For example:
.sp
    re> /a(*MARK:X)bc/C
  data> abc
  --->abc
   +0 ^       a
   +1 ^^      (*MARK:X)
  +10 ^^      b
  Latest Mark: X
  +11 ^ ^     c
  +12 ^  ^
   0: abc
.sp
The mark changes between matching "a" and "b", but stays the same for the rest
of the match, so nothing more is output. If, as a result of backtracking, the
mark reverts to being unset, the text "<unset>" is output.
.P
The callout function in \fBpcretest\fP returns zero (carry on matching) by
default, but you can use a \eC item in a data line (as described above) to
change this and other parameters of the callout.
.P
Inserting callouts can be helpful when using \fBpcretest\fP to check
complicated regular expressions. For further information about callouts, see
the
.\" HREF
\fBpcrecallout\fP
.\"
documentation.
.
.
.
.SH "NON-PRINTING CHARACTERS"
.rs
.sp
When \fBpcretest\fP is outputting text in the compiled version of a pattern,
bytes other than 32-126 are always treated as non-printing characters are are
therefore shown as hex escapes.
.P
When \fBpcretest\fP is outputting text that is a matched part of a subject
string, it behaves in the same way, unless a different locale has been set for
the pattern (using the \fB/L\fP modifier). In this case, the \fBisprint()\fP
function to distinguish printing and non-printing characters.
.
.
.
.SH "SAVING AND RELOADING COMPILED PATTERNS"
.rs
.sp
The facilities described in this section are not available when the POSIX
interface to PCRE is being used, that is, when the \fB/P\fP pattern modifier is
specified.
.P
When the POSIX interface is not in use, you can cause \fBpcretest\fP to write a
compiled pattern to a file, by following the modifiers with > and a file name.
For example:
.sp
  /pattern/im >/some/file
.sp
See the
.\" HREF
\fBpcreprecompile\fP
.\"
documentation for a discussion about saving and re-using compiled patterns.
Note that if the pattern was successfully studied with JIT optimization, the
JIT data cannot be saved.
.P
The data that is written is binary. The first eight bytes are the length of the
compiled pattern data followed by the length of the optional study data, each
written as four bytes in big-endian order (most significant byte first). If
there is no study data (either the pattern was not studied, or studying did not
return any data), the second length is zero. The lengths are followed by an
exact copy of the compiled pattern. If there is additional study data, this
(excluding any JIT data) follows immediately after the compiled pattern. After
writing the file, \fBpcretest\fP expects to read a new pattern.
.P
A saved pattern can be reloaded into \fBpcretest\fP by specifying < and a file
name instead of a pattern. There must be no space between < and the file name,
which must not contain a < character, as otherwise \fBpcretest\fP will
interpret the line as a pattern delimited by < characters. For example:
.sp
   re> </some/file
  Compiled pattern loaded from /some/file
  No study data
.sp
If the pattern was previously studied with the JIT optimization, the JIT
information cannot be saved and restored, and so is lost. When the pattern has
been loaded, \fBpcretest\fP proceeds to read data lines in the usual way.
.P
You can copy a file written by \fBpcretest\fP to a different host and reload it
there, even if the new host has opposite endianness to the one on which the
pattern was compiled. For example, you can compile on an i86 machine and run on
a SPARC machine. When a pattern is reloaded on a host with different
endianness, the confirmation message is changed to:
.sp
  Compiled pattern (byte-inverted) loaded from /some/file
.sp
The test suite contains some saved pre-compiled patterns with different
endianness. These are reloaded using "<!" instead of just "<". This suppresses
the "(byte-inverted)" text so that the output is the same on all hosts. It also
forces debugging output once the pattern has been reloaded.
.P
File names for saving and reloading can be absolute or relative, but note that
the shell facility of expanding a file name that starts with a tilde (~) is not
available.
.P
The ability to save and reload files in \fBpcretest\fP is intended for testing
and experimentation. It is not intended for production use because only a
single pattern can be written to a file. Furthermore, there is no facility for
supplying custom character tables for use with a reloaded pattern. If the
original pattern was compiled with custom tables, an attempt to match a subject
string using a reloaded pattern is likely to cause \fBpcretest\fP to crash.
Finally, if you attempt to load a file that is not in the correct format, the
result is undefined.
.
.
.SH "SEE ALSO"
.rs
.sp
\fBpcre\fP(3), \fBpcre16\fP(3), \fBpcre32\fP(3), \fBpcreapi\fP(3),
\fBpcrecallout\fP(3),
\fBpcrejit\fP, \fBpcrematching\fP(3), \fBpcrepartial\fP(d),
\fBpcrepattern\fP(3), \fBpcreprecompile\fP(3).
.
.
.SH AUTHOR
.rs
.sp
.nf
Philip Hazel
University Computing Service
Cambridge CB2 3QH, England.
.fi
.
.
.SH REVISION
.rs
.sp
.nf
Last updated: 23 February 2017
Copyright (c) 1997-2017 University of Cambridge.
.fi
PK1N%[	������perl5/Expect.pmnu�7��m# -*-cperl-*-
# This module is copyrighted as per the usual perl legalese:
# Copyright (c) 1997 Austin Schutz.
# expect() interface & functionality enhancements (c) 1999 Roland Giersig.
#
# All rights reserved. This program is free software; you can
# redistribute it and/or modify it under the same terms as Perl
# itself.
#
# Don't blame/flame me if you bust your stuff.
# Austin Schutz <ASchutz@users.sourceforge.net>
#
# This module now is maintained by
# Dave Jacoby <jacoby@cpan.org>
#

use 5.006;

package Expect;
use strict;
use warnings;

use IO::Pty 1.11; # We need make_slave_controlling_terminal()
use IO::Tty;

use POSIX qw(:sys_wait_h :unistd_h); # For WNOHANG and isatty
use Fcntl qw(:DEFAULT);              # For checking file handle settings.
use Carp qw(cluck croak carp confess);
use IO::Handle ();
use Exporter   qw(import);
use Errno;
use Scalar::Util qw/ looks_like_number /;

# This is necessary to make routines within Expect work.

@Expect::ISA    = qw(IO::Pty);
@Expect::EXPORT = qw(expect exp_continue exp_continue_timeout);

BEGIN {
	$Expect::VERSION = '1.38';

	# These are defaults which may be changed per object, or set as
	# the user wishes.
	# This will be unset, since the default behavior differs between
	# spawned processes and initialized filehandles.
	#  $Expect::Log_Stdout = 1;
	$Expect::Log_Group          = 1;
	$Expect::Debug              = 0;
	$Expect::Exp_Max_Accum      = 0; # unlimited
	$Expect::Exp_Internal       = 0;
	$Expect::IgnoreEintr        = 0;
	$Expect::Manual_Stty        = 0;
	$Expect::Multiline_Matching = 1;
	$Expect::Do_Soft_Close      = 0;
	@Expect::Before_List        = ();
	@Expect::After_List         = ();
	%Expect::Spawned_PIDs       = ();
}

sub version {
	my ($version) = @_;

	warn "Version $version is later than $Expect::VERSION. It may not be supported"
		if ( defined($version) && ( $version > $Expect::VERSION ) );

	die "Versions before 1.03 are not supported in this release"
		if ( ( defined($version) ) && ( $version < 1.03 ) );
	return $Expect::VERSION;
}

sub new {
	my ($class, @args) = @_;

	$class = ref($class) if ref($class); # so we can be called as $exp->new()

	# Create the pty which we will use to pass process info.
	my ($self) = IO::Pty->new;
	die "$class: Could not assign a pty" unless $self;
	bless $self => $class;
	$self->autoflush(1);

	# This is defined here since the default is different for
	# initialized handles as opposed to spawned processes.
	${*$self}{exp_Log_Stdout} = 1;
	$self->_init_vars();

	if (@args) {

		# we got add'l parms, so pass them to spawn
		return $self->spawn(@args);
	}
	return $self;
}

sub timeout {
    my $self = shift;
    ${*$self}{expect_timeout} = shift if @_;
    return ${*$self}{expect_timeout};
}

sub spawn {
	my ($class, @cmd) = @_;
	# spawn is passed command line args.

	my $self;

	if ( ref($class) ) {
		$self = $class;
	} else {
		$self = $class->new();
	}

	croak "Cannot reuse an object with an already spawned command"
		if exists ${*$self}{"exp_Command"};
	${*$self}{"exp_Command"} = \@cmd;

	# set up pipe to detect childs exec error
	pipe( FROM_CHILD,  TO_PARENT ) or die "Cannot open pipe: $!";
	pipe( FROM_PARENT, TO_CHILD )  or die "Cannot open pipe: $!";
	TO_PARENT->autoflush(1);
	TO_CHILD->autoflush(1);
	eval { fcntl( TO_PARENT, Fcntl::F_SETFD, Fcntl::FD_CLOEXEC ); };

	my $pid = fork;

	unless ( defined($pid) ) {
		warn "Cannot fork: $!" if $^W;
		return;
	}

	if ($pid) {

		# parent
		my $errno;
		${*$self}{exp_Pid} = $pid;
		close TO_PARENT;
		close FROM_PARENT;
		$self->close_slave();
		$self->set_raw() if $self->raw_pty and isatty($self);
		close TO_CHILD; # so child gets EOF and can go ahead

		# now wait for child exec (eof due to close-on-exit) or exec error
		my $errstatus = sysread( FROM_CHILD, $errno, 256 );
		die "Cannot sync with child: $!" if not defined $errstatus;
		close FROM_CHILD;
		if ($errstatus) {
			$! = $errno + 0;
			warn "Cannot exec(@cmd): $!\n" if $^W;
			return;
		}
	} else {

		# child
		close FROM_CHILD;
		close TO_CHILD;

		$self->make_slave_controlling_terminal();
		my $slv = $self->slave()
			or die "Cannot get slave: $!";

		$slv->set_raw() if $self->raw_pty;
		close($self);

		# wait for parent before we detach
		my $buffer;
		my $errstatus = sysread( FROM_PARENT, $buffer, 256 );
		die "Cannot sync with parent: $!" if not defined $errstatus;
		close FROM_PARENT;

		close(STDIN);
		open( STDIN, "<&" . $slv->fileno() )
			or die "Couldn't reopen STDIN for reading, $!\n";
		close(STDOUT);
		open( STDOUT, ">&" . $slv->fileno() )
			or die "Couldn't reopen STDOUT for writing, $!\n";
		close(STDERR);
		open( STDERR, ">&" . $slv->fileno() )
			or die "Couldn't reopen STDERR for writing, $!\n";

		{ exec(@cmd) };
		print TO_PARENT $! + 0;
		die "Cannot exec(@cmd): $!\n";
	}

	# This is sort of for code compatibility, and to make debugging a little
	# easier. By code compatibility I mean that previously the process's
	# handle was referenced by $process{Pty_Handle} instead of just $process.
	# This is almost like 'naming' the handle to the process.
	# I think this also reflects Tcl Expect-like behavior.
	${*$self}{exp_Pty_Handle} = "spawn id(" . $self->fileno() . ")";
	if ( ( ${*$self}{"exp_Debug"} ) or ( ${*$self}{"exp_Exp_Internal"} ) ) {
		cluck(
			"Spawned '@cmd'\r\n",
			"\t${*$self}{exp_Pty_Handle}\r\n",
			"\tPid: ${*$self}{exp_Pid}\r\n",
			"\tTty: " . $self->SUPER::ttyname() . "\r\n",
		);
	}
	$Expect::Spawned_PIDs{ ${*$self}{exp_Pid} } = undef;
	return $self;
}

sub exp_init {
	my ($class, $self) = @_;

	# take a filehandle, for use later with expect() or interconnect() .
	# All the functions are written for reading from a tty, so if the naming
	# scheme looks odd, that's why.
	bless $self, $class;
	croak "exp_init not passed a file object, stopped"
		unless defined( $self->fileno() );
	$self->autoflush(1);

	# Define standard variables.. debug states, etc.
	$self->_init_vars();

	# Turn of logging. By default we don't want crap from a file to get spewed
	# on screen as we read it.
	${*$self}{exp_Log_Stdout} = 0;
	${*$self}{exp_Pty_Handle} = "handle id(" . $self->fileno() . ")";
	${*$self}{exp_Pty_Handle} = "STDIN" if $self->fileno() == fileno(STDIN);
	print STDERR "Initialized ${*$self}{exp_Pty_Handle}.'\r\n"
		if ${*$self}{"exp_Debug"};
	return $self;
}

# make an alias
*init = \&exp_init;

######################################################################
# We're happy OOP people. No direct access to stuff.
# For standard read-writeable parameters, we define some autoload magic...
my %Writeable_Vars = (
	debug                        => 'exp_Debug',
	exp_internal                 => 'exp_Exp_Internal',
	do_soft_close                => 'exp_Do_Soft_Close',
	max_accum                    => 'exp_Max_Accum',
	match_max                    => 'exp_Max_Accum',
	notransfer                   => 'exp_NoTransfer',
	log_stdout                   => 'exp_Log_Stdout',
	log_user                     => 'exp_Log_Stdout',
	log_group                    => 'exp_Log_Group',
	manual_stty                  => 'exp_Manual_Stty',
	restart_timeout_upon_receive => 'exp_Continue',
	raw_pty                      => 'exp_Raw_Pty',
);
my %Readable_Vars = (
	pid              => 'exp_Pid',
	exp_pid          => 'exp_Pid',
	exp_match_number => 'exp_Match_Number',
	match_number     => 'exp_Match_Number',
	exp_error        => 'exp_Error',
	error            => 'exp_Error',
	exp_command      => 'exp_Command',
	command          => 'exp_Command',
	exp_match        => 'exp_Match',
	match            => 'exp_Match',
	exp_matchlist    => 'exp_Matchlist',
	matchlist        => 'exp_Matchlist',
	exp_before       => 'exp_Before',
	before           => 'exp_Before',
	exp_after        => 'exp_After',
	after            => 'exp_After',
	exp_exitstatus   => 'exp_Exit',
	exitstatus       => 'exp_Exit',
	exp_pty_handle   => 'exp_Pty_Handle',
	pty_handle       => 'exp_Pty_Handle',
	exp_logfile      => 'exp_Log_File',
	logfile          => 'exp_Log_File',
	%Writeable_Vars,
);

sub AUTOLOAD {
	my ($self, @args) = @_;

	my $type = ref($self)
		or croak "$self is not an object";

	use vars qw($AUTOLOAD);
	my $name = $AUTOLOAD;
	$name =~ s/.*:://; # strip fully-qualified portion

	unless ( exists $Readable_Vars{$name} ) {
		croak "ERROR: cannot find method `$name' in class $type";
	}
	my $varname = $Readable_Vars{$name};
	my $tmp;
	$tmp = ${*$self}{$varname} if exists ${*$self}{$varname};

	if (@args) {
		if ( exists $Writeable_Vars{$name} ) {
			my $ref = ref($tmp);
			if ( $ref eq 'ARRAY' ) {
				${*$self}{$varname} = [@args];
			} elsif ( $ref eq 'HASH' ) {
				${*$self}{$varname} = {@args};
			} else {
				${*$self}{$varname} = shift @args;
			}
		} else {
			carp "Trying to set read-only variable `$name'"
				if $^W;
		}
	}

	my $ref = ref($tmp);
	return ( wantarray ? @{$tmp} : $tmp ) if ( $ref eq 'ARRAY' );
	return ( wantarray ? %{$tmp} : $tmp ) if ( $ref eq 'HASH' );
	return $tmp;
}

######################################################################

sub set_seq {
	my ( $self, $escape_sequence, $function, $params, @args ) = @_;

	# Set an escape sequence/function combo for a read handle for interconnect.
	# Ex: $read_handle->set_seq('',\&function,\@parameters);
	${ ${*$self}{exp_Function} }{$escape_sequence} = $function;
	if ( ( !defined($function) ) || ( $function eq 'undef' ) ) {
		${ ${*$self}{exp_Function} }{$escape_sequence} = \&_undef;
	}
	${ ${*$self}{exp_Parameters} }{$escape_sequence} = $params;

	# This'll be a joy to execute. :)
	if ( ${*$self}{"exp_Debug"} ) {
		print STDERR "Escape seq. '" . $escape_sequence;
		print STDERR "' function for ${*$self}{exp_Pty_Handle} set to '";
		print STDERR ${ ${*$self}{exp_Function} }{$escape_sequence};
		print STDERR "(" . join( ',', @args ) . ")'\r\n";
	}
}

sub set_group {
	my ($self, @args) = @_;

	# Make sure we can read from the read handle
	if ( !defined( $args[0] ) ) {
		if ( defined( ${*$self}{exp_Listen_Group} ) ) {
			return @{ ${*$self}{exp_Listen_Group} };
		} else {

			# Refrain from referencing an undef
			return;
		}
	}
	@{ ${*$self}{exp_Listen_Group} } = ();
	if ( $self->_get_mode() !~ 'r' ) {
		warn(
			"Attempting to set a handle group on ${*$self}{exp_Pty_Handle}, ",
			"a non-readable handle!\r\n"
		);
	}
	while ( my $write_handle = shift @args ) {
		if ( $write_handle->_get_mode() !~ 'w' ) {
			warn(
				"Attempting to set a non-writeable listen handle ",
				"${*$write_handle}{exp_Pty_handle} for ",
				"${*$self}{exp_Pty_Handle}!\r\n"
			);
		}
		push( @{ ${*$self}{exp_Listen_Group} }, $write_handle );
	}
}

sub log_file {
	my ($self, $file, $mode)  = @_;
	$mode ||= "a";

	return ( ${*$self}{exp_Log_File} )
		if @_ < 2; # we got no param, return filehandle
	# $e->log_file(undef) is an acceptable call hence we need to check the number of parameters here

	if ( ${*$self}{exp_Log_File} and ref( ${*$self}{exp_Log_File} ) ne 'CODE' ) {
		close( ${*$self}{exp_Log_File} );
	}
	${*$self}{exp_Log_File} = undef;
	return if ( not $file );
	my $fh = $file;
	if ( not ref($file) ) {

		# it's a filename
		$fh = IO::File->new( $file, $mode )
			or croak "Cannot open logfile $file: $!";
	}
	if ( ref($file) ne 'CODE' ) {
		croak "Given logfile doesn't have a 'print' method"
			if not $fh->can("print");
		$fh->autoflush(1); # so logfile is up to date
	}

	${*$self}{exp_Log_File} = $fh;

	return $fh;
}

# I'm going to leave this here in case I might need to change something.
# Previously this was calling `stty`, in a most bastardized manner.
sub exp_stty {
	my ($self) = shift;
	my ($mode) = "@_";

	return unless defined $mode;
	if ( not defined $INC{"IO/Stty.pm"} ) {
		carp "IO::Stty not installed, cannot change mode";
		return;
	}

	if ( ${*$self}{"exp_Debug"} ) {
		print STDERR "Setting ${*$self}{exp_Pty_Handle} to tty mode '$mode'\r\n";
	}
	unless ( POSIX::isatty($self) ) {
		if ( ${*$self}{"exp_Debug"} or $^W ) {
			warn "${*$self}{exp_Pty_Handle} is not a tty. Not changing mode";
		}
		return ''; # No undef to avoid warnings elsewhere.
	}
	IO::Stty::stty( $self, split( /\s/, $mode ) );
}

*stty = \&exp_stty;

# If we want to clear the buffer. Otherwise Accum will grow during send_slow
# etc. and contain the remainder after matches.
sub clear_accum {
	my ($self) = @_;
	return $self->set_accum('');
}

sub set_accum {
	my ($self, $accum) = @_;

	my $old_accum = ${*$self}{exp_Accum};
	${*$self}{exp_Accum} = $accum;

	# return the contents of the accumulator.
	return $old_accum;
}
sub get_accum {
	my ($self) = @_;
	return ${*$self}{exp_Accum};
}

######################################################################
# define constants for pattern subs
sub exp_continue         {"exp_continue"}
sub exp_continue_timeout {"exp_continue_timeout"}

######################################################################
# Expect on multiple objects at once.
#
# Call as Expect::expect($timeout, -i => \@exp_list, @patternlist,
#                       -i => $exp, @pattern_list, ...);
# or $exp->expect($timeout, @patternlist, -i => \@exp_list, @patternlist,
#                 -i => $exp, @pattern_list, ...);
#
# Patterns are arrays that consist of
#   [ $pattern_type, $pattern, $sub, @subparms ]
#
#   Optional $pattern_type is '-re' (RegExp, default) or '-ex' (exact);
#
#   $sub is optional CODE ref, which is called as &{$sub}($exp, @subparms)
#     if pattern matched; may return exp_continue or exp_continue_timeout.
#
# Old-style syntax (pure pattern strings with optional type)  also supported.
#

sub expect {
	my $self;

	print STDERR ("expect(@_) called...\n") if $Expect::Debug;
	if ( defined( $_[0] ) ) {
		if ( ref( $_[0] ) and $_[0]->isa('Expect') ) {
			$self = shift;
		} elsif ( $_[0] eq 'Expect' ) {
			shift; # or as Expect->expect
		}
	}
	croak "expect(): not enough arguments, should be expect(timeout, [patterns...])"
		if @_ < 1;
	my $timeout;
	if ( looks_like_number($_[0]) or not defined $_[0] ) {
		$timeout = shift;
		}
	else {
		$timeout = $self->timeout; 
		}
	my $timeout_hook = undef;

	my @object_list;
	my %patterns;

	my @pattern_list;
	my @timeout_list;
	my $curr_list;

	if ($self) {
		$curr_list = [$self];
	} else {

		# called directly, so first parameter must be '-i' to establish
		# object list.
		$curr_list = [];
		croak
			"expect(): ERROR: if called directly (not as \$obj->expect(...), but as Expect::expect(...), first parameter MUST be '-i' to set an object (list) for the patterns to work on."
			if ( $_[0] ne '-i' );
	}

	# Let's make a list of patterns wanting to be evaled as regexps.
	my $parm;
	my $parm_nr = 1;
	while ( defined( $parm = shift ) ) {
		print STDERR ("expect(): handling param '$parm'...\n")
			if $Expect::Debug;
		if ( ref($parm) ) {
			if ( ref($parm) eq 'Regexp' ) {
                push @pattern_list, [ $parm_nr, '-re', $parm, undef ];
            }
			elsif ( ref($parm) eq 'ARRAY' ) {
			# if ( ref($parm) eq 'ARRAY' ) {
				my $err = _add_patterns_to_list(
					\@pattern_list, \@timeout_list,
					$parm_nr,       $parm
				);
				carp(
					"expect(): Warning: multiple `timeout' patterns (",
					scalar(@timeout_list), ").\r\n"
				) if @timeout_list > 1;
				$timeout_hook = $timeout_list[-1] if $timeout_list[-1];
				croak $err if $err;
				$parm_nr++;
			} else {
				croak("expect(): Unknown pattern ref $parm");
			}
		} else {

			# not a ref, is an option or raw pattern
			if ( substr( $parm, 0, 1 ) eq '-' ) {

				# it's an option
				print STDERR ("expect(): handling option '$parm'...\n")
					if $Expect::Debug;
				if ( $parm eq '-i' ) {

					# first add collected patterns to object list
					if ( scalar(@$curr_list) ) {
						push @object_list, $curr_list
							if not exists $patterns{"$curr_list"};
						push @{ $patterns{"$curr_list"} }, @pattern_list;
						@pattern_list = ();
					}

					# now put parm(s) into current object list
					if ( ref( $_[0] ) eq 'ARRAY' ) {
						$curr_list = shift;
					} else {
						$curr_list = [shift];
					}
				} elsif ( $parm eq '-re'
					or $parm eq '-ex' )
				{
					if ( ref( $_[1] ) eq 'CODE' ) {
						push @pattern_list, [ $parm_nr, $parm, shift, shift ];
					} else {
						push @pattern_list, [ $parm_nr, $parm, shift, undef ];
					}
					$parm_nr++;
				} else {
					croak("Unknown option $parm");
				}
			} else {

				# a plain pattern, check if it is followed by a CODE ref
				if ( ref( $_[0] ) eq 'CODE' ) {
					if ( $parm eq 'timeout' ) {
						push @timeout_list, shift;
						carp(
							"expect(): Warning: multiple `timeout' patterns (",
							scalar(@timeout_list),
							").\r\n"
						) if @timeout_list > 1;
						$timeout_hook = $timeout_list[-1] if $timeout_list[-1];
					} elsif ( $parm eq 'eof' ) {
						push @pattern_list, [ $parm_nr, "-$parm", undef, shift ];
					} else {
						push @pattern_list, [ $parm_nr, '-ex', $parm, shift ];
					}
				} else {
					print STDERR ("expect(): exact match '$parm'...\n")
						if $Expect::Debug;
					push @pattern_list, [ $parm_nr, '-ex', $parm, undef ];
				}
				$parm_nr++;
			}
		}
	}

	# add rest of collected patterns to object list
	carp "expect(): Empty object list" unless $curr_list;
	push @object_list, $curr_list if not exists $patterns{"$curr_list"};
	push @{ $patterns{"$curr_list"} }, @pattern_list;

	my $debug    = $self ? ${*$self}{exp_Debug}        : $Expect::Debug;
	my $internal = $self ? ${*$self}{exp_Exp_Internal} : $Expect::Exp_Internal;

	# now start matching...

	if (@Expect::Before_List) {
		print STDERR ("Starting BEFORE pattern matching...\r\n")
			if ( $debug or $internal );
		_multi_expect( 0, undef, @Expect::Before_List );
	}

	cluck("Starting EXPECT pattern matching...\r\n")
		if ( $debug or $internal );
	my @ret;
	@ret = _multi_expect(
		$timeout, $timeout_hook,
		map { [ $_, @{ $patterns{"$_"} } ] } @object_list
	);

	if (@Expect::After_List) {
		print STDERR ("Starting AFTER pattern matching...\r\n")
			if ( $debug or $internal );
		_multi_expect( 0, undef, @Expect::After_List );
	}

	return wantarray ? @ret : $ret[0];
}

######################################################################
# the real workhorse
#
sub _multi_expect {
	my ($timeout, $timeout_hook, @params) = @_;

	if ($timeout_hook) {
		croak "Unknown timeout_hook type $timeout_hook"
			unless ( ref($timeout_hook) eq 'CODE'
			or ref($timeout_hook) eq 'ARRAY' );
	}

	foreach my $pat (@params) {
		my @patterns = @{$pat}[ 1 .. $#{$pat} ];
		foreach my $exp ( @{ $pat->[0] } ) {
			${*$exp}{exp_New_Data} = 1; # first round we always try to match
			if ( exists ${*$exp}{"exp_Max_Accum"}
				and ${*$exp}{"exp_Max_Accum"} )
			{
				${*$exp}{exp_Accum} = $exp->_trim_length(
					${*$exp}{exp_Accum},
					${*$exp}{exp_Max_Accum}
				);
			}
			print STDERR (
				"${*$exp}{exp_Pty_Handle}: beginning expect.\r\n",
				"\tTimeout: ",
				( defined($timeout) ? $timeout : "unlimited" ),
				" seconds.\r\n",
				"\tCurrent time: " . localtime() . "\r\n",
			) if $Expect::Debug;

			# What are we expecting? What do you expect? :-)
			if ( ${*$exp}{exp_Exp_Internal} ) {
				print STDERR "${*$exp}{exp_Pty_Handle}: list of patterns:\r\n";
				foreach my $pattern (@patterns) {
					print STDERR (
						'  ',
						defined( $pattern->[0] )
						? '#' . $pattern->[0] . ': '
						: '',
						$pattern->[1],
						" `",
						_make_readable( $pattern->[2] ),
						"'\r\n"
					);
				}
				print STDERR "\r\n";
			}
		}
	}

	my $successful_pattern;
	my $exp_matched;
	my $err;
	my $before;
	my $after;
	my $match;
	my @matchlist;

	# Set the last loop time to now for time comparisons at end of loop.
	my $start_loop_time = time();
	my $exp_cont        = 1;

	READLOOP:
	while ($exp_cont) {
		$exp_cont = 1;
		$err      = "";
		my $rmask     = '';
		my $time_left = undef;
		if ( defined $timeout ) {
			$time_left = $timeout - ( time() - $start_loop_time );
			$time_left = 0 if $time_left < 0;
		}

		$exp_matched = undef;

		# Test for a match first so we can test the current Accum w/out
		# worrying about an EOF.

		foreach my $pat (@params) {
			my @patterns = @{$pat}[ 1 .. $#{$pat} ];
			foreach my $exp ( @{ $pat->[0] } ) {

				# build mask for select in next section...
				my $fn = $exp->fileno();
				vec( $rmask, $fn, 1 ) = 1 if defined $fn;

				next unless ${*$exp}{exp_New_Data};

				# clear error status
				${*$exp}{exp_Error} = undef;
				${*$exp}{exp_After}        = undef;
				${*$exp}{exp_Match_Number} = undef;
				${*$exp}{exp_Match}        = undef;

				# This could be huge. We should attempt to do something
				# about this.  Because the output is used for debugging
				# I'm of the opinion that showing smaller amounts if the
				# total is huge should be ok.
				# Thus the 'trim_length'
				print STDERR (
					"\r\n${*$exp}{exp_Pty_Handle}: Does `",
					$exp->_trim_length( _make_readable( ${*$exp}{exp_Accum} ) ),
					"'\r\nmatch:\r\n"
				) if ${*$exp}{exp_Exp_Internal};

				# we don't keep the parameter number anymore
				# (clashes with before & after), instead the parameter number is
				# stored inside the pattern; we keep the pattern ref
				# and look up the number later.
				foreach my $pattern (@patterns) {
					print STDERR (
						"  pattern",
						defined( $pattern->[0] ) ? ' #' . $pattern->[0] : '',
						": ",
						$pattern->[1],
						" `",
						_make_readable( $pattern->[2] ),
						"'? "
					) if ( ${*$exp}{exp_Exp_Internal} );

					# Matching exactly
					if ( $pattern->[1] eq '-ex' ) {
						my $match_index =
							index( ${*$exp}{exp_Accum}, $pattern->[2] );

						# We matched if $match_index > -1
						if ( $match_index > -1 ) {
							$before =
								substr( ${*$exp}{exp_Accum}, 0, $match_index );
							$match = substr(
								${*$exp}{exp_Accum},
								$match_index, length( $pattern->[2] )
							);
							$after = substr(
								${*$exp}{exp_Accum},
								$match_index + length( $pattern->[2] )
							);
							${*$exp}{exp_Before}       = $before;
							${*$exp}{exp_Match}        = $match;
							${*$exp}{exp_After}        = $after;
							${*$exp}{exp_Match_Number} = $pattern->[0];
							$exp_matched = $exp;
						}
					} elsif ( $pattern->[1] eq '-re' ) {

						if ($Expect::Multiline_Matching) {
							@matchlist =
								( ${*$exp}{exp_Accum}  =~ m/($pattern->[2])/m);
						} else {
							@matchlist =
								( ${*$exp}{exp_Accum} =~ m/($pattern->[2])/);
						}
						if (@matchlist) {

							# Matching regexp
							$match  = shift @matchlist;
							my $start = index ${*$exp}{exp_Accum}, $match;
							die 'The match could not be found' if $start == -1;
							$before = substr ${*$exp}{exp_Accum}, 0, $start;
							$after = substr ${*$exp}{exp_Accum}, $start + length($match);

							${*$exp}{exp_Before} = $before;
							${*$exp}{exp_Match}  = $match;
							${*$exp}{exp_After}  = $after;
							#pop @matchlist; # remove kludged empty bracket from end
							@{ ${*$exp}{exp_Matchlist} } = @matchlist;
							${*$exp}{exp_Match_Number} = $pattern->[0];
							$exp_matched = $exp;
						}
					} else {

						# 'timeout' or 'eof'
					}

					if ($exp_matched) {
						${*$exp}{exp_Accum} = $after
							unless ${*$exp}{exp_NoTransfer};
						print STDERR "YES!!\r\n"
							if ${*$exp}{exp_Exp_Internal};
						print STDERR (
							"    Before match string: `",
							$exp->_trim_length( _make_readable( ($before) ) ),
							"'\r\n",
							"    Match string: `",
							_make_readable($match),
							"'\r\n",
							"    After match string: `",
							$exp->_trim_length( _make_readable( ($after) ) ),
							"'\r\n",
							"    Matchlist: (",
							join(
								",  ",
								map { "`" . $exp->_trim_length( _make_readable( ($_) ) ) . "'" } @matchlist,
							),
							")\r\n",
						) if ( ${*$exp}{exp_Exp_Internal} );

						# call hook function if defined
						if ( $pattern->[3] ) {
							print STDERR (
								"Calling hook $pattern->[3]...\r\n",
								)
								if ( ${*$exp}{exp_Exp_Internal}
								or $Expect::Debug );
							if ( $#{$pattern} > 3 ) {

								# call with parameters if given
								$exp_cont = &{ $pattern->[3] }( $exp, @{$pattern}[ 4 .. $#{$pattern} ] );
							} else {
								$exp_cont = &{ $pattern->[3] }($exp);
							}
						}
						if ( $exp_cont and $exp_cont eq exp_continue ) {
							print STDERR ("Continuing expect, restarting timeout...\r\n")
								if ( ${*$exp}{exp_Exp_Internal}
								or $Expect::Debug );
							$start_loop_time = time(); # restart timeout count
							next READLOOP;
						} elsif ( $exp_cont
							and $exp_cont eq exp_continue_timeout )
						{
							print STDERR ("Continuing expect...\r\n")
								if ( ${*$exp}{exp_Exp_Internal}
								or $Expect::Debug );
							next READLOOP;
						}
						last READLOOP;
					}
					print STDERR "No.\r\n" if ${*$exp}{exp_Exp_Internal};
				}
				print STDERR "\r\n" if ${*$exp}{exp_Exp_Internal};

				# don't have to match again until we get new data
				${*$exp}{exp_New_Data} = 0;
			}
		} # End of matching section

		# No match, let's see what is pending on the filehandles...
		print STDERR (
			"Waiting for new data (",
			defined($time_left) ? $time_left : 'unlimited',
			" seconds)...\r\n",
		) if ( $Expect::Exp_Internal or $Expect::Debug );
		my $nfound;
		SELECT: {
			$nfound = select( $rmask, undef, undef, $time_left );
			if ( $nfound < 0 ) {
				if ( $!{EINTR} and $Expect::IgnoreEintr ) {
					print STDERR ("ignoring EINTR, restarting select()...\r\n")
						if ( $Expect::Exp_Internal or $Expect::Debug );
					next SELECT;
				}
				print STDERR ("select() returned error code '$!'\r\n")
					if ( $Expect::Exp_Internal or $Expect::Debug );

				# returned error
				$err = "4:$!";
				last READLOOP;
			}
		}

		# go until we don't find something (== timeout).
		if ( $nfound == 0 ) {

			# No pattern, no EOF. Did we time out?
			$err = "1:TIMEOUT";
			foreach my $pat (@params) {
				foreach my $exp ( @{ $pat->[0] } ) {
					$before = ${*$exp}{exp_Before} = ${*$exp}{exp_Accum};
					next if not defined $exp->fileno(); # skip already closed
					${*$exp}{exp_Error} = $err unless ${*$exp}{exp_Error};
				}
			}
			print STDERR ("TIMEOUT\r\n")
				if ( $Expect::Debug or $Expect::Exp_Internal );
			if ($timeout_hook) {
				my $ret;
				print STDERR ("Calling timeout function $timeout_hook...\r\n")
					if ( $Expect::Debug or $Expect::Exp_Internal );
				if ( ref($timeout_hook) eq 'CODE' ) {
					$ret = &{$timeout_hook}( $params[0]->[0] );
				} else {
					if ( $#{$timeout_hook} > 3 ) {
						$ret = &{ $timeout_hook->[3] }(
							$params[0]->[0],
							@{$timeout_hook}[ 4 .. $#{$timeout_hook} ]
						);
					} else {
						$ret = &{ $timeout_hook->[3] }( $params[0]->[0] );
					}
				}
				if ( $ret and $ret eq exp_continue ) {
					$start_loop_time = time(); # restart timeout count
					next READLOOP;
				}
			}
			last READLOOP;
		}

		my @bits = split( //, unpack( 'b*', $rmask ) );
		foreach my $pat (@params) {
			foreach my $exp ( @{ $pat->[0] } ) {
				next if not defined $exp->fileno(); # skip already closed
				if ( $bits[ $exp->fileno() ] ) {
					print STDERR ("${*$exp}{exp_Pty_Handle}: new data.\r\n")
						if $Expect::Debug;

					# read in what we found.
					my $buffer;
					my $nread = sysread( $exp, $buffer, 2048 );

					# Make errors (nread undef) show up as EOF.
					$nread = 0 unless defined($nread);

					if ( $nread == 0 ) {
						print STDERR ("${*$exp}{exp_Pty_Handle}: EOF\r\n")
							if ($Expect::Debug);
						$before = ${*$exp}{exp_Before} = $exp->clear_accum();
						$err = "2:EOF";
						${*$exp}{exp_Error}   = $err;
						${*$exp}{exp_Has_EOF} = 1;
						$exp_cont = undef;
						foreach my $eof_pat ( grep { $_->[1] eq '-eof' } @{$pat}[ 1 .. $#{$pat} ] ) {
							my $ret;
							print STDERR ( "Calling EOF hook $eof_pat->[3]...\r\n", )
								if ($Expect::Debug);
							if ( $#{$eof_pat} > 3 ) {

								# call with parameters if given
								$ret = &{ $eof_pat->[3] }( $exp, @{$eof_pat}[ 4 .. $#{$eof_pat} ] );
							} else {
								$ret = &{ $eof_pat->[3] }($exp);
							}
							if ($ret
								and (  $ret eq exp_continue
									or $ret eq exp_continue_timeout )
								)
							{
								$exp_cont = $ret;
							}
						}

						# is it dead?
						if ( defined( ${*$exp}{exp_Pid} ) ) {
							my $ret =
								waitpid( ${*$exp}{exp_Pid}, POSIX::WNOHANG );
							if ( $ret == ${*$exp}{exp_Pid} ) {
								printf STDERR (
									"%s: exit(0x%02X)\r\n",
									${*$exp}{exp_Pty_Handle}, $?
								) if ($Expect::Debug);
								$err = "3:Child PID ${*$exp}{exp_Pid} exited with status $?";
								${*$exp}{exp_Error} = $err;
								${*$exp}{exp_Exit}  = $?;
								delete $Expect::Spawned_PIDs{ ${*$exp}{exp_Pid} };
								${*$exp}{exp_Pid} = undef;
							}
						}
						print STDERR ("${*$exp}{exp_Pty_Handle}: closing...\r\n")
							if ($Expect::Debug);
						$exp->hard_close();
						next;
					}
					print STDERR ("${*$exp}{exp_Pty_Handle}: read $nread byte(s).\r\n")
						if ($Expect::Debug);

					# ugly hack for broken solaris ttys that spew <blank><backspace>
					# into our pretty output
					$buffer =~ s/ \cH//g if not ${*$exp}{exp_Raw_Pty};

					# Append it to the accumulator.
					${*$exp}{exp_Accum} .= $buffer;
					if ( exists ${*$exp}{exp_Max_Accum}
						and ${*$exp}{exp_Max_Accum} )
					{
						${*$exp}{exp_Accum} = $exp->_trim_length(
							${*$exp}{exp_Accum},
							${*$exp}{exp_Max_Accum}
						);
					}
					${*$exp}{exp_New_Data} = 1; # next round we try to match again

					$exp_cont = exp_continue
						if ( exists ${*$exp}{exp_Continue}
						and ${*$exp}{exp_Continue} );

					# Now propagate what we have read to other listeners...
					$exp->_print_handles($buffer);

					# End handle reading section.
				}
			}
		} # end read loop
		$start_loop_time = time() # restart timeout count
			if ( $exp_cont and $exp_cont eq exp_continue );
	}

	# End READLOOP

	# Post loop. Do we have anything?
	# Tell us status
	if ( $Expect::Debug or $Expect::Exp_Internal ) {
		if ($exp_matched) {
			print STDERR (
				"Returning from expect ",
				${*$exp_matched}{exp_Error} ? 'un' : '',
				"successfully.",
				${*$exp_matched}{exp_Error}
				? "\r\n  Error: ${*$exp_matched}{exp_Error}."
				: '',
				"\r\n"
			);
		} else {
			print STDERR ("Returning from expect with TIMEOUT or EOF\r\n");
		}
		if ( $Expect::Debug and $exp_matched ) {
			print STDERR "  ${*$exp_matched}{exp_Pty_Handle}: accumulator: `";
			if ( ${*$exp_matched}{exp_Error} ) {
				print STDERR (
					$exp_matched->_trim_length( _make_readable( ${*$exp_matched}{exp_Before} ) ),
					"'\r\n"
				);
			} else {
				print STDERR (
					$exp_matched->_trim_length( _make_readable( ${*$exp_matched}{exp_Accum} ) ),
					"'\r\n"
				);
			}
		}
	}

	if ($exp_matched) {
		return wantarray
			? (
			${*$exp_matched}{exp_Match_Number}, ${*$exp_matched}{exp_Error},
			${*$exp_matched}{exp_Match},        ${*$exp_matched}{exp_Before},
			${*$exp_matched}{exp_After},        $exp_matched,
			)
			: ${*$exp_matched}{exp_Match_Number};
	}

	return wantarray ? ( undef, $err, undef, $before, undef, undef ) : undef;
}

# Patterns are arrays that consist of
# [ $pattern_type, $pattern, $sub, @subparms ]
# optional $pattern_type is '-re' (RegExp, default) or '-ex' (exact);
# $sub is optional CODE ref, which is called as &{$sub}($exp, @subparms)
#   if pattern matched;
# the $parm_nr gets unshifted onto the array for reporting purposes.

sub _add_patterns_to_list {
	my ($listref, $timeoutlistref,$store_parm_nr, @params) = @_;

	# $timeoutlistref gets timeout patterns
	my $parm_nr        = $store_parm_nr || 1;
	foreach my $parm (@params) {
		if ( not ref($parm) eq 'ARRAY' ) {
			return "Parameter #$parm_nr is not an ARRAY ref.";
		}
		$parm = [@$parm];                    # make copy
		if ( $parm->[0] =~ m/\A-/ ) {

			# it's an option
			if (    $parm->[0] ne '-re'
				and $parm->[0] ne '-ex' )
			{
				return "Unknown option $parm->[0] in pattern #$parm_nr";
			}
		} else {
			if ( $parm->[0] eq 'timeout' ) {
				if ( defined $timeoutlistref ) {
					splice @$parm, 0, 1, ( "-$parm->[0]", undef );
					unshift @$parm, $store_parm_nr ? $parm_nr : undef;
					push @$timeoutlistref, $parm;
				}
				next;
			} elsif ( $parm->[0] eq 'eof' ) {
				splice @$parm, 0, 1, ( "-$parm->[0]", undef );
			} else {
				unshift @$parm, '-re'; # defaults to RegExp
			}
		}
		if ( @$parm > 2 ) {
			if ( ref( $parm->[2] ) ne 'CODE' ) {
				croak(
					"Pattern #$parm_nr doesn't have a CODE reference",
					"after the pattern."
				);
			}
		} else {
			push @$parm, undef;        # make sure we have three elements
		}

		unshift @$parm, $store_parm_nr ? $parm_nr : undef;
		push @$listref, $parm;
		$parm_nr++;
	}

	return;
}

######################################################################
# $process->interact([$in_handle],[$escape sequence])
# If you don't specify in_handle STDIN  will be used.
sub interact {
	my ($self, $infile, $escape_sequence) = @_;

	my $outfile;
	my @old_group = $self->set_group();

	# If the handle is STDIN we'll
	# $infile->fileno == 0 should be stdin.. follow stdin rules.
	no strict 'subs'; # Allow bare word 'STDIN'
	unless ( defined($infile) ) {
		# We need a handle object Associated with STDIN.
		$infile = IO::File->new;
		$infile->IO::File::fdopen( STDIN, 'r' );
		$outfile = IO::File->new;
		$outfile->IO::File::fdopen( STDOUT, 'w' );
	} elsif ( fileno($infile) == fileno(STDIN) ) {

		# With STDIN we want output to go to stdout.
		$outfile = IO::File->new;
		$outfile->IO::File::fdopen( STDOUT, 'w' );
	} else {
		undef($outfile);
	}

	# Here we assure ourselves we have an Expect object.
	my $in_object = Expect->exp_init($infile);
	if ( defined($outfile) ) {

		# as above.. we want output to go to stdout if we're given stdin.
		my $out_object = Expect->exp_init($outfile);
		$out_object->manual_stty(1);
		$self->set_group($out_object);
	} else {
		$self->set_group($in_object);
	}
	$in_object->set_group($self);
	$in_object->set_seq( $escape_sequence, undef ) if defined($escape_sequence);

	# interconnect normally sets stty -echo raw. Interact really sort
	# of implies we don't do that by default. If anyone wanted to they could
	# set it before calling interact, of use interconnect directly.
	my $old_manual_stty_val = $self->manual_stty();
	$self->manual_stty(1);

	# I think this is right. Don't send stuff from in_obj to stdout by default.
	# in theory whatever 'self' is should echo what's going on.
	my $old_log_stdout_val = $self->log_stdout();
	$self->log_stdout(0);
	$in_object->log_stdout(0);

	# Allow for the setting of an optional EOF escape function.
	#  $in_object->set_seq('EOF',undef);
	#  $self->set_seq('EOF',undef);
	Expect::interconnect( $self, $in_object );
	$self->log_stdout($old_log_stdout_val);
	$self->set_group(@old_group);

	# If old_group was undef, make sure that occurs. This is a slight hack since
	# it modifies the value directly.
	# Normally an undef passed to set_group will return the current groups.
	# It is possible that it may be of worth to make it possible to undef
	# The current group without doing this.
	unless (@old_group) {
		@{ ${*$self}{exp_Listen_Group} } = ();
	}
	$self->manual_stty($old_manual_stty_val);

	return;
}

sub interconnect {
	my (@handles) = @_;

	#  my ($handle)=(shift); call as Expect::interconnect($spawn1,$spawn2,...)
	my ( $nread );
	my ( $rout, $emask, $eout );
	my ( $escape_character_buffer );
	my ( $read_mask, $temp_mask ) = ( '', '' );

	# Get read/write handles
	foreach my $handle (@handles) {
		$temp_mask = '';
		vec( $temp_mask, $handle->fileno(), 1 ) = 1;

		# Under Linux w/ 5.001 the next line comes up w/ 'Uninit var.'.
		# It appears to be impossible to make the warning go away.
		# doing something like $temp_mask='' unless defined ($temp_mask)
		# has no effect whatsoever. This may be a bug in 5.001.
		$read_mask = $read_mask | $temp_mask;
	}
	if ($Expect::Debug) {
		print STDERR "Read handles:\r\n";
		foreach my $handle (@handles) {
			print STDERR "\tRead handle: ";
			print STDERR "'${*$handle}{exp_Pty_Handle}'\r\n";
			print STDERR "\t\tListen Handles:";
			foreach my $write_handle ( @{ ${*$handle}{exp_Listen_Group} } ) {
				print STDERR " '${*$write_handle}{exp_Pty_Handle}'";
			}
			print STDERR ".\r\n";
		}
	}

	#  I think if we don't set raw/-echo here we may have trouble. We don't
	# want a bunch of echoing crap making all the handles jabber at each other.
	foreach my $handle (@handles) {
		unless ( ${*$handle}{"exp_Manual_Stty"} ) {

			# This is probably O/S specific.
			${*$handle}{exp_Stored_Stty} = $handle->exp_stty('-g');
			print STDERR "Setting tty for ${*$handle}{exp_Pty_Handle} to 'raw -echo'.\r\n"
				if ${*$handle}{"exp_Debug"};
			$handle->exp_stty("raw -echo");
		}
		foreach my $write_handle ( @{ ${*$handle}{exp_Listen_Group} } ) {
			unless ( ${*$write_handle}{"exp_Manual_Stty"} ) {
				${*$write_handle}{exp_Stored_Stty} =
					$write_handle->exp_stty('-g');
				print STDERR "Setting ${*$write_handle}{exp_Pty_Handle} to 'raw -echo'.\r\n"
					if ${*$handle}{"exp_Debug"};
				$write_handle->exp_stty("raw -echo");
			}
		}
	}

	print STDERR "Attempting interconnection\r\n" if $Expect::Debug;

	# Wait until the process dies or we get EOF
	# In the case of !${*$handle}{exp_Pid} it means
	# the handle was exp_inited instead of spawned.
	CONNECT_LOOP:

	# Go until we have a reason to stop
	while (1) {

		# test each handle to see if it's still alive.
		foreach my $read_handle (@handles) {
			waitpid( ${*$read_handle}{exp_Pid}, WNOHANG )
				if ( exists( ${*$read_handle}{exp_Pid} )
				and ${*$read_handle}{exp_Pid} );
			if (    exists( ${*$read_handle}{exp_Pid} )
				and ( ${*$read_handle}{exp_Pid} )
				and ( !kill( 0, ${*$read_handle}{exp_Pid} ) ) )
			{
				print STDERR
					"Got EOF (${*$read_handle}{exp_Pty_Handle} died) reading ${*$read_handle}{exp_Pty_Handle}\r\n"
					if ${*$read_handle}{"exp_Debug"};
				last CONNECT_LOOP
					unless defined( ${ ${*$read_handle}{exp_Function} }{"EOF"} );
				last CONNECT_LOOP
					unless &{ ${ ${*$read_handle}{exp_Function} }{"EOF"} }
					( @{ ${ ${*$read_handle}{exp_Parameters} }{"EOF"} } );
			}
		}

		# Every second? No, go until we get something from someone.
		my $nfound = select( $rout = $read_mask, undef, $eout = $emask, undef );

		# Is there anything to share?  May be -1 if interrupted by a signal...
		next CONNECT_LOOP if not defined $nfound or $nfound < 1;

		# Which handles have stuff?
		my @bits = split( //, unpack( 'b*', $rout ) );
		$eout = 0 unless defined($eout);
		my @ebits = split( //, unpack( 'b*', $eout ) );

		#    print "Ebits: $eout\r\n";
		foreach my $read_handle (@handles) {
			if ( $bits[ $read_handle->fileno() ] ) {
				$nread = sysread(
					$read_handle, ${*$read_handle}{exp_Pty_Buffer},
					1024
				);

				# Appease perl -w
				$nread = 0 unless defined($nread);
				print STDERR "interconnect: read $nread byte(s) from ${*$read_handle}{exp_Pty_Handle}.\r\n"
					if ${*$read_handle}{"exp_Debug"} > 1;

				# Test for escape seq. before printing.
				# Appease perl -w
				$escape_character_buffer = ''
					unless defined($escape_character_buffer);
				$escape_character_buffer .= ${*$read_handle}{exp_Pty_Buffer};
				foreach my $escape_sequence ( keys( %{ ${*$read_handle}{exp_Function} } ) ) {
					print STDERR "Tested escape sequence $escape_sequence from ${*$read_handle}{exp_Pty_Handle}"
						if ${*$read_handle}{"exp_Debug"} > 1;

					# Make sure it doesn't grow out of bounds.
					$escape_character_buffer = $read_handle->_trim_length(
						$escape_character_buffer,
						${*$read_handle}{"exp_Max_Accum"}
					) if ( ${*$read_handle}{"exp_Max_Accum"} );
					if ( $escape_character_buffer =~ /($escape_sequence)/ ) {
						my $match = $1;
						if ( ${*$read_handle}{"exp_Debug"} ) {
							print STDERR
								"\r\ninterconnect got escape sequence from ${*$read_handle}{exp_Pty_Handle}.\r\n";

							# I'm going to make the esc. seq. pretty because it will
							# probably contain unprintable characters.
							print STDERR "\tEscape Sequence: '"
								. _trim_length(
								undef,
								_make_readable($escape_sequence)
								) . "'\r\n";
							print STDERR "\tMatched by string: '" . _trim_length( undef, _make_readable($match) ) . "'\r\n";
						}

						# Print out stuff before the escape.
						# Keep in mind that the sequence may have been split up
						# over several reads.
						# Let's get rid of it from this read. If part of it was
						# in the last read there's not a lot we can do about it now.
						if ( ${*$read_handle}{exp_Pty_Buffer} =~ /([\w\W]*)($escape_sequence)/ ) {
							$read_handle->_print_handles($1);
						} else {
							$read_handle->_print_handles( ${*$read_handle}{exp_Pty_Buffer} );
						}

						# Clear the buffer so no more matches can be made and it will
						# only be printed one time.
						${*$read_handle}{exp_Pty_Buffer} = '';
						$escape_character_buffer = '';

						# Do the function here. Must return non-zero to continue.
						# More cool syntax. Maybe I should turn these in to objects.
						last CONNECT_LOOP
							unless &{ ${ ${*$read_handle}{exp_Function} }{$escape_sequence} }
							( @{ ${ ${*$read_handle}{exp_Parameters} }{$escape_sequence} } );
					}
				}
				$nread = 0 unless defined($nread); # Appease perl -w?
				waitpid( ${*$read_handle}{exp_Pid}, WNOHANG )
					if ( defined( ${*$read_handle}{exp_Pid} )
					&& ${*$read_handle}{exp_Pid} );
				if ( $nread == 0 ) {
					print STDERR "Got EOF reading ${*$read_handle}{exp_Pty_Handle}\r\n"
						if ${*$read_handle}{"exp_Debug"};
					last CONNECT_LOOP
						unless defined( ${ ${*$read_handle}{exp_Function} }{"EOF"} );
					last CONNECT_LOOP
						unless &{ ${ ${*$read_handle}{exp_Function} }{"EOF"} }
						( @{ ${ ${*$read_handle}{exp_Parameters} }{"EOF"} } );
				}
				last CONNECT_LOOP if ( $nread < 0 ); # This would be an error
				$read_handle->_print_handles( ${*$read_handle}{exp_Pty_Buffer} );
			}

			# I'm removing this because I haven't determined what causes exceptions
			# consistently.
			if (0) #$ebits[$read_handle->fileno()])
			{
				print STDERR "Got Exception reading ${*$read_handle}{exp_Pty_Handle}\r\n"
					if ${*$read_handle}{"exp_Debug"};
				last CONNECT_LOOP
					unless defined( ${ ${*$read_handle}{exp_Function} }{"EOF"} );
				last CONNECT_LOOP
					unless &{ ${ ${*$read_handle}{exp_Function} }{"EOF"} }
					( @{ ${ ${*$read_handle}{exp_Parameters} }{"EOF"} } );
			}
		}
	}
	foreach my $handle (@handles) {
		unless ( ${*$handle}{"exp_Manual_Stty"} ) {
			$handle->exp_stty( ${*$handle}{exp_Stored_Stty} );
		}
		foreach my $write_handle ( @{ ${*$handle}{exp_Listen_Group} } ) {
			unless ( ${*$write_handle}{"exp_Manual_Stty"} ) {
				$write_handle->exp_stty( ${*$write_handle}{exp_Stored_Stty} );
			}
		}
	}

	return;
}

# user can decide if log output gets also sent to logfile
sub print_log_file {
	my ($self, @params) = @_;

	if ( ${*$self}{exp_Log_File} ) {
		if ( ref( ${*$self}{exp_Log_File} ) eq 'CODE' ) {
			${*$self}{exp_Log_File}->(@params);
		} else {
			${*$self}{exp_Log_File}->print(@params);
		}
	}

	return;
}

# we provide our own print so we can debug what gets sent to the
# processes...
sub print {
	my ( $self, @args ) = @_;

	return if not defined $self->fileno(); # skip if closed
	if ( ${*$self}{exp_Exp_Internal} ) {
		my $args = _make_readable( join( '', @args ) );
		cluck "Sending '$args' to ${*$self}{exp_Pty_Handle}\r\n";
	}
	foreach my $arg (@args) {
		while ( length($arg) > 80 ) {
			$self->SUPER::print( substr( $arg, 0, 80 ) );
			$arg = substr( $arg, 80 );
		}
		$self->SUPER::print($arg);
	}

	return;
}

# make an alias for Tcl/Expect users for a DWIM experience...
*send = \&print;

# This is an Expect standard. It's nice for talking to modems and the like
# where from time to time they get unhappy if you send items too quickly.
sub send_slow {
	my ($self, $sleep_time, @chunks) = @_;

	return if not defined $self->fileno(); # skip if closed

	# Flushing makes it so each character can be seen separately.
	my $chunk;
	while ( $chunk = shift @chunks ) {
		my @linechars = split( '', $chunk );
		foreach my $char (@linechars) {

			# How slow?
			select( undef, undef, undef, $sleep_time );

			print $self $char;
			print STDERR "Printed character \'" . _make_readable($char) . "\' to ${*$self}{exp_Pty_Handle}.\r\n"
				if ${*$self}{"exp_Debug"} > 1;

			# I think I can get away with this if I save it in accum
			if ( ${*$self}{"exp_Log_Stdout"} || ${*$self}{exp_Log_Group} ) {
				my $rmask = "";
				vec( $rmask, $self->fileno(), 1 ) = 1;

				# .01 sec granularity should work. If we miss something it will
				# probably get flushed later, maybe in an expect call.
				while ( select( $rmask, undef, undef, .01 ) ) {
					my $ret = sysread( $self, ${*$self}{exp_Pty_Buffer}, 1024 );
					last if not defined $ret or $ret == 0;

					# Is this necessary to keep? Probably.. #
					# if you need to expect it later.
					${*$self}{exp_Accum} .= ${*$self}{exp_Pty_Buffer};
					${*$self}{exp_Accum} = $self->_trim_length(
						${*$self}{exp_Accum},
						${*$self}{"exp_Max_Accum"}
					) if ( ${*$self}{"exp_Max_Accum"} );
					$self->_print_handles( ${*$self}{exp_Pty_Buffer} );
					print STDERR "Received \'"
						. $self->_trim_length( _make_readable($char) )
						. "\' from ${*$self}{exp_Pty_Handle}\r\n"
						if ${*$self}{"exp_Debug"} > 1;
				}
			}
		}
	}

	return;
}

sub test_handles {
	my ($timeout, @handle_list)  = @_;

	# This should be called by Expect::test_handles($timeout,@objects);
	my ( $allmask, $rout );
	foreach my $handle (@handle_list) {
		my $rmask = '';
		vec( $rmask, $handle->fileno(), 1 ) = 1;
		$allmask = '' unless defined($allmask);
		$allmask = $allmask | $rmask;
	}
	my $nfound = select( $rout = $allmask, undef, undef, $timeout );
	return () unless $nfound;

	# Which handles have stuff?
	my @bits = split( //, unpack( 'b*', $rout ) );

	my $handle_num  = 0;
	my @return_list = ();
	foreach my $handle (@handle_list) {

		# I go to great lengths to get perl -w to shut the hell up.
		if ( defined( $bits[ $handle->fileno() ] )
			and ( $bits[ $handle->fileno() ] ) )
		{
			push( @return_list, $handle_num );
		}
	} continue {
		$handle_num++;
	}

	return @return_list;
}

# Be nice close. This should emulate what an interactive shell does after a
# command finishes... sort of. We're not as patient as a shell.
sub soft_close {
	my ($self) = @_;

	my ( $nfound, $nread, $rmask, $end_time, $temp_buffer );

	# Give it 15 seconds to cough up an eof.
	cluck "Closing ${*$self}{exp_Pty_Handle}.\r\n" if ${*$self}{exp_Debug};
	return -1 if not defined $self->fileno(); # skip if handle already closed
	unless ( exists ${*$self}{exp_Has_EOF} and ${*$self}{exp_Has_EOF} ) {
		$end_time = time() + 15;
		while ( $end_time > time() ) {
			my $select_time = $end_time - time();

			# Sanity check.
			$select_time = 0 if $select_time < 0;
			$rmask = '';
			vec( $rmask, $self->fileno(), 1 ) = 1;
			($nfound) = select( $rmask, undef, undef, $select_time );
			last unless ( defined($nfound) && $nfound );
			$nread = sysread( $self, $temp_buffer, 8096 );

			# 0 = EOF.
			unless ( defined($nread) && $nread ) {
				print STDERR "Got EOF from ${*$self}{exp_Pty_Handle}.\r\n"
					if ${*$self}{exp_Debug};
				last;
			}
			$self->_print_handles($temp_buffer);
		}
		if ( ( $end_time <= time() ) && ${*$self}{exp_Debug} ) {
			print STDERR "Timed out waiting for an EOF from ${*$self}{exp_Pty_Handle}.\r\n";
		}
	}
	my $close_status = $self->close();
	if ( $close_status && ${*$self}{exp_Debug} ) {
		print STDERR "${*$self}{exp_Pty_Handle} closed.\r\n";
	}

	# quit now if it isn't a process.
	return $close_status unless defined( ${*$self}{exp_Pid} );

	# Now give it 15 seconds to die.
	$end_time = time() + 15;
	while ( $end_time > time() ) {
		my $returned_pid = waitpid( ${*$self}{exp_Pid}, &WNOHANG );

		# Stop here if the process dies.
		if ( defined($returned_pid) && $returned_pid ) {
			delete $Expect::Spawned_PIDs{$returned_pid};
			if ( ${*$self}{exp_Debug} ) {
				printf STDERR (
					"Pid %d of %s exited, Status: 0x%02X\r\n",
					${*$self}{exp_Pid},
					${*$self}{exp_Pty_Handle}, $?
				);
			}
			${*$self}{exp_Pid}  = undef;
			${*$self}{exp_Exit} = $?;
			return ${*$self}{exp_Exit};
		}
		sleep 1; # Keep loop nice.
	}

	# Send it a term if it isn't dead.
	if ( ${*$self}{exp_Debug} ) {
		print STDERR "${*$self}{exp_Pty_Handle} not exiting, sending TERM.\r\n";
	}
	kill TERM => ${*$self}{exp_Pid};

	# Now to be anal retentive.. wait 15 more seconds for it to die.
	$end_time = time() + 15;
	while ( $end_time > time() ) {
		my $returned_pid = waitpid( ${*$self}{exp_Pid}, &WNOHANG );
		if ( defined($returned_pid) && $returned_pid ) {
			delete $Expect::Spawned_PIDs{$returned_pid};
			if ( ${*$self}{exp_Debug} ) {
				printf STDERR (
					"Pid %d of %s terminated, Status: 0x%02X\r\n",
					${*$self}{exp_Pid},
					${*$self}{exp_Pty_Handle}, $?
				);
			}
			${*$self}{exp_Pid}  = undef;
			${*$self}{exp_Exit} = $?;
			return $?;
		}
		sleep 1;
	}

	# Since this is a 'soft' close, sending it a -9 would be inappropriate.
	return;
}

# 'Make it go away' close.
sub hard_close {
	my ($self) = @_;

	cluck "Closing ${*$self}{exp_Pty_Handle}.\r\n" if ${*$self}{exp_Debug};

	# Don't wait for an EOF.
	my $close_status = $self->close();
	if ( $close_status && ${*$self}{exp_Debug} ) {
		print STDERR "${*$self}{exp_Pty_Handle} closed.\r\n";
	}

	# Return now if handle.
	return $close_status unless defined( ${*$self}{exp_Pid} );

	# Now give it 5 seconds to die. Less patience here if it won't die.
	my $end_time = time() + 5;
	while ( $end_time > time() ) {
		my $returned_pid = waitpid( ${*$self}{exp_Pid}, &WNOHANG );

		# Stop here if the process dies.
		if ( defined($returned_pid) && $returned_pid ) {
			delete $Expect::Spawned_PIDs{$returned_pid};
			if ( ${*$self}{exp_Debug} ) {
				printf STDERR (
					"Pid %d of %s terminated, Status: 0x%02X\r\n",
					${*$self}{exp_Pid},
					${*$self}{exp_Pty_Handle}, $?
				);
			}
			${*$self}{exp_Pid}  = undef;
			${*$self}{exp_Exit} = $?;
			return ${*$self}{exp_Exit};
		}
		sleep 1; # Keep loop nice.
	}

	# Send it a term if it isn't dead.
	if ( ${*$self}{exp_Debug} ) {
		print STDERR "${*$self}{exp_Pty_Handle} not exiting, sending TERM.\r\n";
	}
	kill TERM => ${*$self}{exp_Pid};

	# wait 15 more seconds for it to die.
	$end_time = time() + 15;
	while ( $end_time > time() ) {
		my $returned_pid = waitpid( ${*$self}{exp_Pid}, &WNOHANG );
		if ( defined($returned_pid) && $returned_pid ) {
			delete $Expect::Spawned_PIDs{$returned_pid};
			if ( ${*$self}{exp_Debug} ) {
				printf STDERR (
					"Pid %d of %s terminated, Status: 0x%02X\r\n",
					${*$self}{exp_Pid},
					${*$self}{exp_Pty_Handle}, $?
				);
			}
			${*$self}{exp_Pid}  = undef;
			${*$self}{exp_Exit} = $?;
			return ${*$self}{exp_Exit};
		}
		sleep 1;
	}
	kill KILL => ${*$self}{exp_Pid};

	# wait 5 more seconds for it to die.
	$end_time = time() + 5;
	while ( $end_time > time() ) {
		my $returned_pid = waitpid( ${*$self}{exp_Pid}, &WNOHANG );
		if ( defined($returned_pid) && $returned_pid ) {
			delete $Expect::Spawned_PIDs{$returned_pid};
			if ( ${*$self}{exp_Debug} ) {
				printf STDERR (
					"Pid %d of %s killed, Status: 0x%02X\r\n",
					${*$self}{exp_Pid},
					${*$self}{exp_Pty_Handle}, $?
				);
			}
			${*$self}{exp_Pid}  = undef;
			${*$self}{exp_Exit} = $?;
			return ${*$self}{exp_Exit};
		}
		sleep 1;
	}
	warn "Pid ${*$self}{exp_Pid} of ${*$self}{exp_Pty_Handle} is HUNG.\r\n";
	${*$self}{exp_Pid} = undef;

	return;
}

# These should not be called externally.

sub _init_vars {
	my ($self) = @_;

	# for every spawned process or filehandle.
	${*$self}{exp_Log_Stdout} = $Expect::Log_Stdout
		if defined($Expect::Log_Stdout);
	${*$self}{exp_Log_Group}     = $Expect::Log_Group;
	${*$self}{exp_Debug}         = $Expect::Debug;
	${*$self}{exp_Exp_Internal}  = $Expect::Exp_Internal;
	${*$self}{exp_Manual_Stty}   = $Expect::Manual_Stty;
	${*$self}{exp_Stored_Stty}   = 'sane';
	${*$self}{exp_Do_Soft_Close} = $Expect::Do_Soft_Close;

	# sysread doesn't like my or local vars.
	${*$self}{exp_Pty_Buffer} = '';

	# Initialize accumulator.
	${*$self}{exp_Max_Accum}  = $Expect::Exp_Max_Accum;
	${*$self}{exp_Accum}      = '';
	${*$self}{exp_NoTransfer} = 0;

	# create empty expect_before & after lists
	${*$self}{exp_expect_before_list} = [];
	${*$self}{exp_expect_after_list}  = [];

	return;
}

sub _make_readable {
	my ($s) = @_;

	$s = '' if not defined($s);
	study $s;          # Speed things up?
	$s =~ s/\\/\\\\/g; # So we can tell easily(?) what is a backslash
	$s =~ s/\n/\\n/g;
	$s =~ s/\r/\\r/g;
	$s =~ s/\t/\\t/g;
	$s =~ s/\'/\\\'/g; # So we can tell whassa quote and whassa notta quote.
	$s =~ s/\"/\\\"/g;

	# Formfeed (does anyone use formfeed?)
	$s =~ s/\f/\\f/g;
	$s =~ s/\010/\\b/g;

	# escape control chars high/low, but allow ISO 8859-1 chars
	$s =~ s/([\000-\037\177-\237\377])/sprintf("\\%03lo",ord($1))/ge;

	return $s;
}

sub _trim_length {
	my ($self, $string, $length) = @_;

	# This is sort of a reverse truncation function
	# Mostly so we don't have to see the full output when we're using
	# Also used if Max_Accum gets set to limit the size of the accumulator
	# for matching functions.
	# exp_internal

	croak('No string passed') if not defined $string;

	# If we're not passed a length (_trim_length is being used for debugging
	# purposes) AND debug >= 3, don't trim.
	return ($string)
		if (defined($self)
		and ${*$self}{"exp_Debug"} >= 3
		and ( !( defined($length) ) ) );
	my $indicate_truncation = ($length ? '' : '...');
	$length ||= 1021;
	return $string if $length >= length $string;

	# We wouldn't want the accumulator to begin with '...' if max_accum is passed
	# This is because this funct. gets called internally w/ max_accum
	# and is also used to print information back to the user.
	return $indicate_truncation . substr( $string, ( length($string) - $length ), $length );
}

sub _print_handles {
	my ($self, $print_this) = @_;

	# Given crap from 'self' and the handles self wants to print to, print to
	# them. these are indicated by the handle's 'group'
	if ( ${*$self}{exp_Log_Group} ) {
		foreach my $handle ( @{ ${*$self}{exp_Listen_Group} } ) {
			$print_this = '' unless defined($print_this);

			# Appease perl -w
			print STDERR "Printed '"
				. $self->_trim_length( _make_readable($print_this) )
				. "' to ${*$handle}{exp_Pty_Handle} from ${*$self}{exp_Pty_Handle}.\r\n"
				if ( ${*$handle}{"exp_Debug"} > 1 );
			print $handle $print_this;
		}
	}

	# If ${*$self}{exp_Pty_Handle} is STDIN this would make it echo.
	print STDOUT $print_this
		if ${*$self}{"exp_Log_Stdout"};
	$self->print_log_file($print_this);
	$| = 1; # This should not be necessary but autoflush() doesn't always work.

	return;
}

sub _get_mode {
	my ($handle)      = @_;

	my ($fcntl_flags) = '';

	# What mode are we opening with? use fcntl to find out.
	$fcntl_flags = fcntl( \*{$handle}, Fcntl::F_GETFL, $fcntl_flags );
	die "fcntl returned undef during exp_init of $handle, $!\r\n"
		unless defined($fcntl_flags);
	if ( $fcntl_flags | (Fcntl::O_RDWR) ) {
		return 'rw';
	} elsif ( $fcntl_flags | (Fcntl::O_WRONLY) ) {
		return 'w';
	} else {

		# Under Solaris (among others?) O_RDONLY is implemented as 0. so |O_RDONLY would fail.
		return 'r';
	}
}

sub _undef {
	return undef;

	# Seems a little retarded but &CORE::undef fails in interconnect.
	# This is used for the default escape sequence function.
	# w/out the leading & it won't compile.
}

# clean up child processes
sub DESTROY {
	my ($self) = @_;

	my $status = $?;   # save this as it gets mangled by the terminating spawned children
	if ( ${*$self}{exp_Do_Soft_Close} ) {
		$self->soft_close();
	}
	$self->hard_close();
	$? = $status;      # restore it. otherwise deleting an Expect object may mangle $?, which is unintuitive

	return;
}

1;
__END__

=head1 NAME

Expect - automate interactions with command line programs that expose a text terminal interface.

=head1 SYNOPSIS

  use Expect;

  # create an Expect object by spawning another process
  my $exp = Expect->spawn($command, @params)
    or die "Cannot spawn $command: $!\n";

  # or by using an already opened filehandle (e.g. from Net::Telnet)
  my $exp = Expect->exp_init(\*FILEHANDLE);

  # if you prefer the OO mindset:
  my $exp = Expect->new;
  $exp->raw_pty(1);
  $exp->spawn($command, @parameters)
    or die "Cannot spawn $command: $!\n";

  # send some string there:
  $exp->send("string\n");

  # or, for the filehandle mindset:
  print $exp "string\n";

  # then do some pattern matching with either the simple interface
  $patidx = $exp->expect($timeout, @match_patterns);

  # or multi-match on several spawned commands with callbacks,
  # just like the Tcl version
  $exp->expect($timeout,
             [ qr/regex1/ => sub { my $exp = shift;
                       $exp->send("response\n");
                       exp_continue; } ],
             [ "regexp2" , \&callback, @cbparms ],
            );

  # if no longer needed, do a soft_close to nicely shut down the command
  $exp->soft_close();

  # or be less patient with
  $exp->hard_close();

Expect.pm is built to either spawn a process or take an existing filehandle
and interact with it such that normally interactive tasks can be done
without operator assistance. This concept makes more sense if you are
already familiar with the versatile Tcl version of Expect.
The public functions that make up Expect.pm are:

  Expect->new()
  Expect::interconnect(@objects_to_be_read_from)
  Expect::test_handles($timeout, @objects_to_test)
  Expect::version($version_requested | undef);
  $object->spawn(@command)
  $object->clear_accum()
  $object->set_accum($value)
  $object->debug($debug_level)
  $object->exp_internal(0 | 1)
  $object->notransfer(0 | 1)
  $object->raw_pty(0 | 1)
  $object->stty(@stty_modes) # See the IO::Stty docs
  $object->slave()
  $object->before();
  $object->match();
  $object->after();
  $object->matchlist();
  $object->match_number();
  $object->error();
  $object->command();
  $object->exitstatus();
  $object->pty_handle();
  $object->do_soft_close();
  $object->restart_timeout_upon_receive(0 | 1);
  $object->interact($other_object, $escape_sequence)
  $object->log_group(0 | 1 | undef)
  $object->log_user(0 | 1 | undef)
  $object->log_file("filename" | $filehandle | \&coderef | undef)
  $object->manual_stty(0 | 1 | undef)
  $object->match_max($max_buffersize or undef)
  $object->pid();
  $object->send_slow($delay, @strings_to_send)
  $object->set_group(@listen_group_objects | undef)
  $object->set_seq($sequence,\&function,\@parameters);

There are several configurable package variables that affect the behavior of Expect. They are:

  $Expect::Debug;
  $Expect::Exp_Internal;
  $Expect::IgnoreEintr;
  $Expect::Log_Group;
  $Expect::Log_Stdout;
  $Expect::Manual_Stty;
  $Expect::Multiline_Matching;
  $Expect::Do_Soft_Close;

=head1 DESCRIPTION

See an explanation of L<What is Expect|http://code-maven.com/expect>

The Expect module is a successor of Comm.pl and a descendent of Chat.pl. It
more closely resembles the Tcl Expect language than its predecessors. It
does not contain any of the networking code found in Comm.pl. I suspect this
would be obsolete anyway given the advent of IO::Socket and external tools
such as netcat.

Expect.pm is an attempt to have more of a switch() & case feeling to make
decision processing more fluid.  Three separate types of debugging have
been implemented to make code production easier.

It is possible to interconnect multiple file handles (and processes) much
like Tcl's Expect. An attempt was made to enable all the features of Tcl's
Expect without forcing Tcl on the victim programmer :-) .

Please, before you consider using Expect, read the FAQs about
L</"I want to automate password entry for su/ssh/scp/rsh/..."> and
L</"I want to use Expect to automate [anything with a buzzword]...">


=head1 USAGE

=over 4

=item new

Creates a new Expect object, i.e. a pty.  You can change parameters on
it before actually spawning a command.  This is important if you want
to modify the terminal settings for the slave.  See slave() below.
The object returned is actually a reblessed IO::Pty filehandle, so see
there for additional methods.


=item Expect->exp_init(\*FILEHANDLE) I<or>

=item Expect->init(\*FILEHANDLE)

Initializes $new_handle_object for use with other Expect functions. It must
be passed a B<_reference_> to FILEHANDLE if you want it to work properly.
IO::File objects are preferable. Returns a reference to the newly created
object.

You can use only real filehandles, certain tied filehandles
(e.g. Net::SSH2) that lack a fileno() will not work. Net::Telnet
objects can be used but have been reported to work only for certain
hosts. YMMV.


=item Expect->spawn($command, @parameters) I<or>

=item $object->spawn($command, @parameters) I<or>

=item Expect->new($command, @parameters)

Forks and execs $command. Returns an Expect object upon success or
C<undef> if the fork was unsuccessful or the command could not be
found.  spawn() passes its parameters unchanged to Perls exec(), so
look there for detailed semantics.

Note that if spawn cannot exec() the given command, the Expect object
is still valid and the next expect() will see "Cannot exec", so you
can use that for error handling.

Also note that you cannot reuse an object with an already spawned
command, even if that command has exited.  Sorry, but you have to
allocate a new object...


=item $object->debug(0 | 1 | 2 | 3 | undef)

Sets debug level for $object. 1 refers to general debugging
information, 2 refers to verbose debugging and 0 refers to no
debugging. If you call debug() with no parameters it will return the
current debugging level.  When the object is created the debugging
level will match that $Expect::Debug, normally 0.

The '3' setting is new with 1.05, and adds the additional
functionality of having the _full_ accumulated buffer printed every
time data is read from an Expect object. This was implemented by
request. I recommend against using this unless you think you need it
as it can create quite a quantity of output under some circumstances..


=item $object->exp_internal(1 | 0)

Sets/unsets 'exp_internal' debugging. This is similar in nature to its Tcl
counterpart. It is extremely valuable when debugging expect() sequences.
When the object is created the exp_internal setting will match the value of
$Expect::Exp_Internal, normally 0. Returns the current setting if called
without parameters. It is highly recommended that you make use of the
debugging features lest you have angry code.


=item $object->raw_pty(1 | 0)

Set pty to raw mode before spawning.  This disables echoing, CR->LF
translation and an ugly hack for broken Solaris TTYs (which send
<space><backspace> to slow things down) and thus gives a more
pipe-like behaviour (which is important if you want to transfer binary
content).  Note that this must be set I<before> spawning the program.


=item $object->stty(qw(mode1 mode2...))

Sets the tty mode for $object's associated terminal to the given
modes.  Note that on many systems the master side of the pty is not a
tty, so you have to modify the slave pty instead, see next item.  This
needs IO::Stty installed, which is no longer required.


=item $object->slave()

Returns a filehandle to the slave part of the pty.  Very useful in modifying
the terminal settings:

  $object->slave->stty(qw(raw -echo));

Typical values are 'sane', 'raw', and 'raw -echo'.  Note that I
recommend setting the terminal to 'raw' or 'raw -echo', as this avoids
a lot of hassle and gives pipe-like (i.e. transparent) behaviour
(without the buffering issue).


=item $object->print(@strings) I<or>

=item $object->send(@strings)

Sends the given strings to the spawned command.  Note that the strings
are not logged in the logfile (see print_log_file) but will probably
be echoed back by the pty, depending on pty settings (default is echo)
and thus end up there anyway.  This must also be taken into account
when expect()ing for an answer: the next string will be the command
just sent.  I suggest setting the pty to raw, which disables echo and
makes the pty transparently act like a bidirectional pipe.


=item $object->expect($timeout, @match_patterns)

=over 4

=item Simple interface

Given $timeout in seconds Expect will wait for $object's handle to produce
one of the match_patterns, which are matched exactly by default. If you
want a regexp match, use a regexp object (C<qr//>) or prefix the pattern with '-re'.

  $object->expect(15, 'match me exactly', qr/match\s+me\s+exactly/);
  $object->expect(15, 'match me exactly','-re','match\s+me\s+exactly');

Due to o/s limitations $timeout should be a round number. If $timeout
is 0 Expect will check one time to see if $object's handle contains
any of the match_patterns. If $timeout is undef Expect
will wait forever for a pattern to match. If you don't want to 
explicitly put the timeout on all calls to C<expect>, you can set 
it via the C<timeout> method . If the first argument of C<expect> 
doesn't look like a number, that value will be used.

  $object->timeout(15);
  $object->expect('match me exactly','-re','match\s+me\s+exactly');


If called in a scalar context, expect() will return the position of
the matched pattern within @matched_patterns, or undef if no pattern was
matched. This is a position starting from 1, so if you want to know
which of an array of @matched_patterns matched you should subtract one
from the return value.

If called in an array context expect() will return
($matched_pattern_position, $error, $successfully_matching_string,
$before_match, and $after_match).

C<$matched_pattern_position> will contain the value that would have been
returned if expect() had been called in a scalar context.

C<$error> is
the error that occurred that caused expect() to return. $error will
contain a number followed by a string equivalent expressing the nature
of the error. Possible values are undef, indicating no error,
'1:TIMEOUT' indicating that $timeout seconds had elapsed without a
match, '2:EOF' indicating an eof was read from $object, '3: spawn
id($fileno) died' indicating that the process exited before matching
and '4:$!' indicating whatever error was set in $ERRNO during the last
read on $object's handle or during select(). All handles indicated by
set_group plus STDOUT will have all data to come out of $object
printed to them during expect() if log_group and log_stdout are set.

C<$successfully_matching_string>
C<$before_match>
C<$after_match>

Changed from older versions is the regular expression handling. By
default now all strings passed to expect() are treated as literals. To
match a regular expression pass '-re' as a parameter in front of the
pattern you want to match as a regexp.

This change makes it possible to match literals and regular expressions
in the same expect() call.

Also new is multiline matching. ^ will now match the beginning of
lines. Unfortunately, because perl doesn't use $/ in determining where
lines break using $ to find the end of a line frequently doesn't work. This
is because your terminal is returning "\r\n" at the end of every line. One
way to check for a pattern at the end of a line would be to use \r?$ instead
of $.

Example: Spawning telnet to a host, you might look for the escape
character.  telnet would return to you "\r\nEscape character is
'^]'.\r\n". To find this you might use $match='^Escape char.*\.\r?$';

  $telnet->expect(10,'-re',$match);

=item New more Tcl/Expect-like interface

  expect($timeout,
       '-i', [ $obj1, $obj2, ... ],
             [ $re_pattern, sub { ...; exp_continue; }, @subparms, ],
             [ 'eof', sub { ... } ],
             [ 'timeout', sub { ... }, \$subparm1 ],
       '-i', [ $objn, ...],
       '-ex', $exact_pattern, sub { ... },
              $exact_pattern, sub { ...; exp_continue_timeout; },
       '-re', $re_pattern, sub { ... },
       '-i', \@object_list, @pattern_list,
       ...);


It's now possible to expect on more than one connection at a time by
specifying 'C<-i>' and a single Expect object or a ref to an array
containing Expect objects, e.g.

 expect($timeout,
        '-i', $exp1, @patterns_1,
        '-i', [ $exp2, $exp3 ], @patterns_2_3,
       )

Furthermore, patterns can now be specified as array refs containing
[$regexp, sub { ...}, @optional_subprams] . When the pattern matches,
the subroutine is called with parameters ($matched_expect_obj,
@optional_subparms). The subroutine can return the symbol
`exp_continue' to continue the expect matching with timeout starting
anew or return the symbol `exp_continue_timeout' for continuing expect
without resetting the timeout count.

 $exp->expect($timeout,
              [ qr/username: /i, sub { my $self = shift;
                                       $self->send("$username\n");
                                       exp_continue; }],
              [ qr/password: /i, sub { my $self = shift;
                                       $self->send("$password\n");
                                       exp_continue; }],
             $shell_prompt);


`expect' is now exported by default.

=back

=item $object->exp_before() I<or>

=item $object->before()

before() returns the 'before' part of the last expect() call. If the last
expect() call didn't match anything, exp_before() will return the entire
output of the object accumulated before the expect() call finished.

Note that this is something different than Tcl Expects before()!!


=item $object->exp_after() I<or>

=item $object->after()

returns the 'after' part of the last expect() call. If the last
expect() call didn't match anything, exp_after() will return undef().


=item $object->exp_match() I<or>

=item $object->match()

returns the string matched by the last expect() call, undef if
no string was matched.


=item $object->exp_match_number() I<or>

=item $object->match_number()

exp_match_number() returns the number of the pattern matched by the last
expect() call. Keep in mind that the first pattern in a list of patterns is 1,
not 0. Returns undef if no pattern was matched.


=item $object->exp_matchlist() I<or>

=item $object->matchlist()

exp_matchlist() returns a list of matched substrings from the brackets
() inside the regexp that last matched. ($object->matchlist)[0]
thus corresponds to $1, ($object->matchlist)[1] to $2, etc.


=item $object->exp_error() I<or>

=item $object->error()

exp_error() returns the error generated by the last expect() call if
no pattern was matched. It is typically useful to examine the value returned by
before() to find out what the output of the object was in determining
why it didn't match any of the patterns.


=item $object->clear_accum()

Clear the contents of the accumulator for $object. This gets rid of
any residual contents of a handle after expect() or send_slow() such
that the next expect() call will only see new data from $object. The
contents of the accumulator are returned.


=item $object->set_accum($value)

Sets the content of the accumulator for $object to $value. The
previous content of the accumulator is returned.


=item $object->exp_command() I<or>

=item $object->command()

exp_command() returns the string that was used to spawn the command. Helpful
for debugging and for reused patternmatch subroutines.


=item $object->exp_exitstatus() I<or>

=item $object->exitstatus()

Returns the exit status of $object (if it already exited).


=item $object->exp_pty_handle() I<or>

=item $object->pty_handle()

Returns a string representation of the attached pty, for example:
`spawn id(5)' (pty has fileno 5), `handle id(7)' (pty was initialized
from fileno 7) or `STDIN'. Useful for debugging.


=item $object->restart_timeout_upon_receive(0 | 1)

If this is set to 1, the expect timeout is retriggered whenever something
is received from the spawned command.  This allows to perform some
aliveness testing and still expect for patterns.

    $exp->restart_timeout_upon_receive(1);
    $exp->expect($timeout,
                 [ timeout => \&report_timeout ],
                 [ qr/pattern/ => \&handle_pattern],
                );

Now the timeout isn't triggered if the command produces any kind of output,
i.e. is still alive, but you can act upon patterns in the output.


=item $object->notransfer(1 | 0)

Do not truncate the content of the accumulator after a match.
Normally, the accumulator is set to the remains that come after the
matched string.  Note that this setting is per object and not per
pattern, so if you want to have normal acting patterns that truncate
the accumulator, you have to add a

    $exp->set_accum($exp->after);

to their callback, e.g.

    $exp->notransfer(1);
    $exp->expect($timeout,
                 # accumulator not truncated, pattern1 will match again
                 [ "pattern1" => sub { my $self = shift;
                                       ...
                                     } ],
                 # accumulator truncated, pattern2 will not match again
                 [ "pattern2" => sub { my $self = shift;
                                       ...
                                       $self->set_accum($self->after());
                                     } ],
                );

This is only a temporary fix until I can rewrite the pattern matching
part so it can take that additional -notransfer argument.


=item Expect::interconnect(@objects);

Read from @objects and print to their @listen_groups until an escape sequence
is matched from one of @objects and the associated function returns 0 or undef.
The special escape sequence 'EOF' is matched when an object's handle returns
an end of file. Note that it is not necessary to include objects that only
accept data in @objects since the escape sequence is _read_ from an object.
Further note that the listen_group for a write-only object is always empty.
Why would you want to have objects listening to STDOUT (for example)?
By default every member of @objects _as well as every member of its listen
group_ will be set to 'raw -echo' for the duration of interconnection.
Setting $object->manual_stty() will stop this behavior per object.
The original tty settings will be restored as interconnect exits.

For a generic way to interconnect processes, take a look at L<IPC::Run>.


=item Expect::test_handles(@objects)

Given a set of objects determines which objects' handles have data ready
to be read. B<Returns an array> who's members are positions in @objects that
have ready handles. Returns undef if there are no such handles ready.


=item Expect::version($version_requested or undef);

Returns current version of Expect. As of .99 earlier versions are not
supported. Too many things were changed to make versioning possible.


=item $object->interact( C<\*FILEHANDLE, $escape_sequence>)

interact() is essentially a macro for calling interconnect() for
connecting 2 processes together. \*FILEHANDLE defaults to \*STDIN and
$escape_sequence defaults to undef. Interaction ceases when $escape_sequence
is read from B<FILEHANDLE>, not $object. $object's listen group will
consist solely of \*FILEHANDLE for the duration of the interaction.
\*FILEHANDLE will not be echoed on STDOUT.


=item $object->log_group(0 | 1 | undef)

Set/unset logging of $object to its 'listen group'. If set all objects
in the listen group will have output from $object printed to them during
$object->expect(), $object->send_slow(), and C<Expect::interconnect($object
, ...)>. Default value is on. During creation of $object the setting will
match the value of $Expect::Log_Group, normally 1.


=item $object->log_user(0 | 1 | undef) I<or>

=item $object->log_stdout(0 | 1 | undef)

Set/unset logging of object's handle to STDOUT. This corresponds to Tcl's
log_user variable. Returns current setting if called without parameters.
Default setting is off for initialized handles.  When a process object is
created (not a filehandle initialized with exp_init) the log_stdout setting
will match the value of $Expect::Log_Stdout variable, normally 1.
If/when you initialize STDIN it is usually associated with a tty which
will by default echo to STDOUT anyway, so be careful or you will have
multiple echoes.


=item $object->log_file("filename" | $filehandle | \&coderef | undef)

Log session to a file.  All characters send to or received from the
spawned process are written to the file.  Normally appends to the
logfile, but you can pass an additional mode of "w" to truncate the
file upon open():

  $object->log_file("filename", "w");

Returns the logfilehandle.

If called with an undef value, stops logging and closes logfile:

  $object->log_file(undef);

If called without argument, returns the logfilehandle:

  $fh = $object->log_file();

Can be set to a code ref, which will be called instead of printing
to the logfile:

  $object->log_file(\&myloggerfunc);


=item $object->print_log_file(@strings)

Prints to logfile (if opened) or calls the logfile hook function.
This allows the user to add arbitrary text to the logfile.  Note that
this could also be done as $object->log_file->print() but would only
work for log files, not code hooks.


=item $object->set_seq($sequence, \&function, \@function_parameters)

During Expect->interconnect() if $sequence is read from $object &function
will be executed with parameters @function_parameters. It is B<_highly
recommended_> that the escape sequence be a single character since the
likelihood is great that the sequence will be broken into to separate reads
from the $object's handle, making it impossible to strip $sequence from
getting printed to $object's listen group. \&function should be something
like 'main::control_w_function' and @function_parameters should be an
array defined by the caller, passed by reference to set_seq().
Your function should return a non-zero value if execution of interconnect()
is to resume after the function returns, zero or undefined if interconnect()
should return after your function returns.
The special sequence 'EOF' matches the end of file being reached by $object.
See interconnect() for details.


=item $object->set_group(@listener_objects)

@listener_objects is the list of objects that should have their handles
printed to by $object when Expect::interconnect, $object->expect() or
$object->send_slow() are called. Calling w/out parameters will return
the current list of the listener objects.


=item $object->manual_stty(0 | 1 | undef)

Sets/unsets whether or not Expect should make reasonable guesses as to
when and how to set tty parameters for $object. Will match
$Expect::Manual_Stty value (normally 0) when $object is created. If called
without parameters manual_stty() will return the current manual_stty setting.


=item $object->match_max($maximum_buffer_length | undef) I<or>

=item $object->max_accum($maximum_buffer_length | undef)

Set the maximum accumulator size for object. This is useful if you think
that the accumulator will grow out of hand during expect() calls. Since
the buffer will be matched by every match_pattern it may get slow if the
buffer gets too large. Returns current value if called without parameters.
Not defined by default.


=item $object->notransfer(0 | 1)

If set, matched strings will not be deleted from the accumulator.
Returns current value if called without parameters.  False by default.


=item $object->exp_pid() I<or>

=item $object->pid()

Return pid of $object, if one exists. Initialized filehandles will not have
pids (of course).


=item $object->send_slow($delay, @strings);

print each character from each string of @strings one at a time with $delay
seconds before each character. This is handy for devices such as modems
that can be annoying if you send them data too fast. After each character
$object will be checked to determine whether or not it has any new data ready
and if so update the accumulator for future expect() calls and print the
output to STDOUT and @listen_group if log_stdout and log_group are
appropriately set.

=back

=head2 Configurable Package Variables:

=over 4

=item $Expect::Debug

Defaults to 0. Newly created objects have a $object->debug() value
of $Expect::Debug. See $object->debug();

=item $Expect::Do_Soft_Close

Defaults to 0. When destroying objects, soft_close may take up to half
a minute to shut everything down.  From now on, only hard_close will
be called, which is less polite but still gives the process a chance
to terminate properly.  Set this to '1' for old behaviour.

=item $Expect::Exp_Internal

Defaults to 0. Newly created objects have a $object->exp_internal()
value of $Expect::Exp_Internal. See $object->exp_internal().

=item $Expect::IgnoreEintr

Defaults to 0. If set to 1, when waiting for new data, Expect will
ignore EINTR errors and restart the select() call instead.

=item $Expect::Log_Group

Defaults to 1. Newly created objects have a $object->log_group()
value of $Expect::Log_Group. See $object->log_group().

=item $Expect::Log_Stdout

Defaults to 1 for spawned commands, 0 for file handles
attached with exp_init(). Newly created objects have a
$object->log_stdout() value of $Expect::Log_Stdout. See
$object->log_stdout().

=item $Expect::Manual_Stty

Defaults to 0. Newly created objects have a $object->manual_stty()
value of $Expect::Manual_Stty. See $object->manual_stty().

=item $Expect::Multiline_Matching

Defaults to 1. Affects whether or not expect() uses the /m flag for
doing regular expression matching. If set to 1 /m is used.

This makes a difference when you are trying to match ^ and $. If
you have this on you can match lines in the middle of a page of output
using ^ and $ instead of it matching the beginning and end of the entire
expression. I think this is handy.

The $Expect::Multiline_Matching turns on and off Expect's multi-line
matching mode. But this only has an effect if you pass in a string, and
then use '-re' mode. If you pass in a regular expression value (via
qr//), then the qr//'s own flags are preserved irrespective of what it
gets interpolated into. There was a bug in Perl 5.8.x where interpolating
a regex without /m into a match with /m would incorrectly apply the /m
to the inner regex too, but this was fixed in Perl 5.10. The correct
behavior, as seen in Perl 5.10, is that if you pass in a regex (via
qr//), then $Expect::Multiline_Matching has no effect. 
So if you pass in a regex, then you must use the qr's flags
to control whether it is multiline (which by default it is not, opposite
of the default behavior of Expect).

=back

=head1 CONTRIBUTIONS

Lee Eakin <leakin@japh.itg.ti.com> has ported the kibitz script
from Tcl/Expect to Perl/Expect.

Jeff Carr <jcarr@linuxmachines.com> provided a simple example of how
handle terminal window resize events (transmitted via the WINCH
signal) in a ssh session.

You can find both scripts in the examples/ subdir.  Thanks to both!

Historical notes:

There are still a few lines of code dating back to the inspirational
Comm.pl and Chat.pl modules without which this would not have been possible.
Kudos to Eric Arnold <Eric.Arnold@Sun.com> and Randal 'Nuke your NT box with
one line of perl code' Schwartz<merlyn@stonehenge.com> for making these
available to the perl public.

As of .98 I think all the old code is toast. No way could this have been done
without it though. Special thanks to Graham Barr for helping make sense of
the IO::Handle stuff as well as providing the highly recommended IO::Tty
module.


=head1 REFERENCES

Mark Rogaski <rogaski@att.com> wrote:

"I figured that you'd like to know that Expect.pm has been very
useful to AT&T Labs over the past couple of years (since I first talked to
Austin about design decisions). We use Expect.pm for managing
the switches in our network via the telnet interface, and such automation
has significantly increased our reliability. So, you can honestly say that
one of the largest digital networks in existence (AT&T Frame Relay) uses
Expect.pm quite extensively."


=head1 FAQ - Frequently Asked Questions

This is a growing collection of things that might help.
Please send you questions that are not answered here to
RGiersig@cpan.org


=head2 What systems does Expect run on?

Expect itself doesn't have real system dependencies, but the underlying
IO::Tty needs pseudoterminals. IO::Stty uses POSIX.pm and Fcntl.pm.

I have used it on Solaris, Linux and AIX, others report *BSD and OSF
as working.  Generally, any modern POSIX Unix should do, but there
are exceptions to every rule.  Feedback is appreciated.

See L<IO::Tty> for a list of verified systems.


=head2 Can I use this module with ActivePerl on Windows?

Up to now, the answer was 'No', but this has changed.

You still cannot use ActivePerl, but if you use the Cygwin environment
(http://sources.redhat.com), which brings its own perl, and have
the latest IO::Tty (v0.05 or later) installed, it should work (feedback
appreciated).


=head2 The examples in the tutorial don't work!

The tutorial is hopelessly out of date and needs a serious overhaul.
I apologize for this, I have concentrated my efforts mainly on the
functionality.  Volunteers welcomed.


=head2 How can I find out what Expect is doing?

If you set

  $Expect::Exp_Internal = 1;

Expect will tell you very verbosely what it is receiving and sending,
what matching it is trying and what it found.  You can do this on a
per-command base with

  $exp->exp_internal(1);

You can also set

  $Expect::Debug = 1;  # or 2, 3 for more verbose output

or

  $exp->debug(1);

which gives you even more output.


=head2 I am seeing the output of the command I spawned.  Can I turn that off?

Yes, just set

  $Expect::Log_Stdout = 0;

to globally disable it or

   $exp->log_stdout(0);

for just that command.  'log_user' is provided as an alias so
Tcl/Expect user get a DWIM experience... :-)


=head2 No, I mean that when I send some text to the spawned process, it gets echoed back and I have to deal with it in the next expect.

This is caused by the pty, which has probably 'echo' enabled.  A
solution would be to set the pty to raw mode, which in general is
cleaner for communication between two programs (no more unexpected
character translations).  Unfortunately this would break a lot of old
code that sends "\r" to the program instead of "\n" (translating this
is also handled by the pty), so I won't add this to Expect just like that.
But feel free to experiment with C<$exp-E<gt>raw_pty(1)>.


=head2 How do I send control characters to a process?

A: You can send any characters to a process with the print command. To
represent a control character in Perl, use \c followed by the letter. For
example, control-G can be represented with "\cG" . Note that this will not
work if you single-quote your string. So, to send control-C to a process in
$exp, do:

  print $exp "\cC";

Or, if you prefer:

  $exp->send("\cC");

The ability to include control characters in a string like this is provided
by Perl, not by Expect.pm . Trying to learn Expect.pm without a thorough
grounding in Perl can be very daunting. We suggest you look into some of
the excellent Perl learning material, such as the books _Programming Perl_
and _Learning Perl_ by O'Reilly, as well as the extensive online Perl
documentation available through the perldoc command.


=head2 My script fails from time to time without any obvious reason.  It seems that I am sometimes loosing output from the spawned program.

You could be exiting too fast without giving the spawned program
enough time to finish.  Try adding $exp->soft_close() to terminate the
program gracefully or do an expect() for 'eof'.

Alternatively, try adding a 'sleep 1' after you spawn() the program.
It could be that pty creation on your system is just slow (but this is
rather improbable if you are using the latest IO-Tty).


=head2 I want to automate password entry for su/ssh/scp/rsh/...

You shouldn't use Expect for this.  Putting passwords, especially
root passwords, into scripts in clear text can mean severe security
problems.  I strongly recommend using other means.  For 'su', consider
switching to 'sudo', which gives you root access on a per-command and
per-user basis without the need to enter passwords.  'ssh'/'scp' can be
set up with RSA authentication without passwords.  'rsh' can use
the .rhost mechanism, but I'd strongly suggest to switch to 'ssh'; to
mention 'rsh' and 'security' in the same sentence makes an oxymoron.

It will work for 'telnet', though, and there are valid uses for it,
but you still might want to consider using 'ssh', as keeping cleartext
passwords around is very insecure.


=head2 I want to use Expect to automate [anything with a buzzword]...

Are you sure there is no other, easier way?  As a rule of thumb,
Expect is useful for automating things that expect to talk to a human,
where no formal standard applies.  For other tasks that do follow a
well-defined protocol, there are often better-suited modules that
already can handle those protocols.  Don't try to do HTTP requests by
spawning telnet to port 80, use LWP instead.  To automate FTP, take a
look at L<Net::FTP> or C<ncftp> (http://www.ncftp.org).  You don't use
a screwdriver to hammer in your nails either, or do you?


=head2 Is it possible to use threads with Expect?

Basically yes, with one restriction: you must spawn() your programs in
the main thread and then pass the Expect objects to the handling
threads. The reason is that spawn() uses fork(), and L<perlthrtut>:

  "Thinking of mixing fork() and threads?  Please lie down and wait until the feeling passes."


=head2 I want to log the whole session to a file.

Use

  $exp->log_file("filename");

or

  $exp->log_file($filehandle);

or even

  $exp->log_file(\&log_procedure);

for maximum flexibility.

Note that the logfile is appended to by default, but you can
specify an optional mode "w" to truncate the logfile:

  $exp->log_file("filename", "w");

To stop logging, just call it with a false argument:

  $exp->log_file(undef);


=head2 How can I turn off multi-line matching for my regexps?

To globally unset multi-line matching for all regexps:

  $Expect::Multiline_Matching = 0;

You can do that on a per-regexp basis by stating C<(?-m)> inside the regexp
(you need perl5.00503 or later for that).


=head2 How can I expect on multiple spawned commands?

You can use the B<-i> parameter to specify a single object or a list
of Expect objects.  All following patterns will be evaluated against
that list.

You can specify B<-i> multiple times to create groups of objects
and patterns to match against within the same expect statement.

This works just like in Tcl/Expect.

See the source example below.


=head2 I seem to have problems with ptys!

Well, pty handling is really a black magic, as it is extremely system
dependent.  I have extensively revised IO-Tty, so these problems
should be gone.

If your system is listed in the "verified" list of IO::Tty, you
probably have some non-standard setup, e.g. you compiled your
Linux-kernel yourself and disabled ptys.  Please ask your friendly
sysadmin for help.

If your system is not listed, unpack the latest version of IO::Tty,
do a 'perl Makefile.PL; make; make test; uname C<-a>' and send me the
results and I'll see what I can deduce from that.


=head2 I just want to read the output of a process without expect()ing anything. How can I do this?

[ Are you sure you need Expect for this?  How about qx() or open("prog|")? ]

By using expect without any patterns to match.

  $process->expect(undef); # Forever until EOF
  $process->expect($timeout); # For a few seconds
  $process->expect(0); # Is there anything ready on the handle now?


=head2 Ok, so now how do I get what was read on the handle?

  $read = $process->before();


=head2  Where's IO::Pty?

Find it on CPAN as IO-Tty, which provides both.


=head2 How come when I automate the passwd program to change passwords for me passwd dies before changing the password sometimes/every time?

What's happening is you are closing the handle before passwd exits.
When you close the handle to a process, it is sent a signal (SIGPIPE?)
telling it that STDOUT has gone away. The default behavior for
processes is to die in this circumstance. Two ways you can make this
not happen are:

  $process->soft_close();

This will wait 15 seconds for a process to come up with an EOF by
itself before killing it.

  $process->expect(undef);

This will wait forever for the process to match an empty set of
patterns. It will return when the process hits an EOF.

As a rule, you should always expect() the result of your transaction
before you continue with processing.


=head2 How come when I try to make a logfile with log_file() or set_group() it doesn't print anything after the last time I run expect()?

Output is only printed to the logfile/group when Expect reads from the
process, during expect(), send_slow() and interconnect().
One way you can force this is to make use of

  $process->expect(undef);

and

  $process->expect(0);

which will make expect() run with an empty pattern set forever or just
for an instant to capture the output of $process. The output is
available in the accumulator, so you can grab it using
$process->before().


=head2 I seem to have problems with terminal settings, double echoing, etc.

Tty settings are a major pain to keep track of. If you find unexpected
behavior such as double-echoing or a frozen session, doublecheck the
documentation for default settings. When in doubt, handle them
yourself using $exp->stty() and manual_stty() functions.  As of .98
you shouldn't have to worry about stty settings getting fouled unless
you use interconnect or intentionally change them (like doing -echo to
get a password).

If you foul up your terminal's tty settings, kill any hung processes
and enter 'stty sane' at a shell prompt. This should make your
terminal manageable again.

Note that IO::Tty returns ptys with your systems default setting
regarding echoing, CRLF translation etc. and Expect does not change
them.  I have considered setting the ptys to 'raw' without any
translation whatsoever, but this would break a lot of existing things,
as '\r' translation would not work anymore.  On the other hand, a raw
pty works much like a pipe and is more WYGIWYE (what you get is what
you expect), so I suggest you set it to 'raw' by yourself:

  $exp = Expect->new;
  $exp->raw_pty(1);
  $exp->spawn(...);

To disable echo:

  $exp->slave->stty(qw(-echo));


=head2 I'm spawning a telnet/ssh session and then let the user interact with it.  But screen-oriented applications on the other side don't work properly.

You have to set the terminal screen size for that.  Luckily, IO::Pty
already has a method for that, so modify your code to look like this:

  my $exp = Expect->new;
  $exp->slave->clone_winsize_from(\*STDIN);
  $exp->spawn("telnet somehost);

Also, some applications need the TERM shell variable set so they know
how to move the cursor across the screen.  When logging in, the remote
shell sends a query (Ctrl-Z I think) and expects the terminal to
answer with a string, e.g. 'xterm'.  If you really want to go that way
(be aware, madness lies at its end), you can handle that and send back
the value in $ENV{TERM}.  This is only a hand-waving explanation,
please figure out the details by yourself.


=head2 I set the terminal size as explained above, but if I resize the window, the application does not notice this.

You have to catch the signal WINCH ("window size changed"), change the
terminal size and propagate the signal to the spawned application:

  my $exp = Expect->new;
  $exp->slave->clone_winsize_from(\*STDIN);
  $exp->spawn("ssh somehost);
  $SIG{WINCH} = \&winch;

  sub winch {
    $exp->slave->clone_winsize_from(\*STDIN);
    kill WINCH => $exp->pid if $exp->pid;
    $SIG{WINCH} = \&winch;
  }

  $exp->interact();

There is an example file ssh.pl in the examples/ subdir that shows how
this works with ssh. Please note that I do strongly object against
using Expect to automate ssh login, as there are better way to do that
(see L<ssh-keygen>).

=head2 I noticed that the test uses a string that resembles, but not exactly matches, a well-known sentence that contains every character.  What does that mean?

That means you are anal-retentive. :-)  [Gotcha there!]


=head2 I get a "Could not assign a pty" error when running as a non-root user on an IRIX box?

The OS may not be configured to grant additional pty's (pseudo terminals)
to non-root users.  /usr/sbin/mkpts should be 4755, not 700 for this
to work.  I don't know about security implications if you do this.


=head2 How come I don't notice when the spawned process closes its stdin/out/err??

You are probably on one of the systems where the master doesn't get an
EOF when the slave closes stdin/out/err.

One possible solution is when you spawn a process, follow it with a
unique string that would indicate the process is finished.

  $process = Expect->spawn('telnet somehost; echo ____END____');

And then $process->expect($timeout,'____END____','other','patterns');


=head1 Source Examples


=head2 How to automate login

  my $telnet = Net::Telnet->new("remotehost") # see Net::Telnet
    or die "Cannot telnet to remotehost: $!\n";;
  my $exp = Expect->exp_init($telnet);

  # deprecated use of spawned telnet command
  # my $exp = Expect->spawn("telnet localhost")
  #   or die "Cannot spawn telnet: $!\n";;

  my $spawn_ok;
  $exp->expect($timeout,
           [
        qr'login: $',
        sub {
                  $spawn_ok = 1;
          my $fh = shift;
          $fh->send("$username\n");
                  exp_continue;
        }
           ],
           [
        'Password: $',
        sub {
          my $fh = shift;
          print $fh "$password\n";
                  exp_continue;
        }
           ],
           [
        eof =>
        sub {
                  if ($spawn_ok) {
            die "ERROR: premature EOF in login.\n";
                  } else {
            die "ERROR: could not spawn telnet.\n";
                  }
        }
           ],
           [
        timeout =>
        sub {
          die "No login.\n";
        }
           ],
           '-re', qr'[#>:] $', #' wait for shell prompt, then exit expect
          );


=head2 How to expect on multiple spawned commands

  foreach my $cmd (@list_of_commands) {
    push @commands, Expect->spawn($cmd);
  }

  expect($timeout,
     '-i', \@commands,
     [
      qr"pattern",        # find this pattern in output of all commands
      sub {
        my $obj = shift;    # object that matched
        print $obj "something\n";
        exp_continue;    # we don't want to terminate the expect call
      }
     ],
     '-i', $some_other_command,
     [
      "some other pattern",
      sub {
        my ($obj, $parmref) = @_;
        # ...

        # now we exit the expect command
      },
      \$parm
     ],
    );


=head2 How to propagate terminal sizes

  my $exp = Expect->new;
  $exp->slave->clone_winsize_from(\*STDIN);
  $exp->spawn("ssh somehost);
  $SIG{WINCH} = \&winch;

  sub winch {
    $exp->slave->clone_winsize_from(\*STDIN);
    kill WINCH => $exp->pid if $exp->pid;
    $SIG{WINCH} = \&winch;
  }

  $exp->interact();

=head1 HOMEPAGE

L<http://sourceforge.net/projects/expectperl/> though the source code is now in GitHub: L<https://github.com/jacoby/expect.pm>


=head1 MAILING LISTS

There are two mailing lists available, expectperl-announce and
expectperl-discuss, at

  http://lists.sourceforge.net/lists/listinfo/expectperl-announce

and

  http://lists.sourceforge.net/lists/listinfo/expectperl-discuss


=head1 BUG TRACKING

You can use the CPAN Request Tracker http://rt.cpan.org/ and submit
new bugs under

  http://rt.cpan.org/Ticket/Create.html?Queue=Expect


=head1 AUTHORS

(c) 1997 Austin Schutz E<lt>F<ASchutz@users.sourceforge.net>E<gt> (retired)

expect() interface & functionality enhancements (c) 1999-2006 Roland Giersig.

This module is now maintained by Dave Jacoby E<lt>F<jacoby@cpan.org>E<gt>

=head1 LICENSE

This module can be used under the same terms as Perl.


=head1 DISCLAIMER

THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.

In other words: Use at your own risk.  Provided as is.  Your mileage
may vary.  Read the source, Luke!

And finally, just to be sure:

Any Use of This Product, in Any Manner Whatsoever, Will Increase the
Amount of Disorder in the Universe. Although No Liability Is Implied
Herein, the Consumer Is Warned That This Process Will Ultimately Lead
to the Heat Death of the Universe.

=cut
PK1N%[P��Y�!�!perl5/Test/Needs.pmnu��6�$package Test::Needs;
use strict;
use warnings;
no warnings 'once';
our $VERSION = '0.002010';
$VERSION =~ tr/_//d;

BEGIN {
  *_WORK_AROUND_HINT_LEAKAGE
    = "$]" < 5.011 && !("$]" >= 5.009004 && "$]" < 5.010001)
    ? sub(){1} : sub(){0};
  *_WORK_AROUND_BROKEN_MODULE_STATE
    = "$]" < 5.009
    ? sub(){1} : sub(){0};

  # this allows regexes to match wide characters in vstrings
  if ("$]" >= 5.006001 && "$]" <= 5.006002) {
    require utf8;
    utf8->import;
  }
}

our @EXPORT = qw(test_needs);

our $Level = 0;

sub _try_require {
  local %^H
    if _WORK_AROUND_HINT_LEAKAGE;
  my ($module) = @_;
  (my $file = "$module.pm") =~ s{::|'}{/}g;
  my $err;
  {
    local $@;
    eval { require $file }
      or $err = $@;
  }
  if (defined $err) {
    delete $INC{$file}
      if _WORK_AROUND_BROKEN_MODULE_STATE;
    die $err
      unless $err =~ /\ACan't locate \Q$file\E/;
    return !1;
  }
  !0;
}

sub _croak {
  my $message = join '', @_;
  my $i = 1;
  while (my ($p, $f, $l) = caller($i++)) {
    next
      if $p =~ /\ATest::Needs(?:::|\z)/;
    die "$message at $f line $l.\n";
  }
  die $message;
}

sub _try_version {
  my ($module, $version) = @_;
  local $@;
  !!eval { $module->VERSION($version); 1 };
}

sub _numify_version {
  for ($_[0]) {
    return
        !$_ ? 0
      : /^[0-9]+(?:\.[0-9]+)?$/ ? sprintf('%.6f', $_)
      : /^v?([0-9]+(?:\.[0-9]+)*)$/
        ? sprintf('%d.%03d%03d', ((split /\./, $1), 0, 0)[0..2])
      : /^([\x05-\x07])(.*)$/s
        ? sprintf('%d.%03d%03d', ((map ord, /(.)/gs), 0, 0)[0..2])
      : _croak qq{version "$_" does not look like a number};
  }
}

sub _find_missing {
  my @bad = map {
    my ($module, $version) = @$_;
    $module eq 'perl' ? do {
      $version = _numify_version($version);
      "$]" < $version ? (sprintf "perl %s (have %.6f)", $version, $]) : ()
    }
    : $module =~ /^\d|[^\w:]|:::|[^:]:[^:]|^:|:$/
      ? _croak sprintf qq{"%s" does not look like a module name}, $module
    : _try_require($module) ? (
      defined $version && !_try_version($module, $version)
        ? "$module $version (have ".(defined $module->VERSION ? $module->VERSION : 'undef').')'
        : ()
    )
    : $version ? "$module $version"
    : $module;
  }
  _pairs(@_);
  @bad ? "Need " . join(', ', @bad) : undef;
}

sub import {
  my $class = shift;
  my $target = caller;
  if (@_) {
    local $Level = $Level + 1;
    test_needs(@_);
  }
  no strict 'refs';
  *{"${target}::$_"} = \&{"${class}::$_"}
    for @{"${class}::EXPORT"};
}

sub test_needs {
  my $missing = _find_missing(@_);
  local $Level = $Level + 1;
  if ($missing) {
    if ($ENV{RELEASE_TESTING}) {
      _fail("$missing due to RELEASE_TESTING");
    }
    else {
      _skip($missing);
    }
  }
  return 1;
}

sub _skip {
  local $Level = $Level + 1;
  _fail_or_skip($_[0], 0)
}
sub _fail {
  local $Level = $Level + 1;
  _fail_or_skip($_[0], 1)
}

sub _pairs {
  map +(
    ref eq 'HASH' ? do {
      my $arg = $_;
      map [ $_ => $arg->{$_} ], sort keys %$arg;
    }
    : ref eq 'ARRAY' ? do {
      my $arg = $_;
      map [ @{$arg}[$_*2,$_*2+1] ], 0 .. int($#$arg / 2);
    }
    : [ $_ ]
  ), @_;
}

sub _fail_or_skip {
  my ($message, $fail) = @_;
  if ($INC{'Test2/API.pm'}) {
    my $ctx = Test2::API::context(level => $Level);
    my $hub = $ctx->hub;
    if ($fail) {
      $ctx->ok(0, "Test::Needs modules available", [$message]);
    }
    else {
      my $plan = $hub->plan;
      my $tests = $hub->count;
      if ($plan || $tests) {
        my $skips
          = $plan && $plan ne 'NO PLAN' ? $plan - $tests : 1;
        $ctx->skip("Test::Needs modules not available") for 1 .. $skips;
        $ctx->note($message);
      }
      else {
        $ctx->plan(0, 'SKIP', $message);
      }
    }
    $ctx->done_testing;
    $ctx->release if $Test2::API::VERSION < 1.302053;
    $ctx->send_event('+'._t2_terminate_event());
  }
  elsif ($INC{'Test/Builder.pm'}) {
    local $Test::Builder::Level = $Test::Builder::Level + $Level;
    my $tb = Test::Builder->new;
    my $has_plan = Test::Builder->can('has_plan') ? 'has_plan'
      : sub { $_[0]->expected_tests || eval { $_[0]->current_test($_[0]->current_test); 'no_plan' } };
    my $tests = $tb->current_test;
    if ($fail) {
      $tb->plan(tests => 1)
        unless $tb->$has_plan;
      $tests++;
      $tb->ok(0, "Test::Needs modules available");
      $tb->diag($message);
    }
    else {
      my $plan = $tb->$has_plan;
      if ($plan || $tests) {
        my $skips
          = $plan && $plan ne 'no_plan' ? $plan - $tests : 1;
        $tb->skip("Test::Needs modules not available")
          for 1 .. $skips;
        $tests += $skips;
        Test::Builder->can('note') ? $tb->note($message) : print "# $message\n";
      }
      else {
        $tb->skip_all($message);
      }
    }
    $tb->done_testing($tests)
      if Test::Builder->can('done_testing');
    die bless {} => 'Test::Builder::Exception'
      if Test::Builder->can('parent') && $tb->parent;
  }
  else {
    if ($fail) {
      print "1..1\n";
      print "not ok 1 - Test::Needs modules available\n";
      print STDERR "# $message\n";
      exit 1;
    }
    else {
      print "1..0 # SKIP $message\n";
    }
  }
  exit 0;
}

my $terminate_event;
sub _t2_terminate_event () {
  return $terminate_event
    if $terminate_event;
  local $@;
  $terminate_event = eval sprintf <<'END_CODE', __LINE__+2, __FILE__ or die "$@";
#line %d "%s"
    package # hide
      Test::Needs::Event::Terminate;
    use Test2::Event ();
    our @ISA = qw(Test2::Event);
    sub no_display { 1 }
    sub terminate { 0 }
    __PACKAGE__;
END_CODE
    (my $pm = "$terminate_event.pm") =~ s{::}{/}g;
    $INC{$pm} = __FILE__;
    $terminate_event;
}

1;
__END__

=pod

=encoding utf-8

=head1 NAME

Test::Needs - Skip tests when modules not available

=head1 SYNOPSIS

  # need one module
  use Test::Needs 'Some::Module';

  # need multiple modules
  use Test::Needs 'Some::Module', 'Some::Other::Module';

  # need a given version of a module
  use Test::Needs {
    'Some::Module' => '1.005',
  };

  # check later
  use Test::Needs;
  test_needs 'Some::Module';

  # skips remainder of subtest
  use Test::More;
  use Test::Needs;
  subtest 'my subtest' => sub {
    test_needs 'Some::Module';
    ...
  };

  # check perl version
  use Test::Needs { perl => 5.020 };

=head1 DESCRIPTION

Skip test scripts if modules are not available.  The requested modules will be
loaded, and optionally have their versions checked.  If the module is missing,
the test script will be skipped.  Modules that are found but fail to compile
will exit with an error rather than skip.

If used in a subtest, the remainder of the subtest will be skipped.

Skipping will work even if some tests have already been run, or if a plan has
been declared.

Versions are checked via a C<< $module->VERSION($wanted_version) >> call.
Versions must be provided in a format that will be accepted.  No extra
processing is done on them.

If C<perl> is used as a module, the version is checked against the running perl
version (L<$]|perlvar/$]>).  The version can be specified as a number,
dotted-decimal string, v-string, or version object.

If the C<RELEASE_TESTING> environment variable is set, the tests will fail
rather than skip.  Subtests will be aborted, but the test script will continue
running after that point.

=head1 EXPORTS

=head2 test_needs

Has the same interface as when using Test::Needs in a C<use>.

=head1 SEE ALSO

=over 4

=item L<Test::Requires>

A similar module, with some important differences.  L<Test::Requires> will act
as a C<use> statement (despite its name), calling the import sub.  Under
C<RELEASE_TESTING>, it will BAIL_OUT if a module fails to load rather than
using a normal test fail.  It also doesn't distinguish between missing modules
and broken modules.

=item L<Test2::Require::Module>

Part of the L<Test2> ecosystem.  Only supports running as a C<use> command to
skip an entire plan.

=item L<Test2::Require::Perl>

Part of the L<Test2> ecosystem.  Only supports running as a C<use> command to
skip an entire plan.  Checks perl versions.

=item L<Test::If>

Acts as a C<use> statement.  Only supports running as a C<use> command to skip
an entire plan.  Can skip based on subref results.

=back

=head1 AUTHORS

haarg - Graham Knop (cpan:HAARG) <haarg@haarg.org>

=head1 CONTRIBUTORS

None so far.

=head1 COPYRIGHT AND LICENSE

Copyright (c) 2016 the Test::Needs L</AUTHORS> and L</CONTRIBUTORS>
as listed above.

This library is free software and may be distributed under the same terms
as perl itself. See L<http://dev.perl.org/licenses/>.

=cut
PK1N%[`�$�yyperl5/Test/RequiresInternet.pmnu��6�$use strict;
use warnings;
package Test::RequiresInternet;
$Test::RequiresInternet::VERSION = '0.05';
# ABSTRACT: Easily test network connectivity


use Socket;

sub import {
    skip_all("NO_NETWORK_TESTING") if env("NO_NETWORK_TESTING");

    my $namespace = shift;

    my $argc = scalar @_;
    if ( $argc == 0 ) {
        push @_, 'www.google.com', 80;
    }
    elsif ( $argc % 2 != 0 ) {
        die "Must supply server and a port pairs. You supplied " . (join ", ", @_) . "\n";
    }

    while ( @_ ) {
        my $host = shift;
        my $port = shift;

        local $@;

        eval {make_socket($host, $port)};

        if ( $@ ) {
            skip_all("$@");
        }
    }
}

sub make_socket {
    my ($host, $port) = @_;

    my $portnum;
    if ($port =~ /\D/) { 
        $portnum = getservbyname($port, "tcp");
    }
    else {
        $portnum = $port;
    }

    die "Could not find a port number for $port\n" if not $portnum;

    my $iaddr = inet_aton($host) or die "no host: $host\n";

    my $paddr = sockaddr_in($portnum, $iaddr);
    my $proto = getprotobyname("tcp");

    socket(my $sock, PF_INET, SOCK_STREAM, $proto) or die "socket: $!\n";
    connect($sock, $paddr) or die "connect: $!\n";
    close ($sock) or die "close: $!\n";

    1;
}

sub env {
    exists $ENV{$_[0]} && $ENV{$_[0]} eq '1'
}

sub skip_all {
    my $reason = shift;
    print "1..0 # Skipped: $reason";
    exit 0;
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Test::RequiresInternet - Easily test network connectivity

=head1 VERSION

version 0.05

=head1 SYNOPSIS

  use Test::More;
  use Test::RequiresInternet ('www.example.com' => 80, 'foobar.io' => 25);

  # if you reach here, sockets successfully connected to hosts/ports above
  plan tests => 1;

  ok(do_that_internet_thing());

=head1 OVERVIEW

This module is intended to easily test network connectivity before functional 
tests begin to non-local Internet resources.  It does not require any modules
beyond those supplied in core Perl.

If you do not specify a host/port pair, then the module defaults to using
C<www.google.com> on port C<80>.  

You may optionally specify the port by its name, as in C<http> or C<ldap>.
If you do this, the test module will attempt to look up the port number
using C<getservbyname>.

If you do specify a host and port, they must be specified in B<pairs>. It is a
fatal error to omit one or the other.

If the environment variable C<NO_NETWORK_TESTING> is set, then the tests
will be skipped without attempting any socket connections.

If the sockets cannot connect to the specified hosts and ports, the exception
is caught, reported and the tests skipped.

=head1 AUTHOR

Mark Allen <mrallen1@yahoo.com>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2014 by Mark Allen.

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

=cut
PK1N%[��n�t�tperl5/Test/Alien.pmnu��6�$package Test::Alien;

use strict;
use warnings;
use 5.008004;
use Env qw( @PATH );
use File::Which 1.10 qw( which );
use Capture::Tiny qw( capture capture_merged );
use Alien::Build::Temp;
use File::Copy qw( move );
use Text::ParseWords qw( shellwords );
use Test2::API qw( context run_subtest );
use Exporter qw( import );
use Path::Tiny qw( path );
use Alien::Build::Util qw( _dump );
use Config;

our @EXPORT = qw( alien_ok run_ok xs_ok ffi_ok with_subtest synthetic helper_ok interpolate_template_is interpolate_run_ok plugin_ok );

# ABSTRACT: Testing tools for Alien modules
our $VERSION = '2.84'; # VERSION


our @aliens;

sub alien_ok ($;$)
{
  my($alien, $message) = @_;

  my $name = ref $alien ? ref($alien) . '[instance]' : $alien;
  $name = 'undef' unless defined $name;
  my @methods = qw( cflags libs dynamic_libs bin_dir );
  $message ||= "$name responds to: @methods";

  my $ok;
  my @diag;

  if(defined $alien)
  {
    my @missing = grep { ! $alien->can($_) } @methods;

    $ok = !@missing;
    push @diag, map { "  missing method $_" } @missing;

    if($ok)
    {
      push @aliens, $alien;
      if($^O eq 'MSWin32' && $alien->isa('Alien::MSYS'))
      {
        unshift @PATH, Alien::MSYS::msys_path();
      }
      else
      {
        unshift @PATH, $alien->bin_dir;
      }
    }

    if($alien->can('alien_helper'))
    {
      my($intr) = _interpolator();

      my $help = eval { $alien->alien_helper };

      if(my $error = $@)
      {
        $ok = 0;
        push @diag, "  error getting helpers: $error";
      }

      foreach my $name (keys %$help)
      {
        my $code = $help->{$name};
        $intr->replace_helper($name, $code);
      }
    }
  }
  else
  {
    $ok = 0;
    push @diag, "  undefined alien";
  }

  my $ctx = context();
  $ctx->ok($ok, $message);
  $ctx->diag($_) for @diag;
  $ctx->release;

  $ok;
}


sub synthetic
{
  my($opt) = @_;
  $opt ||= {};
  my %alien = %$opt;
  require Test::Alien::Synthetic;
  bless \%alien, 'Test::Alien::Synthetic',
}


sub run_ok
{
  my($command, $message) = @_;

  my(@command) = ref $command ? @$command : (do {
    my $command = $command; # make a copy

    # Double the backslashes so that when they are unescaped by shellwords(),
    # they become a single backslash. This should be fine on Windows since
    # backslashes are not used to escape metacharacters in cmd.exe.
    $command =~ s/\\/\\\\/g if $^O eq 'MSWin32';
    shellwords $command;
  });
  $message ||= ref $command ? "run @command" : "run $command";

  require Test::Alien::Run;
  my $run = bless {
    out    => '',
    err    => '',
    exit   => 0,
    sig    => 0,
    cmd    => [@command],
  }, 'Test::Alien::Run';

  my $ctx = context();
  my $exe = which $command[0];
  if(defined $exe)
  {
    if(ref $command)
    {
      shift @command;
      $run->{cmd} = [$exe, @command];
    }
    else
    {
      $run->{cmd} = [$command];
    }
    my @diag;
    my $ok = 1;
    my($exit, $errno);
    ($run->{out}, $run->{err}, $exit, $errno) = capture {

      if(ref $command)
      {
        system $exe, @command;
      }
      else
      {
        system $command;
      }

      ($?,$!);
    };

    if($exit == -1)
    {
      $ok = 0;
      $run->{fail} = "failed to execute: $errno";
      push @diag, "  failed to execute: $errno";
    }
    elsif($exit & 127)
    {
      $ok = 0;
      push @diag, "  killed with signal: @{[ $exit & 127 ]}";
      $run->{sig} = $exit & 127;
    }
    else
    {
      $run->{exit} = $exit >> 8;
    }

    $ctx->ok($ok, $message);
    $ok
      ? $ctx->note("  using $exe")
      : $ctx->diag("  using $exe");
    $ctx->diag(@diag) for @diag;

  }
  else
  {
    $ctx->ok(0, $message);
    $ctx->diag("  command not found");
    $run->{fail} = 'command not found';
  }

  unless(@aliens || $ENV{TEST_ALIEN_ALIENS_MISSING})
  {
    $ctx->diag("run_ok called without any aliens, you may want to call alien_ok");
  }

  $ctx->release;

  $run;
}


sub _flags
{
  my($class, $method) = @_;
  my $static = "${method}_static";
  $class->can($static) && $class->can('install_type') && $class->install_type eq 'share' && (!$class->can('xs_load'))
    ? $class->$static
    : $class->$method;
}

sub xs_ok
{
  my $cb;
  $cb = pop if defined $_[-1] && ref $_[-1] eq 'CODE';
  my($xs, $message) = @_;
  $message ||= 'xs';

  $xs = { xs => $xs } unless ref $xs;
  # make sure this is a copy because we may
  # modify it.
  $xs->{xs} = "@{[ $xs->{xs} ]}";
  $xs->{pxs}              ||= {};
  $xs->{cbuilder_check}   ||= 'have_compiler';
  $xs->{cbuilder_config}  ||= {};
  $xs->{cbuilder_compile} ||= {};
  $xs->{cbuilder_link}    ||= {};

  require ExtUtils::CBuilder;
  my $skip = do {
    my $have_compiler = $xs->{cbuilder_check};
    my %config = %{ $xs->{cbuilder_config} };
    !ExtUtils::CBuilder->new( config => \%config )->$have_compiler;
  };

  if($skip)
  {
    my $ctx = context();
    $ctx->skip($message, 'test requires a compiler');
    $ctx->skip("$message subtest", 'test requires a compiler') if $cb;
    $ctx->release;
    return;
  }

  if($xs->{cpp} || $xs->{'C++'})
  {
    my $ctx = context();
    $ctx->bail("The cpp and C++ options have been removed from xs_ok");
  }
  else
  {
    $xs->{c_ext} ||= 'c';
  }

  my $verbose = $xs->{verbose} || 0;
  my $ok = 1;
  my @diag;
  my $dir = Alien::Build::Temp->newdir(
    TEMPLATE => 'test-alien-XXXXXX',
    CLEANUP  => $^O =~ /^(MSWin32|cygwin|msys)$/ ? 0 : 1,
  );

  my $xs_filename = path($dir)->child('test.xs')->stringify;
  my $c_filename  = path($dir)->child("test.@{[ $xs->{c_ext} ]}")->stringify;

  my $ctx = context();
  my $module;

  if($ENV{TEST_ALIEN_ALWAYS_KEEP})
  {
    $dir->unlink_on_destroy(0);
    $ctx->note("keeping XS temporary directory $dir at user request");
  }

  if($xs->{xs} =~ /\bTA_MODULE\b/)
  {
    our $count;
    $count = 0 unless defined $count;
    my $name = sprintf "Test::Alien::XS::Mod%s%s", $count, chr(65 + $count % 26 ) x 4;
    $count++;
    my $code = $xs->{xs};
    $code =~ s{\bTA_MODULE\b}{$name}g;
    $xs->{xs} = $code;
  }

  # this regex copied shamefully from ExtUtils::ParseXS
  # in part because we need the module name to do the bootstrap
  # and also because if this regex doesn't match then ParseXS
  # does an exit() which we don't want.
  if($xs->{xs} =~ /^MODULE\s*=\s*([\w:]+)(?:\s+PACKAGE\s*=\s*([\w:]+))?(?:\s+PREFIX\s*=\s*(\S+))?\s*$/m)
  {
    $module = $1;
    $ctx->note("detect module name $module") if $verbose;
  }
  else
  {
    $ok = 0;
    push @diag, '  XS does not have a module decleration that we could find';
  }

  if($ok)
  {
    open my $fh, '>', $xs_filename;
    print $fh $xs->{xs};
    close $fh;

    require ExtUtils::ParseXS;
    my $pxs = ExtUtils::ParseXS->new;

    my($out, $err) = capture_merged {
      eval {
        $pxs->process_file(
          filename     => $xs_filename,
          output       => $c_filename,
          versioncheck => 0,
          prototypes   => 0,
          %{ $xs->{pxs} },
        );
      };
      $@;
    };

    $ctx->note("parse xs $xs_filename => $c_filename") if $verbose;
    $ctx->note($out) if $verbose;
    $ctx->note("error: $err") if $verbose && $err;

    unless($pxs->report_error_count == 0)
    {
      $ok = 0;
      push @diag, '  ExtUtils::ParseXS failed:';
      push @diag, "    $err" if $err;
      push @diag, "    $_" for split /\r?\n/, $out;
    }
  }

  push @diag, "xs_ok called without any aliens, you may want to call alien_ok" unless @aliens || $ENV{TEST_ALIEN_ALIENS_MISSING};

  if($ok)
  {
    my $cb = ExtUtils::CBuilder->new(
      config => do {
        my %config = %{ $xs->{cbuilder_config} };
        my $lddlflags = join(' ', grep !/^-l/, shellwords map { _flags $_, 'libs' } @aliens) . " $Config{lddlflags}";
        $config{lddlflags} = defined $config{lddlflags} ? "$lddlflags $config{lddlflags}" : $lddlflags;
        \%config;
      },
    );

    my %compile_options = (
      source               => $c_filename,
      %{ $xs->{cbuilder_compile} },
    );

    if(defined $compile_options{extra_compiler_flags} && ref($compile_options{extra_compiler_flags}) eq '')
    {
      $compile_options{extra_compiler_flags} = [ shellwords $compile_options{extra_compiler_flags} ];
    }

    push @{ $compile_options{extra_compiler_flags} }, shellwords map { _flags $_, 'cflags' } @aliens;

    my($out, $obj, $err) = capture_merged {
      my $obj = eval {
        $cb->compile(%compile_options);
      };
      ($obj, $@);
    };

    $ctx->note("compile $c_filename") if $verbose;
    $ctx->note($out) if $verbose;
    $ctx->note($err) if $verbose && $err;

    if($verbose > 1)
    {
      $ctx->note(_dump({ compile_options => \%compile_options }));
    }

    unless($obj)
    {
      $ok = 0;
      push @diag, '  ExtUtils::CBuilder->compile failed';
      push @diag, "    $err" if $err;
      push @diag, "    $_" for split /\r?\n/, $out;
    }

    if($ok)
    {

      my %link_options = (
        objects            => [$obj],
        module_name        => $module,
        %{ $xs->{cbuilder_link} },
      );

      if(defined $link_options{extra_linker_flags} && ref($link_options{extra_linker_flags}) eq '')
      {
        $link_options{extra_linker_flags} = [ shellwords $link_options{extra_linker_flags} ];
      }

      unshift @{ $link_options{extra_linker_flags} }, grep /^-l/, shellwords map { _flags $_, 'libs' } @aliens;

      my($out, $lib, $err) = capture_merged {
        my $lib = eval {
          $cb->link(%link_options);
        };
        ($lib, $@);
      };

      $ctx->note("link $obj") if $verbose;
      $ctx->note($out) if $verbose;
      $ctx->note($err) if $verbose && $err;

      if($verbose > 1)
      {
        $ctx->note(_dump({ link_options => \%link_options }));
      }

      if($lib && -f $lib)
      {
        $ctx->note("created lib $lib") if $xs->{verbose};
      }
      else
      {
        $ok = 0;
        push @diag, '  ExtUtils::CBuilder->link failed';
        push @diag, "    $err" if $err;
        push @diag, "    $_" for split /\r?\n/, $out;
      }

      if($ok)
      {
        my @modparts = split(/::/,$module);
        my $dl_dlext = $Config{dlext};
        my $modfname = $modparts[-1];

        my $libpath = path($dir)->child('auto', @modparts, "$modfname.$dl_dlext");
        $libpath->parent->mkpath;
        move($lib, "$libpath") || die "unable to copy $lib => $libpath $!";

        pop @modparts;
        my $pmpath = path($dir)->child(@modparts, "$modfname.pm");
        $pmpath->parent->mkpath;
        open my $fh, '>', "$pmpath";

        my($alien_with_xs_load, @rest) = grep { $_->can('xs_load') } @aliens;

        if($alien_with_xs_load)
        {
          {
            no strict 'refs';
            @{join '::', $module, 'rest'} = @rest;
            ${join '::', $module, 'alien_with_xs_load'} = $alien_with_xs_load;
          }
          print $fh '# line '. __LINE__ . ' "' . __FILE__ . qq("\n) . qq{
            package $module;

            use strict;
            use warnings;
            our \$VERSION = '0.01';
            our \@rest;
            our \$alien_with_xs_load;

            \$alien_with_xs_load->xs_load('$module', \$VERSION, \@rest);

            1;
          };
        }
        else
        {
          print $fh '# line '. __LINE__ . ' "' . __FILE__ . qq("\n) . qq{
            package $module;

            use strict;
            use warnings;
            require XSLoader;
            our \$VERSION = '0.01';
            XSLoader::load('$module',\$VERSION);

            1;
          };
        }
        close $fh;

        {
          local @INC = @INC;
          unshift @INC, "$dir";
          ## no critic
          eval '# line '. __LINE__ . ' "' . __FILE__ . qq("\n) . qq{
            use $module;
          };
          ## use critic
        }

        if(my $error = $@)
        {
          $ok = 0;
          push @diag, '  XSLoader failed';
          push @diag, "    $error";
        }
      }
    }
  }

  $ctx->ok($ok, $message);
  $ctx->diag($_) for @diag;
  $ctx->release;

  unless($ok || defined $ENV{TEST_ALIEN_ALWAYS_KEEP})
  {
    $ctx->note("keeping XS temporary directory $dir due to failure");
    $dir->unlink_on_destroy(0);
  }

  if($cb)
  {
    $cb = sub {
      my $ctx = context();
      $ctx->plan(0, 'SKIP', "subtest requires xs success");
      $ctx->release;
    } unless $ok;

    @_ = ("$message subtest", $cb, 1, $module);

    goto \&Test2::API::run_subtest;
  }

  $ok;
}

sub with_subtest (&)
{
  my($code) = @_;

  # it may be possible to catch a segmentation fault,
  # but not with signal handlers apparently.  See:
  # https://feepingcreature.github.io/handling.html
  return $code if $^O eq 'MSWin32';

  # try to catch a segmentation fault and bail out
  # with a useful diagnostic.  prove test to swallow
  # the diagnostic on such failures.
  sub {
    local $SIG{SEGV} = sub {
      my $ctx = context();
      $ctx->bail("Segmentation fault");
    };
    $code->(@_);
  }
}


sub ffi_ok
{
  my $cb;
  $cb = pop if defined $_[-1] && ref $_[-1] eq 'CODE';
  my($opt, $message) = @_;

  $message ||= 'ffi';

  my $ok = 1;
  my $skip;
  my $ffi;
  my @diag;

  {
    my $min = '0.12'; # the first CPAN release
    $min = '0.15' if $opt->{ignore_not_found};
    $min = '0.18' if $opt->{lang};
    $min = '0.99' if defined $opt->{api} && $opt->{api} > 0;
    unless(eval { require FFI::Platypus; FFI::Platypus->VERSION($min) })
    {
      $ok = 0;
      $skip = "Test requires FFI::Platypus $min";
    }
  }

  if($ok && $opt->{lang})
  {
    my $class = "FFI::Platypus::Lang::@{[ $opt->{lang} ]}";
    {
      my $pm = "$class.pm";
      $pm =~ s/::/\//g;
      eval { require $pm };
    }
    if($@)
    {
      $ok = 0;
      $skip = "Test requires FFI::Platypus::Lang::@{[ $opt->{lang} ]}";
    }
  }

  unless(@aliens || $ENV{TEST_ALIEN_ALIENS_MISSING})
  {
    push @diag, 'ffi_ok called without any aliens, you may want to call alien_ok';
  }

  if($ok)
  {
    $ffi = FFI::Platypus->new(
      do {
        my @args = (
          lib              => [map { $_->dynamic_libs } @aliens],
          ignore_not_found => $opt->{ignore_not_found},
          lang             => $opt->{lang},
        );
        push @args, api => $opt->{api} if defined $opt->{api};
        @args;
      }
    );
    foreach my $symbol (@{ $opt->{symbols} || [] })
    {
      unless($ffi->find_symbol($symbol))
      {
        $ok = 0;
        push @diag, "  $symbol not found"
      }
    }
  }

  my $ctx = context();

  if($skip)
  {
    $ctx->skip($message, $skip);
  }
  else
  {
    $ctx->ok($ok, $message);
  }
  $ctx->diag($_) for @diag;

  $ctx->release;

  if($cb)
  {
    $cb = sub {
      my $ctx = context();
      $ctx->plan(0, 'SKIP', "subtest requires ffi success");
      $ctx->release;
    } unless $ok;

    @_ = ("$message subtest", $cb, 1, $ffi);

    goto \&Test2::API::run_subtest;
  }

  $ok;
}


{
  my @ret;

  sub _interpolator
  {
    return @ret if @ret;

    require Alien::Build::Interpolate::Default;
    my $intr = Alien::Build::Interpolate::Default->new;

    require Alien::Build;
    my $build = Alien::Build->new;
    $build->meta->interpolator($intr);

    @ret = ($intr, $build);
  }
}

sub helper_ok
{
  my($name, $message) = @_;

  $message ||= "helper $name exists";

  my($intr) = _interpolator;

  my $code = $intr->has_helper($name);

  my $ok = defined $code;

  my $ctx = context();
  $ctx->ok($ok, $message);
  $ctx->diag("helper_ok called without any aliens, you may want to call alien_ok") unless @aliens || $ENV{TEST_ALIEN_ALIENS_MISSING};
  $ctx->release;

  $ok;
}


sub plugin_ok
{
  my($name, $message) = @_;

  my @args;

  ($name, @args) = @$name if ref $name;

  $message ||= "plugin $name";

  my($intr, $build) = _interpolator;

  my $class = "Alien::Build::Plugin::$name";
  my $pm = "$class.pm";
  $pm =~ s/::/\//g;

  my $ctx = context();

  my $plugin = eval {
    require $pm unless $class->can('new');
    $class->new(@args);
  };

  if(my $error = $@)
  {
    $ctx->ok(0, $message, ['unable to create $name plugin', $error]);
    $ctx->release;
    return 0;
  }

  eval {
    $plugin->init($build->meta);
  };

  if($^O eq 'MSWin32' && ($plugin->isa('Alien::Build::Plugin::Build::MSYS') || $plugin->isa('Alien::Build::Plugin::Build::Autoconf')))
  {
    require Alien::MSYS;
    unshift @PATH, Alien::MSYS::msys_path();
  }

  if(my $error = $@)
  {
    $ctx->ok(0, $message, ['unable to initiate $name plugin', $error]);
    $ctx->release;
    return 0;
  }
  else
  {
    $ctx->ok(1, $message);
    $ctx->release;
    return 1;
  }
}


sub interpolate_template_is
{
  my($template, $pattern, $message) = @_;

  $message ||= "template matches";

  my($intr) = _interpolator;

  my $value = eval { $intr->interpolate($template) };
  my $error = $@;
  my @diag;
  my $ok;

  if($error)
  {
    $ok = 0;
    push @diag, "error in evaluation:";
    push @diag, "  $error";
  }
  elsif(ref($pattern) eq 'Regexp')
  {
    $ok = $value =~ $pattern;
    push @diag, "value '$value' does not match $pattern'" unless $ok;
  }
  else
  {
    $ok = $value eq "$pattern";
    push @diag, "value '$value' does not equal '$pattern'" unless $ok;
  }

  my $ctx = context();
  $ctx->ok($ok, $message, [@diag]);
  $ctx->diag('interpolate_template_is called without any aliens, you may want to call alien_ok') unless @aliens || $ENV{TEST_ALIEN_ALIENS_MISSING};
  $ctx->release;

  $ok;
}


sub interpolate_run_ok
{
  my($template, $message) = @_;

  my(@template) = ref $template ? @$template : ($template);

  my($intr) = _interpolator;

  my $ok = 1;
  my @diag;
  my @command;

  foreach my $template (@template)
  {
    my $command = eval { $intr->interpolate($template) };
    if(my $error = $@)
    {
      $ok = 0;
      push @diag, "error in evaluation:";
      push @diag, "  $error";
    }
    else
    {
      push @command, $command;
    }
  }

  my $ctx = context();

  if($ok)
  {
    my $command = ref $template ? \@command : $command[0];
    $ok = run_ok($command, $message);
  }
  else
  {
    $message ||= "run @template";
    $ctx->ok($ok, $message, [@diag]);
    $ctx->diag('interpolate_run_ok called without any aliens, you may want to call alien_ok') unless @aliens || $ENV{TEST_ALIEN_ALIENS_MISSING};
  }

  $ctx->release;

  $ok;
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Test::Alien - Testing tools for Alien modules

=head1 VERSION

version 2.84

=head1 SYNOPSIS

Test commands that come with your Alien:

 use Test2::V0;
 use Test::Alien;
 use Alien::patch;
 
 alien_ok 'Alien::patch';
 run_ok([ 'patch', '--version' ])
   ->success
   # we only accept the version written
   # by Larry ...
   ->out_like(qr{Larry Wall});
 
 done_testing;

Test that your library works with C<XS>:

 use Test2::V0;
 use Test::Alien;
 use Alien::Editline;
 
 alien_ok 'Alien::Editline';
 my $xs = do { local $/; <DATA> };
 xs_ok $xs, with_subtest {
   my($module) = @_;
   ok $module->version;
 };
 
 done_testing;
 
 __DATA__
 
 #include "EXTERN.h"
 #include "perl.h"
 #include "XSUB.h"
 #include <editline/readline.h>
 
 const char *
 version(const char *class)
 {
   return rl_library_version;
 }
 
 MODULE = TA_MODULE PACKAGE = TA_MODULE
 
 const char *version(class);
     const char *class;

Test that your library works with L<FFI::Platypus>:

 use Test2::V0;
 use Test::Alien;
 use Alien::LibYAML;
 
 alien_ok 'Alien::LibYAML';
 ffi_ok { symbols => ['yaml_get_version'] }, with_subtest {
   my($ffi) = @_;
   my $get_version = $ffi->function(yaml_get_version => ['int*','int*','int*'] => 'void');
   $get_version->call(\my $major, \my $minor, \my $patch);
   like $major, qr{[0-9]+};
   like $minor, qr{[0-9]+};
   like $patch, qr{[0-9]+};
 };
 
 done_testing;

=head1 DESCRIPTION

This module provides tools for testing L<Alien> modules.  It has hooks
to work easily with L<Alien::Base> based modules, but can also be used
via the synthetic interface to test non L<Alien::Base> based L<Alien>
modules.  It has very modest prerequisites.

Prior to this module the best way to test a L<Alien> module was via L<Test::CChecker>.
The main downside to that module is that it is heavily influenced by and uses
L<ExtUtils::CChecker>, which is a tool for checking at install time various things
about your compiler.  It was also written before L<Alien::Base> became as stable as it
is today.  In particular, L<Test::CChecker> does its testing by creating an executable
and running it.  Unfortunately Perl uses extensions by creating dynamic libraries
and linking them into the Perl process, which is different in subtle and error prone
ways.  This module attempts to test the libraries in the way that they will actually
be used, via either C<XS> or L<FFI::Platypus>.  It also provides a mechanism for
testing binaries that are provided by the various L<Alien> modules (for example
L<Alien::gmake> and L<Alien::patch>).

L<Alien> modules can actually be usable without a compiler, or without L<FFI::Platypus>
(for example, if the library is provided by the system, and you are using L<FFI::Platypus>,
or if you are building from source and you are using C<XS>), so tests with missing
prerequisites are automatically skipped.  For example, L</xs_ok> will automatically skip
itself if a compiler is not found, and L</ffi_ok> will automatically skip itself
if L<FFI::Platypus> is not installed.

=head1 FUNCTIONS

=head2 alien_ok

 alien_ok $alien, $message;
 alien_ok $alien;

Load the given L<Alien> instance or class.  Checks that the instance or class conforms to the same
interface as L<Alien::Base>.  Will be used by subsequent tests.  The C<$alien> module only needs to
provide these methods in order to conform to the L<Alien::Base> interface:

=over 4

=item cflags

String containing the compiler flags

=item libs

String containing the linker and library flags

=item dynamic_libs

List of dynamic libraries.  Returns empty list if the L<Alien> module does not provide this.

=item bin_dir

Directory containing tool binaries.  Returns empty list if the L<Alien> module does not provide
this.

=back

If your L<Alien> module does not conform to this interface then you can create a synthetic L<Alien>
module using the L</synthetic> function.

=head2 synthetic

 my $alien = synthetic \%config;

Create a synthetic L<Alien> module which can be passed into L</alien_ok>.  C<\%config>
can contain these keys (all of which are optional):

=over 4

=item cflags

String containing the compiler flags.

=item cflags_static

String containing the static compiler flags (optional).

=item libs

String containing the linker and library flags.

=item libs_static

String containing the static linker flags (optional).

=item dynamic_libs

List reference containing the dynamic libraries.

=item bin_dir

Tool binary directory.

=item runtime_prop

Runtime properties.

=back

See L<Test::Alien::Synthetic> for more details.

=head2 run_ok

 my $run = run_ok $command;
 my $run = run_ok $command, $message;

Runs the given command, falling back on any C<Alien::Base#bin_dir> methods provided by L<Alien> modules
specified with L</alien_ok>.

C<$command> can be either a string or an array reference.

Only fails if the command cannot be found, or if it is killed by a signal!  Returns a L<Test::Alien::Run>
object, which you can use to test the exit status, output and standard error.

Always returns an instance of L<Test::Alien::Run>, even if the command could not be found.

=head2 xs_ok

 xs_ok $xs;
 xs_ok $xs, $message;

Compiles, links the given C<XS> code and attaches to Perl.

If you use the special module name C<TA_MODULE> in your C<XS>
code, it will be replaced by an automatically generated
package name.  This can be useful if you want to pass the same
C<XS> code to multiple calls to C<xs_ok> without subsequent
calls replacing previous ones.

C<$xs> may be either a string containing the C<XS> code,
or a hash reference with these keys:

=over 4

=item xs

The XS code.  This is the only required element.

=item pxs

Extra L<ExtUtils::ParseXS> arguments passed in as a hash reference.

=item cbuilder_check

The compile check that should be done prior to attempting to build.
Should be one of C<have_compiler> or C<have_cplusplus>.  Defaults
to C<have_compiler>.

=item cbuilder_config

Hash to override values normally provided by C<Config>.

=item cbuilder_compile

Extra The L<ExtUtils::CBuilder> arguments passed in as a hash reference.

=item cbuilder_link

Extra The L<ExtUtils::CBuilder> arguments passed in as a hash reference.

=item verbose

Spew copious debug information via test note.

=back

You can use the C<with_subtest> keyword to conditionally
run a subtest if the C<xs_ok> call succeeds.  If C<xs_ok>
does not work, then the subtest will automatically be
skipped.  Example:

 xs_ok $xs, with_subtest {
   # skipped if $xs fails for some reason
   my($module) = @_;
   is $module->foo, 1;
 };

The module name detected during the XS parsing phase will
be passed in to the subtest.  This is helpful when you are
using a generated module name.

If you need to test XS C++ interfaces, see L<Test::Alien::CPP>.

Caveats: C<xs_ok> uses L<ExtUtils::ParseXS>, which may call C<exit>
under certain error conditions.  While this is not really good
thing to happen in the middle of a test, it usually indicates
a real failure condition, and it should return a failure condition
so the test should still fail overall.

[version 2.53]

As of version 2.53, C<xs_ok> will only remove temporary generated files
if the test is successful by default.  You can force either always
or never removing the temporary generated files using the
C<TEST_ALIEN_ALWAYS_KEEP> environment variable (see L</ENVIRONMENT> below).

=head2 ffi_ok

 ffi_ok;
 ffi_ok \%opt;
 ffi_ok \%opt, $message;

Test that L<FFI::Platypus> works.

C<\%opt> is a hash reference with these keys (all optional):

=over 4

=item symbols

List references of symbols that must be found for the test to succeed.

=item ignore_not_found

Ignores symbols that aren't found.  This affects functions accessed via
L<FFI::Platypus#attach> and L<FFI::Platypus#function> methods, and does
not influence the C<symbols> key above.

=item lang

Set the language.  Used primarily for language specific native types.

=item api

Set the API.  C<api = 1> requires FFI::Platypus 0.99 or later.  This
option was added with Test::Alien version 1.90, so your use line should
include this version as a safeguard to make sure it works:

 use Test::Alien 1.90;
 ...
 ffi_ok ...;

=back

As with L</xs_ok> above, you can use the C<with_subtest> keyword to specify
a subtest to be run if C<ffi_ok> succeeds (it will skip otherwise).  The
L<FFI::Platypus> instance is passed into the subtest as the first argument.
For example:

 ffi_ok with_subtest {
   my($ffi) = @_;
   is $ffi->function(foo => [] => 'void')->call, 42;
 };

=head2 helper_ok

 helper_ok $name;
 helper_ok $name, $message;

Tests that the given helper has been defined.

=head2 plugin_ok

[version 2.52]

 plugin_ok $plugin_name, $message;
 plugin_ok [$plugin_name, @args], $message;

This applies an L<Alien::Build::Plugin> to the interpolator used by L</helper_ok>, L</interpolate_template_is>
and L</interpolate_run_ok> so that you can test with any helpers that plugin provides.  Useful,
for example for getting C<%{configure}> from L<Alien::Build::Plugin::Build::Autoconf>.

=head2 interpolate_template_is

 interpolate_template_is $template, $string;
 interpolate_template_is $template, $string, $message;
 interpolate_template_is $template, $regex;
 interpolate_template_is $template, $regex, $message;

Tests that the given template when evaluated with the appropriate helpers will match
either the given string or regular expression.

=head2 interpolate_run_ok

[version 2.52]

 my $run = interpolate_run_ok $command;
 my $run = interpolate_run_ok $command, $message;

This is the same as L</run_ok> except it runs the command through the interpolator first.

=head1 ENVIRONMENT

=over 4

=item C<TEST_ALIEN_ALWAYS_KEEP>

If this is defined then it will override the built in logic that decides if
the temporary files generated by L</xs_ok> should be kept when the test file
terminates.  If set to true the generated files will always be kept.  If
set to false, then they will always be removed.

=item C<TEST_ALIEN_ALIENS_MISSING>

By default, this module will warn you if some tools are used without first
invoking L</alien_ok>.  This is usually a mistake, but if you really do
want to use one of these tools with no aliens loaded, you can set this
environment variable to false.

=back

=head1 SEE ALSO

=over 4

=item L<Alien>

=item L<Alien::Base>

=item L<Alien::Build>

=item L<alienfile>

=item L<Test2>

=item L<Test::Alien::Run>

=item L<Test::Alien::CanCompile>

=item L<Test::Alien::CanPlatypus>

=item L<Test::Alien::Synthetic>

=item L<Test::Alien::CPP>

=back

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK1N%[k��
perl5/Test/Alien/Diag.pmnu��6�$package Test::Alien::Diag;

use strict;
use warnings;
use 5.008004;
use Test2::API qw( context );
use Exporter qw( import );

our @EXPORT = qw( alien_diag );
our @EXPORT_OK = @EXPORT;

# ABSTRACT: Print out standard diagnostic for Aliens in the test step.
our $VERSION = '2.84'; # VERSION


my @default_scalar_properties = qw(
  cflags cflags_static libs libs_static version install_type
);

my @default_list_properties = qw(
  dynamic_libs bin_dir
);

sub alien_diag ($@)
{
  my $ctx = context();

  my %options = defined $_[-1] && ref($_[-1]) eq 'HASH' ?  %{ pop @_ } : ();

  my @extra_properties      = @{ delete $options{properties}      || [] };
  my @extra_list_properties = @{ delete $options{list_properties} || [] };

  my $max = 0;
  foreach my $alien (@_)
  {
    foreach my $name (@default_scalar_properties, @default_list_properties, @extra_properties, @extra_list_properties)
    {
      if(eval { $alien->can($name) })
      {
        my $str = "$alien->$name";
        if(length($str) > $max)
        {
          $max = length($str);
        }
      }
    }
  }


  $ctx->diag('');

  if(%options)
  {
    my @extra = sort keys %options;
    $ctx->diag("warning: unknown option@{[ @extra > 1 ? 's' : '' ]} for alien_diag: @extra");
    $ctx->diag("(you should check for typos or maybe upgrade to a newer version of Alien::Build)");
  }


  foreach my $alien (@_) {
    $ctx->diag('') for 1..2;

    my $found = 0;

    foreach my $name (sort(@default_scalar_properties, @extra_properties))
    {
      if(eval { $alien->can($name) })
      {
        $found++;
        my $value = $alien->$name;
        $value = '[undef]' unless defined $value;
        $ctx->diag(sprintf "%-${max}s = %s", "$alien->$name", $value);
      }
    }

    foreach my $name (sort(@default_list_properties, @extra_list_properties))
    {
      if(eval { $alien->can($name) })
      {
        $found++;
        my @list = eval { $alien->$name };
        next if $@;
        $ctx->diag(sprintf "%-${max}s = %s", "$alien->$name", $_) for @list;
      }
    }

    $ctx->diag("no diagnostics found for $alien") unless $found;
  }

  $ctx->diag('') for 1..2;

  $ctx->release;
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Test::Alien::Diag - Print out standard diagnostic for Aliens in the test step.

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use Test2::V0;
 use Test::Alien::Diag qw( alien_diag );

=head1 DESCRIPTION

This module provides an C<alien_diag> method that prints out diagnostics useful for
cpantesters and other bug reports that gives a quick summary of the important settings
like C<clfags> and C<libs>.

=head1 FUNCTIONS

=head2 alien_diag

 alien_diag @aliens;

prints out diagnostics for each given alien.  Each alien must be the class
name of an alien.

[version 2.68]

 alien_diag @aliens, \%options;

Starting with L<Alien::Build> 2.68, you can provide an option hash to adjust the
behavior of C<alien_diag>.  Valid options are:

=over 4

=item properties

Additional properties to display in the diagnostic.  Useful when you have an L<Alien>
with custom properties defined in the subclass.

=item list_properties

Additional properties that are returned as a list to display in the diagnostic.  Useful
when you have an L<Alien> with customer properties that return a list.

=back

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK1N%[�!m�ddperl5/Test/Alien/Run.pmnu��6�$package Test::Alien::Run;

use strict;
use warnings;
use 5.008004;
use Test2::API qw( context );

# ABSTRACT: Run object
our $VERSION = '2.84'; # VERSION


sub out    { shift->{out} }
sub err    { shift->{err} }
sub exit   { shift->{exit} }
sub signal { shift->{sig} }


sub success
{
  my($self, $message) = @_;
  $message ||= 'command succeeded';
  my $ok = $self->exit == 0 && $self->signal == 0;
  $ok = 0 if $self->{fail};

  my $ctx = context();
  $ctx->ok($ok, $message);
  unless($ok)
  {
    $ctx->diag("  command exited with @{[ $self->exit   ]}") if $self->exit;
    $ctx->diag("  command killed with @{[ $self->signal ]}") if $self->signal;
    $ctx->diag("  @{[ $self->{fail} ]}") if $self->{fail};
  }
  $ctx->release;
  $self;
}


sub exit_is
{
  my($self, $exit, $message) = @_;

  $message ||= "command exited with value $exit";
  my $ok = $self->exit == $exit;

  my $ctx = context();
  $ctx->ok($ok, $message);
  $ctx->diag("  actual exit value was: @{[ $self->exit ]}") unless $ok;
  $ctx->release;
  $self;
}


sub exit_isnt
{
  my($self, $exit, $message) = @_;

  $message ||= "command exited with value not $exit";
  my $ok = $self->exit != $exit;

  my $ctx = context();
  $ctx->ok($ok, $message);
  $ctx->diag("  actual exit value was: @{[ $self->exit ]}") unless $ok;
  $ctx->release;
  $self;
}


sub _like
{
  my($self, $regex, $source, $not, $message) = @_;

  my $ok = $self->{$source} =~ $regex;
  $ok = !$ok if $not;

  my $ctx = context();
  $ctx->ok($ok, $message);
  unless($ok)
  {
    $ctx->diag("  $source:");
    $ctx->diag("    $_") for split /\r?\n/, $self->{$source};
    $ctx->diag($not ? '  matches:' : '  does not match:');
    $ctx->diag("    $regex");
  }
  $ctx->release;

  $self;
}

sub out_like
{
  my($self, $regex, $message) = @_;
  $message ||= "output matches $regex";
  $self->_like($regex, 'out', 0, $message);
}


sub out_unlike
{
  my($self, $regex, $message) = @_;
  $message ||= "output does not match $regex";
  $self->_like($regex, 'out', 1, $message);
}


sub err_like
{
  my($self, $regex, $message) = @_;
  $message ||= "standard error matches $regex";
  $self->_like($regex, 'err', 0, $message);
}


sub err_unlike
{
  my($self, $regex, $message) = @_;
  $message ||= "standard error does not match $regex";
  $self->_like($regex, 'err', 1, $message);
}


sub note
{
  my($self) = @_;
  my $ctx = context();
  $ctx->note("[cmd]");
  $ctx->note("  @{$self->{cmd}}");
  if($self->out ne '')
  {
    $ctx->note("[out]");
    $ctx->note("  $_") for split /\r?\n/, $self->out;
  }
  if($self->err ne '')
  {
    $ctx->note("[err]");
    $ctx->note("  $_") for split /\r?\n/, $self->err;
  }
  $ctx->release;
  $self;
}


sub diag
{
  my($self) = @_;
  my $ctx = context();
  $ctx->diag("[cmd]");
  $ctx->diag("  @{$self->{cmd}}");
  if($self->out ne '')
  {
    $ctx->diag("[out]");
    $ctx->diag("  $_") for split /\r?\n/, $self->out;
  }
  if($self->err ne '')
  {
    $ctx->diag("[err]");
    $ctx->diag("  $_") for split /\r?\n/, $self->err;
  }
  $ctx->release;
  $self;
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Test::Alien::Run - Run object

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use Test2::V0;
 use Test::Alien;
 
 run_ok([ $^X, -e => 'print "some output"; exit 22'])
   ->exit_is(22)
   ->out_like(qr{some});

=head1 DESCRIPTION

This class stores information about a process run as performed by
L<Test::Alien#run_ok>.  That function is the I<ONLY> way to create
an instance of this class.

=head1 ATTRIBUTES

=head2 out

 my $str = $run->out;

The standard output from the run.

=head2 err

 my $str = $run->err;

The standard error from the run.

=head2 exit

 my $int = $run->exit;

The exit value of the run.

=head2 signal

 my $int = $run->signal;

The signal that killed the run, or zero if the process was terminated normally.

=head1 METHODS

These methods return the run object itself, so they can be chained,
as in the synopsis above.

=head2 success

 $run->success;
 $run->success($message);

Passes if the process terminated normally with an exit value of 0.

=head2 exit_is

 $run->exit_is($exit);
 $run->exit_is($exit, $message);

Passes if the process terminated with the given exit value.

=head2 exit_isnt

 $run->exit_isnt($exit);
 $run->exit_isnt($exit, $message);

Passes if the process terminated with an exit value of anything
but the given value.

=head2 out_like

 $run->out_like($regex);
 $run->out_like($regex, $message);

Passes if the output of the run matches the given pattern.

=head2 out_unlike

 $run->out_unlike($regex);
 $run->out_unlike($regex, $message);

Passes if the output of the run does not match the given pattern.

=head2 err_like

 $run->err_like($regex);
 $run->err_like($regex, $message);

Passes if the standard error of the run matches the given pattern.

=head2 err_unlike

 $run->err_unlike($regex);
 $run->err_unlike($regex, $message);

Passes if the standard error of the run does not match the given pattern.

=head2 note

 $run->note;

Send the output and standard error as test note.

=head2 diag

 $run->diag;

Send the output and standard error as test diagnostic.

=head1 SEE ALSO

=over 4

=item L<Test::Alien>

=back

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK1N%[�Ո��perl5/Test/Alien/CanCompile.pmnu��6�$package Test::Alien::CanCompile;

use strict;
use warnings;
use 5.008004;
use Test2::API qw( context );

# ABSTRACT: Skip a test file unless a C compiler is available
our $VERSION = '2.84'; # VERSION


sub skip
{
  require ExtUtils::CBuilder;
  ExtUtils::CBuilder->new->have_compiler ? undef : 'This test requires a compiler.';
}

sub import
{
  my $skip = __PACKAGE__->skip;
  return unless defined $skip;

  my $ctx = context();
  $ctx->plan(0, SKIP => $skip);
  $ctx->release;
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Test::Alien::CanCompile - Skip a test file unless a C compiler is available

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use Test::Alien::CanCompile;

=head1 DESCRIPTION

This is just a L<Test2> plugin that requires that a compiler
be available.  Otherwise the test will be skipped.

=head1 SEE ALSO

=over 4

=item L<Test::Alien>

=back

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK1N%[����ppperl5/Test/Alien/Synthetic.pmnu��6�$package Test::Alien::Synthetic;

use strict;
use warnings;
use 5.008004;
use Test2::API qw( context );

# ABSTRACT: A mock alien object for testing
our $VERSION = '2.84'; # VERSION


sub _def ($) { my($val) = @_; defined $val ? $val : '' }

sub cflags       { _def shift->{cflags}             }
sub libs         { _def shift->{libs}               }
sub dynamic_libs { @{ shift->{dynamic_libs} || [] } }

sub runtime_prop
{
  my($self) = @_;
  defined $self->{runtime_prop}
    ? $self->{runtime_prop}
    : {};
}

sub cflags_static
{
  my($self) = @_;
  defined $self->{cflags_static}
    ? $self->{cflags_static}
    : $self->cflags;
}

sub libs_static
{
  my($self) = @_;
  defined $self->{libs_static}
    ? $self->{libs_static}
    : $self->libs;
}

sub bin_dir
{
  my $dir = shift->{bin_dir};
  defined $dir && -d $dir ? ($dir) : ();
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Test::Alien::Synthetic - A mock alien object for testing

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use Test2::V0;
 use Test::Alien;
 
 my $alien = synthetic {
   cflags => '-I/foo/bar/include',
   libs   => '-L/foo/bar/lib -lbaz',
 };
 
 alien_ok $alien;
 
 done_testing;

=head1 DESCRIPTION

This class is used to model a synthetic L<Alien>
class that implements the minimum L<Alien::Base>
interface needed by L<Test::Alien>.

It can be useful if you have a non-L<Alien::Base>
based L<Alien> distribution that you need to test.

B<NOTE>: The name of this class may move in the
future, so do not refer to this class name directly.
Instead create instances of this class using the
L<Test::Alien#synthetic> function.

=head1 ATTRIBUTES

=head2 cflags

String containing the compiler flags

=head2 cflags_static

String containing the static compiler flags

=head2 libs

String containing the linker and library flags

=head2 libs_static

String containing the static linker and library flags

=head2 dynamic_libs

List reference containing the dynamic libraries.

=head2 bin_dir

Tool binary directory.

=head2 runtime_prop

Runtime properties.

=head1 EXAMPLE

Here is a complete example using L<Alien::Libarchive> which is a non-L<Alien::Base>
based L<Alien> distribution.

 use strict;
 use warnings;
 use Test2::V0;
 use Test::Alien;
 use Alien::Libarchive;
 
 my $real = Alien::Libarchive->new;
 my $alien = synthetic {
   cflags       => scalar $real->cflags,
   libs         => scalar $real->libs,
   dynamic_libs => [$real->dlls],
 };
 
 alien_ok $alien;
 
 xs_ok do { local $/; <DATA> }, with_subtest {
   my($module) = @_;
   my $ptr = $module->archive_read_new;
   like $ptr, qr{^[0-9]+$};
   $module->archive_read_free($ptr);
 };
 
 ffi_ok { symbols => [qw( archive_read_new )] }, with_subtest {
   my($ffi) = @_;
   my $new  = $ffi->function(archive_read_new => [] => 'opaque');
   my $free = $ffi->function(archive_read_close => ['opaque'] => 'void');
   my $ptr = $new->();
   like $ptr, qr{^[0-9]+$};
   $free->($ptr);
 };
 
 done_testing;
 
 __DATA__
 
 #include "EXTERN.h"
 #include "perl.h"
 #include "XSUB.h"
 #include <archive.h>
 
 MODULE = TA_MODULE PACKAGE = TA_MODULE
 
 void *archive_read_new(class);
     const char *class;
   CODE:
     RETVAL = (void*) archive_read_new();
   OUTPUT:
     RETVAL
 
 void archive_read_free(class, ptr);
     const char *class;
     void *ptr;
   CODE:
     archive_read_free(ptr);

=head1 SEE ALSO

=over 4

=item L<Test::Alien>

=back

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK1N%[�\-�EEperl5/Test/Alien/Build.pmnu��6�$package Test::Alien::Build;

use strict;
use warnings;
use 5.008004;
use Exporter qw( import );
use Path::Tiny qw( path );
use Carp qw( croak );
use Test2::API qw( context run_subtest );
use Capture::Tiny qw( capture_merged );
use Alien::Build::Util qw( _mirror );
use List::Util 1.33 qw( any );
use Alien::Build::Temp;

our @EXPORT = qw(
  alienfile
  alienfile_ok
  alienfile_skip_if_missing_prereqs
  alien_download_ok
  alien_extract_ok
  alien_build_ok
  alien_build_clean
  alien_clean_install
  alien_install_type_is
  alien_checkpoint_ok
  alien_resume_ok
  alien_subtest
  alien_rc
);

# ABSTRACT: Tools for testing Alien::Build + alienfile
our $VERSION = '2.84'; # VERSION


my $build;
my $build_alienfile;
my $build_root;
my $build_targ;

sub alienfile::targ
{
  $build_targ;
}

sub alienfile
{
  my($package, $filename, $line) = caller;
  ($package, $filename, $line) = caller(2) if $package eq __PACKAGE__;
  $filename = path($filename)->absolute;
  my %args = @_ == 0 ? (filename => 'alienfile') : @_ % 2 ? ( source => do { '# line '. $line . ' "' . path($filename)->absolute . qq("\n) . $_[0] }) : @_;

  require alienfile;
  push @alienfile::EXPORT, 'targ' unless any { /^targ$/ } @alienfile::EXPORT;

  my $temp = Alien::Build::Temp->newdir;
  my $get_temp_root = do{
    my $root; # may be undef;
    sub {
      $root ||= Path::Tiny->new($temp);

      if(@_)
      {
        my $path = $root->child(@_);
        $path->mkpath;
        $path;
      }
      else
      {
        return $root;
      }
    };
  };

  if($args{source})
  {
    my $file = $get_temp_root->()->child('alienfile');
    $file->spew_utf8($args{source});
    $args{filename} = $file->stringify;
  }
  else
  {
    unless(defined $args{filename})
    {
      croak "You must specify at least one of filename or source";
    }
    $args{filename} = path($args{filename})->absolute->stringify;
  }

  $args{stage}  ||= $get_temp_root->('stage')->stringify;
  $args{prefix} ||= $get_temp_root->('prefix')->stringify;
  $args{root}   ||= $get_temp_root->('root')->stringify;

  require Alien::Build;

  _alienfile_clear();
  my $out = capture_merged {
    $build_targ = $args{targ};
    $build = Alien::Build->load($args{filename}, root => $args{root});
    $build->set_stage($args{stage});
    $build->set_prefix($args{prefix});
  };

  my $ctx = context();
  $ctx->note($out) if $out;
  $ctx->release;

  $build_alienfile = $args{filename};
  $build_root      = $temp;
  $build
}

sub _alienfile_clear
{
  eval { defined $build_root && -d $build_root && path($build_root)->remove_tree };
  undef $build;
  undef $build_alienfile;
  undef $build_root;
  undef $build_targ;
}


sub alienfile_ok
{
  my $build;
  my $name;
  my $error;

  if(@_ == 1 && ! defined $_[0])
  {
    $build = $_[0];
    $error = 'no alienfile given';
    $name = 'alienfile compiled';
  }
  elsif(@_ == 1 && eval { $_[0]->isa('Alien::Build') })
  {
    $build = $_[0];
    $name = 'alienfile compiled';
  }
  else
  {
    $build = eval { alienfile(@_) };
    $error = $@;
    $name = 'alienfile compiles';
  }

  my $ok = !! $build;

  my $ctx = context();
  $ctx->ok($ok, $name);
  $ctx->diag("error: $error") if $error;
  $ctx->release;

  $build;
}


sub alienfile_skip_if_missing_prereqs
{
  my($phase) = @_;

  if($build)
  {
    eval { $build->load_requires('configure', 1) };
    if(my $error = $@)
    {
      my $reason = "Missing configure prereq";
      if($error =~ /Required (.*) (.*),/)
      {
        $reason .= ": $1 $2";
      }
      my $ctx = context();
      $ctx->plan(0, SKIP => $reason);
      $ctx->release;
      return;
    }
    $phase ||= $build->install_type;
    eval { $build->load_requires($phase, 1) };
    if(my $error = $@)
    {
      my $reason = "Missing $phase prereq";
      if($error =~ /Required (.*) (.*),/)
      {
        $reason .= ": $1 $2";
      }
      my $ctx = context();
      $ctx->plan(0, SKIP => $reason);
      $ctx->release;
      return;
    }
  }
}


sub alien_install_type_is
{
  my($type, $name) = @_;

  croak "invalid install type" unless defined $type && $type =~ /^(system|share)$/;
  $name ||= "alien install type is $type";

  my $ok = 0;
  my @diag;

  if($build)
  {
    my($out, $actual) = capture_merged {
      $build->load_requires('configure');
      $build->install_type;
    };
    if($type eq $actual)
    {
      $ok = 1;
    }
    else
    {
      push @diag, "expected install type of $type, but got $actual";
    }
  }
  else
  {
    push @diag, 'no alienfile'
  }

  my $ctx = context();
  $ctx->ok($ok, $name);
  $ctx->diag($_) for @diag;
  $ctx->release;

  $ok;
}


sub alien_download_ok
{
  my($name) = @_;

  $name ||= 'alien download';

  my $ok;
  my $file;
  my @diag;
  my @note;

  if($build)
  {
    my($out, $error) = capture_merged {
      eval {
        $build->load_requires('configure');
        $build->load_requires($build->install_type);
        $build->download;
      };
      $@;
    };
    if($error)
    {
      $ok = 0;
      push @diag, $out if defined $out;
      push @diag, "extract threw exception: $error";
    }
    else
    {
      $file = $build->install_prop->{download};
      if(-d $file || -f $file)
      {
        $ok = 1;
        push @note, $out if defined $out;
      }
      else
      {
        $ok = 0;
        push @diag, $out if defined $out;
        push @diag, 'no file or directory';
      }
    }
  }
  else
  {
    $ok = 0;
    push @diag, 'no alienfile';
  }

  my $ctx = context();
  $ctx->ok($ok, $name);
  $ctx->note($_) for @note;
  $ctx->diag($_) for @diag;
  $ctx->release;

  $file;
}


sub alien_extract_ok
{
  my($archive, $name) = @_;

  $name ||= $archive ? "alien extraction of $archive" : 'alien extraction';
  my $ok;
  my $dir;
  my @diag;
  my @note;

  if($build)
  {
    my($out, $error);
    ($out, $dir, $error) = capture_merged {
      my $dir = eval {
        $build->load_requires('configure');
        $build->load_requires($build->install_type);
        $build->download;
        $build->extract($archive);
      };
      ($dir, $@);
    };
    if($error)
    {
      $ok = 0;
      push @diag, $out if defined $out;
      push @diag, "extract threw exception: $error";
    }
    else
    {
      if(-d $dir)
      {
        $ok = 1;
        push @note, $out if defined $out;
      }
      else
      {
        $ok = 0;
        push @diag, $out if defined $out;
        push @diag, 'no directory';
      }
    }
  }
  else
  {
    $ok = 0;
    push @diag, 'no alienfile';
  }

  my $ctx = context();
  $ctx->ok($ok, $name);
  $ctx->note($_) for @note;
  $ctx->diag($_) for @diag;
  $ctx->release;

  $dir;
}


my $count = 1;

sub alien_build_ok
{
  my $opt = defined $_[0] && ref($_[0]) eq 'HASH'
    ? shift : { class => 'Alien::Base' };

  my($name) = @_;

  $name ||= 'alien builds okay';
  my $ok;
  my @diag;
  my @note;
  my $alien;

  if($build)
  {
    my($out,$error) = capture_merged {
      eval {
        $build->load_requires('configure');
        $build->load_requires($build->install_type);
        $build->download;
        $build->build;
      };
      $@;
    };
    if($error)
    {
      $ok = 0;
      push @diag, $out if defined $out;
      push @diag, "build threw exception: $error";
    }
    else
    {
      $ok = 1;

      push @note, $out if defined $out;

      require Alien::Base;

      my $prefix = $build->runtime_prop->{prefix};
      my $stage  = $build->install_prop->{stage};
      my %prop   = %{ $build->runtime_prop };

      $prop{distdir} = $prefix;

      _mirror $stage, $prefix;

      my $dist_dir = sub {
        $prefix;
      };

      my $runtime_prop = sub {
        \%prop;
      };

      $alien = sprintf 'Test::Alien::Build::Faux%04d', $count++;
      {
        no strict 'refs';
        @{ "${alien}::ISA" }          = $opt->{class};
        *{ "${alien}::dist_dir" }     = $dist_dir;
        *{ "${alien}::runtime_prop" } = $runtime_prop;
      }
    }
  }
  else
  {
    $ok = 0;
    push @diag, 'no alienfile';
  }

  my $ctx = context();
  $ctx->ok($ok, $name);
  $ctx->diag($_) for @diag;
  $ctx->note($_) for @note;
  $ctx->release;

  $alien;
}


sub alien_build_clean
{
  my $ctx = context();
  if($build_root)
  {
    foreach my $child (path($build_root)->children)
    {
      next if $child->basename eq 'prefix';
      $ctx->note("clean: rm: $child");
      $child->remove_tree;
    }
  }
  else
  {
    $ctx->note("no build to clean");
  }
  $ctx->release;
}


sub alien_clean_install
{
  my($name) = @_;

  $name ||= "run clean_install";

  my $ok;
  my @diag;
  my @note;

  if($build)
  {
    my($out,$error) = capture_merged {
      eval {
        $build->clean_install;
      };
      $@;
    };
    if($error)
    {
      $ok = 0;
      push @diag, $out if defined $out && $out ne '';
      push @diag, "build threw exception: $error";
    }
    else
    {
      $ok = 1;
      push @note, $out if defined $out && $out ne '';
    }
  }
  else
  {
    $ok = 0;
    push @diag, 'no alienfile';
  }

  my $ctx = context();
  $ctx->ok($ok, $name);
  $ctx->diag($_) for @diag;
  $ctx->note($_) for @note;
  $ctx->release;
}


sub alien_checkpoint_ok
{
  my($name) = @_;

  $name ||= "alien checkpoint ok";
  my $ok;
  my @diag;

  if($build)
  {
    eval { $build->checkpoint };
    if($@)
    {
      push @diag, "error in checkpoint: $@";
      $ok = 0;
    }
    else
    {
      $ok = 1;
    }
    undef $build;
  }
  else
  {
    push @diag, "no build to checkpoint";
    $ok = 0;
  }

  my $ctx = context();
  $ctx->ok($ok, $name);
  $ctx->diag($_) for @diag;
  $ctx->release;

  $ok;
}


sub alien_resume_ok
{
  my($name) = @_;

  $name ||= "alien resume ok";
  my $ok;
  my @diag;

  if($build_alienfile && $build_root && !defined $build)
  {
    $build = eval { Alien::Build->resume($build_alienfile, "$build_root/root") };
    if($@)
    {
      push @diag, "error in resume: $@";
      $ok = 0;
    }
    else
    {
      $ok = 1;
    }
  }
  else
  {
    if($build)
    {
      push @diag, "build has not been checkpointed";
    }
    else
    {
      push @diag, "no build to resume";
    }
    $ok = 0;
  }

  my $ctx = context();
  $ctx->ok($ok, $name);
  $ctx->diag($_) for @diag;
  $ctx->release;

  ($ok && $build) || $ok;
}


my $alien_rc_root;

sub alien_rc
{
  my($code) = @_;

  croak "passed in undef rc" unless defined $code;
  croak "looks like you have already defined a rc.pl file" if $ENV{ALIEN_BUILD_RC} ne '-';

  my(undef, $filename, $line) = caller;
  my $code2 = "use strict; use warnings;\n" .
              '# line ' . $line . ' "' . path($filename)->absolute . "\n$code";

  $alien_rc_root ||= Alien::Build::Temp->newdir;

  my $rc = path($alien_rc_root)->child('rc.pl');
  $rc->spew_utf8($code2);
  $ENV{ALIEN_BUILD_RC} = "$rc";
  return 1;
}


sub alien_subtest
{
  my($name, $code, @args) = @_;

  _alienfile_clear;

  my $ctx = context();
  my $pass = run_subtest($name, $code, { buffered => 1 }, @args);
  $ctx->release;

  _alienfile_clear;

  $pass;
}

delete $ENV{$_} for qw( ALIEN_BUILD_LOG ALIEN_BUILD_PRELOAD ALIEN_BUILD_POSTLOAD ALIEN_INSTALL_TYPE PKG_CONFIG_PATH ALIEN_BUILD_PKG_CONFIG );
$ENV{ALIEN_BUILD_RC} = '-';

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Test::Alien::Build - Tools for testing Alien::Build + alienfile

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use Test2::V0;
 use Test::Alien::Build;
 
 # returns an instance of Alien::Build.
 my $build = alienfile_ok q{
   use alienfile;
 
   plugin 'My::Plugin' => (
     foo => 1,
     bar => 'string',
     ...
   );
 };
 
 alien_build_ok 'builds okay.';
 
 done_testing;

=head1 DESCRIPTION

This module provides some tools for testing L<Alien::Build> and L<alienfile>.  Outside of L<Alien::Build>
core development, It is probably most useful for L<Alien::Build::Plugin> developers.

This module also unsets a number of L<Alien::Build> specific environment variables, in order to make tests
reproducible even when overrides are set in different environments.  So if you want to test those variables in
various states you should explicitly set them in your test script.  These variables are unset if they defined:
C<ALIEN_BUILD_PRELOAD> C<ALIEN_BUILD_POSTLOAD> C<ALIEN_INSTALL_TYPE>.

=head1 FUNCTIONS

=head2 alienfile

 my $build = alienfile;
 my $build = alienfile q{ use alienfile ... };
 my $build = alienfile filename => 'alienfile';

Create a Alien::Build instance from the given L<alienfile>.  The first two forms are abbreviations.

 my $build = alienfile;
 # is the same as
 my $build = alienfile filename => 'alienfile';

and

 my $build = alienfile q{ use alienfile ... };
 # is the same as
 my $build = alienfile source => q{ use alienfile ... };

Except for the second abbreviated form sets the line number before feeding the source into L<Alien::Build>
so that you will get diagnostics with the correct line numbers.

=over 4

=item source

The source for the alienfile as a string.  You must specify one of C<source> or C<filename>.

=item filename

The filename for the alienfile.  You must specify one of C<source> or C<filename>.

=item root

The build root.

=item stage

The staging area for the build.

=item prefix

The install prefix for the build.

=back

=head2 alienfile_ok

 my $build = alienfile_ok;
 my $build = alienfile_ok q{ use alienfile ... };
 my $build = alienfile_ok filename => 'alienfile';
 my $build = alienfile_ok $build;

Same as C<alienfile> above, except that it runs as a test, and will not throw an exception
on failure (it will return undef instead).

[version 1.49]

As of version 1.49 you can also pass in an already formed instance of L<Alien::Build>.  This
allows you to do something like this:

 subtest 'a subtest' => sub {
   my $build = alienfile q{ use alienfile; ... };
   alienfile_skip_if_missing_prereqs; # skip if alienfile prereqs are missing
   alienfile_ok $build;  # delayed pass/fail for the compile of alienfile
 };

=head2 alienfile_skip_if_missing_prereqs

 alienfile_skip_if_missing_prereqs;
 alienfile_skip_if_missing_prereqs $phase;

Skips the test or subtest if the prereqs for the alienfile are missing.
If C<$phase> is not given, then either C<share> or C<system> will be
detected.

=head2 alien_install_type_is

 alien_install_type_is $type;
 alien_install_type_is $type, $name;

Simple test to see if the install type is what you expect.
C<$type> should be one of C<system> or C<share>.

=head2 alien_download_ok

 my $file = alien_download_ok;
 my $file = alien_download_ok $name;

Makes a download attempt and test that a file or directory results.  Returns
the file or directory if successful.  Returns C<undef> otherwise.

=head2 alien_extract_ok

 my $dir = alien_extract_ok;
 my $dir = alien_extract_ok $archive;
 my $dir = alien_extract_ok $archive, $name;
 my $dir = alien_extract_ok undef, $name;

Makes an extraction attempt and test that a directory results.  Returns
the directory if successful.  Returns C<undef> otherwise.

=head2 alien_build_ok

 my $alien = alien_build_ok;
 my $alien = alien_build_ok $name;
 my $alien = alien_build_ok { class => $class };
 my $alien = alien_build_ok { class => $class }, $name;

Runs the download and build stages.  Passes if the build succeeds.  Returns an instance
of L<Alien::Base> which can be passed into C<alien_ok> from L<Test::Alien>.  Returns
C<undef> if the test fails.

Options

=over 4

=item class

The base class to use for your alien.  This is L<Alien::Base> by default.  Should
be a subclass of L<Alien::Base>, or at least adhere to its API.

=back

=head2 alien_build_clean

 alien_build_clean;

Removes all files with the current build, except for the runtime prefix.
This helps test that the final install won't depend on the build files.

=head2 alien_clean_install

 alien_clean_install;

Runs C<$build-E<gt>clean_install>, and verifies it did not crash.

=head2 alien_checkpoint_ok

 alien_checkpoint_ok;
 alien_checkpoint_ok $test_name;

Test the checkpoint of a build.

=head2 alien_resume_ok

 alien_resume_ok;
 alien_resume_ok $test_name;

Test a resume a checkpointed build.

=head2 alien_rc

 alien_rc $code;

Creates C<rc.pl> file in a temp directory and sets ALIEN_BUILD_RC.  Useful for testing
plugins that should be called from C<~/.alienbuild/rc.pl>.  Note that because of the
nature of how the C<~/.alienbuild/rc.pl> file works, you can only use this once!

=head2 alien_subtest

 alien_subtest $test_name => sub {
   ...
 };

Clear the build object and clear the build object before and after the subtest.

=head1 SEE ALSO

=over 4

=item L<Alien>

=item L<alienfile>

=item L<Alien::Build>

=item L<Test::Alien>

=back

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK1N%[���m��perl5/Test/Alien/CanPlatypus.pmnu��6�$package Test::Alien::CanPlatypus;

use strict;
use warnings;
use 5.008004;
use Test2::API qw( context );

# ABSTRACT: Skip a test file unless FFI::Platypus is available
our $VERSION = '2.84'; # VERSION


sub skip
{
  eval { require FFI::Platypus; 1 } ? undef : 'This test requires FFI::Platypus.';
}

sub import
{
  my $skip = __PACKAGE__->skip;
  return unless defined $skip;

  my $ctx = context();
  $ctx->plan(0, SKIP => $skip);
  $ctx->release;
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Test::Alien::CanPlatypus - Skip a test file unless FFI::Platypus is available

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use Test::Alien::CanPlatypus;

=head1 DESCRIPTION

This is just a L<Test2> plugin that requires that L<FFI::Platypus>
be available.  Otherwise the test will be skipped.

=head1 SEE ALSO

=over 4

=item L<Test::Alien>

=item L<FFI::Platypus>

=back

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK1N%[o1D���perl5/Scope/Guard.pmnu��6�$package Scope::Guard;

use strict;
use warnings;

use Carp qw(confess);
use Exporter ();

our @ISA = qw(Exporter);
our @EXPORT_OK = qw(guard scope_guard);
our $VERSION = '0.21';

sub new {
    confess "Can't create a Scope::Guard in void context" unless (defined wantarray);

    my $class = shift;
    my $handler = shift() || die 'Scope::Guard::new: no handler supplied';
    my $ref = ref $handler || '';

    die "Scope::Guard::new: invalid handler - expected CODE ref, got: '$ref'"
        unless ref($handler) eq 'CODE';

    bless [ 0, $handler ], ref $class || $class;
}

sub dismiss {
    my $self = shift;
    my $dismiss = @_ ? shift : 1;

    $self->[0] = $dismiss;
}

sub guard(&) { __PACKAGE__->new(shift) }
sub scope_guard($) { __PACKAGE__->new(shift) }

sub DESTROY {
    my $self = shift;
    my ($dismiss, $handler) = @$self;

    $handler->() unless ($dismiss);
}

1;

__END__

=pod

=head1 NAME

Scope::Guard - lexically-scoped resource management

=head1 SYNOPSIS

    my $guard = guard { ... };

      # or

    my $guard = scope_guard \&handler;

      # or

    my $guard = Scope::Guard->new(sub { ... });

    $guard->dismiss(); # disable the handler

=head1 DESCRIPTION

This module provides a convenient way to perform cleanup or other forms of resource
management at the end of a scope. It is particularly useful when dealing with exceptions:
the C<Scope::Guard> constructor takes a reference to a subroutine that is guaranteed to
be called even if the thread of execution is aborted prematurely. This effectively allows
lexically-scoped "promises" to be made that are automatically honoured by perl's garbage
collector.

For more information, see: L<http://www.drdobbs.com/cpp/184403758>

=head1 METHODS

=head2 new

    my $guard = Scope::Guard->new(sub { ... });

      # or

    my $guard = Scope::Guard->new(\&handler);

The C<new> method creates a new C<Scope::Guard> object which calls the supplied handler when its C<DESTROY> method is
called, typically at the end of the scope.

=head2 dismiss

    $guard->dismiss();

      # or

    $guard->dismiss(1);

C<dismiss> detaches the handler from the C<Scope::Guard> object. This revokes the "promise" to call the
handler when the object is destroyed.

The handler can be re-enabled by calling:

    $guard->dismiss(0);

=head1 EXPORTS

=head2 guard

C<guard> takes a block and returns a new C<Scope::Guard> object. It can be used
as a shorthand for:

    Scope::Guard->new(...)

e.g.

    my $guard = guard { ... };

Note: calling C<guard> anonymously, i.e. in void context, will raise an exception.
This is because anonymous guards are destroyed B<immediately>
(rather than at the end of the scope), which is unlikely to be the desired behaviour.

=head2 scope_guard

C<scope_guard> is the same as C<guard>, but it takes a code ref rather than a block.
e.g.

    my $guard = scope_guard \&handler;

or:

    my $guard = scope_guard sub { ... };

or:

    my $guard = scope_guard $handler;

As with C<guard>, calling C<scope_guard> in void context will raise an exception.

=head1 VERSION

0.21

=head1 SEE ALSO

=over

=item * L<B::Hooks::EndOfScope|B::Hooks::EndOfScope>

=item * L<End|End>

=item * L<Guard|Guard>

=item * L<Hook::Scope|Hook::Scope>

=item * L<Object::Destroyer|Object::Destroyer>

=item * L<Perl::AtEndOfScope|Perl::AtEndOfScope>

=item * L<ReleaseAction|ReleaseAction>

=item * L<Scope::local_OnExit|Scope::local_OnExit>

=item * L<Scope::OnExit|Scope::OnExit>

=item * L<Sub::ScopeFinalizer|Sub::ScopeFinalizer>

=item * L<Value::Canary|Value::Canary>

=back

=head1 AUTHOR

chocolateboy <chocolate@cpan.org>

=head1 COPYRIGHT

Copyright (c) 2005-2015, chocolateboy.

This module is free software. It may be used, redistributed and/or modified under the same terms
as Perl itself.

=cut
PK1N%[�߻lYHYH
perl5/CPAN.pmnu��6�$# -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*-
# vim: ts=4 sts=4 sw=4:
use strict;
package CPAN;
$CPAN::VERSION = '2.38';
$CPAN::VERSION =~ s/_//;

# we need to run chdir all over and we would get at wrong libraries
# there
use File::Spec ();
BEGIN {
    if (File::Spec->can("rel2abs")) {
        for my $inc (@INC) {
            $inc = File::Spec->rel2abs($inc) unless ref $inc;
        }
    }
    $SIG{WINCH} = 'IGNORE' if exists $SIG{WINCH};
}
use CPAN::Author;
use CPAN::HandleConfig;
use CPAN::Version;
use CPAN::Bundle;
use CPAN::CacheMgr;
use CPAN::Complete;
use CPAN::Debug;
use CPAN::Distribution;
use CPAN::Distrostatus;
use CPAN::FTP;
use CPAN::Index 1.93; # https://rt.cpan.org/Ticket/Display.html?id=43349
use CPAN::InfoObj;
use CPAN::Module;
use CPAN::Prompt;
use CPAN::URL;
use CPAN::Queue;
use CPAN::Tarzip;
use CPAN::DeferredCode;
use CPAN::Shell;
use CPAN::LWP::UserAgent;
use CPAN::Exception::RecursiveDependency;
use CPAN::Exception::yaml_not_installed;
use CPAN::Exception::yaml_process_error;

use Carp ();
use Config ();
use Cwd qw(chdir);
use DirHandle ();
use Exporter ();
use ExtUtils::MakeMaker qw(prompt); # for some unknown reason,
                                    # 5.005_04 does not work without
                                    # this
use File::Basename ();
use File::Copy ();
use File::Find;
use File::Path ();
use FileHandle ();
use Fcntl qw(:flock);
use Safe ();
use Sys::Hostname qw(hostname);
use Text::ParseWords ();
use Text::Wrap ();

# protect against "called too early"
sub find_perl ();
sub anycwd ();
sub _uniq;

no lib ".";

require Mac::BuildTools if $^O eq 'MacOS';
if ($ENV{PERL5_CPAN_IS_RUNNING} && $$ != $ENV{PERL5_CPAN_IS_RUNNING}) {
    $ENV{PERL5_CPAN_IS_RUNNING_IN_RECURSION} ||= $ENV{PERL5_CPAN_IS_RUNNING};
    my @rec = _uniq split(/,/, $ENV{PERL5_CPAN_IS_RUNNING_IN_RECURSION}), $$;
    $ENV{PERL5_CPAN_IS_RUNNING_IN_RECURSION} = join ",", @rec;
    # warn "# Note: Recursive call of CPAN.pm detected\n";
    my $w = sprintf "# Note: CPAN.pm is running in process %d now", pop @rec;
    my %sleep = (
                 5 => 30,
                 6 => 60,
                 7 => 120,
                );
    my $sleep = @rec > 7 ? 300 : ($sleep{scalar @rec}||0);
    my $verbose = @rec >= 4;
    while (@rec) {
        $w .= sprintf " which has been called by process %d", pop @rec;
    }
    if ($sleep) {
        $w .= ".\n\n# Sleeping $sleep seconds to protect other processes\n";
    }
    if ($verbose) {
        warn $w;
    }
    local $| = 1;
    my $have_been_sleeping = 0;
    while ($sleep > 0) {
        printf "\r#%5d", --$sleep;
        sleep 1;
	++$have_been_sleeping;
    }
    print "\n" if $have_been_sleeping;
}
$ENV{PERL5_CPAN_IS_RUNNING}=$$;
$ENV{PERL5_CPANPLUS_IS_RUNNING}=$$; # https://rt.cpan.org/Ticket/Display.html?id=23735

END { $CPAN::End++; &cleanup; }

$CPAN::Signal ||= 0;
$CPAN::Frontend ||= "CPAN::Shell";
unless (@CPAN::Defaultsites) {
    @CPAN::Defaultsites = map {
        CPAN::URL->new(TEXT => $_, FROM => "DEF")
    }
        "http://www.perl.org/CPAN/",
        "ftp://ftp.perl.org/pub/CPAN/";
}
# $CPAN::iCwd (i for initial)
$CPAN::iCwd ||= CPAN::anycwd();
$CPAN::Perl ||= CPAN::find_perl();
$CPAN::Defaultdocs ||= "http://search.cpan.org/perldoc?";
$CPAN::Defaultrecent ||= "http://search.cpan.org/uploads.rdf";
$CPAN::Defaultrecent ||= "http://cpan.uwinnipeg.ca/htdocs/cpan.xml";

# our globals are getting a mess
use vars qw(
            $AUTOLOAD
            $Be_Silent
            $CONFIG_DIRTY
            $Defaultdocs
            $Echo_readline
            $Frontend
            $GOTOSHELL
            $HAS_USABLE
            $Have_warned
            $MAX_RECURSION
            $META
            $RUN_DEGRADED
            $Signal
            $SQLite
            $Suppress_readline
            $VERSION
            $autoload_recursion
            $term
            @Defaultsites
            @EXPORT
           );

$MAX_RECURSION = 32;

@CPAN::ISA = qw(CPAN::Debug Exporter);

# note that these functions live in CPAN::Shell and get executed via
# AUTOLOAD when called directly
@EXPORT = qw(
             autobundle
             bundle
             clean
             cvs_import
             expand
             force
             fforce
             get
             install
             install_tested
             is_tested
             make
             mkmyconfig
             notest
             perldoc
             readme
             recent
             recompile
             report
             shell
             smoke
             test
             upgrade
            );

sub soft_chdir_with_alternatives ($);

{
    $autoload_recursion ||= 0;

    #-> sub CPAN::AUTOLOAD ;
    sub AUTOLOAD { ## no critic
        $autoload_recursion++;
        my($l) = $AUTOLOAD;
        $l =~ s/.*:://;
        if ($CPAN::Signal) {
            warn "Refusing to autoload '$l' while signal pending";
            $autoload_recursion--;
            return;
        }
        if ($autoload_recursion > 1) {
            my $fullcommand = join " ", map { "'$_'" } $l, @_;
            warn "Refusing to autoload $fullcommand in recursion\n";
            $autoload_recursion--;
            return;
        }
        my(%export);
        @export{@EXPORT} = '';
        CPAN::HandleConfig->load unless $CPAN::Config_loaded++;
        if (exists $export{$l}) {
            CPAN::Shell->$l(@_);
        } else {
            die(qq{Unknown CPAN command "$AUTOLOAD". }.
                qq{Type ? for help.\n});
        }
        $autoload_recursion--;
    }
}

{
    my $x = *SAVEOUT; # avoid warning
    open($x,">&STDOUT") or die "dup failed";
    my $redir = 0;
    sub _redirect(@) {
        #die if $redir;
        local $_;
        push(@_,undef);
        while(defined($_=shift)) {
            if (s/^\s*>//){
                my ($m) = s/^>// ? ">" : "";
                s/\s+//;
                $_=shift unless length;
                die "no dest" unless defined;
                open(STDOUT,">$m$_") or die "open:$_:$!\n";
                $redir=1;
            } elsif ( s/^\s*\|\s*// ) {
                my $pipe="| $_";
                while(defined($_[0])){
                    $pipe .= ' ' . shift;
                }
                open(STDOUT,$pipe) or die "open:$pipe:$!\n";
                $redir=1;
            } else {
                push(@_,$_);
            }
        }
        return @_;
    }
    sub _unredirect {
        return unless $redir;
        $redir = 0;
        ## redirect: unredirect and propagate errors.  explicit close to wait for pipe.
        close(STDOUT);
        open(STDOUT,">&SAVEOUT");
        die "$@" if "$@";
        ## redirect: done
    }
}

sub _uniq {
    my(@list) = @_;
    my %seen;
    return grep { !$seen{$_}++ } @list;
}

#-> sub CPAN::shell ;
sub shell {
    my($self) = @_;
    $Suppress_readline = ! -t STDIN unless defined $Suppress_readline;
    CPAN::HandleConfig->load unless $CPAN::Config_loaded++;

    my $oprompt = shift || CPAN::Prompt->new;
    my $prompt = $oprompt;
    my $commandline = shift || "";
    $CPAN::CurrentCommandId ||= 1;

    local($^W) = 1;
    unless ($Suppress_readline) {
        require Term::ReadLine;
        if (! $term
            or
            $term->ReadLine eq "Term::ReadLine::Stub"
           ) {
            $term = Term::ReadLine->new('CPAN Monitor');
        }
        if ($term->ReadLine eq "Term::ReadLine::Gnu") {
            my $attribs = $term->Attribs;
            $attribs->{attempted_completion_function} = sub {
                &CPAN::Complete::gnu_cpl;
            }
        } else {
            $readline::rl_completion_function =
                $readline::rl_completion_function = 'CPAN::Complete::cpl';
        }
        if (my $histfile = $CPAN::Config->{'histfile'}) {{
            unless ($term->can("AddHistory")) {
                $CPAN::Frontend->mywarn("Terminal does not support AddHistory.\n");
                unless ($CPAN::META->has_inst('Term::ReadLine::Perl')) {
                    $CPAN::Frontend->mywarn("\nTo fix that, maybe try>  install Term::ReadLine::Perl\n\n");
                }
                last;
            }
            $META->readhist($term,$histfile);
        }}
        for ($CPAN::Config->{term_ornaments}) { # alias
            local $Term::ReadLine::termcap_nowarn = 1;
            $term->ornaments($_) if defined;
        }
        # $term->OUT is autoflushed anyway
        my $odef = select STDERR;
        $| = 1;
        select STDOUT;
        $| = 1;
        select $odef;
    }

    $META->checklock();
    my @cwd = grep { defined $_ and length $_ }
        CPAN::anycwd(),
              File::Spec->can("tmpdir") ? File::Spec->tmpdir() : (),
                    File::Spec->rootdir();
    my $try_detect_readline;
    $try_detect_readline = $term->ReadLine eq "Term::ReadLine::Stub" if $term;
    unless ($CPAN::Config->{inhibit_startup_message}) {
        my $rl_avail = $Suppress_readline ? "suppressed" :
            ($term->ReadLine ne "Term::ReadLine::Stub") ? "enabled" :
                "available (maybe install Bundle::CPAN or Bundle::CPANxxl?)";
        $CPAN::Frontend->myprint(
                                 sprintf qq{
cpan shell -- CPAN exploration and modules installation (v%s)
Enter 'h' for help.

},
                                 $CPAN::VERSION,
                                )
    }
    my($continuation) = "";
    my $last_term_ornaments;
  SHELLCOMMAND: while () {
        if ($Suppress_readline) {
            if ($Echo_readline) {
                $|=1;
            }
            print $prompt;
            last SHELLCOMMAND unless defined ($_ = <> );
            if ($Echo_readline) {
                # backdoor: I could not find a way to record sessions
                print $_;
            }
            chomp;
        } else {
            last SHELLCOMMAND unless
                defined ($_ = $term->readline($prompt, $commandline));
        }
        $_ = "$continuation$_" if $continuation;
        s/^\s+//;
        next SHELLCOMMAND if /^$/;
        s/^\s*\?\s*/help /;
        if (/^(?:q(?:uit)?|bye|exit)\s*$/i) {
            last SHELLCOMMAND;
        } elsif (s/\\$//s) {
            chomp;
            $continuation = $_;
            $prompt = "    > ";
        } elsif (/^\!/) {
            s/^\!//;
            my($eval) = $_;
            package
                CPAN::Eval; # hide from the indexer
            use strict;
            use vars qw($import_done);
            CPAN->import(':DEFAULT') unless $import_done++;
            CPAN->debug("eval[$eval]") if $CPAN::DEBUG;
            eval($eval);
            warn $@ if $@;
            $continuation = "";
            $prompt = $oprompt;
        } elsif (/./) {
            my(@line);
            eval { @line = Text::ParseWords::shellwords($_) };
            warn($@), next SHELLCOMMAND if $@;
            warn("Text::Parsewords could not parse the line [$_]"),
                next SHELLCOMMAND unless @line;
            $CPAN::META->debug("line[".join("|",@line)."]") if $CPAN::DEBUG;
            my $command = shift @line;
            eval {
                local (*STDOUT)=*STDOUT;
                @line = _redirect(@line);
                CPAN::Shell->$command(@line)
              };
            my $command_error = $@;
            _unredirect;
            my $reported_error;
            if ($command_error) {
                my $err = $command_error;
                if (ref $err and $err->isa('CPAN::Exception::blocked_urllist')) {
                    $CPAN::Frontend->mywarn("Client not fully configured, please proceed with configuring.$err");
                    $reported_error = ref $err;
                } else {
                    # I'd prefer never to arrive here and make all errors exception objects
                    if ($err =~ /\S/) {
                        require Carp;
                        require Dumpvalue;
                        my $dv = Dumpvalue->new(tick => '"');
                        Carp::cluck(sprintf "Catching error: %s", $dv->stringify($err));
                    }
                }
            }
            if ($command =~ /^(
                             # classic commands
                             make
                             |test
                             |install
                             |clean

                             # pragmas for classic commands
                             |ff?orce
                             |notest

                             # compounds
                             |report
                             |smoke
                             |upgrade
                            )$/x) {
                # only commands that tell us something about failed distros
                # eval necessary for people without an urllist
                eval {CPAN::Shell->failed($CPAN::CurrentCommandId,1);};
                if (my $err = $@) {
                    unless (ref $err and $reported_error eq ref $err) {
                        die $@;
                    }
                }
            }
            soft_chdir_with_alternatives(\@cwd);
            $CPAN::Frontend->myprint("\n");
            $continuation = "";
            $CPAN::CurrentCommandId++;
            $prompt = $oprompt;
        }
    } continue {
        $commandline = ""; # I do want to be able to pass a default to
                           # shell, but on the second command I see no
                           # use in that
        $Signal=0;
        CPAN::Queue->nullify_queue;
        if ($try_detect_readline) {
            if ($CPAN::META->has_inst("Term::ReadLine::Gnu")
                ||
                $CPAN::META->has_inst("Term::ReadLine::Perl")
            ) {
                delete $INC{"Term/ReadLine.pm"};
                my $redef = 0;
                local($SIG{__WARN__}) = CPAN::Shell::paintdots_onreload(\$redef);
                require Term::ReadLine;
                $CPAN::Frontend->myprint("\n$redef subroutines in ".
                                         "Term::ReadLine redefined\n");
                $GOTOSHELL = 1;
            }
        }
        if ($term and $term->can("ornaments")) {
            for ($CPAN::Config->{term_ornaments}) { # alias
                if (defined $_) {
                    if (not defined $last_term_ornaments
                        or $_ != $last_term_ornaments
                    ) {
                        local $Term::ReadLine::termcap_nowarn = 1;
                        $term->ornaments($_);
                        $last_term_ornaments = $_;
                    }
                } else {
                    undef $last_term_ornaments;
                }
            }
        }
        for my $class (qw(Module Distribution)) {
            # again unsafe meta access?
            for my $dm (sort keys %{$CPAN::META->{readwrite}{"CPAN::$class"}}) {
                next unless $CPAN::META->{readwrite}{"CPAN::$class"}{$dm}{incommandcolor};
                CPAN->debug("BUG: $class '$dm' was in command state, resetting");
                delete $CPAN::META->{readwrite}{"CPAN::$class"}{$dm}{incommandcolor};
            }
        }
        if ($GOTOSHELL) {
            $GOTOSHELL = 0; # not too often
            $META->savehist if $CPAN::term && $CPAN::term->can("GetHistory");
            @_ = ($oprompt,"");
            goto &shell;
        }
    }
    soft_chdir_with_alternatives(\@cwd);
}

#-> CPAN::soft_chdir_with_alternatives ;
sub soft_chdir_with_alternatives ($) {
    my($cwd) = @_;
    unless (@$cwd) {
        my $root = File::Spec->rootdir();
        $CPAN::Frontend->mywarn(qq{Warning: no good directory to chdir to!
Trying '$root' as temporary haven.
});
        push @$cwd, $root;
    }
    while () {
        if (chdir "$cwd->[0]") {
            return;
        } else {
            if (@$cwd>1) {
                $CPAN::Frontend->mywarn(qq{Could not chdir to "$cwd->[0]": $!
Trying to chdir to "$cwd->[1]" instead.
});
                shift @$cwd;
            } else {
                $CPAN::Frontend->mydie(qq{Could not chdir to "$cwd->[0]": $!});
            }
        }
    }
}

sub _flock {
    my($fh,$mode) = @_;
    if ( $Config::Config{d_flock} || $Config::Config{d_fcntl_can_lock} ) {
        return flock $fh, $mode;
    } elsif (!$Have_warned->{"d_flock"}++) {
        $CPAN::Frontend->mywarn("Your OS does not seem to support locking; continuing and ignoring all locking issues\n");
        $CPAN::Frontend->mysleep(5);
        return 1;
    } else {
        return 1;
    }
}

sub _yaml_module () {
    my $yaml_module = $CPAN::Config->{yaml_module} || "YAML";
    if (
        $yaml_module ne "YAML"
        &&
        !$CPAN::META->has_inst($yaml_module)
       ) {
        # $CPAN::Frontend->mywarn("'$yaml_module' not installed, falling back to 'YAML'\n");
        $yaml_module = "YAML";
    }
    if ($yaml_module eq "YAML"
        &&
        $CPAN::META->has_inst($yaml_module)
        &&
        $YAML::VERSION < 0.60
        &&
        !$Have_warned->{"YAML"}++
       ) {
        $CPAN::Frontend->mywarn("Warning: YAML version '$YAML::VERSION' is too low, please upgrade!\n".
                                "I'll continue but problems are *very* likely to happen.\n"
                               );
        $CPAN::Frontend->mysleep(5);
    }
    return $yaml_module;
}

# CPAN::_yaml_loadfile
sub _yaml_loadfile {
    my($self,$local_file,$opt) = @_;
    return +[] unless -s $local_file;
    my $opt_loadblessed = $opt->{loadblessed} || $CPAN::Config->{yaml_load_code} || 0;
    my $yaml_module = _yaml_module;
    if ($CPAN::META->has_inst($yaml_module)) {
        # temporarily enable yaml code deserialisation
        no strict 'refs';
        # 5.6.2 could not do the local() with the reference
        # so we do it manually instead
        my $old_loadcode = ${"$yaml_module\::LoadCode"};
        my $old_loadblessed = ${"$yaml_module\::LoadBlessed"};
        ${ "$yaml_module\::LoadCode" } = $CPAN::Config->{yaml_load_code} || 0;
        ${ "$yaml_module\::LoadBlessed" } = $opt_loadblessed ? 1 : 0;

        my ($code, @yaml);
        if ($code = UNIVERSAL::can($yaml_module, "LoadFile")) {
            eval { @yaml = $code->($local_file); };
            if ($@) {
                # this shall not be done by the frontend
                die CPAN::Exception::yaml_process_error->new($yaml_module,$local_file,"parse",$@);
            }
        } elsif ($code = UNIVERSAL::can($yaml_module, "Load")) {
            local *FH;
            if (open FH, $local_file) {
                local $/;
                my $ystream = <FH>;
                eval { @yaml = $code->($ystream); };
                if ($@) {
                    # this shall not be done by the frontend
                    die CPAN::Exception::yaml_process_error->new($yaml_module,$local_file,"parse",$@);
                }
            } else {
                $CPAN::Frontend->mywarn("Could not open '$local_file': $!");
            }
        }
        ${"$yaml_module\::LoadCode"} = $old_loadcode;
        ${"$yaml_module\::LoadBlessed"} = $old_loadblessed;
        return \@yaml;
    } else {
        # this shall not be done by the frontend
        die CPAN::Exception::yaml_not_installed->new($yaml_module, $local_file, "parse");
    }
    return +[];
}

# CPAN::_yaml_dumpfile
sub _yaml_dumpfile {
    my($self,$local_file,@what) = @_;
    my $yaml_module = _yaml_module;
    if ($CPAN::META->has_inst($yaml_module)) {
        my $code;
        if (UNIVERSAL::isa($local_file, "FileHandle")) {
            $code = UNIVERSAL::can($yaml_module, "Dump");
            eval { print $local_file $code->(@what) };
        } elsif ($code = UNIVERSAL::can($yaml_module, "DumpFile")) {
            eval { $code->($local_file,@what); };
        } elsif ($code = UNIVERSAL::can($yaml_module, "Dump")) {
            local *FH;
            open FH, ">$local_file" or die "Could not open '$local_file': $!";
            print FH $code->(@what);
        }
        if ($@) {
            die CPAN::Exception::yaml_process_error->new($yaml_module,$local_file,"dump",$@);
        }
    } else {
        if (UNIVERSAL::isa($local_file, "FileHandle")) {
            # I think this case does not justify a warning at all
        } else {
            die CPAN::Exception::yaml_not_installed->new($yaml_module, $local_file, "dump");
        }
    }
}

sub _init_sqlite () {
    unless ($CPAN::META->has_inst("CPAN::SQLite")) {
        $CPAN::Frontend->mywarn(qq{CPAN::SQLite not installed, trying to work without\n})
            unless $Have_warned->{"CPAN::SQLite"}++;
        return;
    }
    require CPAN::SQLite::META; # not needed since CVS version of 2006-12-17
    $CPAN::SQLite ||= CPAN::SQLite::META->new($CPAN::META);
}

{
    my $negative_cache = {};
    sub _sqlite_running {
        if ($negative_cache->{time} && time < $negative_cache->{time} + 60) {
            # need to cache the result, otherwise too slow
            return $negative_cache->{fact};
        } else {
            $negative_cache = {}; # reset
        }
        my $ret = $CPAN::Config->{use_sqlite} && ($CPAN::SQLite || _init_sqlite());
        return $ret if $ret; # fast anyway
        $negative_cache->{time} = time;
        return $negative_cache->{fact} = $ret;
    }
}

$META ||= CPAN->new; # In case we re-eval ourselves we need the ||

# from here on only subs.
################################################################################

sub _perl_fingerprint {
    my($self,$other_fingerprint) = @_;
    my $dll = eval {OS2::DLLname()};
    my $mtime_dll = 0;
    if (defined $dll) {
        $mtime_dll = (-f $dll ? (stat(_))[9] : '-1');
    }
    my $mtime_perl = (-f CPAN::find_perl ? (stat(_))[9] : '-1');
    my $this_fingerprint = {
                            '$^X' => CPAN::find_perl,
                            sitearchexp => $Config::Config{sitearchexp},
                            'mtime_$^X' => $mtime_perl,
                            'mtime_dll' => $mtime_dll,
                           };
    if ($other_fingerprint) {
        if (exists $other_fingerprint->{'stat($^X)'}) { # repair fp from rev. 1.88_57
            $other_fingerprint->{'mtime_$^X'} = $other_fingerprint->{'stat($^X)'}[9];
        }
        # mandatory keys since 1.88_57
        for my $key (qw($^X sitearchexp mtime_dll mtime_$^X)) {
            return unless $other_fingerprint->{$key} eq $this_fingerprint->{$key};
        }
        return 1;
    } else {
        return $this_fingerprint;
    }
}

sub suggest_myconfig () {
  SUGGEST_MYCONFIG: if(!$INC{'CPAN/MyConfig.pm'}) {
        $CPAN::Frontend->myprint("You don't seem to have a user ".
                                 "configuration (MyConfig.pm) yet.\n");
        my $new = CPAN::Shell::colorable_makemaker_prompt("Do you want to create a ".
                                              "user configuration now? (Y/n)",
                                              "yes");
        if($new =~ m{^y}i) {
            CPAN::Shell->mkmyconfig();
            return &checklock;
        } else {
            $CPAN::Frontend->mydie("OK, giving up.");
        }
    }
}

#-> sub CPAN::all_objects ;
sub all_objects {
    my($mgr,$class) = @_;
    CPAN::HandleConfig->load unless $CPAN::Config_loaded++;
    CPAN->debug("mgr[$mgr] class[$class]") if $CPAN::DEBUG;
    CPAN::Index->reload;
    values %{ $META->{readwrite}{$class} }; # unsafe meta access, ok
}

# Called by shell, not in batch mode. In batch mode I see no risk in
# having many processes updating something as installations are
# continually checked at runtime. In shell mode I suspect it is
# unintentional to open more than one shell at a time

#-> sub CPAN::checklock ;
sub checklock {
    my($self) = @_;
    my $lockfile = File::Spec->catfile($CPAN::Config->{cpan_home},".lock");
    if (-f $lockfile && -M _ > 0) {
        my $fh = FileHandle->new($lockfile) or
            $CPAN::Frontend->mydie("Could not open lockfile '$lockfile': $!");
        my $otherpid  = <$fh>;
        my $otherhost = <$fh>;
        $fh->close;
        if (defined $otherpid && length $otherpid) {
            chomp $otherpid;
        }
        if (defined $otherhost && length $otherhost) {
            chomp $otherhost;
        }
        my $thishost  = hostname();
        my $ask_if_degraded_wanted = 0;
        if (defined $otherhost && defined $thishost &&
            $otherhost ne '' && $thishost ne '' &&
            $otherhost ne $thishost) {
            $CPAN::Frontend->mydie(sprintf("CPAN.pm panic: Lockfile '$lockfile'\n".
                                           "reports other host $otherhost and other ".
                                           "process $otherpid.\n".
                                           "Cannot proceed.\n"));
        } elsif ($RUN_DEGRADED) {
            $CPAN::Frontend->mywarn("Running in downgraded mode (experimental)\n");
        } elsif (defined $otherpid && $otherpid) {
            return if $$ == $otherpid; # should never happen
            $CPAN::Frontend->mywarn(
                                    qq{
There seems to be running another CPAN process (pid $otherpid).  Contacting...
});
            if (kill 0, $otherpid or $!{EPERM}) {
                $CPAN::Frontend->mywarn(qq{Other job is running.\n});
                $ask_if_degraded_wanted = 1;
            } elsif (-w $lockfile) {
                my($ans) =
                    CPAN::Shell::colorable_makemaker_prompt
                        (qq{Other job not responding. Shall I overwrite }.
                        qq{the lockfile '$lockfile'? (Y/n)},"y");
            $CPAN::Frontend->myexit("Ok, bye\n")
                unless $ans =~ /^y/i;
            } else {
                Carp::croak(
                    qq{Lockfile '$lockfile' not writable by you. }.
                    qq{Cannot proceed.\n}.
                    qq{    On UNIX try:\n}.
                    qq{    rm '$lockfile'\n}.
                    qq{  and then rerun us.\n}
                );
            }
        } elsif ($^O eq "MSWin32") {
            $CPAN::Frontend->mywarn(
                                    qq{
There seems to be running another CPAN process according to '$lockfile'.
});
            $ask_if_degraded_wanted = 1;
        } else {
            $CPAN::Frontend->mydie(sprintf("CPAN.pm panic: Found invalid lockfile ".
                                           "'$lockfile', please remove. Cannot proceed.\n"));
        }
        if ($ask_if_degraded_wanted) {
            my($ans) =
                CPAN::Shell::colorable_makemaker_prompt
                    (qq{Shall I try to run in downgraded }.
                     qq{mode? (Y/n)},"y");
            if ($ans =~ /^y/i) {
                $CPAN::Frontend->mywarn("Running in downgraded mode (experimental).
Please report if something unexpected happens\n");
                $RUN_DEGRADED = 1;
                for ($CPAN::Config) {
                    # XXX
                    # $_->{build_dir_reuse} = 0; # 2006-11-17 akoenig Why was that?
                    $_->{commandnumber_in_prompt} = 0; # visibility
                    $_->{histfile}       = "";  # who should win otherwise?
                    $_->{cache_metadata} = 0;   # better would be a lock?
                    $_->{use_sqlite}     = 0;   # better would be a write lock!
                    $_->{auto_commit}    = 0;   # we are violent, do not persist
                    $_->{test_report}    = 0;   # Oliver Paukstadt had sent wrong reports in degraded mode
                }
            } else {
                my $msg = "You may want to kill the other job and delete the lockfile.";
                if (defined $otherpid) {
                    $msg .= " Something like:
    kill $otherpid
    rm $lockfile
";
                }
                $CPAN::Frontend->mydie("\n$msg");
            }
        }
    }
    my $dotcpan = $CPAN::Config->{cpan_home};
    eval { File::Path::mkpath($dotcpan);};
    if ($@) {
        # A special case at least for Jarkko.
        my $firsterror = $@;
        my $seconderror;
        my $symlinkcpan;
        if (-l $dotcpan) {
            $symlinkcpan = readlink $dotcpan;
            die "readlink $dotcpan failed: $!" unless defined $symlinkcpan;
            eval { File::Path::mkpath($symlinkcpan); };
            if ($@) {
                $seconderror = $@;
            } else {
                $CPAN::Frontend->mywarn(qq{
Working directory $symlinkcpan created.
});
            }
        }
        unless (-d $dotcpan) {
            my $mess = qq{
Your configuration suggests "$dotcpan" as your
CPAN.pm working directory. I could not create this directory due
to this error: $firsterror\n};
            $mess .= qq{
As "$dotcpan" is a symlink to "$symlinkcpan",
I tried to create that, but I failed with this error: $seconderror
} if $seconderror;
            $mess .= qq{
Please make sure the directory exists and is writable.
};
            $CPAN::Frontend->mywarn($mess);
            return suggest_myconfig;
        }
    } # $@ after eval mkpath $dotcpan
    if (0) { # to test what happens when a race condition occurs
        for (reverse 1..10) {
            print $_, "\n";
            sleep 1;
        }
    }
    # locking
    if (!$RUN_DEGRADED && !$self->{LOCKFH}) {
        my $fh;
        unless ($fh = FileHandle->new("+>>$lockfile")) {
            $CPAN::Frontend->mywarn(qq{

Your configuration suggests that CPAN.pm should use a working
directory of
    $CPAN::Config->{cpan_home}
Unfortunately we could not create the lock file
    $lockfile
due to '$!'.

Please make sure that the configuration variable
    \$CPAN::Config->{cpan_home}
points to a directory where you can write a .lock file. You can set
this variable in either a CPAN/MyConfig.pm or a CPAN/Config.pm in your
\@INC path;
});
            return suggest_myconfig;
        }
        my $sleep = 1;
        while (!CPAN::_flock($fh, LOCK_EX|LOCK_NB)) {
            my $err = $! || "unknown error";
            if ($sleep>3) {
                $CPAN::Frontend->mydie("Could not lock '$lockfile' with flock: $err; giving up\n");
            }
            $CPAN::Frontend->mysleep($sleep+=0.1);
            $CPAN::Frontend->mywarn("Could not lock '$lockfile' with flock: $err; retrying\n");
        }

        seek $fh, 0, 0;
        truncate $fh, 0;
        $fh->autoflush(1);
        $fh->print($$, "\n");
        $fh->print(hostname(), "\n");
        $self->{LOCK} = $lockfile;
        $self->{LOCKFH} = $fh;
    }
    $SIG{TERM} = sub {
        my $sig = shift;
        &cleanup;
        $CPAN::Frontend->mydie("Got SIG$sig, leaving");
    };
    $SIG{INT} = sub {
      # no blocks!!!
        my $sig = shift;
        &cleanup if $Signal;
        die "Got yet another signal" if $Signal > 1;
        $CPAN::Frontend->mydie("Got another SIG$sig") if $Signal;
        $CPAN::Frontend->mywarn("Caught SIG$sig, trying to continue\n");
        $Signal++;
    };

#       From: Larry Wall <larry@wall.org>
#       Subject: Re: deprecating SIGDIE
#       To: perl5-porters@perl.org
#       Date: Thu, 30 Sep 1999 14:58:40 -0700 (PDT)
#
#       The original intent of __DIE__ was only to allow you to substitute one
#       kind of death for another on an application-wide basis without respect
#       to whether you were in an eval or not.  As a global backstop, it should
#       not be used any more lightly (or any more heavily :-) than class
#       UNIVERSAL.  Any attempt to build a general exception model on it should
#       be politely squashed.  Any bug that causes every eval {} to have to be
#       modified should be not so politely squashed.
#
#       Those are my current opinions.  It is also my opinion that polite
#       arguments degenerate to personal arguments far too frequently, and that
#       when they do, it's because both people wanted it to, or at least didn't
#       sufficiently want it not to.
#
#       Larry

    # global backstop to cleanup if we should really die
    $SIG{__DIE__} = \&cleanup;
    $self->debug("Signal handler set.") if $CPAN::DEBUG;
}

#-> sub CPAN::DESTROY ;
sub DESTROY {
    &cleanup; # need an eval?
}

#-> sub CPAN::anycwd ;
sub anycwd () {
    my $getcwd;
    $getcwd = $CPAN::Config->{'getcwd'} || 'cwd';
    CPAN->$getcwd();
}

#-> sub CPAN::cwd ;
sub cwd {Cwd::cwd();}

#-> sub CPAN::getcwd ;
sub getcwd {Cwd::getcwd();}

#-> sub CPAN::fastcwd ;
sub fastcwd {Cwd::fastcwd();}

#-> sub CPAN::getdcwd ;
sub getdcwd {Cwd::getdcwd();}

#-> sub CPAN::backtickcwd ;
sub backtickcwd {my $cwd = `cwd`; chomp $cwd; $cwd}

# Adapted from Probe::Perl
#-> sub CPAN::_perl_is_same
sub _perl_is_same {
  my ($perl) = @_;
  return MM->maybe_command($perl)
    && `$perl -MConfig=myconfig -e print -e myconfig` eq Config->myconfig;
}

# Adapted in part from Probe::Perl
#-> sub CPAN::find_perl ;
sub find_perl () {
    if ( File::Spec->file_name_is_absolute($^X) ) {
        return $^X;
    }
    else {
        my $exe = $Config::Config{exe_ext};
        my @candidates = (
            File::Spec->catfile($CPAN::iCwd,$^X),
            $Config::Config{'perlpath'},
        );
        for my $perl_name ($^X, 'perl', 'perl5', "perl$]") {
            for my $path (File::Spec->path(), $Config::Config{'binexp'}) {
                if ( defined($path) && length $path && -d $path ) {
                    my $perl = File::Spec->catfile($path,$perl_name);
                    push @candidates, $perl;
                    # try with extension if not provided already
                    if ($^O eq 'VMS') {
                        # VMS might have a file version at the end
                        push @candidates, $perl . $exe
                            unless $perl =~ m/$exe(;\d+)?$/i;
                    } elsif (defined $exe && length $exe) {
                        push @candidates, $perl . $exe
                            unless $perl =~ m/$exe$/i;
                    }
                }
            }
        }
        for my $perl ( @candidates ) {
            if (MM->maybe_command($perl) && _perl_is_same($perl)) {
                $^X = $perl;
                return $perl;
            }
        }
    }
    return $^X; # default fall back
}

#-> sub CPAN::exists ;
sub exists {
    my($mgr,$class,$id) = @_;
    CPAN::HandleConfig->load unless $CPAN::Config_loaded++;
    CPAN::Index->reload;
    ### Carp::croak "exists called without class argument" unless $class;
    $id ||= "";
    $id =~ s/:+/::/g if $class eq "CPAN::Module";
    my $exists;
    if (CPAN::_sqlite_running) {
        $exists = (exists $META->{readonly}{$class}{$id} or
                   $CPAN::SQLite->set($class, $id));
    } else {
        $exists =  exists $META->{readonly}{$class}{$id};
    }
    $exists ||= exists $META->{readwrite}{$class}{$id}; # unsafe meta access, ok
}

#-> sub CPAN::delete ;
sub delete {
  my($mgr,$class,$id) = @_;
  delete $META->{readonly}{$class}{$id}; # unsafe meta access, ok
  delete $META->{readwrite}{$class}{$id}; # unsafe meta access, ok
}

#-> sub CPAN::has_usable
# has_inst is sometimes too optimistic, we should replace it with this
# has_usable whenever a case is given
sub has_usable {
    my($self,$mod,$message) = @_;
    return 1 if $HAS_USABLE->{$mod};
    my $has_inst = $self->has_inst($mod,$message);
    return unless $has_inst;
    my $usable;
    $usable = {

               #
               # most of these subroutines warn on the frontend, then
               # die if the installed version is unusable for some
               # reason; has_usable() then returns false when it caught
               # an exception, otherwise returns true and caches that;
               #
               'CPAN::Meta' => [
                            sub {
                                require CPAN::Meta;
                                unless (CPAN::Version->vge(CPAN::Meta->VERSION, 2.110350)) {
                                    for ("Will not use CPAN::Meta, need version 2.110350\n") {
                                        $CPAN::Frontend->mywarn($_);
                                        die $_;
                                    }
                                }
                            },
                           ],

               'CPAN::Meta::Requirements' => [
                            sub {
                                if (defined $CPAN::Meta::Requirements::VERSION
                                    && CPAN::Version->vlt($CPAN::Meta::Requirements::VERSION, "2.120920")
                                   ) {
                                    delete $INC{"CPAN/Meta/Requirements.pm"};
                                }
                                require CPAN::Meta::Requirements;
                                unless (CPAN::Version->vge(CPAN::Meta::Requirements->VERSION, 2.120920)) {
                                    for ("Will not use CPAN::Meta::Requirements, need version 2.120920\n") {
                                        $CPAN::Frontend->mywarn($_);
                                        die $_;
                                    }
                                }
                            },
                           ],

               'CPAN::Reporter' => [
                            sub {
                                if (defined $CPAN::Reporter::VERSION
                                    && CPAN::Version->vlt($CPAN::Reporter::VERSION, "1.2011")
                                   ) {
                                    delete $INC{"CPAN/Reporter.pm"};
                                }
                                require CPAN::Reporter;
                                unless (CPAN::Version->vge(CPAN::Reporter->VERSION, "1.2011")) {
                                    for ("Will not use CPAN::Reporter, need version 1.2011\n") {
                                        $CPAN::Frontend->mywarn($_);
                                        die $_;
                                    }
                                }
                            },
                           ],

               LWP => [ # we frequently had "Can't locate object
                        # method "new" via package "LWP::UserAgent" at
                        # (eval 69) line 2006
                       sub {require LWP},
                       sub {require LWP::UserAgent},
                       sub {require HTTP::Request},
                       sub {require URI::URL;
                            unless (CPAN::Version->vge(URI::URL::->VERSION,0.08)) {
                                for ("Will not use URI::URL, need 0.08\n") {
                                    $CPAN::Frontend->mywarn($_);
                                    die $_;
                                }
                            }
                       },
                      ],
               'Net::FTP' => [
                            sub {
                                my $var = $CPAN::Config->{ftp_proxy} || $ENV{ftp_proxy};
                                if ($var and $var =~ /^http:/i) {
                                    # rt #110833
                                    for ("Net::FTP cannot handle http proxy") {
                                        $CPAN::Frontend->mywarn($_);
                                        die $_;
                                    }
                                }
                            },
                            sub {require Net::FTP},
                            sub {require Net::Config},
                           ],
               'IO::Socket::SSL' => [
                                 sub {
                                     require IO::Socket::SSL;
                                     unless (CPAN::Version->vge(IO::Socket::SSL::->VERSION,1.56)) {
                                         for ("Will not use IO::Socket::SSL, need 1.56\n") {
                                             $CPAN::Frontend->mywarn($_);
                                             die $_;
                                         }
                                     }
                                 }
                                ],
               'Net::SSLeay' => [
                                 sub {
                                     require Net::SSLeay;
                                     unless (CPAN::Version->vge(Net::SSLeay::->VERSION,1.49)) {
                                         for ("Will not use Net::SSLeay, need 1.49\n") {
                                             $CPAN::Frontend->mywarn($_);
                                             die $_;
                                         }
                                     }
                                 }
                                ],
               'HTTP::Tiny' => [
                            sub {
                                require HTTP::Tiny;
                                unless (CPAN::Version->vge(HTTP::Tiny->VERSION, 0.005)) {
                                    for ("Will not use HTTP::Tiny, need version 0.005\n") {
                                        $CPAN::Frontend->mywarn($_);
                                        die $_;
                                    }
                                }
                            },
                           ],
               'File::HomeDir' => [
                                   sub {require File::HomeDir;
                                        unless (CPAN::Version->vge(File::HomeDir::->VERSION, 0.52)) {
                                            for ("Will not use File::HomeDir, need 0.52\n") {
                                                $CPAN::Frontend->mywarn($_);
                                                die $_;
                                            }
                                        }
                                    },
                                  ],
               'Archive::Tar' => [
                                  sub {require Archive::Tar;
                                       my $demand = "1.50";
                                       unless (CPAN::Version->vge(Archive::Tar::->VERSION, $demand)) {
                                            my $atv = Archive::Tar->VERSION;
                                            for ("You have Archive::Tar $atv, but $demand or later is recommended. Please upgrade.\n") {
                                                $CPAN::Frontend->mywarn($_);
                                            # don't die, because we may need
                                            # Archive::Tar to upgrade
                                            }

                                       }
                                  },
                                 ],
               'File::Temp' => [
                                # XXX we should probably delete from
                                # %INC too so we can load after we
                                # installed a new enough version --
                                # I'm not sure.
                                sub {require File::Temp;
                                     unless (CPAN::Version->vge(File::Temp::->VERSION,0.16)) {
                                         for ("Will not use File::Temp, need 0.16\n") {
                                                $CPAN::Frontend->mywarn($_);
                                                die $_;
                                         }
                                     }
                                },
                               ]
              };
    if ($usable->{$mod}) {
        local @INC = @INC;
        pop @INC if $INC[-1] eq '.';
        for my $c (0..$#{$usable->{$mod}}) {
            my $code = $usable->{$mod}[$c];
            my $ret = eval { &$code() };
            $ret = "" unless defined $ret;
            if ($@) {
                # warn "DEBUG: c[$c]\$\@[$@]ret[$ret]";
                return;
            }
        }
    }
    return $HAS_USABLE->{$mod} = 1;
}

sub frontend {
    shift;
    $CPAN::Frontend = shift if @_;
    $CPAN::Frontend;
}

sub use_inst {
    my ($self, $module) = @_;

    unless ($self->has_inst($module)) {
        $self->frontend->mydie("$module not installed, cannot continue");
    }
}

#-> sub CPAN::has_inst
sub has_inst {
    my($self,$mod,$message) = @_;
    Carp::croak("CPAN->has_inst() called without an argument")
        unless defined $mod;
    my %dont = map { $_ => 1 } keys %{$CPAN::META->{dontload_hash}||{}},
        keys %{$CPAN::Config->{dontload_hash}||{}},
            @{$CPAN::Config->{dontload_list}||[]};
    if (defined $message && $message eq "no"  # as far as I remember only used by Nox
        ||
        $dont{$mod}
       ) {
      $CPAN::META->{dontload_hash}{$mod}||=1; # unsafe meta access, ok
      return 0;
    }
    local @INC = @INC;
    pop @INC if $INC[-1] eq '.';
    my $file = $mod;
    my $obj;
    $file =~ s|::|/|g;
    $file .= ".pm";
    if ($INC{$file}) {
        # checking %INC is wrong, because $INC{LWP} may be true
        # although $INC{"URI/URL.pm"} may have failed. But as
        # I really want to say "blah loaded OK", I have to somehow
        # cache results.
        ### warn "$file in %INC"; #debug
        return 1;
    } elsif (eval { require $file }) {
        # eval is good: if we haven't yet read the database it's
        # perfect and if we have installed the module in the meantime,
        # it tries again. The second require is only a NOOP returning
        # 1 if we had success, otherwise it's retrying

        my $mtime = (stat $INC{$file})[9];
        # privileged files loaded by has_inst; Note: we use $mtime
        # as a proxy for a checksum.
        $CPAN::Shell::reload->{$file} = $mtime;
        my $v = eval "\$$mod\::VERSION";
        $v = $v ? " (v$v)" : "";
        CPAN::Shell->optprint("load_module","CPAN: $mod loaded ok$v\n");
        if ($mod eq "CPAN::WAIT") {
            push @CPAN::Shell::ISA, 'CPAN::WAIT';
        }
        return 1;
    } elsif ($mod eq "Net::FTP") {
        $CPAN::Frontend->mywarn(qq{
  Please, install Net::FTP as soon as possible. CPAN.pm installs it for you
  if you just type
      install Bundle::libnet

}) unless $Have_warned->{"Net::FTP"}++;
        $CPAN::Frontend->mysleep(3);
    } elsif ($mod eq "Digest::SHA") {
        if ($Have_warned->{"Digest::SHA"}++) {
            $CPAN::Frontend->mywarn(qq{CPAN: checksum security checks disabled }.
                                     qq{because Digest::SHA not installed.\n});
        } else {
            $CPAN::Frontend->mywarn(qq{
  CPAN: checksum security checks disabled because Digest::SHA not installed.
  Please consider installing the Digest::SHA module.

});
            $CPAN::Frontend->mysleep(2);
        }
    } elsif ($mod eq "Module::Signature") {
        # NOT prefs_lookup, we are not a distro
        my $check_sigs = $CPAN::Config->{check_sigs};
        if (not $check_sigs) {
            # they do not want us:-(
        } elsif (not $Have_warned->{"Module::Signature"}++) {
            # No point in complaining unless the user can
            # reasonably install and use it.
            if (eval { require Crypt::OpenPGP; 1 } ||
                (
                 defined $CPAN::Config->{'gpg'}
                 &&
                 $CPAN::Config->{'gpg'} =~ /\S/
                )
               ) {
                $CPAN::Frontend->mywarn(qq{
  CPAN: Module::Signature security checks disabled because Module::Signature
  not installed.  Please consider installing the Module::Signature module.
  You may also need to be able to connect over the Internet to the public
  key servers like pool.sks-keyservers.net or pgp.mit.edu.

});
                $CPAN::Frontend->mysleep(2);
            }
        }
    } else {
        delete $INC{$file}; # if it inc'd LWP but failed during, say, URI
    }
    return 0;
}

#-> sub CPAN::instance ;
sub instance {
    my($mgr,$class,$id) = @_;
    CPAN::Index->reload;
    $id ||= "";
    # unsafe meta access, ok?
    return $META->{readwrite}{$class}{$id} if exists $META->{readwrite}{$class}{$id};
    $META->{readwrite}{$class}{$id} ||= $class->new(ID => $id);
}

#-> sub CPAN::new ;
sub new {
    bless {}, shift;
}

#-> sub CPAN::_exit_messages ;
sub _exit_messages {
    my ($self) = @_;
    $self->{exit_messages} ||= [];
}

#-> sub CPAN::cleanup ;
sub cleanup {
  # warn "cleanup called with arg[@_] End[$CPAN::End] Signal[$Signal]";
  local $SIG{__DIE__} = '';
  my($message) = @_;
  my $i = 0;
  my $ineval = 0;
  my($subroutine);
  while ((undef,undef,undef,$subroutine) = caller(++$i)) {
      $ineval = 1, last if
        $subroutine eq '(eval)';
  }
  return if $ineval && !$CPAN::End;
  return unless defined $META->{LOCK};
  return unless -f $META->{LOCK};
  $META->savehist;
  $META->{cachemgr} ||= CPAN::CacheMgr->new('atexit');
  close $META->{LOCKFH};
  unlink $META->{LOCK};
  # require Carp;
  # Carp::cluck("DEBUGGING");
  if ( $CPAN::CONFIG_DIRTY ) {
      $CPAN::Frontend->mywarn("Warning: Configuration not saved.\n");
  }
  $CPAN::Frontend->myprint("Lockfile removed.\n");
  for my $msg ( @{ $META->_exit_messages } ) {
      $CPAN::Frontend->myprint($msg);
  }
}

#-> sub CPAN::readhist
sub readhist {
    my($self,$term,$histfile) = @_;
    my $histsize = $CPAN::Config->{'histsize'} || 100;
    $term->Attribs->{'MaxHistorySize'} = $histsize if (defined($term->Attribs->{'MaxHistorySize'}));
    my($fh) = FileHandle->new;
    open $fh, "<$histfile" or return;
    local $/ = "\n";
    while (<$fh>) {
        chomp;
        $term->AddHistory($_);
    }
    close $fh;
}

#-> sub CPAN::savehist
sub savehist {
    my($self) = @_;
    my($histfile,$histsize);
    unless ($histfile = $CPAN::Config->{'histfile'}) {
        $CPAN::Frontend->mywarn("No history written (no histfile specified).\n");
        return;
    }
    $histsize = $CPAN::Config->{'histsize'} || 100;
    if ($CPAN::term) {
        unless ($CPAN::term->can("GetHistory")) {
            $CPAN::Frontend->mywarn("Terminal does not support GetHistory.\n");
            return;
        }
    } else {
        return;
    }
    my @h = $CPAN::term->GetHistory;
    splice @h, 0, @h-$histsize if @h>$histsize;
    my($fh) = FileHandle->new;
    open $fh, ">$histfile" or $CPAN::Frontend->mydie("Couldn't open >$histfile: $!");
    local $\ = local $, = "\n";
    print $fh @h;
    close $fh;
}

#-> sub CPAN::is_tested
sub is_tested {
    my($self,$what,$when) = @_;
    unless ($what) {
        Carp::cluck("DEBUG: empty what");
        return;
    }
    $self->{is_tested}{$what} = $when;
}

#-> sub CPAN::reset_tested
# forget all distributions tested -- resets what gets included in PERL5LIB
sub reset_tested {
    my ($self) = @_;
    $self->{is_tested} = {};
}

#-> sub CPAN::is_installed
# unsets the is_tested flag: as soon as the thing is installed, it is
# not needed in set_perl5lib anymore
sub is_installed {
    my($self,$what) = @_;
    delete $self->{is_tested}{$what};
}

sub _list_sorted_descending_is_tested {
    my($self) = @_;
    my $foul = 0;
    my @sorted = sort
        { ($self->{is_tested}{$b}||0) <=> ($self->{is_tested}{$a}||0) }
            grep
                { if ($foul){ 0 } elsif (-e) { 1 } else { $foul = $_; 0 } }
                    keys %{$self->{is_tested}};
    if ($foul) {
        $CPAN::Frontend->mywarn("Lost build_dir detected ($foul), giving up all cached test results of currently running session.\n");
        for my $dbd (sort keys %{$self->{is_tested}}) { # distro-build-dir
        SEARCH: for my $d (sort { $a->id cmp $b->id } $CPAN::META->all_objects("CPAN::Distribution")) {
                if ($d->{build_dir} && $d->{build_dir} eq $dbd) {
                    $CPAN::Frontend->mywarn(sprintf "Flushing cache for %s\n", $d->pretty_id);
                    $d->fforce("");
                    last SEARCH;
                }
            }
            delete $self->{is_tested}{$dbd};
        }
        return ();
    } else {
        return @sorted;
    }
}

#-> sub CPAN::set_perl5lib
# Notes on max environment variable length:
#   - Win32 : XP or later, 8191; Win2000 or NT4, 2047
{
my $fh;
sub set_perl5lib {
    my($self,$for) = @_;
    unless ($for) {
        (undef,undef,undef,$for) = caller(1);
        $for =~ s/.*://;
    }
    $self->{is_tested} ||= {};
    return unless %{$self->{is_tested}};
    my $env = $ENV{PERL5LIB};
    $env = $ENV{PERLLIB} unless defined $env;
    my @env;
    push @env, split /\Q$Config::Config{path_sep}\E/, $env if defined $env and length $env;
    #my @dirs = map {("$_/blib/arch", "$_/blib/lib")} keys %{$self->{is_tested}};
    #$CPAN::Frontend->myprint("Prepending @dirs to PERL5LIB.\n");

    my @dirs = map {("$_/blib/arch", "$_/blib/lib")} $self->_list_sorted_descending_is_tested;
    return if !@dirs;

    if (@dirs < 12) {
        $CPAN::Frontend->optprint('perl5lib', "Prepending @dirs to PERL5LIB for '$for'\n");
        $ENV{PERL5LIB} = join $Config::Config{path_sep}, @dirs, @env;
    } elsif (@dirs < 24 ) {
        my @d = map {my $cp = $_;
                     $cp =~ s/^\Q$CPAN::Config->{build_dir}\E/%BUILDDIR%/;
                     $cp
                 } @dirs;
        $CPAN::Frontend->optprint('perl5lib', "Prepending @d to PERL5LIB; ".
                                 "%BUILDDIR%=$CPAN::Config->{build_dir} ".
                                 "for '$for'\n"
                                );
        $ENV{PERL5LIB} = join $Config::Config{path_sep}, @dirs, @env;
    } else {
        my $cnt = keys %{$self->{is_tested}};
        my $newenv = join $Config::Config{path_sep}, @dirs, @env;
        $CPAN::Frontend->optprint('perl5lib', sprintf ("Prepending blib/arch and blib/lib of ".
                                 "%d build dirs to PERL5LIB, reaching size %d; ".
                                 "for '%s'\n", $cnt, length($newenv), $for)
                                );
        $ENV{PERL5LIB} = $newenv;
    }
}}


1;


__END__

=head1 NAME

CPAN - query, download and build perl modules from CPAN sites

=head1 SYNOPSIS

Interactive mode:

  perl -MCPAN -e shell

--or--

  cpan

Basic commands:

  # Modules:

  cpan> install Acme::Meta                       # in the shell

  CPAN::Shell->install("Acme::Meta");            # in perl

  # Distributions:

  cpan> install NWCLARK/Acme-Meta-0.02.tar.gz    # in the shell

  CPAN::Shell->
    install("NWCLARK/Acme-Meta-0.02.tar.gz");    # in perl

  # module objects:

  $mo = CPAN::Shell->expandany($mod);
  $mo = CPAN::Shell->expand("Module",$mod);      # same thing

  # distribution objects:

  $do = CPAN::Shell->expand("Module",$mod)->distribution;
  $do = CPAN::Shell->expandany($distro);         # same thing
  $do = CPAN::Shell->expand("Distribution",
                            $distro);            # same thing

=head1 DESCRIPTION

The CPAN module automates or at least simplifies the make and install
of perl modules and extensions. It includes some primitive searching
capabilities and knows how to use LWP, HTTP::Tiny, Net::FTP and certain
external download clients to fetch distributions from the net.

These are fetched from one or more mirrored CPAN (Comprehensive
Perl Archive Network) sites and unpacked in a dedicated directory.

The CPAN module also supports named and versioned
I<bundles> of modules. Bundles simplify handling of sets of
related modules. See Bundles below.

The package contains a session manager and a cache manager. The
session manager keeps track of what has been fetched, built, and
installed in the current session. The cache manager keeps track of the
disk space occupied by the make processes and deletes excess space
using a simple FIFO mechanism.

All methods provided are accessible in a programmer style and in an
interactive shell style.

=head2 CPAN::shell([$prompt, $command]) Starting Interactive Mode

Enter interactive mode by running

    perl -MCPAN -e shell

or

    cpan

which puts you into a readline interface. If C<Term::ReadKey> and
either of C<Term::ReadLine::Perl> or C<Term::ReadLine::Gnu> are installed,
history and command completion are supported.

Once at the command line, type C<h> for one-page help
screen; the rest should be self-explanatory.

The function call C<shell> takes two optional arguments: one the
prompt, the second the default initial command line (the latter
only works if a real ReadLine interface module is installed).

The most common uses of the interactive modes are

=over 2

=item Searching for authors, bundles, distribution files and modules

There are corresponding one-letter commands C<a>, C<b>, C<d>, and C<m>
for each of the four categories and another, C<i> for any of the
mentioned four. Each of the four entities is implemented as a class
with slightly differing methods for displaying an object.

Arguments to these commands are either strings exactly matching
the identification string of an object, or regular expressions
matched case-insensitively against various attributes of the
objects. The parser only recognizes a regular expression when you
enclose it with slashes.

The principle is that the number of objects found influences how an
item is displayed. If the search finds one item, the result is
displayed with the rather verbose method C<as_string>, but if
more than one is found, each object is displayed with the terse method
C<as_glimpse>.

Examples:

  cpan> m Acme::MetaSyntactic
  Module id = Acme::MetaSyntactic
      CPAN_USERID  BOOK (Philippe Bruhat (BooK) <[...]>)
      CPAN_VERSION 0.99
      CPAN_FILE    B/BO/BOOK/Acme-MetaSyntactic-0.99.tar.gz
      UPLOAD_DATE  2006-11-06
      MANPAGE      Acme::MetaSyntactic - Themed metasyntactic variables names
      INST_FILE    /usr/local/lib/perl/5.10.0/Acme/MetaSyntactic.pm
      INST_VERSION 0.99
  cpan> a BOOK
  Author id = BOOK
      EMAIL        [...]
      FULLNAME     Philippe Bruhat (BooK)
  cpan> d BOOK/Acme-MetaSyntactic-0.99.tar.gz
  Distribution id = B/BO/BOOK/Acme-MetaSyntactic-0.99.tar.gz
      CPAN_USERID  BOOK (Philippe Bruhat (BooK) <[...]>)
      CONTAINSMODS Acme::MetaSyntactic Acme::MetaSyntactic::Alias [...]
      UPLOAD_DATE  2006-11-06
  cpan> m /lorem/
  Module  = Acme::MetaSyntactic::loremipsum (BOOK/Acme-MetaSyntactic-0.99.tar.gz)
  Module    Text::Lorem            (ADEOLA/Text-Lorem-0.3.tar.gz)
  Module    Text::Lorem::More      (RKRIMEN/Text-Lorem-More-0.12.tar.gz)
  Module    Text::Lorem::More::Source (RKRIMEN/Text-Lorem-More-0.12.tar.gz)
  cpan> i /berlin/
  Distribution    BEATNIK/Filter-NumberLines-0.02.tar.gz
  Module  = DateTime::TimeZone::Europe::Berlin (DROLSKY/DateTime-TimeZone-0.7904.tar.gz)
  Module    Filter::NumberLines    (BEATNIK/Filter-NumberLines-0.02.tar.gz)
  Author          [...]

The examples illustrate several aspects: the first three queries
target modules, authors, or distros directly and yield exactly one
result. The last two use regular expressions and yield several
results. The last one targets all of bundles, modules, authors, and
distros simultaneously. When more than one result is available, they
are printed in one-line format.

=item C<get>, C<make>, C<test>, C<install>, C<clean> modules or distributions

These commands take any number of arguments and investigate what is
necessary to perform the action. Argument processing is as follows:

  known module name in format Foo/Bar.pm   module
  other embedded slash                     distribution
    - with trailing slash dot              directory
  enclosing slashes                        regexp
  known module name in format Foo::Bar     module

If the argument is a distribution file name (recognized by embedded
slashes), it is processed. If it is a module, CPAN determines the
distribution file in which this module is included and processes that,
following any dependencies named in the module's META.yml or
Makefile.PL (this behavior is controlled by the configuration
parameter C<prerequisites_policy>). If an argument is enclosed in
slashes it is treated as a regular expression: it is expanded and if
the result is a single object (distribution, bundle or module), this
object is processed.

Example:

    install Dummy::Perl                   # installs the module
    install AUXXX/Dummy-Perl-3.14.tar.gz  # installs that distribution
    install /Dummy-Perl-3.14/             # same if the regexp is unambiguous

C<get> downloads a distribution file and untars or unzips it, C<make>
builds it, C<test> runs the test suite, and C<install> installs it.

Any C<make> or C<test> is run unconditionally. An

  install <distribution_file>

is also run unconditionally. But for

  install <module>

CPAN checks whether an install is needed and prints
I<module up to date> if the distribution file containing
the module doesn't need updating.

CPAN also keeps track of what it has done within the current session
and doesn't try to build a package a second time regardless of whether it
succeeded or not. It does not repeat a test run if the test
has been run successfully before. Same for install runs.

The C<force> pragma may precede another command (currently: C<get>,
C<make>, C<test>, or C<install>) to execute the command from scratch
and attempt to continue past certain errors. See the section below on
the C<force> and the C<fforce> pragma.

The C<notest> pragma skips the test part in the build
process.

Example:

    cpan> notest install Tk

A C<clean> command results in a

  make clean

being executed within the distribution file's working directory.

=item C<readme>, C<perldoc>, C<look> module or distribution

C<readme> displays the README file of the associated distribution.
C<Look> gets and untars (if not yet done) the distribution file,
changes to the appropriate directory and opens a subshell process in
that directory. C<perldoc> displays the module's pod documentation
in html or plain text format.

=item C<ls> author

=item C<ls> globbing_expression

The first form lists all distribution files in and below an author's
CPAN directory as stored in the CHECKSUMS files distributed on
CPAN. The listing recurses into subdirectories.

The second form limits or expands the output with shell
globbing as in the following examples:

      ls JV/make*
      ls GSAR/*make*
      ls */*make*

The last example is very slow and outputs extra progress indicators
that break the alignment of the result.

Note that globbing only lists directories explicitly asked for, for
example FOO/* will not list FOO/bar/Acme-Sthg-n.nn.tar.gz. This may be
regarded as a bug that may be changed in some future version.

=item C<failed>

The C<failed> command reports all distributions that failed on one of
C<make>, C<test> or C<install> for some reason in the currently
running shell session.

=item Persistence between sessions

If the C<YAML> or the C<YAML::Syck> module is installed a record of
the internal state of all modules is written to disk after each step.
The files contain a signature of the currently running perl version
for later perusal.

If the configurations variable C<build_dir_reuse> is set to a true
value, then CPAN.pm reads the collected YAML files. If the stored
signature matches the currently running perl, the stored state is
loaded into memory such that persistence between sessions
is effectively established.

=item The C<force> and the C<fforce> pragma

To speed things up in complex installation scenarios, CPAN.pm keeps
track of what it has already done and refuses to do some things a
second time. A C<get>, a C<make>, and an C<install> are not repeated.
A C<test> is repeated only if the previous test was unsuccessful. The
diagnostic message when CPAN.pm refuses to do something a second time
is one of I<Has already been >C<unwrapped|made|tested successfully> or
something similar. Another situation where CPAN refuses to act is an
C<install> if the corresponding C<test> was not successful.

In all these cases, the user can override this stubborn behaviour by
prepending the command with the word force, for example:

  cpan> force get Foo
  cpan> force make AUTHOR/Bar-3.14.tar.gz
  cpan> force test Baz
  cpan> force install Acme::Meta

Each I<forced> command is executed with the corresponding part of its
memory erased.

The C<fforce> pragma is a variant that emulates a C<force get> which
erases the entire memory followed by the action specified, effectively
restarting the whole get/make/test/install procedure from scratch.

=item Lockfile

Interactive sessions maintain a lockfile, by default C<~/.cpan/.lock>.
Batch jobs can run without a lockfile and not disturb each other.

The shell offers to run in I<downgraded mode> when another process is
holding the lockfile. This is an experimental feature that is not yet
tested very well. This second shell then does not write the history
file, does not use the metadata file, and has a different prompt.

=item Signals

CPAN.pm installs signal handlers for SIGINT and SIGTERM. While you are
in the cpan-shell, it is intended that you can press C<^C> anytime and
return to the cpan-shell prompt. A SIGTERM will cause the cpan-shell
to clean up and leave the shell loop. You can emulate the effect of a
SIGTERM by sending two consecutive SIGINTs, which usually means by
pressing C<^C> twice.

CPAN.pm ignores SIGPIPE. If the user sets C<inactivity_timeout>, a
SIGALRM is used during the run of the C<perl Makefile.PL> or C<perl
Build.PL> subprocess. A SIGALRM is also used during module version
parsing, and is controlled by C<version_timeout>.

=back

=head2 CPAN::Shell

The commands available in the shell interface are methods in
the package CPAN::Shell. If you enter the shell command, your
input is split by the Text::ParseWords::shellwords() routine, which
acts like most shells do. The first word is interpreted as the
method to be invoked, and the rest of the words are treated as the method's arguments.
Continuation lines are supported by ending a line with a
literal backslash.

=head2 autobundle

C<autobundle> writes a bundle file into the
C<$CPAN::Config-E<gt>{cpan_home}/Bundle> directory. The file contains
a list of all modules that are both available from CPAN and currently
installed within @INC. Duplicates of each distribution are suppressed.
The name of the bundle file is based on the current date and a
counter, e.g. F<Bundle/Snapshot_2012_05_21_00.pm>. This is installed
again by running C<cpan Bundle::Snapshot_2012_05_21_00>, or installing
C<Bundle::Snapshot_2012_05_21_00> from the CPAN shell.

Return value: path to the written file.

=head2 hosts

Note: this feature is still in alpha state and may change in future
versions of CPAN.pm

This commands provides a statistical overview over recent download
activities. The data for this is collected in the YAML file
C<FTPstats.yml> in your C<cpan_home> directory. If no YAML module is
configured or YAML not installed, or if C<ftpstats_size> is set to a
value C<< <=0 >>, no stats are provided.

=head2 install_tested

Install all distributions that have been tested successfully but have
not yet been installed. See also C<is_tested>.

=head2 is_tested

List all build directories of distributions that have been tested
successfully but have not yet been installed. See also
C<install_tested>.

=head2 mkmyconfig

mkmyconfig() writes your own CPAN::MyConfig file into your C<~/.cpan/>
directory so that you can save your own preferences instead of the
system-wide ones.

=head2 r [Module|/Regexp/]...

scans current perl installation for modules that have a newer version
available on CPAN and provides a list of them. If called without
argument, all potential upgrades are listed; if called with arguments
the list is filtered to the modules and regexps given as arguments.

The listing looks something like this:

  Package namespace         installed    latest  in CPAN file
  CPAN                        1.94_64    1.9600  ANDK/CPAN-1.9600.tar.gz
  CPAN::Reporter               1.1801    1.1902  DAGOLDEN/CPAN-Reporter-1.1902.tar.gz
  YAML                           0.70      0.73  INGY/YAML-0.73.tar.gz
  YAML::Syck                     1.14      1.17  AVAR/YAML-Syck-1.17.tar.gz
  YAML::Tiny                     1.44      1.50  ADAMK/YAML-Tiny-1.50.tar.gz
  CGI                            3.43      3.55  MARKSTOS/CGI.pm-3.55.tar.gz
  Module::Build::YAML            1.40      1.41  DAGOLDEN/Module-Build-0.3800.tar.gz
  TAP::Parser::Result::YAML      3.22      3.23  ANDYA/Test-Harness-3.23.tar.gz
  YAML::XS                       0.34      0.35  INGY/YAML-LibYAML-0.35.tar.gz

It suppresses duplicates in the column C<in CPAN file> such that
distributions with many upgradeable modules are listed only once.

Note that the list is not sorted.

=head2 recent ***EXPERIMENTAL COMMAND***

The C<recent> command downloads a list of recent uploads to CPAN and
displays them I<slowly>. While the command is running, a $SIG{INT}
exits the loop after displaying the current item.

B<Note>: This command requires XML::LibXML installed.

B<Note>: This whole command currently is just a hack and will
probably change in future versions of CPAN.pm, but the general
approach will likely remain.

B<Note>: See also L<smoke>

=head2 recompile

recompile() is a special command that takes no argument and
runs the make/test/install cycle with brute force over all installed
dynamically loadable extensions (a.k.a. XS modules) with 'force' in
effect. The primary purpose of this command is to finish a network
installation. Imagine you have a common source tree for two different
architectures. You decide to do a completely independent fresh
installation. You start on one architecture with the help of a Bundle
file produced earlier. CPAN installs the whole Bundle for you, but
when you try to repeat the job on the second architecture, CPAN
responds with a C<"Foo up to date"> message for all modules. So you
invoke CPAN's recompile on the second architecture and you're done.

Another popular use for C<recompile> is to act as a rescue in case your
perl breaks binary compatibility. If one of the modules that CPAN uses
is in turn depending on binary compatibility (so you cannot run CPAN
commands), then you should try the CPAN::Nox module for recovery.

=head2 report Bundle|Distribution|Module

The C<report> command temporarily turns on the C<test_report> config
variable, then runs the C<force test> command with the given
arguments. The C<force> pragma reruns the tests and repeats
every step that might have failed before.

=head2 smoke ***EXPERIMENTAL COMMAND***

B<*** WARNING: this command downloads and executes software from CPAN to
your computer of completely unknown status. You should never do
this with your normal account and better have a dedicated well
separated and secured machine to do this. ***>

The C<smoke> command takes the list of recent uploads to CPAN as
provided by the C<recent> command and tests them all. While the
command is running $SIG{INT} is defined to mean that the current item
shall be skipped.

B<Note>: This whole command currently is just a hack and will
probably change in future versions of CPAN.pm, but the general
approach will likely remain.

B<Note>: See also L<recent>

=head2 upgrade [Module|/Regexp/]...

The C<upgrade> command first runs an C<r> command with the given
arguments and then installs the newest versions of all modules that
were listed by that.

=head2 The four C<CPAN::*> Classes: Author, Bundle, Module, Distribution

Although it may be considered internal, the class hierarchy does matter
for both users and programmer. CPAN.pm deals with the four
classes mentioned above, and those classes all share a set of methods. Classical
single polymorphism is in effect. A metaclass object registers all
objects of all kinds and indexes them with a string. The strings
referencing objects have a separated namespace (well, not completely
separated):

         Namespace                         Class

   words containing a "/" (slash)      Distribution
    words starting with Bundle::          Bundle
          everything else            Module or Author

Modules know their associated Distribution objects. They always refer
to the most recent official release. Developers may mark their releases
as unstable development versions (by inserting an underscore into the
module version number which will also be reflected in the distribution
name when you run 'make dist'), so the really hottest and newest
distribution is not always the default.  If a module Foo circulates
on CPAN in both version 1.23 and 1.23_90, CPAN.pm offers a convenient
way to install version 1.23 by saying

    install Foo

This would install the complete distribution file (say
BAR/Foo-1.23.tar.gz) with all accompanying material. But if you would
like to install version 1.23_90, you need to know where the
distribution file resides on CPAN relative to the authors/id/
directory. If the author is BAR, this might be BAR/Foo-1.23_90.tar.gz;
so you would have to say

    install BAR/Foo-1.23_90.tar.gz

The first example will be driven by an object of the class
CPAN::Module, the second by an object of class CPAN::Distribution.

=head2 Integrating local directories

Note: this feature is still in alpha state and may change in future
versions of CPAN.pm

Distribution objects are normally distributions from the CPAN, but
there is a slightly degenerate case for Distribution objects, too, of
projects held on the local disk. These distribution objects have the
same name as the local directory and end with a dot. A dot by itself
is also allowed for the current directory at the time CPAN.pm was
used. All actions such as C<make>, C<test>, and C<install> are applied
directly to that directory. This gives the command C<cpan .> an
interesting touch: while the normal mantra of installing a CPAN module
without CPAN.pm is one of

    perl Makefile.PL                 perl Build.PL
           ( go and get prerequisites )
    make                             ./Build
    make test                        ./Build test
    make install                     ./Build install

the command C<cpan .> does all of this at once. It figures out which
of the two mantras is appropriate, fetches and installs all
prerequisites, takes care of them recursively, and finally finishes the
installation of the module in the current directory, be it a CPAN
module or not.

The typical usage case is for private modules or working copies of
projects from remote repositories on the local disk.

=head2 Redirection

The usual shell redirection symbols C< | > and C<< > >> are recognized
by the cpan shell B<only when surrounded by whitespace>. So piping to
pager or redirecting output into a file works somewhat as in a normal
shell, with the stipulation that you must type extra spaces.

=head2 Plugin support ***EXPERIMENTAL***

Plugins are objects that implement any of currently eight methods:

  pre_get
  post_get
  pre_make
  post_make
  pre_test
  post_test
  pre_install
  post_install

The C<plugin_list> configuration parameter holds a list of strings of
the form

  Modulename=arg0,arg1,arg2,arg3,...

eg:

  CPAN::Plugin::Flurb=dir,/opt/pkgs/flurb/raw,verbose,1

At run time, each listed plugin is instantiated as a singleton object
by running the equivalent of this pseudo code:

  my $plugin = <string representation from config>;
  <generate Modulename and arguments from $plugin>;
  my $p = $instance{$plugin} ||= Modulename->new($arg0,$arg1,...);

The generated singletons are kept around from instantiation until the
end of the shell session. <plugin_list> can be reconfigured at any
time at run time. While the cpan shell is running, it checks all
activated plugins at each of the 8 reference points listed above and
runs the respective method if it is implemented for that object. The
method is called with the active CPAN::Distribution object passed in
as an argument.

=head1 CONFIGURATION

When the CPAN module is used for the first time, a configuration
dialogue tries to determine a couple of site specific options. The
result of the dialog is stored in a hash reference C< $CPAN::Config >
in a file CPAN/Config.pm.

Default values defined in the CPAN/Config.pm file can be
overridden in a user specific file: CPAN/MyConfig.pm. Such a file is
best placed in C<$HOME/.cpan/CPAN/MyConfig.pm>, because C<$HOME/.cpan> is
added to the search path of the CPAN module before the use() or
require() statements. The mkmyconfig command writes this file for you.

If you want to keep your own CPAN/MyConfig.pm somewhere else, you
should load it before loading CPAN.pm, e.g.:

  perl -I/tmp/somewhere -MCPAN::MyConfig -MCPAN -eshell

  --or--

 perl -I/tmp/somewhere -MCPAN::MyConfig -S cpan

Once you are in the shell you can change your configuration as follows.

The C<o conf> command has various bells and whistles:

=over

=item completion support

If you have a ReadLine module installed, you can hit TAB at any point
of the commandline and C<o conf> will offer you completion for the
built-in subcommands and/or config variable names.

=item displaying some help: o conf help

Displays a short help

=item displaying current values: o conf [KEY]

Displays the current value(s) for this config variable. Without KEY,
displays all subcommands and config variables.

Example:

  o conf shell

If KEY starts and ends with a slash, the string in between is
treated as a regular expression and only keys matching this regexp
are displayed

Example:

  o conf /color/

=item changing of scalar values: o conf KEY VALUE

Sets the config variable KEY to VALUE. The empty string can be
specified as usual in shells, with C<''> or C<"">

Example:

  o conf wget /usr/bin/wget

=item changing of list values: o conf KEY SHIFT|UNSHIFT|PUSH|POP|SPLICE|LIST

If a config variable name ends with C<list>, it is a list. C<o conf
KEY shift> removes the first element of the list, C<o conf KEY pop>
removes the last element of the list. C<o conf KEYS unshift LIST>
prepends a list of values to the list, C<o conf KEYS push LIST>
appends a list of valued to the list.

Likewise, C<o conf KEY splice LIST> passes the LIST to the corresponding
splice command.

Finally, any other list of arguments is taken as a new list value for
the KEY variable discarding the previous value.

Examples:

  o conf urllist unshift http://cpan.dev.local/CPAN
  o conf urllist splice 3 1
  o conf urllist http://cpan1.local http://cpan2.local ftp://ftp.perl.org

=item reverting to saved: o conf defaults

Reverts all config variables to the state in the saved config file.

=item saving the config: o conf commit

Saves all config variables to the current config file (CPAN/Config.pm
or CPAN/MyConfig.pm that was loaded at start).

=back

The configuration dialog can be started any time later again by
issuing the command C< o conf init > in the CPAN shell. A subset of
the configuration dialog can be run by issuing C<o conf init WORD>
where WORD is any valid config variable or a regular expression.

=head2 Config Variables

The following keys in the hash reference $CPAN::Config are
currently defined:

  allow_installing_module_downgrades
                     allow or disallow installing module downgrades
  allow_installing_outdated_dists
                     allow or disallow installing modules that are
                     indexed in the cpan index pointing to a distro
                     with a higher distro-version number
  applypatch         path to external prg
  auto_commit        commit all changes to config variables to disk
  build_cache        size of cache for directories to build modules
  build_dir          locally accessible directory to build modules
  build_dir_reuse    boolean if distros in build_dir are persistent
  build_requires_install_policy
                     to install or not to install when a module is
                     only needed for building. yes|no|ask/yes|ask/no
  bzip2              path to external prg
  cache_metadata     use serializer to cache metadata
  check_sigs         if signatures should be verified
  cleanup_after_install
                     remove build directory immediately after a
                     successful install and remember that for the
                     duration of the session
  colorize_debug     Term::ANSIColor attributes for debugging output
  colorize_output    boolean if Term::ANSIColor should colorize output
  colorize_print     Term::ANSIColor attributes for normal output
  colorize_warn      Term::ANSIColor attributes for warnings
  commandnumber_in_prompt
                     boolean if you want to see current command number
  commands_quote     preferred character to use for quoting external
                     commands when running them. Defaults to double
                     quote on Windows, single tick everywhere else;
                     can be set to space to disable quoting
  connect_to_internet_ok
                     whether to ask if opening a connection is ok before
                     urllist is specified
  cpan_home          local directory reserved for this package
  curl               path to external prg
  dontload_hash      DEPRECATED
  dontload_list      arrayref: modules in the list will not be
                     loaded by the CPAN::has_inst() routine
  ftp                path to external prg
  ftp_passive        if set, the environment variable FTP_PASSIVE is set
                     for downloads
  ftp_proxy          proxy host for ftp requests
  ftpstats_period    max number of days to keep download statistics
  ftpstats_size      max number of items to keep in the download statistics
  getcwd             see below
  gpg                path to external prg
  gzip               location of external program gzip
  halt_on_failure    stop processing after the first failure of queued
                     items or dependencies
  histfile           file to maintain history between sessions
  histsize           maximum number of lines to keep in histfile
  http_proxy         proxy host for http requests
  inactivity_timeout breaks interactive Makefile.PLs or Build.PLs
                     after this many seconds inactivity. Set to 0 to
                     disable timeouts.
  index_expire       refetch index files after this many days
  inhibit_startup_message
                     if true, suppress the startup message
  keep_source_where  directory in which to keep the source (if we do)
  load_module_verbosity
                     report loading of optional modules used by CPAN.pm
  lynx               path to external prg
  make               location of external make program
  make_arg           arguments that should always be passed to 'make'
  make_install_make_command
                     the make command for running 'make install', for
                     example 'sudo make'
  make_install_arg   same as make_arg for 'make install'
  makepl_arg         arguments passed to 'perl Makefile.PL'
  mbuild_arg         arguments passed to './Build'
  mbuild_install_arg arguments passed to './Build install'
  mbuild_install_build_command
                     command to use instead of './Build' when we are
                     in the install stage, for example 'sudo ./Build'
  mbuildpl_arg       arguments passed to 'perl Build.PL'
  ncftp              path to external prg
  ncftpget           path to external prg
  no_proxy           don't proxy to these hosts/domains (comma separated list)
  pager              location of external program more (or any pager)
  password           your password if you CPAN server wants one
  patch              path to external prg
  patches_dir        local directory containing patch files
  perl5lib_verbosity verbosity level for PERL5LIB additions
  plugin_list        list of active hooks (see Plugin support above
                     and the CPAN::Plugin module)
  prefer_external_tar
                     per default all untar operations are done with
                     Archive::Tar; by setting this variable to true
                     the external tar command is used if available
  prefer_installer   legal values are MB and EUMM: if a module comes
                     with both a Makefile.PL and a Build.PL, use the
                     former (EUMM) or the latter (MB); if the module
                     comes with only one of the two, that one will be
                     used no matter the setting
  prerequisites_policy
                     what to do if you are missing module prerequisites
                     ('follow' automatically, 'ask' me, or 'ignore')
                     For 'follow', also sets PERL_AUTOINSTALL and
                     PERL_EXTUTILS_AUTOINSTALL for "--defaultdeps" if
                     not already set
  prefs_dir          local directory to store per-distro build options
  proxy_user         username for accessing an authenticating proxy
  proxy_pass         password for accessing an authenticating proxy
  pushy_https        use https to cpan.org when possible, otherwise use http
                     to cpan.org and issue a warning
  randomize_urllist  add some randomness to the sequence of the urllist
  recommends_policy  whether recommended prerequisites should be included
  scan_cache         controls scanning of cache ('atstart', 'atexit' or 'never')
  shell              your favorite shell
  show_unparsable_versions
                     boolean if r command tells which modules are versionless
  show_upload_date   boolean if commands should try to determine upload date
  show_zero_versions boolean if r command tells for which modules $version==0
  suggests_policy    whether suggested prerequisites should be included
  tar                location of external program tar
  tar_verbosity      verbosity level for the tar command
  term_is_latin      deprecated: if true Unicode is translated to ISO-8859-1
                     (and nonsense for characters outside latin range)
  term_ornaments     boolean to turn ReadLine ornamenting on/off
  test_report        email test reports (if CPAN::Reporter is installed)
  trust_test_report_history
                     skip testing when previously tested ok (according to
                     CPAN::Reporter history)
  unzip              location of external program unzip
  urllist            arrayref to nearby CPAN sites (or equivalent locations)
  urllist_ping_external
                     use external ping command when autoselecting mirrors
  urllist_ping_verbose
                     increase verbosity when autoselecting mirrors
  use_prompt_default set PERL_MM_USE_DEFAULT for configure/make/test/install
  use_sqlite         use CPAN::SQLite for metadata storage (fast and lean)
  username           your username if you CPAN server wants one
  version_timeout    stops version parsing after this many seconds.
                     Default is 15 secs. Set to 0 to disable.
  wait_list          arrayref to a wait server to try (See CPAN::WAIT)
  wget               path to external prg
  yaml_load_code     enable YAML code deserialisation via CPAN::DeferredCode
  yaml_module        which module to use to read/write YAML files

You can set and query each of these options interactively in the cpan
shell with the C<o conf> or the C<o conf init> command as specified below.

=over 2

=item C<o conf E<lt>scalar optionE<gt>>

prints the current value of the I<scalar option>

=item C<o conf E<lt>scalar optionE<gt> E<lt>valueE<gt>>

Sets the value of the I<scalar option> to I<value>

=item C<o conf E<lt>list optionE<gt>>

prints the current value of the I<list option> in MakeMaker's
neatvalue format.

=item C<o conf E<lt>list optionE<gt> [shift|pop]>

shifts or pops the array in the I<list option> variable

=item C<o conf E<lt>list optionE<gt> [unshift|push|splice] E<lt>listE<gt>>

works like the corresponding perl commands.

=item interactive editing: o conf init [MATCH|LIST]

Runs an interactive configuration dialog for matching variables.
Without argument runs the dialog over all supported config variables.
To specify a MATCH the argument must be enclosed by slashes.

Examples:

  o conf init ftp_passive ftp_proxy
  o conf init /color/

Note: this method of setting config variables often provides more
explanation about the functioning of a variable than the manpage.

=back

=head2 CPAN::anycwd($path): Note on config variable getcwd

CPAN.pm changes the current working directory often and needs to
determine its own current working directory. By default it uses
Cwd::cwd, but if for some reason this doesn't work on your system,
configure alternatives according to the following table:

=over 4

=item cwd

Calls Cwd::cwd

=item getcwd

Calls Cwd::getcwd

=item fastcwd

Calls Cwd::fastcwd

=item getdcwd

Calls Cwd::getdcwd

=item backtickcwd

Calls the external command cwd.

=back

=head2 Note on the format of the urllist parameter

urllist parameters are URLs according to RFC 1738. We do a little
guessing if your URL is not compliant, but if you have problems with
C<file> URLs, please try the correct format. Either:

    file://localhost/whatever/ftp/pub/CPAN/

or

    file:///home/ftp/pub/CPAN/

=head2 The urllist parameter has CD-ROM support

The C<urllist> parameter of the configuration table contains a list of
URLs used for downloading. If the list contains any
C<file> URLs, CPAN always tries there first. This
feature is disabled for index files. So the recommendation for the
owner of a CD-ROM with CPAN contents is: include your local, possibly
outdated CD-ROM as a C<file> URL at the end of urllist, e.g.

  o conf urllist push file://localhost/CDROM/CPAN

CPAN.pm will then fetch the index files from one of the CPAN sites
that come at the beginning of urllist. It will later check for each
module to see whether there is a local copy of the most recent version.

Another peculiarity of urllist is that the site that we could
successfully fetch the last file from automatically gets a preference
token and is tried as the first site for the next request. So if you
add a new site at runtime it may happen that the previously preferred
site will be tried another time. This means that if you want to disallow
a site for the next transfer, it must be explicitly removed from
urllist.

=head2 Maintaining the urllist parameter

If you have YAML.pm (or some other YAML module configured in
C<yaml_module>) installed, CPAN.pm collects a few statistical data
about recent downloads. You can view the statistics with the C<hosts>
command or inspect them directly by looking into the C<FTPstats.yml>
file in your C<cpan_home> directory.

To get some interesting statistics, it is recommended that
C<randomize_urllist> be set; this introduces some amount of
randomness into the URL selection.

=head2 The C<requires> and C<build_requires> dependency declarations

Since CPAN.pm version 1.88_51 modules declared as C<build_requires> by
a distribution are treated differently depending on the config
variable C<build_requires_install_policy>. By setting
C<build_requires_install_policy> to C<no>, such a module is not
installed. It is only built and tested, and then kept in the list of
tested but uninstalled modules. As such, it is available during the
build of the dependent module by integrating the path to the
C<blib/arch> and C<blib/lib> directories in the environment variable
PERL5LIB. If C<build_requires_install_policy> is set to C<yes>, then
both modules declared as C<requires> and those declared as
C<build_requires> are treated alike. By setting to C<ask/yes> or
C<ask/no>, CPAN.pm asks the user and sets the default accordingly.

=head2 Configuration of the allow_installing_* parameters

The C<allow_installing_*> parameters are evaluated during
the C<make> phase. If set to C<yes>, they allow the testing and the installation of
the current distro and otherwise have no effect. If set to C<no>, they
may abort the build (preventing testing and installing), depending on the contents of the
C<blib/> directory. The C<blib/> directory is the directory that holds
all the files that would usually be installed in the C<install> phase.

C<allow_installing_outdated_dists> compares the C<blib/> directory with the CPAN index.
If it finds something there that belongs, according to the index, to a different
dist, it aborts the current build.

C<allow_installing_module_downgrades> compares the C<blib/> directory
with already installed modules, actually their version numbers, as
determined by ExtUtils::MakeMaker or equivalent. If a to-be-installed
module would downgrade an already installed module, the current build
is aborted.

An interesting twist occurs when a distroprefs document demands the
installation of an outdated dist via goto while
C<allow_installing_outdated_dists> forbids it. Without additional
provisions, this would let the C<allow_installing_outdated_dists>
win and the distroprefs lose. So the proper arrangement in such a case
is to write a second distroprefs document for the distro that C<goto>
points to and overrule the C<cpanconfig> there. E.g.:

  ---
  match:
    distribution: "^MAUKE/Keyword-Simple-0.04.tar.gz"
  goto: "MAUKE/Keyword-Simple-0.03.tar.gz"
  ---
  match:
    distribution: "^MAUKE/Keyword-Simple-0.03.tar.gz"
  cpanconfig:
    allow_installing_outdated_dists: yes

=head2 Configuration for individual distributions (I<Distroprefs>)

(B<Note:> This feature has been introduced in CPAN.pm 1.8854)

Distributions on CPAN usually behave according to what we call the
CPAN mantra. Or since the advent of Module::Build we should talk about
two mantras:

    perl Makefile.PL     perl Build.PL
    make                 ./Build
    make test            ./Build test
    make install         ./Build install

But some modules cannot be built with this mantra. They try to get
some extra data from the user via the environment, extra arguments, or
interactively--thus disturbing the installation of large bundles like
Phalanx100 or modules with many dependencies like Plagger.

The distroprefs system of C<CPAN.pm> addresses this problem by
allowing the user to specify extra informations and recipes in YAML
files to either

=over

=item

pass additional arguments to one of the four commands,

=item

set environment variables

=item

instantiate an Expect object that reads from the console, waits for
some regular expressions and enters some answers

=item

temporarily override assorted C<CPAN.pm> configuration variables

=item

specify dependencies the original maintainer forgot

=item

disable the installation of an object altogether

=back

See the YAML and Data::Dumper files that come with the C<CPAN.pm>
distribution in the C<distroprefs/> directory for examples.

=head2 Filenames

The YAML files themselves must have the C<.yml> extension; all other
files are ignored (for two exceptions see I<Fallback Data::Dumper and
Storable> below). The containing directory can be specified in
C<CPAN.pm> in the C<prefs_dir> config variable. Try C<o conf init
prefs_dir> in the CPAN shell to set and activate the distroprefs
system.

Every YAML file may contain arbitrary documents according to the YAML
specification, and every document is treated as an entity that
can specify the treatment of a single distribution.

Filenames can be picked arbitrarily; C<CPAN.pm> always reads
all files (in alphabetical order) and takes the key C<match> (see
below in I<Language Specs>) as a hashref containing match criteria
that determine if the current distribution matches the YAML document
or not.

=head2 Fallback Data::Dumper and Storable

If neither your configured C<yaml_module> nor YAML.pm is installed,
CPAN.pm falls back to using Data::Dumper and Storable and looks for
files with the extensions C<.dd> or C<.st> in the C<prefs_dir>
directory. These files are expected to contain one or more hashrefs.
For Data::Dumper generated files, this is expected to be done with by
defining C<$VAR1>, C<$VAR2>, etc. The YAML shell would produce these
with the command

    ysh < somefile.yml > somefile.dd

For Storable files the rule is that they must be constructed such that
C<Storable::retrieve(file)> returns an array reference and the array
elements represent one distropref object each. The conversion from
YAML would look like so:

    perl -MYAML=LoadFile -MStorable=nstore -e '
        @y=LoadFile(shift);
        nstore(\@y, shift)' somefile.yml somefile.st

In bootstrapping situations it is usually sufficient to translate only
a few YAML files to Data::Dumper for crucial modules like
C<YAML::Syck>, C<YAML.pm> and C<Expect.pm>. If you prefer Storable
over Data::Dumper, remember to pull out a Storable version that writes
an older format than all the other Storable versions that will need to
read them.

=head2 Blueprint

The following example contains all supported keywords and structures
with the exception of C<eexpect> which can be used instead of
C<expect>.

  ---
  comment: "Demo"
  match:
    module: "Dancing::Queen"
    distribution: "^CHACHACHA/Dancing-"
    not_distribution: "\.zip$"
    perl: "/usr/local/cariba-perl/bin/perl"
    perlconfig:
      archname: "freebsd"
      not_cc: "gcc"
    env:
      DANCING_FLOOR: "Shubiduh"
  disabled: 1
  cpanconfig:
    make: gmake
  pl:
    args:
      - "--somearg=specialcase"

    env: {}

    expect:
      - "Which is your favorite fruit"
      - "apple\n"

  make:
    args:
      - all
      - extra-all

    env: {}

    expect: []

    commandline: "echo SKIPPING make"

  test:
    args: []

    env: {}

    expect: []

  install:
    args: []

    env:
      WANT_TO_INSTALL: YES

    expect:
      - "Do you really want to install"
      - "y\n"

  patches:
    - "ABCDE/Fedcba-3.14-ABCDE-01.patch"

  depends:
    configure_requires:
      LWP: 5.8
    build_requires:
      Test::Exception: 0.25
    requires:
      Spiffy: 0.30


=head2 Language Specs

Every YAML document represents a single hash reference. The valid keys
in this hash are as follows:

=over

=item comment [scalar]

A comment

=item cpanconfig [hash]

Temporarily override assorted C<CPAN.pm> configuration variables.

Supported are: C<build_requires_install_policy>, C<check_sigs>,
C<make>, C<make_install_make_command>, C<prefer_installer>,
C<test_report>. Please report as a bug when you need another one
supported.

=item depends [hash] *** EXPERIMENTAL FEATURE ***

All three types, namely C<configure_requires>, C<build_requires>, and
C<requires> are supported in the way specified in the META.yml
specification. The current implementation I<merges> the specified
dependencies with those declared by the package maintainer. In a
future implementation this may be changed to override the original
declaration.

=item disabled [boolean]

Specifies that this distribution shall not be processed at all.

=item features [array] *** EXPERIMENTAL FEATURE ***

Experimental implementation to deal with optional_features from
META.yml. Still needs coordination with installer software and
currently works only for META.yml declaring C<dynamic_config=0>. Use
with caution.

=item goto [string]

The canonical name of a delegate distribution to install
instead. Useful when a new version, although it tests OK itself,
breaks something else or a developer release or a fork is already
uploaded that is better than the last released version.

=item install [hash]

Processing instructions for the C<make install> or C<./Build install>
phase of the CPAN mantra. See below under I<Processing Instructions>.

=item make [hash]

Processing instructions for the C<make> or C<./Build> phase of the
CPAN mantra. See below under I<Processing Instructions>.

=item match [hash]

A hashref with one or more of the keys C<distribution>, C<module>,
C<perl>, C<perlconfig>, and C<env> that specify whether a document is
targeted at a specific CPAN distribution or installation.
Keys prefixed with C<not_> negates the corresponding match.

The corresponding values are interpreted as regular expressions. The
C<distribution> related one will be matched against the canonical
distribution name, e.g. "AUTHOR/Foo-Bar-3.14.tar.gz".

The C<module> related one will be matched against I<all> modules
contained in the distribution until one module matches.

The C<perl> related one will be matched against C<$^X> (but with the
absolute path).

The value associated with C<perlconfig> is itself a hashref that is
matched against corresponding values in the C<%Config::Config> hash
living in the C<Config.pm> module.
Keys prefixed with C<not_> negates the corresponding match.

The value associated with C<env> is itself a hashref that is
matched against corresponding values in the C<%ENV> hash.
Keys prefixed with C<not_> negates the corresponding match.

If more than one restriction of C<module>, C<distribution>, etc. is
specified, the results of the separately computed match values must
all match. If so, the hashref represented by the
YAML document is returned as the preference structure for the current
distribution.

=item patches [array]

An array of patches on CPAN or on the local disk to be applied in
order via an external patch program. If the value for the C<-p>
parameter is C<0> or C<1> is determined by reading the patch
beforehand. The path to each patch is either an absolute path on the
local filesystem or relative to a patch directory specified in the
C<patches_dir> configuration variable or in the format of a canonical
distro name. For examples please consult the distroprefs/ directory in
the CPAN.pm distribution (these examples are not installed by
default).

Note: if the C<applypatch> program is installed and C<CPAN::Config>
knows about it B<and> a patch is written by the C<makepatch> program,
then C<CPAN.pm> lets C<applypatch> apply the patch. Both C<makepatch>
and C<applypatch> are available from CPAN in the C<JV/makepatch-*>
distribution.

=item pl [hash]

Processing instructions for the C<perl Makefile.PL> or C<perl
Build.PL> phase of the CPAN mantra. See below under I<Processing
Instructions>.

=item test [hash]

Processing instructions for the C<make test> or C<./Build test> phase
of the CPAN mantra. See below under I<Processing Instructions>.

=back

=head2 Processing Instructions

=over

=item args [array]

Arguments to be added to the command line

=item commandline

A full commandline to run via C<system()>.
During execution, the environment variable PERL is set
to $^X (but with an absolute path). If C<commandline> is specified,
C<args> is not used.

=item eexpect [hash]

Extended C<expect>. This is a hash reference with four allowed keys,
C<mode>, C<timeout>, C<reuse>, and C<talk>.

You must install the C<Expect> module to use C<eexpect>. CPAN.pm
does not install it for you.

C<mode> may have the values C<deterministic> for the case where all
questions come in the order written down and C<anyorder> for the case
where the questions may come in any order. The default mode is
C<deterministic>.

C<timeout> denotes a timeout in seconds. Floating-point timeouts are
OK. With C<mode=deterministic>, the timeout denotes the
timeout per question; with C<mode=anyorder> it denotes the
timeout per byte received from the stream or questions.

C<talk> is a reference to an array that contains alternating questions
and answers. Questions are regular expressions and answers are literal
strings. The Expect module watches the stream from the
execution of the external program (C<perl Makefile.PL>, C<perl
Build.PL>, C<make>, etc.).

For C<mode=deterministic>, the CPAN.pm injects the
corresponding answer as soon as the stream matches the regular expression.

For C<mode=anyorder> CPAN.pm answers a question as soon
as the timeout is reached for the next byte in the input stream. In
this mode you can use the C<reuse> parameter to decide what will
happen with a question-answer pair after it has been used. In the
default case (reuse=0) it is removed from the array, avoiding being
used again accidentally. If you want to answer the
question C<Do you really want to do that> several times, then it must
be included in the array at least as often as you want this answer to
be given. Setting the parameter C<reuse> to 1 makes this repetition
unnecessary.

=item env [hash]

Environment variables to be set during the command

=item expect [array]

You must install the C<Expect> module to use C<expect>. CPAN.pm
does not install it for you.

C<< expect: <array> >> is a short notation for this C<eexpect>:

	eexpect:
		mode: deterministic
		timeout: 15
		talk: <array>

=back

=head2 Schema verification with C<Kwalify>

If you have the C<Kwalify> module installed (which is part of the
Bundle::CPANxxl), then all your distroprefs files are checked for
syntactic correctness.

=head2 Example Distroprefs Files

C<CPAN.pm> comes with a collection of example YAML files. Note that these
are really just examples and should not be used without care because
they cannot fit everybody's purpose. After all, the authors of the
packages that ask questions had a need to ask, so you should watch
their questions and adjust the examples to your environment and your
needs. You have been warned:-)

=head1 PROGRAMMER'S INTERFACE

If you do not enter the shell, shell commands are
available both as methods (C<CPAN::Shell-E<gt>install(...)>) and as
functions in the calling package (C<install(...)>).  Before calling low-level
commands, it makes sense to initialize components of CPAN you need, e.g.:

  CPAN::HandleConfig->load;
  CPAN::Shell::setup_output;
  CPAN::Index->reload;

High-level commands do such initializations automatically.

There's currently only one class that has a stable interface -
CPAN::Shell. All commands that are available in the CPAN shell are
methods of the class CPAN::Shell. The arguments on the commandline are
passed as arguments to the method.

So if you take for example the shell command

  notest install A B C

the actually executed command is

  CPAN::Shell->notest("install","A","B","C");

Each of the commands that produce listings of modules (C<r>,
C<autobundle>, C<u>) also return a list of the IDs of all modules
within the list.

=over 2

=item expand($type,@things)

The IDs of all objects available within a program are strings that can
be expanded to the corresponding real objects with the
C<CPAN::Shell-E<gt>expand("Module",@things)> method. Expand returns a
list of CPAN::Module objects according to the C<@things> arguments
given. In scalar context, it returns only the first element of the
list.

=item expandany(@things)

Like expand, but returns objects of the appropriate type, i.e.
CPAN::Bundle objects for bundles, CPAN::Module objects for modules, and
CPAN::Distribution objects for distributions. Note: it does not expand
to CPAN::Author objects.

=item Programming Examples

This enables the programmer to do operations that combine
functionalities that are available in the shell.

    # install everything that is outdated on my disk:
    perl -MCPAN -e 'CPAN::Shell->install(CPAN::Shell->r)'

    # install my favorite programs if necessary:
    for $mod (qw(Net::FTP Digest::SHA Data::Dumper)) {
        CPAN::Shell->install($mod);
    }

    # list all modules on my disk that have no VERSION number
    for $mod (CPAN::Shell->expand("Module","/./")) {
        next unless $mod->inst_file;
        # MakeMaker convention for undefined $VERSION:
        next unless $mod->inst_version eq "undef";
        print "No VERSION in ", $mod->id, "\n";
    }

    # find out which distribution on CPAN contains a module:
    print CPAN::Shell->expand("Module","Apache::Constants")->cpan_file

Or if you want to schedule a I<cron> job to watch CPAN, you could list
all modules that need updating. First a quick and dirty way:

    perl -e 'use CPAN; CPAN::Shell->r;'

If you don't want any output should all modules be
up to date, parse the output of above command for the regular
expression C</modules are up to date/> and decide to mail the output
only if it doesn't match.

If you prefer to do it more in a programmerish style in one single
process, something like this may better suit you:

  # list all modules on my disk that have newer versions on CPAN
  for $mod (CPAN::Shell->expand("Module","/./")) {
    next unless $mod->inst_file;
    next if $mod->uptodate;
    printf "Module %s is installed as %s, could be updated to %s from CPAN\n",
        $mod->id, $mod->inst_version, $mod->cpan_version;
  }

If that gives too much output every day, you may want to
watch only for three modules. You can write

  for $mod (CPAN::Shell->expand("Module","/Apache|LWP|CGI/")) {

as the first line instead. Or you can combine some of the above
tricks:

  # watch only for a new mod_perl module
  $mod = CPAN::Shell->expand("Module","mod_perl");
  exit if $mod->uptodate;
  # new mod_perl arrived, let me know all update recommendations
  CPAN::Shell->r;

=back

=head2 Methods in the other Classes

=over 4

=item CPAN::Author::as_glimpse()

Returns a one-line description of the author

=item CPAN::Author::as_string()

Returns a multi-line description of the author

=item CPAN::Author::email()

Returns the author's email address

=item CPAN::Author::fullname()

Returns the author's name

=item CPAN::Author::name()

An alias for fullname

=item CPAN::Bundle::as_glimpse()

Returns a one-line description of the bundle

=item CPAN::Bundle::as_string()

Returns a multi-line description of the bundle

=item CPAN::Bundle::clean()

Recursively runs the C<clean> method on all items contained in the bundle.

=item CPAN::Bundle::contains()

Returns a list of objects' IDs contained in a bundle. The associated
objects may be bundles, modules or distributions.

=item CPAN::Bundle::force($method,@args)

Forces CPAN to perform a task that it normally would have refused to
do. Force takes as arguments a method name to be called and any number
of additional arguments that should be passed to the called method.
The internals of the object get the needed changes so that CPAN.pm
does not refuse to take the action. The C<force> is passed recursively
to all contained objects. See also the section above on the C<force>
and the C<fforce> pragma.

=item CPAN::Bundle::get()

Recursively runs the C<get> method on all items contained in the bundle

=item CPAN::Bundle::inst_file()

Returns the highest installed version of the bundle in either @INC or
C<< $CPAN::Config->{cpan_home} >>. Note that this is different from
CPAN::Module::inst_file.

=item CPAN::Bundle::inst_version()

Like CPAN::Bundle::inst_file, but returns the $VERSION

=item CPAN::Bundle::uptodate()

Returns 1 if the bundle itself and all its members are up-to-date.

=item CPAN::Bundle::install()

Recursively runs the C<install> method on all items contained in the bundle

=item CPAN::Bundle::make()

Recursively runs the C<make> method on all items contained in the bundle

=item CPAN::Bundle::readme()

Recursively runs the C<readme> method on all items contained in the bundle

=item CPAN::Bundle::test()

Recursively runs the C<test> method on all items contained in the bundle

=item CPAN::Distribution::as_glimpse()

Returns a one-line description of the distribution

=item CPAN::Distribution::as_string()

Returns a multi-line description of the distribution

=item CPAN::Distribution::author

Returns the CPAN::Author object of the maintainer who uploaded this
distribution

=item CPAN::Distribution::pretty_id()

Returns a string of the form "AUTHORID/TARBALL", where AUTHORID is the
author's PAUSE ID and TARBALL is the distribution filename.

=item CPAN::Distribution::base_id()

Returns the distribution filename without any archive suffix.  E.g
"Foo-Bar-0.01"

=item CPAN::Distribution::clean()

Changes to the directory where the distribution has been unpacked and
runs C<make clean> there.

=item CPAN::Distribution::containsmods()

Returns a list of IDs of modules contained in a distribution file.
Works only for distributions listed in the 02packages.details.txt.gz
file. This typically means that just most recent version of a
distribution is covered.

=item CPAN::Distribution::cvs_import()

Changes to the directory where the distribution has been unpacked and
runs something like

    cvs -d $cvs_root import -m $cvs_log $cvs_dir $userid v$version

there.

=item CPAN::Distribution::dir()

Returns the directory into which this distribution has been unpacked.

=item CPAN::Distribution::force($method,@args)

Forces CPAN to perform a task that it normally would have refused to
do. Force takes as arguments a method name to be called and any number
of additional arguments that should be passed to the called method.
The internals of the object get the needed changes so that CPAN.pm
does not refuse to take the action. See also the section above on the
C<force> and the C<fforce> pragma.

=item CPAN::Distribution::get()

Downloads the distribution from CPAN and unpacks it. Does nothing if
the distribution has already been downloaded and unpacked within the
current session.

=item CPAN::Distribution::install()

Changes to the directory where the distribution has been unpacked and
runs the external command C<make install> there. If C<make> has not
yet been run, it will be run first. A C<make test> is issued in
any case and if this fails, the install is cancelled. The
cancellation can be avoided by letting C<force> run the C<install> for
you.

This install method only has the power to install the distribution if
there are no dependencies in the way. To install an object along with all
its dependencies, use CPAN::Shell->install.

Note that install() gives no meaningful return value. See uptodate().

=item CPAN::Distribution::isa_perl()

Returns 1 if this distribution file seems to be a perl distribution.
Normally this is derived from the file name only, but the index from
CPAN can contain a hint to achieve a return value of true for other
filenames too.

=item CPAN::Distribution::look()

Changes to the directory where the distribution has been unpacked and
opens a subshell there. Exiting the subshell returns.

=item CPAN::Distribution::make()

First runs the C<get> method to make sure the distribution is
downloaded and unpacked. Changes to the directory where the
distribution has been unpacked and runs the external commands C<perl
Makefile.PL> or C<perl Build.PL> and C<make> there.

=item CPAN::Distribution::perldoc()

Downloads the pod documentation of the file associated with a
distribution (in HTML format) and runs it through the external
command I<lynx> specified in C<< $CPAN::Config->{lynx} >>. If I<lynx>
isn't available, it converts it to plain text with the external
command I<html2text> and runs it through the pager specified
in C<< $CPAN::Config->{pager} >>.

=item CPAN::Distribution::prefs()

Returns the hash reference from the first matching YAML file that the
user has deposited in the C<prefs_dir/> directory. The first
succeeding match wins. The files in the C<prefs_dir/> are processed
alphabetically, and the canonical distro name (e.g.
AUTHOR/Foo-Bar-3.14.tar.gz) is matched against the regular expressions
stored in the $root->{match}{distribution} attribute value.
Additionally all module names contained in a distribution are matched
against the regular expressions in the $root->{match}{module} attribute
value. The two match values are ANDed together. Each of the two
attributes are optional.

=item CPAN::Distribution::prereq_pm()

Returns the hash reference that has been announced by a distribution
as the C<requires> and C<build_requires> elements. These can be
declared either by the C<META.yml> (if authoritative) or can be
deposited after the run of C<Build.PL> in the file C<./_build/prereqs>
or after the run of C<Makfile.PL> written as the C<PREREQ_PM> hash in
a comment in the produced C<Makefile>. I<Note>: this method only works
after an attempt has been made to C<make> the distribution. Returns
undef otherwise.

=item CPAN::Distribution::readme()

Downloads the README file associated with a distribution and runs it
through the pager specified in C<< $CPAN::Config->{pager} >>.

=item CPAN::Distribution::reports()

Downloads report data for this distribution from www.cpantesters.org
and displays a subset of them.

=item CPAN::Distribution::read_yaml()

Returns the content of the META.yml of this distro as a hashref. Note:
works only after an attempt has been made to C<make> the distribution.
Returns undef otherwise. Also returns undef if the content of META.yml
is not authoritative. (The rules about what exactly makes the content
authoritative are still in flux.)

=item CPAN::Distribution::test()

Changes to the directory where the distribution has been unpacked and
runs C<make test> there.

=item CPAN::Distribution::uptodate()

Returns 1 if all the modules contained in the distribution are
up-to-date. Relies on containsmods.

=item CPAN::Index::force_reload()

Forces a reload of all indices.

=item CPAN::Index::reload()

Reloads all indices if they have not been read for more than
C<< $CPAN::Config->{index_expire} >> days.

=item CPAN::InfoObj::dump()

CPAN::Author, CPAN::Bundle, CPAN::Module, and CPAN::Distribution
inherit this method. It prints the data structure associated with an
object. Useful for debugging. Note: the data structure is considered
internal and thus subject to change without notice.

=item CPAN::Module::as_glimpse()

Returns a one-line description of the module in four columns: The
first column contains the word C<Module>, the second column consists
of one character: an equals sign if this module is already installed
and up-to-date, a less-than sign if this module is installed but can be
upgraded, and a space if the module is not installed. The third column
is the name of the module and the fourth column gives maintainer or
distribution information.

=item CPAN::Module::as_string()

Returns a multi-line description of the module

=item CPAN::Module::clean()

Runs a clean on the distribution associated with this module.

=item CPAN::Module::cpan_file()

Returns the filename on CPAN that is associated with the module.

=item CPAN::Module::cpan_version()

Returns the latest version of this module available on CPAN.

=item CPAN::Module::cvs_import()

Runs a cvs_import on the distribution associated with this module.

=item CPAN::Module::description()

Returns a 44 character description of this module. Only available for
modules listed in The Module List (CPAN/modules/00modlist.long.html
or 00modlist.long.txt.gz)

=item CPAN::Module::distribution()

Returns the CPAN::Distribution object that contains the current
version of this module.

=item CPAN::Module::dslip_status()

Returns a hash reference. The keys of the hash are the letters C<D>,
C<S>, C<L>, C<I>, and <P>, for development status, support level,
language, interface and public licence respectively. The data for the
DSLIP status are collected by pause.perl.org when authors register
their namespaces. The values of the 5 hash elements are one-character
words whose meaning is described in the table below. There are also 5
hash elements C<DV>, C<SV>, C<LV>, C<IV>, and <PV> that carry a more
verbose value of the 5 status variables.

Where the 'DSLIP' characters have the following meanings:

  D - Development Stage  (Note: *NO IMPLIED TIMESCALES*):
    i   - Idea, listed to gain consensus or as a placeholder
    c   - under construction but pre-alpha (not yet released)
    a/b - Alpha/Beta testing
    R   - Released
    M   - Mature (no rigorous definition)
    S   - Standard, supplied with Perl 5

  S - Support Level:
    m   - Mailing-list
    d   - Developer
    u   - Usenet newsgroup comp.lang.perl.modules
    n   - None known, try comp.lang.perl.modules
    a   - abandoned; volunteers welcome to take over maintenance

  L - Language Used:
    p   - Perl-only, no compiler needed, should be platform independent
    c   - C and perl, a C compiler will be needed
    h   - Hybrid, written in perl with optional C code, no compiler needed
    +   - C++ and perl, a C++ compiler will be needed
    o   - perl and another language other than C or C++

  I - Interface Style
    f   - plain Functions, no references used
    h   - hybrid, object and function interfaces available
    n   - no interface at all (huh?)
    r   - some use of unblessed References or ties
    O   - Object oriented using blessed references and/or inheritance

  P - Public License
    p   - Standard-Perl: user may choose between GPL and Artistic
    g   - GPL: GNU General Public License
    l   - LGPL: "GNU Lesser General Public License" (previously known as
          "GNU Library General Public License")
    b   - BSD: The BSD License
    a   - Artistic license alone
    2   - Artistic license 2.0 or later
    o   - open source: approved by www.opensource.org
    d   - allows distribution without restrictions
    r   - restricted distribution
    n   - no license at all

=item CPAN::Module::force($method,@args)

Forces CPAN to perform a task it would normally refuse to
do. Force takes as arguments a method name to be invoked and any number
of additional arguments to pass that method.
The internals of the object get the needed changes so that CPAN.pm
does not refuse to take the action. See also the section above on the
C<force> and the C<fforce> pragma.

=item CPAN::Module::get()

Runs a get on the distribution associated with this module.

=item CPAN::Module::inst_file()

Returns the filename of the module found in @INC. The first file found
is reported, just as perl itself stops searching @INC once it finds a
module.

=item CPAN::Module::available_file()

Returns the filename of the module found in PERL5LIB or @INC. The
first file found is reported. The advantage of this method over
C<inst_file> is that modules that have been tested but not yet
installed are included because PERL5LIB keeps track of tested modules.

=item CPAN::Module::inst_version()

Returns the version number of the installed module in readable format.

=item CPAN::Module::available_version()

Returns the version number of the available module in readable format.

=item CPAN::Module::install()

Runs an C<install> on the distribution associated with this module.

=item CPAN::Module::look()

Changes to the directory where the distribution associated with this
module has been unpacked and opens a subshell there. Exiting the
subshell returns.

=item CPAN::Module::make()

Runs a C<make> on the distribution associated with this module.

=item CPAN::Module::manpage_headline()

If module is installed, peeks into the module's manpage, reads the
headline, and returns it. Moreover, if the module has been downloaded
within this session, does the equivalent on the downloaded module even
if it hasn't been installed yet.

=item CPAN::Module::perldoc()

Runs a C<perldoc> on this module.

=item CPAN::Module::readme()

Runs a C<readme> on the distribution associated with this module.

=item CPAN::Module::reports()

Calls the reports() method on the associated distribution object.

=item CPAN::Module::test()

Runs a C<test> on the distribution associated with this module.

=item CPAN::Module::uptodate()

Returns 1 if the module is installed and up-to-date.

=item CPAN::Module::userid()

Returns the author's ID of the module.

=back

=head2 Cache Manager

Currently the cache manager only keeps track of the build directory
($CPAN::Config->{build_dir}). It is a simple FIFO mechanism that
deletes complete directories below C<build_dir> as soon as the size of
all directories there gets bigger than $CPAN::Config->{build_cache}
(in MB). The contents of this cache may be used for later
re-installations that you intend to do manually, but will never be
trusted by CPAN itself. This is due to the fact that the user might
use these directories for building modules on different architectures.

There is another directory ($CPAN::Config->{keep_source_where}) where
the original distribution files are kept. This directory is not
covered by the cache manager and must be controlled by the user. If
you choose to have the same directory as build_dir and as
keep_source_where directory, then your sources will be deleted with
the same fifo mechanism.

=head2 Bundles

A bundle is just a perl module in the namespace Bundle:: that does not
define any functions or methods. It usually only contains documentation.

It starts like a perl module with a package declaration and a $VERSION
variable. After that the pod section looks like any other pod with the
only difference being that I<one special pod section> exists starting with
(verbatim):

    =head1 CONTENTS

In this pod section each line obeys the format

        Module_Name [Version_String] [- optional text]

The only required part is the first field, the name of a module
(e.g. Foo::Bar, i.e. I<not> the name of the distribution file). The rest
of the line is optional. The comment part is delimited by a dash just
as in the man page header.

The distribution of a bundle should follow the same convention as
other distributions.

Bundles are treated specially in the CPAN package. If you say 'install
Bundle::Tkkit' (assuming such a bundle exists), CPAN will install all
the modules in the CONTENTS section of the pod. You can install your
own Bundles locally by placing a conformant Bundle file somewhere into
your @INC path. The autobundle() command which is available in the
shell interface does that for you by including all currently installed
modules in a snapshot bundle file.

=head1 PREREQUISITES

The CPAN program is trying to depend on as little as possible so the
user can use it in hostile environment. It works better the more goodies
the environment provides. For example if you try in the CPAN shell

  install Bundle::CPAN

or

  install Bundle::CPANxxl

you will find the shell more convenient than the bare shell before.

If you have a local mirror of CPAN and can access all files with
"file:" URLs, then you only need a perl later than perl5.003 to run
this module. Otherwise Net::FTP is strongly recommended. LWP may be
required for non-UNIX systems, or if your nearest CPAN site is
associated with a URL that is not C<ftp:>.

If you have neither Net::FTP nor LWP, there is a fallback mechanism
implemented for an external ftp command or for an external lynx
command.

=head1 UTILITIES

=head2 Finding packages and VERSION

This module presumes that all packages on CPAN

=over 2

=item *

declare their $VERSION variable in an easy to parse manner. This
prerequisite can hardly be relaxed because it consumes far too much
memory to load all packages into the running program just to determine
the $VERSION variable. Currently all programs that are dealing with
version use something like this

    perl -MExtUtils::MakeMaker -le \
        'print MM->parse_version(shift)' filename

If you are author of a package and wonder if your $VERSION can be
parsed, please try the above method.

=item *

come as compressed or gzipped tarfiles or as zip files and contain a
C<Makefile.PL> or C<Build.PL> (well, we try to handle a bit more, but
with little enthusiasm).

=back

=head2 Debugging

Debugging this module is more than a bit complex due to interference from
the software producing the indices on CPAN, the mirroring process on CPAN,
packaging, configuration, synchronicity, and even (gasp!) due to bugs
within the CPAN.pm module itself.

For debugging the code of CPAN.pm itself in interactive mode, some
debugging aid can be turned on for most packages within
CPAN.pm with one of

=over 2

=item o debug package...

sets debug mode for packages.

=item o debug -package...

unsets debug mode for packages.

=item o debug all

turns debugging on for all packages.

=item o debug number

=back

which sets the debugging packages directly. Note that C<o debug 0>
turns debugging off.

What seems a successful strategy is the combination of C<reload
cpan> and the debugging switches. Add a new debug statement while
running in the shell and then issue a C<reload cpan> and see the new
debugging messages immediately without losing the current context.

C<o debug> without an argument lists the valid package names and the
current set of packages in debugging mode. C<o debug> has built-in
completion support.

For debugging of CPAN data there is the C<dump> command which takes
the same arguments as make/test/install and outputs each object's
Data::Dumper dump. If an argument looks like a perl variable and
contains one of C<$>, C<@> or C<%>, it is eval()ed and fed to
Data::Dumper directly.

=head2 Floppy, Zip, Offline Mode

CPAN.pm works nicely without network access, too. If you maintain machines
that are not networked at all, you should consider working with C<file:>
URLs. You'll have to collect your modules somewhere first. So
you might use CPAN.pm to put together all you need on a networked
machine. Then copy the $CPAN::Config->{keep_source_where} (but not
$CPAN::Config->{build_dir}) directory on a floppy. This floppy is kind
of a personal CPAN. CPAN.pm on the non-networked machines works nicely
with this floppy. See also below the paragraph about CD-ROM support.

=head2 Basic Utilities for Programmers

=over 2

=item has_inst($module)

Returns true if the module is installed. Used to load all modules into
the running CPAN.pm that are considered optional. The config variable
C<dontload_list> intercepts the C<has_inst()> call such
that an optional module is not loaded despite being available. For
example, the following command will prevent C<YAML.pm> from being
loaded:

    cpan> o conf dontload_list push YAML

See the source for details.

=item use_inst($module)

Similary to L<has_inst()> tries to load optional library but also dies if
library is not available

=item has_usable($module)

Returns true if the module is installed and in a usable state. Only
useful for a handful of modules that are used internally. See the
source for details.

=item instance($module)

The constructor for all the singletons used to represent modules,
distributions, authors, and bundles. If the object already exists, this
method returns the object; otherwise, it calls the constructor.

=item frontend()

=item frontend($new_frontend)

Getter/setter for frontend object. Method just allows to subclass CPAN.pm.

=back

=head1 SECURITY

There's no strong security layer in CPAN.pm. CPAN.pm helps you to
install foreign, unmasked, unsigned code on your machine. We compare
to a checksum that comes from the net just as the distribution file
itself. But we try to make it easy to add security on demand:

=head2 Cryptographically signed modules

Since release 1.77, CPAN.pm has been able to verify cryptographically
signed module distributions using Module::Signature.  The CPAN modules
can be signed by their authors, thus giving more security.  The simple
unsigned MD5 checksums that were used before by CPAN protect mainly
against accidental file corruption.

You will need to have Module::Signature installed, which in turn
requires that you have at least one of Crypt::OpenPGP module or the
command-line F<gpg> tool installed.

You will also need to be able to connect over the Internet to the public
key servers, like pgp.mit.edu, and their port 11731 (the HKP protocol).

The configuration parameter check_sigs is there to turn signature
checking on or off.

=head1 EXPORT

Most functions in package CPAN are exported by default. The reason
for this is that the primary use is intended for the cpan shell or for
one-liners.

=head1 ENVIRONMENT

When the CPAN shell enters a subshell via the look command, it sets
the environment CPAN_SHELL_LEVEL to 1, or increments that variable if it is
already set.

When CPAN runs, it sets the environment variable PERL5_CPAN_IS_RUNNING
to the ID of the running process. It also sets
PERL5_CPANPLUS_IS_RUNNING to prevent runaway processes which could
happen with older versions of Module::Install.

When running C<perl Makefile.PL>, the environment variable
C<PERL5_CPAN_IS_EXECUTING> is set to the full path of the
C<Makefile.PL> that is being executed. This prevents runaway processes
with newer versions of Module::Install.

When the config variable ftp_passive is set, all downloads will be run
with the environment variable FTP_PASSIVE set to this value. This is
in general a good idea as it influences both Net::FTP and LWP based
connections. The same effect can be achieved by starting the cpan
shell with this environment variable set. For Net::FTP alone, one can
also always set passive mode by running libnetcfg.

=head1 POPULATE AN INSTALLATION WITH LOTS OF MODULES

Populating a freshly installed perl with one's favorite modules is pretty
easy if you maintain a private bundle definition file. To get a useful
blueprint of a bundle definition file, the command autobundle can be used
on the CPAN shell command line. This command writes a bundle definition
file for all modules installed for the current perl
interpreter. It's recommended to run this command once only, and from then
on maintain the file manually under a private name, say
Bundle/my_bundle.pm. With a clever bundle file you can then simply say

    cpan> install Bundle::my_bundle

then answer a few questions and go out for coffee (possibly
even in a different city).

Maintaining a bundle definition file means keeping track of two
things: dependencies and interactivity. CPAN.pm sometimes fails on
calculating dependencies because not all modules define all MakeMaker
attributes correctly, so a bundle definition file should specify
prerequisites as early as possible. On the other hand, it's
annoying that so many distributions need some interactive configuring. So
what you can try to accomplish in your private bundle file is to have the
packages that need to be configured early in the file and the gentle
ones later, so you can go out for coffee after a few minutes and leave CPAN.pm
to churn away unattended.

=head1 WORKING WITH CPAN.pm BEHIND FIREWALLS

Thanks to Graham Barr for contributing the following paragraphs about
the interaction between perl, and various firewall configurations. For
further information on firewalls, it is recommended to consult the
documentation that comes with the I<ncftp> program. If you are unable to
go through the firewall with a simple Perl setup, it is likely
that you can configure I<ncftp> so that it works through your firewall.

=head2 Three basic types of firewalls

Firewalls can be categorized into three basic types.

=over 4

=item http firewall

This is when the firewall machine runs a web server, and to access the
outside world, you must do so via that web server. If you set environment
variables like http_proxy or ftp_proxy to values beginning with http://,
or in your web browser you've proxy information set, then you know
you are running behind an http firewall.

To access servers outside these types of firewalls with perl (even for
ftp), you need LWP or HTTP::Tiny.

=item ftp firewall

This where the firewall machine runs an ftp server. This kind of
firewall will only let you access ftp servers outside the firewall.
This is usually done by connecting to the firewall with ftp, then
entering a username like "user@outside.host.com".

To access servers outside these type of firewalls with perl, you
need Net::FTP.

=item One-way visibility

One-way visibility means these firewalls try to make themselves
invisible to users inside the firewall. An FTP data connection is
normally created by sending your IP address to the remote server and then
listening for the return connection. But the remote server will not be able to
connect to you because of the firewall. For these types of firewall,
FTP connections need to be done in a passive mode.

There are two that I can think off.

=over 4

=item SOCKS

If you are using a SOCKS firewall, you will need to compile perl and link
it with the SOCKS library.  This is what is normally called a 'socksified'
perl. With this executable you will be able to connect to servers outside
the firewall as if it were not there.

=item IP Masquerade

This is when the firewall implemented in the kernel (via NAT, or networking
address translation), it allows you to hide a complete network behind one
IP address. With this firewall no special compiling is needed as you can
access hosts directly.

For accessing ftp servers behind such firewalls you usually need to
set the environment variable C<FTP_PASSIVE> or the config variable
ftp_passive to a true value.

=back

=back

=head2 Configuring lynx or ncftp for going through a firewall

If you can go through your firewall with e.g. lynx, presumably with a
command such as

    /usr/local/bin/lynx -pscott:tiger

then you would configure CPAN.pm with the command

    o conf lynx "/usr/local/bin/lynx -pscott:tiger"

That's all. Similarly for ncftp or ftp, you would configure something
like

    o conf ncftp "/usr/bin/ncftp -f /home/scott/ncftplogin.cfg"

Your mileage may vary...

=head1 FAQ

=over 4

=item 1)

I installed a new version of module X but CPAN keeps saying,
I have the old version installed

Probably you B<do> have the old version installed. This can
happen if a module installs itself into a different directory in the
@INC path than it was previously installed. This is not really a
CPAN.pm problem, you would have the same problem when installing the
module manually. The easiest way to prevent this behaviour is to add
the argument C<UNINST=1> to the C<make install> call, and that is why
many people add this argument permanently by configuring

  o conf make_install_arg UNINST=1

=item 2)

So why is UNINST=1 not the default?

Because there are people who have their precise expectations about who
may install where in the @INC path and who uses which @INC array. In
fine tuned environments C<UNINST=1> can cause damage.

=item 3)

I want to clean up my mess, and install a new perl along with
all modules I have. How do I go about it?

Run the autobundle command for your old perl and optionally rename the
resulting bundle file (e.g. Bundle/mybundle.pm), install the new perl
with the Configure option prefix, e.g.

    ./Configure -Dprefix=/usr/local/perl-5.6.78.9

Install the bundle file you produced in the first step with something like

    cpan> install Bundle::mybundle

and you're done.

=item 4)

When I install bundles or multiple modules with one command
there is too much output to keep track of.

You may want to configure something like

  o conf make_arg "| tee -ai /root/.cpan/logs/make.out"
  o conf make_install_arg "| tee -ai /root/.cpan/logs/make_install.out"

so that STDOUT is captured in a file for later inspection.


=item 5)

I am not root, how can I install a module in a personal directory?

As of CPAN 1.9463, if you do not have permission to write the default perl
library directories, CPAN's configuration process will ask you whether
you want to bootstrap <local::lib>, which makes keeping a personal
perl library directory easy.

Another thing you should bear in mind is that the UNINST parameter can
be dangerous when you are installing into a private area because you
might accidentally remove modules that other people depend on that are
not using the private area.

=item 6)

How to get a package, unwrap it, and make a change before building it?

Have a look at the C<look> (!) command.

=item 7)

I installed a Bundle and had a couple of fails. When I
retried, everything resolved nicely. Can this be fixed to work
on first try?

The reason for this is that CPAN does not know the dependencies of all
modules when it starts out. To decide about the additional items to
install, it just uses data found in the META.yml file or the generated
Makefile. An undetected missing piece breaks the process. But it may
well be that your Bundle installs some prerequisite later than some
depending item and thus your second try is able to resolve everything.
Please note, CPAN.pm does not know the dependency tree in advance and
cannot sort the queue of things to install in a topologically correct
order. It resolves perfectly well B<if> all modules declare the
prerequisites correctly with the PREREQ_PM attribute to MakeMaker or
the C<requires> stanza of Module::Build. For bundles which fail and
you need to install often, it is recommended to sort the Bundle
definition file manually.

=item 8)

In our intranet, we have many modules for internal use. How
can I integrate these modules with CPAN.pm but without uploading
the modules to CPAN?

Have a look at the CPAN::Site module.

=item 9)

When I run CPAN's shell, I get an error message about things in my
C</etc/inputrc> (or C<~/.inputrc>) file.

These are readline issues and can only be fixed by studying readline
configuration on your architecture and adjusting the referenced file
accordingly. Please make a backup of the C</etc/inputrc> or C<~/.inputrc>
and edit them. Quite often harmless changes like uppercasing or
lowercasing some arguments solves the problem.

=item 10)

Some authors have strange characters in their names.

Internally CPAN.pm uses the UTF-8 charset. If your terminal is
expecting ISO-8859-1 charset, a converter can be activated by setting
term_is_latin to a true value in your config file. One way of doing so
would be

    cpan> o conf term_is_latin 1

If other charset support is needed, please file a bug report against
CPAN.pm at rt.cpan.org and describe your needs. Maybe we can extend
the support or maybe UTF-8 terminals become widely available.

Note: this config variable is deprecated and will be removed in a
future version of CPAN.pm. It will be replaced with the conventions
around the family of $LANG and $LC_* environment variables.

=item 11)

When an install fails for some reason and then I correct the error
condition and retry, CPAN.pm refuses to install the module, saying
C<Already tried without success>.

You could use the force pragma like so

  force install Foo::Bar

Or, to avoid a force install (which would install even if the tests
fail), you can force only the test and then install:

  force test Foo::Bar
  install Foo::Bar

Or you can use

  look Foo::Bar

and then C<make install> directly in the subshell.

=item 12)

How do I install a "DEVELOPER RELEASE" of a module?

By default, CPAN will install the latest non-developer release of a
module. If you want to install a dev release, you have to specify the
partial path starting with the author id to the tarball you wish to
install, like so:

    cpan> install KWILLIAMS/Module-Build-0.27_07.tar.gz

Note that you can use the C<ls> command to get this path listed.

=item 13)

How do I install a module and all its dependencies from the commandline,
without being prompted for anything, despite my CPAN configuration
(or lack thereof)?

CPAN uses ExtUtils::MakeMaker's prompt() function to ask its questions, so
if you set the PERL_MM_USE_DEFAULT environment variable, you shouldn't be
asked any questions at all (assuming the modules you are installing are
nice about obeying that variable as well):

    % PERL_MM_USE_DEFAULT=1 perl -MCPAN -e 'install My::Module'

=item 14)

How do I create a Module::Build based Build.PL derived from an
ExtUtils::MakeMaker focused Makefile.PL?

http://search.cpan.org/dist/Module-Build-Convert/

=item 15)

I'm frequently irritated with the CPAN shell's inability to help me
select a good mirror.

CPAN can now help you select a "good" mirror, based on which ones have the
lowest 'ping' round-trip times.  From the shell, use the command 'o conf init
urllist' and allow CPAN to automatically select mirrors for you.

Beyond that help, the urllist config parameter is yours. You can add and remove
sites at will. You should find out which sites have the best up-to-dateness,
bandwidth, reliability, etc. and are topologically close to you. Some people
prefer fast downloads, others up-to-dateness, others reliability.  You decide
which to try in which order.

Henk P. Penning maintains a site that collects data about CPAN sites:

  http://mirrors.cpan.org/

Also, feel free to play with experimental features. Run

  o conf init randomize_urllist ftpstats_period ftpstats_size

and choose your favorite parameters. After a few downloads running the
C<hosts> command will probably assist you in choosing the best mirror
sites.

=item 16)

Why do I get asked the same questions every time I start the shell?

You can make your configuration changes permanent by calling the
command C<o conf commit>. Alternatively set the C<auto_commit>
variable to true by running C<o conf init auto_commit> and answering
the following question with yes.

=item 17)

Older versions of CPAN.pm had the original root directory of all
tarballs in the build directory. Now there are always random
characters appended to these directory names. Why was this done?

The random characters are provided by File::Temp and ensure that each
module's individual build directory is unique. This makes running
CPAN.pm in concurrent processes simultaneously safe.

=item 18)

Speaking of the build directory. Do I have to clean it up myself?

You have the choice to set the config variable C<scan_cache> to
C<never>. Then you must clean it up yourself. The other possible
values, C<atstart> and C<atexit> clean up the build directory when you
start (or more precisely, after the first extraction into the build
directory) or exit the CPAN shell, respectively. If you never start up
the CPAN shell, you probably also have to clean up the build directory
yourself.

=item 19)

How can I switch to sudo instead of local::lib?

The following 5 environment veriables need to be reset to the previous
values: PATH, PERL5LIB, PERL_LOCAL_LIB_ROOT, PERL_MB_OPT, PERL_MM_OPT;
and these two CPAN.pm config variables must be reconfigured:
make_install_make_command and mbuild_install_build_command. The five
env variables have probably been overwritten in your $HOME/.bashrc or
some equivalent. You either find them there and delete their traces
and logout/login or you override them temporarily, depending on your
exact desire. The two cpanpm config variables can be set with:

  o conf init /install_.*_command/

probably followed by

  o conf commit

=item 20)

How do recommends_policy and suggests_policy work, exactly?

The terms C<recommends> and C<suggests> have been standardized in
https://metacpan.org/pod/CPAN::Meta::Spec

In CPAN.pm, if you set C<recommands_policy> to a true value, that
means: if you then install a distribution C<Foo> that I<recommends> a
module C<Bar>, both C<Foo> and C<Bar> will be tested and potentially
installed.

Similarly, if you set C<suggests_policy> to a true value, it means: if
you install a distribution C<Foo> that I<suggests> a module C<Bar>,
both C<Foo> and C<Bar> will be tested and potentially installed.

In either case, when C<Foo> passes its tests and C<Bar> does not pass
its tests, C<Foo> will be installed nontheless. But if C<Foo> does not
pass its tests, neither will be installed.

This also works recursively for all recommends and suggests of the
module C<Bar>.

This has also been illustrated by a cpan tester, who wrote:

I just tested Starlink-AST-3.03 which recommends Tk::Zinc;
Tk-Zinc-3.306 fails with
http://www.cpantesters.org/cpan/report/a2de7c38-810d-11ee-9ad4-e2167316189a
; nonetheless Starlink-AST-3.03 succeeds with
http://www.cpantesters.org/cpan/report/9352e754-810d-11ee-90e9-46117316189a

=back

=head1 COMPATIBILITY

=head2 OLD PERL VERSIONS

CPAN.pm is regularly tested to run under 5.005 and assorted
newer versions. It is getting more and more difficult to get the
minimal prerequisites working on older perls. It is close to
impossible to get the whole Bundle::CPAN working there. If you're in
the position to have only these old versions, be advised that CPAN is
designed to work fine without the Bundle::CPAN installed.

To get things going, note that GBARR/Scalar-List-Utils-1.18.tar.gz is
compatible with ancient perls and that File::Temp is listed as a
prerequisite but CPAN has reasonable workarounds if it is missing.

=head2 CPANPLUS

This module and its competitor, the CPANPLUS module, are both much
cooler than the other. CPAN.pm is older. CPANPLUS was designed to be
more modular, but it was never intended to be compatible with CPAN.pm.

=head2 CPANMINUS

In the year 2010 App::cpanminus was launched as a new approach to a
cpan shell with a considerably smaller footprint. Very cool stuff.

=head1 SECURITY ADVICE

This software enables you to upgrade software on your computer and so
is inherently dangerous because the newly installed software may
contain bugs and may alter the way your computer works or even make it
unusable. Please consider backing up your data before every upgrade.

=head1 BUGS

Please report bugs via L<http://rt.cpan.org/>

Before submitting a bug, please make sure that the traditional method
of building a Perl module package from a shell by following the
installation instructions of that package still works in your
environment.

=head1 AUTHOR

Andreas Koenig C<< <andk@cpan.org> >>

=head1 LICENSE

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

See L<http://www.perl.com/perl/misc/Artistic.html>

=head1 TRANSLATIONS

Kawai,Takanori provides a Japanese translation of a very old version
of this manpage at
L<http://homepage3.nifty.com/hippo2000/perltips/CPAN.htm>

=head1 SEE ALSO

Many people enter the CPAN shell by running the L<cpan> utility
program which is installed in the same directory as perl itself. So if
you have this directory in your PATH variable (or some equivalent in
your operating system) then typing C<cpan> in a console window will
work for you as well. Above that the utility provides several
commandline shortcuts.

melezhik (Alexey) sent me a link where he published a chef recipe to
work with CPAN.pm: http://community.opscode.com/cookbooks/cpan.


=cut
PK1N%[���/�T�Tperl5/LWP.pmnu��6�$package LWP;

our $VERSION = '6.78';

require LWP::UserAgent;  # this should load everything you need

1;

__END__

=pod

=encoding utf-8

=head1 NAME

LWP - The World-Wide Web library for Perl

=head1 SYNOPSIS

  use LWP;
  print "This is libwww-perl-$LWP::VERSION\n";


=head1 DESCRIPTION

The libwww-perl collection is a set of Perl modules which provides a
simple and consistent application programming interface (API) to the
World-Wide Web.  The main focus of the library is to provide classes
and functions that allow you to write WWW clients. The library also
contain modules that are of more general use and even classes that
help you implement simple HTTP servers.

Most modules in this library provide an object oriented API.  The user
agent, requests sent and responses received from the WWW server are
all represented by objects.  This makes a simple and powerful
interface to these services.  The interface is easy to extend
and customize for your own needs.

The main features of the library are:

=over 3

=item *

Contains various reusable components (modules) that can be
used separately or together.

=item *

Provides an object oriented model of HTTP-style communication.  Within
this framework we currently support access to C<http>, C<https>, C<gopher>,
C<ftp>, C<news>, C<file>, and C<mailto> resources.

=item *

Provides a full object oriented interface or
a very simple procedural interface.

=item *

Supports the basic and digest authorization schemes.

=item *

Supports transparent redirect handling.

=item *

Supports access through proxy servers.

=item *

Provides parser for F<robots.txt> files and a framework for constructing robots.

=item *

Supports parsing of HTML forms.

=item *

Implements HTTP content negotiation algorithm that can
be used both in protocol modules and in server scripts (like CGI
scripts).

=item *

Supports HTTP cookies.

=item *

Some simple command line clients, for instance C<lwp-request> and C<lwp-download>.

=back


=head1 HTTP STYLE COMMUNICATION


The libwww-perl library is based on HTTP style communication. This
section tries to describe what that means.

Let us start with this quote from the HTTP specification document
L<http://www.w3.org/Protocols/>:

=over 3

=item *

The HTTP protocol is based on a request/response paradigm. A client
establishes a connection with a server and sends a request to the
server in the form of a request method, URI, and protocol version,
followed by a MIME-like message containing request modifiers, client
information, and possible body content. The server responds with a
status line, including the message's protocol version and a success or
error code, followed by a MIME-like message containing server
information, entity meta-information, and possible body content.

=back

What this means to libwww-perl is that communication always take place
through these steps: First a I<request> object is created and
configured. This object is then passed to a server and we get a
I<response> object in return that we can examine. A request is always
independent of any previous requests, i.e. the service is stateless.
The same simple model is used for any kind of service we want to
access.

For example, if we want to fetch a document from a remote file server,
then we send it a request that contains a name for that document and
the response will contain the document itself.  If we access a search
engine, then the content of the request will contain the query
parameters and the response will contain the query result.  If we want
to send a mail message to somebody then we send a request object which
contains our message to the mail server and the response object will
contain an acknowledgment that tells us that the message has been
accepted and will be forwarded to the recipient(s).

It is as simple as that!


=head2 The Request Object

The libwww-perl request object has the class name L<HTTP::Request>.
The fact that the class name uses C<HTTP::> as a
prefix only implies that we use the HTTP model of communication.  It
does not limit the kind of services we can try to pass this I<request>
to.  For instance, we will send L<HTTP::Request>s both to ftp and
gopher servers, as well as to the local file system.

The main attributes of the request objects are:

=over 3

=item *

B<method> is a short string that tells what kind of
request this is.  The most common methods are B<GET>, B<PUT>,
B<POST> and B<HEAD>.

=item *

B<uri> is a string denoting the protocol, server and
the name of the "document" we want to access.  The B<uri> might
also encode various other parameters.

=item *

B<headers> contains additional information about the
request and can also used to describe the content.  The headers
are a set of keyword/value pairs.

=item *

B<content> is an arbitrary amount of data.

=back

=head2 The Response Object

The libwww-perl response object has the class name L<HTTP::Response>.
The main attributes of objects of this class are:

=over 3

=item *

B<code> is a numerical value that indicates the overall
outcome of the request.

=item *

B<message> is a short, human readable string that
corresponds to the I<code>.

=item *

B<headers> contains additional information about the
response and describe the content.

=item *

B<content> is an arbitrary amount of data.

=back

Since we don't want to handle all possible I<code> values directly in
our programs, a libwww-perl response object has methods that can be
used to query what kind of response this is.  The most commonly used
response classification methods are:

=over 3

=item is_success()

The request was successfully received, understood or accepted.

=item is_error()

The request failed.  The server or the resource might not be
available, access to the resource might be denied or other things might
have failed for some reason.

=back

=head2 The User Agent

Let us assume that we have created a I<request> object. What do we
actually do with it in order to receive a I<response>?

The answer is that you pass it to a I<user agent> object and this
object takes care of all the things that need to be done
(like low-level communication and error handling) and returns
a I<response> object. The user agent represents your
application on the network and provides you with an interface that
can accept I<requests> and return I<responses>.

The user agent is an interface layer between
your application code and the network.  Through this interface you are
able to access the various servers on the network.

The class name for the user agent is L<LWP::UserAgent>.  Every
libwww-perl application that wants to communicate should create at
least one object of this class. The main method provided by this
object is request(). This method takes an L<HTTP::Request> object as
argument and (eventually) returns a L<HTTP::Response> object.

The user agent has many other attributes that let you
configure how it will interact with the network and with your
application.

=over 3

=item *

B<timeout> specifies how much time we give remote servers to
respond before the library disconnects and creates an
internal I<timeout> response.

=item *

B<agent> specifies the name that your application uses when it
presents itself on the network.

=item *

B<from> can be set to the e-mail address of the person
responsible for running the application.  If this is set, then the
address will be sent to the servers with every request.

=item *

B<parse_head> specifies whether we should initialize response
headers from the C<< <head> >> section of HTML documents.

=item *

B<proxy> and B<no_proxy> specify if and when to go through
a proxy server. L<http://www.w3.org/History/1994/WWW/Proxies/>

=item *

B<credentials> provides a way to set up user names and
passwords needed to access certain services.

=back

Many applications want even more control over how they interact
with the network and they get this by sub-classing
L<LWP::UserAgent>.  The library includes a
sub-class, L<LWP::RobotUA>, for robot applications.

=head2 An Example

This example shows how the user agent, a request and a response are
represented in actual perl code:

  # Create a user agent object
  use LWP::UserAgent;
  my $ua = LWP::UserAgent->new;
  $ua->agent("MyApp/0.1 ");

  # Create a request
  my $req = HTTP::Request->new(POST => 'http://search.cpan.org/search');
  $req->content_type('application/x-www-form-urlencoded');
  $req->content('query=libwww-perl&mode=dist');

  # Pass request to the user agent and get a response back
  my $res = $ua->request($req);

  # Check the outcome of the response
  if ($res->is_success) {
      print $res->content;
  }
  else {
      print $res->status_line, "\n";
  }

The C<$ua> is created once when the application starts up.  New request
objects should normally created for each request sent.


=head1 NETWORK SUPPORT

This section discusses the various protocol schemes and
the HTTP style methods that headers may be used for each.

For all requests, a "User-Agent" header is added and initialized from
the C<< $ua->agent >> attribute before the request is handed to the network
layer.  In the same way, a "From" header is initialized from the
$ua->from attribute.

For all responses, the library adds a header called "Client-Date".
This header holds the time when the response was received by
your application.  The format and semantics of the header are the
same as the server created "Date" header.  You may also encounter other
"Client-XXX" headers.  They are all generated by the library
internally and are not received from the servers.

=head2 HTTP Requests

HTTP requests are just handed off to an HTTP server and it
decides what happens.  Few servers implement methods beside the usual
"GET", "HEAD", "POST" and "PUT", but CGI-scripts may implement
any method they like.

If the server is not available then the library will generate an
internal error response.

The library automatically adds a "Host" and a "Content-Length" header
to the HTTP request before it is sent over the network.

For a GET request you might want to add an "If-Modified-Since" or
"If-None-Match" header to make the request conditional.

For a POST request you should add the "Content-Type" header.  When you
try to emulate HTML E<lt>FORM> handling you should usually let the value
of the "Content-Type" header be "application/x-www-form-urlencoded".
See L<lwpcook> for examples of this.

The libwww-perl HTTP implementation currently support the HTTP/1.1
and HTTP/1.0 protocol.

The library allows you to access proxy server through HTTP.  This
means that you can set up the library to forward all types of request
through the HTTP protocol module.  See L<LWP::UserAgent> for
documentation of this.


=head2 HTTPS Requests

HTTPS requests are HTTP requests over an encrypted network connection
using the SSL protocol developed by Netscape.  Everything about HTTP
requests above also apply to HTTPS requests.  In addition the library
will add the headers "Client-SSL-Cipher", "Client-SSL-Cert-Subject" and
"Client-SSL-Cert-Issuer" to the response.  These headers denote the
encryption method used and the name of the server owner.

The request can contain the header "If-SSL-Cert-Subject" in order to
make the request conditional on the content of the server certificate.
If the certificate subject does not match, no request is sent to the
server and an internally generated error response is returned.  The
value of the "If-SSL-Cert-Subject" header is interpreted as a Perl
regular expression.


=head2 FTP Requests

The library currently supports GET, HEAD and PUT requests.  GET
retrieves a file or a directory listing from an FTP server.  PUT
stores a file on a ftp server.

You can specify a ftp account for servers that want this in addition
to user name and password.  This is specified by including an "Account"
header in the request.

User name/password can be specified using basic authorization or be
encoded in the URL.  Failed logins return an UNAUTHORIZED response with
"WWW-Authenticate: Basic" and can be treated like basic authorization
for HTTP.

The library supports ftp ASCII transfer mode by specifying the "type=a"
parameter in the URL. It also supports transfer of ranges for FTP transfers
using the "Range" header.

Directory listings are by default returned unprocessed (as returned
from the ftp server) with the content media type reported to be
"text/ftp-dir-listing". The L<File::Listing> module provides methods
for parsing of these directory listing.

The ftp module is also able to convert directory listings to HTML and
this can be requested via the standard HTTP content negotiation
mechanisms (add an "Accept: text/html" header in the request if you
want this).

For normal file retrievals, the "Content-Type" is guessed based on the
file name suffix. See L<LWP::MediaTypes>.

The "If-Modified-Since" request header works for servers that implement
the C<MDTM> command.  It will probably not work for directory listings though.

Example:

  $req = HTTP::Request->new(GET => 'ftp://me:passwd@ftp.some.where.com/');
  $req->header(Accept => "text/html, */*;q=0.1");

=head2 News Requests

Access to the USENET News system is implemented through the NNTP
protocol.  The name of the news server is obtained from the
NNTP_SERVER environment variable and defaults to "news".  It is not
possible to specify the hostname of the NNTP server in news: URLs.

The library supports GET and HEAD to retrieve news articles through the
NNTP protocol.  You can also post articles to newsgroups by using
(surprise!) the POST method.

GET on newsgroups is not implemented yet.

Examples:

  $req = HTTP::Request->new(GET => 'news:abc1234@a.sn.no');

  $req = HTTP::Request->new(POST => 'news:comp.lang.perl.test');
  $req->header(Subject => 'This is a test',
               From    => 'me@some.where.org');
  $req->content(<<EOT);
  This is the content of the message that we are sending to
  the world.
  EOT


=head2 Gopher Request

The library supports the GET and HEAD methods for gopher requests.  All
request header values are ignored.  HEAD cheats and returns a
response without even talking to server.

Gopher menus are always converted to HTML.

The response "Content-Type" is generated from the document type
encoded (as the first letter) in the request URL path itself.

Example:

  $req = HTTP::Request->new(GET => 'gopher://gopher.sn.no/');



=head2 File Request

The library supports GET and HEAD methods for file requests.  The
"If-Modified-Since" header is supported.  All other headers are
ignored.  The I<host> component of the file URL must be empty or set
to "localhost".  Any other I<host> value will be treated as an error.

Directories are always converted to an HTML document.  For normal
files, the "Content-Type" and "Content-Encoding" in the response are
guessed based on the file suffix.

Example:

  $req = HTTP::Request->new(GET => 'file:/etc/passwd');


=head2 Mailto Request

You can send (aka "POST") mail messages using the library.  All
headers specified for the request are passed on to the mail system.
The "To" header is initialized from the mail address in the URL.

Example:

  $req = HTTP::Request->new(POST => 'mailto:libwww@perl.org');
  $req->header(Subject => "subscribe");
  $req->content("Please subscribe me to the libwww-perl mailing list!\n");

=head2 CPAN Requests

URLs with scheme C<cpan:> are redirected to a suitable CPAN
mirror.  If you have your own local mirror of CPAN you might tell LWP
to use it for C<cpan:> URLs by an assignment like this:

  $LWP::Protocol::cpan::CPAN = "file:/local/CPAN/";

Suitable CPAN mirrors are also picked up from the configuration for
the CPAN.pm, so if you have used that module a suitable mirror should
be picked automatically.  If neither of these apply, then a redirect
to the generic CPAN http location is issued.

Example request to download the newest perl:

  $req = HTTP::Request->new(GET => "cpan:src/latest.tar.gz");


=head1 OVERVIEW OF CLASSES AND PACKAGES

This table should give you a quick overview of the classes provided by the
library. Indentation shows class inheritance.

 LWP::MemberMixin   -- Access to member variables of Perl5 classes
   LWP::UserAgent   -- WWW user agent class
     LWP::RobotUA   -- When developing a robot applications
   LWP::Protocol          -- Interface to various protocol schemes
     LWP::Protocol::http  -- http:// access
     LWP::Protocol::file  -- file:// access
     LWP::Protocol::ftp   -- ftp:// access
     ...

 LWP::Authen::Basic -- Handle 401 and 407 responses
 LWP::Authen::Digest

 HTTP::Headers      -- MIME/RFC822 style header (used by HTTP::Message)
 HTTP::Message      -- HTTP style message
   HTTP::Request    -- HTTP request
   HTTP::Response   -- HTTP response
 HTTP::Daemon       -- A HTTP server class

 WWW::RobotRules    -- Parse robots.txt files
   WWW::RobotRules::AnyDBM_File -- Persistent RobotRules

 Net::HTTP          -- Low level HTTP client

The following modules provide various functions and definitions.

 LWP                -- This file.  Library version number and documentation.
 LWP::MediaTypes    -- MIME types configuration (text/html etc.)
 LWP::Simple        -- Simplified procedural interface for common functions
 HTTP::Status       -- HTTP status code (200 OK etc)
 HTTP::Date         -- Date parsing module for HTTP date formats
 HTTP::Negotiate    -- HTTP content negotiation calculation
 File::Listing      -- Parse directory listings
 HTML::Form         -- Processing for <form>s in HTML documents


=head1 MORE DOCUMENTATION

All modules contain detailed information on the interfaces they
provide.  The L<lwpcook> manpage is the libwww-perl cookbook that contain
examples of typical usage of the library.  You might want to take a
look at how the scripts L<lwp-request>, L<lwp-download>, L<lwp-dump>
and L<lwp-mirror> are implemented.

=head1 ENVIRONMENT

The following environment variables are used by LWP:

=over

=item HOME

The L<LWP::MediaTypes> functions will look for the F<.media.types> and
F<.mime.types> files relative to you home directory.

=item http_proxy

=item ftp_proxy

=item xxx_proxy

=item no_proxy

These environment variables can be set to enable communication through
a proxy server.  See the description of the C<env_proxy> method in
L<LWP::UserAgent>.

=item PERL_LWP_ENV_PROXY

If set to a TRUE value, then the L<LWP::UserAgent> will by default call
C<env_proxy> during initialization.  This makes LWP honor the proxy variables
described above.

=item PERL_LWP_SSL_VERIFY_HOSTNAME

The default C<verify_hostname> setting for L<LWP::UserAgent>.  If
not set the default will be 1.  Set it as 0 to disable hostname
verification (the default prior to libwww-perl 5.840.

=item PERL_LWP_SSL_CA_FILE

=item PERL_LWP_SSL_CA_PATH

The file and/or directory
where the trusted Certificate Authority certificates
is located.  See L<LWP::UserAgent> for details.

=item PERL_HTTP_URI_CLASS

Used to decide what URI objects to instantiate.  The default is L<URI>.
You might want to set it to L<URI::URL> for compatibility with old times.

=back

=head1 AUTHORS

LWP was made possible by contributions from Adam Newby, Albert
Dvornik, Alexandre Duret-Lutz, Andreas Gustafsson, Andreas König,
Andrew Pimlott, Andy Lester, Ben Coleman, Benjamin Low, Ben Low, Ben
Tilly, Blair Zajac, Bob Dalgleish, BooK, Brad Hughes, Brian
J. Murrell, Brian McCauley, Charles C. Fu, Charles Lane, Chris Nandor,
Christian Gilmore, Chris W. Unger, Craig Macdonald, Dale Couch, Dan
Kubb, Dave Dunkin, Dave W. Smith, David Coppit, David Dick, David
D. Kilzer, Doug MacEachern, Edward Avis, erik, Gary Shea, Gisle Aas,
Graham Barr, Gurusamy Sarathy, Hans de Graaff, Harald Joerg, Harry
Bochner, Hugo, Ilya Zakharevich, INOUE Yoshinari, Ivan Panchenko, Jack
Shirazi, James Tillman, Jan Dubois, Jared Rhine, Jim Stern, Joao
Lopes, John Klar, Johnny Lee, Josh Kronengold, Josh Rai, Joshua
Chamas, Joshua Hoblitt, Kartik Subbarao, Keiichiro Nagano, Ken
Williams, KONISHI Katsuhiro, Lee T Lindley, Liam Quinn, Marc Hedlund,
Marc Langheinrich, Mark D. Anderson, Marko Asplund, Mark Stosberg,
Markus B Krüger, Markus Laker, Martijn Koster, Martin Thurn, Matthew
Eldridge, Matthew.van.Eerde, Matt Sergeant, Michael A. Chase, Michael
Quaranta, Michael Thompson, Mike Schilli, Moshe Kaminsky, Nathan
Torkington, Nicolai Langfeldt, Norton Allen, Olly Betts, Paul
J. Schinder, peterm, Philip Guenther, Daniel Buenzli, Pon Hwa Lin,
Radoslaw Zielinski, Radu Greab, Randal L. Schwartz, Richard Chen,
Robin Barker, Roy Fielding, Sander van Zoest, Sean M. Burke,
shildreth, Slaven Rezic, Steve A Fink, Steve Hay, Steven Butler,
Steve_Kilbane, Takanori Ugai, Thomas Lotterer, Tim Bunce, Tom Hughes,
Tony Finch, Ville Skyttä, Ward Vandewege, William York, Yale Huang,
and Yitzchak Scott-Thoennes.

LWP owes a lot in motivation, design, and code, to the libwww-perl
library for Perl4 by Roy Fielding, which included work from Alberto
Accomazzi, James Casey, Brooks Cutter, Martijn Koster, Oscar
Nierstrasz, Mel Melchner, Gertjan van Oosten, Jared Rhine, Jack
Shirazi, Gene Spafford, Marc VanHeyningen, Steven E. Brenner, Marion
Hakanson, Waldemar Kebsch, Tony Sanders, and Larry Wall; see the
libwww-perl-0.40 library for details.

=head1 COPYRIGHT

  Copyright 1995-2009, Gisle Aas
  Copyright 1995, Martijn Koster

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

=head1 AVAILABILITY

The latest version of this library is likely to be available from CPAN
as well as:

  http://github.com/libwww-perl/libwww-perl

The best place to discuss this code is on the <libwww@perl.org>
mailing list.

=cut
PK1N%[av“+�+perl5/WWW/RobotRules.pmnu��6�$package WWW::RobotRules;

$VERSION = "6.02";
sub Version { $VERSION; }

use strict;
use URI ();



sub new {
    my($class, $ua) = @_;

    # This ugly hack is needed to ensure backwards compatibility.
    # The "WWW::RobotRules" class is now really abstract.
    $class = "WWW::RobotRules::InCore" if $class eq "WWW::RobotRules";

    my $self = bless { }, $class;
    $self->agent($ua);
    $self;
}


sub parse {
    my($self, $robot_txt_uri, $txt, $fresh_until) = @_;
    $robot_txt_uri = URI->new("$robot_txt_uri");
    my $netloc = $robot_txt_uri->host . ":" . $robot_txt_uri->port;

    $self->clear_rules($netloc);
    $self->fresh_until($netloc, $fresh_until || (time + 365*24*3600));

    my $ua;
    my $is_me = 0;		# 1 iff this record is for me
    my $is_anon = 0;		# 1 iff this record is for *
    my $seen_disallow = 0;      # watch for missing record separators
    my @me_disallowed = ();	# rules disallowed for me
    my @anon_disallowed = ();	# rules disallowed for *

    # blank lines are significant, so turn CRLF into LF to avoid generating
    # false ones
    $txt =~ s/\015\012/\012/g;

    # split at \012 (LF) or \015 (CR) (Mac text files have just CR for EOL)
    for(split(/[\012\015]/, $txt)) {

	# Lines containing only a comment are discarded completely, and
        # therefore do not indicate a record boundary.
	next if /^\s*\#/;

	s/\s*\#.*//;        # remove comments at end-of-line

	if (/^\s*$/) {	    # blank line
	    last if $is_me; # That was our record. No need to read the rest.
	    $is_anon = 0;
	    $seen_disallow = 0;
	}
        elsif (/^\s*User-Agent\s*:\s*(.*)/i) {
	    $ua = $1;
	    $ua =~ s/\s+$//;

	    if ($seen_disallow) {
		# treat as start of a new record
		$seen_disallow = 0;
		last if $is_me; # That was our record. No need to read the rest.
		$is_anon = 0;
	    }

	    if ($is_me) {
		# This record already had a User-agent that
		# we matched, so just continue.
	    }
	    elsif ($ua eq '*') {
		$is_anon = 1;
	    }
	    elsif($self->is_me($ua)) {
		$is_me = 1;
	    }
	}
	elsif (/^\s*Disallow\s*:\s*(.*)/i) {
	    unless (defined $ua) {
		warn "RobotRules <$robot_txt_uri>: Disallow without preceding User-agent\n" if $^W;
		$is_anon = 1;  # assume that User-agent: * was intended
	    }
	    my $disallow = $1;
	    $disallow =~ s/\s+$//;
	    $seen_disallow = 1;
	    if (length $disallow) {
		my $ignore;
		eval {
		    my $u = URI->new_abs($disallow, $robot_txt_uri);
		    $ignore++ if $u->scheme ne $robot_txt_uri->scheme;
		    $ignore++ if lc($u->host) ne lc($robot_txt_uri->host);
		    $ignore++ if $u->port ne $robot_txt_uri->port;
		    $disallow = $u->path_query;
		    $disallow = "/" unless length $disallow;
		};
		next if $@;
		next if $ignore;
	    }

	    if ($is_me) {
		push(@me_disallowed, $disallow);
	    }
	    elsif ($is_anon) {
		push(@anon_disallowed, $disallow);
	    }
	}
        elsif (/\S\s*:/) {
             # ignore
        }
	else {
	    warn "RobotRules <$robot_txt_uri>: Malformed record: <$_>\n" if $^W;
	}
    }

    if ($is_me) {
	$self->push_rules($netloc, @me_disallowed);
    }
    else {
	$self->push_rules($netloc, @anon_disallowed);
    }
}


#
# Returns TRUE if the given name matches the
# name of this robot
#
sub is_me {
    my($self, $ua_line) = @_;
    my $me = $self->agent;

    # See whether my short-name is a substring of the
    #  "User-Agent: ..." line that we were passed:

    if(index(lc($me), lc($ua_line)) >= 0) {
      return 1;
    }
    else {
      return '';
    }
}


sub allowed {
    my($self, $uri) = @_;
    $uri = URI->new("$uri");

    return 1 unless $uri->scheme eq 'http' or $uri->scheme eq 'https';
     # Robots.txt applies to only those schemes.

    my $netloc = $uri->host . ":" . $uri->port;

    my $fresh_until = $self->fresh_until($netloc);
    return -1 if !defined($fresh_until) || $fresh_until < time;

    my $str = $uri->path_query;
    my $rule;
    for $rule ($self->rules($netloc)) {
	return 1 unless length $rule;
	return 0 if index($str, $rule) == 0;
    }
    return 1;
}


# The following methods must be provided by the subclass.
sub agent;
sub visit;
sub no_visits;
sub last_visits;
sub fresh_until;
sub push_rules;
sub clear_rules;
sub rules;
sub dump;



package WWW::RobotRules::InCore;

use vars qw(@ISA);
@ISA = qw(WWW::RobotRules);



sub agent {
    my ($self, $name) = @_;
    my $old = $self->{'ua'};
    if ($name) {
        # Strip it so that it's just the short name.
        # I.e., "FooBot"                                      => "FooBot"
        #       "FooBot/1.2"                                  => "FooBot"
        #       "FooBot/1.2 [http://foobot.int; foo@bot.int]" => "FooBot"

	$name = $1 if $name =~ m/(\S+)/; # get first word
	$name =~ s!/.*!!;  # get rid of version
	unless ($old && $old eq $name) {
	    delete $self->{'loc'}; # all old info is now stale
	    $self->{'ua'} = $name;
	}
    }
    $old;
}


sub visit {
    my($self, $netloc, $time) = @_;
    return unless $netloc;
    $time ||= time;
    $self->{'loc'}{$netloc}{'last'} = $time;
    my $count = \$self->{'loc'}{$netloc}{'count'};
    if (!defined $$count) {
	$$count = 1;
    }
    else {
	$$count++;
    }
}


sub no_visits {
    my ($self, $netloc) = @_;
    $self->{'loc'}{$netloc}{'count'};
}


sub last_visit {
    my ($self, $netloc) = @_;
    $self->{'loc'}{$netloc}{'last'};
}


sub fresh_until {
    my ($self, $netloc, $fresh_until) = @_;
    my $old = $self->{'loc'}{$netloc}{'fresh'};
    if (defined $fresh_until) {
	$self->{'loc'}{$netloc}{'fresh'} = $fresh_until;
    }
    $old;
}


sub push_rules {
    my($self, $netloc, @rules) = @_;
    push (@{$self->{'loc'}{$netloc}{'rules'}}, @rules);
}


sub clear_rules {
    my($self, $netloc) = @_;
    delete $self->{'loc'}{$netloc}{'rules'};
}


sub rules {
    my($self, $netloc) = @_;
    if (defined $self->{'loc'}{$netloc}{'rules'}) {
	return @{$self->{'loc'}{$netloc}{'rules'}};
    }
    else {
	return ();
    }
}


sub dump
{
    my $self = shift;
    for (keys %$self) {
	next if $_ eq 'loc';
	print "$_ = $self->{$_}\n";
    }
    for (keys %{$self->{'loc'}}) {
	my @rules = $self->rules($_);
	print "$_: ", join("; ", @rules), "\n";
    }
}


1;

__END__


# Bender: "Well, I don't have anything else
#          planned for today.  Let's get drunk!"

=head1 NAME

WWW::RobotRules - database of robots.txt-derived permissions

=head1 SYNOPSIS

 use WWW::RobotRules;
 my $rules = WWW::RobotRules->new('MOMspider/1.0');

 use LWP::Simple qw(get);

 {
   my $url = "http://some.place/robots.txt";
   my $robots_txt = get $url;
   $rules->parse($url, $robots_txt) if defined $robots_txt;
 }

 {
   my $url = "http://some.other.place/robots.txt";
   my $robots_txt = get $url;
   $rules->parse($url, $robots_txt) if defined $robots_txt;
 }

 # Now we can check if a URL is valid for those servers
 # whose "robots.txt" files we've gotten and parsed:
 if($rules->allowed($url)) {
     $c = get $url;
     ...
 }

=head1 DESCRIPTION

This module parses F</robots.txt> files as specified in
"A Standard for Robot Exclusion", at
<http://www.robotstxt.org/wc/norobots.html>
Webmasters can use the F</robots.txt> file to forbid conforming
robots from accessing parts of their web site.

The parsed files are kept in a WWW::RobotRules object, and this object
provides methods to check if access to a given URL is prohibited.  The
same WWW::RobotRules object can be used for one or more parsed
F</robots.txt> files on any number of hosts.

The following methods are provided:

=over 4

=item $rules = WWW::RobotRules->new($robot_name)

This is the constructor for WWW::RobotRules objects.  The first
argument given to new() is the name of the robot.

=item $rules->parse($robot_txt_url, $content, $fresh_until)

The parse() method takes as arguments the URL that was used to
retrieve the F</robots.txt> file, and the contents of the file.

=item $rules->allowed($uri)

Returns TRUE if this robot is allowed to retrieve this URL.

=item $rules->agent([$name])

Get/set the agent name. NOTE: Changing the agent name will clear the robots.txt
rules and expire times out of the cache.

=back

=head1 ROBOTS.TXT

The format and semantics of the "/robots.txt" file are as follows
(this is an edited abstract of
<http://www.robotstxt.org/wc/norobots.html>):

The file consists of one or more records separated by one or more
blank lines. Each record contains lines of the form

  <field-name>: <value>

The field name is case insensitive.  Text after the '#' character on a
line is ignored during parsing.  This is used for comments.  The
following <field-names> can be used:

=over 3

=item User-Agent

The value of this field is the name of the robot the record is
describing access policy for.  If more than one I<User-Agent> field is
present the record describes an identical access policy for more than
one robot. At least one field needs to be present per record.  If the
value is '*', the record describes the default access policy for any
robot that has not not matched any of the other records.

The I<User-Agent> fields must occur before the I<Disallow> fields.  If a
record contains a I<User-Agent> field after a I<Disallow> field, that
constitutes a malformed record.  This parser will assume that a blank
line should have been placed before that I<User-Agent> field, and will
break the record into two.  All the fields before the I<User-Agent> field
will constitute a record, and the I<User-Agent> field will be the first
field in a new record.

=item Disallow

The value of this field specifies a partial URL that is not to be
visited. This can be a full path, or a partial path; any URL that
starts with this value will not be retrieved

=back

Unrecognized records are ignored.

=head1 ROBOTS.TXT EXAMPLES

The following example "/robots.txt" file specifies that no robots
should visit any URL starting with "/cyberworld/map/" or "/tmp/":

  User-agent: *
  Disallow: /cyberworld/map/ # This is an infinite virtual URL space
  Disallow: /tmp/ # these will soon disappear

This example "/robots.txt" file specifies that no robots should visit
any URL starting with "/cyberworld/map/", except the robot called
"cybermapper":

  User-agent: *
  Disallow: /cyberworld/map/ # This is an infinite virtual URL space

  # Cybermapper knows where to go.
  User-agent: cybermapper
  Disallow:

This example indicates that no robots should visit this site further:

  # go away
  User-agent: *
  Disallow: /

This is an example of a malformed robots.txt file.

  # robots.txt for ancientcastle.example.com
  # I've locked myself away.
  User-agent: *
  Disallow: /
  # The castle is your home now, so you can go anywhere you like.
  User-agent: Belle
  Disallow: /west-wing/ # except the west wing!
  # It's good to be the Prince...
  User-agent: Beast
  Disallow:

This file is missing the required blank lines between records.
However, the intention is clear.

=head1 SEE ALSO

L<LWP::RobotUA>, L<WWW::RobotRules::AnyDBM_File>

=head1 COPYRIGHT

  Copyright 1995-2009, Gisle Aas
  Copyright 1995, Martijn Koster

This library is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
PK1N%[�<��!!#perl5/WWW/RobotRules/AnyDBM_File.pmnu��6�$package WWW::RobotRules::AnyDBM_File;

require  WWW::RobotRules;
@ISA = qw(WWW::RobotRules);
$VERSION = "6.00";

use Carp ();
use AnyDBM_File;
use Fcntl;
use strict;

=head1 NAME

WWW::RobotRules::AnyDBM_File - Persistent RobotRules

=head1 SYNOPSIS

 require WWW::RobotRules::AnyDBM_File;
 require LWP::RobotUA;

 # Create a robot useragent that uses a diskcaching RobotRules
 my $rules = WWW::RobotRules::AnyDBM_File->new( 'my-robot/1.0', 'cachefile' );
 my $ua = WWW::RobotUA->new( 'my-robot/1.0', 'me@foo.com', $rules );

 # Then just use $ua as usual
 $res = $ua->request($req);

=head1 DESCRIPTION

This is a subclass of I<WWW::RobotRules> that uses the AnyDBM_File
package to implement persistent diskcaching of F<robots.txt> and host
visit information.

The constructor (the new() method) takes an extra argument specifying
the name of the DBM file to use.  If the DBM file already exists, then
you can specify undef as agent name as the name can be obtained from
the DBM database.

=cut

sub new 
{ 
  my ($class, $ua, $file) = @_;
  Carp::croak('WWW::RobotRules::AnyDBM_File filename required') unless $file;

  my $self = bless { }, $class;
  $self->{'filename'} = $file;
  tie %{$self->{'dbm'}}, 'AnyDBM_File', $file, O_CREAT|O_RDWR, 0640
    or Carp::croak("Can't open $file: $!");
  
  if ($ua) {
      $self->agent($ua);
  }
  else {
      # Try to obtain name from DBM file
      $ua = $self->{'dbm'}{"|ua-name|"};
      Carp::croak("No agent name specified") unless $ua;
  }

  $self;
}

sub agent {
    my($self, $newname) = @_;
    my $old = $self->{'dbm'}{"|ua-name|"};
    if (defined $newname) {
	$newname =~ s!/?\s*\d+.\d+\s*$!!;  # loose version
	unless ($old && $old eq $newname) {
	# Old info is now stale.
	    my $file = $self->{'filename'};
	    untie %{$self->{'dbm'}};
	    tie %{$self->{'dbm'}}, 'AnyDBM_File', $file, O_TRUNC|O_RDWR, 0640;
	    %{$self->{'dbm'}} = ();
	    $self->{'dbm'}{"|ua-name|"} = $newname;
	}
    }
    $old;
}

sub no_visits {
    my ($self, $netloc) = @_;
    my $t = $self->{'dbm'}{"$netloc|vis"};
    return 0 unless $t;
    (split(/;\s*/, $t))[0];
}

sub last_visit {
    my ($self, $netloc) = @_;
    my $t = $self->{'dbm'}{"$netloc|vis"};
    return undef unless $t;
    (split(/;\s*/, $t))[1];
}

sub fresh_until {
    my ($self, $netloc, $fresh) = @_;
    my $old = $self->{'dbm'}{"$netloc|exp"};
    if ($old) {
	$old =~ s/;.*//;  # remove cleartext
    }
    if (defined $fresh) {
	$fresh .= "; " . localtime($fresh);
	$self->{'dbm'}{"$netloc|exp"} = $fresh;
    }
    $old;
}

sub visit {
    my($self, $netloc, $time) = @_;
    $time ||= time;

    my $count = 0;
    my $old = $self->{'dbm'}{"$netloc|vis"};
    if ($old) {
	my $last;
	($count,$last) = split(/;\s*/, $old);
	$time = $last if $last > $time;
    }
    $count++;
    $self->{'dbm'}{"$netloc|vis"} = "$count; $time; " . localtime($time);
}

sub push_rules {
    my($self, $netloc, @rules) = @_;
    my $cnt = 1;
    $cnt++ while $self->{'dbm'}{"$netloc|r$cnt"};

    foreach (@rules) {
	$self->{'dbm'}{"$netloc|r$cnt"} = $_;
	$cnt++;
    }
}

sub clear_rules {
    my($self, $netloc) = @_;
    my $cnt = 1;
    while ($self->{'dbm'}{"$netloc|r$cnt"}) {
	delete $self->{'dbm'}{"$netloc|r$cnt"};
	$cnt++;
    }
}

sub rules {
    my($self, $netloc) = @_;
    my @rules = ();
    my $cnt = 1;
    while (1) {
	my $rule = $self->{'dbm'}{"$netloc|r$cnt"};
	last unless $rule;
	push(@rules, $rule);
	$cnt++;
    }
    @rules;
}

sub dump
{
}

1;

=head1 SEE ALSO

L<WWW::RobotRules>, L<LWP::RobotUA>

=head1 AUTHORS

Hakan Ardo E<lt>hakan@munin.ub2.lu.se>, Gisle Aas E<lt>aas@sn.no>

=cut

PK1N%[���\��perl5/AppConfig/Args.pmnu��6�$#============================================================================
#
# AppConfig::Args.pm
#
# Perl5 module to read command line argument and update the variable 
# values in an AppConfig::State object accordingly.
#
# Written by Andy Wardley <abw@wardley.org>
#
# Copyright (C) 1997-2007 Andy Wardley.  All Rights Reserved.
# Copyright (C) 1997,1998 Canon Research Centre Europe Ltd.
#============================================================================

package AppConfig::Args;
use 5.006;
use strict;
use warnings;
use AppConfig::State;
our $VERSION = '1.71';


#------------------------------------------------------------------------
# new($state, \@args)
#
# Module constructor.  The first, mandatory parameter should be a 
# reference to an AppConfig::State object to which all actions should 
# be applied.  The second parameter may be a reference to a list of 
# command line arguments.  This list reference is passed to args() for
# processing.
#
# Returns a reference to a newly created AppConfig::Args object.
#------------------------------------------------------------------------

sub new {
    my $class = shift;
    my $state = shift;


    my $self = {
        STATE    => $state,                # AppConfig::State ref
        DEBUG    => $state->_debug(),      # store local copy of debug
        PEDANTIC => $state->_pedantic,     # and pedantic flags
    };

    bless $self, $class;

    # call parse() to parse any arg list passed 
    $self->parse(shift)
        if @_;

    return $self;
}


#------------------------------------------------------------------------
# parse(\@args)
#
# Examines the argument list and updates the contents of the 
# AppConfig::State referenced by $self->{ STATE } accordingly.  If 
# no argument list is provided then the method defaults to examining 
# @ARGV.  The method reports any warning conditions (such as undefined
# variables) by calling $self->{ STATE }->_error() and then continues to
# examine the rest of the list.  If the PEDANTIC option is set in the
# AppConfig::State object, this behaviour is overridden and the method
# returns 0 immediately on any parsing error.
#
# Returns 1 on success or 0 if one or more warnings were raised.
#------------------------------------------------------------------------

sub parse {
    my $self = shift;
    my $argv = shift || \@ARGV;
    my $warnings = 0;
    my ($arg, $nargs, $variable, $value);


    # take a local copy of the state to avoid much hash dereferencing
    my ($state, $debug, $pedantic) = @$self{ qw( STATE DEBUG PEDANTIC ) };

    # loop around arguments
    ARG: while (@$argv && $argv->[0] =~ /^-/) {
        $arg = shift(@$argv);

        # '--' indicates the end of the options
        last if $arg eq '--';

        # strip leading '-';
        ($variable = $arg) =~ s/^-(-)?//;

        # test for '--' prefix and push back any '=value' item
        if (defined $1) {
            ($variable, $value) = split(/=/, $variable);
            unshift(@$argv, $value) if defined $value;
        }

        # check the variable exists
        if ($state->_exists($variable)) {

            # see if it expects any mandatory arguments
            $nargs = $state->_argcount($variable);
            if ($nargs) {
                # check there's another arg and it's not another '-opt'
                if(defined($argv->[0])) {
                    $value = shift(@$argv);
                }
                else {
                    $state->_error("$arg expects an argument");
                    $warnings++;
                    last ARG if $pedantic;
                    next;
                }
            }
            else {
                # set a value of 1 if option doesn't expect an argument
                $value = 1;
            }

            # set the variable with the new value
            $state->set($variable, $value);
        }
        else {
            $state->_error("$arg: invalid option");
            $warnings++;
            last ARG if $pedantic;
        }
    }

    # return status
    return $warnings ? 0 : 1;
}



1;

__END__

=head1 NAME

AppConfig::Args - Perl5 module for reading command line arguments.

=head1 SYNOPSIS

    use AppConfig::Args;

    my $state   = AppConfig::State->new(\%cfg);
    my $cfgargs = AppConfig::Args->new($state);

    $cfgargs->parse(\@args);            # read args

=head1 OVERVIEW

AppConfig::Args is a Perl5 module which reads command line arguments and 
uses the options therein to update variable values in an AppConfig::State 
object.

AppConfig::File is distributed as part of the AppConfig bundle.

=head1 DESCRIPTION

=head2 USING THE AppConfig::Args MODULE

To import and use the AppConfig::Args module the following line should appear
in your Perl script:

    use AppConfig::Args;

AppConfig::Args is used automatically if you use the AppConfig module 
and create an AppConfig::Args object through the parse() method.

AppConfig::File is implemented using object-oriented methods.  A new 
AppConfig::Args object is created and initialised using the new() method.
This returns a reference to a new AppConfig::File object.  A reference to
an AppConfig::State object should be passed in as the first parameter:

    my $state   = AppConfig::State->new();
    my $cfgargs = AppConfig::Args->new($state);

This will create and return a reference to a new AppConfig::Args object. 

=head2 PARSING COMMAND LINE ARGUMENTS

The C<parse()> method is used to read a list of command line arguments and 
update the STATE accordingly.  A reference to the list of arguments should
be passed in.

    $cfgargs->parse(\@ARGV);

If the method is called without a reference to an argument list then it
will examine and manipulate @ARGV.

If the PEDANTIC option is turned off in the AppConfig::State object, any 
parsing errors (invalid variables, unvalidated values, etc) will generate
warnings, but not cause the method to return.  Having processed all
arguments, the method will return 1 if processed without warning or 0 if
one or more warnings were raised.  When the PEDANTIC option is turned on,
the method generates a warning and immediately returns a value of 0 as soon
as it encounters any parsing error.

The method continues parsing arguments until it detects the first one that
does not start with a leading dash, '-'.  Arguments that constitute values
for other options are not examined in this way.

=head1 FUTURE DEVELOPMENT

This module was developed to provide backwards compatibility (to some 
degree) with the preceeding App::Config module.  The argument parsing 
it provides is basic but offers a quick and efficient solution for those
times when simple option handling is all that is required.

If you require more flexibility in parsing command line arguments, then 
you should consider using the AppConfig::Getopt module.  This is loaded 
and used automatically by calling the AppConfig getopt() method.

The AppConfig::Getopt module provides considerably extended functionality 
over the AppConfig::Args module by delegating out the task of argument 
parsing to Johan Vromans' Getopt::Long module.  For advanced command-line 
parsing, this module (either Getopt::Long by itself, or in conjunction with 
AppConfig::Getopt) is highly recommended.

=head1 AUTHOR

Andy Wardley, E<lt>abw@wardley.orgE<gt>

=head1 COPYRIGHT

Copyright (C) 1997-2007 Andy Wardley.  All Rights Reserved.

Copyright (C) 1997,1998 Canon Research Centre Europe Ltd.

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

=head1 SEE ALSO

AppConfig, AppConfig::State, AppConfig::Getopt, Getopt::Long

=cut
PK1N%[���Lperl5/AppConfig/CGI.pmnu��6�$#============================================================================
#
# AppConfig::CGI.pm
#
# Perl5 module to provide a CGI interface to AppConfig.  Internal variables
# may be set through the CGI "arguments" appended to a URL.
# 
# Written by Andy Wardley <abw@wardley.org>
#
# Copyright (C) 1997-2003 Andy Wardley.  All Rights Reserved.
# Copyright (C) 1997,1998 Canon Research Centre Europe Ltd.
#
#============================================================================

package AppConfig::CGI;
use 5.006;
use strict;
use warnings;
use AppConfig::State;
our $VERSION = '1.71';


#------------------------------------------------------------------------
# new($state, $query)
#
# Module constructor.  The first, mandatory parameter should be a 
# reference to an AppConfig::State object to which all actions should 
# be applied.  The second parameter may be a string containing a CGI
# QUERY_STRING which is then passed to parse() to process.  If no second
# parameter is specifiied then the parse() process is skipped.
#
# Returns a reference to a newly created AppConfig::CGI object.
#------------------------------------------------------------------------

sub new {
    my $class = shift;
    my $state = shift;
    my $self  = {
        STATE    => $state,                # AppConfig::State ref
        DEBUG    => $state->_debug(),      # store local copy of debug
        PEDANTIC => $state->_pedantic,     # and pedantic flags
    };
    bless $self, $class;

    # call parse(@_) to parse any arg list passed 
    $self->parse(@_)
        if @_;

    return $self;
}


#------------------------------------------------------------------------
# parse($query)
#
# Method used to parse a CGI QUERY_STRING and set internal variable 
# values accordingly.  If a query is not passed as the first parameter,
# then _get_cgi_query() is called to try to determine the query by 
# examing the environment as per CGI protocol.
#
# Returns 0 if one or more errors or warnings were raised or 1 if the
# string parsed successfully.
#------------------------------------------------------------------------

sub parse {
    my $self     = shift;
    my $query    = shift;
    my $warnings = 0;
    my ($variable, $value, $nargs);


    # take a local copy of the state to avoid much hash dereferencing
    my ($state, $debug, $pedantic) = @$self{ qw( STATE DEBUG PEDANTIC ) };

    # get the cgi query if not defined
    $query = $ENV{ QUERY_STRING }
        unless defined $query;

    # no query to process
    return 1 unless defined $query;

    # we want to install a custom error handler into the AppConfig::State 
    # which appends filename and line info to error messages and then 
    # calls the previous handler;  we start by taking a copy of the 
    # current handler..
    my $errhandler = $state->_ehandler();

    # install a closure as a new error handler
    $state->_ehandler(
        sub {
            # modify the error message 
            my $format  = shift;
            $format =~ s/</&lt;/g;
            $format =~ s/>/&gt;/g;
            $format  = "<p>\n<b>[ AppConfig::CGI error: </b>$format<b> ] </b>\n<p>\n";
            # send error to stdout for delivery to web client
            printf($format, @_);
        }
    );


    PARAM: foreach (split('&', $query)) {

        # extract parameter and value from query token
        ($variable, $value) = map { _unescape($_) } split('=');

        # check an argument was provided if one was expected
        if ($nargs = $state->_argcount($variable)) {
            unless (defined $value) {
                $state->_error("$variable expects an argument");
                $warnings++;
                last PARAM if $pedantic;
                next;
            }
        }
        # default an undefined value to 1 if ARGCOUNT_NONE
        else {
            $value = 1 unless defined $value;
        }

        # set the variable, noting any error
        unless ($state->set($variable, $value)) {
            $warnings++;
            last PARAM if $pedantic;
        }
    }

    # restore original error handler
    $state->_ehandler($errhandler);

    # return $warnings => 0, $success => 1
    return $warnings ? 0 : 1;
}



# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# The following sub-routine was lifted from Lincoln Stein's CGI.pm
# module, version 2.36.  Name has been prefixed by a '_'.

# unescape URL-encoded data
sub _unescape {
    my($todecode) = @_;
    $todecode =~ tr/+/ /;       # pluses become spaces
    $todecode =~ s/%([0-9a-fA-F]{2})/pack("c",hex($1))/ge;
    return $todecode;
}

#
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -




1;

__END__

=head1 NAME

AppConfig::CGI - Perl5 module for processing CGI script parameters.

=head1 SYNOPSIS

    use AppConfig::CGI;

    my $state = AppConfig::State->new(\%cfg);
    my $cgi   = AppConfig::CGI->new($state);

    $cgi->parse($cgi_query);
    $cgi->parse();               # looks for CGI query in environment

=head1 OVERVIEW

AppConfig::CGI is a Perl5 module which implements a CGI interface to 
AppConfig.  It examines the QUERY_STRING environment variable, or a string
passed explicitly by parameter, which represents the additional parameters
passed to a CGI query.  This is then used to update variable values in an
AppConfig::State object accordingly.

AppConfig::CGI is distributed as part of the AppConfig bundle.

=head1 DESCRIPTION

=head2 USING THE AppConfig::CGI MODULE

To import and use the AppConfig::CGI module the following line should appear
in your Perl script:

    use AppConfig::CGI;

AppConfig::CGI is used automatically if you use the AppConfig module
and create an AppConfig::CGI object through the cgi() method.
AppConfig::CGI is implemented using object-oriented methods.  A new
AppConfig::CGI object is created and initialised using the new()
method.  This returns a reference to a new AppConfig::CGI object.  A
reference to an AppConfig::State object should be passed in as the
first parameter: 

    my $state = AppConfig::State->new(); 
    my $cgi   = AppConfig::CGI->new($state);

This will create and return a reference to a new AppConfig::CGI object. 

=head2 PARSING CGI QUERIES

The C<parse()> method is used to parse a CGI query which can be specified 
explicitly, or is automatically extracted from the "QUERY_STRING" CGI 
environment variable.  This currently limits the module to only supporting 
the GET method.

See AppConfig for information about using the AppConfig::CGI
module via the cgi() method.

=head1 AUTHOR

Andy Wardley, C<E<lt>abw@wardley.org<gt>>

=head1 COPYRIGHT

Copyright (C) 1997-2007 Andy Wardley.  All Rights Reserved.

Copyright (C) 1997,1998 Canon Research Centre Europe Ltd.

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

=head1 SEE ALSO

AppConfig, AppConfig::State

=cut

PK1N%[�k��))perl5/AppConfig/Sys.pmnu��6�$#============================================================================
#
# AppConfig::Sys.pm
#
# Perl5 module providing platform-specific information and operations as 
# required by other AppConfig::* modules.
#
# Written by Andy Wardley <abw@wardley.org>
#
# Copyright (C) 1997-2003 Andy Wardley.  All Rights Reserved.
# Copyright (C) 1997,1998 Canon Research Centre Europe Ltd.
#
# $Id: Sys.pm,v 1.61 2004/02/04 10:11:23 abw Exp $
#
#============================================================================

package AppConfig::Sys;
use 5.006;
use strict;
use warnings;
use POSIX qw( getpwnam getpwuid );

our $VERSION = '1.71';
our ($AUTOLOAD, $OS, %CAN, %METHOD);


BEGIN {
    # define the methods that may be available
    if($^O =~ m/win32/i) {
        $METHOD{ getpwuid } = sub { 
            return wantarray() 
                ? ( (undef) x 7, getlogin() )
                : getlogin(); 
        };
        $METHOD{ getpwnam } = sub { 
            die("Can't getpwnam on win32"); 
        };
    }
    else
    {
        $METHOD{ getpwuid } = sub { 
            getpwuid( defined $_[0] ? shift : $< ); 
        };
        $METHOD{ getpwnam } = sub { 
            getpwnam( defined $_[0] ? shift : '' );
        };
    }

    # try out each METHOD to see if it's supported on this platform;
    # it's important we do this before defining AUTOLOAD which would
    # otherwise catch the unresolved call
    foreach my $method  (keys %METHOD) {
        eval { &{ $METHOD{ $method } }() };
    	$CAN{ $method } = ! $@;
    }
}



#------------------------------------------------------------------------
# new($os)
#
# Module constructor.  An optional operating system string may be passed
# to explicitly define the platform type.
#
# Returns a reference to a newly created AppConfig::Sys object.
#------------------------------------------------------------------------

sub new {
    my $class = shift;

    my $self = {
        METHOD => \%METHOD,
        CAN    => \%CAN,
    };

    bless $self, $class;

    $self->_configure(@_);
	
    return $self;
}


#------------------------------------------------------------------------
# AUTOLOAD
#
# Autoload function called whenever an unresolved object method is 
# called.  If the method name relates to a METHODS entry, then it is 
# called iff the corresponding CAN_$method is set true.  If the 
# method name relates to a CAN_$method value then that is returned.
#------------------------------------------------------------------------

sub AUTOLOAD {
    my $self = shift;
    my $method;


    # splat the leading package name
    ($method = $AUTOLOAD) =~ s/.*:://;

    # ignore destructor
    $method eq 'DESTROY' && return;

    # can_method()
    if ($method =~ s/^can_//i && exists $self->{ CAN }->{ $method }) {
        return $self->{ CAN }->{ $method };
    }
    # method() 
    elsif (exists $self->{ METHOD }->{ $method }) {
        if ($self->{ CAN }->{ $method }) {
            return &{ $self->{ METHOD }->{ $method } }(@_);
        }
        else {
            return undef;
        }
    } 
    # variable
    elsif (exists $self->{ uc $method }) {
        return $self->{ uc $method };
    }
    else {
        warn("AppConfig::Sys->", $method, "(): no such method or variable\n");
    }

    return undef;
}


#------------------------------------------------------------------------
# _configure($os)
#
# Uses the first parameter, $os, the package variable $AppConfig::Sys::OS,
# the value of $^O, or as a last resort, the value of
# $Config::Config('osname') to determine the current operating
# system/platform.  Sets internal variables accordingly.
#------------------------------------------------------------------------

sub _configure {
    my $self = shift;

    # operating system may be defined as a parameter or in $OS
    my $os = shift || $OS;


    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
    # The following was lifted (and adapated slightly) from Lincoln Stein's 
    # CGI.pm module, version 2.36...
    #
    # FIGURE OUT THE OS WE'RE RUNNING UNDER
    # Some systems support the $^O variable.  If not
    # available then require() the Config library
    unless ($os) {
	unless ($os = $^O) {
	    require Config;
	    $os = $Config::Config{'osname'};
	}
    }
    if ($os =~ /win32/i) {
        $os = 'WINDOWS';
    } elsif ($os =~ /vms/i) {
        $os = 'VMS';
    } elsif ($os =~ /mac/i) {
        $os = 'MACINTOSH';
    } elsif ($os =~ /os2/i) {
        $os = 'OS2';
    } else {
        $os = 'UNIX';
    }


    # The path separator is a slash, backslash or semicolon, depending
    # on the platform.
    my $ps = {
        UNIX      => '/',
        OS2       => '\\',
        WINDOWS   => '\\',
        MACINTOSH => ':',
        VMS       => '\\'
    }->{ $os };
    #
    # Thanks Lincoln!
    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 


    $self->{ OS      } = $os;
    $self->{ PATHSEP } = $ps;
}


#------------------------------------------------------------------------
# _dump()
#
# Dump internals for debugging.
#------------------------------------------------------------------------

sub _dump {
    my $self = shift;

    print "=" x 71, "\n";
    print "Status of AppConfig::Sys (Version $VERSION) object: $self\n";
    print "    Operating System : ", $self->{ OS      }, "\n";
    print "      Path Separator : ", $self->{ PATHSEP }, "\n";
    print "   Available methods :\n";
    foreach my $can (keys %{ $self->{ CAN } }) {
        printf "%20s : ", $can;
        print  $self->{ CAN }->{ $can } ? "yes" : "no", "\n";
    }
    print "=" x 71, "\n";
}



1;

__END__

=pod

=head1 NAME

AppConfig::Sys - Perl5 module defining platform-specific information and methods for other AppConfig::* modules.

=head1 SYNOPSIS

    use AppConfig::Sys;
    my $sys = AppConfig::Sys->new();

    @fields = $sys->getpwuid($userid);
    @fields = $sys->getpwnam($username);

=head1 OVERVIEW

AppConfig::Sys is a Perl5 module provides platform-specific information and
operations as required by other AppConfig::* modules.

AppConfig::Sys is distributed as part of the AppConfig bundle.

=head1 DESCRIPTION

=head2 USING THE AppConfig::Sys MODULE

To import and use the AppConfig::Sys module the following line should
appear in your Perl script:

     use AppConfig::Sys;

AppConfig::Sys is implemented using object-oriented methods.  A new
AppConfig::Sys object is created and initialised using the
AppConfig::Sys->new() method.  This returns a reference to a new
AppConfig::Sys object.  

    my $sys = AppConfig::Sys->new();

This will attempt to detect your operating system and create a reference to
a new AppConfig::Sys object that is applicable to your platform.  You may 
explicitly specify an operating system name to override this automatic 
detection:

    $unix_sys = AppConfig::Sys->new("Unix");

Alternatively, the package variable $AppConfig::Sys::OS can be set to an
operating system name.  The valid operating system names are: Win32, VMS,
Mac, OS2 and Unix.  They are not case-specific.

=head2 AppConfig::Sys METHODS

AppConfig::Sys defines the following methods:

=over 4

=item getpwnam()

Calls the system function getpwnam() if available and returns the result.
Returns undef if not available.  The can_getpwnam() method can be called to
determine if this function is available.

=item getpwuid()

Calls the system function getpwuid() if available and returns the result.
Returns undef if not available.  The can_getpwuid() method can be called to
determine if this function is available.

=back

=head1 AUTHOR

Andy Wardley, E<lt>abw@wardley.orgE<gt>

=head1 COPYRIGHT

Copyright (C) 1997-2007 Andy Wardley.  All Rights Reserved.

Copyright (C) 1997,1998 Canon Research Centre Europe Ltd.

This module is free software; you can redistribute it and/or modify it under 
the term of the Perl Artistic License.

=head1 SEE ALSO

AppConfig, AppConfig::File

=cut
PK1N%[��f���perl5/AppConfig/State.pmnu��6�$#============================================================================
#
# AppConfig::State.pm
#
# Perl5 module in which configuration information for an application can
# be stored and manipulated.  AppConfig::State objects maintain knowledge 
# about variables; their identities, options, aliases, targets, callbacks 
# and so on.  This module is used by a number of other AppConfig::* modules.
#
# Written by Andy Wardley <abw@wardley.org>
#
# Copyright (C) 1997-2007 Andy Wardley.  All Rights Reserved.
# Copyright (C) 1997,1998 Canon Research Centre Europe Ltd.
#
#----------------------------------------------------------------------------
#
# TODO
#
# * Change varlist() to varhash() and provide another varlist() method
#   which returns a list.  Multiple parameters passed implies a hash 
#   slice/list grep, a single parameter should indicate a regex.
#
# * Perhaps allow a callback to be installed which is called *instead* of 
#   the get() and set() methods (or rather, is called by them).
#
# * Maybe CMDARG should be in there to specify extra command-line only 
#   options that get added to the AppConfig::GetOpt alias construction, 
#   but not applied in config files, general usage, etc.  The GLOBAL 
#   CMDARG might be specified as a format, e.g. "-%c" where %s = name, 
#   %c = first character, %u - first unique sequence(?).  Will 
#   GetOpt::Long handle --long to -l application automagically?
#
# * ..and an added thought is that CASE sensitivity may be required for the
#   command line (-v vs -V, -r vs -R, for example), but not for parsing 
#   config files where you may wish to treat "Name", "NAME" and "name" alike.
#
#============================================================================

package AppConfig::State;
use 5.006;
use strict;
use warnings;

our $VERSION = '1.71';
our $DEBUG   = 0;
our $AUTOLOAD;

# need access to AppConfig::ARGCOUNT_*
use AppConfig ':argcount';

# internal per-variable hashes that AUTOLOAD should provide access to
my %METHVARS;
   @METHVARS{ qw( EXPAND ARGS ARGCOUNT ) } = ();

# internal values that AUTOLOAD should provide access to
my %METHFLAGS;
   @METHFLAGS{ qw( PEDANTIC ) } = ();

# variable attributes that may be specified in GLOBAL;
my @GLOBAL_OK = qw( DEFAULT EXPAND VALIDATE ACTION ARGS ARGCOUNT );


#------------------------------------------------------------------------
# new(\%config, @vars)
#
# Module constructor.  A reference to a hash array containing 
# configuration options may be passed as the first parameter.  This is 
# passed off to _configure() for processing.  See _configure() for 
# information about configurarion options.  The remaining parameters
# may be variable definitions and are passed en masse to define() for
# processing.
#
# Returns a reference to a newly created AppConfig::State object.
#------------------------------------------------------------------------

sub new {
    my $class = shift;

    my $self = {
        # internal hash arrays to store variable specification information
        VARIABLE   => { },     # variable values
        DEFAULT    => { },     # default values
        ALIAS      => { },     # known aliases  ALIAS => VARIABLE
        ALIASES    => { },     # reverse alias lookup VARIABLE => ALIASES
        ARGCOUNT   => { },     # arguments expected
        ARGS       => { },     # specific argument pattern (AppConfig::Getopt)
        EXPAND     => { },     # variable expansion (AppConfig::File)
        VALIDATE   => { },     # validation regexen or functions
        ACTION     => { },     # callback functions for when variable is set
        GLOBAL     => { },     # default global settings for new variables

        # other internal data
        CREATE     => 0,       # auto-create variables when set
        CASE       => 0,       # case sensitivity flag (1 = sensitive)
        PEDANTIC   => 0,       # return immediately on parse warnings
        EHANDLER   => undef,   # error handler (let's hope we don't need it!)
        ERROR      => '',      # error message
    };

    bless $self, $class;

    # configure if first param is a config hash ref
    $self->_configure(shift)
        if ref($_[0]) eq 'HASH';

    # call define(@_) to handle any variables definitions
    $self->define(@_)
        if @_;

    return $self;
}


#------------------------------------------------------------------------
# define($variable, \%cfg, [$variable, \%cfg, ...])
#
# Defines one or more variables.  The first parameter specifies the 
# variable name.  The following parameter may reference a hash of 
# configuration options for the variable.  Further variables and 
# configuration hashes may follow and are processed in turn.  If the 
# parameter immediately following a variable name isn't a hash reference 
# then it is ignored and the variable is defined without a specific 
# configuration, although any default parameters as specified in the 
# GLOBAL option will apply.
#
# The $variable value may contain an alias/args definition in compact
# format, such as "Foo|Bar=1".  
#
# A warning is issued (via _error()) if an invalid option is specified.
#------------------------------------------------------------------------

sub define {
    my $self = shift;
    my ($var, $args, $count, $opt, $val, $cfg, @names);

    while (@_) {
        $var = shift;
        $cfg = ref($_[0]) eq 'HASH' ? shift : { };

        # variable may be specified in compact format, 'foo|bar=i@'
        if ($var =~ s/(.+?)([!+=:].*)/$1/) {

            # anything coming after the name|alias list is the ARGS
            $cfg->{ ARGS } = $2
                if length $2;
        }

        # examine any ARGS option
        if (defined ($args = $cfg->{ ARGS })) {
          ARGGCOUNT: {
              $count = ARGCOUNT_NONE, last if $args =~ /^!/;
              $count = ARGCOUNT_LIST, last if $args =~ /@/;
              $count = ARGCOUNT_HASH, last if $args =~ /%/;
              $count = ARGCOUNT_ONE;
          }
            $cfg->{ ARGCOUNT } = $count;
        }

        # split aliases out
        @names = split(/\|/, $var);
        $var = shift @names;
        $cfg->{ ALIAS } = [ @names ] if @names;

        # variable name gets folded to lower unless CASE sensitive
        $var = lc $var unless $self->{ CASE };

        # activate $variable (so it does 'exist()') 
        $self->{ VARIABLE }->{ $var } = undef;

        # merge GLOBAL and variable-specific configurations
        $cfg = { %{ $self->{ GLOBAL } }, %$cfg };

        # examine each variable configuration parameter
        while (($opt, $val) = each %$cfg) {
            $opt = uc $opt;

            # DEFAULT, VALIDATE, EXPAND, ARGS and ARGCOUNT are stored as 
            # they are;
            $opt =~ /^DEFAULT|VALIDATE|EXPAND|ARGS|ARGCOUNT$/ && do {
                $self->{ $opt }->{ $var } = $val;
                next;
            };

            # CMDARG has been deprecated
            $opt eq 'CMDARG' && do {
                $self->_error("CMDARG has been deprecated.  "
                              . "Please use an ALIAS if required.");
                next;
            };

            # ACTION should be a code ref
            $opt eq 'ACTION' && do {
                unless (ref($val) eq 'CODE') {
                    $self->_error("'$opt' value is not a code reference");
                    next;
                };

                # store code ref, forcing keyword to upper case
                $self->{ ACTION }->{ $var } = $val;

                next;
            };

            # ALIAS creates alias links to the variable name
            $opt eq 'ALIAS' && do {

                # coerce $val to an array if not already so
                $val = [ split(/\|/, $val) ]
                    unless ref($val) eq 'ARRAY';

                # fold to lower case unless CASE sensitivity set
                unless ($self->{ CASE }) {
                    @$val = map { lc } @$val;
                }

                # store list of aliases...
                $self->{ ALIASES }->{ $var } = $val;

                # ...and create ALIAS => VARIABLE lookup hash entries
                foreach my $a (@$val) {
                    $self->{ ALIAS }->{ $a } = $var;
                }

                next;
            };

            # default 
            $self->_error("$opt is not a valid configuration item");
        }

        # set variable to default value
        $self->_default($var);

        # DEBUG: dump new variable definition
        if ($DEBUG) {
            print STDERR "Variable defined:\n";
            $self->_dump_var($var);
        }
    }
}


#------------------------------------------------------------------------
# get($variable)
#
# Returns the value of the variable specified, $variable.  Returns undef
# if the variable does not exists or is undefined and send a warning
# message to the _error() function.
#------------------------------------------------------------------------

sub get {
    my $self     = shift;
    my $variable = shift;
    my $negate   = 0;
    my $value;

    # _varname returns variable name after aliasing and case conversion
    # $negate indicates if the name got converted from "no<var>" to "<var>"
    $variable = $self->_varname($variable, \$negate);

    # check the variable has been defined
    unless (exists($self->{ VARIABLE }->{ $variable })) {
        $self->_error("$variable: no such variable");
        return undef;
    }

    # DEBUG
    print STDERR "$self->get($variable) => ", 
           defined $self->{ VARIABLE }->{ $variable }
                  ? $self->{ VARIABLE }->{ $variable }
                  : "<undef>",
          "\n"
          if $DEBUG;

    # return variable value, possibly negated if the name was "no<var>"
    $value = $self->{ VARIABLE }->{ $variable };

    return $negate ? !$value : $value;
}


#------------------------------------------------------------------------
# set($variable, $value)
#
# Assigns the value, $value, to the variable specified.
#
# Returns 1 if the variable is successfully updated or 0 if the variable 
# does not exist.  If an ACTION sub-routine exists for the variable, it 
# will be executed and its return value passed back.
#------------------------------------------------------------------------

sub set {
    my $self     = shift;
    my $variable = shift;
    my $value    = shift;
    my $negate   = 0;
    my $create;

    # _varname returns variable name after aliasing and case conversion
    # $negate indicates if the name got converted from "no<var>" to "<var>"
    $variable = $self->_varname($variable, \$negate);

    # check the variable exists
    if (exists($self->{ VARIABLE }->{ $variable })) {
        # variable found, so apply any value negation
        $value = $value ? 0 : 1 if $negate;
    }
    else {
        # auto-create variable if CREATE is 1 or a pattern matching 
        # the variable name (real name, not an alias)
        $create = $self->{ CREATE };
        if (defined $create
            && ($create eq '1' || $variable =~ /$create/)) {
            $self->define($variable);

            print STDERR "Auto-created $variable\n" if $DEBUG;
        }
        else {
            $self->_error("$variable: no such variable");
            return 0;
        }
    }

    # call the validate($variable, $value) method to perform any validation
    unless ($self->_validate($variable, $value)) {
        $self->_error("$variable: invalid value: $value");
        return 0;
    }

    # DEBUG
    print STDERR "$self->set($variable, ", 
    defined $value
        ? $value
        : "<undef>",
        ")\n"
        if $DEBUG;


    # set the variable value depending on its ARGCOUNT
    my $argcount = $self->{ ARGCOUNT }->{ $variable };
    $argcount = AppConfig::ARGCOUNT_ONE unless defined $argcount;

    if ($argcount eq AppConfig::ARGCOUNT_LIST) {
        # push value onto the end of the list
        push(@{ $self->{ VARIABLE }->{ $variable } }, $value);
    }
    elsif ($argcount eq AppConfig::ARGCOUNT_HASH) {
        # insert "<key>=<value>" data into hash 
        my ($k, $v) = split(/\s*=\s*/, $value, 2);
        # strip quoting
        $v =~ s/^(['"])(.*)\1$/$2/ if defined $v;
        $self->{ VARIABLE }->{ $variable }->{ $k } = $v;
    }
    else {
        # set simple variable
        $self->{ VARIABLE }->{ $variable } = $value;
    }


    # call any ACTION function bound to this variable
    return &{ $self->{ ACTION }->{ $variable } }($self, $variable, $value)
        if (exists($self->{ ACTION }->{ $variable }));

    # ...or just return 1 (ok)
    return 1;
}


#------------------------------------------------------------------------
# varlist($criteria, $filter)
#
# Returns a hash array of all variables and values whose real names 
# match the $criteria regex pattern passed as the first parameter.
# If $filter is set to any true value, the keys of the hash array 
# (variable names) will have the $criteria part removed.  This allows 
# the caller to specify the variables from one particular [block] and
# have the "block_" prefix removed, for example.  
#
# TODO: This should be changed to varhash().  varlist() should return a 
# list.  Also need to consider specification by list rather than regex.
#
#------------------------------------------------------------------------

sub varlist {
    my $self     = shift;
    my $criteria = shift;
    my $strip    = shift;

    $criteria = "" unless defined $criteria;

    # extract relevant keys and slice out corresponding values
    my @keys = grep(/$criteria/, keys %{ $self->{ VARIABLE } });
    my @vals = @{ $self->{ VARIABLE } }{ @keys };
    my %set;

    # clean off the $criteria part if $strip is set
    @keys = map { s/$criteria//; $_ } @keys if $strip;

    # slice values into the target hash 
    @set{ @keys } = @vals;
    return %set;
}


#------------------------------------------------------------------------
# AUTOLOAD
#
# Autoload function called whenever an unresolved object method is 
# called.  If the method name relates to a defined VARIABLE, we patch
# in $self->get() and $self->set() to magically update the varaiable
# (if a parameter is supplied) and return the previous value.
#
# Thus the function can be used in the folowing ways:
#    $state->variable(123);     # set a new value
#    $foo = $state->variable(); # get the current value
#
# Returns the current value of the variable, taken before any new value
# is set.  Prints a warning if the variable isn't defined (i.e. doesn't
# exist rather than exists with an undef value) and returns undef.
#------------------------------------------------------------------------

sub AUTOLOAD {
    my $self = shift;
    my ($variable, $attrib);


    # splat the leading package name
    ($variable = $AUTOLOAD) =~ s/.*:://;

    # ignore destructor
    $variable eq 'DESTROY' && return;


    # per-variable attributes and internal flags listed as keys in 
    # %METHFLAGS and %METHVARS respectively can be accessed by a 
    # method matching the attribute or flag name in lower case with 
    # a leading underscore_
    if (($attrib = $variable) =~ s/_//g) {
        $attrib = uc $attrib;

        if (exists $METHFLAGS{ $attrib }) {
            return $self->{ $attrib };
        }

        if (exists $METHVARS{ $attrib }) {
            # next parameter should be variable name
            $variable = shift;
            $variable = $self->_varname($variable);

            # check we've got a valid variable
#           $self->_error("$variable: no such variable or method"), 
#                   return undef
#               unless exists($self->{ VARIABLE }->{ $variable });

            # return attribute
            return $self->{ $attrib }->{ $variable };
        }
    }

    # set a new value if a parameter was supplied or return the old one
    return defined($_[0])
           ? $self->set($variable, shift)
           : $self->get($variable);
}



#========================================================================
#                      -----  PRIVATE METHODS -----
#========================================================================

#------------------------------------------------------------------------
# _configure(\%cfg)
#
# Sets the various configuration options using the values passed in the
# hash array referenced by $cfg.
#------------------------------------------------------------------------

sub _configure {
    my $self = shift;
    my $cfg  = shift || return;

    # construct a regex to match values which are ok to be found in GLOBAL
    my $global_ok = join('|', @GLOBAL_OK);

    foreach my $opt (keys %$cfg) {

        # GLOBAL must be a hash ref
        $opt =~ /^GLOBALS?$/i && do {
            unless (ref($cfg->{ $opt }) eq 'HASH') {
                $self->_error("\U$opt\E parameter is not a hash ref");
                next;
            }

            # we check each option is ok to be in GLOBAL, but we don't do 
            # any error checking on the values they contain (but should?).
            foreach my $global ( keys %{ $cfg->{ $opt } } )  {

                # continue if the attribute is ok to be GLOBAL 
                next if ($global =~ /(^$global_ok$)/io);

                $self->_error( "\U$global\E parameter cannot be GLOBAL");
            }
            $self->{ GLOBAL } = $cfg->{ $opt };
            next;
        };

        # CASE, CREATE and PEDANTIC are stored as they are
        $opt =~ /^CASE|CREATE|PEDANTIC$/i && do {
            $self->{ uc $opt } = $cfg->{ $opt };
            next;
        };

        # ERROR triggers $self->_ehandler()
        $opt =~ /^ERROR$/i && do {
            $self->_ehandler($cfg->{ $opt });
            next;
        };

        # DEBUG triggers $self->_debug()
        $opt =~ /^DEBUG$/i && do {
            $self->_debug($cfg->{ $opt });
            next;
        };

        # warn about invalid options
        $self->_error("\U$opt\E is not a valid configuration option");
    }
}


#------------------------------------------------------------------------
# _varname($variable, \$negated)
#
# Variable names are treated case-sensitively or insensitively, depending 
# on the value of $self->{ CASE }.  When case-insensitive ($self->{ CASE } 
# != 0), all variable names are converted to lower case.  Variable values 
# are not converted.  This function simply converts the parameter 
# (variable) to lower case if $self->{ CASE } isn't set.  _varname() also 
# expands a variable alias to the name of the target variable.  
#
# Variables with an ARGCOUNT of ARGCOUNT_ZERO may be specified as 
# "no<var>" in which case, the intended value should be negated.  The 
# leading "no" part is stripped from the variable name.  A reference to 
# a scalar value can be passed as the second parameter and if the 
# _varname() method identified such a variable, it will negate the value.  
# This allows the intended value or a simple negate flag to be passed by
# reference and be updated to indicate any negation activity taking place.
#
# The (possibly modified) variable name is returned.
#------------------------------------------------------------------------

sub _varname {
    my $self     = shift;
    my $variable = shift;
    my $negated  = shift;

    # convert to lower case if case insensitive
    $variable = $self->{ CASE } ? $variable : lc $variable;

    # get the actual name if this is an alias
    $variable = $self->{ ALIAS }->{ $variable }
        if (exists($self->{ ALIAS }->{ $variable }));

    # if the variable doesn't exist, we can try to chop off a leading 
    # "no" and see if the remainder matches an ARGCOUNT_ZERO variable
    unless (exists($self->{ VARIABLE }->{ $variable })) {
        # see if the variable is specified as "no<var>"
        if ($variable =~ /^no(.*)/) {
            # see if the real variable (minus "no") exists and it
            # has an ARGOUNT of ARGCOUNT_NONE (or no ARGCOUNT at all)
            my $novar = $self->_varname($1);
            if (exists($self->{ VARIABLE }->{ $novar })
                && ! $self->{ ARGCOUNT }->{ $novar }) {
                # set variable name and negate value 
                $variable = $novar;
                $$negated = ! $$negated if defined $negated;
            }
        }
    }

    # return the variable name
    $variable;
}


#------------------------------------------------------------------------
# _default($variable)
#
# Sets the variable specified to the default value or undef if it doesn't
# have a default.  The default value is returned.
#------------------------------------------------------------------------

sub _default {
    my $self     = shift;
    my $variable = shift;

    # _varname returns variable name after aliasing and case conversion
    $variable = $self->_varname($variable);

    # check the variable exists
    if (exists($self->{ VARIABLE }->{ $variable })) {
        # set variable value to the default scalar, an empty list or empty
        # hash array, depending on its ARGCOUNT value
        my $argcount = $self->{ ARGCOUNT }->{ $variable };
        $argcount = AppConfig::ARGCOUNT_ONE unless defined $argcount;

        if ($argcount == AppConfig::ARGCOUNT_NONE) {
            return $self->{ VARIABLE }->{ $variable } 
                 = $self->{ DEFAULT }->{ $variable } || 0;
        }
        elsif ($argcount == AppConfig::ARGCOUNT_LIST) {
            my $deflist = $self->{ DEFAULT }->{ $variable };
            return $self->{ VARIABLE }->{ $variable } = 
                [ ref $deflist eq 'ARRAY' ? @$deflist : ( ) ];

        }
        elsif ($argcount == AppConfig::ARGCOUNT_HASH) {
            my $defhash = $self->{ DEFAULT }->{ $variable };
            return $self->{ VARIABLE }->{ $variable } = 
            { ref $defhash eq 'HASH' ? %$defhash : () };
        }
        else {
            return $self->{ VARIABLE }->{ $variable } 
                 = $self->{ DEFAULT }->{ $variable };
        }
    }
    else {
        $self->_error("$variable: no such variable");
        return 0;
    }
}


#------------------------------------------------------------------------
# _exists($variable)
#
# Returns 1 if the variable specified exists or 0 if not.
#------------------------------------------------------------------------

sub _exists {
    my $self     = shift;
    my $variable = shift;


    # _varname returns variable name after aliasing and case conversion
    $variable = $self->_varname($variable);

    # check the variable has been defined
    return exists($self->{ VARIABLE }->{ $variable });
}


#------------------------------------------------------------------------
# _validate($variable, $value)
#
# Uses any validation rules or code defined for the variable to test if
# the specified value is acceptable.
#
# Returns 1 if the value passed validation checks, 0 if not.
#------------------------------------------------------------------------

sub _validate {
    my $self     = shift;
    my $variable = shift;
    my $value    = shift;
    my $validator;


    # _varname returns variable name after aliasing and case conversion
    $variable = $self->_varname($variable);

    # return OK unless there is a validation function
    return 1 unless defined($validator = $self->{ VALIDATE }->{ $variable });

    #
    # the validation performed is based on the validator type;
    #
    #   CODE ref: code executed, returning 1 (ok) or 0 (failed)
    #   SCALAR  : a regex which should match the value
    #

    # CODE ref
    ref($validator) eq 'CODE' && do {
        # run the validation function and return the result
        return &$validator($variable, $value);
    };

    # non-ref (i.e. scalar)
    ref($validator) || do {
        # not a ref - assume it's a regex
        return $value =~ /$validator/;
    };

    # validation failed
    return 0;
}


#------------------------------------------------------------------------
# _error($format, @params)
#
# Checks for the existence of a user defined error handling routine and
# if defined, passes all variable straight through to that.  The routine
# is expected to handle a string format and optional parameters as per
# printf(3C).  If no error handler is defined, the message is formatted
# and passed to warn() which prints it to STDERR.
#------------------------------------------------------------------------

sub _error {
    my $self   = shift;
    my $format = shift;

    # user defined error handler?
    if (ref($self->{ EHANDLER }) eq 'CODE') {
        &{ $self->{ EHANDLER } }($format, @_);
    }
    else {
        warn(sprintf("$format\n", @_));
    }
}


#------------------------------------------------------------------------
# _ehandler($handler)
#
# Allows a new error handler to be installed.  The current value of 
# the error handler is returned.
#
# This is something of a kludge to allow other AppConfig::* modules to 
# install their own error handlers to format error messages appropriately.
# For example, AppConfig::File appends a message of the form 
# "at $file line $line" to each error message generated while parsing 
# configuration files.  The previous handler is returned (and presumably
# stored by the caller) to allow new error handlers to chain control back
# to any user-defined handler, and also restore the original handler when 
# done.
#------------------------------------------------------------------------

sub _ehandler {
    my $self    = shift;
    my $handler = shift;

    # save previous value
    my $previous = $self->{ EHANDLER };

    # update internal reference if a new handler vas provide
    if (defined $handler) {
        # check this is a code reference
        if (ref($handler) eq 'CODE') {
            $self->{ EHANDLER } = $handler;

            # DEBUG
            print STDERR "installed new ERROR handler: $handler\n" if $DEBUG;
        }
        else {
            $self->_error("ERROR handler parameter is not a code ref");
        }
    }

    return $previous;
}


#------------------------------------------------------------------------
# _debug($debug)
#
# Sets the package debugging variable, $AppConfig::State::DEBUG depending 
# on the value of the $debug parameter.  1 turns debugging on, 0 turns 
# debugging off.
#
# May be called as an object method, $state->_debug(1), or as a package
# function, AppConfig::State::_debug(1).  Returns the previous value of 
# $DEBUG, before any new value was applied.
#------------------------------------------------------------------------

sub _debug {
    # object reference may not be present if called as a package function
    my $self   = shift if ref($_[0]);
    my $newval = shift;

    # save previous value
    my $oldval = $DEBUG;

    # update $DEBUG if a new value was provided
    $DEBUG = $newval if defined $newval;

    # return previous value
    $oldval;
}


#------------------------------------------------------------------------
# _dump_var($var)
#
# Displays the content of the specified variable, $var.
#------------------------------------------------------------------------

sub _dump_var {
    my $self   = shift;
    my $var    = shift;

    return unless defined $var;

    # $var may be an alias, so we resolve the real variable name
    my $real = $self->_varname($var);
    if ($var eq $real) {
        print STDERR "$var\n";
    }
    else {
        print STDERR "$real  ('$var' is an alias)\n";
        $var = $real;
    }

    # for some bizarre reason, the variable VALUE is stored in VARIABLE
    # (it made sense at some point in time)
    printf STDERR "    VALUE        => %s\n", 
                defined($self->{ VARIABLE }->{ $var }) 
                    ? $self->{ VARIABLE }->{ $var } 
                    : "<undef>";

    # the rest of the values can be read straight out of their hashes
    foreach my $param (qw( DEFAULT ARGCOUNT VALIDATE ACTION EXPAND )) {
        printf STDERR "    %-12s => %s\n", $param, 
                defined($self->{ $param }->{ $var }) 
                    ? $self->{ $param }->{ $var } 
                    : "<undef>";
    }

    # summarise all known aliases for this variable
    print STDERR "    ALIASES      => ", 
            join(", ", @{ $self->{ ALIASES }->{ $var } }), "\n"
            if defined $self->{ ALIASES }->{ $var };
} 


#------------------------------------------------------------------------
# _dump()
#
# Dumps the contents of the Config object and all stored variables.  
#------------------------------------------------------------------------

sub _dump {
    my $self = shift;
    my $var;

    print STDERR "=" x 71, "\n";
    print STDERR 
        "Status of AppConfig::State (version $VERSION) object:\n\t$self\n";


    print STDERR "- " x 36, "\nINTERNAL STATE:\n";
    foreach (qw( CREATE CASE PEDANTIC EHANDLER ERROR )) {
        printf STDERR "    %-12s => %s\n", $_, 
                defined($self->{ $_ }) ? $self->{ $_ } : "<undef>";
    }       

    print STDERR "- " x 36, "\nVARIABLES:\n";
    foreach $var (keys %{ $self->{ VARIABLE } }) {
        $self->_dump_var($var);
    }

    print STDERR "- " x 36, "\n", "ALIASES:\n";
    foreach $var (keys %{ $self->{ ALIAS } }) {
        printf("    %-12s => %s\n", $var, $self->{ ALIAS }->{ $var });
    }
    print STDERR "=" x 72, "\n";
} 



1;

__END__

=head1 NAME

AppConfig::State - application configuration state

=head1 SYNOPSIS

    use AppConfig::State;

    my $state = AppConfig::State->new(\%cfg);

    $state->define("foo");            # very simple variable definition
    $state->define("bar", \%varcfg);  # variable specific configuration
    $state->define("foo|bar=i@");     # compact format

    $state->set("foo", 123);          # trivial set/get examples
    $state->get("foo");      

    $state->foo();                    # shortcut variable access 
    $state->foo(456);                 # shortcut variable update 

=head1 OVERVIEW

AppConfig::State is a Perl5 module to handle global configuration variables
for perl programs.  It maintains the state of any number of variables,
handling default values, aliasing, validation, update callbacks and 
option arguments for use by other AppConfig::* modules.  

AppConfig::State is distributed as part of the AppConfig bundle.

=head1 DESCRIPTION

=head2 USING THE AppConfig::State MODULE

To import and use the AppConfig::State module the following line should 
appear in your Perl script:

     use AppConfig::State;

The AppConfig::State module is loaded automatically by the new()
constructor of the AppConfig module.

AppConfig::State is implemented using object-oriented methods.  A 
new AppConfig::State object is created and initialised using the 
new() method.  This returns a reference to a new AppConfig::State 
object.

    my $state = AppConfig::State->new();

This will create a reference to a new AppConfig::State with all 
configuration options set to their default values.  You can initialise 
the object by passing a reference to a hash array containing 
configuration options:

    $state = AppConfig::State->new( {
        CASE      => 1,
        ERROR     => \&my_error,
    } );

The new() constructor of the AppConfig module automatically passes all 
parameters to the AppConfig::State new() constructor.  Thus, any global 
configuration values and variable definitions for AppConfig::State are 
also applicable to AppConfig.

The following configuration options may be specified.  

=over 4

=item CASE

Determines if the variable names are treated case sensitively.  Any non-zero
value makes case significant when naming variables.  By default, CASE is set
to 0 and thus "Variable", "VARIABLE" and "VaRiAbLe" are all treated as 
"variable".

=item CREATE

By default, CREATE is turned off meaning that all variables accessed via
set() (which includes access via shortcut such as 
C<$state-E<gt>variable($value)> which delegates to set()) must previously 
have been defined via define().  When CREATE is set to 1, calling 
set($variable, $value) on a variable that doesn't exist will cause it 
to be created automatically.

When CREATE is set to any other non-zero value, it is assumed to be a
regular expression pattern.  If the variable name matches the regex, the
variable is created.  This can be used to specify configuration file 
blocks in which variables should be created, for example:

    $state = AppConfig::State->new( {
        CREATE => '^define_',
    } );

In a config file:

    [define]
    name = fred           # define_name gets created automatically

    [other]
    name = john           # other_name doesn't - warning raised

Note that a regex pattern specified in CREATE is applied to the real 
variable name rather than any alias by which the variables may be 
accessed.  

=item PEDANTIC

The PEDANTIC option determines what action the configuration file 
(AppConfig::File) or argument parser (AppConfig::Args) should take 
on encountering a warning condition (typically caused when trying to set an
undeclared variable).  If PEDANTIC is set to any true value, the parsing
methods will immediately return a value of 0 on encountering such a
condition.  If PEDANTIC is not set, the method will continue to parse the
remainder of the current file(s) or arguments, returning 0 when complete.

If no warnings or errors are encountered, the method returns 1.

In the case of a system error (e.g. unable to open a file), the method
returns undef immediately, regardless of the PEDANTIC option.

=item ERROR

Specifies a user-defined error handling routine.  When the handler is 
called, a format string is passed as the first parameter, followed by 
any additional values, as per printf(3C).

=item DEBUG

Turns debugging on or off when set to 1 or 0 accordingly.  Debugging may 
also be activated by calling _debug() as an object method 
(C<$state-E<gt>_debug(1)>) or as a package function 
(C<AppConfig::State::_debug(1)>), passing in a true/false value to 
set the debugging state accordingly.  The package variable 
$AppConfig::State::DEBUG can also be set directly.  

The _debug() method returns the current debug value.  If a new value 
is passed in, the internal value is updated, but the previous value is 
returned.

Note that any AppConfig::File or App::Config::Args objects that are 
instantiated with a reference to an App::State will inherit the 
DEBUG (and also PEDANTIC) values of the state at that time.  Subsequent
changes to the AppConfig::State debug value will not affect them.

=item GLOBAL 

The GLOBAL option allows default values to be set for the DEFAULT, ARGCOUNT, 
EXPAND, VALIDATE and ACTION options for any subsequently defined variables.

    $state = AppConfig::State->new({
        GLOBAL => {
            DEFAULT  => '<undef>',     # default value for new vars
            ARGCOUNT => 1,             # vars expect an argument
            ACTION   => \&my_set_var,  # callback when vars get set
        }
    });

Any attributes specified explicitly when a variable is defined will
override any GLOBAL values.

See L<DEFINING VARIABLES> below which describes these options in detail.

=back

=head2 DEFINING VARIABLES

The C<define()> function is used to pre-declare a variable and specify 
its configuration.

    $state->define("foo");

In the simple example above, a new variable called "foo" is defined.  A 
reference to a hash array may also be passed to specify configuration 
information for the variable:

    $state->define("foo", {
            DEFAULT   => 99,
            ALIAS     => 'metavar1',
        });

Any variable-wide GLOBAL values passed to the new() constructor in the 
configuration hash will also be applied.  Values explicitly specified 
in a variable's define() configuration will override the respective GLOBAL 
values.

The following configuration options may be specified

=over 4

=item DEFAULT

The DEFAULT value is used to initialise the variable.  

    $state->define("drink", {
            DEFAULT => 'coffee',
        });

    print $state->drink();        # prints "coffee"

=item ALIAS

The ALIAS option allows a number of alternative names to be specified for 
this variable.  A single alias should be specified as a string.  Multiple 
aliases can be specified as a reference to an array of alternatives or as 
a string of names separated by vertical bars, '|'.  e.g.:

    # either
    $state->define("name", {
            ALIAS  => 'person',
        });

    # or
    $state->define("name", {
            ALIAS => [ 'person', 'user', 'uid' ],
        });

    # or
    $state->define("name", {
            ALIAS => 'person|user|uid',
        });

    $state->user('abw');     # equivalent to $state->name('abw');

=item ARGCOUNT

The ARGCOUNT option specifies the number of arguments that should be 
supplied for this variable.  By default, no additional arguments are 
expected for variables (ARGCOUNT_NONE).

The ARGCOUNT_* constants can be imported from the AppConfig module:

    use AppConfig ':argcount';

    $state->define('foo', { ARGCOUNT => ARGCOUNT_ONE });

or can be accessed directly from the AppConfig package:

    use AppConfig;

    $state->define('foo', { ARGCOUNT => AppConfig::ARGCOUNT_ONE });

The following values for ARGCOUNT may be specified.  

=over 4

=item ARGCOUNT_NONE (0)

Indicates that no additional arguments are expected.  If the variable is
identified in a confirguration file or in the command line arguments, it
is set to a value of 1 regardless of whatever arguments follow it.

=item ARGCOUNT_ONE (1)

Indicates that the variable expects a single argument to be provided.
The variable value will be overwritten with a new value each time it 
is encountered.

=item ARGCOUNT_LIST (2)

Indicates that the variable expects multiple arguments.  The variable 
value will be appended to the list of previous values each time it is
encountered.  

=item ARGCOUNT_HASH (3)

Indicates that the variable expects multiple arguments and that each
argument is of the form "key=value".  The argument will be split into 
a key/value pair and inserted into the hash of values each time it 
is encountered.

=back

=item ARGS

The ARGS option can also be used to specify advanced command line options 
for use with AppConfig::Getopt, which itself delegates to Getopt::Long.  
See those two modules for more information on the format and meaning of
these options.

    $state->define("name", {
            ARGS => "=i@",
        });

=item EXPAND 

The EXPAND option specifies how the AppConfig::File processor should 
expand embedded variables in the configuration file values it reads.
By default, EXPAND is turned off (EXPAND_NONE) and no expansion is made.  

The EXPAND_* constants can be imported from the AppConfig module:

    use AppConfig ':expand';

    $state->define('foo', { EXPAND => EXPAND_VAR });

or can be accessed directly from the AppConfig package:

    use AppConfig;

    $state->define('foo', { EXPAND => AppConfig::EXPAND_VAR });

The following values for EXPAND may be specified.  Multiple values should
be combined with vertical bars , '|', e.g. C<EXPAND_UID | EXPAND_VAR>).

=over 4

=item EXPAND_NONE

Indicates that no variable expansion should be attempted.

=item EXPAND_VAR

Indicates that variables embedded as $var or $(var) should be expanded
to the values of the relevant AppConfig::State variables.

=item EXPAND_UID 

Indicates that '~' or '~uid' patterns in the string should be 
expanded to the current users ($<), or specified user's home directory.
In the first case, C<~> is expanded to the value of the C<HOME>
environment variable.  In the second case, the C<getpwnam()> method
is used if it is available on your system (which it isn't on Win32).

=item EXPAND_ENV

Inidicates that variables embedded as ${var} should be expanded to the 
value of the relevant environment variable.

=item EXPAND_ALL

Equivalent to C<EXPAND_VARS | EXPAND_UIDS | EXPAND_ENVS>).

=item EXPAND_WARN

Indicates that embedded variables that are not defined should raise a
warning.  If PEDANTIC is set, this will cause the read() method to return 0
immediately.

=back

=item VALIDATE

Each variable may have a sub-routine or regular expression defined which 
is used to validate the intended value for a variable before it is set.

If VALIDATE is defined as a regular expression, it is applied to the
value and deemed valid if the pattern matches.  In this case, the
variable is then set to the new value.  A warning message is generated
if the pattern match fails.

VALIDATE may also be defined as a reference to a sub-routine which takes
as its arguments the name of the variable and its intended value.  The 
sub-routine should return 1 or 0 to indicate that the value is valid
or invalid, respectively.  An invalid value will cause a warning error
message to be generated.

If the GLOBAL VALIDATE variable is set (see GLOBAL in L<DESCRIPTION> 
above) then this value will be used as the default VALIDATE for each 
variable unless otherwise specified.

    $state->define("age", {
            VALIDATE => '\d+',
        });

    $state->define("pin", {
            VALIDATE => \&check_pin,
        });

=item ACTION

The ACTION option allows a sub-routine to be bound to a variable as a
callback that is executed whenever the variable is set.  The ACTION is
passed a reference to the AppConfig::State object, the name of the
variable and the value of the variable.

The ACTION routine may be used, for example, to post-process variable
data, update the value of some other dependant variable, generate a
warning message, etc.

Example:

    $state->define("foo", { ACTION => \&my_notify });

    sub my_notify {
        my $state = shift;
        my $var   = shift;
        my $val   = shift;

        print "$variable set to $value";
    }

    $state->foo(42);        # prints "foo set to 42"

Be aware that calling C<$state-E<gt>set()> to update the same variable
from within the ACTION function will cause a recursive loop as the
ACTION function is repeatedly called.  

=back

=head2 DEFINING VARIABLES USING THE COMPACT FORMAT

Variables may be defined in a compact format which allows any ALIAS and
ARGS values to be specified as part of the variable name.  This is designed
to mimic the behaviour of Johan Vromans' Getopt::Long module.

Aliases for a variable should be specified after the variable name, 
separated by vertical bars, '|'.  Any ARGS parameter should be appended 
after the variable name(s) and/or aliases.

The following examples are equivalent:

    $state->define("foo", { 
            ALIAS => [ 'bar', 'baz' ],
            ARGS  => '=i',
        });

    $state->define("foo|bar|baz=i");

=head2 READING AND MODIFYING VARIABLE VALUES

AppConfig::State defines two methods to manipulate variable values: 

    set($variable, $value);
    get($variable);

Both functions take the variable name as the first parameter and
C<set()> takes an additional parameter which is the new value for the
variable.  C<set()> returns 1 or 0 to indicate successful or
unsuccessful update of the variable value.  If there is an ACTION
routine associated with the named variable, the value returned will be
passed back from C<set()>.  The C<get()> function returns the current
value of the variable.

Once defined, variables may be accessed directly as object methods where
the method name is the same as the variable name.  i.e.

    $state->set("verbose", 1);

is equivalent to 

    $state->verbose(1); 

Without parameters, the current value of the variable is returned.  If
a parameter is specified, the variable is set to that value and the 
result of the set() operation is returned.

    $state->age(29);        # sets 'age' to 29, returns 1 (ok)

=head2 VARLIST

The varlist() method can be used to extract a number of variables into
a hash array.  The first parameter should be a regular expression
used for matching against the variable names.

    my %vars = $state->varlist("^file");   # all "file*" variables

A second parameter may be specified (any true value) to indicate that
the part of the variable name matching the regex should be removed
when copied to the target hash.

    $state->file_name("/tmp/file");
    $state->file_path("/foo:/bar:/baz");

    my %vars = $state->varlist("^file_", 1);

    # %vars:
    #    name => /tmp/file
    #    path => "/foo:/bar:/baz"

=head2 INTERNAL METHODS

The interal (private) methods of the AppConfig::State class are listed 
below.

They aren't intended for regular use and potential users should consider
the fact that nothing about the internal implementation is guaranteed to
remain the same.  Having said that, the AppConfig::State class is
intended to co-exist and work with a number of other modules and these
are considered "friend" classes.  These methods are provided, in part,
as services to them.  With this acknowledged co-operation in mind, it is
safe to assume some stability in this core interface.

The _varname() method can be used to determine the real name of a variable 
from an alias:

    $varname->_varname($alias);

Note that all methods that take a variable name, including those listed
below, can accept an alias and automatically resolve it to the correct 
variable name.  There is no need to call _varname() explicitly to do 
alias expansion.  The _varname() method will fold all variables names
to lower case unless CASE sensititvity is set.

The _exists() method can be used to check if a variable has been
defined:

    $state->_exists($varname);

The _default() method can be used to reset a variable to its default value:

    $state->_default($varname);

The _expand() method can be used to determine the EXPAND value for a 
variable:

    print "$varname EXPAND: ", $state->_expand($varname), "\n";

The _argcount() method returns the value of the ARGCOUNT attribute for a 
variable:

    print "$varname ARGCOUNT: ", $state->_argcount($varname), "\n";

The _validate() method can be used to determine if a new value for a variable
meets any validation criteria specified for it.  The variable name and 
intended value should be passed in.  The methods returns a true/false value
depending on whether or not the validation succeeded:

    print "OK\n" if $state->_validate($varname, $value);

The _pedantic() method can be called to determine the current value of the
PEDANTIC option.

    print "pedantic mode is ", $state->_pedantic() ? "on" ; "off", "\n";

The _debug() method can be used to turn debugging on or off (pass 1 or 0
as a parameter).  It can also be used to check the debug state,
returning the current internal value of $AppConfig::State::DEBUG.  If a
new debug value is provided, the debug state is updated and the previous
state is returned.

    $state->_debug(1);               # debug on, returns previous value

The _dump_var($varname) and _dump() methods may also be called for
debugging purposes.  

    $state->_dump_var($varname);    # show variable state
    $state->_dump();                # show internal state and all vars

=head1 AUTHOR

Andy Wardley, E<lt>abw@wardley.orgE<gt>

=head1 COPYRIGHT

Copyright (C) 1997-2007 Andy Wardley.  All Rights Reserved.

Copyright (C) 1997,1998 Canon Research Centre Europe Ltd.

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

=head1 SEE ALSO

AppConfig, AppConfig::File, AppConfig::Args, AppConfig::Getopt

=cut
PK1N%[f�OM^^perl5/AppConfig/File.pmnu��6�$#============================================================================
#
# AppConfig::File.pm
#
# Perl5 module to read configuration files and use the contents therein 
# to update variable values in an AppConfig::State object.
#
# Written by Andy Wardley <abw@wardley.org>
#
# Copyright (C) 1997-2007 Andy Wardley.  All Rights Reserved.
# Copyright (C) 1997,1998 Canon Research Centre Europe Ltd.
#
#============================================================================

package AppConfig::File;
use 5.006;
use strict;
use warnings;
use AppConfig;
use AppConfig::State;
our $VERSION = '1.71';


#------------------------------------------------------------------------
# new($state, $file, [$file, ...])
#
# Module constructor.  The first, mandatory parameter should be a 
# reference to an AppConfig::State object to which all actions should 
# be applied.  The remaining parameters are assumed to be file names or
# file handles for reading and are passed to parse().
#
# Returns a reference to a newly created AppConfig::File object.
#------------------------------------------------------------------------

sub new {
    my $class = shift;
    my $state = shift;
    my $self  = {
        STATE    => $state,                # AppConfig::State ref
        DEBUG    => $state->_debug(),      # store local copy of debug 
        PEDANTIC => $state->_pedantic,     # and pedantic flags
    };

    bless $self, $class;

    # call parse(@_) to parse any files specified as further params
    $self->parse(@_) if @_;

    return $self;
}


#------------------------------------------------------------------------
# parse($file, [file, ...])
#
# Reads and parses a config file, updating the contents of the 
# AppConfig::State referenced by $self->{ STATE } according to the 
# contents of the file.  Multiple files may be specified and are 
# examined in turn.  The method reports any error condition via 
# $self->{ STATE }->_error() and immediately returns undef if it 
# encounters a system error (i.e. cannot open one of the files.  
# Parsing errors such as unknown variables or unvalidated values will 
# also cause warnings to be raised vi the same _error(), but parsing
# continues to the end of the current file and through any subsequent
# files.  If the PEDANTIC option is set in the $self->{ STATE } object, 
# the behaviour is overridden and the method returns 0 immediately on 
# any system or parsing error.
#
# The EXPAND option for each variable determines how the variable
# value should be expanded.
#
# Returns undef on system error, 0 if all files were parsed but generated
# one or more warnings, 1 if all files parsed without warnings.
#------------------------------------------------------------------------

sub parse {
    my $self     = shift;
    my $warnings = 0;
    my $prefix;           # [block] defines $prefix
    my $file;
    my $flag;

    # take a local copy of the state to avoid much hash dereferencing
    my ($state, $debug, $pedantic) = @$self{ qw( STATE DEBUG PEDANTIC ) };

    # we want to install a custom error handler into the AppConfig::State 
    # which appends filename and line info to error messages and then 
    # calls the previous handler;  we start by taking a copy of the 
    # current handler..
    my $errhandler = $state->_ehandler();

    # ...and if it doesn't exist, we craft a default handler
    $errhandler = sub { warn(sprintf(shift, @_), "\n") }
        unless defined $errhandler;

    # install a closure as a new error handler
    $state->_ehandler(
        sub {
            # modify the error message 
            my $format  = shift;
               $format .= ref $file 
                          ? " at line $."
                          : " at $file line $.";

            # chain call to prevous handler
            &$errhandler($format, @_);
        }
    );

    # trawl through all files passed as params
    FILE: while ($file = shift) {

        # local/lexical vars ensure opened files get closed
        my $handle;
        local *FH;

        # if the file is a reference, we assume it's a file handle, if
        # not, we assume it's a filename and attempt to open it
        $handle = $file;
        if (ref($file)) {
            $handle = $file;

            # DEBUG
            print STDERR "reading from file handle: $file\n" if $debug;
        }
        else {
            # open and read config file
            open(FH, $file) or do {
                # restore original error handler and report error
                $state->_ehandler($errhandler);
                $state->_error("$file: $!");

                return undef;
            };
            $handle = \*FH;

            # DEBUG
            print STDERR "reading file: $file\n" if $debug;
        }

        # initialise $prefix to nothing (no [block])
        $prefix = '';

        local $_;
        while (<$handle>) {
            chomp;

            # Throw away everything from an unescaped # to EOL
            s/(^|\s+)#.*/$1/;

            # add next line if there is one and this is a continuation
            if (s/\\$// && !eof($handle)) {
                $_ .= <$handle>;
                redo;
            }

            # Convert \# -> #
            s/\\#/#/g;

            # ignore blank lines
            next if /^\s*$/;

            # strip leading and trailing whitespace
            s/^\s+//;
            s/\s+$//;

            # look for a [block] to set $prefix
            if (/^\[([^\]]+)\]$/) {
                $prefix = $1;
                print STDERR "Entering [$prefix] block\n" if $debug;
                next;
            }

            # split line up by whitespace (\s+) or "equals" (\s*=\s*)
            if (/^([^\s=]+)(?:(?:(?:\s*=\s*)|\s+)(.*))?/) {
                my ($variable, $value) = ($1, $2);

                if (defined $value) {
                    # here document
                    if ($value =~ /^([^\s=]+\s*=)?\s*<<(['"]?)(\S+)\2$/) { # '<<XX' or 'hashkey =<<XX'
                        my $boundary = "$3\n";
                        $value = defined($1) ? $1 : '';
                        while (<$handle>) {
                            last if $_ eq $boundary;
                            $value .= $_;
                        };
                        $value =~ s/[\r\n]$//;
                    } else {
                        # strip any quoting from the variable value
                        $value =~ s/^(['"])(.*)\1$/$2/;
                    };
                };

                # strip any leading '+/-' from the variable
                $variable =~ s/^([\-+]?)//;
                $flag = $1;

                # $variable gets any $prefix 
                $variable = $prefix . '_' . $variable
                    if length $prefix;

                # if the variable doesn't exist, we call set() to give 
                # AppConfig::State a chance to auto-create it
                unless ($state->_exists($variable) 
                            || $state->set($variable, 1)) {
                    $warnings++;
                    last FILE if $pedantic;
                    next;
                }       

                my $nargs = $state->_argcount($variable);

                # variables prefixed '-' are reset to their default values
                if ($flag eq '-') {
                    $state->_default($variable);
                    next;
                }
                # those prefixed '+' get set to 1
                elsif ($flag eq '+') {
                    $value = 1 unless defined $value;
                }

                # determine if any extra arguments were expected
                if ($nargs) {
                    if (defined $value && length $value) {
                        # expand any embedded variables, ~uids or
                        # environment variables, testing the return value
                        # for errors;  we pass in any variable-specific
                        # EXPAND value 
                        unless ($self->_expand(\$value, 
                                $state->_expand($variable), $prefix)) {
                            print STDERR "expansion of [$value] failed\n" 
                                if $debug;
                            $warnings++;
                            last FILE if $pedantic;
                        }
                    }
                    else {
                        $state->_error("$variable expects an argument");
                        $warnings++;
                        last FILE if $pedantic;
                        next;
                    }
                }
                # $nargs = 0
                else {
                    # default value to 1 unless it is explicitly defined
                    # as '0' or "off"
                    if (defined $value) {
                        # "off" => 0
                        $value = 0 if $value =~ /off/i;
                        # any value => 1
                        $value = 1 if $value;
                    }
                    else {
                        # assume 1 unless explicitly defined off/0
                        $value = 1;
                    }
                    print STDERR "$variable => $value (no expansion)\n"
                        if $debug;
                }

                # set the variable, noting any failure from set()
                unless ($state->set($variable, $value)) {
                    $warnings++;
                    last FILE if $pedantic;
                }
            }
            else {
                $state->_error("parse error");
                $warnings++;
            }
        }
    }

    # restore original error handler
    $state->_ehandler($errhandler);

    # return $warnings => 0, $success => 1
    return $warnings ? 0 : 1;
}



#========================================================================
#                      -----  PRIVATE METHODS -----
#========================================================================

#------------------------------------------------------------------------
# _expand(\$value, $expand, $prefix)
#
# The variable value string, referenced by $value, is examined and any 
# embedded variables, environment variables or tilde globs (home 
# directories) are replaced with their respective values, depending on 
# the value of the second parameter, $expand.  The third paramter may
# specify the name of the current [block] in which the parser is 
# parsing.  This prefix is prepended to any embedded variable name that
# can't otherwise be resolved.  This allows the following to work:
#
#   [define]
#   home = /home/abw
#   html = $define_home/public_html
#   html = $home/public_html     # same as above, 'define' is prefix
#
# Modifications are made directly into the variable referenced by $value.
# The method returns 1 on success or 0 if any warnings (undefined 
# variables) were encountered.
#------------------------------------------------------------------------

sub _expand {
    my ($self, $value, $expand, $prefix) = @_;
    my $warnings = 0;
    my ($sys, $var, $val);


    # ensure prefix contains something (nothing!) valid for length()
    $prefix = "" unless defined $prefix;

    # take a local copy of the state to avoid much hash dereferencing
    my ($state, $debug, $pedantic) = @$self{ qw( STATE DEBUG PEDANTIC ) };

    # bail out if there's nothing to do
    return 1 unless $expand && defined($$value);

    # create an AppConfig::Sys instance, or re-use a previous one, 
    # to handle platform dependant functions: getpwnam(), getpwuid()
    unless ($sys = $self->{ SYS }) {
        require AppConfig::Sys;
        $sys = $self->{ SYS } = AppConfig::Sys->new();
    }

    print STDERR "Expansion of [$$value] " if $debug;

    EXPAND: {

        # 
        # EXPAND_VAR
        # expand $(var) and $var as AppConfig::State variables
        #
        if ($expand & AppConfig::EXPAND_VAR) {

            $$value =~ s{
                (?<!\\)\$ (?: \((\w+)\) | (\w+) ) # $2 => $(var) | $3 => $var

            } {
                # embedded variable name will be one of $2 or $3
                $var = defined $1 ? $1 : $2;

                # expand the variable if defined
                if ($state->_exists($var)) {
                    $val = $state->get($var);
                }
                elsif (length $prefix 
                        && $state->_exists($prefix . '_' . $var)) {
                    print STDERR "(\$$var => \$${prefix}_$var) "
                        if $debug;
                    $var = $prefix . '_' . $var;
                    $val = $state->get($var);
                }
                else {
                    # raise a warning if EXPAND_WARN set
                    if ($expand & AppConfig::EXPAND_WARN) {
                        $state->_error("$var: no such variable");
                        $warnings++;
                    }

                    # replace variable with nothing
                    $val = '';
                }

                # $val gets substituted back into the $value string
                $val;
            }gex;

            $$value =~ s/\\\$/\$/g;

            # bail out now if we need to
            last EXPAND if $warnings && $pedantic;
        }


        #
        # EXPAND_UID
        # expand ~uid as home directory (for $< if uid not specified)
        #
        if ($expand & AppConfig::EXPAND_UID) {
            $$value =~ s{
                ~(\w+)?                    # $1 => username (optional)
            } {
                $val = undef;

                # embedded user name may be in $1
                if (defined ($var = $1)) {
                    # try and get user's home directory
                    if ($sys->can_getpwnam()) {
                        $val = ($sys->getpwnam($var))[7];
                    }
                } else {
                    # determine home directory 
                    $val = $ENV{ HOME };
                }

                # catch-all for undefined $dir
                unless (defined $val) {
                    # raise a warning if EXPAND_WARN set
                    if ($expand & AppConfig::EXPAND_WARN) {
                        $state->_error("cannot determine home directory%s",
                            defined $var ? " for $var" : "");
                        $warnings++;
                    }

                    # replace variable with nothing
                    $val = '';
                }

                # $val gets substituted back into the $value string
                $val;
            }gex;

            # bail out now if we need to
            last EXPAND if $warnings && $pedantic;
        }


        #
        # EXPAND_ENV
        # expand ${VAR} as environment variables
        #
        if ($expand & AppConfig::EXPAND_ENV) {

            $$value =~ s{ 
                ( \$ \{ (\w+) \} )
            } {
                $var = $2;

                # expand the variable if defined
                if (exists $ENV{ $var }) {
                    $val = $ENV{ $var };
                } elsif ( $var eq 'HOME' ) {
                    # In the special case of HOME, if not set
                    # use the internal version
                    $val = $self->{ HOME };
                } else {
                    # raise a warning if EXPAND_WARN set
                    if ($expand & AppConfig::EXPAND_WARN) {
                        $state->_error("$var: no such environment variable");
                        $warnings++;
                    }

                    # replace variable with nothing
                    $val = '';
                }
                # $val gets substituted back into the $value string
                $val;
            }gex;

            # bail out now if we need to
            last EXPAND if $warnings && $pedantic;
        }
    }

    print STDERR "=> [$$value] (EXPAND = $expand)\n" if $debug;

    # return status 
    return $warnings ? 0 : 1;
}



#------------------------------------------------------------------------
# _dump()
#
# Dumps the contents of the Config object.
#------------------------------------------------------------------------

sub _dump {
    my $self = shift;

    foreach my $key (keys %$self) {
        printf("%-10s => %s\n", $key, 
                defined($self->{ $key }) ? $self->{ $key } : "<undef>");
    }       
} 



1;

__END__

=head1 NAME

AppConfig::File - Perl5 module for reading configuration files.

=head1 SYNOPSIS

    use AppConfig::File;

    my $state   = AppConfig::State->new(\%cfg1);
    my $cfgfile = AppConfig::File->new($state, $file);

    $cfgfile->parse($file);            # read config file

=head1 OVERVIEW

AppConfig::File is a Perl5 module which reads configuration files and use 
the contents therein to update variable values in an AppConfig::State 
object.

AppConfig::File is distributed as part of the AppConfig bundle.

=head1 DESCRIPTION

=head2 USING THE AppConfig::File MODULE

To import and use the AppConfig::File module the following line should appear
in your Perl script:

    use AppConfig::File;

AppConfig::File is used automatically if you use the AppConfig module 
and create an AppConfig::File object through the file() method.

AppConfig::File is implemented using object-oriented methods.  A new 
AppConfig::File object is created and initialised using the 
AppConfig::File->new() method.  This returns a reference to a new 
AppConfig::File object.  A reference to an AppConfig::State object 
should be passed in as the first parameter:

    my $state   = AppConfig::State->new();
    my $cfgfile = AppConfig::File->new($state);

This will create and return a reference to a new AppConfig::File object.

=head2 READING CONFIGURATION FILES 

The C<parse()> method is used to read a configuration file and have the 
contents update the STATE accordingly.

    $cfgfile->parse($file);

Multiple files maye be specified and will be read in turn.

    $cfgfile->parse($file1, $file2, $file3);

The method will return an undef value if it encounters any errors opening
the files.  It will return immediately without processing any further files.
By default, the PEDANTIC option in the AppConfig::State object, 
$self->{ STATE }, is turned off and any parsing errors (invalid variables,
unvalidated values, etc) will generated warnings, but not cause the method
to return.  Having processed all files, the method will return 1 if all
files were processed without warning or 0 if one or more warnings were
raised.  When the PEDANTIC option is turned on, the method generates a
warning and immediately returns a value of 0 as soon as it encounters any
parsing error.

Variables values in the configuration files may be expanded depending on 
the value of their EXPAND option, as determined from the App::State object.
See L<AppConfig::State> for more information on variable expansion.

=head2 CONFIGURATION FILE FORMAT

A configuration file may contain blank lines and comments which are
ignored.  Comments begin with a '#' as the first character on a line
or following one or more whitespace tokens, and continue to the end of
the line.

    # this is a comment
    foo = bar               # so is this
    url = index.html#hello  # this too, but not the '#welcome'

Notice how the '#welcome' part of the URL is not treated as a comment
because a whitespace character doesn't precede it.  

Long lines can be continued onto the next line by ending the first 
line with a '\'.

    callsign = alpha bravo camel delta echo foxtrot golf hipowls \
               india juliet kilo llama mike november oscar papa  \
               quebec romeo sierra tango umbrella victor whiskey \
               x-ray yankee zebra

Variables that are simple flags and do not expect an argument (ARGCOUNT = 
ARGCOUNT_NONE) can be specified without any value.  They will be set with 
the value 1, with any value explicitly specified (except "0" and "off")
being ignored.  The variable may also be specified with a "no" prefix to 
implicitly set the variable to 0.

    verbose                              # on  (1)
    verbose = 1                          # on  (1)
    verbose = 0                          # off (0)
    verbose off                          # off (0)
    verbose on                           # on  (1)
    verbose mumble                       # on  (1)
    noverbose                            # off (0)

Variables that expect an argument (ARGCOUNT = ARGCOUNT_ONE) will be set to 
whatever follows the variable name, up to the end of the current line.  An
equals sign may be inserted between the variable and value for clarity.

    room = /home/kitchen     
    room   /home/bedroom

Each subsequent re-definition of the variable value overwrites the previous
value.

    print $config->room();               # prints "/home/bedroom"

Variables may be defined to accept multiple values (ARGCOUNT = ARGCOUNT_LIST).
Each subsequent definition of the variable adds the value to the list of
previously set values for the variable.  

    drink = coffee
    drink = tea

A reference to a list of values is returned when the variable is requested.

    my $beverages = $config->drinks();
    print join(", ", @$beverages);      # prints "coffee, tea"

Variables may also be defined as hash lists (ARGCOUNT = ARGCOUNT_HASH).
Each subsequent definition creates a new key and value in the hash array.

    alias l="ls -CF"
    alias h="history"

A reference to the hash is returned when the variable is requested.

    my $aliases = $config->alias();
    foreach my $k (keys %$aliases) {
        print "$k => $aliases->{ $k }\n";
    }

A large chunk of text can be defined using Perl's "heredoc" quoting
style.

   scalar = <<BOUNDARY_STRING
   line 1
   line 2: Space/linebreaks within a HERE document are kept.
   line 3: The last linebreak (\n) is stripped.
   BOUNDARY_STRING

   hash   key1 = <<'FOO'
     * Quotes (['"]) around the boundary string are simply ignored.
     * Whether the variables in HERE document are expanded depends on
       the EXPAND option of the variable or global setting.
   FOO

   hash = key2 = <<"_bar_"
   Text within HERE document are kept as is.
   # comments are treated as a normal text.
   The same applies to line continuation. \
   _bar_

Note that you cannot use HERE document as a key in a hash or a name 
of a variable.

The '-' prefix can be used to reset a variable to its default value and
the '+' prefix can be used to set it to 1

    -verbose
    +debug

Variable, environment variable and tilde (home directory) expansions
Variable values may contain references to other AppConfig variables, 
environment variables and/or users' home directories.  These will be 
expanded depending on the EXPAND value for each variable or the GLOBAL
EXPAND value.

Three different expansion types may be applied:

    bin = ~/bin          # expand '~' to home dir if EXPAND_UID
    tmp = ~abw/tmp       # as above, but home dir for user 'abw'

    perl = $bin/perl     # expand value of 'bin' variable if EXPAND_VAR
    ripl = $(bin)/ripl   # as above with explicit parens

    home = ${HOME}       # expand HOME environment var if EXPAND_ENV

See L<AppConfig::State> for more information on expanding variable values.

The configuration files may have variables arranged in blocks.  A block 
header, consisting of the block name in square brackets, introduces a 
configuration block.  The block name and an underscore are then prefixed 
to the names of all variables subsequently referenced in that block.  The 
block continues until the next block definition or to the end of the current 
file.

    [block1]
    foo = 10             # block1_foo = 10

    [block2]
    foo = 20             # block2_foo = 20

=head1 AUTHOR

Andy Wardley, E<lt>abw@wardley.orgE<gt>

=head1 COPYRIGHT

Copyright (C) 1997-2007 Andy Wardley.  All Rights Reserved.

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

=head1 SEE ALSO

AppConfig, AppConfig::State

=cut
PK1N%[���3 3 perl5/AppConfig/Getopt.pmnu��6�$#============================================================================
#
# AppConfig::Getopt.pm
#
# Perl5 module to interface AppConfig::* to Johan Vromans' Getopt::Long
# module.  Getopt::Long implements the POSIX standard for command line
# options, with GNU extensions, and also traditional one-letter options.
# AppConfig::Getopt constructs the necessary Getopt:::Long configuration
# from the internal AppConfig::State and delegates the parsing of command
# line arguments to it.  Internal variable values are updated by callback
# from GetOptions().
# 
# Written by Andy Wardley <abw@wardley.org>
#
# Copyright (C) 1997-2007 Andy Wardley.  All Rights Reserved.
# Copyright (C) 1997,1998 Canon Research Centre Europe Ltd.
#
#============================================================================

package AppConfig::Getopt;
use 5.006;
use strict;
use warnings;
use AppConfig::State;
use Getopt::Long 2.17;
our $VERSION = '1.71';


#------------------------------------------------------------------------
# new($state, \@args)
#
# Module constructor.  The first, mandatory parameter should be a 
# reference to an AppConfig::State object to which all actions should 
# be applied.  The second parameter may be a reference to a list of 
# command line arguments.  This list reference is passed to parse() for
# processing.
#
# Returns a reference to a newly created AppConfig::Getopt object.
#------------------------------------------------------------------------

sub new {
    my $class = shift;
    my $state = shift;
    my $self = {
        STATE => $state,
   };

    bless $self, $class;

    # call parse() to parse any arg list passed 
    $self->parse(@_)
        if @_;

    return $self;
}


#------------------------------------------------------------------------
# parse(@$config, \@args)
#
# Constructs the appropriate configuration information and then delegates
# the task of processing command line options to Getopt::Long.
#
# Returns 1 on success or 0 if one or more warnings were raised.
#------------------------------------------------------------------------

sub parse {
    my $self  = shift;
    my $state = $self->{ STATE };
    my (@config, $args, $getopt);

    local $" = ', ';

    # we trap $SIG{__WARN__} errors and patch them into AppConfig::State
    local $SIG{__WARN__} = sub {
        my $msg = shift;

        # AppConfig::State doesn't expect CR terminated error messages
        # and it uses printf, so we protect any embedded '%' chars 
        chomp($msg);
        $state->_error("%s", $msg);
    };

    # slurp all config items into @config
    push(@config, shift) while defined $_[0] && ! ref($_[0]);   

    # add debug status if appropriate (hmm...can't decide about this)
#    push(@config, 'debug') if $state->_debug();

    # next parameter may be a reference to a list of args
    $args = shift;

    # copy any args explicitly specified into @ARGV
    @ARGV = @$args if defined $args;

    # we enclose in an eval block because constructor may die()
    eval {
        # configure Getopt::Long
        Getopt::Long::Configure(@config);

        # construct options list from AppConfig::State variables
        my @opts = $self->{ STATE   }->_getopt_state();

        # DEBUG
        if ($state->_debug()) {
            print STDERR "Calling GetOptions(@opts)\n";
            print STDERR "\@ARGV = (@ARGV)\n";
        };

        # call GetOptions() with specifications constructed from the state
        $getopt = GetOptions(@opts);
    };
    if ($@) {
        chomp($@);
        $state->_error("%s", $@);
        return 0;
    }

    # udpdate any args reference passed to include only that which is left 
    # in @ARGV
    @$args = @ARGV if defined $args;

    return $getopt;
}


#========================================================================
# AppConfig::State
#========================================================================

package AppConfig::State;

#------------------------------------------------------------------------
# _getopt_state()
#
# Constructs option specs in the Getopt::Long format for each variable 
# definition.
#
# Returns a list of specification strings.
#------------------------------------------------------------------------

sub _getopt_state {
    my $self = shift;
    my ($var, $spec, $args, $argcount, @specs);

    my $linkage = sub { $self->set(@_) };

    foreach $var (keys %{ $self->{ VARIABLE } }) {
        $spec  = join('|', $var, @{ $self->{ ALIASES }->{ $var } || [ ] });

        # an ARGS value is used, if specified
        unless (defined ($args = $self->{ ARGS }->{ $var })) {
            # otherwise, construct a basic one from ARGCOUNT
            ARGCOUNT: {
                last ARGCOUNT unless 
                    defined ($argcount = $self->{ ARGCOUNT }->{ $var });

                $args = "=s",  last ARGCOUNT if $argcount eq ARGCOUNT_ONE;
                $args = "=s@", last ARGCOUNT if $argcount eq ARGCOUNT_LIST;
                $args = "=s%", last ARGCOUNT if $argcount eq ARGCOUNT_HASH;
                $args = "!";
            }
        }
        $spec .= $args if defined $args;

        push(@specs, $spec, $linkage);
    }

    return @specs;
}



1;

__END__

=head1 NAME

AppConfig::Getopt - Perl5 module for processing command line arguments via delegation to Getopt::Long.

=head1 SYNOPSIS

    use AppConfig::Getopt;

    my $state  = AppConfig::State->new(\%cfg);
    my $getopt = AppConfig::Getopt->new($state);

    $getopt->parse(\@args);            # read args

=head1 OVERVIEW

AppConfig::Getopt is a Perl5 module which delegates to Johan Vroman's
Getopt::Long module to parse command line arguments and update values 
in an AppConfig::State object accordingly.

AppConfig::Getopt is distributed as part of the AppConfig bundle.

=head1 DESCRIPTION

=head2 USING THE AppConfig::Getopt MODULE

To import and use the AppConfig::Getopt module the following line should appear
in your Perl script:

    use AppConfig::Getopt;

AppConfig::Getopt is used automatically if you use the AppConfig module 
and create an AppConfig::Getopt object through the getopt() method.

AppConfig::Getopt is implemented using object-oriented methods.  A new 
AppConfig::Getopt object is created and initialised using the new() method.
This returns a reference to a new AppConfig::Getopt object.  A reference to
an AppConfig::State object should be passed in as the first parameter:

    my $state  = AppConfig::State->new();
    my $getopt = AppConfig::Getopt->new($state);

This will create and return a reference to a new AppConfig::Getopt object. 

=head2 PARSING COMMAND LINE ARGUMENTS

The C<parse()> method is used to read a list of command line arguments and 
update the state accordingly.  

The first (non-list reference) parameters may contain a number of 
configuration strings to pass to Getopt::Long::Configure.  A reference 
to a list of arguments may additionally be passed or @ARGV is used by 
default.

    $getopt->parse();                       # uses @ARGV
    $getopt->parse(\@myargs);
    $getopt->parse(qw(auto_abbrev debug));  # uses @ARGV
    $getopt->parse(qw(debug), \@myargs);

See Getopt::Long for details of the configuartion options available.

A Getopt::Long specification string is constructed for each variable 
defined in the AppConfig::State.  This consists of the name, any aliases
and the ARGS value for the variable.

These specification string are then passed to Getopt::Long, the arguments
are parsed and the values in the AppConfig::State updated.

See AppConfig for information about using the AppConfig::Getopt
module via the getopt() method.

=head1 AUTHOR

Andy Wardley, E<lt>abw@wardley.orgE<gt>

=head1 COPYRIGHT

Copyright (C) 1997-2007 Andy Wardley.  All Rights Reserved.

Copyright (C) 1997,1998 Canon Research Centre Europe Ltd.

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

=head1 ACKNOWLEDGMENTS

Many thanks are due to Johan Vromans for the Getopt::Long module.  He was 
kind enough to offer assistance and access to early releases of his code to 
enable this module to be written.

=head1 SEE ALSO

AppConfig, AppConfig::State, AppConfig::Args, Getopt::Long

=cut
PK1N%[��E�1$1$perl5/lwpcook.podnu��6�$=head1 NAME

lwpcook - The libwww-perl cookbook

=head1 DESCRIPTION

This document contain some examples that show typical usage of the
libwww-perl library.  You should consult the documentation for the
individual modules for more detail.

All examples should be runnable programs. You can, in most cases, test
the code sections by piping the program text directly to perl.



=head1 GET

It is very easy to use this library to just fetch documents from the
net.  The LWP::Simple module provides the get() function that return
the document specified by its URL argument:

  use LWP::Simple;
  $doc = get 'http://search.cpan.org/dist/libwww-perl/';

or, as a perl one-liner using the getprint() function:

  perl -MLWP::Simple -e 'getprint "http://search.cpan.org/dist/libwww-perl/"'

or, how about fetching the latest perl by running this command:

  perl -MLWP::Simple -e '
    getstore "ftp://ftp.sunet.se/pub/lang/perl/CPAN/src/latest.tar.gz",
             "perl.tar.gz"'

You will probably first want to find a CPAN site closer to you by
running something like the following command:

  perl -MLWP::Simple -e 'getprint "http://www.cpan.org/SITES.html"'

Enough of this simple stuff!  The LWP object oriented interface gives
you more control over the request sent to the server.  Using this
interface you have full control over headers sent and how you want to
handle the response returned.

  use LWP::UserAgent;
  $ua = LWP::UserAgent->new;
  $ua->agent("$0/0.1 " . $ua->agent);
  # $ua->agent("Mozilla/8.0") # pretend we are very capable browser

  $req = HTTP::Request->new(
     GET => 'http://search.cpan.org/dist/libwww-perl/');
  $req->header('Accept' => 'text/html');

  # send request
  $res = $ua->request($req);

  # check the outcome
  if ($res->is_success) {
     print $res->decoded_content;
  }
  else {
     print "Error: " . $res->status_line . "\n";
  }

The lwp-request program (alias GET) that is distributed with the
library can also be used to fetch documents from WWW servers.



=head1 HEAD

If you just want to check if a document is present (i.e. the URL is
valid) try to run code that looks like this:

  use LWP::Simple;

  if (head($url)) {
     # ok document exists
  }

The head() function really returns a list of meta-information about
the document.  The first three values of the list returned are the
document type, the size of the document, and the age of the document.

More control over the request or access to all header values returned
require that you use the object oriented interface described for GET
above.  Just s/GET/HEAD/g.


=head1 POST

There is no simple procedural interface for posting data to a WWW server.  You
must use the object oriented interface for this. The most common POST
operation is to access a WWW form application:

  use LWP::UserAgent;
  $ua = LWP::UserAgent->new;

  my $req = HTTP::Request->new(
      POST => 'https://rt.cpan.org/Public/Dist/Display.html');
  $req->content_type('application/x-www-form-urlencoded');
  $req->content('Status=Active&Name=libwww-perl');

  my $res = $ua->request($req);
  print $res->as_string;

Lazy people use the HTTP::Request::Common module to set up a suitable
POST request message (it handles all the escaping issues) and has a
suitable default for the content_type:

  use HTTP::Request::Common qw(POST);
  use LWP::UserAgent;
  $ua = LWP::UserAgent->new;

  my $req = POST 'https://rt.cpan.org/Public/Dist/Display.html',
                [ Status => 'Active', Name => 'libwww-perl' ];

  print $ua->request($req)->as_string;

The lwp-request program (alias POST) that is distributed with the
library can also be used for posting data.



=head1 PROXIES

Some sites use proxies to go through fire wall machines, or just as
cache in order to improve performance.  Proxies can also be used for
accessing resources through protocols not supported directly (or
supported badly :-) by the libwww-perl library.

You should initialize your proxy setting before you start sending
requests:

  use LWP::UserAgent;
  $ua = LWP::UserAgent->new;
  $ua->env_proxy; # initialize from environment variables
  # or
  $ua->proxy(ftp  => 'http://proxy.myorg.com');
  $ua->proxy(wais => 'http://proxy.myorg.com');
  $ua->no_proxy(qw(no se fi));

  my $req = HTTP::Request->new(GET => 'wais://xxx.com/');
  print $ua->request($req)->as_string;

The LWP::Simple interface will call env_proxy() for you automatically.
Applications that use the $ua->env_proxy() method will normally not
use the $ua->proxy() and $ua->no_proxy() methods.

Some proxies also require that you send it a username/password in
order to let requests through.  You should be able to add the
required header, with something like this:

 use LWP::UserAgent;

 $ua = LWP::UserAgent->new;
 $ua->proxy(['http', 'ftp'] => 'http://username:password@proxy.myorg.com');

 $req = HTTP::Request->new('GET',"http://www.perl.com");

 $res = $ua->request($req);
 print $res->decoded_content if $res->is_success;

Replace C<proxy.myorg.com>, C<username> and
C<password> with something suitable for your site.


=head1 ACCESS TO PROTECTED DOCUMENTS

Documents protected by basic authorization can easily be accessed
like this:

  use LWP::UserAgent;
  $ua = LWP::UserAgent->new;
  $req = HTTP::Request->new(GET => 'http://www.linpro.no/secret/');
  $req->authorization_basic('aas', 'mypassword');
  print $ua->request($req)->as_string;

The other alternative is to provide a subclass of I<LWP::UserAgent> that
overrides the get_basic_credentials() method. Study the I<lwp-request>
program for an example of this.


=head1 COOKIES

Some sites like to play games with cookies.  By default LWP ignores
cookies provided by the servers it visits.  LWP will collect cookies
and respond to cookie requests if you set up a cookie jar. LWP doesn't
provide a cookie jar itself, but if you install L<HTTP::CookieJar::LWP>,
it can be used like this:

  use LWP::UserAgent;
  use HTTP::CookieJar::LWP;

  $ua = LWP::UserAgent->new(
      cookie_jar => HTTP::CookieJar::LWP->new,
  );

  # and then send requests just as you used to do
  $res = $ua->request(HTTP::Request->new(GET => "http://no.yahoo.com/"));
  print $res->status_line, "\n";

=head1 HTTPS

URLs with https scheme are accessed in exactly the same way as with
http scheme, provided that an SSL interface module for LWP has been
properly installed (see the F<README.SSL> file found in the
libwww-perl distribution for more details).  If no SSL interface is
installed for LWP to use, then you will get "501 Protocol scheme
'https' is not supported" errors when accessing such URLs.

Here's an example of fetching and printing a WWW page using SSL:

  use LWP::UserAgent;

  my $ua = LWP::UserAgent->new;
  my $req = HTTP::Request->new(GET => 'https://www.helsinki.fi/');
  my $res = $ua->request($req);
  if ($res->is_success) {
      print $res->as_string;
  }
  else {
      print "Failed: ", $res->status_line, "\n";
  }

=head1 MIRRORING

If you want to mirror documents from a WWW server, then try to run
code similar to this at regular intervals:

  use LWP::Simple;

  %mirrors = (
     'http://www.sn.no/'                       => 'sn.html',
     'http://www.perl.com/'                    => 'perl.html',
     'http://search.cpan.org/distlibwww-perl/' => 'lwp.html',
     'gopher://gopher.sn.no/'                  => 'gopher.html',
  );

  while (($url, $localfile) = each(%mirrors)) {
     mirror($url, $localfile);
  }

Or, as a perl one-liner:

  perl -MLWP::Simple -e 'mirror("http://www.perl.com/", "perl.html")';

The document will not be transferred unless it has been updated.



=head1 LARGE DOCUMENTS

If the document you want to fetch is too large to be kept in memory,
then you have two alternatives.  You can instruct the library to write
the document content to a file (second $ua->request() argument is a file
name):

  use LWP::UserAgent;
  $ua = LWP::UserAgent->new;

  my $req = HTTP::Request->new(GET =>
      'http://www.cpan.org/CPAN/authors/id/O/OA/OALDERS/libwww-perl-6.26.tar.gz');
  $res = $ua->request($req, "libwww-perl.tar.gz");
  if ($res->is_success) {
     print "ok\n";
  }
  else {
     print $res->status_line, "\n";
  }


Or you can process the document as it arrives (second $ua->request()
argument is a code reference):

  use LWP::UserAgent;
  $ua = LWP::UserAgent->new;
  $URL = 'ftp://ftp.isc.org/pub/rfc/rfc-index.txt';

  my $expected_length;
  my $bytes_received = 0;
  my $res =
     $ua->request(HTTP::Request->new(GET => $URL),
               sub {
                   my($chunk, $res) = @_;
                   $bytes_received += length($chunk);
	           unless (defined $expected_length) {
	              $expected_length = $res->content_length || 0;
                   }
		   if ($expected_length) {
		        printf STDERR "%d%% - ",
	                          100 * $bytes_received / $expected_length;
                   }
	           print STDERR "$bytes_received bytes received\n";

                   # XXX Should really do something with the chunk itself
	           # print $chunk;
               });
   print $res->status_line, "\n";



=head1 COPYRIGHT

Copyright 1996-2001, Gisle Aas

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


PK1N%[�^�`R	R	perl5/Path/Class/Entity.pmnu��6�$use strict;

package Path::Class::Entity;
{
  $Path::Class::Entity::VERSION = '0.37';
}

use File::Spec 3.26;
use File::stat ();
use Cwd;
use Carp();

use overload
  (
   q[""] => 'stringify',
   'bool' => 'boolify',
   fallback => 1,
  );

sub new {
  my $from = shift;
  my ($class, $fs_class) = (ref($from)
			    ? (ref $from, $from->{file_spec_class})
			    : ($from, $Path::Class::Foreign));
  return bless {file_spec_class => $fs_class}, $class;
}

sub is_dir { 0 }

sub _spec_class {
  my ($class, $type) = @_;

  die "Invalid system type '$type'" unless ($type) = $type =~ /^(\w+)$/;  # Untaint
  my $spec = "File::Spec::$type";
  ## no critic
  eval "require $spec; 1" or die $@;
  return $spec;
}

sub new_foreign {
  my ($class, $type) = (shift, shift);
  local $Path::Class::Foreign = $class->_spec_class($type);
  return $class->new(@_);
}

sub _spec { (ref($_[0]) && $_[0]->{file_spec_class}) || 'File::Spec' }

sub boolify { 1 }
  
sub is_absolute { 
  # 5.6.0 has a bug with regexes and stringification that's ticked by
  # file_name_is_absolute().  Help it along with an explicit stringify().
  $_[0]->_spec->file_name_is_absolute($_[0]->stringify) 
}

sub is_relative { ! $_[0]->is_absolute }

sub cleanup {
  my $self = shift;
  my $cleaned = $self->new( $self->_spec->canonpath("$self") );
  %$self = %$cleaned;
  return $self;
}

sub resolve {
  my $self = shift;
  Carp::croak($! . " $self") unless -e $self;  # No such file or directory
  my $cleaned = $self->new( scalar Cwd::realpath($self->stringify) );

  # realpath() always returns absolute path, kind of annoying
  $cleaned = $cleaned->relative if $self->is_relative;

  %$self = %$cleaned;
  return $self;
}

sub absolute {
  my $self = shift;
  return $self if $self->is_absolute;
  return $self->new($self->_spec->rel2abs($self->stringify, @_));
}

sub relative {
  my $self = shift;
  return $self->new($self->_spec->abs2rel($self->stringify, @_));
}

sub stat  { File::stat::stat("$_[0]") }
sub lstat { File::stat::lstat("$_[0]") }

sub PRUNE { return \&PRUNE; }

1;
__END__

=head1 NAME

Path::Class::Entity - Base class for files and directories

=head1 VERSION

version 0.37

=head1 DESCRIPTION

This class is the base class for C<Path::Class::File> and
C<Path::Class::Dir>, it is not used directly by callers.

=head1 AUTHOR

Ken Williams, kwilliams@cpan.org

=head1 SEE ALSO

Path::Class

=cut
PK1N%[K�+�k9k9perl5/Path/Class/File.pmnu��6�$use strict;

package Path::Class::File;
{
  $Path::Class::File::VERSION = '0.37';
}

use Path::Class::Dir;
use parent qw(Path::Class::Entity);
use Carp;

use IO::File ();

sub new {
  my $self = shift->SUPER::new;
  my $file = pop();
  my @dirs = @_;

  my ($volume, $dirs, $base) = $self->_spec->splitpath($file);

  if (length $dirs) {
    push @dirs, $self->_spec->catpath($volume, $dirs, '');
  }

  $self->{dir}  = @dirs ? $self->dir_class->new(@dirs) : undef;
  $self->{file} = $base;

  return $self;
}

sub dir_class { "Path::Class::Dir" }

sub as_foreign {
  my ($self, $type) = @_;
  local $Path::Class::Foreign = $self->_spec_class($type);
  my $foreign = ref($self)->SUPER::new;
  $foreign->{dir} = $self->{dir}->as_foreign($type) if defined $self->{dir};
  $foreign->{file} = $self->{file};
  return $foreign;
}

sub stringify {
  my $self = shift;
  return $self->{file} unless defined $self->{dir};
  return $self->_spec->catfile($self->{dir}->stringify, $self->{file});
}

sub dir {
  my $self = shift;
  return $self->{dir} if defined $self->{dir};
  return $self->dir_class->new($self->_spec->curdir);
}
BEGIN { *parent = \&dir; }

sub volume {
  my $self = shift;
  return '' unless defined $self->{dir};
  return $self->{dir}->volume;
}

sub components {
  my $self = shift;
  croak "Arguments are not currently supported by File->components()" if @_;
  return ($self->dir->components, $self->basename);
}

sub basename { shift->{file} }
sub open  { IO::File->new(@_) }

sub openr { $_[0]->open('r') or croak "Can't read $_[0]: $!"  }
sub openw { $_[0]->open('w') or croak "Can't write to $_[0]: $!" }
sub opena { $_[0]->open('a') or croak "Can't append to $_[0]: $!" }

sub touch {
  my $self = shift;
  if (-e $self) {
    utime undef, undef, $self;
  } else {
    $self->openw;
  }
}

sub slurp {
  my ($self, %args) = @_;
  my $iomode = $args{iomode} || 'r';
  my $fh = $self->open($iomode) or croak "Can't read $self: $!";

  if (wantarray) {
    my @data = <$fh>;
    chomp @data if $args{chomped} or $args{chomp};

    if ( my $splitter = $args{split} ) {
      @data = map { [ split $splitter, $_ ] } @data;
    }

    return @data;
  }


  croak "'split' argument can only be used in list context"
    if $args{split};


  if ($args{chomped} or $args{chomp}) {
    chomp( my @data = <$fh> );
    return join '', @data;
  }


  local $/;
  return <$fh>;
}

sub spew {
    my $self = shift;
    my %args = splice( @_, 0, @_-1 );

    my $iomode = $args{iomode} || 'w';
    my $fh = $self->open( $iomode ) or croak "Can't write to $self: $!";

    if (ref($_[0]) eq 'ARRAY') {
        # Use old-school for loop to avoid copying.
        for (my $i = 0; $i < @{ $_[0] }; $i++) {
            print $fh $_[0]->[$i]
                or croak "Can't write to $self: $!";
        }
    }
    else {
        print $fh $_[0]
            or croak "Can't write to $self: $!";
    }

    close $fh
        or croak "Can't write to $self: $!";

    return;
}

sub spew_lines {
    my $self = shift;
    my %args = splice( @_, 0, @_-1 );

    my $content = $_[0];

    # If content is an array ref, appends $/ to each element of the array.
    # Otherwise, if it is a simple scalar, just appends $/ to that scalar.

    $content
        = ref( $content ) eq 'ARRAY'
        ? [ map { $_, $/ } @$content ]
        : "$content$/";

    return $self->spew( %args, $content );
}

sub remove {
  my $file = shift->stringify;
  return unlink $file unless -e $file; # Sets $! correctly
  1 while unlink $file;
  return not -e $file;
}

sub copy_to {
  my ($self, $dest) = @_;
  if ( eval{ $dest->isa("Path::Class::File")} ) { 
    $dest = $dest->stringify;
    croak "Can't copy to file $dest: it is a directory" if -d $dest;
  } elsif ( eval{ $dest->isa("Path::Class::Dir") } ) {
    $dest = $dest->stringify;
    croak "Can't copy to directory $dest: it is a file" if -f $dest;
    croak "Can't copy to directory $dest: no such directory" unless -d $dest;
  } elsif ( ref $dest ) {
    croak "Don't know how to copy files to objects of type '".ref($self)."'";
  }

  require Perl::OSType;
  if ( !Perl::OSType::is_os_type('Unix') ) {

      require File::Copy;
      return unless File::Copy::cp($self->stringify, "${dest}");

  } else {

      return unless (system('cp', $self->stringify, "${dest}") == 0);

  }

  return $self->new($dest);
}

sub move_to {
  my ($self, $dest) = @_;
  require File::Copy;
  if (File::Copy::move($self->stringify, "${dest}")) {

      my $new = $self->new($dest);

      $self->{$_} = $new->{$_} foreach (qw/ dir file /);

      return $self;

  } else {

      return;

  }
}

sub traverse {
  my $self = shift;
  my ($callback, @args) = @_;
  return $self->$callback(sub { () }, @args);
}

sub traverse_if {
  my $self = shift;
  my ($callback, $condition, @args) = @_;
  return $self->$callback(sub { () }, @args);
}

1;
__END__

=head1 NAME

Path::Class::File - Objects representing files

=head1 VERSION

version 0.37

=head1 SYNOPSIS

  use Path::Class;  # Exports file() by default

  my $file = file('foo', 'bar.txt');  # Path::Class::File object
  my $file = Path::Class::File->new('foo', 'bar.txt'); # Same thing

  # Stringifies to 'foo/bar.txt' on Unix, 'foo\bar.txt' on Windows, etc.
  print "file: $file\n";

  if ($file->is_absolute) { ... }
  if ($file->is_relative) { ... }

  my $v = $file->volume; # Could be 'C:' on Windows, empty string
                         # on Unix, 'Macintosh HD:' on Mac OS

  $file->cleanup; # Perform logical cleanup of pathname
  $file->resolve; # Perform physical cleanup of pathname

  my $dir = $file->dir;  # A Path::Class::Dir object

  my $abs = $file->absolute; # Transform to absolute path
  my $rel = $file->relative; # Transform to relative path

=head1 DESCRIPTION

The C<Path::Class::File> class contains functionality for manipulating
file names in a cross-platform way.

=head1 METHODS

=over 4

=item $file = Path::Class::File->new( <dir1>, <dir2>, ..., <file> )

=item $file = file( <dir1>, <dir2>, ..., <file> )

Creates a new C<Path::Class::File> object and returns it.  The
arguments specify the path to the file.  Any volume may also be
specified as the first argument, or as part of the first argument.
You can use platform-neutral syntax:

  my $file = file( 'foo', 'bar', 'baz.txt' );

or platform-native syntax:

  my $file = file( 'foo/bar/baz.txt' );

or a mixture of the two:

  my $file = file( 'foo/bar', 'baz.txt' );

All three of the above examples create relative paths.  To create an
absolute path, either use the platform native syntax for doing so:

  my $file = file( '/var/tmp/foo.txt' );

or use an empty string as the first argument:

  my $file = file( '', 'var', 'tmp', 'foo.txt' );

If the second form seems awkward, that's somewhat intentional - paths
like C</var/tmp> or C<\Windows> aren't cross-platform concepts in the
first place, so they probably shouldn't appear in your code if you're
trying to be cross-platform.  The first form is perfectly fine,
because paths like this may come from config files, user input, or
whatever.

=item $file->stringify

This method is called internally when a C<Path::Class::File> object is
used in a string context, so the following are equivalent:

  $string = $file->stringify;
  $string = "$file";

=item $file->volume

Returns the volume (e.g. C<C:> on Windows, C<Macintosh HD:> on Mac OS,
etc.) of the object, if any.  Otherwise, returns the empty string.

=item $file->basename

Returns the name of the file as a string, without the directory
portion (if any).

=item $file->components

Returns a list of the directory components of this file, followed by
the basename.

Note: unlike C<< $dir->components >>, this method currently does not
accept any arguments to select which elements of the list will be
returned.  It may do so in the future.  Currently it throws an
exception if such arguments are present.


=item $file->is_dir

Returns a boolean value indicating whether this object represents a
directory.  Not surprisingly, C<Path::Class::File> objects always
return false, and L<Path::Class::Dir> objects always return true.

=item $file->is_absolute

Returns true or false depending on whether the file refers to an
absolute path specifier (like C</usr/local/foo.txt> or C<\Windows\Foo.txt>).

=item $file->is_relative

Returns true or false depending on whether the file refers to a
relative path specifier (like C<lib/foo.txt> or C<.\Foo.txt>).

=item $file->cleanup

Performs a logical cleanup of the file path.  For instance:

  my $file = file('/foo//baz/./foo.txt')->cleanup;
  # $file now represents '/foo/baz/foo.txt';

=item $dir->resolve

Performs a physical cleanup of the file path.  For instance:

  my $file = file('/foo/baz/../foo.txt')->resolve;
  # $file now represents '/foo/foo.txt', assuming no symlinks

This actually consults the filesystem to verify the validity of the
path.

=item $dir = $file->dir

Returns a C<Path::Class::Dir> object representing the directory
containing this file.

=item $dir = $file->parent

A synonym for the C<dir()> method.

=item $abs = $file->absolute

Returns a C<Path::Class::File> object representing C<$file> as an
absolute path.  An optional argument, given as either a string or a
L<Path::Class::Dir> object, specifies the directory to use as the base
of relativity - otherwise the current working directory will be used.

=item $rel = $file->relative

Returns a C<Path::Class::File> object representing C<$file> as a
relative path.  An optional argument, given as either a string or a
C<Path::Class::Dir> object, specifies the directory to use as the base
of relativity - otherwise the current working directory will be used.

=item $foreign = $file->as_foreign($type)

Returns a C<Path::Class::File> object representing C<$file> as it would
be specified on a system of type C<$type>.  Known types include
C<Unix>, C<Win32>, C<Mac>, C<VMS>, and C<OS2>, i.e. anything for which
there is a subclass of C<File::Spec>.

Any generated objects (subdirectories, files, parents, etc.) will also
retain this type.

=item $foreign = Path::Class::File->new_foreign($type, @args)

Returns a C<Path::Class::File> object representing a file as it would
be specified on a system of type C<$type>.  Known types include
C<Unix>, C<Win32>, C<Mac>, C<VMS>, and C<OS2>, i.e. anything for which
there is a subclass of C<File::Spec>.

The arguments in C<@args> are the same as they would be specified in
C<new()>.

=item $fh = $file->open($mode, $permissions)

Passes the given arguments, including C<$file>, to C<< IO::File->new >>
(which in turn calls C<< IO::File->open >> and returns the result
as an L<IO::File> object.  If the opening
fails, C<undef> is returned and C<$!> is set.

=item $fh = $file->openr()

A shortcut for

 $fh = $file->open('r') or croak "Can't read $file: $!";

=item $fh = $file->openw()

A shortcut for

 $fh = $file->open('w') or croak "Can't write to $file: $!";

=item $fh = $file->opena()

A shortcut for

 $fh = $file->open('a') or croak "Can't append to $file: $!";

=item $file->touch

Sets the modification and access time of the given file to right now,
if the file exists.  If it doesn't exist, C<touch()> will I<make> it
exist, and - YES! - set its modification and access time to now.

=item $file->slurp()

In a scalar context, returns the contents of C<$file> in a string.  In
a list context, returns the lines of C<$file> (according to how C<$/>
is set) as a list.  If the file can't be read, this method will throw
an exception.

If you want C<chomp()> run on each line of the file, pass a true value
for the C<chomp> or C<chomped> parameters:

  my @lines = $file->slurp(chomp => 1);

You may also use the C<iomode> parameter to pass in an IO mode to use
when opening the file, usually IO layers (though anything accepted by
the MODE argument of C<open()> is accepted here).  Just make sure it's
a I<reading> mode.

  my @lines = $file->slurp(iomode => ':crlf');
  my $lines = $file->slurp(iomode => '<:encoding(UTF-8)');

The default C<iomode> is C<r>.

Lines can also be automatically split, mimicking the perl command-line
option C<-a> by using the C<split> parameter. If this parameter is used,
each line will be returned as an array ref.

    my @lines = $file->slurp( chomp => 1, split => qr/\s*,\s*/ );

The C<split> parameter can only be used in a list context.

=item $file->spew( $content );

The opposite of L</slurp>, this takes a list of strings and prints them
to the file in write mode.  If the file can't be written to, this method
will throw an exception.

The content to be written can be either an array ref or a plain scalar.
If the content is an array ref then each entry in the array will be
written to the file.

You may use the C<iomode> parameter to pass in an IO mode to use when
opening the file, just like L</slurp> supports.

  $file->spew(iomode => '>:raw', $content);

The default C<iomode> is C<w>.

=item $file->spew_lines( $content );

Just like C<spew>, but, if $content is a plain scalar, appends $/
to it, or, if $content is an array ref, appends $/ to each element
of the array.

Can also take an C<iomode> parameter like C<spew>. Again, the
default C<iomode> is C<w>.

=item $file->traverse(sub { ... }, @args)

Calls the given callback on $file. This doesn't do much on its own,
but see the associated documentation in L<Path::Class::Dir>.

=item $file->remove()

This method will remove the file in a way that works well on all
platforms, and returns a boolean value indicating whether or not the
file was successfully removed.

C<remove()> is better than simply calling Perl's C<unlink()> function,
because on some platforms (notably VMS) you actually may need to call
C<unlink()> several times before all versions of the file are gone -
the C<remove()> method handles this process for you.

=item $st = $file->stat()

Invokes C<< File::stat::stat() >> on this file and returns a
L<File::stat> object representing the result.

=item $st = $file->lstat()

Same as C<stat()>, but if C<$file> is a symbolic link, C<lstat()>
stats the link instead of the file the link points to.

=item $class = $file->dir_class()

Returns the class which should be used to create directory objects.

Generally overridden whenever this class is subclassed.

=item $copy = $file->copy_to( $dest );

Copies the C<$file> to C<$dest>. It returns a L<Path::Class::File>
object when successful, C<undef> otherwise.

=item $moved = $file->move_to( $dest );

Moves the C<$file> to C<$dest>, and updates C<$file> accordingly.

It returns C<$file> is successful, C<undef> otherwise.

=back

=head1 AUTHOR

Ken Williams, kwilliams@cpan.org

=head1 SEE ALSO

L<Path::Class>, L<Path::Class::Dir>, L<File::Spec>

=cut
PK1N%[f����a�aperl5/Path/Class/Dir.pmnu��6�$use strict;

package Path::Class::Dir;
{
  $Path::Class::Dir::VERSION = '0.37';
}

use Path::Class::File;
use Carp();
use parent qw(Path::Class::Entity);

use IO::Dir ();
use File::Path ();
use File::Temp ();
use Scalar::Util ();

# updir & curdir on the local machine, for screening them out in
# children().  Note that they don't respect 'foreign' semantics.
my $Updir  = __PACKAGE__->_spec->updir;
my $Curdir = __PACKAGE__->_spec->curdir;

sub new {
  my $self = shift->SUPER::new();

  # If the only arg is undef, it's probably a mistake.  Without this
  # special case here, we'd return the root directory, which is a
  # lousy thing to do to someone when they made a mistake.  Return
  # undef instead.
  return if @_==1 && !defined($_[0]);

  my $s = $self->_spec;
  
  my $first = (@_ == 0     ? $s->curdir :
	       !ref($_[0]) && $_[0] eq '' ? (shift, $s->rootdir) :
	       shift()
	      );
  
  $self->{dirs} = [];
  if ( Scalar::Util::blessed($first) && $first->isa("Path::Class::Dir") ) {
    $self->{volume} = $first->{volume};
    push @{$self->{dirs}}, @{$first->{dirs}};
  }
  else {
    ($self->{volume}, my $dirs) = $s->splitpath( $s->canonpath("$first") , 1);
    push @{$self->{dirs}}, $dirs eq $s->rootdir ? "" : $s->splitdir($dirs);
  }

  push @{$self->{dirs}}, map {
    Scalar::Util::blessed($_) && $_->isa("Path::Class::Dir")
      ? @{$_->{dirs}}
      : $s->splitdir( $s->canonpath($_) )
  } @_;


  return $self;
}

sub file_class { "Path::Class::File" }

sub is_dir { 1 }

sub as_foreign {
  my ($self, $type) = @_;

  my $foreign = do {
    local $self->{file_spec_class} = $self->_spec_class($type);
    $self->SUPER::new;
  };
  
  # Clone internal structure
  $foreign->{volume} = $self->{volume};
  my ($u, $fu) = ($self->_spec->updir, $foreign->_spec->updir);
  $foreign->{dirs} = [ map {$_ eq $u ? $fu : $_} @{$self->{dirs}}];
  return $foreign;
}

sub stringify {
  my $self = shift;
  my $s = $self->_spec;
  return $s->catpath($self->{volume},
		     $s->catdir(@{$self->{dirs}}),
		     '');
}

sub volume { shift()->{volume} }

sub file {
  local $Path::Class::Foreign = $_[0]->{file_spec_class} if $_[0]->{file_spec_class};
  return $_[0]->file_class->new(@_);
}

sub basename { shift()->{dirs}[-1] }

sub dir_list {
  my $self = shift;
  my $d = $self->{dirs};
  return @$d unless @_;
  
  my $offset = shift;
  if ($offset < 0) { $offset = $#$d + $offset + 1 }
  
  return wantarray ? @$d[$offset .. $#$d] : $d->[$offset] unless @_;
  
  my $length = shift;
  if ($length < 0) { $length = $#$d + $length + 1 - $offset }
  return @$d[$offset .. $length + $offset - 1];
}

sub components {
  my $self = shift;
  return $self->dir_list(@_);
}

sub subdir {
  my $self = shift;
  return $self->new($self, @_);
}

sub parent {
  my $self = shift;
  my $dirs = $self->{dirs};
  my ($curdir, $updir) = ($self->_spec->curdir, $self->_spec->updir);

  if ($self->is_absolute) {
    my $parent = $self->new($self);
    pop @{$parent->{dirs}} if @$dirs > 1;
    return $parent;

  } elsif ($self eq $curdir) {
    return $self->new($updir);

  } elsif (!grep {$_ ne $updir} @$dirs) {  # All updirs
    return $self->new($self, $updir); # Add one more

  } elsif (@$dirs == 1) {
    return $self->new($curdir);

  } else {
    my $parent = $self->new($self);
    pop @{$parent->{dirs}};
    return $parent;
  }
}

sub relative {
  # File::Spec->abs2rel before version 3.13 returned the empty string
  # when the two paths were equal - work around it here.
  my $self = shift;
  my $rel = $self->_spec->abs2rel($self->stringify, @_);
  return $self->new( length $rel ? $rel : $self->_spec->curdir );
}

sub open  { IO::Dir->new(@_) }
sub mkpath { File::Path::mkpath(shift()->stringify, @_) }
sub rmtree { File::Path::rmtree(shift()->stringify, @_) }

sub remove {
  rmdir( shift() );
}

sub traverse {
  my $self = shift;
  my ($callback, @args) = @_;
  my @children = $self->children;
  return $self->$callback(
    sub {
      my @inner_args = @_;
      return map { $_->traverse($callback, @inner_args) } @children;
    },
    @args
  );
}

sub traverse_if {
  my $self = shift;
  my ($callback, $condition, @args) = @_;
  my @children = grep { $condition->($_) } $self->children;
  return $self->$callback(
    sub {
      my @inner_args = @_;
      return map { $_->traverse_if($callback, $condition, @inner_args) } @children;
    },
    @args
  );
}

sub recurse {
  my $self = shift;
  my %opts = (preorder => 1, depthfirst => 0, @_);
  
  my $callback = $opts{callback}
    or Carp::croak( "Must provide a 'callback' parameter to recurse()" );
  
  my @queue = ($self);
  
  my $visit_entry;
  my $visit_dir = 
    $opts{depthfirst} && $opts{preorder}
    ? sub {
      my $dir = shift;
      my $ret = $callback->($dir);
      unless( ($ret||'') eq $self->PRUNE ) {
          unshift @queue, $dir->children;
      }
    }
    : $opts{preorder}
    ? sub {
      my $dir = shift;
      my $ret = $callback->($dir);
      unless( ($ret||'') eq $self->PRUNE ) {
          push @queue, $dir->children;
      }
    }
    : sub {
      my $dir = shift;
      $visit_entry->($_) foreach $dir->children;
      $callback->($dir);
    };
  
  $visit_entry = sub {
    my $entry = shift;
    if ($entry->is_dir) { $visit_dir->($entry) } # Will call $callback
    else { $callback->($entry) }
  };
  
  while (@queue) {
    $visit_entry->( shift @queue );
  }
}

sub children {
  my ($self, %opts) = @_;
  
  my $dh = $self->open or Carp::croak( "Can't open directory $self: $!" );
  
  my @out;
  while (defined(my $entry = $dh->read)) {
    next if !$opts{all} && $self->_is_local_dot_dir($entry);
    next if ($opts{no_hidden} && $entry =~ /^\./);
    push @out, $self->file($entry);
    $out[-1] = $self->subdir($entry) if -d $out[-1];
  }
  return @out;
}

sub _is_local_dot_dir {
  my $self = shift;
  my $dir  = shift;

  return ($dir eq $Updir or $dir eq $Curdir);
}

sub next {
  my $self = shift;
  unless ($self->{dh}) {
    $self->{dh} = $self->open or Carp::croak( "Can't open directory $self: $!" );
  }
  
  my $next = $self->{dh}->read;
  unless (defined $next) {
    delete $self->{dh};
    ## no critic
    return undef;
  }
  
  # Figure out whether it's a file or directory
  my $file = $self->file($next);
  $file = $self->subdir($next) if -d $file;
  return $file;
}

sub subsumes {
  Carp::croak "Too many arguments given to subsumes()" if $#_ > 2;
  my ($self, $other) = @_;
  Carp::croak( "No second entity given to subsumes()" ) unless defined $other;

  $other = $self->new($other) unless eval{$other->isa( "Path::Class::Entity")};
  $other = $other->dir unless $other->is_dir;

  if ($self->is_absolute) {
    $other = $other->absolute;
  } elsif ($other->is_absolute) {
    $self = $self->absolute;
  }

  $self = $self->cleanup;
  $other = $other->cleanup;

  if ($self->volume || $other->volume) {
    return 0 unless $other->volume eq $self->volume;
  }

  # The root dir subsumes everything (but ignore the volume because
  # we've already checked that)
  return 1 if "@{$self->{dirs}}" eq "@{$self->new('')->{dirs}}";

  # The current dir subsumes every relative path (unless starting with updir)
  if ($self eq $self->_spec->curdir) {
    return $other->{dirs}[0] ne $self->_spec->updir;
  }

  my $i = 0;
  while ($i <= $#{ $self->{dirs} }) {
    return 0 if $i > $#{ $other->{dirs} };
    return 0 if $self->{dirs}[$i] ne $other->{dirs}[$i];
    $i++;
  }
  return 1;
}

sub contains {
  Carp::croak "Too many arguments given to contains()" if $#_ > 2;
  my ($self, $other) = @_;
  Carp::croak "No second entity given to contains()" unless defined $other;
  return unless -d $self and (-e $other or -l $other);

  # We're going to resolve the path, and don't want side effects on the objects
  # so clone them.  This also handles strings passed as $other.
  $self= $self->new($self)->resolve;
  $other= $self->new($other)->resolve;
  
  return $self->subsumes($other);
}

sub tempfile {
  my $self = shift;
  return File::Temp::tempfile(@_, DIR => $self->stringify);
}

1;
__END__

=head1 NAME

Path::Class::Dir - Objects representing directories

=head1 VERSION

version 0.37

=head1 SYNOPSIS

  use Path::Class;  # Exports dir() by default
  
  my $dir = dir('foo', 'bar');       # Path::Class::Dir object
  my $dir = Path::Class::Dir->new('foo', 'bar');  # Same thing
  
  # Stringifies to 'foo/bar' on Unix, 'foo\bar' on Windows, etc.
  print "dir: $dir\n";
  
  if ($dir->is_absolute) { ... }
  if ($dir->is_relative) { ... }
  
  my $v = $dir->volume; # Could be 'C:' on Windows, empty string
                        # on Unix, 'Macintosh HD:' on Mac OS
  
  $dir->cleanup; # Perform logical cleanup of pathname
  $dir->resolve; # Perform physical cleanup of pathname
  
  my $file = $dir->file('file.txt'); # A file in this directory
  my $subdir = $dir->subdir('george'); # A subdirectory
  my $parent = $dir->parent; # The parent directory, 'foo'
  
  my $abs = $dir->absolute; # Transform to absolute path
  my $rel = $abs->relative; # Transform to relative path
  my $rel = $abs->relative('/foo'); # Relative to /foo
  
  print $dir->as_foreign('Mac');   # :foo:bar:
  print $dir->as_foreign('Win32'); #  foo\bar

  # Iterate with IO::Dir methods:
  my $handle = $dir->open;
  while (my $file = $handle->read) {
    $file = $dir->file($file);  # Turn into Path::Class::File object
    ...
  }
  
  # Iterate with Path::Class methods:
  while (my $file = $dir->next) {
    # $file is a Path::Class::File or Path::Class::Dir object
    ...
  }


=head1 DESCRIPTION

The C<Path::Class::Dir> class contains functionality for manipulating
directory names in a cross-platform way.

=head1 METHODS

=over 4

=item $dir = Path::Class::Dir->new( <dir1>, <dir2>, ... )

=item $dir = dir( <dir1>, <dir2>, ... )

Creates a new C<Path::Class::Dir> object and returns it.  The
arguments specify names of directories which will be joined to create
a single directory object.  A volume may also be specified as the
first argument, or as part of the first argument.  You can use
platform-neutral syntax:

  my $dir = dir( 'foo', 'bar', 'baz' );

or platform-native syntax:

  my $dir = dir( 'foo/bar/baz' );

or a mixture of the two:

  my $dir = dir( 'foo/bar', 'baz' );

All three of the above examples create relative paths.  To create an
absolute path, either use the platform native syntax for doing so:

  my $dir = dir( '/var/tmp' );

or use an empty string as the first argument:

  my $dir = dir( '', 'var', 'tmp' );

If the second form seems awkward, that's somewhat intentional - paths
like C</var/tmp> or C<\Windows> aren't cross-platform concepts in the
first place (many non-Unix platforms don't have a notion of a "root
directory"), so they probably shouldn't appear in your code if you're
trying to be cross-platform.  The first form is perfectly natural,
because paths like this may come from config files, user input, or
whatever.

As a special case, since it doesn't otherwise mean anything useful and
it's convenient to define this way, C<< Path::Class::Dir->new() >> (or
C<dir()>) refers to the current directory (C<< File::Spec->curdir >>).
To get the current directory as an absolute path, do C<<
dir()->absolute >>.

Finally, as another special case C<dir(undef)> will return undef,
since that's usually an accident on the part of the caller, and
returning the root directory would be a nasty surprise just asking for
trouble a few lines later.

=item $dir->stringify

This method is called internally when a C<Path::Class::Dir> object is
used in a string context, so the following are equivalent:

  $string = $dir->stringify;
  $string = "$dir";

=item $dir->volume

Returns the volume (e.g. C<C:> on Windows, C<Macintosh HD:> on Mac OS,
etc.) of the directory object, if any.  Otherwise, returns the empty
string.

=item $dir->basename

Returns the last directory name of the path as a string.

=item $dir->is_dir

Returns a boolean value indicating whether this object represents a
directory.  Not surprisingly, L<Path::Class::File> objects always
return false, and C<Path::Class::Dir> objects always return true.

=item $dir->is_absolute

Returns true or false depending on whether the directory refers to an
absolute path specifier (like C</usr/local> or C<\Windows>).

=item $dir->is_relative

Returns true or false depending on whether the directory refers to a
relative path specifier (like C<lib/foo> or C<./dir>).

=item $dir->cleanup

Performs a logical cleanup of the file path.  For instance:

  my $dir = dir('/foo//baz/./foo')->cleanup;
  # $dir now represents '/foo/baz/foo';

=item $dir->resolve

Performs a physical cleanup of the file path.  For instance:

  my $dir = dir('/foo//baz/../foo')->resolve;
  # $dir now represents '/foo/foo', assuming no symlinks

This actually consults the filesystem to verify the validity of the
path.

=item $file = $dir->file( <dir1>, <dir2>, ..., <file> )

Returns a L<Path::Class::File> object representing an entry in C<$dir>
or one of its subdirectories.  Internally, this just calls C<<
Path::Class::File->new( @_ ) >>.

=item $subdir = $dir->subdir( <dir1>, <dir2>, ... )

Returns a new C<Path::Class::Dir> object representing a subdirectory
of C<$dir>.

=item $parent = $dir->parent

Returns the parent directory of C<$dir>.  Note that this is the
I<logical> parent, not necessarily the physical parent.  It really
means we just chop off entries from the end of the directory list
until we cain't chop no more.  If the directory is relative, we start
using the relative forms of parent directories.

The following code demonstrates the behavior on absolute and relative
directories:

  $dir = dir('/foo/bar');
  for (1..6) {
    print "Absolute: $dir\n";
    $dir = $dir->parent;
  }
  
  $dir = dir('foo/bar');
  for (1..6) {
    print "Relative: $dir\n";
    $dir = $dir->parent;
  }
  
  ########### Output on Unix ################
  Absolute: /foo/bar
  Absolute: /foo
  Absolute: /
  Absolute: /
  Absolute: /
  Absolute: /
  Relative: foo/bar
  Relative: foo
  Relative: .
  Relative: ..
  Relative: ../..
  Relative: ../../..

=item @list = $dir->children

Returns a list of L<Path::Class::File> and/or C<Path::Class::Dir>
objects listed in this directory, or in scalar context the number of
such objects.  Obviously, it is necessary for C<$dir> to
exist and be readable in order to find its children.

Note that the children are returned as subdirectories of C<$dir>,
i.e. the children of F<foo> will be F<foo/bar> and F<foo/baz>, not
F<bar> and F<baz>.

Ordinarily C<children()> will not include the I<self> and I<parent>
entries C<.> and C<..> (or their equivalents on non-Unix systems),
because that's like I'm-my-own-grandpa business.  If you do want all
directory entries including these special ones, pass a true value for
the C<all> parameter:

  @c = $dir->children(); # Just the children
  @c = $dir->children(all => 1); # All entries

In addition, there's a C<no_hidden> parameter that will exclude all
normally "hidden" entries - on Unix this means excluding all entries
that begin with a dot (C<.>):

  @c = $dir->children(no_hidden => 1); # Just normally-visible entries


=item $abs = $dir->absolute

Returns a C<Path::Class::Dir> object representing C<$dir> as an
absolute path.  An optional argument, given as either a string or a
C<Path::Class::Dir> object, specifies the directory to use as the base
of relativity - otherwise the current working directory will be used.

=item $rel = $dir->relative

Returns a C<Path::Class::Dir> object representing C<$dir> as a
relative path.  An optional argument, given as either a string or a
C<Path::Class::Dir> object, specifies the directory to use as the base
of relativity - otherwise the current working directory will be used.

=item $boolean = $dir->subsumes($other)

Returns true if this directory spec subsumes the other spec, and false
otherwise.  Think of "subsumes" as "contains", but we only look at the
I<specs>, not whether C<$dir> actually contains C<$other> on the
filesystem.

The C<$other> argument may be a C<Path::Class::Dir> object, a
L<Path::Class::File> object, or a string.  In the latter case, we
assume it's a directory.

  # Examples:
  dir('foo/bar' )->subsumes(dir('foo/bar/baz'))  # True
  dir('/foo/bar')->subsumes(dir('/foo/bar/baz')) # True
  dir('foo/..')->subsumes(dir('foo/../bar))      # True
  dir('foo/bar' )->subsumes(dir('bar/baz'))      # False
  dir('/foo/bar')->subsumes(dir('foo/bar'))      # False
  dir('foo/..')->subsumes(dir('bar'))            # False! Use C<contains> to resolve ".."


=item $boolean = $dir->contains($other)

Returns true if this directory actually contains C<$other> on the
filesystem.  C<$other> doesn't have to be a direct child of C<$dir>,
it just has to be subsumed after both paths have been resolved.

=item $foreign = $dir->as_foreign($type)

Returns a C<Path::Class::Dir> object representing C<$dir> as it would
be specified on a system of type C<$type>.  Known types include
C<Unix>, C<Win32>, C<Mac>, C<VMS>, and C<OS2>, i.e. anything for which
there is a subclass of C<File::Spec>.

Any generated objects (subdirectories, files, parents, etc.) will also
retain this type.

=item $foreign = Path::Class::Dir->new_foreign($type, @args)

Returns a C<Path::Class::Dir> object representing C<$dir> as it would
be specified on a system of type C<$type>.  Known types include
C<Unix>, C<Win32>, C<Mac>, C<VMS>, and C<OS2>, i.e. anything for which
there is a subclass of C<File::Spec>.

The arguments in C<@args> are the same as they would be specified in
C<new()>.

=item @list = $dir->dir_list([OFFSET, [LENGTH]])

Returns the list of strings internally representing this directory
structure.  Each successive member of the list is understood to be an
entry in its predecessor's directory list.  By contract, C<<
Path::Class->new( $dir->dir_list ) >> should be equivalent to C<$dir>.

The semantics of this method are similar to Perl's C<splice> or
C<substr> functions; they return C<LENGTH> elements starting at
C<OFFSET>.  If C<LENGTH> is omitted, returns all the elements starting
at C<OFFSET> up to the end of the list.  If C<LENGTH> is negative,
returns the elements from C<OFFSET> onward except for C<-LENGTH>
elements at the end.  If C<OFFSET> is negative, it counts backward
C<OFFSET> elements from the end of the list.  If C<OFFSET> and
C<LENGTH> are both omitted, the entire list is returned.

In a scalar context, C<dir_list()> with no arguments returns the
number of entries in the directory list; C<dir_list(OFFSET)> returns
the single element at that offset; C<dir_list(OFFSET, LENGTH)> returns
the final element that would have been returned in a list context.

=item $dir->components

Identical to C<dir_list()>.  It exists because there's an analogous
method C<dir_list()> in the C<Path::Class::File> class that also
returns the basename string, so this method lets someone call
C<components()> without caring whether the object is a file or a
directory.

=item $fh = $dir->open()

Passes C<$dir> to C<< IO::Dir->open >> and returns the result as an
L<IO::Dir> object.  If the opening fails, C<undef> is returned and
C<$!> is set.

=item $dir->mkpath($verbose, $mode)

Passes all arguments, including C<$dir>, to C<< File::Path::mkpath()
>> and returns the result (a list of all directories created).

=item $dir->rmtree($verbose, $cautious)

Passes all arguments, including C<$dir>, to C<< File::Path::rmtree()
>> and returns the result (the number of files successfully deleted).

=item $dir->remove()

Removes the directory, which must be empty.  Returns a boolean value
indicating whether or not the directory was successfully removed.
This method is mainly provided for consistency with
C<Path::Class::File>'s C<remove()> method.

=item $dir->tempfile(...)

An interface to L<File::Temp>'s C<tempfile()> function.  Just like
that function, if you call this in a scalar context, the return value
is the filehandle and the file is C<unlink>ed as soon as possible
(which is immediately on Unix-like platforms).  If called in a list
context, the return values are the filehandle and the filename.

The given directory is passed as the C<DIR> parameter.

Here's an example of pretty good usage which doesn't allow race
conditions, won't leave yucky tempfiles around on your filesystem,
etc.:

  my $fh = $dir->tempfile;
  print $fh "Here's some data...\n";
  seek($fh, 0, 0);
  while (<$fh>) { do something... }

Or in combination with a C<fork>:

  my $fh = $dir->tempfile;
  print $fh "Here's some more data...\n";
  seek($fh, 0, 0);
  if ($pid=fork()) {
    wait;
  } else {
    something($_) while <$fh>;
  }


=item $dir_or_file = $dir->next()

A convenient way to iterate through directory contents.  The first
time C<next()> is called, it will C<open()> the directory and read the
first item from it, returning the result as a C<Path::Class::Dir> or
L<Path::Class::File> object (depending, of course, on its actual
type).  Each subsequent call to C<next()> will simply iterate over the
directory's contents, until there are no more items in the directory,
and then the undefined value is returned.  For example, to iterate
over all the regular files in a directory:

  while (my $file = $dir->next) {
    next unless -f $file;
    my $fh = $file->open('r') or die "Can't read $file: $!";
    ...
  }

If an error occurs when opening the directory (for instance, it
doesn't exist or isn't readable), C<next()> will throw an exception
with the value of C<$!>.

=item $dir->traverse( sub { ... }, @args )

Calls the given callback for the root, passing it a continuation
function which, when called, will call this recursively on each of its
children. The callback function should be of the form:

  sub {
    my ($child, $cont, @args) = @_;
    # ...
  }

For instance, to calculate the number of files in a directory, you
can do this:

  my $nfiles = $dir->traverse(sub {
    my ($child, $cont) = @_;
    return sum($cont->(), ($child->is_dir ? 0 : 1));
  });

or to calculate the maximum depth of a directory:

  my $depth = $dir->traverse(sub {
    my ($child, $cont, $depth) = @_;
    return max($cont->($depth + 1), $depth);
  }, 0);

You can also choose not to call the callback in certain situations:

  $dir->traverse(sub {
    my ($child, $cont) = @_;
    return if -l $child; # don't follow symlinks
    # do something with $child
    return $cont->();
  });

=item $dir->traverse_if( sub { ... }, sub { ... }, @args )

traverse with additional "should I visit this child" callback.
Particularly useful in case examined tree contains inaccessible
directories.

Canonical example:

  $dir->traverse_if(
    sub {
       my ($child, $cont) = @_;
       # do something with $child
       return $cont->();
    }, 
    sub {
       my ($child) = @_;
       # Process only readable items
       return -r $child;
    });

Second callback gets single parameter: child. Only children for
which it returns true will be processed by the first callback.

Remaining parameters are interpreted as in traverse, in particular
C<traverse_if(callback, sub { 1 }, @args> is equivalent to
C<traverse(callback, @args)>.

=item $dir->recurse( callback => sub {...} )

Iterates through this directory and all of its children, and all of
its children's children, etc., calling the C<callback> subroutine for
each entry.  This is a lot like what the L<File::Find> module does,
and of course C<File::Find> will work fine on L<Path::Class> objects,
but the advantage of the C<recurse()> method is that it will also feed
your callback routine C<Path::Class> objects rather than just pathname
strings.

The C<recurse()> method requires a C<callback> parameter specifying
the subroutine to invoke for each entry.  It will be passed the
C<Path::Class> object as its first argument.

C<recurse()> also accepts two boolean parameters, C<depthfirst> and
C<preorder> that control the order of recursion.  The default is a
preorder, breadth-first search, i.e. C<< depthfirst => 0, preorder => 1 >>.
At the time of this writing, all combinations of these two parameters
are supported I<except> C<< depthfirst => 0, preorder => 0 >>.

C<callback> is normally not required to return any value. If it
returns special constant C<Path::Class::Entity::PRUNE()> (more easily
available as C<< $item->PRUNE >>),  no children of analyzed
item will be analyzed (mostly as if you set C<$File::Find::prune=1>). Of course
pruning is available only in C<preorder>, in postorder return value
has no effect.

=item $st = $file->stat()

Invokes C<< File::stat::stat() >> on this directory and returns a
C<File::stat> object representing the result.

=item $st = $file->lstat()

Same as C<stat()>, but if C<$file> is a symbolic link, C<lstat()>
stats the link instead of the directory the link points to.

=item $class = $file->file_class()

Returns the class which should be used to create file objects.

Generally overridden whenever this class is subclassed.

=back

=head1 AUTHOR

Ken Williams, kwilliams@cpan.org

=head1 SEE ALSO

L<Path::Class>, L<Path::Class::File>, L<File::Spec>

=cut
PK1N%[6����perl5/Path/Tiny.pmnu��6�$use 5.008001;
use strict;
use warnings;

package Path::Tiny;
# ABSTRACT: File path utility

our $VERSION = '0.148';

# Dependencies
use Config;
use Exporter 5.57   (qw/import/);
use File::Spec 0.86 ();          # shipped with 5.8.1
use Carp ();

our @EXPORT    = qw/path/;
our @EXPORT_OK = qw/cwd rootdir tempfile tempdir/;

use constant {
    PATH     => 0,
    CANON    => 1,
    VOL      => 2,
    DIR      => 3,
    FILE     => 4,
    TEMP     => 5,
    IS_WIN32 => ( $^O eq 'MSWin32' ),
};

use overload (
    q{""}    => 'stringify',
    bool     => sub () { 1 },
    fallback => 1,
);

# FREEZE/THAW per Sereal/CBOR/Types::Serialiser protocol
sub THAW   { return path( $_[2] ) }
{ no warnings 'once'; *TO_JSON = *FREEZE = \&stringify };

my $HAS_UU; # has Unicode::UTF8; lazily populated

sub _check_UU {
    local $SIG{__DIE__}; # prevent outer handler from being called
    !!eval {
        require Unicode::UTF8;
        Unicode::UTF8->VERSION(0.58);
        1;
    };
}

my $HAS_PU;              # has PerlIO::utf8_strict; lazily populated

sub _check_PU {
    local $SIG{__DIE__}; # prevent outer handler from being called
    !!eval {
        # MUST preload Encode or $SIG{__DIE__} localization fails
        # on some Perl 5.8.8 (maybe other 5.8.*) compiled with -O2.
        require Encode;
        require PerlIO::utf8_strict;
        PerlIO::utf8_strict->VERSION(0.003);
        1;
    };
}

my $HAS_FLOCK = $Config{d_flock} || $Config{d_fcntl_can_lock} || $Config{d_lockf};

# notions of "root" directories differ on Win32: \\server\dir\ or C:\ or \
my $SLASH      = qr{[\\/]};
my $NOTSLASH   = qr{[^\\/]};
my $DRV_VOL    = qr{[a-z]:}i;
my $UNC_VOL    = qr{$SLASH $SLASH $NOTSLASH+ $SLASH $NOTSLASH+}x;
my $WIN32_ROOT = qr{(?: $UNC_VOL $SLASH | $DRV_VOL $SLASH | $SLASH )}x;

sub _win32_vol {
    my ( $path, $drv ) = @_;
    require Cwd;
    my $dcwd = eval { Cwd::getdcwd($drv) }; # C: -> C:\some\cwd
    # getdcwd on non-existent drive returns empty string
    # so just use the original drive Z: -> Z:
    $dcwd = "$drv" unless defined $dcwd && length $dcwd;
    # normalize dwcd to end with a slash: might be C:\some\cwd or D:\ or Z:
    $dcwd =~ s{$SLASH?\z}{/};
    # make the path absolute with dcwd
    $path =~ s{^$DRV_VOL}{$dcwd};
    return $path;
}

# This is a string test for before we have the object; see is_rootdir for well-formed
# object test
sub _is_root {
    return IS_WIN32() ? ( $_[0] =~ /^$WIN32_ROOT\z/ ) : ( $_[0] eq '/' );
}

BEGIN {
    *_same = IS_WIN32() ? sub { lc( $_[0] ) eq lc( $_[1] ) } : sub { $_[0] eq $_[1] };
}

# mode bits encoded for chmod in symbolic mode
my %MODEBITS = ( om => 0007, gm => 0070, um => 0700 ); ## no critic
{ my $m = 0; $MODEBITS{$_} = ( 1 << $m++ ) for qw/ox ow or gx gw gr ux uw ur/ };

sub _symbolic_chmod {
    my ( $mode, $symbolic ) = @_;
    for my $clause ( split /,\s*/, $symbolic ) {
        if ( $clause =~ m{\A([augo]+)([=+-])([rwx]+)\z} ) {
            my ( $who, $action, $perms ) = ( $1, $2, $3 );
            $who =~ s/a/ugo/g;
            for my $w ( split //, $who ) {
                my $p = 0;
                $p |= $MODEBITS{"$w$_"} for split //, $perms;
                if ( $action eq '=' ) {
                    $mode = ( $mode & ~$MODEBITS{"${w}m"} ) | $p;
                }
                else {
                    $mode = $action eq "+" ? ( $mode | $p ) : ( $mode & ~$p );
                }
            }
        }
        else {
            Carp::croak("Invalid mode clause '$clause' for chmod()");
        }
    }
    return $mode;
}

# flock doesn't work on NFS on BSD or on some filesystems like lustre.
# Since program authors often can't control or detect that, we warn once
# instead of being fatal if we can detect it and people who need it strict
# can fatalize the 'flock' category

#<<< No perltidy
{ package flock; use warnings::register }
#>>>

my $WARNED_NO_FLOCK = 0;

sub _throw {
    my ( $self, $function, $file, $msg ) = @_;
    if (   $function =~ /^flock/
        && $! =~ /operation not supported|function not implemented/i
        && !warnings::fatal_enabled('flock') )
    {
        if ( !$WARNED_NO_FLOCK ) {
            warnings::warn( flock => "Flock not available: '$!': continuing in unsafe mode" );
            $WARNED_NO_FLOCK++;
        }
    }
    else {
        $msg = $! unless defined $msg;
        Path::Tiny::Error->throw( $function, ( defined $file ? $file : $self->[PATH] ),
            $msg );
    }
    return;
}

# cheapo option validation
sub _get_args {
    my ( $raw, @valid ) = @_;
    if ( defined($raw) && ref($raw) ne 'HASH' ) {
        my ( undef, undef, undef, $called_as ) = caller(1);
        $called_as =~ s{^.*::}{};
        Carp::croak("Options for $called_as must be a hash reference");
    }
    my $cooked = {};
    for my $k (@valid) {
        $cooked->{$k} = delete $raw->{$k} if exists $raw->{$k};
    }
    if ( keys %$raw ) {
        my ( undef, undef, undef, $called_as ) = caller(1);
        $called_as =~ s{^.*::}{};
        Carp::croak( "Invalid option(s) for $called_as: " . join( ", ", keys %$raw ) );
    }
    return $cooked;
}

#--------------------------------------------------------------------------#
# Constructors
#--------------------------------------------------------------------------#

#pod =construct path
#pod
#pod     $path = path("foo/bar");
#pod     $path = path("/tmp", "file.txt"); # list
#pod     $path = path(".");                # cwd
#pod
#pod Constructs a C<Path::Tiny> object.  It doesn't matter if you give a file or
#pod directory path.  It's still up to you to call directory-like methods only on
#pod directories and file-like methods only on files.  This function is exported
#pod automatically by default.
#pod
#pod The first argument must be defined and have non-zero length or an exception
#pod will be thrown.  This prevents subtle, dangerous errors with code like
#pod C<< path( maybe_undef() )->remove_tree >>.
#pod
#pod B<DEPRECATED>: If and only if the B<first> character of the B<first> argument
#pod to C<path> is a tilde ('~'), then tilde replacement will be applied to the
#pod first path segment. A single tilde will be replaced with C<glob('~')> and a
#pod tilde followed by a username will be replaced with output of
#pod C<glob('~username')>. B<No other method does tilde expansion on its arguments>.
#pod See L</Tilde expansion (deprecated)> for more.
#pod
#pod On Windows, if the path consists of a drive identifier without a path component
#pod (C<C:> or C<D:>), it will be expanded to the absolute path of the current
#pod directory on that volume using C<Cwd::getdcwd()>.
#pod
#pod If called with a single C<Path::Tiny> argument, the original is returned unless
#pod the original is holding a temporary file or directory reference in which case a
#pod stringified copy is made.
#pod
#pod     $path = path("foo/bar");
#pod     $temp = Path::Tiny->tempfile;
#pod
#pod     $p2 = path($path); # like $p2 = $path
#pod     $t2 = path($temp); # like $t2 = path( "$temp" )
#pod
#pod This optimizes copies without proliferating references unexpectedly if a copy is
#pod made by code outside your control.
#pod
#pod Current API available since 0.017.
#pod
#pod =cut

sub path {
    my $path = shift;
    Carp::croak("Path::Tiny paths require defined, positive-length parts")
      unless 1 + @_ == grep { defined && length } $path, @_;

    # non-temp Path::Tiny objects are effectively immutable and can be reused
    if ( !@_ && ref($path) eq __PACKAGE__ && !$path->[TEMP] ) {
        return $path;
    }

    # stringify objects
    $path = "$path";

    # do any tilde expansions
    my ($tilde) = $path =~ m{^(~[^/]*)};
    if ( defined $tilde ) {
        # Escape File::Glob metacharacters
        (my $escaped = $tilde) =~ s/([\[\{\*\?\\])/\\$1/g;
        require File::Glob;
        my ($homedir) = File::Glob::bsd_glob($escaped);
        if (defined $homedir && ! $File::Glob::ERROR) {
            $homedir =~ tr[\\][/] if IS_WIN32();
            $path =~ s{^\Q$tilde\E}{$homedir};
        }
    }

    unshift @_, $path;
    goto &_pathify;
}

# _path is like path but without tilde expansion
sub _path {
    my $path = shift;
    Carp::croak("Path::Tiny paths require defined, positive-length parts")
      unless 1 + @_ == grep { defined && length } $path, @_;

    # non-temp Path::Tiny objects are effectively immutable and can be reused
    if ( !@_ && ref($path) eq __PACKAGE__ && !$path->[TEMP] ) {
        return $path;
    }

    # stringify objects
    $path = "$path";

    unshift @_, $path;
    goto &_pathify;
}

# _pathify expects one or more string arguments, then joins and canonicalizes
# them into an object.
sub _pathify {
    my $path = shift;

    # expand relative volume paths on windows; put trailing slash on UNC root
    if ( IS_WIN32() ) {
        $path = _win32_vol( $path, $1 ) if $path =~ m{^($DRV_VOL)(?:$NOTSLASH|\z)};
        $path .= "/" if $path =~ m{^$UNC_VOL\z};
    }

    # concatenations stringifies objects, too
    if (@_) {
        $path .= ( _is_root($path) ? "" : "/" ) . join( "/", @_ );
    }


    # canonicalize, but with unix slashes and put back trailing volume slash
    my $cpath = $path = File::Spec->canonpath($path);
    $path =~ tr[\\][/] if IS_WIN32();
    $path = "/" if $path eq '/..'; # for old File::Spec
    $path .= "/" if IS_WIN32() && $path =~ m{^$UNC_VOL\z};

    # root paths must always have a trailing slash, but other paths must not
    if ( _is_root($path) ) {
        $path =~ s{/?\z}{/};
    }
    else {
        $path =~ s{/\z}{};
    }

    bless [ $path, $cpath ], __PACKAGE__;
}

#pod =construct new
#pod
#pod     $path = Path::Tiny->new("foo/bar");
#pod
#pod This is just like C<path>, but with method call overhead.  (Why would you
#pod do that?)
#pod
#pod Current API available since 0.001.
#pod
#pod =cut

sub new { shift; path(@_) }

#pod =construct cwd
#pod
#pod     $path = Path::Tiny->cwd; # path( Cwd::getcwd )
#pod     $path = cwd; # optional export
#pod
#pod Gives you the absolute path to the current directory as a C<Path::Tiny> object.
#pod This is slightly faster than C<< path(".")->absolute >>.
#pod
#pod C<cwd> may be exported on request and used as a function instead of as a
#pod method.
#pod
#pod Current API available since 0.018.
#pod
#pod =cut

sub cwd {
    require Cwd;
    return _path( Cwd::getcwd() );
}

#pod =construct rootdir
#pod
#pod     $path = Path::Tiny->rootdir; # /
#pod     $path = rootdir;             # optional export 
#pod
#pod Gives you C<< File::Spec->rootdir >> as a C<Path::Tiny> object if you're too
#pod picky for C<path("/")>.
#pod
#pod C<rootdir> may be exported on request and used as a function instead of as a
#pod method.
#pod
#pod Current API available since 0.018.
#pod
#pod =cut

sub rootdir { _path( File::Spec->rootdir ) }

#pod =construct tempfile, tempdir
#pod
#pod     $temp = Path::Tiny->tempfile( @options );
#pod     $temp = Path::Tiny->tempdir( @options );
#pod     $temp = $dirpath->tempfile( @options );
#pod     $temp = $dirpath->tempdir( @options );
#pod     $temp = tempfile( @options ); # optional export
#pod     $temp = tempdir( @options );  # optional export
#pod
#pod C<tempfile> passes the options to C<< File::Temp->new >> and returns a
#pod C<Path::Tiny> object with the file name.  The C<TMPDIR> option will be enabled
#pod by default, but you can override that by passing C<< TMPDIR => 0 >> along with
#pod the options.  (If you use an absolute C<TEMPLATE> option, you will want to
#pod disable C<TMPDIR>.)
#pod
#pod The resulting C<File::Temp> object is cached. When the C<Path::Tiny> object is
#pod destroyed, the C<File::Temp> object will be as well.
#pod
#pod C<File::Temp> annoyingly requires you to specify a custom template in slightly
#pod different ways depending on which function or method you call, but
#pod C<Path::Tiny> lets you ignore that and can take either a leading template or a
#pod C<TEMPLATE> option and does the right thing.
#pod
#pod     $temp = Path::Tiny->tempfile( "customXXXXXXXX" );             # ok
#pod     $temp = Path::Tiny->tempfile( TEMPLATE => "customXXXXXXXX" ); # ok
#pod
#pod The tempfile path object will be normalized to have an absolute path, even if
#pod created in a relative directory using C<DIR>.  If you want it to have
#pod the C<realpath> instead, pass a leading options hash like this:
#pod
#pod     $real_temp = tempfile({realpath => 1}, @options);
#pod
#pod C<tempdir> is just like C<tempfile>, except it calls
#pod C<< File::Temp->newdir >> instead.
#pod
#pod Both C<tempfile> and C<tempdir> may be exported on request and used as
#pod functions instead of as methods.
#pod
#pod The methods can be called on an instances representing a
#pod directory. In this case, the directory is used as the base to create the
#pod temporary file/directory, setting the C<DIR> option in File::Temp.
#pod
#pod     my $target_dir = path('/to/destination');
#pod     my $tempfile = $target_dir->tempfile('foobarXXXXXX');
#pod     $tempfile->spew('A lot of data...');  # not atomic
#pod     $tempfile->move($target_dir->child('foobar')); # hopefully atomic
#pod
#pod In this case, any value set for option C<DIR> is ignored.
#pod
#pod B<Note>: for tempfiles, the filehandles from File::Temp are closed and not
#pod reused.  This is not as secure as using File::Temp handles directly, but is
#pod less prone to deadlocks or access problems on some platforms.  Think of what
#pod C<Path::Tiny> gives you to be just a temporary file B<name> that gets cleaned
#pod up.
#pod
#pod B<Note 2>: if you don't want these cleaned up automatically when the object
#pod is destroyed, File::Temp requires different options for directories and
#pod files.  Use C<< CLEANUP => 0 >> for directories and C<< UNLINK => 0 >> for
#pod files.
#pod
#pod B<Note 3>: Don't lose the temporary object by chaining a method call instead
#pod of storing it:
#pod
#pod     my $lost = tempdir()->child("foo"); # tempdir cleaned up right away
#pod
#pod B<Note 4>: The cached object may be accessed with the L</cached_temp> method.
#pod Keeping a reference to, or modifying the cached object may break the
#pod behavior documented above and is not supported.  Use at your own risk.
#pod
#pod Current API available since 0.119.
#pod
#pod =cut

sub tempfile {
    my ( $opts, $maybe_template, $args )
        = _parse_file_temp_args(tempfile => @_);

    # File::Temp->new demands TEMPLATE
    $args->{TEMPLATE} = $maybe_template->[0] if @$maybe_template;

    require File::Temp;
    my $temp = File::Temp->new( TMPDIR => 1, %$args );
    close $temp;
    my $self = $opts->{realpath} ? _path($temp)->realpath : _path($temp)->absolute;
    $self->[TEMP] = $temp;                # keep object alive while we are
    return $self;
}

sub tempdir {
    my ( $opts, $maybe_template, $args )
        = _parse_file_temp_args(tempdir => @_);

    require File::Temp;
    my $temp = File::Temp->newdir( @$maybe_template, TMPDIR => 1, %$args );
    my $self = $opts->{realpath} ? _path($temp)->realpath : _path($temp)->absolute;
    $self->[TEMP] = $temp;                # keep object alive while we are
    # Some ActiveState Perls for Windows break Cwd in ways that lead
    # File::Temp to get confused about what path to remove; this
    # monkey-patches the object with our own view of the absolute path
    $temp->{REALNAME} = $self->[CANON] if IS_WIN32;
    return $self;
}

# normalize the various ways File::Temp does templates
sub _parse_file_temp_args {
    my $called_as = shift;
    if ( @_ && $_[0] eq 'Path::Tiny' ) { shift } # class method
    elsif ( @_ && eval{$_[0]->isa('Path::Tiny')} ) {
        my $dir = shift;
        if (! $dir->is_dir) {
            $dir->_throw( $called_as, $dir, "is not a directory object" );
        }
        push @_, DIR => $dir->stringify; # no overriding
    }
    my $opts = ( @_ && ref $_[0] eq 'HASH' ) ? shift @_ : {};
    $opts = _get_args( $opts, qw/realpath/ );

    my $leading_template = ( scalar(@_) % 2 == 1 ? shift(@_) : '' );
    my %args = @_;
    %args = map { uc($_), $args{$_} } keys %args;
    my @template = (
          exists $args{TEMPLATE} ? delete $args{TEMPLATE}
        : $leading_template      ? $leading_template
        :                          ()
    );

    return ( $opts, \@template, \%args );
}

#--------------------------------------------------------------------------#
# Private methods
#--------------------------------------------------------------------------#

sub _splitpath {
    my ($self) = @_;
    @{$self}[ VOL, DIR, FILE ] = File::Spec->splitpath( $self->[PATH] );
}

sub _resolve_symlinks {
    my ($self) = @_;
    my $new = $self;
    my ( $count, %seen ) = 0;
    while ( -l $new->[PATH] ) {
        if ( $seen{ $new->[PATH] }++ ) {
            $self->_throw( 'readlink', $self->[PATH], "symlink loop detected" );
        }
        if ( ++$count > 100 ) {
            $self->_throw( 'readlink', $self->[PATH], "maximum symlink depth exceeded" );
        }
        my $resolved = readlink $new->[PATH];
        $new->_throw( 'readlink', $new->[PATH] ) unless defined $resolved;
        $resolved = _path($resolved);
        $new = $resolved->is_absolute ? $resolved : $new->sibling($resolved);
    }
    return $new;
}

sub _replacement_path {
    my ($self) = @_;

    my $unique_suffix = $$ . int( rand( 2**31 ) );
    my $temp          = _path( $self . $unique_suffix );

    # If filename with process+random suffix is too long, use a shorter
    # version that doesn't preserve the basename.
    if ( length $temp->basename > 255 ) {
        $temp = $self->sibling( "temp" . $unique_suffix );
    }

    return $temp;
}

#--------------------------------------------------------------------------#
# Public methods
#--------------------------------------------------------------------------#

#pod =method absolute
#pod
#pod     $abs = path("foo/bar")->absolute;
#pod     $abs = path("foo/bar")->absolute("/tmp");
#pod
#pod Returns a new C<Path::Tiny> object with an absolute path (or itself if already
#pod absolute).  If no argument is given, the current directory is used as the
#pod absolute base path.  If an argument is given, it will be converted to an
#pod absolute path (if it is not already) and used as the absolute base path.
#pod
#pod This will not resolve upward directories ("foo/../bar") unless C<canonpath>
#pod in L<File::Spec> would normally do so on your platform.  If you need them
#pod resolved, you must call the more expensive C<realpath> method instead.
#pod
#pod On Windows, an absolute path without a volume component will have it added
#pod based on the current drive.
#pod
#pod Current API available since 0.101.
#pod
#pod =cut

sub absolute {
    my ( $self, $base ) = @_;

    # absolute paths handled differently by OS
    if (IS_WIN32) {
        return $self if length $self->volume;
        # add missing volume
        if ( $self->is_absolute ) {
            require Cwd;
            # use Win32::GetCwd not Cwd::getdcwd because we're sure
            # to have the former but not necessarily the latter
            my ($drv) = Win32::GetCwd() =~ /^($DRV_VOL | $UNC_VOL)/x;
            return _path( $drv . $self->[PATH] );
        }
    }
    else {
        return $self if $self->is_absolute;
    }

    # no base means use current directory as base
    require Cwd;
    return _path( Cwd::getcwd(), $_[0]->[PATH] ) unless defined $base;

    # relative base should be made absolute; we check is_absolute rather
    # than unconditionally make base absolute so that "/foo" doesn't become
    # "C:/foo" on Windows.
    $base = _path($base);
    return _path( ( $base->is_absolute ? $base : $base->absolute ), $_[0]->[PATH] );
}

#pod =method append, append_raw, append_utf8
#pod
#pod     path("foo.txt")->append(@data);
#pod     path("foo.txt")->append(\@data);
#pod     path("foo.txt")->append({binmode => ":raw"}, @data);
#pod     path("foo.txt")->append_raw(@data);
#pod     path("foo.txt")->append_utf8(@data);
#pod
#pod Appends data to a file.  The file is locked with C<flock> prior to writing
#pod and closed afterwards.  An optional hash reference may be used to pass
#pod options.  Valid options are:
#pod
#pod =for :list
#pod * C<binmode>: passed to C<binmode()> on the handle used for writing.
#pod * C<truncate>: truncates the file after locking and before appending
#pod
#pod The C<truncate> option is a way to replace the contents of a file
#pod B<in place>, unlike L</spew> which writes to a temporary file and then
#pod replaces the original (if it exists).
#pod
#pod C<append_raw> is like C<append> with a C<binmode> of C<:unix> for a fast,
#pod unbuffered, raw write.
#pod
#pod C<append_utf8> is like C<append> with an unbuffered C<binmode>
#pod C<:unix:encoding(UTF-8)> (or C<:unix:utf8_strict> with
#pod L<PerlIO::utf8_strict>).  If L<Unicode::UTF8> 0.58+ is installed, an
#pod unbuffered, raw append will be done instead on the data encoded with
#pod C<Unicode::UTF8>.
#pod
#pod Current API available since 0.060.
#pod
#pod =cut

sub append {
    my ( $self, @data ) = @_;
    my $args = ( @data && ref $data[0] eq 'HASH' ) ? shift @data : {};
    $args = _get_args( $args, qw/binmode truncate/ );
    my $binmode = $args->{binmode};
    $binmode = ( ( caller(0) )[10] || {} )->{'open>'} unless defined $binmode;
    my $mode = $args->{truncate} ? ">" : ">>";
    my $fh = $self->filehandle( { locked => 1 }, $mode, $binmode );
    print( {$fh} map { ref eq 'ARRAY' ? @$_ : $_ } @data ) or $self->_throw('print');
    close $fh or $self->_throw('close');
}

sub append_raw {
    my ( $self, @data ) = @_;
    my $args = ( @data && ref $data[0] eq 'HASH' ) ? shift @data : {};
    $args = _get_args( $args, qw/binmode truncate/ );
    $args->{binmode} = ':unix';
    append( $self, $args, @data );
}

sub append_utf8 {
    my ( $self, @data ) = @_;
    my $args = ( @data && ref $data[0] eq 'HASH' ) ? shift @data : {};
    $args = _get_args( $args, qw/binmode truncate/ );
    if ( defined($HAS_UU) ? $HAS_UU : ( $HAS_UU = _check_UU() ) ) {
        $args->{binmode} = ":unix";
        append( $self, $args, map { Unicode::UTF8::encode_utf8($_) } @data );
    }
    elsif ( defined($HAS_PU) ? $HAS_PU : ( $HAS_PU = _check_PU() ) ) {
        $args->{binmode} = ":unix:utf8_strict";
        append( $self, $args, @data );
    }
    else {
        $args->{binmode} = ":unix:encoding(UTF-8)";
        append( $self, $args, @data );
    }
}

#pod =method assert
#pod
#pod     $path = path("foo.txt")->assert( sub { $_->exists } );
#pod
#pod Returns the invocant after asserting that a code reference argument returns
#pod true.  When the assertion code reference runs, it will have the invocant
#pod object in the C<$_> variable.  If it returns false, an exception will be
#pod thrown.  The assertion code reference may also throw its own exception.
#pod
#pod If no assertion is provided, the invocant is returned without error.
#pod
#pod Current API available since 0.062.
#pod
#pod =cut

sub assert {
    my ( $self, $assertion ) = @_;
    return $self unless $assertion;
    if ( ref $assertion eq 'CODE' ) {
        local $_ = $self;
        $assertion->()
          or Path::Tiny::Error->throw( "assert", $self->[PATH], "failed assertion" );
    }
    else {
        Carp::croak("argument to assert must be a code reference argument");
    }
    return $self;
}

#pod =method basename
#pod
#pod     $name = path("foo/bar.txt")->basename;        # bar.txt
#pod     $name = path("foo.txt")->basename('.txt');    # foo
#pod     $name = path("foo.txt")->basename(qr/.txt/);  # foo
#pod     $name = path("foo.txt")->basename(@suffixes);
#pod
#pod Returns the file portion or last directory portion of a path.
#pod
#pod Given a list of suffixes as strings or regular expressions, any that match at
#pod the end of the file portion or last directory portion will be removed before
#pod the result is returned.
#pod
#pod Current API available since 0.054.
#pod
#pod =cut

sub basename {
    my ( $self, @suffixes ) = @_;
    $self->_splitpath unless defined $self->[FILE];
    my $file = $self->[FILE];
    for my $s (@suffixes) {
        my $re = ref($s) eq 'Regexp' ? qr/$s\z/ : qr/\Q$s\E\z/;
        last if $file =~ s/$re//;
    }
    return $file;
}

#pod =method canonpath
#pod
#pod     $canonical = path("foo/bar")->canonpath; # foo\bar on Windows
#pod
#pod Returns a string with the canonical format of the path name for
#pod the platform.  In particular, this means directory separators
#pod will be C<\> on Windows.
#pod
#pod Current API available since 0.001.
#pod
#pod =cut

sub canonpath { $_[0]->[CANON] }

#pod =method cached_temp
#pod
#pod Returns the cached C<File::Temp> or C<File::Temp::Dir> object if the
#pod C<Path::Tiny> object was created with C</tempfile> or C</tempdir>.
#pod If there is no such object, this method throws.
#pod
#pod B<WARNING>: Keeping a reference to, or modifying the cached object may
#pod break the behavior documented for temporary files and directories created
#pod with C<Path::Tiny> and is not supported.  Use at your own risk.
#pod
#pod Current API available since 0.101.
#pod
#pod =cut

sub cached_temp {
    my $self = shift;
    $self->_throw( "cached_temp", $self, "has no cached File::Temp object" )
      unless defined $self->[TEMP];
    return $self->[TEMP];
}

#pod =method child
#pod
#pod     $file = path("/tmp")->child("foo.txt"); # "/tmp/foo.txt"
#pod     $file = path("/tmp")->child(@parts);
#pod
#pod Returns a new C<Path::Tiny> object relative to the original.  Works
#pod like C<catfile> or C<catdir> from File::Spec, but without caring about
#pod file or directories.
#pod
#pod B<WARNING>: because the argument could contain C<..> or refer to symlinks,
#pod there is no guarantee that the new path refers to an actual descendent of
#pod the original.  If this is important to you, transform parent and child with
#pod L</realpath> and check them with L</subsumes>.
#pod
#pod Current API available since 0.001.
#pod
#pod =cut

sub child {
    my ( $self, @parts ) = @_;
    return _path( $self->[PATH], @parts );
}

#pod =method children
#pod
#pod     @paths = path("/tmp")->children;
#pod     @paths = path("/tmp")->children( qr/\.txt\z/ );
#pod
#pod Returns a list of C<Path::Tiny> objects for all files and directories
#pod within a directory.  Excludes "." and ".." automatically.
#pod
#pod If an optional C<qr//> argument is provided, it only returns objects for child
#pod names that match the given regular expression.  Only the base name is used
#pod for matching:
#pod
#pod     @paths = path("/tmp")->children( qr/^foo/ );
#pod     # matches children like the glob foo*
#pod
#pod Current API available since 0.028.
#pod
#pod =cut

sub children {
    my ( $self, $filter ) = @_;
    my $dh;
    opendir $dh, $self->[PATH] or $self->_throw('opendir');
    my @children = readdir $dh;
    closedir $dh or $self->_throw('closedir');

    if ( not defined $filter ) {
        @children = grep { $_ ne '.' && $_ ne '..' } @children;
    }
    elsif ( $filter && ref($filter) eq 'Regexp' ) {
        @children = grep { $_ ne '.' && $_ ne '..' && $_ =~ $filter } @children;
    }
    else {
        Carp::croak("Invalid argument '$filter' for children()");
    }

    return map { _path( $self->[PATH], $_ ) } @children;
}

#pod =method chmod
#pod
#pod     path("foo.txt")->chmod(0777);
#pod     path("foo.txt")->chmod("0755");
#pod     path("foo.txt")->chmod("go-w");
#pod     path("foo.txt")->chmod("a=r,u+wx");
#pod
#pod Sets file or directory permissions.  The argument can be a numeric mode, a
#pod octal string beginning with a "0" or a limited subset of the symbolic mode use
#pod by F</bin/chmod>.
#pod
#pod The symbolic mode must be a comma-delimited list of mode clauses.  Clauses must
#pod match C<< qr/\A([augo]+)([=+-])([rwx]+)\z/ >>, which defines "who", "op" and
#pod "perms" parameters for each clause.  Unlike F</bin/chmod>, all three parameters
#pod are required for each clause, multiple ops are not allowed and permissions
#pod C<stugoX> are not supported.  (See L<File::chmod> for more complex needs.)
#pod
#pod Current API available since 0.053.
#pod
#pod =cut

sub chmod {
    my ( $self, $new_mode ) = @_;

    my $mode;
    if ( $new_mode =~ /\d/ ) {
        $mode = ( $new_mode =~ /^0/ ? oct($new_mode) : $new_mode );
    }
    elsif ( $new_mode =~ /[=+-]/ ) {
        $mode = _symbolic_chmod( $self->stat->mode & 07777, $new_mode ); ## no critic
    }
    else {
        Carp::croak("Invalid mode argument '$new_mode' for chmod()");
    }

    CORE::chmod( $mode, $self->[PATH] ) or $self->_throw("chmod");

    return 1;
}

#pod =method copy
#pod
#pod     path("/tmp/foo.txt")->copy("/tmp/bar.txt");
#pod
#pod Copies the current path to the given destination using L<File::Copy>'s
#pod C<copy> function. Upon success, returns the C<Path::Tiny> object for the
#pod newly copied file.
#pod
#pod Current API available since 0.070.
#pod
#pod =cut

# XXX do recursively for directories?
sub copy {
    my ( $self, $dest ) = @_;
    require File::Copy;
    File::Copy::copy( $self->[PATH], $dest )
      or Carp::croak("copy failed for $self to $dest: $!");

    return -d $dest ? _path( $dest, $self->basename ) : _path($dest);
}

#pod =method digest
#pod
#pod     $obj = path("/tmp/foo.txt")->digest;        # SHA-256
#pod     $obj = path("/tmp/foo.txt")->digest("MD5"); # user-selected
#pod     $obj = path("/tmp/foo.txt")->digest( { chunk_size => 1e6 }, "MD5" );
#pod
#pod Returns a hexadecimal digest for a file.  An optional hash reference of options may
#pod be given.  The only option is C<chunk_size>.  If C<chunk_size> is given, that many
#pod bytes will be read at a time.  If not provided, the entire file will be slurped
#pod into memory to compute the digest.
#pod
#pod Any subsequent arguments are passed to the constructor for L<Digest> to select
#pod an algorithm.  If no arguments are given, the default is SHA-256.
#pod
#pod Current API available since 0.056.
#pod
#pod =cut

sub digest {
    my ( $self, @opts ) = @_;
    my $args = ( @opts && ref $opts[0] eq 'HASH' ) ? shift @opts : {};
    $args = _get_args( $args, qw/chunk_size/ );
    unshift @opts, 'SHA-256' unless @opts;
    require Digest;
    my $digest = Digest->new(@opts);
    if ( $args->{chunk_size} ) {
        my $fh = $self->filehandle( { locked => 1 }, "<", ":unix" );
        my $buf;
        while (!eof($fh)) {
            my $rc = read $fh, $buf, $args->{chunk_size};
            $self->_throw('read') unless defined $rc;
            $digest->add($buf);
        }
    }
    else {
        $digest->add( $self->slurp_raw );
    }
    return $digest->hexdigest;
}

#pod =method dirname (deprecated)
#pod
#pod     $name = path("/tmp/foo.txt")->dirname; # "/tmp/"
#pod
#pod Returns the directory portion you would get from calling
#pod C<< File::Spec->splitpath( $path->stringify ) >> or C<"."> for a path without a
#pod parent directory portion.  Because L<File::Spec> is inconsistent, the result
#pod might or might not have a trailing slash.  Because of this, this method is
#pod B<deprecated>.
#pod
#pod A better, more consistently approach is likely C<< $path->parent->stringify >>,
#pod which will not have a trailing slash except for a root directory.
#pod
#pod Deprecated in 0.056.
#pod
#pod =cut

sub dirname {
    my ($self) = @_;
    $self->_splitpath unless defined $self->[DIR];
    return length $self->[DIR] ? $self->[DIR] : ".";
}

#pod =method edit, edit_raw, edit_utf8
#pod
#pod     path("foo.txt")->edit( \&callback, $options );
#pod     path("foo.txt")->edit_utf8( \&callback );
#pod     path("foo.txt")->edit_raw( \&callback );
#pod
#pod These are convenience methods that allow "editing" a file using a single
#pod callback argument. They slurp the file using C<slurp>, place the contents
#pod inside a localized C<$_> variable, call the callback function (without
#pod arguments), and then write C<$_> (presumably mutated) back to the
#pod file with C<spew>.
#pod
#pod An optional hash reference may be used to pass options.  The only option is
#pod C<binmode>, which is passed to C<slurp> and C<spew>.
#pod
#pod C<edit_utf8> and C<edit_raw> act like their respective C<slurp_*> and
#pod C<spew_*> methods.
#pod
#pod Current API available since 0.077.
#pod
#pod =cut

sub edit {
    my $self = shift;
    my $cb   = shift;
    my $args = _get_args( shift, qw/binmode/ );
    Carp::croak("Callback for edit() must be a code reference")
      unless defined($cb) && ref($cb) eq 'CODE';

    local $_ =
      $self->slurp( exists( $args->{binmode} ) ? { binmode => $args->{binmode} } : () );
    $cb->();
    $self->spew( $args, $_ );

    return;
}

# this is done long-hand to benefit from slurp_utf8 optimizations
sub edit_utf8 {
    my ( $self, $cb ) = @_;
    Carp::croak("Callback for edit_utf8() must be a code reference")
      unless defined($cb) && ref($cb) eq 'CODE';

    local $_ = $self->slurp_utf8;
    $cb->();
    $self->spew_utf8($_);

    return;
}

sub edit_raw { $_[2] = { binmode => ":unix" }; goto &edit }

#pod =method edit_lines, edit_lines_utf8, edit_lines_raw
#pod
#pod     path("foo.txt")->edit_lines( \&callback, $options );
#pod     path("foo.txt")->edit_lines_utf8( \&callback );
#pod     path("foo.txt")->edit_lines_raw( \&callback );
#pod
#pod These are convenience methods that allow "editing" a file's lines using a
#pod single callback argument.  They iterate over the file: for each line, the
#pod line is put into a localized C<$_> variable, the callback function is
#pod executed (without arguments) and then C<$_> is written to a temporary file.
#pod When iteration is finished, the temporary file is atomically renamed over
#pod the original.
#pod
#pod An optional hash reference may be used to pass options.  The only option is
#pod C<binmode>, which is passed to the method that open handles for reading and
#pod writing.
#pod
#pod C<edit_lines_raw> is like C<edit_lines> with a buffered C<binmode> of
#pod C<:raw>.
#pod
#pod C<edit_lines_utf8> is like C<edit_lines> with a buffered C<binmode>
#pod C<:raw:encoding(UTF-8)> (or C<:raw:utf8_strict> with
#pod L<PerlIO::utf8_strict>).
#pod
#pod Current API available since 0.077.
#pod
#pod =cut

sub edit_lines {
    my $self = shift;
    my $cb   = shift;
    my $args = _get_args( shift, qw/binmode/ );
    Carp::croak("Callback for edit_lines() must be a code reference")
      unless defined($cb) && ref($cb) eq 'CODE';

    my $binmode = $args->{binmode};
    # get default binmode from caller's lexical scope (see "perldoc open")
    $binmode = ( ( caller(0) )[10] || {} )->{'open>'} unless defined $binmode;

    # writing needs to follow the link and create the tempfile in the same
    # dir for later atomic rename
    my $resolved_path = $self->_resolve_symlinks;
    my $temp          = $resolved_path->_replacement_path;

    my $temp_fh = $temp->filehandle( { exclusive => 1, locked => 1 }, ">", $binmode );
    my $in_fh = $self->filehandle( { locked => 1 }, '<', $binmode );

    local $_;
    while (! eof($in_fh) ) {
        defined( $_ = readline($in_fh) ) or $self->_throw('readline');
        $cb->();
        $temp_fh->print($_) or $self->_throw('print', $temp);
    }

    close $temp_fh or $self->_throw( 'close', $temp );
    close $in_fh or $self->_throw('close');

    return $temp->move($resolved_path);
}

sub edit_lines_raw { $_[2] = { binmode => ":raw" }; goto &edit_lines }

sub edit_lines_utf8 {
    if ( defined($HAS_PU) ? $HAS_PU : ( $HAS_PU = _check_PU() ) ) {
        $_[2] = { binmode => ":raw:utf8_strict" };
    }
    else {
        $_[2] = { binmode => ":raw:encoding(UTF-8)" };
    }
    goto &edit_lines;
}

#pod =method exists, is_file, is_dir
#pod
#pod     if ( path("/tmp")->exists ) { ... }     # -e
#pod     if ( path("/tmp")->is_dir ) { ... }     # -d
#pod     if ( path("/tmp")->is_file ) { ... }    # -e && ! -d
#pod
#pod Implements file test operations, this means the file or directory actually has
#pod to exist on the filesystem.  Until then, it's just a path.
#pod
#pod B<Note>: C<is_file> is not C<-f> because C<-f> is not the opposite of C<-d>.
#pod C<-f> means "plain file", excluding symlinks, devices, etc. that often can be
#pod read just like files.
#pod
#pod Use C<-f> instead if you really mean to check for a plain file.
#pod
#pod Current API available since 0.053.
#pod
#pod =cut

sub exists { -e $_[0]->[PATH] }

sub is_file { -e $_[0]->[PATH] && !-d _ }

sub is_dir { -d $_[0]->[PATH] }

#pod =method filehandle
#pod
#pod     $fh = path("/tmp/foo.txt")->filehandle($mode, $binmode);
#pod     $fh = path("/tmp/foo.txt")->filehandle({ locked => 1 }, $mode, $binmode);
#pod     $fh = path("/tmp/foo.txt")->filehandle({ exclusive => 1  }, $mode, $binmode);
#pod
#pod Returns an open file handle.  The C<$mode> argument must be a Perl-style
#pod read/write mode string ("<" ,">", ">>", etc.).  If a C<$binmode>
#pod is given, it is set during the C<open> call.
#pod
#pod An optional hash reference may be used to pass options.
#pod
#pod The C<locked> option governs file locking; if true, handles opened for writing,
#pod appending or read-write are locked with C<LOCK_EX>; otherwise, they are
#pod locked with C<LOCK_SH>.  When using C<locked>, ">" or "+>" modes will delay
#pod truncation until after the lock is acquired.
#pod
#pod The C<exclusive> option causes the open() call to fail if the file already
#pod exists.  This corresponds to the O_EXCL flag to sysopen / open(2).
#pod C<exclusive> implies C<locked> and will set it for you if you forget it.
#pod
#pod See C<openr>, C<openw>, C<openrw>, and C<opena> for sugar.
#pod
#pod Current API available since 0.066.
#pod
#pod =cut

# Note: must put binmode on open line, not subsequent binmode() call, so things
# like ":unix" actually stop perlio/crlf from being added

sub filehandle {
    my ( $self, @args ) = @_;
    my $args = ( @args && ref $args[0] eq 'HASH' ) ? shift @args : {};
    $args = _get_args( $args, qw/locked exclusive/ );
    $args->{locked} = 1 if $args->{exclusive};
    my ( $opentype, $binmode ) = @args;

    $opentype = "<" unless defined $opentype;
    Carp::croak("Invalid file mode '$opentype'")
      unless grep { $opentype eq $_ } qw/< +< > +> >> +>>/;

    $binmode = ( ( caller(0) )[10] || {} )->{ 'open' . substr( $opentype, -1, 1 ) }
      unless defined $binmode;
    $binmode = "" unless defined $binmode;

    my ( $fh, $lock, $trunc );
    if ( $HAS_FLOCK && $args->{locked} && !$ENV{PERL_PATH_TINY_NO_FLOCK} ) {
        require Fcntl;
        # truncating file modes shouldn't truncate until lock acquired
        if ( grep { $opentype eq $_ } qw( > +> ) ) {
            # sysopen in write mode without truncation
            my $flags = $opentype eq ">" ? Fcntl::O_WRONLY() : Fcntl::O_RDWR();
            $flags |= Fcntl::O_CREAT();
            $flags |= Fcntl::O_EXCL() if $args->{exclusive};
            sysopen( $fh, $self->[PATH], $flags ) or $self->_throw("sysopen");

            # fix up the binmode since sysopen() can't specify layers like
            # open() and binmode() can't start with just :unix like open()
            if ( $binmode =~ s/^:unix// ) {
                # eliminate pseudo-layers
                binmode( $fh, ":raw" ) or $self->_throw("binmode (:raw)");
                # strip off real layers until only :unix is left
                while ( 1 < ( my $layers =()= PerlIO::get_layers( $fh, output => 1 ) ) ) {
                    binmode( $fh, ":pop" ) or $self->_throw("binmode (:pop)");
                }
            }

            # apply any remaining binmode layers
            if ( length $binmode ) {
                binmode( $fh, $binmode ) or $self->_throw("binmode ($binmode)");
            }

            # ask for lock and truncation
            $lock  = Fcntl::LOCK_EX();
            $trunc = 1;
        }
        elsif ( $^O eq 'aix' && $opentype eq "<" ) {
            # AIX can only lock write handles, so upgrade to RW and LOCK_EX if
            # the file is writable; otherwise give up on locking.  N.B.
            # checking -w before open to determine the open mode is an
            # unavoidable race condition
            if ( -w $self->[PATH] ) {
                $opentype = "+<";
                $lock     = Fcntl::LOCK_EX();
            }
        }
        else {
            $lock = $opentype eq "<" ? Fcntl::LOCK_SH() : Fcntl::LOCK_EX();
        }
    }

    unless ($fh) {
        my $mode = $opentype . $binmode;
        open $fh, $mode, $self->[PATH] or $self->_throw("open ($mode)");
    }

    do { flock( $fh, $lock ) or $self->_throw("flock ($lock)") } if $lock;
    do { truncate( $fh, 0 ) or $self->_throw("truncate") } if $trunc;

    return $fh;
}

#pod =method has_same_bytes
#pod
#pod     if ( path("foo.txt")->has_same_bytes("bar.txt") ) {
#pod        # ...
#pod     }
#pod
#pod This method returns true if both the invocant and the argument can be opened as
#pod file handles and the handles contain the same bytes.  It returns false if their
#pod contents differ.  If either can't be opened as a file (e.g. a directory or
#pod non-existent file), the method throws an exception.  If both can be opened and
#pod both have the same C<realpath>, the method returns true without scanning any
#pod data.
#pod
#pod Current API available since 0.125.
#pod
#pod =cut

sub has_same_bytes {
    my ($self, $other_path) = @_;
    my $other = _path($other_path);

    my $fh1 = $self->openr_raw({ locked => 1 });
    my $fh2 = $other->openr_raw({ locked => 1 });

    # check for directories
    if (-d $fh1) {
        $self->_throw('has_same_bytes', $self->[PATH], "directory not allowed");
    }
    if (-d $fh2) {
        $self->_throw('has_same_bytes', $other->[PATH], "directory not allowed");
    }

    # Now that handles are open, we know the inputs are readable files that
    # exist, so it's safe to compare via realpath
    if ($self->realpath eq $other->realpath) {
        return 1
    }

    # result is 0 for equal, 1 for unequal, -1 for error
    require File::Compare;
    my $res = File::Compare::compare($fh1, $fh2, 65536);
    if ($res < 0) {
        $self->_throw('has_same_bytes')
    }

    return $res == 0;
}

#pod =method is_absolute, is_relative
#pod
#pod     if ( path("/tmp")->is_absolute ) { ... }
#pod     if ( path("/tmp")->is_relative ) { ... }
#pod
#pod Booleans for whether the path appears absolute or relative.
#pod
#pod Current API available since 0.001.
#pod
#pod =cut

sub is_absolute { substr( $_[0]->dirname, 0, 1 ) eq '/' }

sub is_relative { substr( $_[0]->dirname, 0, 1 ) ne '/' }

#pod =method is_rootdir
#pod
#pod     while ( ! $path->is_rootdir ) {
#pod         $path = $path->parent;
#pod         ...
#pod     }
#pod
#pod Boolean for whether the path is the root directory of the volume.  I.e. the
#pod C<dirname> is C<q[/]> and the C<basename> is C<q[]>.
#pod
#pod This works even on C<MSWin32> with drives and UNC volumes:
#pod
#pod     path("C:/")->is_rootdir;             # true
#pod     path("//server/share/")->is_rootdir; #true
#pod
#pod Current API available since 0.038.
#pod
#pod =cut

sub is_rootdir {
    my ($self) = @_;
    $self->_splitpath unless defined $self->[DIR];
    return $self->[DIR] eq '/' && $self->[FILE] eq '';
}

#pod =method iterator
#pod
#pod     $iter = path("/tmp")->iterator( \%options );
#pod
#pod Returns a code reference that walks a directory lazily.  Each invocation
#pod returns a C<Path::Tiny> object or undef when the iterator is exhausted.
#pod
#pod     $iter = path("/tmp")->iterator;
#pod     while ( $path = $iter->() ) {
#pod         ...
#pod     }
#pod
#pod The current and parent directory entries ("." and "..") will not
#pod be included.
#pod
#pod If the C<recurse> option is true, the iterator will walk the directory
#pod recursively, breadth-first.  If the C<follow_symlinks> option is also true,
#pod directory links will be followed recursively.  There is no protection against
#pod loops when following links. If a directory is not readable, it will not be
#pod followed.
#pod
#pod The default is the same as:
#pod
#pod     $iter = path("/tmp")->iterator( {
#pod         recurse         => 0,
#pod         follow_symlinks => 0,
#pod     } );
#pod
#pod For a more powerful, recursive iterator with built-in loop avoidance, see
#pod L<Path::Iterator::Rule>.
#pod
#pod See also L</visit>.
#pod
#pod Current API available since 0.016.
#pod
#pod =cut

sub iterator {
    my $self = shift;
    my $args = _get_args( shift, qw/recurse follow_symlinks/ );
    my @dirs = $self;
    my $current;
    return sub {
        my $next;
        while (@dirs) {
            if ( ref $dirs[0] eq 'Path::Tiny' ) {
                if ( !-r $dirs[0] ) {
                    # Directory is missing or not readable, so skip it.  There
                    # is still a race condition possible between the check and
                    # the opendir, but we can't easily differentiate between
                    # error cases that are OK to skip and those that we want
                    # to be exceptions, so we live with the race and let opendir
                    # be fatal.
                    shift @dirs and next;
                }
                $current = $dirs[0];
                my $dh;
                opendir( $dh, $current->[PATH] )
                  or $self->_throw( 'opendir', $current->[PATH] );
                $dirs[0] = $dh;
                if ( -l $current->[PATH] && !$args->{follow_symlinks} ) {
                    # Symlink attack! It was a real dir, but is now a symlink!
                    # N.B. we check *after* opendir so the attacker has to win
                    # two races: replace dir with symlink before opendir and
                    # replace symlink with dir before -l check above
                    shift @dirs and next;
                }
            }
            while ( defined( $next = readdir $dirs[0] ) ) {
                next if $next eq '.' || $next eq '..';
                my $path = $current->child($next);
                push @dirs, $path
                  if $args->{recurse} && -d $path && !( !$args->{follow_symlinks} && -l $path );
                return $path;
            }
            shift @dirs;
        }
        return;
    };
}

#pod =method lines, lines_raw, lines_utf8
#pod
#pod     @contents = path("/tmp/foo.txt")->lines;
#pod     @contents = path("/tmp/foo.txt")->lines(\%options);
#pod     @contents = path("/tmp/foo.txt")->lines_raw;
#pod     @contents = path("/tmp/foo.txt")->lines_utf8;
#pod
#pod     @contents = path("/tmp/foo.txt")->lines( { chomp => 1, count => 4 } );
#pod
#pod Returns a list of lines from a file.  Optionally takes a hash-reference of
#pod options.  Valid options are C<binmode>, C<count> and C<chomp>.
#pod
#pod If C<binmode> is provided, it will be set on the handle prior to reading.
#pod
#pod If a positive C<count> is provided, that many lines will be returned from the
#pod start of the file.  If a negative C<count> is provided, the entire file will be
#pod read, but only C<abs(count)> will be kept and returned.  If C<abs(count)>
#pod exceeds the number of lines in the file, all lines will be returned.
#pod
#pod If C<chomp> is set, any end-of-line character sequences (C<CR>, C<CRLF>, or
#pod C<LF>) will be removed from the lines returned.
#pod
#pod Because the return is a list, C<lines> in scalar context will return the number
#pod of lines (and throw away the data).
#pod
#pod     $number_of_lines = path("/tmp/foo.txt")->lines;
#pod
#pod C<lines_raw> is like C<lines> with a C<binmode> of C<:raw>.  We use C<:raw>
#pod instead of C<:unix> so PerlIO buffering can manage reading by line.
#pod
#pod C<lines_utf8> is like C<lines> with a C<binmode> of C<:raw:encoding(UTF-8)>
#pod (or C<:raw:utf8_strict> with L<PerlIO::utf8_strict>).  If L<Unicode::UTF8>
#pod 0.58+ is installed, a raw, unbuffered UTF-8 slurp will be done and then the
#pod lines will be split.  This is actually faster than relying on
#pod IO layers, though a bit memory intensive.  If memory use is a
#pod concern, consider C<openr_utf8> and iterating directly on the handle.
#pod
#pod See also L</slurp> if you want to load a file as a whole chunk.
#pod
#pod Current API available since 0.065.
#pod
#pod =cut

sub lines {
    my $self    = shift;
    my $args    = _get_args( shift, qw/binmode chomp count/ );
    my $binmode = $args->{binmode};
    $binmode = ( ( caller(0) )[10] || {} )->{'open<'} unless defined $binmode;
    my $fh = $self->filehandle( { locked => 1 }, "<", $binmode );
    my $chomp = $args->{chomp};
    # XXX more efficient to read @lines then chomp(@lines) vs map?
    if ( $args->{count} ) {
        my ( $counter, $mod, @result ) = ( 0, abs( $args->{count} ) );
        my $line;
        while ( !eof($fh) ) {
            defined( $line = readline($fh) ) or $self->_throw('readline');

            $line =~ s/(?:\x{0d}?\x{0a}|\x{0d})\z// if $chomp;
            $result[ $counter++ ] = $line;
            # for positive count, terminate after right number of lines
            last if $counter == $args->{count};
            # for negative count, eventually wrap around in the result array
            $counter %= $mod;
        }
        # reorder results if full and wrapped somewhere in the middle
        splice( @result, 0, 0, splice( @result, $counter ) )
          if @result == $mod && $counter % $mod;
        return @result;
    }
    elsif ($chomp) {
        local $!;
        my @lines = map { s/(?:\x{0d}?\x{0a}|\x{0d})\z//; $_ } <$fh>; ## no critic
        $self->_throw('readline') if $!;
        return @lines;
    }
    else {
        if ( wantarray ) {
            local $!;
            my @lines = <$fh>;
            $self->_throw('readline') if $!;
            return @lines;
        } else {
            local $!;
            my $count =()= <$fh>;
            $self->_throw('readline') if $!;
            return $count;
        }
    }
}

sub lines_raw {
    my $self = shift;
    my $args = _get_args( shift, qw/binmode chomp count/ );
    if ( $args->{chomp} && !$args->{count} ) {
        return split /\n/, slurp_raw($self);                    ## no critic
    }
    else {
        $args->{binmode} = ":raw";
        return lines( $self, $args );
    }
}

my $CRLF = qr/(?:\x{0d}?\x{0a}|\x{0d})/;

sub lines_utf8 {
    my $self = shift;
    my $args = _get_args( shift, qw/binmode chomp count/ );
    if (   ( defined($HAS_UU) ? $HAS_UU : ( $HAS_UU = _check_UU() ) )
        && $args->{chomp}
        && !$args->{count} )
    {
        my $slurp = slurp_utf8($self);
        $slurp =~ s/$CRLF\z//; # like chomp, but full CR?LF|CR
        return split $CRLF, $slurp, -1; ## no critic
    }
    elsif ( defined($HAS_PU) ? $HAS_PU : ( $HAS_PU = _check_PU() ) ) {
        $args->{binmode} = ":raw:utf8_strict";
        return lines( $self, $args );
    }
    else {
        $args->{binmode} = ":raw:encoding(UTF-8)";
        return lines( $self, $args );
    }
}

#pod =method mkdir
#pod
#pod     path("foo/bar/baz")->mkdir;
#pod     path("foo/bar/baz")->mkdir( \%options );
#pod
#pod Like calling C<make_path> from L<File::Path>.  An optional hash reference
#pod is passed through to C<make_path>.  Errors will be trapped and an exception
#pod thrown.  Returns the the path object to facilitate chaining.
#pod
#pod B<NOTE>: unlike Perl's builtin C<mkdir>, this will create intermediate paths
#pod similar to the Unix C<mkdir -p> command.  It will not error if applied to an
#pod existing directory.
#pod
#pod Passing a defined argument I<other> than a hash reference is an error, and an
#pod exception will be thrown.
#pod
#pod Current API available since 0.125.
#pod
#pod =cut

sub mkdir {
    my ( $self, $args, @rest ) = @_;

    $args = {} unless defined $args;
    if (@rest || (defined $args && ref $args ne 'HASH')) {
        $self->_throw('mkdir', undef, "method argument was given, but was not a hash reference");
    }

    my $err;

    $args->{error} = \$err unless defined $args->{error};
    require File::Path;
    my @dirs;
    my $ok = eval {
        File::Path::make_path( $self->[PATH], $args );
        1;
    };
    if (!$ok) {
        $self->_throw('mkdir', $self->[PATH], "error creating path: $@");
    }
    if ( $err && @$err ) {
        my ( $file, $message ) = %{ $err->[0] };
        $self->_throw('mkdir', $file, $message);
    }
    return $self;
}

#pod =method mkpath (deprecated)
#pod
#pod Like calling C<mkdir>, but returns the list of directories created or an empty list if
#pod the directories already exist, just like C<make_path>.
#pod
#pod Passing a defined argument I<other> than a hash reference is an error, and an
#pod exception will be thrown.
#pod
#pod Deprecated in 0.125.
#pod
#pod =cut

sub mkpath {
    my ( $self, $args, @rest ) = @_;

    $args = {} unless defined $args;
    if (@rest || (defined $args && ref $args ne 'HASH')) {
        $self->_throw('mkdir', undef, "method argument was given, but was not a hash reference");
    }

    my $err;
    $args->{error} = \$err unless defined $args->{error};
    require File::Path;
    my @dirs = File::Path::make_path( $self->[PATH], $args );
    if ( $err && @$err ) {
        my ( $file, $message ) = %{ $err->[0] };
        Carp::croak("mkpath failed for $file: $message");
    }
    return @dirs;
}

#pod =method move
#pod
#pod     path("foo.txt")->move("bar.txt");
#pod
#pod Moves the current path to the given destination using L<File::Copy>'s
#pod C<move> function. Upon success, returns the C<Path::Tiny> object for the
#pod newly moved file.
#pod
#pod If the destination already exists and is a directory, and the source is not a
#pod directory, then the source file will be renamed into the directory
#pod specified by the destination.
#pod
#pod If possible, move() will simply rename the file. Otherwise, it
#pod copies the file to the new location and deletes the original. If an
#pod error occurs during this copy-and-delete process, you may be left
#pod with a (possibly partial) copy of the file under the destination
#pod name.
#pod
#pod Current API available since 0.124. Prior versions used Perl's
#pod -built-in (and less robust) L<rename|perlfunc/rename> function
#pod and did not return an object.
#pod
#pod =cut

sub move {
    my ( $self, $dest ) = @_;
    require File::Copy;
    File::Copy::move( $self->[PATH], $dest )
      or $self->_throw( 'move', $self->[PATH] . "' -> '$dest" );

    return -d $dest ? _path( $dest, $self->basename ) : _path($dest);
}

#pod =method openr, openw, openrw, opena
#pod
#pod     $fh = path("foo.txt")->openr($binmode);  # read
#pod     $fh = path("foo.txt")->openr_raw;
#pod     $fh = path("foo.txt")->openr_utf8;
#pod
#pod     $fh = path("foo.txt")->openw($binmode);  # write
#pod     $fh = path("foo.txt")->openw_raw;
#pod     $fh = path("foo.txt")->openw_utf8;
#pod
#pod     $fh = path("foo.txt")->opena($binmode);  # append
#pod     $fh = path("foo.txt")->opena_raw;
#pod     $fh = path("foo.txt")->opena_utf8;
#pod
#pod     $fh = path("foo.txt")->openrw($binmode); # read/write
#pod     $fh = path("foo.txt")->openrw_raw;
#pod     $fh = path("foo.txt")->openrw_utf8;
#pod
#pod Returns a file handle opened in the specified mode.  The C<openr> style methods
#pod take a single C<binmode> argument.  All of the C<open*> methods have
#pod C<open*_raw> and C<open*_utf8> equivalents that use buffered I/O layers C<:raw>
#pod and C<:raw:encoding(UTF-8)> (or C<:raw:utf8_strict> with
#pod L<PerlIO::utf8_strict>).
#pod
#pod An optional hash reference may be used to pass options.  The only option is
#pod C<locked>.  If true, handles opened for writing, appending or read-write are
#pod locked with C<LOCK_EX>; otherwise, they are locked for C<LOCK_SH>.
#pod
#pod     $fh = path("foo.txt")->openrw_utf8( { locked => 1 } );
#pod
#pod See L</filehandle> for more on locking.
#pod
#pod Current API available since 0.011.
#pod
#pod =cut

# map method names to corresponding open mode
my %opens = (
    opena  => ">>",
    openr  => "<",
    openw  => ">",
    openrw => "+<"
);

while ( my ( $k, $v ) = each %opens ) {
    no strict 'refs';
    # must check for lexical IO mode hint
    *{$k} = sub {
        my ( $self, @args ) = @_;
        my $args = ( @args && ref $args[0] eq 'HASH' ) ? shift @args : {};
        $args = _get_args( $args, qw/locked/ );
        my ($binmode) = @args;
        $binmode = ( ( caller(0) )[10] || {} )->{ 'open' . substr( $v, -1, 1 ) }
          unless defined $binmode;
        $self->filehandle( $args, $v, $binmode );
    };
    *{ $k . "_raw" } = sub {
        my ( $self, @args ) = @_;
        my $args = ( @args && ref $args[0] eq 'HASH' ) ? shift @args : {};
        $args = _get_args( $args, qw/locked/ );
        $self->filehandle( $args, $v, ":raw" );
    };
    *{ $k . "_utf8" } = sub {
        my ( $self, @args ) = @_;
        my $args = ( @args && ref $args[0] eq 'HASH' ) ? shift @args : {};
        $args = _get_args( $args, qw/locked/ );
        my $layer;
        if ( defined($HAS_PU) ? $HAS_PU : ( $HAS_PU = _check_PU() ) ) {
            $layer = ":raw:utf8_strict";
        }
        else {
            $layer = ":raw:encoding(UTF-8)";
        }
        $self->filehandle( $args, $v, $layer );
    };
}

#pod =method parent
#pod
#pod     $parent = path("foo/bar/baz")->parent; # foo/bar
#pod     $parent = path("foo/wibble.txt")->parent; # foo
#pod
#pod     $parent = path("foo/bar/baz")->parent(2); # foo
#pod
#pod Returns a C<Path::Tiny> object corresponding to the parent directory of the
#pod original directory or file. An optional positive integer argument is the number
#pod of parent directories upwards to return.  C<parent> by itself is equivalent to
#pod C<parent(1)>.
#pod
#pod Current API available since 0.014.
#pod
#pod =cut

# XXX this is ugly and coverage is incomplete.  I think it's there for windows
# so need to check coverage there and compare
sub parent {
    my ( $self, $level ) = @_;
    $level = 1 unless defined $level && $level > 0;
    $self->_splitpath unless defined $self->[FILE];
    my $parent;
    if ( length $self->[FILE] ) {
        if ( $self->[FILE] eq '.' || $self->[FILE] eq ".." ) {
            $parent = _path( $self->[PATH] . "/.." );
        }
        else {
            $parent = _path( _non_empty( $self->[VOL] . $self->[DIR] ) );
        }
    }
    elsif ( length $self->[DIR] ) {
        # because of symlinks, any internal updir requires us to
        # just add more updirs at the end
        if ( $self->[DIR] =~ m{(?:^\.\./|/\.\./|/\.\.\z)} ) {
            $parent = _path( $self->[VOL] . $self->[DIR] . "/.." );
        }
        else {
            ( my $dir = $self->[DIR] ) =~ s{/[^\/]+/\z}{/};
            $parent = _path( $self->[VOL] . $dir );
        }
    }
    else {
        $parent = _path( _non_empty( $self->[VOL] ) );
    }
    return $level == 1 ? $parent : $parent->parent( $level - 1 );
}

sub _non_empty {
    my ($string) = shift;
    return ( ( defined($string) && length($string) ) ? $string : "." );
}

#pod =method realpath
#pod
#pod     $real = path("/baz/foo/../bar")->realpath;
#pod     $real = path("foo/../bar")->realpath;
#pod
#pod Returns a new C<Path::Tiny> object with all symbolic links and upward directory
#pod parts resolved using L<Cwd>'s C<realpath>.  Compared to C<absolute>, this is
#pod more expensive as it must actually consult the filesystem.
#pod
#pod If the parent path can't be resolved (e.g. if it includes directories that
#pod don't exist), an exception will be thrown:
#pod
#pod     $real = path("doesnt_exist/foo")->realpath; # dies
#pod
#pod However, if the parent path exists and only the last component (e.g. filename)
#pod doesn't exist, the realpath will be the realpath of the parent plus the
#pod non-existent last component:
#pod
#pod     $real = path("./aasdlfasdlf")->realpath; # works
#pod
#pod The underlying L<Cwd> module usually worked this way on Unix, but died on
#pod Windows (and some Unixes) if the full path didn't exist.  As of version 0.064,
#pod it's safe to use anywhere.
#pod
#pod Current API available since 0.001.
#pod
#pod =cut

# Win32 and some Unixes need parent path resolved separately so realpath
# doesn't throw an error resolving non-existent basename
sub realpath {
    my $self = shift;
    $self = $self->_resolve_symlinks;
    require Cwd;
    $self->_splitpath if !defined $self->[FILE];
    my $check_parent =
      length $self->[FILE] && $self->[FILE] ne '.' && $self->[FILE] ne '..';
    my $realpath = eval {
        # pure-perl Cwd can carp
        local $SIG{__WARN__} = sub { };
        Cwd::realpath( $check_parent ? $self->parent->[PATH] : $self->[PATH] );
    };
    # parent realpath must exist; not all Cwd::realpath will error if it doesn't
    $self->_throw("resolving realpath")
      unless defined $realpath && length $realpath && -e $realpath;
    return ( $check_parent ? _path( $realpath, $self->[FILE] ) : _path($realpath) );
}

#pod =method relative
#pod
#pod     $rel = path("/tmp/foo/bar")->relative("/tmp"); # foo/bar
#pod
#pod Returns a C<Path::Tiny> object with a path relative to a new base path
#pod given as an argument.  If no argument is given, the current directory will
#pod be used as the new base path.
#pod
#pod If either path is already relative, it will be made absolute based on the
#pod current directly before determining the new relative path.
#pod
#pod The algorithm is roughly as follows:
#pod
#pod =for :list
#pod * If the original and new base path are on different volumes, an exception
#pod   will be thrown.
#pod * If the original and new base are identical, the relative path is C<".">.
#pod * If the new base subsumes the original, the relative path is the original
#pod   path with the new base chopped off the front
#pod * If the new base does not subsume the original, a common prefix path is
#pod   determined (possibly the root directory) and the relative path will
#pod   consist of updirs (C<"..">) to reach the common prefix, followed by the
#pod   original path less the common prefix.
#pod
#pod Unlike C<File::Spec::abs2rel>, in the last case above, the calculation based
#pod on a common prefix takes into account symlinks that could affect the updir
#pod process.  Given an original path "/A/B" and a new base "/A/C",
#pod (where "A", "B" and "C" could each have multiple path components):
#pod
#pod =for :list
#pod * Symlinks in "A" don't change the result unless the last component of A is
#pod   a symlink and the first component of "C" is an updir.
#pod * Symlinks in "B" don't change the result and will exist in the result as
#pod   given.
#pod * Symlinks and updirs in "C" must be resolved to actual paths, taking into
#pod   account the possibility that not all path components might exist on the
#pod   filesystem.
#pod
#pod Current API available since 0.001.  New algorithm (that accounts for
#pod symlinks) available since 0.079.
#pod
#pod =cut

sub relative {
    my ( $self, $base ) = @_;
    $base = _path( defined $base && length $base ? $base : '.' );

    # relative paths must be converted to absolute first
    $self = $self->absolute if $self->is_relative;
    $base = $base->absolute if $base->is_relative;

    # normalize volumes if they exist
    $self = $self->absolute if !length $self->volume && length $base->volume;
    $base = $base->absolute if length $self->volume  && !length $base->volume;

    # can't make paths relative across volumes
    if ( !_same( $self->volume, $base->volume ) ) {
        Carp::croak("relative() can't cross volumes: '$self' vs '$base'");
    }

    # if same absolute path, relative is current directory
    return _path(".") if _same( $self->[PATH], $base->[PATH] );

    # if base is a prefix of self, chop prefix off self
    if ( $base->subsumes($self) ) {
        $base = "" if $base->is_rootdir;
        my $relative = "$self";
        $relative =~ s{\A\Q$base/}{};
        return _path(".", $relative);
    }

    # base is not a prefix, so must find a common prefix (even if root)
    my ( @common, @self_parts, @base_parts );
    @base_parts = split /\//, $base->_just_filepath;

    # if self is rootdir, then common directory is root (shown as empty
    # string for later joins); otherwise, must be computed from path parts.
    if ( $self->is_rootdir ) {
        @common = ("");
        shift @base_parts;
    }
    else {
        @self_parts = split /\//, $self->_just_filepath;

        while ( @self_parts && @base_parts && _same( $self_parts[0], $base_parts[0] ) ) {
            push @common, shift @base_parts;
            shift @self_parts;
        }
    }

    # if there are any symlinks from common to base, we have a problem, as
    # you can't guarantee that updir from base reaches the common prefix;
    # we must resolve symlinks and try again; likewise, any updirs are
    # a problem as it throws off calculation of updirs needed to get from
    # self's path to the common prefix.
    if ( my $new_base = $self->_resolve_between( \@common, \@base_parts ) ) {
        return $self->relative($new_base);
    }

    # otherwise, symlinks in common or from common to A don't matter as
    # those don't involve updirs
    my @new_path = ( ("..") x ( 0+ @base_parts ), @self_parts );
    return _path(@new_path);
}

sub _just_filepath {
    my $self     = shift;
    my $self_vol = $self->volume;
    return "$self" if !length $self_vol;

    ( my $self_path = "$self" ) =~ s{\A\Q$self_vol}{};

    return $self_path;
}

sub _resolve_between {
    my ( $self, $common, $base ) = @_;
    my $path = $self->volume . join( "/", @$common );
    my $changed = 0;
    for my $p (@$base) {
        $path .= "/$p";
        if ( $p eq '..' ) {
            $changed = 1;
            if ( -e $path ) {
                $path = _path($path)->realpath->[PATH];
            }
            else {
                $path =~ s{/[^/]+/..\z}{/};
            }
        }
        if ( -l $path ) {
            $changed = 1;
            $path    = _path($path)->realpath->[PATH];
        }
    }
    return $changed ? _path($path) : undef;
}

#pod =method remove
#pod
#pod     path("foo.txt")->remove;
#pod
#pod This is just like C<unlink>, except for its error handling: if the path does
#pod not exist, it returns false; if deleting the file fails, it throws an
#pod exception.
#pod
#pod Current API available since 0.012.
#pod
#pod =cut

sub remove {
    my $self = shift;

    return 0 if !-e $self->[PATH] && !-l $self->[PATH];

    return unlink( $self->[PATH] ) || $self->_throw('unlink');
}

#pod =method remove_tree
#pod
#pod     # directory
#pod     path("foo/bar/baz")->remove_tree;
#pod     path("foo/bar/baz")->remove_tree( \%options );
#pod     path("foo/bar/baz")->remove_tree( { safe => 0 } ); # force remove
#pod
#pod Like calling C<remove_tree> from L<File::Path>, but defaults to C<safe> mode.
#pod An optional hash reference is passed through to C<remove_tree>.  Errors will be
#pod trapped and an exception thrown.  Returns the number of directories deleted,
#pod just like C<remove_tree>.
#pod
#pod If you want to remove a directory only if it is empty, use the built-in
#pod C<rmdir> function instead.
#pod
#pod     rmdir path("foo/bar/baz/");
#pod
#pod Current API available since 0.013.
#pod
#pod Passing a defined argument I<other> than a hash reference is an error, and an
#pod exception will be thrown.
#pod
#pod =cut

sub remove_tree {
    my ( $self, $args, @rest ) = @_;

    $args = {} unless defined $args;
    if (@rest || (defined $args && ref $args ne 'HASH')) {
        $self->_throw('mkdir', undef, "method argument was given, but was not a hash reference");
    }

    return 0 if !-e $self->[PATH] && !-l $self->[PATH];

    my $err;
    $args->{error} = \$err unless defined $args->{error};
    $args->{safe}  = 1     unless defined $args->{safe};
    require File::Path;
    my $count = File::Path::remove_tree( $self->[PATH], $args );

    if ( $err && @$err ) {
        my ( $file, $message ) = %{ $err->[0] };
        Carp::croak("remove_tree failed for $file: $message");
    }
    return $count;
}

#pod =method sibling
#pod
#pod     $foo = path("/tmp/foo.txt");
#pod     $sib = $foo->sibling("bar.txt");        # /tmp/bar.txt
#pod     $sib = $foo->sibling("baz", "bam.txt"); # /tmp/baz/bam.txt
#pod
#pod Returns a new C<Path::Tiny> object relative to the parent of the original.
#pod This is slightly more efficient than C<< $path->parent->child(...) >>.
#pod
#pod Current API available since 0.058.
#pod
#pod =cut

sub sibling {
    my $self = shift;
    return _path( $self->parent->[PATH], @_ );
}

#pod =method size, size_human
#pod
#pod     my $p = path("foo"); # with size 1025 bytes
#pod
#pod     $p->size;                            # "1025"
#pod     $p->size_human;                      # "1.1 K"
#pod     $p->size_human( {format => "iec"} ); # "1.1 KiB"
#pod
#pod Returns the size of a file.  The C<size> method is just a wrapper around C<-s>.
#pod
#pod The C<size_human> method provides a human-readable string similar to
#pod C<ls -lh>.  Like C<ls>, it rounds upwards and provides one decimal place for
#pod single-digit sizes and no decimal places for larger sizes.  The only available
#pod option is C<format>, which has three valid values:
#pod
#pod =for :list
#pod * 'ls' (the default): base-2 sizes, with C<ls> style single-letter suffixes (K, M, etc.)
#pod * 'iec': base-2 sizes, with IEC binary suffixes (KiB, MiB, etc.)
#pod * 'si': base-10 sizes, with SI decimal suffixes (kB, MB, etc.)
#pod
#pod If C<-s> would return C<undef>, C<size_human> returns the empty string.
#pod
#pod Current API available since 0.122.
#pod
#pod =cut

sub size { -s $_[0]->[PATH] }

my %formats = (
    'ls'  => [ 1024, log(1024), [ "", map { " $_" } qw/K M G T/ ] ],
    'iec' => [ 1024, log(1024), [ "", map { " $_" } qw/KiB MiB GiB TiB/ ] ],
    'si'  => [ 1000, log(1000), [ "", map { " $_" } qw/kB MB GB TB/ ] ],
);

sub _formats { return $formats{$_[0]} }

sub size_human {
    my $self     = shift;
    my $args     = _get_args( shift, qw/format/ );
    my $format   = defined $args->{format} ? $args->{format} : "ls";
    my $fmt_opts = $formats{$format}
      or Carp::croak("Invalid format '$format' for size_human()");
    my $size = -s $self->[PATH];
    return defined $size ? _human_size( $size, @$fmt_opts ) : "";
}

sub _ceil {
    return $_[0] == int($_[0]) ? $_[0] : int($_[0]+1);
}

sub _human_size {
    my ( $size, $base, $log_base, $suffixes ) = @_;
    return "0" if $size == 0;

    my $mag = int( log($size) / $log_base );
    $size /= $base**$mag;
    $size =
        $mag == 0               ? $size
      : length( int($size) ) == 1 ? _ceil( $size * 10 ) / 10
      :                             _ceil($size);
    if ( $size >= $base ) {
        $size /= $base;
        $mag++;
    }

    my $fmt = ( $mag == 0 || length( int($size) ) > 1 ) ? "%.0f%s" : "%.1f%s";
    return sprintf( $fmt, $size, $suffixes->[$mag] );
}

#pod =method slurp, slurp_raw, slurp_utf8
#pod
#pod     $data = path("foo.txt")->slurp;
#pod     $data = path("foo.txt")->slurp( {binmode => ":raw"} );
#pod     $data = path("foo.txt")->slurp_raw;
#pod     $data = path("foo.txt")->slurp_utf8;
#pod
#pod Reads file contents into a scalar.  Takes an optional hash reference which may
#pod be used to pass options.  The only available option is C<binmode>, which is
#pod passed to C<binmode()> on the handle used for reading.
#pod
#pod C<slurp_raw> is like C<slurp> with a C<binmode> of C<:unix> for
#pod a fast, unbuffered, raw read.
#pod
#pod C<slurp_utf8> is like C<slurp> with a C<binmode> of
#pod C<:unix:encoding(UTF-8)> (or C<:unix:utf8_strict> with
#pod L<PerlIO::utf8_strict>).  If L<Unicode::UTF8> 0.58+ is installed, a
#pod unbuffered, raw slurp will be done instead and the result decoded with
#pod C<Unicode::UTF8>. This is just as strict and is roughly an order of
#pod magnitude faster than using C<:encoding(UTF-8)>.
#pod
#pod B<Note>: C<slurp> and friends lock the filehandle before slurping.  If
#pod you plan to slurp from a file created with L<File::Temp>, be sure to
#pod close other handles or open without locking to avoid a deadlock:
#pod
#pod     my $tempfile = File::Temp->new(EXLOCK => 0);
#pod     my $guts = path($tempfile)->slurp;
#pod
#pod See also L</lines> if you want to slurp a file into a line array.
#pod
#pod Current API available since 0.004.
#pod
#pod =cut

sub slurp {
    my $self    = shift;
    my $args    = _get_args( shift, qw/binmode/ );
    my $binmode = $args->{binmode};
    $binmode = ( ( caller(0) )[10] || {} )->{'open<'} unless defined $binmode;
    my $fh = $self->filehandle( { locked => 1 }, "<", $binmode );
    if ( ( defined($binmode) ? $binmode : "" ) eq ":unix"
        and my $size = -s $fh )
    {
        my $buf;
        my $rc = read $fh, $buf, $size; # File::Slurp in a nutshell
        $self->_throw('read') unless defined $rc;
        return $buf;
    }
    else {
        local $/;
        my $buf = scalar <$fh>;
        $self->_throw('read') unless defined $buf;
        return $buf;
    }
}

sub slurp_raw { $_[1] = { binmode => ":unix" }; goto &slurp }

sub slurp_utf8 {
    if ( defined($HAS_UU) ? $HAS_UU : ( $HAS_UU = _check_UU() ) ) {
        return Unicode::UTF8::decode_utf8( slurp( $_[0], { binmode => ":unix" } ) );
    }
    elsif ( defined($HAS_PU) ? $HAS_PU : ( $HAS_PU = _check_PU() ) ) {
        $_[1] = { binmode => ":unix:utf8_strict" };
        goto &slurp;
    }
    else {
        $_[1] = { binmode => ":unix:encoding(UTF-8)" };
        goto &slurp;
    }
}

#pod =method spew, spew_raw, spew_utf8
#pod
#pod     path("foo.txt")->spew(@data);
#pod     path("foo.txt")->spew(\@data);
#pod     path("foo.txt")->spew({binmode => ":raw"}, @data);
#pod     path("foo.txt")->spew_raw(@data);
#pod     path("foo.txt")->spew_utf8(@data);
#pod
#pod Writes data to a file atomically.  The file is written to a temporary file in
#pod the same directory, then renamed over the original.  An optional hash reference
#pod may be used to pass options.  The only option is C<binmode>, which is passed to
#pod C<binmode()> on the handle used for writing.
#pod
#pod C<spew_raw> is like C<spew> with a C<binmode> of C<:unix> for a fast,
#pod unbuffered, raw write.
#pod
#pod C<spew_utf8> is like C<spew> with a C<binmode> of C<:unix:encoding(UTF-8)>
#pod (or C<:unix:utf8_strict> with L<PerlIO::utf8_strict>).  If L<Unicode::UTF8>
#pod 0.58+ is installed, a raw, unbuffered spew will be done instead on the data
#pod encoded with C<Unicode::UTF8>.
#pod
#pod B<NOTE>: because the file is written to a temporary file and then renamed, the
#pod new file will wind up with permissions based on your current umask.  This is a
#pod feature to protect you from a race condition that would otherwise give
#pod different permissions than you might expect.  If you really want to keep the
#pod original mode flags, use L</append> with the C<truncate> option.
#pod
#pod Current API available since 0.011.
#pod
#pod =cut

sub spew {
    my ( $self, @data ) = @_;
    my $args = ( @data && ref $data[0] eq 'HASH' ) ? shift @data : {};
    $args = _get_args( $args, qw/binmode/ );
    my $binmode = $args->{binmode};
    # get default binmode from caller's lexical scope (see "perldoc open")
    $binmode = ( ( caller(0) )[10] || {} )->{'open>'} unless defined $binmode;

    # writing needs to follow the link and create the tempfile in the same
    # dir for later atomic rename
    my $resolved_path = $self->_resolve_symlinks;
    my $temp          = $resolved_path->_replacement_path;

    my $fh;
    my $ok = eval { $fh = $temp->filehandle( { exclusive => 1, locked => 1 }, ">", $binmode ); 1 };
    if (!$ok) {
        my $msg = ref($@) eq 'Path::Tiny::Error'
            ? "error opening temp file '$@->{file}' for atomic write: $@->{err}"
            : "error opening temp file for atomic write: $@";
        $self->_throw('spew', $self->[PATH], $msg);
    }
    print( {$fh} map { ref eq 'ARRAY' ? @$_ : $_ } @data) or $self->_throw('print', $temp->[PATH]);
    close $fh or $self->_throw( 'close', $temp->[PATH] );

    return $temp->move($resolved_path);
}

sub spew_raw { splice @_, 1, 0, { binmode => ":unix" }; goto &spew }

sub spew_utf8 {
    if ( defined($HAS_UU) ? $HAS_UU : ( $HAS_UU = _check_UU() ) ) {
        my $self = shift;
        spew(
            $self,
            { binmode => ":unix" },
            map { Unicode::UTF8::encode_utf8($_) } map { ref eq 'ARRAY' ? @$_ : $_ } @_
        );
    }
    elsif ( defined($HAS_PU) ? $HAS_PU : ( $HAS_PU = _check_PU() ) ) {
        splice @_, 1, 0, { binmode => ":unix:utf8_strict" };
        goto &spew;
    }
    else {
        splice @_, 1, 0, { binmode => ":unix:encoding(UTF-8)" };
        goto &spew;
    }
}

#pod =method stat, lstat
#pod
#pod     $stat = path("foo.txt")->stat;
#pod     $stat = path("/some/symlink")->lstat;
#pod
#pod Like calling C<stat> or C<lstat> from L<File::stat>.
#pod
#pod Current API available since 0.001.
#pod
#pod =cut

# XXX break out individual stat() components as subs?
sub stat {
    my $self = shift;
    require File::stat;
    return File::stat::stat( $self->[PATH] ) || $self->_throw('stat');
}

sub lstat {
    my $self = shift;
    require File::stat;
    return File::stat::lstat( $self->[PATH] ) || $self->_throw('lstat');
}

#pod =method stringify
#pod
#pod     $path = path("foo.txt");
#pod     say $path->stringify; # same as "$path"
#pod
#pod Returns a string representation of the path.  Unlike C<canonpath>, this method
#pod returns the path standardized with Unix-style C</> directory separators.
#pod
#pod Current API available since 0.001.
#pod
#pod =cut

sub stringify { $_[0]->[PATH] =~ /^~/ ? './' . $_[0]->[PATH] : $_[0]->[PATH] }

#pod =method subsumes
#pod
#pod     path("foo/bar")->subsumes("foo/bar/baz"); # true
#pod     path("/foo/bar")->subsumes("/foo/baz");   # false
#pod
#pod Returns true if the first path is a prefix of the second path at a directory
#pod boundary.
#pod
#pod This B<does not> resolve parent directory entries (C<..>) or symlinks:
#pod
#pod     path("foo/bar")->subsumes("foo/bar/../baz"); # true
#pod
#pod If such things are important to you, ensure that both paths are resolved to
#pod the filesystem with C<realpath>:
#pod
#pod     my $p1 = path("foo/bar")->realpath;
#pod     my $p2 = path("foo/bar/../baz")->realpath;
#pod     if ( $p1->subsumes($p2) ) { ... }
#pod
#pod Current API available since 0.048.
#pod
#pod =cut

sub subsumes {
    my $self = shift;
    Carp::croak("subsumes() requires a defined, positive-length argument")
      unless defined $_[0];
    my $other = _path(shift);

    # normalize absolute vs relative
    if ( $self->is_absolute && !$other->is_absolute ) {
        $other = $other->absolute;
    }
    elsif ( $other->is_absolute && !$self->is_absolute ) {
        $self = $self->absolute;
    }

    # normalize volume vs non-volume; do this after absolute path
    # adjustments above since that might add volumes already
    if ( length $self->volume && !length $other->volume ) {
        $other = $other->absolute;
    }
    elsif ( length $other->volume && !length $self->volume ) {
        $self = $self->absolute;
    }

    if ( $self->[PATH] eq '.' ) {
        return !!1; # cwd subsumes everything relative
    }
    elsif ( $self->is_rootdir ) {
        # a root directory ("/", "c:/") already ends with a separator
        return $other->[PATH] =~ m{^\Q$self->[PATH]\E};
    }
    else {
        # exact match or prefix breaking at a separator
        return $other->[PATH] =~ m{^\Q$self->[PATH]\E(?:/|\z)};
    }
}

#pod =method touch
#pod
#pod     path("foo.txt")->touch;
#pod     path("foo.txt")->touch($epoch_secs);
#pod
#pod Like the Unix C<touch> utility.  Creates the file if it doesn't exist, or else
#pod changes the modification and access times to the current time.  If the first
#pod argument is the epoch seconds then it will be used.
#pod
#pod Returns the path object so it can be easily chained with other methods:
#pod
#pod     # won't die if foo.txt doesn't exist
#pod     $content = path("foo.txt")->touch->slurp;
#pod
#pod Current API available since 0.015.
#pod
#pod =cut

sub touch {
    my ( $self, $epoch ) = @_;
    if ( !-e $self->[PATH] ) {
        my $fh = $self->openw;
        close $fh or $self->_throw('close');
    }
    if ( defined $epoch ) {
        utime $epoch, $epoch, $self->[PATH]
          or $self->_throw("utime ($epoch)");
    }
    else {
        # literal undef prevents warnings :-(
        utime undef, undef, $self->[PATH]
          or $self->_throw("utime ()");
    }
    return $self;
}

#pod =method touchpath
#pod
#pod     path("bar/baz/foo.txt")->touchpath;
#pod
#pod Combines C<mkdir> and C<touch>.  Creates the parent directory if it doesn't exist,
#pod before touching the file.  Returns the path object like C<touch> does.
#pod
#pod If you need to pass options, use C<mkdir> and C<touch> separately:
#pod
#pod     path("bar/baz")->mkdir( \%options )->child("foo.txt")->touch($epoch_secs);
#pod
#pod Current API available since 0.022.
#pod
#pod =cut

sub touchpath {
    my ($self) = @_;
    my $parent = $self->parent;
    $parent->mkdir unless $parent->exists;
    $self->touch;
}

#pod =method visit
#pod
#pod     path("/tmp")->visit( \&callback, \%options );
#pod
#pod Executes a callback for each child of a directory.  It returns a hash
#pod reference with any state accumulated during iteration.
#pod
#pod The options are the same as for L</iterator> (which it uses internally):
#pod C<recurse> and C<follow_symlinks>.  Both default to false.
#pod
#pod The callback function will receive a C<Path::Tiny> object as the first argument
#pod and a hash reference to accumulate state as the second argument.  For example:
#pod
#pod     # collect files sizes
#pod     my $sizes = path("/tmp")->visit(
#pod         sub {
#pod             my ($path, $state) = @_;
#pod             return if $path->is_dir;
#pod             $state->{$path} = -s $path;
#pod         },
#pod         { recurse => 1 }
#pod     );
#pod
#pod For convenience, the C<Path::Tiny> object will also be locally aliased as the
#pod C<$_> global variable:
#pod
#pod     # print paths matching /foo/
#pod     path("/tmp")->visit( sub { say if /foo/ }, { recurse => 1} );
#pod
#pod If the callback returns a B<reference> to a false scalar value, iteration will
#pod terminate.  This is not the same as "pruning" a directory search; this just
#pod stops all iteration and returns the state hash reference.
#pod
#pod     # find up to 10 files larger than 100K
#pod     my $files = path("/tmp")->visit(
#pod         sub {
#pod             my ($path, $state) = @_;
#pod             $state->{$path}++ if -s $path > 102400
#pod             return \0 if keys %$state == 10;
#pod         },
#pod         { recurse => 1 }
#pod     );
#pod
#pod If you want more flexible iteration, use a module like L<Path::Iterator::Rule>.
#pod
#pod Current API available since 0.062.
#pod
#pod =cut

sub visit {
    my $self = shift;
    my $cb   = shift;
    my $args = _get_args( shift, qw/recurse follow_symlinks/ );
    Carp::croak("Callback for visit() must be a code reference")
      unless defined($cb) && ref($cb) eq 'CODE';
    my $next  = $self->iterator($args);
    my $state = {};
    while ( my $file = $next->() ) {
        local $_ = $file;
        my $r = $cb->( $file, $state );
        last if ref($r) eq 'SCALAR' && !$$r;
    }
    return $state;
}

#pod =method volume
#pod
#pod     $vol = path("/tmp/foo.txt")->volume;   # ""
#pod     $vol = path("C:/tmp/foo.txt")->volume; # "C:"
#pod
#pod Returns the volume portion of the path.  This is equivalent
#pod to what L<File::Spec> would give from C<splitpath> and thus
#pod usually is the empty string on Unix-like operating systems or the
#pod drive letter for an absolute path on C<MSWin32>.
#pod
#pod Current API available since 0.001.
#pod
#pod =cut

sub volume {
    my ($self) = @_;
    $self->_splitpath unless defined $self->[VOL];
    return $self->[VOL];
}

package Path::Tiny::Error;

our @CARP_NOT = qw/Path::Tiny/;

use overload ( q{""} => sub { (shift)->{msg} }, fallback => 1 );

sub throw {
    my ( $class, $op, $file, $err ) = @_;
    chomp( my $trace = Carp::shortmess );
    my $msg = "Error $op on '$file': $err$trace\n";
    die bless { op => $op, file => $file, err => $err, msg => $msg }, $class;
}

1;


# vim: ts=4 sts=4 sw=4 et:

__END__

=pod

=encoding UTF-8

=head1 NAME

Path::Tiny - File path utility

=head1 VERSION

version 0.148

=head1 SYNOPSIS

  use Path::Tiny;

  # Creating Path::Tiny objects

  my $dir = path("/tmp");
  my $foo = path("foo.txt");

  my $subdir = $dir->child("foo");
  my $bar = $subdir->child("bar.txt");

  # Stringifies as cleaned up path

  my $file = path("./foo.txt");
  print $file; # "foo.txt"

  # Reading files

  my $guts = $file->slurp;
     $guts = $file->slurp_utf8;

  my @lines = $file->lines;
     @lines = $file->lines_utf8;

  my ($head) = $file->lines( {count => 1} );
  my ($tail) = $file->lines( {count => -1} );

  # Writing files

  $bar->spew( @data );
  $bar->spew_utf8( @data );

  # Reading directories

  for ( $dir->children ) { ... }

  my $iter = $dir->iterator;
  while ( my $next = $iter->() ) { ... }

=head1 DESCRIPTION

This module provides a small, fast utility for working with file paths.  It is
friendlier to use than L<File::Spec> and provides easy access to functions from
several other core file handling modules.  It aims to be smaller and faster
than many alternatives on CPAN, while helping people do many common things in
consistent and less error-prone ways.

Path::Tiny does not try to work for anything except Unix-like and Win32
platforms.  Even then, it might break if you try something particularly obscure
or tortuous.  (Quick!  What does this mean:
C<< ///../../..//./././a//b/.././c/././ >>?  And how does it differ on Win32?)

All paths are forced to have Unix-style forward slashes.  Stringifying
the object gives you back the path (after some clean up).

File input/output methods C<flock> handles before reading or writing,
as appropriate (if supported by the platform and/or filesystem).

The C<*_utf8> methods (C<slurp_utf8>, C<lines_utf8>, etc.) operate in raw
mode.  On Windows, that means they will not have CRLF translation from the
C<:crlf> IO layer.  Installing L<Unicode::UTF8> 0.58 or later will speed up
C<*_utf8> situations in many cases and is highly recommended.
Alternatively, installing L<PerlIO::utf8_strict> 0.003 or later will be
used in place of the default C<:encoding(UTF-8)>.

This module depends heavily on PerlIO layers for correct operation and thus
requires Perl 5.008001 or later.

=head1 CONSTRUCTORS

=head2 path

    $path = path("foo/bar");
    $path = path("/tmp", "file.txt"); # list
    $path = path(".");                # cwd

Constructs a C<Path::Tiny> object.  It doesn't matter if you give a file or
directory path.  It's still up to you to call directory-like methods only on
directories and file-like methods only on files.  This function is exported
automatically by default.

The first argument must be defined and have non-zero length or an exception
will be thrown.  This prevents subtle, dangerous errors with code like
C<< path( maybe_undef() )->remove_tree >>.

B<DEPRECATED>: If and only if the B<first> character of the B<first> argument
to C<path> is a tilde ('~'), then tilde replacement will be applied to the
first path segment. A single tilde will be replaced with C<glob('~')> and a
tilde followed by a username will be replaced with output of
C<glob('~username')>. B<No other method does tilde expansion on its arguments>.
See L</Tilde expansion (deprecated)> for more.

On Windows, if the path consists of a drive identifier without a path component
(C<C:> or C<D:>), it will be expanded to the absolute path of the current
directory on that volume using C<Cwd::getdcwd()>.

If called with a single C<Path::Tiny> argument, the original is returned unless
the original is holding a temporary file or directory reference in which case a
stringified copy is made.

    $path = path("foo/bar");
    $temp = Path::Tiny->tempfile;

    $p2 = path($path); # like $p2 = $path
    $t2 = path($temp); # like $t2 = path( "$temp" )

This optimizes copies without proliferating references unexpectedly if a copy is
made by code outside your control.

Current API available since 0.017.

=head2 new

    $path = Path::Tiny->new("foo/bar");

This is just like C<path>, but with method call overhead.  (Why would you
do that?)

Current API available since 0.001.

=head2 cwd

    $path = Path::Tiny->cwd; # path( Cwd::getcwd )
    $path = cwd; # optional export

Gives you the absolute path to the current directory as a C<Path::Tiny> object.
This is slightly faster than C<< path(".")->absolute >>.

C<cwd> may be exported on request and used as a function instead of as a
method.

Current API available since 0.018.

=head2 rootdir

    $path = Path::Tiny->rootdir; # /
    $path = rootdir;             # optional export 

Gives you C<< File::Spec->rootdir >> as a C<Path::Tiny> object if you're too
picky for C<path("/")>.

C<rootdir> may be exported on request and used as a function instead of as a
method.

Current API available since 0.018.

=head2 tempfile, tempdir

    $temp = Path::Tiny->tempfile( @options );
    $temp = Path::Tiny->tempdir( @options );
    $temp = $dirpath->tempfile( @options );
    $temp = $dirpath->tempdir( @options );
    $temp = tempfile( @options ); # optional export
    $temp = tempdir( @options );  # optional export

C<tempfile> passes the options to C<< File::Temp->new >> and returns a
C<Path::Tiny> object with the file name.  The C<TMPDIR> option will be enabled
by default, but you can override that by passing C<< TMPDIR => 0 >> along with
the options.  (If you use an absolute C<TEMPLATE> option, you will want to
disable C<TMPDIR>.)

The resulting C<File::Temp> object is cached. When the C<Path::Tiny> object is
destroyed, the C<File::Temp> object will be as well.

C<File::Temp> annoyingly requires you to specify a custom template in slightly
different ways depending on which function or method you call, but
C<Path::Tiny> lets you ignore that and can take either a leading template or a
C<TEMPLATE> option and does the right thing.

    $temp = Path::Tiny->tempfile( "customXXXXXXXX" );             # ok
    $temp = Path::Tiny->tempfile( TEMPLATE => "customXXXXXXXX" ); # ok

The tempfile path object will be normalized to have an absolute path, even if
created in a relative directory using C<DIR>.  If you want it to have
the C<realpath> instead, pass a leading options hash like this:

    $real_temp = tempfile({realpath => 1}, @options);

C<tempdir> is just like C<tempfile>, except it calls
C<< File::Temp->newdir >> instead.

Both C<tempfile> and C<tempdir> may be exported on request and used as
functions instead of as methods.

The methods can be called on an instances representing a
directory. In this case, the directory is used as the base to create the
temporary file/directory, setting the C<DIR> option in File::Temp.

    my $target_dir = path('/to/destination');
    my $tempfile = $target_dir->tempfile('foobarXXXXXX');
    $tempfile->spew('A lot of data...');  # not atomic
    $tempfile->move($target_dir->child('foobar')); # hopefully atomic

In this case, any value set for option C<DIR> is ignored.

B<Note>: for tempfiles, the filehandles from File::Temp are closed and not
reused.  This is not as secure as using File::Temp handles directly, but is
less prone to deadlocks or access problems on some platforms.  Think of what
C<Path::Tiny> gives you to be just a temporary file B<name> that gets cleaned
up.

B<Note 2>: if you don't want these cleaned up automatically when the object
is destroyed, File::Temp requires different options for directories and
files.  Use C<< CLEANUP => 0 >> for directories and C<< UNLINK => 0 >> for
files.

B<Note 3>: Don't lose the temporary object by chaining a method call instead
of storing it:

    my $lost = tempdir()->child("foo"); # tempdir cleaned up right away

B<Note 4>: The cached object may be accessed with the L</cached_temp> method.
Keeping a reference to, or modifying the cached object may break the
behavior documented above and is not supported.  Use at your own risk.

Current API available since 0.119.

=head1 METHODS

=head2 absolute

    $abs = path("foo/bar")->absolute;
    $abs = path("foo/bar")->absolute("/tmp");

Returns a new C<Path::Tiny> object with an absolute path (or itself if already
absolute).  If no argument is given, the current directory is used as the
absolute base path.  If an argument is given, it will be converted to an
absolute path (if it is not already) and used as the absolute base path.

This will not resolve upward directories ("foo/../bar") unless C<canonpath>
in L<File::Spec> would normally do so on your platform.  If you need them
resolved, you must call the more expensive C<realpath> method instead.

On Windows, an absolute path without a volume component will have it added
based on the current drive.

Current API available since 0.101.

=head2 append, append_raw, append_utf8

    path("foo.txt")->append(@data);
    path("foo.txt")->append(\@data);
    path("foo.txt")->append({binmode => ":raw"}, @data);
    path("foo.txt")->append_raw(@data);
    path("foo.txt")->append_utf8(@data);

Appends data to a file.  The file is locked with C<flock> prior to writing
and closed afterwards.  An optional hash reference may be used to pass
options.  Valid options are:

=over 4

=item *

C<binmode>: passed to C<binmode()> on the handle used for writing.

=item *

C<truncate>: truncates the file after locking and before appending

=back

The C<truncate> option is a way to replace the contents of a file
B<in place>, unlike L</spew> which writes to a temporary file and then
replaces the original (if it exists).

C<append_raw> is like C<append> with a C<binmode> of C<:unix> for a fast,
unbuffered, raw write.

C<append_utf8> is like C<append> with an unbuffered C<binmode>
C<:unix:encoding(UTF-8)> (or C<:unix:utf8_strict> with
L<PerlIO::utf8_strict>).  If L<Unicode::UTF8> 0.58+ is installed, an
unbuffered, raw append will be done instead on the data encoded with
C<Unicode::UTF8>.

Current API available since 0.060.

=head2 assert

    $path = path("foo.txt")->assert( sub { $_->exists } );

Returns the invocant after asserting that a code reference argument returns
true.  When the assertion code reference runs, it will have the invocant
object in the C<$_> variable.  If it returns false, an exception will be
thrown.  The assertion code reference may also throw its own exception.

If no assertion is provided, the invocant is returned without error.

Current API available since 0.062.

=head2 basename

    $name = path("foo/bar.txt")->basename;        # bar.txt
    $name = path("foo.txt")->basename('.txt');    # foo
    $name = path("foo.txt")->basename(qr/.txt/);  # foo
    $name = path("foo.txt")->basename(@suffixes);

Returns the file portion or last directory portion of a path.

Given a list of suffixes as strings or regular expressions, any that match at
the end of the file portion or last directory portion will be removed before
the result is returned.

Current API available since 0.054.

=head2 canonpath

    $canonical = path("foo/bar")->canonpath; # foo\bar on Windows

Returns a string with the canonical format of the path name for
the platform.  In particular, this means directory separators
will be C<\> on Windows.

Current API available since 0.001.

=head2 cached_temp

Returns the cached C<File::Temp> or C<File::Temp::Dir> object if the
C<Path::Tiny> object was created with C</tempfile> or C</tempdir>.
If there is no such object, this method throws.

B<WARNING>: Keeping a reference to, or modifying the cached object may
break the behavior documented for temporary files and directories created
with C<Path::Tiny> and is not supported.  Use at your own risk.

Current API available since 0.101.

=head2 child

    $file = path("/tmp")->child("foo.txt"); # "/tmp/foo.txt"
    $file = path("/tmp")->child(@parts);

Returns a new C<Path::Tiny> object relative to the original.  Works
like C<catfile> or C<catdir> from File::Spec, but without caring about
file or directories.

B<WARNING>: because the argument could contain C<..> or refer to symlinks,
there is no guarantee that the new path refers to an actual descendent of
the original.  If this is important to you, transform parent and child with
L</realpath> and check them with L</subsumes>.

Current API available since 0.001.

=head2 children

    @paths = path("/tmp")->children;
    @paths = path("/tmp")->children( qr/\.txt\z/ );

Returns a list of C<Path::Tiny> objects for all files and directories
within a directory.  Excludes "." and ".." automatically.

If an optional C<qr//> argument is provided, it only returns objects for child
names that match the given regular expression.  Only the base name is used
for matching:

    @paths = path("/tmp")->children( qr/^foo/ );
    # matches children like the glob foo*

Current API available since 0.028.

=head2 chmod

    path("foo.txt")->chmod(0777);
    path("foo.txt")->chmod("0755");
    path("foo.txt")->chmod("go-w");
    path("foo.txt")->chmod("a=r,u+wx");

Sets file or directory permissions.  The argument can be a numeric mode, a
octal string beginning with a "0" or a limited subset of the symbolic mode use
by F</bin/chmod>.

The symbolic mode must be a comma-delimited list of mode clauses.  Clauses must
match C<< qr/\A([augo]+)([=+-])([rwx]+)\z/ >>, which defines "who", "op" and
"perms" parameters for each clause.  Unlike F</bin/chmod>, all three parameters
are required for each clause, multiple ops are not allowed and permissions
C<stugoX> are not supported.  (See L<File::chmod> for more complex needs.)

Current API available since 0.053.

=head2 copy

    path("/tmp/foo.txt")->copy("/tmp/bar.txt");

Copies the current path to the given destination using L<File::Copy>'s
C<copy> function. Upon success, returns the C<Path::Tiny> object for the
newly copied file.

Current API available since 0.070.

=head2 digest

    $obj = path("/tmp/foo.txt")->digest;        # SHA-256
    $obj = path("/tmp/foo.txt")->digest("MD5"); # user-selected
    $obj = path("/tmp/foo.txt")->digest( { chunk_size => 1e6 }, "MD5" );

Returns a hexadecimal digest for a file.  An optional hash reference of options may
be given.  The only option is C<chunk_size>.  If C<chunk_size> is given, that many
bytes will be read at a time.  If not provided, the entire file will be slurped
into memory to compute the digest.

Any subsequent arguments are passed to the constructor for L<Digest> to select
an algorithm.  If no arguments are given, the default is SHA-256.

Current API available since 0.056.

=head2 dirname (deprecated)

    $name = path("/tmp/foo.txt")->dirname; # "/tmp/"

Returns the directory portion you would get from calling
C<< File::Spec->splitpath( $path->stringify ) >> or C<"."> for a path without a
parent directory portion.  Because L<File::Spec> is inconsistent, the result
might or might not have a trailing slash.  Because of this, this method is
B<deprecated>.

A better, more consistently approach is likely C<< $path->parent->stringify >>,
which will not have a trailing slash except for a root directory.

Deprecated in 0.056.

=head2 edit, edit_raw, edit_utf8

    path("foo.txt")->edit( \&callback, $options );
    path("foo.txt")->edit_utf8( \&callback );
    path("foo.txt")->edit_raw( \&callback );

These are convenience methods that allow "editing" a file using a single
callback argument. They slurp the file using C<slurp>, place the contents
inside a localized C<$_> variable, call the callback function (without
arguments), and then write C<$_> (presumably mutated) back to the
file with C<spew>.

An optional hash reference may be used to pass options.  The only option is
C<binmode>, which is passed to C<slurp> and C<spew>.

C<edit_utf8> and C<edit_raw> act like their respective C<slurp_*> and
C<spew_*> methods.

Current API available since 0.077.

=head2 edit_lines, edit_lines_utf8, edit_lines_raw

    path("foo.txt")->edit_lines( \&callback, $options );
    path("foo.txt")->edit_lines_utf8( \&callback );
    path("foo.txt")->edit_lines_raw( \&callback );

These are convenience methods that allow "editing" a file's lines using a
single callback argument.  They iterate over the file: for each line, the
line is put into a localized C<$_> variable, the callback function is
executed (without arguments) and then C<$_> is written to a temporary file.
When iteration is finished, the temporary file is atomically renamed over
the original.

An optional hash reference may be used to pass options.  The only option is
C<binmode>, which is passed to the method that open handles for reading and
writing.

C<edit_lines_raw> is like C<edit_lines> with a buffered C<binmode> of
C<:raw>.

C<edit_lines_utf8> is like C<edit_lines> with a buffered C<binmode>
C<:raw:encoding(UTF-8)> (or C<:raw:utf8_strict> with
L<PerlIO::utf8_strict>).

Current API available since 0.077.

=head2 exists, is_file, is_dir

    if ( path("/tmp")->exists ) { ... }     # -e
    if ( path("/tmp")->is_dir ) { ... }     # -d
    if ( path("/tmp")->is_file ) { ... }    # -e && ! -d

Implements file test operations, this means the file or directory actually has
to exist on the filesystem.  Until then, it's just a path.

B<Note>: C<is_file> is not C<-f> because C<-f> is not the opposite of C<-d>.
C<-f> means "plain file", excluding symlinks, devices, etc. that often can be
read just like files.

Use C<-f> instead if you really mean to check for a plain file.

Current API available since 0.053.

=head2 filehandle

    $fh = path("/tmp/foo.txt")->filehandle($mode, $binmode);
    $fh = path("/tmp/foo.txt")->filehandle({ locked => 1 }, $mode, $binmode);
    $fh = path("/tmp/foo.txt")->filehandle({ exclusive => 1  }, $mode, $binmode);

Returns an open file handle.  The C<$mode> argument must be a Perl-style
read/write mode string ("<" ,">", ">>", etc.).  If a C<$binmode>
is given, it is set during the C<open> call.

An optional hash reference may be used to pass options.

The C<locked> option governs file locking; if true, handles opened for writing,
appending or read-write are locked with C<LOCK_EX>; otherwise, they are
locked with C<LOCK_SH>.  When using C<locked>, ">" or "+>" modes will delay
truncation until after the lock is acquired.

The C<exclusive> option causes the open() call to fail if the file already
exists.  This corresponds to the O_EXCL flag to sysopen / open(2).
C<exclusive> implies C<locked> and will set it for you if you forget it.

See C<openr>, C<openw>, C<openrw>, and C<opena> for sugar.

Current API available since 0.066.

=head2 has_same_bytes

    if ( path("foo.txt")->has_same_bytes("bar.txt") ) {
       # ...
    }

This method returns true if both the invocant and the argument can be opened as
file handles and the handles contain the same bytes.  It returns false if their
contents differ.  If either can't be opened as a file (e.g. a directory or
non-existent file), the method throws an exception.  If both can be opened and
both have the same C<realpath>, the method returns true without scanning any
data.

Current API available since 0.125.

=head2 is_absolute, is_relative

    if ( path("/tmp")->is_absolute ) { ... }
    if ( path("/tmp")->is_relative ) { ... }

Booleans for whether the path appears absolute or relative.

Current API available since 0.001.

=head2 is_rootdir

    while ( ! $path->is_rootdir ) {
        $path = $path->parent;
        ...
    }

Boolean for whether the path is the root directory of the volume.  I.e. the
C<dirname> is C<q[/]> and the C<basename> is C<q[]>.

This works even on C<MSWin32> with drives and UNC volumes:

    path("C:/")->is_rootdir;             # true
    path("//server/share/")->is_rootdir; #true

Current API available since 0.038.

=head2 iterator

    $iter = path("/tmp")->iterator( \%options );

Returns a code reference that walks a directory lazily.  Each invocation
returns a C<Path::Tiny> object or undef when the iterator is exhausted.

    $iter = path("/tmp")->iterator;
    while ( $path = $iter->() ) {
        ...
    }

The current and parent directory entries ("." and "..") will not
be included.

If the C<recurse> option is true, the iterator will walk the directory
recursively, breadth-first.  If the C<follow_symlinks> option is also true,
directory links will be followed recursively.  There is no protection against
loops when following links. If a directory is not readable, it will not be
followed.

The default is the same as:

    $iter = path("/tmp")->iterator( {
        recurse         => 0,
        follow_symlinks => 0,
    } );

For a more powerful, recursive iterator with built-in loop avoidance, see
L<Path::Iterator::Rule>.

See also L</visit>.

Current API available since 0.016.

=head2 lines, lines_raw, lines_utf8

    @contents = path("/tmp/foo.txt")->lines;
    @contents = path("/tmp/foo.txt")->lines(\%options);
    @contents = path("/tmp/foo.txt")->lines_raw;
    @contents = path("/tmp/foo.txt")->lines_utf8;

    @contents = path("/tmp/foo.txt")->lines( { chomp => 1, count => 4 } );

Returns a list of lines from a file.  Optionally takes a hash-reference of
options.  Valid options are C<binmode>, C<count> and C<chomp>.

If C<binmode> is provided, it will be set on the handle prior to reading.

If a positive C<count> is provided, that many lines will be returned from the
start of the file.  If a negative C<count> is provided, the entire file will be
read, but only C<abs(count)> will be kept and returned.  If C<abs(count)>
exceeds the number of lines in the file, all lines will be returned.

If C<chomp> is set, any end-of-line character sequences (C<CR>, C<CRLF>, or
C<LF>) will be removed from the lines returned.

Because the return is a list, C<lines> in scalar context will return the number
of lines (and throw away the data).

    $number_of_lines = path("/tmp/foo.txt")->lines;

C<lines_raw> is like C<lines> with a C<binmode> of C<:raw>.  We use C<:raw>
instead of C<:unix> so PerlIO buffering can manage reading by line.

C<lines_utf8> is like C<lines> with a C<binmode> of C<:raw:encoding(UTF-8)>
(or C<:raw:utf8_strict> with L<PerlIO::utf8_strict>).  If L<Unicode::UTF8>
0.58+ is installed, a raw, unbuffered UTF-8 slurp will be done and then the
lines will be split.  This is actually faster than relying on
IO layers, though a bit memory intensive.  If memory use is a
concern, consider C<openr_utf8> and iterating directly on the handle.

See also L</slurp> if you want to load a file as a whole chunk.

Current API available since 0.065.

=head2 mkdir

    path("foo/bar/baz")->mkdir;
    path("foo/bar/baz")->mkdir( \%options );

Like calling C<make_path> from L<File::Path>.  An optional hash reference
is passed through to C<make_path>.  Errors will be trapped and an exception
thrown.  Returns the the path object to facilitate chaining.

B<NOTE>: unlike Perl's builtin C<mkdir>, this will create intermediate paths
similar to the Unix C<mkdir -p> command.  It will not error if applied to an
existing directory.

Passing a defined argument I<other> than a hash reference is an error, and an
exception will be thrown.

Current API available since 0.125.

=head2 mkpath (deprecated)

Like calling C<mkdir>, but returns the list of directories created or an empty list if
the directories already exist, just like C<make_path>.

Passing a defined argument I<other> than a hash reference is an error, and an
exception will be thrown.

Deprecated in 0.125.

=head2 move

    path("foo.txt")->move("bar.txt");

Moves the current path to the given destination using L<File::Copy>'s
C<move> function. Upon success, returns the C<Path::Tiny> object for the
newly moved file.

If the destination already exists and is a directory, and the source is not a
directory, then the source file will be renamed into the directory
specified by the destination.

If possible, move() will simply rename the file. Otherwise, it
copies the file to the new location and deletes the original. If an
error occurs during this copy-and-delete process, you may be left
with a (possibly partial) copy of the file under the destination
name.

Current API available since 0.124. Prior versions used Perl's
-built-in (and less robust) L<rename|perlfunc/rename> function
and did not return an object.

=head2 openr, openw, openrw, opena

    $fh = path("foo.txt")->openr($binmode);  # read
    $fh = path("foo.txt")->openr_raw;
    $fh = path("foo.txt")->openr_utf8;

    $fh = path("foo.txt")->openw($binmode);  # write
    $fh = path("foo.txt")->openw_raw;
    $fh = path("foo.txt")->openw_utf8;

    $fh = path("foo.txt")->opena($binmode);  # append
    $fh = path("foo.txt")->opena_raw;
    $fh = path("foo.txt")->opena_utf8;

    $fh = path("foo.txt")->openrw($binmode); # read/write
    $fh = path("foo.txt")->openrw_raw;
    $fh = path("foo.txt")->openrw_utf8;

Returns a file handle opened in the specified mode.  The C<openr> style methods
take a single C<binmode> argument.  All of the C<open*> methods have
C<open*_raw> and C<open*_utf8> equivalents that use buffered I/O layers C<:raw>
and C<:raw:encoding(UTF-8)> (or C<:raw:utf8_strict> with
L<PerlIO::utf8_strict>).

An optional hash reference may be used to pass options.  The only option is
C<locked>.  If true, handles opened for writing, appending or read-write are
locked with C<LOCK_EX>; otherwise, they are locked for C<LOCK_SH>.

    $fh = path("foo.txt")->openrw_utf8( { locked => 1 } );

See L</filehandle> for more on locking.

Current API available since 0.011.

=head2 parent

    $parent = path("foo/bar/baz")->parent; # foo/bar
    $parent = path("foo/wibble.txt")->parent; # foo

    $parent = path("foo/bar/baz")->parent(2); # foo

Returns a C<Path::Tiny> object corresponding to the parent directory of the
original directory or file. An optional positive integer argument is the number
of parent directories upwards to return.  C<parent> by itself is equivalent to
C<parent(1)>.

Current API available since 0.014.

=head2 realpath

    $real = path("/baz/foo/../bar")->realpath;
    $real = path("foo/../bar")->realpath;

Returns a new C<Path::Tiny> object with all symbolic links and upward directory
parts resolved using L<Cwd>'s C<realpath>.  Compared to C<absolute>, this is
more expensive as it must actually consult the filesystem.

If the parent path can't be resolved (e.g. if it includes directories that
don't exist), an exception will be thrown:

    $real = path("doesnt_exist/foo")->realpath; # dies

However, if the parent path exists and only the last component (e.g. filename)
doesn't exist, the realpath will be the realpath of the parent plus the
non-existent last component:

    $real = path("./aasdlfasdlf")->realpath; # works

The underlying L<Cwd> module usually worked this way on Unix, but died on
Windows (and some Unixes) if the full path didn't exist.  As of version 0.064,
it's safe to use anywhere.

Current API available since 0.001.

=head2 relative

    $rel = path("/tmp/foo/bar")->relative("/tmp"); # foo/bar

Returns a C<Path::Tiny> object with a path relative to a new base path
given as an argument.  If no argument is given, the current directory will
be used as the new base path.

If either path is already relative, it will be made absolute based on the
current directly before determining the new relative path.

The algorithm is roughly as follows:

=over 4

=item *

If the original and new base path are on different volumes, an exception will be thrown.

=item *

If the original and new base are identical, the relative path is C<".">.

=item *

If the new base subsumes the original, the relative path is the original path with the new base chopped off the front

=item *

If the new base does not subsume the original, a common prefix path is determined (possibly the root directory) and the relative path will consist of updirs (C<"..">) to reach the common prefix, followed by the original path less the common prefix.

=back

Unlike C<File::Spec::abs2rel>, in the last case above, the calculation based
on a common prefix takes into account symlinks that could affect the updir
process.  Given an original path "/A/B" and a new base "/A/C",
(where "A", "B" and "C" could each have multiple path components):

=over 4

=item *

Symlinks in "A" don't change the result unless the last component of A is a symlink and the first component of "C" is an updir.

=item *

Symlinks in "B" don't change the result and will exist in the result as given.

=item *

Symlinks and updirs in "C" must be resolved to actual paths, taking into account the possibility that not all path components might exist on the filesystem.

=back

Current API available since 0.001.  New algorithm (that accounts for
symlinks) available since 0.079.

=head2 remove

    path("foo.txt")->remove;

This is just like C<unlink>, except for its error handling: if the path does
not exist, it returns false; if deleting the file fails, it throws an
exception.

Current API available since 0.012.

=head2 remove_tree

    # directory
    path("foo/bar/baz")->remove_tree;
    path("foo/bar/baz")->remove_tree( \%options );
    path("foo/bar/baz")->remove_tree( { safe => 0 } ); # force remove

Like calling C<remove_tree> from L<File::Path>, but defaults to C<safe> mode.
An optional hash reference is passed through to C<remove_tree>.  Errors will be
trapped and an exception thrown.  Returns the number of directories deleted,
just like C<remove_tree>.

If you want to remove a directory only if it is empty, use the built-in
C<rmdir> function instead.

    rmdir path("foo/bar/baz/");

Current API available since 0.013.

Passing a defined argument I<other> than a hash reference is an error, and an
exception will be thrown.

=head2 sibling

    $foo = path("/tmp/foo.txt");
    $sib = $foo->sibling("bar.txt");        # /tmp/bar.txt
    $sib = $foo->sibling("baz", "bam.txt"); # /tmp/baz/bam.txt

Returns a new C<Path::Tiny> object relative to the parent of the original.
This is slightly more efficient than C<< $path->parent->child(...) >>.

Current API available since 0.058.

=head2 size, size_human

    my $p = path("foo"); # with size 1025 bytes

    $p->size;                            # "1025"
    $p->size_human;                      # "1.1 K"
    $p->size_human( {format => "iec"} ); # "1.1 KiB"

Returns the size of a file.  The C<size> method is just a wrapper around C<-s>.

The C<size_human> method provides a human-readable string similar to
C<ls -lh>.  Like C<ls>, it rounds upwards and provides one decimal place for
single-digit sizes and no decimal places for larger sizes.  The only available
option is C<format>, which has three valid values:

=over 4

=item *

'ls' (the default): base-2 sizes, with C<ls> style single-letter suffixes (K, M, etc.)

=item *

'iec': base-2 sizes, with IEC binary suffixes (KiB, MiB, etc.)

=item *

'si': base-10 sizes, with SI decimal suffixes (kB, MB, etc.)

=back

If C<-s> would return C<undef>, C<size_human> returns the empty string.

Current API available since 0.122.

=head2 slurp, slurp_raw, slurp_utf8

    $data = path("foo.txt")->slurp;
    $data = path("foo.txt")->slurp( {binmode => ":raw"} );
    $data = path("foo.txt")->slurp_raw;
    $data = path("foo.txt")->slurp_utf8;

Reads file contents into a scalar.  Takes an optional hash reference which may
be used to pass options.  The only available option is C<binmode>, which is
passed to C<binmode()> on the handle used for reading.

C<slurp_raw> is like C<slurp> with a C<binmode> of C<:unix> for
a fast, unbuffered, raw read.

C<slurp_utf8> is like C<slurp> with a C<binmode> of
C<:unix:encoding(UTF-8)> (or C<:unix:utf8_strict> with
L<PerlIO::utf8_strict>).  If L<Unicode::UTF8> 0.58+ is installed, a
unbuffered, raw slurp will be done instead and the result decoded with
C<Unicode::UTF8>. This is just as strict and is roughly an order of
magnitude faster than using C<:encoding(UTF-8)>.

B<Note>: C<slurp> and friends lock the filehandle before slurping.  If
you plan to slurp from a file created with L<File::Temp>, be sure to
close other handles or open without locking to avoid a deadlock:

    my $tempfile = File::Temp->new(EXLOCK => 0);
    my $guts = path($tempfile)->slurp;

See also L</lines> if you want to slurp a file into a line array.

Current API available since 0.004.

=head2 spew, spew_raw, spew_utf8

    path("foo.txt")->spew(@data);
    path("foo.txt")->spew(\@data);
    path("foo.txt")->spew({binmode => ":raw"}, @data);
    path("foo.txt")->spew_raw(@data);
    path("foo.txt")->spew_utf8(@data);

Writes data to a file atomically.  The file is written to a temporary file in
the same directory, then renamed over the original.  An optional hash reference
may be used to pass options.  The only option is C<binmode>, which is passed to
C<binmode()> on the handle used for writing.

C<spew_raw> is like C<spew> with a C<binmode> of C<:unix> for a fast,
unbuffered, raw write.

C<spew_utf8> is like C<spew> with a C<binmode> of C<:unix:encoding(UTF-8)>
(or C<:unix:utf8_strict> with L<PerlIO::utf8_strict>).  If L<Unicode::UTF8>
0.58+ is installed, a raw, unbuffered spew will be done instead on the data
encoded with C<Unicode::UTF8>.

B<NOTE>: because the file is written to a temporary file and then renamed, the
new file will wind up with permissions based on your current umask.  This is a
feature to protect you from a race condition that would otherwise give
different permissions than you might expect.  If you really want to keep the
original mode flags, use L</append> with the C<truncate> option.

Current API available since 0.011.

=head2 stat, lstat

    $stat = path("foo.txt")->stat;
    $stat = path("/some/symlink")->lstat;

Like calling C<stat> or C<lstat> from L<File::stat>.

Current API available since 0.001.

=head2 stringify

    $path = path("foo.txt");
    say $path->stringify; # same as "$path"

Returns a string representation of the path.  Unlike C<canonpath>, this method
returns the path standardized with Unix-style C</> directory separators.

Current API available since 0.001.

=head2 subsumes

    path("foo/bar")->subsumes("foo/bar/baz"); # true
    path("/foo/bar")->subsumes("/foo/baz");   # false

Returns true if the first path is a prefix of the second path at a directory
boundary.

This B<does not> resolve parent directory entries (C<..>) or symlinks:

    path("foo/bar")->subsumes("foo/bar/../baz"); # true

If such things are important to you, ensure that both paths are resolved to
the filesystem with C<realpath>:

    my $p1 = path("foo/bar")->realpath;
    my $p2 = path("foo/bar/../baz")->realpath;
    if ( $p1->subsumes($p2) ) { ... }

Current API available since 0.048.

=head2 touch

    path("foo.txt")->touch;
    path("foo.txt")->touch($epoch_secs);

Like the Unix C<touch> utility.  Creates the file if it doesn't exist, or else
changes the modification and access times to the current time.  If the first
argument is the epoch seconds then it will be used.

Returns the path object so it can be easily chained with other methods:

    # won't die if foo.txt doesn't exist
    $content = path("foo.txt")->touch->slurp;

Current API available since 0.015.

=head2 touchpath

    path("bar/baz/foo.txt")->touchpath;

Combines C<mkdir> and C<touch>.  Creates the parent directory if it doesn't exist,
before touching the file.  Returns the path object like C<touch> does.

If you need to pass options, use C<mkdir> and C<touch> separately:

    path("bar/baz")->mkdir( \%options )->child("foo.txt")->touch($epoch_secs);

Current API available since 0.022.

=head2 visit

    path("/tmp")->visit( \&callback, \%options );

Executes a callback for each child of a directory.  It returns a hash
reference with any state accumulated during iteration.

The options are the same as for L</iterator> (which it uses internally):
C<recurse> and C<follow_symlinks>.  Both default to false.

The callback function will receive a C<Path::Tiny> object as the first argument
and a hash reference to accumulate state as the second argument.  For example:

    # collect files sizes
    my $sizes = path("/tmp")->visit(
        sub {
            my ($path, $state) = @_;
            return if $path->is_dir;
            $state->{$path} = -s $path;
        },
        { recurse => 1 }
    );

For convenience, the C<Path::Tiny> object will also be locally aliased as the
C<$_> global variable:

    # print paths matching /foo/
    path("/tmp")->visit( sub { say if /foo/ }, { recurse => 1} );

If the callback returns a B<reference> to a false scalar value, iteration will
terminate.  This is not the same as "pruning" a directory search; this just
stops all iteration and returns the state hash reference.

    # find up to 10 files larger than 100K
    my $files = path("/tmp")->visit(
        sub {
            my ($path, $state) = @_;
            $state->{$path}++ if -s $path > 102400
            return \0 if keys %$state == 10;
        },
        { recurse => 1 }
    );

If you want more flexible iteration, use a module like L<Path::Iterator::Rule>.

Current API available since 0.062.

=head2 volume

    $vol = path("/tmp/foo.txt")->volume;   # ""
    $vol = path("C:/tmp/foo.txt")->volume; # "C:"

Returns the volume portion of the path.  This is equivalent
to what L<File::Spec> would give from C<splitpath> and thus
usually is the empty string on Unix-like operating systems or the
drive letter for an absolute path on C<MSWin32>.

Current API available since 0.001.

=for Pod::Coverage openr_utf8 opena_utf8 openw_utf8 openrw_utf8
openr_raw opena_raw openw_raw openrw_raw
IS_WIN32 FREEZE THAW TO_JSON abs2rel

=head1 EXCEPTION HANDLING

Simple usage errors will generally croak.  Failures of underlying Perl
functions will be thrown as exceptions in the class
C<Path::Tiny::Error>.

A C<Path::Tiny::Error> object will be a hash reference with the following fields:

=over 4

=item *

C<op> — a description of the operation, usually function call and any extra info

=item *

C<file> — the file or directory relating to the error

=item *

C<err> — hold C<$!> at the time the error was thrown

=item *

C<msg> — a string combining the above data and a Carp-like short stack trace

=back

Exception objects will stringify as the C<msg> field.

=head1 ENVIRONMENT

=head2 PERL_PATH_TINY_NO_FLOCK

If the environment variable C<PERL_PATH_TINY_NO_FLOCK> is set to a true
value then flock will NOT be used when accessing files (this is not
recommended).

=head1 CAVEATS

=head2 Subclassing not supported

For speed, this class is implemented as an array based object and uses many
direct function calls internally.  You must not subclass it and expect
things to work properly.

=head2 Tilde expansion (deprecated)

Tilde expansion was a nice idea, but it can't easily be applied consistently
across the entire API.  This was a source of bugs and confusion for users.
Therefore, it is B<deprecated> and its use is discouraged.  Limitations to the
existing, legacy behavior follow.

Tilde expansion will only occur if the B<first> argument to C<path> begins with
a tilde. B<No other method does tilde expansion on its arguments>.  If you want
tilde expansion on arguments, you must explicitly wrap them in a call to
C<path>.

    path( "~/foo.txt" )->copy( path( "~/bar.txt" ) );

If you need a literal leading tilde, use C<path("./~whatever")> so that the
argument to C<path> doesn't start with a tilde, but the path still resolves to
the current directory.

Behaviour of tilde expansion with a username for non-existent users depends on
the output of C<glob> on the system.

=head2 File locking

If flock is not supported on a platform, it will not be used, even if
locking is requested.

In situations where a platform normally would support locking, but the
flock fails due to a filesystem limitation, Path::Tiny has some heuristics
to detect this and will warn once and continue in an unsafe mode.  If you
want this failure to be fatal, you can fatalize the 'flock' warnings
category:

    use warnings FATAL => 'flock';

See additional caveats below.

=head3 NFS and BSD

On BSD, Perl's flock implementation may not work to lock files on an
NFS filesystem.  If detected, this situation will warn once, as described
above.

=head3 Lustre

The Lustre filesystem does not support flock.  If detected, this situation
will warn once, as described above.

=head3 AIX and locking

AIX requires a write handle for locking.  Therefore, calls that normally
open a read handle and take a shared lock instead will open a read-write
handle and take an exclusive lock.  If the user does not have write
permission, no lock will be used.

=head2 utf8 vs UTF-8

All the C<*_utf8> methods by default use C<:encoding(UTF-8)> -- either as
C<:unix:encoding(UTF-8)> (unbuffered, for whole file operations) or
C<:raw:encoding(UTF-8)> (buffered, for line-by-line operations). These are
strict against the Unicode spec and disallows illegal Unicode codepoints or
UTF-8 sequences.

Unfortunately, C<:encoding(UTF-8)> is very, very slow.  If you install
L<Unicode::UTF8> 0.58 or later, that module will be used by some C<*_utf8>
methods to encode or decode data after a raw, binary input/output operation,
which is much faster.  Alternatively, if you install L<PerlIO::utf8_strict>,
that will be used instead of C<:encoding(UTF-8)> and is also very fast.

If you need the performance and can accept the security risk,
C<< slurp({binmode => ":unix:utf8"}) >> will be faster than C<:unix:encoding(UTF-8)>
(but not as fast as C<Unicode::UTF8>).

Note that the C<*_utf8> methods read in B<raw> mode.  There is no CRLF
translation on Windows.  If you must have CRLF translation, use the regular
input/output methods with an appropriate binmode:

  $path->spew_utf8($data);                            # raw
  $path->spew({binmode => ":encoding(UTF-8)"}, $data; # LF -> CRLF

=head2 Default IO layers and the open pragma

If you have Perl 5.10 or later, file input/output methods (C<slurp>, C<spew>,
etc.) and high-level handle opening methods ( C<filehandle>, C<openr>,
C<openw>, etc. ) respect default encodings set by the C<-C> switch or lexical
L<open> settings of the caller.  For UTF-8, this is almost certainly slower
than using the dedicated C<_utf8> methods if you have L<Unicode::UTF8> or
L<PerlIP::utf8_strict>.

=head1 TYPE CONSTRAINTS AND COERCION

A standard L<MooseX::Types> library is available at
L<MooseX::Types::Path::Tiny>.  A L<Type::Tiny> equivalent is available as
L<Types::Path::Tiny>.

=head1 SEE ALSO

These are other file/path utilities, which may offer a different feature
set than C<Path::Tiny>.

=over 4

=item *

L<File::chmod>

=item *

L<File::Fu>

=item *

L<IO::All>

=item *

L<Path::Class>

=back

These iterators may be slightly faster than the recursive iterator in
C<Path::Tiny>:

=over 4

=item *

L<Path::Iterator::Rule>

=item *

L<File::Next>

=back

There are probably comparable, non-Tiny tools.  Let me know if you want me to
add a module to the list.

This module was featured in the L<2013 Perl Advent Calendar|http://www.perladvent.org/2013/2013-12-18.html>.

=for :stopwords cpan testmatrix url bugtracker rt cpants kwalitee diff irc mailto metadata placeholders metacpan

=head1 SUPPORT

=head2 Bugs / Feature Requests

Please report any bugs or feature requests through the issue tracker
at L<https://github.com/dagolden/Path-Tiny/issues>.
You will be notified automatically of any progress on your issue.

=head2 Source Code

This is open source software.  The code repository is available for
public review and contribution under the terms of the license.

L<https://github.com/dagolden/Path-Tiny>

  git clone https://github.com/dagolden/Path-Tiny.git

=head1 AUTHOR

David Golden <dagolden@cpan.org>

=head1 CONTRIBUTORS

=for stopwords Alex Efros Aristotle Pagaltzis Chris Williams Dan Book Dave Rolsky David Steinbrunner Doug Bell Elvin Aslanov Flavio Poletti Gabor Szabo Gabriel Andrade George Hartzell Geraud Continsouzas Goro Fuji Graham Knop Ollis Ian Sillitoe James Hunt John Karr Karen Etheridge Mark Ellis Martin H. Sluka Kjeldsen Mary Ehlers Michael G. Schwern NATARAJ (Nikolay Shaplov) Nicolas R Rochelemagne Nigel Gregoire Philippe Bruhat (BooK) regina-verbae Ricardo Signes Roy Ivy III Shlomi Fish Smylers Tatsuhiko Miyagawa Toby Inkster Yanick Champoux yoshikazusawa 김도형 - Keedi Kim

=over 4

=item *

Alex Efros <powerman@powerman.name>

=item *

Aristotle Pagaltzis <pagaltzis@gmx.de>

=item *

Chris Williams <bingos@cpan.org>

=item *

Dan Book <grinnz@grinnz.com>

=item *

Dave Rolsky <autarch@urth.org>

=item *

David Steinbrunner <dsteinbrunner@pobox.com>

=item *

Doug Bell <madcityzen@gmail.com>

=item *

Elvin Aslanov <rwp.primary@gmail.com>

=item *

Flavio Poletti <flavio@polettix.it>

=item *

Gabor Szabo <szabgab@cpan.org>

=item *

Gabriel Andrade <gabiruh@gmail.com>

=item *

George Hartzell <hartzell@cpan.org>

=item *

Geraud Continsouzas <geraud@scsi.nc>

=item *

Goro Fuji <gfuji@cpan.org>

=item *

Graham Knop <haarg@haarg.org>

=item *

Graham Ollis <plicease@cpan.org>

=item *

Ian Sillitoe <ian@sillit.com>

=item *

James Hunt <james@niftylogic.com>

=item *

John Karr <brainbuz@brainbuz.org>

=item *

Karen Etheridge <ether@cpan.org>

=item *

Mark Ellis <mark.ellis@cartridgesave.co.uk>

=item *

Martin H. Sluka <fany@cpan.org>

=item *

Martin Kjeldsen <mk@bluepipe.dk>

=item *

Martin Sluka <martin@sluka.de>

=item *

Mary Ehlers <regina.verb.ae@gmail.com>

=item *

Michael G. Schwern <mschwern@cpan.org>

=item *

NATARAJ (Nikolay Shaplov) <dhyan@nataraj.su>

=item *

Nicolas R <nicolas@atoomic.org>

=item *

Nicolas Rochelemagne <rochelemagne@cpanel.net>

=item *

Nigel Gregoire <nigelgregoire@gmail.com>

=item *

Philippe Bruhat (BooK) <book@cpan.org>

=item *

regina-verbae <regina-verbae@users.noreply.github.com>

=item *

Ricardo Signes <rjbs@semiotic.systems>

=item *

Roy Ivy III <rivy@cpan.org>

=item *

Shlomi Fish <shlomif@shlomifish.org>

=item *

Smylers <Smylers@stripey.com>

=item *

Tatsuhiko Miyagawa <miyagawa@bulknews.net>

=item *

Toby Inkster <tobyink@cpan.org>

=item *

Yanick Champoux <yanick@babyl.dyndns.org>

=item *

yoshikazusawa <883514+yoshikazusawa@users.noreply.github.com>

=item *

김도형 - Keedi Kim <keedi@cpan.org>

=back

=head1 COPYRIGHT AND LICENSE

This software is Copyright (c) 2014 by David Golden.

This is free software, licensed under:

  The Apache License, Version 2.0, January 2004

=cut
PK1N%[!�<��perl5/Path/Class.pmnu��6�$use strict;

package Path::Class;
{
  $Path::Class::VERSION = '0.37';
}

{
  ## no critic
  no strict 'vars';
  @ISA = qw(Exporter);
  @EXPORT    = qw(file dir);
  @EXPORT_OK = qw(file dir foreign_file foreign_dir tempdir);
}

use Exporter;
use Path::Class::File;
use Path::Class::Dir;
use File::Temp ();

sub file { Path::Class::File->new(@_) }
sub dir  { Path::Class::Dir ->new(@_) }
sub foreign_file { Path::Class::File->new_foreign(@_) }
sub foreign_dir  { Path::Class::Dir ->new_foreign(@_) }
sub tempdir { Path::Class::Dir->new(File::Temp::tempdir(@_)) }


1;
__END__

=head1 NAME

Path::Class - Cross-platform path specification manipulation

=head1 VERSION

version 0.37

=head1 SYNOPSIS

  use Path::Class;
  
  my $dir  = dir('foo', 'bar');       # Path::Class::Dir object
  my $file = file('bob', 'file.txt'); # Path::Class::File object
  
  # Stringifies to 'foo/bar' on Unix, 'foo\bar' on Windows, etc.
  print "dir: $dir\n";
  
  # Stringifies to 'bob/file.txt' on Unix, 'bob\file.txt' on Windows
  print "file: $file\n";
  
  my $subdir  = $dir->subdir('baz');  # foo/bar/baz
  my $parent  = $subdir->parent;      # foo/bar
  my $parent2 = $parent->parent;      # foo
  
  my $dir2 = $file->dir;              # bob

  # Work with foreign paths
  use Path::Class qw(foreign_file foreign_dir);
  my $file = foreign_file('Mac', ':foo:file.txt');
  print $file->dir;                   # :foo:
  print $file->as_foreign('Win32');   # foo\file.txt
  
  # Interact with the underlying filesystem:
  
  # $dir_handle is an IO::Dir object
  my $dir_handle = $dir->open or die "Can't read $dir: $!";
  
  # $file_handle is an IO::File object
  my $file_handle = $file->open($mode) or die "Can't read $file: $!";

=head1 DESCRIPTION

C<Path::Class> is a module for manipulation of file and directory
specifications (strings describing their locations, like
C<'/home/ken/foo.txt'> or C<'C:\Windows\Foo.txt'>) in a cross-platform
manner.  It supports pretty much every platform Perl runs on,
including Unix, Windows, Mac, VMS, Epoc, Cygwin, OS/2, and NetWare.

The well-known module L<File::Spec> also provides this service, but
it's sort of awkward to use well, so people sometimes avoid it, or use
it in a way that won't actually work properly on platforms
significantly different than the ones they've tested their code on.

In fact, C<Path::Class> uses C<File::Spec> internally, wrapping all
the unsightly details so you can concentrate on your application code.
Whereas C<File::Spec> provides functions for some common path
manipulations, C<Path::Class> provides an object-oriented model of the
world of path specifications and their underlying semantics.
C<File::Spec> doesn't create any objects, and its classes represent
the different ways in which paths must be manipulated on various
platforms (not a very intuitive concept).  C<Path::Class> creates
objects representing files and directories, and provides methods that
relate them to each other.  For instance, the following C<File::Spec>
code:

 my $absolute = File::Spec->file_name_is_absolute(
                  File::Spec->catfile( @dirs, $file )
                );

can be written using C<Path::Class> as

 my $absolute = Path::Class::File->new( @dirs, $file )->is_absolute;

or even as 

 my $absolute = file( @dirs, $file )->is_absolute;

Similar readability improvements should happen all over the place when
using C<Path::Class>.

Using C<Path::Class> can help solve real problems in your code too -
for instance, how many people actually take the "volume" (like C<C:>
on Windows) into account when writing C<File::Spec>-using code?  I
thought not.  But if you use C<Path::Class>, your file and directory objects
will know what volumes they refer to and do the right thing.

The guts of the C<Path::Class> code live in the L<Path::Class::File>
and L<Path::Class::Dir> modules, so please see those
modules' documentation for more details about how to use them.

=head2 EXPORT

The following functions are exported by default.

=over 4

=item file

A synonym for C<< Path::Class::File->new >>.

=item dir

A synonym for C<< Path::Class::Dir->new >>.

=back

If you would like to prevent their export, you may explicitly pass an
empty list to perl's C<use>, i.e. C<use Path::Class ()>.

The following are exported only on demand.

=over 4

=item foreign_file

A synonym for C<< Path::Class::File->new_foreign >>.

=item foreign_dir

A synonym for C<< Path::Class::Dir->new_foreign >>.

=item tempdir

Create a new Path::Class::Dir instance pointed to temporary directory.

  my $temp = Path::Class::tempdir(CLEANUP => 1);

A synonym for C<< Path::Class::Dir->new(File::Temp::tempdir(@_)) >>.

=back

=head1 Notes on Cross-Platform Compatibility

Although it is much easier to write cross-platform-friendly code with
this module than with C<File::Spec>, there are still some issues to be
aware of.

=over 4

=item *

On some platforms, notably VMS and some older versions of DOS (I think),
all filenames must have an extension.  Thus if you create a file
called F<foo/bar> and then ask for a list of files in the directory
F<foo>, you may find a file called F<bar.> instead of the F<bar> you
were expecting.  Thus it might be a good idea to use an extension in
the first place.

=back

=head1 AUTHOR

Ken Williams, KWILLIAMS@cpan.org

=head1 COPYRIGHT

Copyright (c) Ken Williams.  All rights reserved.

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


=head1 SEE ALSO

L<Path::Class::Dir>, L<Path::Class::File>, L<File::Spec>

=cut
PK1N%[(�*�A�Aperl5/alienfile.pmnu��6�$package alienfile;

use strict;
use warnings;
use 5.008004;
use Alien::Build;
use Exporter ();
use Path::Tiny ();
use Carp ();

sub _path { Path::Tiny::path(@_) }

# ABSTRACT: Specification for defining an external dependency for CPAN
our $VERSION = '2.84'; # VERSION


our @EXPORT = qw( requires on plugin probe configure share sys download fetch decode prefer extract patch patch_ffi build build_ffi gather gather_ffi meta_prop ffi log test start_url before after digest );


sub requires
{
  my($module, $version) = @_;
  $version ||= 0;
  my $caller = caller;
  my $meta = $caller->meta;
  $meta->add_requires($meta->{phase}, $module, $version);
  ();
}


sub plugin
{
  my($name, @args) = @_;

  my $caller = caller;
  $caller->meta->apply_plugin($name, @args);
  return;
}


sub probe
{
  my($instr) = @_;
  my $caller = caller;
  if(my $phase = $caller->meta->{phase})
  {
    Carp::croak "probe must not be in a $phase block" if $phase ne 'any';
  }
  $caller->meta->register_hook(probe => $instr);
  return;
}


sub _phase
{
  my($code, $phase) = @_;
  my $caller = caller(1);
  my $meta = $caller->meta;
  local $meta->{phase} = $phase;
  $code->();
  return;
}

sub configure (&)
{
  _phase($_[0], 'configure');
}


sub sys (&)
{
  _phase($_[0], 'system');
}



sub share (&)
{
  _phase($_[0], 'share');
}


sub _in_phase
{
  my($phase) = @_;
  my $caller = caller(1);
  my(undef, undef, undef, $sub) = caller(1);
  my $meta = $caller->meta;
  $sub =~ s/^.*:://;
  Carp::croak "$sub must be in a $phase block"
    unless $meta->{phase} eq $phase;
}

sub start_url
{
  my($url) = @_;
  _in_phase 'share';
  my $caller = caller;
  my $meta = $caller->meta;
  $meta->prop->{start_url} = $url;
  $meta->add_requires('configure' => 'Alien::Build' => '1.19');
  return;
}


sub digest
{
  my($algo, $digest) = @_;

  my $caller = caller;
  $caller->meta->apply_plugin('Digest', [$algo, $digest]);
  return;
}


sub download
{
  my($instr) = @_;
  _in_phase 'share';
  my $caller = caller;
  $caller->meta->register_hook(download => $instr);
  return;
}


sub fetch
{
  my($instr) = @_;
  _in_phase 'share';
  my $caller = caller;
  $caller->meta->register_hook(fetch => $instr);
  return;
}


sub decode
{
  my($instr) = @_;
  _in_phase 'share';
  my $caller = caller;
  $caller->meta->register_hook(decode => $instr);
  return;
}


sub prefer
{
  my($instr) = @_;
  _in_phase 'share';
  my $caller = caller;
  $caller->meta->register_hook(prefer => $instr);
  return;
}


sub extract
{
  my($instr) = @_;
  _in_phase 'share';
  my $caller = caller;
  $caller->meta->register_hook(extract => $instr);
  return;
}


sub patch
{
  my($instr) = @_;
  _in_phase 'share';
  my $caller = caller;
  my $suffix = $caller->meta->{build_suffix};
  $caller->meta->register_hook("patch$suffix" => $instr);
  return;
}


sub patch_ffi
{
  my($instr) = @_;
  Carp::carp("patch_ffi is deprecated, use ffi { patch ... } } instead");
  _in_phase 'share';
  my $caller = caller;
  $caller->meta->register_hook(patch_ffi => $instr);
  return;
}


sub build
{
  my($instr) = @_;
  _in_phase 'share';
  my $caller = caller;
  my $suffix = $caller->meta->{build_suffix};
  $caller->meta->register_hook("build$suffix" => $instr);
  return;
}


sub build_ffi
{
  my($instr) = @_;
  Carp::carp("build_ffi is deprecated, use ffi { build ... } } instead");
  _in_phase 'share';
  my $caller = caller;
  $caller->meta->register_hook(build_ffi => $instr);
  return;
}


sub gather
{
  my($instr) = @_;
  my $caller = caller;
  my $meta = $caller->meta;
  my $phase = $meta->{phase};
  Carp::croak "gather is not allowed in configure block"
    if $phase eq 'configure';
  my $suffix = $caller->meta->{build_suffix};
  if($suffix eq '_ffi')
  {
    $meta->register_hook(gather_ffi => $instr)
  }
  else
  {
    $meta->register_hook(gather_system => $instr) if $phase =~ /^(any|system)$/;
    $meta->register_hook(gather_share => $instr)  if $phase =~ /^(any|share)$/;
  }
  return;
}


sub gather_ffi
{
  my($instr) = @_;
  Carp::carp("gather_ffi is deprecated, use ffi { gather ... } } instead");
  _in_phase 'share';
  my $caller = caller;
  $caller->meta->register_hook(gather_ffi => $instr);
  return;
}


sub ffi (&)
{
  my($code) = @_;
  _in_phase 'share';
  my $caller = caller;
  local $caller->meta->{build_suffix} = '_ffi';
  $code->();
  return;
}


sub meta_prop
{
  my $caller = caller;
  my $meta = $caller->meta;
  $meta->prop;
}


sub log
{
  unshift @_, 'Alien::Build';
  goto &Alien::Build::log;
}


sub test
{
  my($instr) = @_;
  my $caller = caller;
  my $meta = $caller->meta;
  my $phase = $meta->{phase};
  Carp::croak "test is not allowed in $phase block"
    if $phase eq 'any' || $phase eq 'configure';

  $meta->add_requires('configure' => 'Alien::Build' => '1.14');

  if($phase eq 'share')
  {
    my $suffix = $caller->meta->{build_suffix} || '_share';
    $meta->register_hook(
      "test$suffix" => $instr,
    );
  }
  elsif($phase eq 'system')
  {
    $meta->register_hook(
      "test_system" => $instr,
    );
  }
  else
  {
    die "unknown phase: $phase";
  }
}


my %modifiers = (
  probe    => { any   => 'probe'    },
  download => { share => 'download' },
  fetch    => { share => 'fetch'    },
  decode   => { share => 'fetch'    },
  prefer   => { share => 'prefer'   },
  extract  => { share => 'extract'  },
  patch    => { share => 'patch$'   },
  build    => { share => 'build$'   },
  test     => { share => 'test$'    },
  # Note: below special case gather_ffi for the ffi block :P
  gather   => { share => 'gather_share', system => 'gather_system', any => 'gather_share,gather_system' },
);

sub _add_modifier
{
  my($type, $stage, $sub) = @_;

  my $method = "${type}_hook";

  Carp::croak "No such stage $stage" unless defined $modifiers{$stage};
  Carp::croak "$type $stage argument must be a code reference" unless defined $sub && ref($sub) eq 'CODE';

  my $caller = caller;
  my $meta = $caller->meta;
  Carp::croak "$type $stage is not allowed in sys block" unless defined $modifiers{$stage}->{$meta->{phase}};

  $meta->add_requires('configure' => 'Alien::Build' => '1.40');

  my $suffix = $meta->{build_suffix};
  if($suffix eq '_ffi' && $stage eq 'gather')
  {
    $meta->$method('gather_ffi' => $sub);
  }

  foreach my $hook (
    map { split /,/, $_ }                        # split on , for when multiple hooks must be attached (gather in any)
    map { my $x = $_ ; $x =~ s/\$/$suffix/; $x } # substitute $ at the end for a suffix (_ffi) if any
    $modifiers{$stage}->{$meta->{phase}})        # get the list of modifiers
  {
    $meta->$method($hook => $sub);
  }

  return;
}

sub before
{
  my($stage, $sub) = @_;
  @_ = ('before', @_);
  goto &alienfile::_add_modifier;
}


sub after
{
  my($stage, $sub) = @_;
  @_ = ('after', @_);
  goto &alienfile::_add_modifier;
}

sub import
{
  strict->import;
  warnings->import;
  goto &Exporter::import;
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

alienfile - Specification for defining an external dependency for CPAN

=head1 VERSION

version 2.84

=head1 SYNOPSIS

Do-it-yourself approach:

 use alienfile;
 
 probe [ 'pkg-config --exists libarchive' ];
 
 share {
 
   start_url 'http://libarchive.org/downloads/libarchive-3.2.2.tar.gz';
 
   # the first one which succeeds will be used
   download [ 'wget %{.meta.start_url}' ];
   download [ 'curl -o %{.meta.start_url}' ];
 
   extract [ 'tar xf %{.install.download}' ];
 
   build [
     # Note: will not work on Windows, better to use Build::Autoconf plugin
     # if you need windows support
     './configure --prefix=%{.install.prefix} --disable-shared',
     '%{make}',
     '%{make} install',
   ];
 }
 
 gather [
   [ 'pkg-config', '--modversion', 'libarchive', \'%{.runtime.version}' ],
   [ 'pkg-config', '--cflags',     'libarchive', \'%{.runtime.cflags}'  ],
   [ 'pkg-config', '--libs',       'libarchive', \'%{.runtime.libs}'    ],
 ];

With plugins (better):

 use alienfile;
 
 plugin 'PkgConfig' => 'libarchive';
 
 share {
   start_url 'http://libarchive.org/downloads/';
   plugin Download => (
     filter => qr/^libarchive-.*\.tar\.gz$/,
     version => qr/([0-9\.]+)/,
   );
   plugin Extract => 'tar.gz';
   plugin 'Build::Autoconf';
   plugin 'Gather::IsolateDynamic';
   build [
     '%{configure}',
     '%{make}',
     '%{make} install',
   ];
 };

=head1 DESCRIPTION

An alienfile is a recipe used by L<Alien::Build> to, probe for system libraries or download from the internet, and build source
for those libraries.  This document acts as reference for the alienfile system, but if you are starting out writing your own Alien
you should read L<Alien::Build::Manual::AlienAuthor>, which will teach you how to write your own complete Alien using alienfile +
L<Alien::Build> + L<ExtUtils::MakeMaker>.  Special attention should be taken to the section "a note about dynamic vs. static
libraries".

=head1 DIRECTIVES

=head2 requires

"any" requirement (either share or system):

 requires $module;
 requires $module => $version;

configure time requirement:

 configure {
   requires $module;
   requires $module => $version;
 };

system requirement:

 sys {
   requires $module;
   requires $module => $version;
 };

share requirement:

 share {
   requires $module;
   requires $module => $version;
 };

specifies a requirement.  L<Alien::Build> takes advantage of dynamic requirements, so only
modules that are needed for the specific type of install need to be loaded.  Here are the
different types of requirements:

=over

=item configure

Configure requirements should already be installed before the alienfile is loaded.

=item any

"Any" requirements are those that are needed either for the probe stage, or in either the
system or share installs.

=item share

Share requirements are those modules needed when downloading and building from source.

=item system

System requirements are those modules needed when the system provides the library or tool.

=back

=head2 plugin

 plugin $name => (%args);
 plugin $name => $arg;

Load the given plugin.  If you prefix the plugin name with an C<=> sign,
then it will be assumed to be a fully qualified path name.  Otherwise the
plugin will be assumed to live in the C<Alien::Build::Plugin> namespace.
If there is an appropriate negotiate plugin, that one will be loaded.
Examples:

 # Loads Alien::Build::Plugin::Fetch::Negotiate
 # which will pick the best Alien::Build::Plugin::Fetch
 # plugin based on the URL, and system configuration
 plugin 'Fetch' => 'http://ftp.gnu.org/gnu/gcc';
 
 # loads the plugin with the badly named class!
 plugin '=Badly::Named::Plugin::Not::In::Alien::Build::Namespace';
 
 # explicitly loads Alien::Build::Plugin::Prefer::SortVersions
 plugin 'Prefer::SortVersions' => (
   filter => qr/^gcc-.*\.tar\.gz$/,
   version => qr/([0-9\.]+)/,
 );

=head2 probe

 probe \&code;
 probe \@commandlist;

Instructions for the probe stage.  May be either a code reference, or a command list.
Multiple probes and probe plugins can be given.  These will be used in sequence,
stopping at the first that detects a system installation.  L<Alien::Build> will use
a share install if no system installation is detected by the probes.

=head2 configure

 configure {
   ...
 };

Configure block.  The only directive allowed in a configure block is
requires.

=head2 sys

 sys {
   ...
 };

System block.  Allowed directives are: requires and gather.

=head2 share

 share {
   ...
 };

System block.  Allowed directives are: download, fetch, decode, prefer, extract, build, gather.

=head2 start_url

 share {
   start_url $url;
 };

Set the start URL for download.  This should be the URL to an index page, or the actual tarball of the source.

=head2 digest

[experimental]

 share {
   digest $algorithm, $digest;
 };

Check fetched and downloaded files against the given algorithm and
digest.  Typically you will want to use SHA256 as the algorithm.

=head2 download

 share {
   download \&code;
   download \@commandlist;
 };

Instructions for the download stage.  May be either a
code reference, or a command list.

=head2 fetch

 share {
   fetch \&code;
   fetch \@commandlist;
 };

Instructions for the fetch stage.  May be either a
code reference, or a command list.

=head2 decode

 share {
   decode \&code;
   decode \@commandlist;
 };

Instructions for the decode stage.  May be either a
code reference, or a command list.

=head2 prefer

 share {
   prefer \&code;
   prefer \@commandlist;
 };

Instructions for the prefer stage.  May be either a
code reference, or a command list.

=head2 extract

 share {
   extract \&code;
   extract \@commandlist;
 };

Instructions for the extract stage.  May be either a
code reference, or a command list.

=head2 patch

 share {
   patch \&code;
   patch \@commandlist;
 };

Instructions for the patch stage.  May be either a
code reference, or a command list.

=head2 patch_ffi

 share {
   patch_ffi \&code;
   patch_ffi \@commandlist;
 };

[DEPRECATED]

Instructions for the patch_ffi stage.  May be either a
code reference, or a command list.

=head2 build

 share {
   build \&code;
   build \@commandlist;
 };

Instructions for the build stage.  May be either a
code reference, or a command list.

=head2 build_ffi

 share {
   build \&code;
   build \@commandlist;
 };

[DEPRECATED]

Instructions for the build FFI stage.  Builds shared libraries instead of static.
This is optional, and is only necessary if a fresh and separate build needs to be
done for FFI.

=head2 gather

 gather \&code;
 gather \@commandlist;
 
 share {
   gather \&code;
   gather \@commandlist;
 };
 
 sys {
   gather \&code;
   gather \@commandlist;
 };

Instructions for the gather stage.  May be either a code reference, or a command list.
In the root block of the alienfile it will trigger in both share and system build.
In the share or sys block it will only trigger in the corresponding build.

=head2 gather_ffi

 share {
   gather_ffi \&code;
   gather_ffi \@commandlist;
 }

[DEPRECATED]

Gather specific to C<build_ffi>.  Not usually necessary.

=head2 ffi

 share {
   ffi {
     patch \&code;
     patch \@commandlist;
     build \&code;
     build \@commandlist;
     gather \&code;
     gather \@commandlist;
   }
 }

Specify patch, build or gather stages related to FFI.

=head2 meta_prop

 my $hash = meta_prop;

Get the meta_prop hash reference.

=head2 meta

 my $meta = meta;

Returns the meta object for your L<alienfile>.  For methods that can be used on the
meta object, see L<Alien::Build/"META METHODS">.

=head2 log

 log($message);

Prints the given log to stdout.

=head2 test

 share {
   test \&code;
   test \@commandlist;
 };
 sys {
   test \&code;
   test \@commandlist;
 };

Run the tests

=head2 before

 before $stage => \&code;

Execute the given code before the given stage.  Stage should be one of
C<probe>, C<download>, C<fetch>, C<decode>, C<prefer>, C<extract>,
C<patch>, C<build>, C<test>, and C<gather>.

The before directive is only legal in the same blocks as the stage would
normally be legal in.  For example, you can't do this:

 use alienfile;
 
 sys {
   before 'build' => sub {
     ...
   };
 };

Because a C<build> wouldn't be legal inside a C<sys> block.

=head2 after

 after $stage => \&code;

Execute the given code after the given stage.  Stage should be one of
C<probe>, C<download>, C<fetch>, C<decode>, C<prefer>, C<extract>,
C<patch>, C<build>, C<test>, and C<gather>.

The after directive is only legal in the same blocks as the stage would
normally be legal in.  For example, you can't do this:

 use alienfile;
 
 sys {
   after 'build' => sub {
     ...
   };
 };

Because a C<build> wouldn't be legal inside a C<sys> block.

=head1 SEE ALSO

=over 4

=item L<Alien>

=item L<Alien::Build>

=item L<Alien::Build::MM>

=item L<Alien::Base>

=back

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK1N%[���vavaperl5/lwptut.podnu��6�$=head1 NAME

lwptut -- An LWP Tutorial

=head1 DESCRIPTION

LWP (short for "Library for WWW in Perl") is a very popular group of
Perl modules for accessing data on the Web. Like most Perl
module-distributions, each of LWP's component modules comes with
documentation that is a complete reference to its interface. However,
there are so many modules in LWP that it's hard to know where to start
looking for information on how to do even the simplest most common
things.

Really introducing you to using LWP would require a whole book -- a book
that just happens to exist, called I<Perl & LWP>. But this article
should give you a taste of how you can go about some common tasks with
LWP.


=head2 Getting documents with LWP::Simple

If you just want to get what's at a particular URL, the simplest way
to do it is LWP::Simple's functions.

In a Perl program, you can call its C<get($url)> function.  It will try
getting that URL's content.  If it works, then it'll return the
content; but if there's some error, it'll return undef.

  my $url = 'http://www.npr.org/programs/fa/?todayDate=current';
    # Just an example: the URL for the most recent /Fresh Air/ show

  use LWP::Simple;
  my $content = get $url;
  die "Couldn't get $url" unless defined $content;

  # Then go do things with $content, like this:

  if($content =~ m/jazz/i) {
    print "They're talking about jazz today on Fresh Air!\n";
  }
  else {
    print "Fresh Air is apparently jazzless today.\n";
  }

The handiest variant on C<get> is C<getprint>, which is useful in Perl
one-liners.  If it can get the page whose URL you provide, it sends it
to STDOUT; otherwise it complains to STDERR.

  % perl -MLWP::Simple -e "getprint 'http://www.cpan.org/RECENT'"

That is the URL of a plain text file that lists new files in CPAN in
the past two weeks.  You can easily make it part of a tidy little
shell command, like this one that mails you the list of new
C<Acme::> modules:

  % perl -MLWP::Simple -e "getprint 'http://www.cpan.org/RECENT'"  \
     | grep "/by-module/Acme" | mail -s "New Acme modules! Joy!" $USER

There are other useful functions in LWP::Simple, including one function
for running a HEAD request on a URL (useful for checking links, or
getting the last-revised time of a URL), and two functions for
saving/mirroring a URL to a local file. See L<the LWP::Simple
documentation|LWP::Simple> for the full details, or chapter 2 of I<Perl
& LWP> for more examples.



=for comment
 ##########################################################################



=head2 The Basics of the LWP Class Model

LWP::Simple's functions are handy for simple cases, but its functions
don't support cookies or authorization, don't support setting header
lines in the HTTP request, generally don't support reading header lines
in the HTTP response (notably the full HTTP error message, in case of an
error). To get at all those features, you'll have to use the full LWP
class model.

While LWP consists of dozens of classes, the main two that you have to
understand are L<LWP::UserAgent> and L<HTTP::Response>. LWP::UserAgent
is a class for "virtual browsers" which you use for performing requests,
and L<HTTP::Response> is a class for the responses (or error messages)
that you get back from those requests.

The basic idiom is C<< $response = $browser->get($url) >>, or more fully
illustrated:

  # Early in your program:
  
  use LWP 5.64; # Loads all important LWP classes, and makes
                #  sure your version is reasonably recent.

  my $browser = LWP::UserAgent->new;
  
  ...
  
  # Then later, whenever you need to make a get request:
  my $url = 'http://www.npr.org/programs/fa/?todayDate=current';
  
  my $response = $browser->get( $url );
  die "Can't get $url -- ", $response->status_line
   unless $response->is_success;

  die "Hey, I was expecting HTML, not ", $response->content_type
   unless $response->content_type eq 'text/html';
     # or whatever content-type you're equipped to deal with

  # Otherwise, process the content somehow:
  
  if($response->decoded_content =~ m/jazz/i) {
    print "They're talking about jazz today on Fresh Air!\n";
  }
  else {
    print "Fresh Air is apparently jazzless today.\n";
  }

There are two objects involved: C<$browser>, which holds an object of
class LWP::UserAgent, and then the C<$response> object, which is of
class HTTP::Response. You really need only one browser object per
program; but every time you make a request, you get back a new
HTTP::Response object, which will have some interesting attributes:

=over

=item *

A status code indicating
success or failure
(which you can test with C<< $response->is_success >>).

=item *

An HTTP status
line that is hopefully informative if there's failure (which you can
see with C<< $response->status_line >>,
returning something like "404 Not Found").

=item *

A MIME content-type like "text/html", "image/gif",
"application/xml", etc., which you can see with 
C<< $response->content_type >>

=item *

The actual content of the response, in C<< $response->decoded_content >>.
If the response is HTML, that's where the HTML source will be; if
it's a GIF, then C<< $response->decoded_content >> will be the binary
GIF data.

=item *

And dozens of other convenient and more specific methods that are
documented in the docs for L<HTTP::Response>, and its superclasses
L<HTTP::Message> and L<HTTP::Headers>.

=back



=for comment
 ##########################################################################



=head2 Adding Other HTTP Request Headers

The most commonly used syntax for requests is C<< $response =
$browser->get($url) >>, but in truth, you can add extra HTTP header
lines to the request by adding a list of key-value pairs after the URL,
like so:

  $response = $browser->get( $url, $key1, $value1, $key2, $value2, ... );

For example, here's how to send some commonly used headers, in case
you're dealing with a site that would otherwise reject your request:


  my @ns_headers = (
   'User-Agent' => 'Mozilla/4.76 [en] (Win98; U)',
   'Accept' => 'image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */*',
   'Accept-Charset' => 'iso-8859-1,*,utf-8',
   'Accept-Language' => 'en-US',
  );

  ...
  
  $response = $browser->get($url, @ns_headers);

If you weren't reusing that array, you could just go ahead and do this: 

  $response = $browser->get($url,
   'User-Agent' => 'Mozilla/4.76 [en] (Win98; U)',
   'Accept' => 'image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */*',
   'Accept-Charset' => 'iso-8859-1,*,utf-8',
   'Accept-Language' => 'en-US',
  );

If you were only ever changing the 'User-Agent' line, you could just change
the C<$browser> object's default line from "libwww-perl/5.65" (or the like)
to whatever you like, using the LWP::UserAgent C<agent> method:

   $browser->agent('Mozilla/4.76 [en] (Win98; U)');



=for comment
 ##########################################################################



=head2 Enabling Cookies

A default LWP::UserAgent object acts like a browser with its cookies
support turned off. There are various ways of turning it on, by setting
its C<cookie_jar> attribute. A "cookie jar" is an object representing
a little database of all
the HTTP cookies that a browser knows about. It can correspond to a
file on disk or 
an in-memory object that starts out empty, and whose collection of
cookies will disappear once the program is finished running.

To give a browser an in-memory empty cookie jar, you set its C<cookie_jar>
attribute like so:

  use HTTP::CookieJar::LWP;
  $browser->cookie_jar( HTTP::CookieJar::LWP->new );

To save a cookie jar to disk, see L<< HTTP::CookieJar/dump_cookies >>.
To load cookies from disk into a jar, see L<<
HTTP::CookieJar/load_cookies >>.

=for comment
 ##########################################################################



=head2 Posting Form Data

Many HTML forms send data to their server using an HTTP POST request, which
you can send with this syntax:

 $response = $browser->post( $url,
   [
     formkey1 => value1, 
     formkey2 => value2, 
     ...
   ],
 );

Or if you need to send HTTP headers:

 $response = $browser->post( $url,
   [
     formkey1 => value1, 
     formkey2 => value2, 
     ...
   ],
   headerkey1 => value1, 
   headerkey2 => value2, 
 );

For example, the following program makes a search request to AltaVista
(by sending some form data via an HTTP POST request), and extracts from
the HTML the report of the number of matches:

  use strict;
  use warnings;
  use LWP 5.64;
  my $browser = LWP::UserAgent->new;

  my $word = 'tarragon';

  my $url = 'http://search.yahoo.com/yhs/search';
  my $response = $browser->post( $url,
    [ 'q' => $word,  # the Altavista query string
      'fr' => 'altavista', 'pg' => 'q', 'avkw' => 'tgz', 'kl' => 'XX',
    ]
  );
  die "$url error: ", $response->status_line
   unless $response->is_success;
  die "Weird content type at $url -- ", $response->content_type
   unless $response->content_is_html;

  if( $response->decoded_content =~ m{([0-9,]+)(?:<.*?>)? results for} ) {
    # The substring will be like "996,000</strong> results for"
    print "$word: $1\n";
  }
  else {
    print "Couldn't find the match-string in the response\n";
  }



=for comment
 ##########################################################################



=head2 Sending GET Form Data

Some HTML forms convey their form data not by sending the data
in an HTTP POST request, but by making a normal GET request with
the data stuck on the end of the URL.  For example, if you went to
C<www.imdb.com> and ran a search on "Blade Runner", the URL you'd see
in your browser window would be:

  http://www.imdb.com/find?s=all&q=Blade+Runner

To run the same search with LWP, you'd use this idiom, which involves
the URI class:

  use URI;
  my $url = URI->new( 'http://www.imdb.com/find' );
    # makes an object representing the URL

  $url->query_form(  # And here the form data pairs:
    'q' => 'Blade Runner',
    's' => 'all',
  );

  my $response = $browser->get($url);

See chapter 5 of I<Perl & LWP> for a longer discussion of HTML forms
and of form data, and chapters 6 through 9 for a longer discussion of
extracting data from HTML.



=head2 Absolutizing URLs

The URI class that we just mentioned above provides all sorts of methods
for accessing and modifying parts of URLs (such as asking sort of URL it
is with C<< $url->scheme >>, and asking what host it refers to with C<<
$url->host >>, and so on, as described in L<the docs for the URI
class|URI>.  However, the methods of most immediate interest
are the C<query_form> method seen above, and now the C<new_abs> method
for taking a probably-relative URL string (like "../foo.html") and getting
back an absolute URL (like "http://www.perl.com/stuff/foo.html"), as
shown here:

  use URI;
  $abs = URI->new_abs($maybe_relative, $base);

For example, consider this program that matches URLs in the HTML
list of new modules in CPAN:

  use strict;
  use warnings;
  use LWP;
  my $browser = LWP::UserAgent->new;
  
  my $url = 'http://www.cpan.org/RECENT.html';
  my $response = $browser->get($url);
  die "Can't get $url -- ", $response->status_line
   unless $response->is_success;
  
  my $html = $response->decoded_content;
  while( $html =~ m/<A HREF=\"(.*?)\"/g ) {
    print "$1\n";
  }

When run, it emits output that starts out something like this:

  MIRRORING.FROM
  RECENT
  RECENT.html
  authors/00whois.html
  authors/01mailrc.txt.gz
  authors/id/A/AA/AASSAD/CHECKSUMS
  ...

However, if you actually want to have those be absolute URLs, you
can use the URI module's C<new_abs> method, by changing the C<while>
loop to this:

  while( $html =~ m/<A HREF=\"(.*?)\"/g ) {
    print URI->new_abs( $1, $response->base ) ,"\n";
  }

(The C<< $response->base >> method from L<HTTP::Message|HTTP::Message>
is for returning what URL
should be used for resolving relative URLs -- it's usually just
the same as the URL that you requested.)

That program then emits nicely absolute URLs:

  http://www.cpan.org/MIRRORING.FROM
  http://www.cpan.org/RECENT
  http://www.cpan.org/RECENT.html
  http://www.cpan.org/authors/00whois.html
  http://www.cpan.org/authors/01mailrc.txt.gz
  http://www.cpan.org/authors/id/A/AA/AASSAD/CHECKSUMS
  ...

See chapter 4 of I<Perl & LWP> for a longer discussion of URI objects.

Of course, using a regexp to match hrefs is a bit simplistic, and for
more robust programs, you'll probably want to use an HTML-parsing module
like L<HTML::LinkExtor> or L<HTML::TokeParser> or even maybe
L<HTML::TreeBuilder>.




=for comment
 ##########################################################################

=head2 Other Browser Attributes

LWP::UserAgent objects have many attributes for controlling how they
work.  Here are a few notable ones:

=over

=item *

C<< $browser->timeout(15); >>

This sets this browser object to give up on requests that don't answer
within 15 seconds.


=item *

C<< $browser->protocols_allowed( [ 'http', 'gopher'] ); >>

This sets this browser object to not speak any protocols other than HTTP
and gopher. If it tries accessing any other kind of URL (like an "ftp:"
or "mailto:" or "news:" URL), then it won't actually try connecting, but
instead will immediately return an error code 500, with a message like
"Access to 'ftp' URIs has been disabled".


=item *

C<< use LWP::ConnCache; $browser->conn_cache(LWP::ConnCache->new()); >>

This tells the browser object to try using the HTTP/1.1 "Keep-Alive"
feature, which speeds up requests by reusing the same socket connection
for multiple requests to the same server.


=item *

C<< $browser->agent( 'SomeName/1.23 (more info here maybe)' ) >>

This changes how the browser object will identify itself in
the default "User-Agent" line is its HTTP requests.  By default,
it'll send "libwww-perl/I<versionnumber>", like
"libwww-perl/5.65".  You can change that to something more descriptive
like this:

  $browser->agent( 'SomeName/3.14 (contact@robotplexus.int)' );

Or if need be, you can go in disguise, like this:

  $browser->agent( 'Mozilla/4.0 (compatible; MSIE 5.12; Mac_PowerPC)' );


=item *

C<< push @{ $ua->requests_redirectable }, 'POST'; >>

This tells this browser to obey redirection responses to POST requests
(like most modern interactive browsers), even though the HTTP RFC says
that should not normally be done.


=back


For more options and information, see L<the full documentation for
LWP::UserAgent|LWP::UserAgent>.



=for comment
 ##########################################################################



=head2 Writing Polite Robots

If you want to make sure that your LWP-based program respects F<robots.txt>
files and doesn't make too many requests too fast, you can use the LWP::RobotUA
class instead of the LWP::UserAgent class.

LWP::RobotUA class is just like LWP::UserAgent, and you can use it like so:

  use LWP::RobotUA;
  my $browser = LWP::RobotUA->new('YourSuperBot/1.34', 'you@yoursite.com');
    # Your bot's name and your email address

  my $response = $browser->get($url);

But HTTP::RobotUA adds these features:


=over

=item *

If the F<robots.txt> on C<$url>'s server forbids you from accessing
C<$url>, then the C<$browser> object (assuming it's of class LWP::RobotUA)
won't actually request it, but instead will give you back (in C<$response>) a 403 error
with a message "Forbidden by robots.txt".  That is, if you have this line:

  die "$url -- ", $response->status_line, "\nAborted"
   unless $response->is_success;

then the program would die with an error message like this:

  http://whatever.site.int/pith/x.html -- 403 Forbidden by robots.txt
  Aborted at whateverprogram.pl line 1234

=item *

If this C<$browser> object sees that the last time it talked to
C<$url>'s server was too recently, then it will pause (via C<sleep>) to
avoid making too many requests too often. How long it will pause for, is
by default one minute -- but you can control it with the C<<
$browser->delay( I<minutes> ) >> attribute.

For example, this code:

  $browser->delay( 7/60 );

...means that this browser will pause when it needs to avoid talking to
any given server more than once every 7 seconds.

=back

For more options and information, see L<the full documentation for
LWP::RobotUA|LWP::RobotUA>.





=for comment
 ##########################################################################

=head2 Using Proxies

In some cases, you will want to (or will have to) use proxies for
accessing certain sites and/or using certain protocols. This is most
commonly the case when your LWP program is running (or could be running)
on a machine that is behind a firewall.

To make a browser object use proxies that are defined in the usual
environment variables (C<HTTP_PROXY>, etc.), just call the C<env_proxy>
on a user-agent object before you go making any requests on it.
Specifically:

  use LWP::UserAgent;
  my $browser = LWP::UserAgent->new;
  
  # And before you go making any requests:
  $browser->env_proxy;

For more information on proxy parameters, see L<the LWP::UserAgent
documentation|LWP::UserAgent>, specifically the C<proxy>, C<env_proxy>,
and C<no_proxy> methods.



=for comment
 ##########################################################################

=head2 HTTP Authentication

Many web sites restrict access to documents by using "HTTP
Authentication". This isn't just any form of "enter your password"
restriction, but is a specific mechanism where the HTTP server sends the
browser an HTTP code that says "That document is part of a protected
'realm', and you can access it only if you re-request it and add some
special authorization headers to your request".

For example, the Unicode.org admins stop email-harvesting bots from
harvesting the contents of their mailing list archives, by protecting
them with HTTP Authentication, and then publicly stating the username
and password (at C<http://www.unicode.org/mail-arch/>) -- namely
username "unicode-ml" and password "unicode".  

For example, consider this URL, which is part of the protected
area of the web site:

  http://www.unicode.org/mail-arch/unicode-ml/y2002-m08/0067.html

If you access that with a browser, you'll get a prompt
like 
"Enter username and password for 'Unicode-MailList-Archives' at server
'www.unicode.org'".

In LWP, if you just request that URL, like this:

  use LWP;
  my $browser = LWP::UserAgent->new;

  my $url =
   'http://www.unicode.org/mail-arch/unicode-ml/y2002-m08/0067.html';
  my $response = $browser->get($url);

  die "Error: ", $response->header('WWW-Authenticate') || 'Error accessing',
    #  ('WWW-Authenticate' is the realm-name)
    "\n ", $response->status_line, "\n at $url\n Aborting"
   unless $response->is_success;

Then you'll get this error:

  Error: Basic realm="Unicode-MailList-Archives"
   401 Authorization Required
   at http://www.unicode.org/mail-arch/unicode-ml/y2002-m08/0067.html
   Aborting at auth1.pl line 9.  [or wherever]

...because the C<$browser> doesn't know any the username and password
for that realm ("Unicode-MailList-Archives") at that host
("www.unicode.org").  The simplest way to let the browser know about this
is to use the C<credentials> method to let it know about a username and
password that it can try using for that realm at that host.  The syntax is:

  $browser->credentials(
    'servername:portnumber',
    'realm-name',
   'username' => 'password'
  );

In most cases, the port number is 80, the default TCP/IP port for HTTP; and
you usually call the C<credentials> method before you make any requests.
For example:

  $browser->credentials(
    'reports.mybazouki.com:80',
    'web_server_usage_reports',
    'plinky' => 'banjo123'
  );

So if we add the following to the program above, right after the C<<
$browser = LWP::UserAgent->new; >> line...

  $browser->credentials(  # add this to our $browser 's "key ring"
    'www.unicode.org:80',
    'Unicode-MailList-Archives',
    'unicode-ml' => 'unicode'
  );

...then when we run it, the request succeeds, instead of causing the
C<die> to be called.



=for comment
 ##########################################################################

=head2 Accessing HTTPS URLs

When you access an HTTPS URL, it'll work for you just like an HTTP URL
would -- if your LWP installation has HTTPS support (via an appropriate
Secure Sockets Layer library).  For example:

  use LWP;
  my $url = 'https://www.paypal.com/';   # Yes, HTTPS!
  my $browser = LWP::UserAgent->new;
  my $response = $browser->get($url);
  die "Error at $url\n ", $response->status_line, "\n Aborting"
   unless $response->is_success;
  print "Whee, it worked!  I got that ",
   $response->content_type, " document!\n";

If your LWP installation doesn't have HTTPS support set up, then the
response will be unsuccessful, and you'll get this error message:

  Error at https://www.paypal.com/
   501 Protocol scheme 'https' is not supported
   Aborting at paypal.pl line 7.   [or whatever program and line]

If your LWP installation I<does> have HTTPS support installed, then the
response should be successful, and you should be able to consult
C<$response> just like with any normal HTTP response.

For information about installing HTTPS support for your LWP
installation, see the helpful F<README.SSL> file that comes in the
libwww-perl distribution.


=for comment
 ##########################################################################



=head2 Getting Large Documents

When you're requesting a large (or at least potentially large) document,
a problem with the normal way of using the request methods (like C<<
$response = $browser->get($url) >>) is that the response object in
memory will have to hold the whole document -- I<in memory>. If the
response is a thirty megabyte file, this is likely to be quite an
imposition on this process's memory usage.

A notable alternative is to have LWP save the content to a file on disk,
instead of saving it up in memory.  This is the syntax to use:

  $response = $ua->get($url,
                         ':content_file' => $filespec,
                      );

For example,

  $response = $ua->get('http://search.cpan.org/',
                         ':content_file' => '/tmp/sco.html'
                      );

When you use this C<:content_file> option, the C<$response> will have
all the normal header lines, but C<< $response->content >> will be
empty.  Errors writing to the content file (for example due to
permission denied or the filesystem being full) will be reported via
the C<Client-Aborted> or C<X-Died> response headers, and not the
C<is_success> method:

  if ($response->header('Client-Aborted') eq 'die') {
    # handle error ...

Note that this ":content_file" option isn't supported under older
versions of LWP, so you should consider adding C<use LWP 5.66;> to check
the LWP version, if you think your program might run on systems with
older versions.

If you need to be compatible with older LWP versions, then use
this syntax, which does the same thing:

  use HTTP::Request::Common;
  $response = $ua->request( GET($url), $filespec );


=for comment
 ##########################################################################


=head1 SEE ALSO

Remember, this article is just the most rudimentary introduction to
LWP -- to learn more about LWP and LWP-related tasks, you really
must read from the following:

=over

=item *

L<LWP::Simple> -- simple functions for getting/heading/mirroring URLs

=item *

L<LWP> -- overview of the libwww-perl modules

=item *

L<LWP::UserAgent> -- the class for objects that represent "virtual browsers"

=item *

L<HTTP::Response> -- the class for objects that represent the response to
a LWP response, as in C<< $response = $browser->get(...) >>

=item *

L<HTTP::Message> and L<HTTP::Headers> -- classes that provide more methods
to HTTP::Response.

=item *

L<URI> -- class for objects that represent absolute or relative URLs

=item *

L<URI::Escape> -- functions for URL-escaping and URL-unescaping strings
(like turning "this & that" to and from "this%20%26%20that").

=item *

L<HTML::Entities> -- functions for HTML-escaping and HTML-unescaping strings
(like turning "C. & E. BrontE<euml>" to and from "C. &amp; E. Bront&euml;")

=item *

L<HTML::TokeParser> and L<HTML::TreeBuilder> -- classes for parsing HTML

=item *

L<HTML::LinkExtor> -- class for finding links in HTML documents

=item *

The book I<Perl & LWP> by Sean M. Burke.  O'Reilly & Associates, 
2002.  ISBN: 0-596-00178-9, L<http://oreilly.com/catalog/perllwp/>.  The
whole book is also available free online:
L<http://lwp.interglacial.com>.

=back


=head1 COPYRIGHT

Copyright 2002, Sean M. Burke.  You can redistribute this document and/or
modify it, but only under the same terms as Perl itself.

=head1 AUTHOR

Sean M. Burke C<sburke@cpan.org>

=for comment
 ##########################################################################

=cut

# End of Pod
PK1N%[-�**perl5/Canary/Stability.pmnu��6�$=head1 NAME

Canary::Stability - canary to check perl compatibility for schmorp's modules

=head1 SYNOPSIS

 # in Makefile.PL
 use Canary::Stability DISTNAME => 2001, MINIMUM_PERL_VERSION;

=head1 DESCRIPTION

This module is used by Schmorp's modules during configuration stage to
test the installed perl for compatibility with his modules.

It's not, at this stage, meant as a tool for other module authors,
although in principle nothing prevents them from subscribing to the same
ideas.

See the F<Makefile.PL> in L<Coro> or L<AnyEvent> for usage examples.

=cut

package Canary::Stability;

BEGIN {
   $VERSION = 2013;
}

sub sgr {
   # we just assume ANSI almost everywhere
   # red 31, yellow 33, green 32
   local $| = 1;

   $ENV{PERL_CANARY_STABILITY_COLOUR} ne 0
   and ((-t STDOUT and length $ENV{TERM}) or $ENV{PERL_CANARY_STABILITY_COLOUR})
   and print "\e[$_[0]m";
}

sub import {
   my (undef, $distname, $minvers, $minperl) = @_;

   $ENV{PERL_CANARY_STABILITY_DISABLE}
      and return;

   $minperl ||= 5.008002;

   print <<EOF;

***
*** Canary::Stability COMPATIBILITY AND SUPPORT CHECK
*** =================================================
***
*** Hi!
***
*** I do my best to provide predictable and reliable software.
***
*** However, in recent releases, P5P (who maintain perl) have been
*** introducing regressions that are sometimes subtle and at other times
*** catastrophic, often for personal preferences with little or no concern
*** for existing code, most notably CPAN.
***
*** For this reason, it has become very hard for me to maintain the level
*** of reliability and support I have committed myself to in the past, at
*** least with some perl versions: I simply can't keep up working around new
*** bugs or gratituous incompatibilities, and in turn you might suffer from
*** unanticipated problems.
***
*** Therefore I have introduced a support and compatibility check, the results
*** of which follow below, together with a FAQ and some recommendations.
***
*** This check is just to let you know that there might be a risk, so you can
*** make judgement calls on how to proceed - it will not keep the module from
*** installing or working.
***
EOF

   if ($minvers > $VERSION) {
      sgr 33;
      print <<EOF;
*** The stability canary says: (nothing, it died of old age).
***
*** Your Canary::Stability module (used by $distname) is too old.
*** This is not a fatal problem - while you might want to upgrade to version
*** $minvers (currently installed version: $VERSION) to get better support
*** status testing, you might also not want to care at all, and all will
*** be well as long $distname works well enough for you, as the stability
*** canary is only used when installing the distribution.
***
EOF
   } elsif ($] < $minperl) {

      sgr 33;
      print <<EOF;
*** The stability canary says: chirp (it seems concerned about something).
***
*** Your perl version ($]) is older than the $distname distribution
*** likes ($minperl). This is not a fatal problem - the module might work
*** well with your version of perl, but it does mean the author likely
*** won't do anything to make it work if it breaks.
***
EOF

      if ($ENV{AUTOMATED_TESTING}) {
         print <<EOF;
*** Since this is an AUTOMATED_TESTING environment, the stability canary
*** decided to fail cleanly here, rather than to generate a false test
*** result.
***
EOF
         exit 0;
      }

   } elsif (defined $Internals::StabilityBranchVersion) {
      # note to people studying this modules sources:
      # the above test is not considered a clean or stable way to
      # test for the stability branch.

      sgr 32;
      print <<EOF;
*** The stability canary says: chirp! chirp! (it seems to be quite excited)
***
*** It seems you are running schmorp's stability branch of perl.
*** All should be well, and if it isn't, you should report this as a bug
*** to the $distname author.
***
EOF
   } elsif ($] < 5.021) {
      #sgr 32;
      print <<EOF;
*** The stability canary says: chirp! chirp! (it seems to be quite happy)
***
*** Your version of perl ($]) is quite supported by $distname, nothing
*** else to be said, hope it comes in handy.
***
EOF
   } else {
      sgr 31;
      print <<EOF;
*** The stability canary says: (nothing, it was driven away by harsh weather)
***
*** It seems you are running perl version $], likely the "official" or
*** "standard" version. While there is nothing wrong with doing that,
*** standard perl versions 5.022 and up are not supported by $distname.
*** While this might be fatal, it might also be all right - if you run into
*** problems, you might want to downgrade your perl or switch to the
*** stability branch.
***
*** If everything works fine, you can ignore this message.
***
EOF
      sgr 0;
      print <<EOF;
***
*** Stability canary mini-FAQ:
***
*** Do I need to do anything?
***    With luck, no. While some distributions are known to fail
***    already, most should probably work. This message is here
***    to alert you that your perl is not supported by $distname,
***    and if things go wrong, you either need to downgrade, or
***    sidegrade to the stability variant of your perl version,
***    or simply live with the consequences.
***
*** What is this canary thing?
***    It's purpose is to check support status of $distname with
***    respect to your perl version.
***
*** What is this "stability branch"?
***    It's a branch or fork of the official perl, by schmorp, to
***    improve stability and compatibility with existing modules.
***
*** How can I skip this prompt on automated installs?
***    Set PERL_CANARY_STABILITY_NOPROMPT=1 in your environment.
***    More info is in the Canary::Stability manpage.
***
*** Long version of this FAQ: http://stableperl.schmorp.de/faq.html
*** Stability Branch homepage: http://stableperl.schmorp.de/
***

EOF

      unless ($ENV{PERL_CANARY_STABILITY_NOPROMPT}) {
         require ExtUtils::MakeMaker;

         ExtUtils::MakeMaker::prompt ("Continue anyways? ", "y") =~ /^y/i
            or die "FATAL: User aborted configuration of $distname.\n";
      }
   }

   sgr 0;
}

=head1 ENVIRONMENT VARIABLES

=over 4

=item C<PERL_CANARY_STABILITY_NOPROMPT=1>

Do not prompt the user on alert messages.

=item C<PERL_CANARY_STABILITY_COLOUR=0>

Disable use of colour.

=item C<PERL_CANARY_STABILITY_COLOUR=1>

Force use of colour.

=item C<PERL_CANARY_STABILITY_DISABLE=1>

Disable this modules functionality completely.

=item C<AUTOMATED_TESTING=1>

When this variable is set to a true value and the perl minimum version
requirement is not met, the module will exit, which should skip testing
under automated testing environments.

This is done to avoid false failure or success reports when the chances of
success are already quite low and the failures are not supported by the
author.

=back

=head1 AUTHOR

 Marc Lehmann <schmorp@schmorp.de>
 http://software.schmorp.de/pkg/Canary-Stability.html

=cut

1

PK1N%[���O�O�perl5/local/lib.pmnu��6�$package local::lib;
use 5.006;
BEGIN {
  if ($ENV{RELEASE_TESTING}) {
    require strict;
    strict->import;
    require warnings;
    warnings->import;
  }
}
use Config ();

our $VERSION = '2.000029';
$VERSION =~ tr/_//d;

BEGIN {
  *_WIN32 = ($^O eq 'MSWin32' || $^O eq 'NetWare' || $^O eq 'symbian')
    ? sub(){1} : sub(){0};
  # punt on these systems
  *_USE_FSPEC = ($^O eq 'MacOS' || $^O eq 'VMS' || $INC{'File/Spec.pm'})
    ? sub(){1} : sub(){0};
}
my $_archname = $Config::Config{archname};
my $_version = $Config::Config{version};
my @_inc_version_list = reverse split / /, $Config::Config{inc_version_list};
my $_path_sep = $Config::Config{path_sep};

our $_DIR_JOIN = _WIN32 ? '\\' : '/';
our $_DIR_SPLIT = (_WIN32 || $^O eq 'cygwin') ? qr{[\\/]}
                                              : qr{/};
our $_ROOT = _WIN32 ? do {
  my $UNC = qr{[\\/]{2}[^\\/]+[\\/][^\\/]+};
  qr{^(?:$UNC|[A-Za-z]:|)$_DIR_SPLIT};
} : qr{^/};
our $_PERL;

sub _perl {
  if (!$_PERL) {
    # untaint and validate
    ($_PERL, my $exe) = $^X =~ /((?:.*$_DIR_SPLIT)?(.+))/;
    $_PERL = 'perl'
      if $exe !~ /perl/;
    if (_is_abs($_PERL)) {
    }
    elsif (-x $Config::Config{perlpath}) {
      $_PERL = $Config::Config{perlpath};
    }
    elsif ($_PERL =~ $_DIR_SPLIT && -x $_PERL) {
      $_PERL = _rel2abs($_PERL);
    }
    else {
      ($_PERL) =
        map { /(.*)/ }
        grep { -x $_ }
        map { ($_, _WIN32 ? ("$_.exe") : ()) }
        map { join($_DIR_JOIN, $_, $_PERL) }
        split /\Q$_path_sep\E/, $ENV{PATH};
    }
  }
  $_PERL;
}

sub _cwd {
  if (my $cwd
    = defined &Cwd::sys_cwd ? \&Cwd::sys_cwd
    : defined &Cwd::cwd     ? \&Cwd::cwd
    : undef
  ) {
    no warnings 'redefine';
    *_cwd = $cwd;
    goto &$cwd;
  }
  my $drive = shift;
  return Win32::GetCwd()
    if _WIN32 && defined &Win32::GetCwd && !$drive;
  local @ENV{qw(PATH IFS CDPATH ENV BASH_ENV)};
  delete @ENV{qw(PATH IFS CDPATH ENV BASH_ENV)};
  my $cmd = $drive ? "eval { Cwd::getdcwd(q($drive)) }"
                   : 'getcwd';
  my $perl = _perl;
  my $cwd = `"$perl" -MCwd -le "print $cmd"`;
  chomp $cwd;
  if (!length $cwd && $drive) {
    $cwd = $drive;
  }
  $cwd =~ s/$_DIR_SPLIT?$/$_DIR_JOIN/;
  $cwd;
}

sub _catdir {
  if (_USE_FSPEC) {
    require File::Spec;
    File::Spec->catdir(@_);
  }
  else {
    my $dir = join($_DIR_JOIN, @_);
    $dir =~ s{($_DIR_SPLIT)(?:\.?$_DIR_SPLIT)+}{$1}g;
    $dir;
  }
}

sub _is_abs {
  if (_USE_FSPEC) {
    require File::Spec;
    File::Spec->file_name_is_absolute($_[0]);
  }
  else {
    $_[0] =~ $_ROOT;
  }
}

sub _rel2abs {
  my ($dir, $base) = @_;
  return $dir
    if _is_abs($dir);

  $base = _WIN32 && $dir =~ s/^([A-Za-z]:)// ? _cwd("$1")
        : $base                              ? _rel2abs($base)
                                             : _cwd;
  return _catdir($base, $dir);
}

our $_DEVNULL;
sub _devnull {
  return $_DEVNULL ||=
    _USE_FSPEC      ? (require File::Spec, File::Spec->devnull)
    : _WIN32        ? 'nul'
    : $^O eq 'os2'  ? '/dev/nul'
    : '/dev/null';
}

sub import {
  my ($class, @args) = @_;
  if ($0 eq '-') {
    push @args, @ARGV;
    require Cwd;
  }

  my @steps;
  my %opts;
  my %attr;
  my $shelltype;

  while (@args) {
    my $arg = shift @args;
    # check for lethal dash first to stop processing before causing problems
    # the fancy dash is U+2212 or \xE2\x88\x92
    if ($arg =~ /\xE2\x88\x92/) {
      die <<'DEATH';
WHOA THERE! It looks like you've got some fancy dashes in your commandline!
These are *not* the traditional -- dashes that software recognizes. You
probably got these by copy-pasting from the perldoc for this module as
rendered by a UTF8-capable formatter. This most typically happens on an OS X
terminal, but can happen elsewhere too. Please try again after replacing the
dashes with normal minus signs.
DEATH
    }
    elsif ($arg eq '--self-contained') {
      die <<'DEATH';
FATAL: The local::lib --self-contained flag has never worked reliably and the
original author, Mark Stosberg, was unable or unwilling to maintain it. As
such, this flag has been removed from the local::lib codebase in order to
prevent misunderstandings and potentially broken builds. The local::lib authors
recommend that you look at the lib::core::only module shipped with this
distribution in order to create a more robust environment that is equivalent to
what --self-contained provided (although quite possibly not what you originally
thought it provided due to the poor quality of the documentation, for which we
apologise).
DEATH
    }
    elsif( $arg =~ /^--deactivate(?:=(.*))?$/ ) {
      my $path = defined $1 ? $1 : shift @args;
      push @steps, ['deactivate', $path];
    }
    elsif ( $arg eq '--deactivate-all' ) {
      push @steps, ['deactivate_all'];
    }
    elsif ( $arg =~ /^--shelltype(?:=(.*))?$/ ) {
      $shelltype = defined $1 ? $1 : shift @args;
    }
    elsif ( $arg eq '--no-create' ) {
      $opts{no_create} = 1;
    }
    elsif ( $arg eq '--quiet' ) {
      $attr{quiet} = 1;
    }
    elsif ( $arg eq '--always' ) {
      $attr{always} = 1;
    }
    elsif ( $arg =~ /^--/ ) {
      die "Unknown import argument: $arg";
    }
    else {
      push @steps, ['activate', $arg, \%opts];
    }
  }
  if (!@steps) {
    push @steps, ['activate', undef, \%opts];
  }

  my $self = $class->new(%attr);

  for (@steps) {
    my ($method, @args) = @$_;
    $self = $self->$method(@args);
  }

  if ($0 eq '-') {
    print $self->environment_vars_string($shelltype);
    exit 0;
  }
  else {
    $self->setup_local_lib;
  }
}

sub new {
  my $class = shift;
  bless {@_}, $class;
}

sub clone {
  my $self = shift;
  bless {%$self, @_}, ref $self;
}

sub inc { $_[0]->{inc}     ||= \@INC }
sub libs { $_[0]->{libs}   ||= [ \'PERL5LIB' ] }
sub bins { $_[0]->{bins}   ||= [ \'PATH' ] }
sub roots { $_[0]->{roots} ||= [ \'PERL_LOCAL_LIB_ROOT' ] }
sub extra { $_[0]->{extra} ||= {} }
sub quiet { $_[0]->{quiet} }

sub _as_list {
  my $list = shift;
  grep length, map {
    !(ref $_ && ref $_ eq 'SCALAR') ? $_ : (
      defined $ENV{$$_} ? split(/\Q$_path_sep/, $ENV{$$_})
                        : ()
    )
  } ref $list ? @$list : $list;
}
sub _remove_from {
  my ($list, @remove) = @_;
  return @$list
    if !@remove;
  my %remove = map { $_ => 1 } @remove;
  grep !$remove{$_}, _as_list($list);
}

my @_lib_subdirs = (
  [$_version, $_archname],
  [$_version],
  [$_archname],
  (map [$_], @_inc_version_list),
  [],
);

sub install_base_bin_path {
  my ($class, $path) = @_;
  return _catdir($path, 'bin');
}
sub install_base_perl_path {
  my ($class, $path) = @_;
  return _catdir($path, 'lib', 'perl5');
}
sub install_base_arch_path {
  my ($class, $path) = @_;
  _catdir($class->install_base_perl_path($path), $_archname);
}

sub lib_paths_for {
  my ($class, $path) = @_;
  my $base = $class->install_base_perl_path($path);
  return map { _catdir($base, @$_) } @_lib_subdirs;
}

sub _mm_escape_path {
  my $path = shift;
  $path =~ s/\\/\\\\/g;
  if ($path =~ s/ /\\ /g) {
    $path = qq{"$path"};
  }
  return $path;
}

sub _mb_escape_path {
  my $path = shift;
  $path =~ s/\\/\\\\/g;
  return qq{"$path"};
}

sub installer_options_for {
  my ($class, $path) = @_;
  return (
    PERL_MM_OPT =>
      defined $path ? "INSTALL_BASE="._mm_escape_path($path) : undef,
    PERL_MB_OPT =>
      defined $path ? "--install_base "._mb_escape_path($path) : undef,
  );
}

sub active_paths {
  my ($self) = @_;
  $self = ref $self ? $self : $self->new;

  return grep {
    # screen out entries that aren't actually reflected in @INC
    my $active_ll = $self->install_base_perl_path($_);
    grep { $_ eq $active_ll } @{$self->inc};
  } _as_list($self->roots);
}


sub deactivate {
  my ($self, $path) = @_;
  $self = $self->new unless ref $self;
  $path = $self->resolve_path($path);
  $path = $self->normalize_path($path);

  my @active_lls = $self->active_paths;

  if (!grep { $_ eq $path } @active_lls) {
    warn "Tried to deactivate inactive local::lib '$path'\n";
    return $self;
  }

  my %args = (
    bins  => [ _remove_from($self->bins,
      $self->install_base_bin_path($path)) ],
    libs  => [ _remove_from($self->libs,
      $self->install_base_perl_path($path)) ],
    inc   => [ _remove_from($self->inc,
      $self->lib_paths_for($path)) ],
    roots => [ _remove_from($self->roots, $path) ],
  );

  $args{extra} = { $self->installer_options_for($args{roots}[0]) };

  $self->clone(%args);
}

sub deactivate_all {
  my ($self) = @_;
  $self = $self->new unless ref $self;

  my @active_lls = $self->active_paths;

  my %args;
  if (@active_lls) {
    %args = (
      bins => [ _remove_from($self->bins,
        map $self->install_base_bin_path($_), @active_lls) ],
      libs => [ _remove_from($self->libs,
        map $self->install_base_perl_path($_), @active_lls) ],
      inc => [ _remove_from($self->inc,
        map $self->lib_paths_for($_), @active_lls) ],
      roots => [ _remove_from($self->roots, @active_lls) ],
    );
  }

  $args{extra} = { $self->installer_options_for(undef) };

  $self->clone(%args);
}

sub activate {
  my ($self, $path, $opts) = @_;
  $opts ||= {};
  $self = $self->new unless ref $self;
  $path = $self->resolve_path($path);
  $self->ensure_dir_structure_for($path, { quiet => $self->quiet })
    unless $opts->{no_create};

  $path = $self->normalize_path($path);

  my @active_lls = $self->active_paths;

  if (grep { $_ eq $path } @active_lls[1 .. $#active_lls]) {
    $self = $self->deactivate($path);
  }

  my %args;
  if ($opts->{always} || !@active_lls || $active_lls[0] ne $path) {
    %args = (
      bins  => [ $self->install_base_bin_path($path), @{$self->bins} ],
      libs  => [ $self->install_base_perl_path($path), @{$self->libs} ],
      inc   => [ $self->lib_paths_for($path), @{$self->inc} ],
      roots => [ $path, @{$self->roots} ],
    );
  }

  $args{extra} = { $self->installer_options_for($path) };

  $self->clone(%args);
}

sub normalize_path {
  my ($self, $path) = @_;
  $path = ( Win32::GetShortPathName($path) || $path )
    if $^O eq 'MSWin32';
  return $path;
}

sub build_environment_vars_for {
  my $self = $_[0]->new->activate($_[1], { always => 1 });
  $self->build_environment_vars;
}
sub build_activate_environment_vars_for {
  my $self = $_[0]->new->activate($_[1], { always => 1 });
  $self->build_environment_vars;
}
sub build_deactivate_environment_vars_for {
  my $self = $_[0]->new->deactivate($_[1]);
  $self->build_environment_vars;
}
sub build_deact_all_environment_vars_for {
  my $self = $_[0]->new->deactivate_all;
  $self->build_environment_vars;
}
sub build_environment_vars {
  my $self = shift;
  (
    PATH                => join($_path_sep, _as_list($self->bins)),
    PERL5LIB            => join($_path_sep, _as_list($self->libs)),
    PERL_LOCAL_LIB_ROOT => join($_path_sep, _as_list($self->roots)),
    %{$self->extra},
  );
}

sub setup_local_lib_for {
  my $self = $_[0]->new->activate($_[1]);
  $self->setup_local_lib;
}

sub setup_local_lib {
  my $self = shift;

  # if Carp is already loaded, ensure Carp::Heavy is also loaded, to avoid
  # $VERSION mismatch errors (Carp::Heavy loads Carp, so we do not need to
  # check in the other direction)
  require Carp::Heavy if $INC{'Carp.pm'};

  $self->setup_env_hash;
  @INC = @{$self->inc};
}

sub setup_env_hash_for {
  my $self = $_[0]->new->activate($_[1]);
  $self->setup_env_hash;
}
sub setup_env_hash {
  my $self = shift;
  my %env = $self->build_environment_vars;
  for my $key (keys %env) {
    if (defined $env{$key}) {
      $ENV{$key} = $env{$key};
    }
    else {
      delete $ENV{$key};
    }
  }
}

sub print_environment_vars_for {
  print $_[0]->environment_vars_string_for(@_[1..$#_]);
}

sub environment_vars_string_for {
  my $self = $_[0]->new->activate($_[1], { always => 1});
  $self->environment_vars_string;
}
sub environment_vars_string {
  my ($self, $shelltype) = @_;

  $shelltype ||= $self->guess_shelltype;

  my $extra = $self->extra;
  my @envs = (
    PATH                => $self->bins,
    PERL5LIB            => $self->libs,
    PERL_LOCAL_LIB_ROOT => $self->roots,
    map { $_ => $extra->{$_} } sort keys %$extra,
  );
  $self->_build_env_string($shelltype, \@envs);
}

sub _build_env_string {
  my ($self, $shelltype, $envs) = @_;
  my @envs = @$envs;

  my $build_method = "build_${shelltype}_env_declaration";

  my $out = '';
  while (@envs) {
    my ($name, $value) = (shift(@envs), shift(@envs));
    if (
        ref $value
        && @$value == 1
        && ref $value->[0]
        && ref $value->[0] eq 'SCALAR'
        && ${$value->[0]} eq $name) {
      next;
    }
    $out .= $self->$build_method($name, $value);
  }
  my $wrap_method = "wrap_${shelltype}_output";
  if ($self->can($wrap_method)) {
    return $self->$wrap_method($out);
  }
  return $out;
}

sub build_bourne_env_declaration {
  my ($class, $name, $args) = @_;
  my $value = $class->_interpolate($args, '${%s:-}', qr/["\\\$!`]/, '\\%s');

  if (!defined $value) {
    return qq{unset $name;\n};
  }

  $value =~ s/(^|\G|$_path_sep)\$\{$name:-\}$_path_sep/$1\${$name}\${$name:+$_path_sep}/g;
  $value =~ s/$_path_sep\$\{$name:-\}$/\${$name:+$_path_sep\${$name}}/;

  qq{${name}="$value"; export ${name};\n}
}

sub build_csh_env_declaration {
  my ($class, $name, $args) = @_;
  my ($value, @vars) = $class->_interpolate($args, '${%s}', qr/["\$]/, '"\\%s"');
  if (!defined $value) {
    return qq{unsetenv $name;\n};
  }

  my $out = '';
  for my $var (@vars) {
    $out .= qq{if ! \$?$name setenv $name '';\n};
  }

  my $value_without = $value;
  if ($value_without =~ s/(?:^|$_path_sep)\$\{$name\}(?:$_path_sep|$)//g) {
    $out .= qq{if "\${$name}" != '' setenv $name "$value";\n};
    $out .= qq{if "\${$name}" == '' };
  }
  $out .= qq{setenv $name "$value_without";\n};
  return $out;
}

sub build_cmd_env_declaration {
  my ($class, $name, $args) = @_;
  my $value = $class->_interpolate($args, '%%%s%%', qr(%), '%s');
  if (!$value) {
    return qq{\@set $name=\n};
  }

  my $out = '';
  my $value_without = $value;
  if ($value_without =~ s/(?:^|$_path_sep)%$name%(?:$_path_sep|$)//g) {
    $out .= qq{\@if not "%$name%"=="" set "$name=$value"\n};
    $out .= qq{\@if "%$name%"=="" };
  }
  $out .= qq{\@set "$name=$value_without"\n};
  return $out;
}

sub build_powershell_env_declaration {
  my ($class, $name, $args) = @_;
  my $value = $class->_interpolate($args, '$env:%s', qr/["\$]/, '`%s');

  if (!$value) {
    return qq{Remove-Item -ErrorAction 0 Env:\\$name;\n};
  }

  my $maybe_path_sep = qq{\$(if("\$env:$name"-eq""){""}else{"$_path_sep"})};
  $value =~ s/(^|\G|$_path_sep)\$env:$name$_path_sep/$1\$env:$name"+$maybe_path_sep+"/g;
  $value =~ s/$_path_sep\$env:$name$/"+$maybe_path_sep+\$env:$name+"/;

  qq{\$env:$name = \$("$value");\n};
}
sub wrap_powershell_output {
  my ($class, $out) = @_;
  return $out || " \n";
}

sub build_fish_env_declaration {
  my ($class, $name, $args) = @_;
  my $value = $class->_interpolate($args, '$%s', qr/[\\"'$ ]/, '\\%s');
  if (!defined $value) {
    return qq{set -e $name;\n};
  }

  # fish has special handling for PATH, CDPATH, and MANPATH.  They are always
  # treated as arrays, and joined with ; when storing the environment.  Other
  # env vars can be arrays, but will be joined without a separator.  We only
  # really care about PATH, but might as well make this routine more general.
  if ($name =~ /^(?:CD|MAN)?PATH$/) {
    $value =~ s/$_path_sep/ /g;
    my $silent = $name =~ /^(?:CD)?PATH$/ ? " 2>"._devnull : '';
    return qq{set -x $name $value$silent;\n};
  }

  my $out = '';
  my $value_without = $value;
  if ($value_without =~ s/(?:^|$_path_sep)\$$name(?:$_path_sep|$)//g) {
    $out .= qq{set -q $name; and set -x $name $value;\n};
    $out .= qq{set -q $name; or };
  }
  $out .= qq{set -x $name $value_without;\n};
  $out;
}

sub _interpolate {
  my ($class, $args, $var_pat, $escape, $escape_pat) = @_;
  return
    unless defined $args;
  my @args = ref $args ? @$args : $args;
  return
    unless @args;
  my @vars = map { $$_ } grep { ref $_ eq 'SCALAR' } @args;
  my $string = join $_path_sep, map {
    ref $_ eq 'SCALAR' ? sprintf($var_pat, $$_) : do {
      s/($escape)/sprintf($escape_pat, $1)/ge; $_;
    };
  } @args;
  return wantarray ? ($string, \@vars) : $string;
}

sub pipeline;

sub pipeline {
  my @methods = @_;
  my $last = pop(@methods);
  if (@methods) {
    \sub {
      my ($obj, @args) = @_;
      $obj->${pipeline @methods}(
        $obj->$last(@args)
      );
    };
  } else {
    \sub {
      shift->$last(@_);
    };
  }
}

sub resolve_path {
  my ($class, $path) = @_;

  $path = $class->${pipeline qw(
    resolve_relative_path
    resolve_home_path
    resolve_empty_path
  )}($path);

  $path;
}

sub resolve_empty_path {
  my ($class, $path) = @_;
  if (defined $path) {
    $path;
  } else {
    '~/perl5';
  }
}

sub resolve_home_path {
  my ($class, $path) = @_;
  $path =~ /^~([^\/]*)/ or return $path;
  my $user = $1;
  my $homedir = do {
    if (! length($user) && defined $ENV{HOME}) {
      $ENV{HOME};
    }
    else {
      require File::Glob;
      File::Glob::bsd_glob("~$user", File::Glob::GLOB_TILDE());
    }
  };
  unless (defined $homedir) {
    require Carp; require Carp::Heavy;
    Carp::croak(
      "Couldn't resolve homedir for "
      .(defined $user ? $user : 'current user')
    );
  }
  $path =~ s/^~[^\/]*/$homedir/;
  $path;
}

sub resolve_relative_path {
  my ($class, $path) = @_;
  _rel2abs($path);
}

sub ensure_dir_structure_for {
  my ($class, $path, $opts) = @_;
  $opts ||= {};
  my @dirs;
  foreach my $dir (
    $class->lib_paths_for($path),
    $class->install_base_bin_path($path),
  ) {
    my $d = $dir;
    while (!-d $d) {
      push @dirs, $d;
      require File::Basename;
      $d = File::Basename::dirname($d);
    }
  }

  warn "Attempting to create directory ${path}\n"
    if !$opts->{quiet} && @dirs;

  my %seen;
  foreach my $dir (reverse @dirs) {
    next
      if $seen{$dir}++;

    mkdir $dir
      or -d $dir
      or die "Unable to create $dir: $!"
  }
  return;
}

sub guess_shelltype {
  my $shellbin
    = defined $ENV{SHELL} && length $ENV{SHELL}
      ? ($ENV{SHELL} =~ /([\w.]+)$/)[-1]
    : ( $^O eq 'MSWin32' && exists $ENV{'!EXITCODE'} )
      ? 'bash'
    : ( $^O eq 'MSWin32' && $ENV{PROMPT} && $ENV{COMSPEC} )
      ? ($ENV{COMSPEC} =~ /([\w.]+)$/)[-1]
    : ( $^O eq 'MSWin32' && !$ENV{PROMPT} )
      ? 'powershell.exe'
    : 'sh';

  for ($shellbin) {
    return
        /csh$/                   ? 'csh'
      : /fish$/                  ? 'fish'
      : /command(?:\.com)?$/i    ? 'cmd'
      : /cmd(?:\.exe)?$/i        ? 'cmd'
      : /4nt(?:\.exe)?$/i        ? 'cmd'
      : /powershell(?:\.exe)?$/i ? 'powershell'
                                 : 'bourne';
  }
}

1;
__END__

=encoding utf8

=head1 NAME

local::lib - create and use a local lib/ for perl modules with PERL5LIB

=head1 SYNOPSIS

In code -

  use local::lib; # sets up a local lib at ~/perl5

  use local::lib '~/foo'; # same, but ~/foo

  # Or...
  use FindBin;
  use local::lib "$FindBin::Bin/../support";  # app-local support library

From the shell -

  # Install LWP and its missing dependencies to the '~/perl5' directory
  perl -MCPAN -Mlocal::lib -e 'CPAN::install(LWP)'

  # Just print out useful shell commands
  $ perl -Mlocal::lib
  PERL_MB_OPT='--install_base /home/username/perl5'; export PERL_MB_OPT;
  PERL_MM_OPT='INSTALL_BASE=/home/username/perl5'; export PERL_MM_OPT;
  PERL5LIB="/home/username/perl5/lib/perl5"; export PERL5LIB;
  PATH="/home/username/perl5/bin:$PATH"; export PATH;
  PERL_LOCAL_LIB_ROOT="/home/usename/perl5:$PERL_LOCAL_LIB_ROOT"; export PERL_LOCAL_LIB_ROOT;

From a F<.bash_profile> or F<.bashrc> file -

  eval "$(perl -I$HOME/perl5/lib/perl5 -Mlocal::lib)"

=head2 The bootstrapping technique

A typical way to install local::lib is using what is known as the
"bootstrapping" technique.  You would do this if your system administrator
hasn't already installed local::lib.  In this case, you'll need to install
local::lib in your home directory.

Even if you do have administrative privileges, you will still want to set up your
environment variables, as discussed in step 4. Without this, you would still
install the modules into the system CPAN installation and also your Perl scripts
will not use the lib/ path you bootstrapped with local::lib.

By default local::lib installs itself and the CPAN modules into ~/perl5.

Windows users must also see L</Differences when using this module under Win32>.

=over 4

=item 1.

Download and unpack the local::lib tarball from CPAN (search for "Download"
on the CPAN page about local::lib).  Do this as an ordinary user, not as root
or administrator.  Unpack the file in your home directory or in any other
convenient location.

=item 2.

Run this:

  perl Makefile.PL --bootstrap

If the system asks you whether it should automatically configure as much
as possible, you would typically answer yes.

=item 3.

Run this: (local::lib assumes you have make installed on your system)

  make test && make install

=item 4.

Now we need to setup the appropriate environment variables, so that Perl
starts using our newly generated lib/ directory. If you are using bash or
any other Bourne shells, you can add this to your shell startup script this
way:

  echo 'eval "$(perl -I$HOME/perl5/lib/perl5 -Mlocal::lib)"' >>~/.bashrc

If you are using C shell, you can do this as follows:

  % echo $SHELL
  /bin/csh
  $ echo 'eval `perl -I$HOME/perl5/lib/perl5 -Mlocal::lib`' >> ~/.cshrc

After writing your shell configuration file, be sure to re-read it to get the
changed settings into your current shell's environment. Bourne shells use
C<. ~/.bashrc> for this, whereas C shells use C<source ~/.cshrc>.

=back

=head3 Bootstrapping into an alternate directory

In order to install local::lib into a directory other than the default, you need
to specify the name of the directory when you call bootstrap.  Then, when
setting up the environment variables, both perl and local::lib must be told the
location of the bootstrap directory.  The setup process would look as follows:

  perl Makefile.PL --bootstrap=~/foo
  make test && make install
  echo 'eval "$(perl -I$HOME/foo/lib/perl5 -Mlocal::lib=$HOME/foo)"' >>~/.bashrc
  . ~/.bashrc

=head3 Other bootstrapping options

If you're on a slower machine, or are operating under draconian disk space
limitations, you can disable the automatic generation of manpages from POD when
installing modules by using the C<--no-manpages> argument when bootstrapping:

  perl Makefile.PL --bootstrap --no-manpages

To avoid doing several bootstrap for several Perl module environments on the
same account, for example if you use it for several different deployed
applications independently, you can use one bootstrapped local::lib
installation to install modules in different directories directly this way:

  cd ~/mydir1
  perl -Mlocal::lib=./
  eval $(perl -Mlocal::lib=./)  ### To set the environment for this shell alone
  printenv                      ### You will see that ~/mydir1 is in the PERL5LIB
  perl -MCPAN -e install ...    ### whatever modules you want
  cd ../mydir2
  ... REPEAT ...

If you use F<.bashrc> to activate a local::lib automatically, the local::lib
will be re-enabled in any sub-shells used, overriding adjustments you may have
made in the parent shell.  To avoid this, you can initialize the local::lib in
F<.bash_profile> rather than F<.bashrc>, or protect the local::lib invocation
with a C<$SHLVL> check:

  [ $SHLVL -eq 1 ] && eval "$(perl -I$HOME/perl5/lib/perl5 -Mlocal::lib)"

If you are working with several C<local::lib> environments, you may want to
remove some of them from the current environment without disturbing the others.
You can deactivate one environment like this (using bourne sh):

  eval $(perl -Mlocal::lib=--deactivate,~/path)

which will generate and run the commands needed to remove C<~/path> from your
various search paths. Whichever environment was B<activated most recently> will
remain the target for module installations. That is, if you activate
C<~/path_A> and then you activate C<~/path_B>, new modules you install will go
in C<~/path_B>. If you deactivate C<~/path_B> then modules will be installed
into C<~/pathA> -- but if you deactivate C<~/path_A> then they will still be
installed in C<~/pathB> because pathB was activated later.

You can also ask C<local::lib> to clean itself completely out of the current
shell's environment with the C<--deactivate-all> option.
For multiple environments for multiple apps you may need to include a modified
version of the C<< use FindBin >> instructions in the "In code" sample above.
If you did something like the above, you have a set of Perl modules at C<<
~/mydir1/lib >>. If you have a script at C<< ~/mydir1/scripts/myscript.pl >>,
you need to tell it where to find the modules you installed for it at C<<
~/mydir1/lib >>.

In C<< ~/mydir1/scripts/myscript.pl >>:

  use strict;
  use warnings;
  use local::lib "$FindBin::Bin/..";  ### points to ~/mydir1 and local::lib finds lib
  use lib "$FindBin::Bin/../lib";     ### points to ~/mydir1/lib

Put this before any BEGIN { ... } blocks that require the modules you installed.

=head2 Differences when using this module under Win32

To set up the proper environment variables for your current session of
C<CMD.exe>, you can use this:

  C:\>perl -Mlocal::lib
  set PERL_MB_OPT=--install_base C:\DOCUME~1\ADMINI~1\perl5
  set PERL_MM_OPT=INSTALL_BASE=C:\DOCUME~1\ADMINI~1\perl5
  set PERL5LIB=C:\DOCUME~1\ADMINI~1\perl5\lib\perl5
  set PATH=C:\DOCUME~1\ADMINI~1\perl5\bin;%PATH%

  ### To set the environment for this shell alone
  C:\>perl -Mlocal::lib > %TEMP%\tmp.bat && %TEMP%\tmp.bat && del %TEMP%\tmp.bat
  ### instead of $(perl -Mlocal::lib=./)

If you want the environment entries to persist, you'll need to add them to the
Control Panel's System applet yourself or use L<App::local::lib::Win32Helper>.

The "~" is translated to the user's profile directory (the directory named for
the user under "Documents and Settings" (Windows XP or earlier) or "Users"
(Windows Vista or later)) unless $ENV{HOME} exists. After that, the home
directory is translated to a short name (which means the directory must exist)
and the subdirectories are created.

=head3 PowerShell

local::lib also supports PowerShell, and can be used with the
C<Invoke-Expression> cmdlet.

  Invoke-Expression "$(perl -Mlocal::lib)"

=head1 RATIONALE

The version of a Perl package on your machine is not always the version you
need.  Obviously, the best thing to do would be to update to the version you
need.  However, you might be in a situation where you're prevented from doing
this.  Perhaps you don't have system administrator privileges; or perhaps you
are using a package management system such as Debian, and nobody has yet gotten
around to packaging up the version you need.

local::lib solves this problem by allowing you to create your own directory of
Perl packages downloaded from CPAN (in a multi-user system, this would typically
be within your own home directory).  The existing system Perl installation is
not affected; you simply invoke Perl with special options so that Perl uses the
packages in your own local package directory rather than the system packages.
local::lib arranges things so that your locally installed version of the Perl
packages takes precedence over the system installation.

If you are using a package management system (such as Debian), you don't need to
worry about Debian and CPAN stepping on each other's toes.  Your local version
of the packages will be written to an entirely separate directory from those
installed by Debian.

=head1 DESCRIPTION

This module provides a quick, convenient way of bootstrapping a user-local Perl
module library located within the user's home directory. It also constructs and
prints out for the user the list of environment variables using the syntax
appropriate for the user's current shell (as specified by the C<SHELL>
environment variable), suitable for directly adding to one's shell
configuration file.

More generally, local::lib allows for the bootstrapping and usage of a
directory containing Perl modules outside of Perl's C<@INC>. This makes it
easier to ship an application with an app-specific copy of a Perl module, or
collection of modules. Useful in cases like when an upstream maintainer hasn't
applied a patch to a module of theirs that you need for your application.

On import, local::lib sets the following environment variables to appropriate
values:

=over 4

=item PERL_MB_OPT

=item PERL_MM_OPT

=item PERL5LIB

=item PATH

=item PERL_LOCAL_LIB_ROOT

=back

When possible, these will be appended to instead of overwritten entirely.

These values are then available for reference by any code after import.

=head1 CREATING A SELF-CONTAINED SET OF MODULES

See L<lib::core::only> for one way to do this - but note that
there are a number of caveats, and the best approach is always to perform a
build against a clean perl (i.e. site and vendor as close to empty as possible).

=head1 IMPORT OPTIONS

Options are values that can be passed to the C<local::lib> import besides the
directory to use. They are specified as C<use local::lib '--option'[, path];>
or C<perl -Mlocal::lib=--option[,path]>.

=head2 --deactivate

Remove the chosen path (or the default path) from the module search paths if it
was added by C<local::lib>, instead of adding it.

=head2 --deactivate-all

Remove all directories that were added to search paths by C<local::lib> from the
search paths.

=head2 --quiet

Don't output any messages about directories being created.

=head2 --always

Always add directories to environment variables, ignoring if they are already
included.

=head2 --shelltype

Specify the shell type to use for output.  By default, the shell will be
detected based on the environment.  Should be one of: C<bourne>, C<csh>,
C<cmd>, or C<powershell>.

=head2 --no-create

Prevents C<local::lib> from creating directories when activating dirs.  This is
likely to cause issues on Win32 systems.

=head1 CLASS METHODS

=head2 ensure_dir_structure_for

=over 4

=item Arguments: $path

=item Return value: None

=back

Attempts to create a local::lib directory, including subdirectories and all
required parent directories. Throws an exception on failure.

=head2 print_environment_vars_for

=over 4

=item Arguments: $path

=item Return value: None

=back

Prints to standard output the variables listed above, properly set to use the
given path as the base directory.

=head2 build_environment_vars_for

=over 4

=item Arguments: $path

=item Return value: %environment_vars

=back

Returns a hash with the variables listed above, properly set to use the
given path as the base directory.

=head2 setup_env_hash_for

=over 4

=item Arguments: $path

=item Return value: None

=back

Constructs the C<%ENV> keys for the given path, by calling
L</build_environment_vars_for>.

=head2 active_paths

=over 4

=item Arguments: None

=item Return value: @paths

=back

Returns a list of active C<local::lib> paths, according to the
C<PERL_LOCAL_LIB_ROOT> environment variable and verified against
what is really in C<@INC>.

=head2 install_base_perl_path

=over 4

=item Arguments: $path

=item Return value: $install_base_perl_path

=back

Returns a path describing where to install the Perl modules for this local
library installation. Appends the directories C<lib> and C<perl5> to the given
path.

=head2 lib_paths_for

=over 4

=item Arguments: $path

=item Return value: @lib_paths

=back

Returns the list of paths perl will search for libraries, given a base path.
This includes the base path itself, the architecture specific subdirectory, and
perl version specific subdirectories.  These paths may not all exist.

=head2 install_base_bin_path

=over 4

=item Arguments: $path

=item Return value: $install_base_bin_path

=back

Returns a path describing where to install the executable programs for this
local library installation. Appends the directory C<bin> to the given path.

=head2 installer_options_for

=over 4

=item Arguments: $path

=item Return value: %installer_env_vars

=back

Returns a hash of environment variables that should be set to cause
installation into the given path.

=head2 resolve_empty_path

=over 4

=item Arguments: $path

=item Return value: $base_path

=back

Builds and returns the base path into which to set up the local module
installation. Defaults to C<~/perl5>.

=head2 resolve_home_path

=over 4

=item Arguments: $path

=item Return value: $home_path

=back

Attempts to find the user's home directory.
If no definite answer is available, throws an exception.

=head2 resolve_relative_path

=over 4

=item Arguments: $path

=item Return value: $absolute_path

=back

Translates the given path into an absolute path.

=head2 resolve_path

=over 4

=item Arguments: $path

=item Return value: $absolute_path

=back

Calls the following in a pipeline, passing the result from the previous to the
next, in an attempt to find where to configure the environment for a local
library installation: L</resolve_empty_path>, L</resolve_home_path>,
L</resolve_relative_path>. Passes the given path argument to
L</resolve_empty_path> which then returns a result that is passed to
L</resolve_home_path>, which then has its result passed to
L</resolve_relative_path>. The result of this final call is returned from
L</resolve_path>.

=head1 OBJECT INTERFACE

=head2 new

=over 4

=item Arguments: %attributes

=item Return value: $local_lib

=back

Constructs a new C<local::lib> object, representing the current state of
C<@INC> and the relevant environment variables.

=head1 ATTRIBUTES

=head2 roots

An arrayref representing active C<local::lib> directories.

=head2 inc

An arrayref representing C<@INC>.

=head2 libs

An arrayref representing the PERL5LIB environment variable.

=head2 bins

An arrayref representing the PATH environment variable.

=head2 extra

A hashref of extra environment variables (e.g. C<PERL_MM_OPT> and
C<PERL_MB_OPT>)

=head2 no_create

If set, C<local::lib> will not try to create directories when activating them.

=head1 OBJECT METHODS

=head2 clone

=over 4

=item Arguments: %attributes

=item Return value: $local_lib

=back

Constructs a new C<local::lib> object based on the existing one, overriding the
specified attributes.

=head2 activate

=over 4

=item Arguments: $path

=item Return value: $new_local_lib

=back

Constructs a new instance with the specified path active.

=head2 deactivate

=over 4

=item Arguments: $path

=item Return value: $new_local_lib

=back

Constructs a new instance with the specified path deactivated.

=head2 deactivate_all

=over 4

=item Arguments: None

=item Return value: $new_local_lib

=back

Constructs a new instance with all C<local::lib> directories deactivated.

=head2 environment_vars_string

=over 4

=item Arguments: [ $shelltype ]

=item Return value: $shell_env_string

=back

Returns a string to set up the C<local::lib>, meant to be run by a shell.

=head2 build_environment_vars

=over 4

=item Arguments: None

=item Return value: %environment_vars

=back

Returns a hash with the variables listed above, properly set to use the
given path as the base directory.

=head2 setup_env_hash

=over 4

=item Arguments: None

=item Return value: None

=back

Constructs the C<%ENV> keys for the given path, by calling
L</build_environment_vars>.

=head2 setup_local_lib

Constructs the C<%ENV> hash using L</setup_env_hash>, and set up C<@INC>.

=head1 A WARNING ABOUT UNINST=1

Be careful about using local::lib in combination with "make install UNINST=1".
The idea of this feature is that will uninstall an old version of a module
before installing a new one. However it lacks a safety check that the old
version and the new version will go in the same directory. Used in combination
with local::lib, you can potentially delete a globally accessible version of a
module while installing the new version in a local place. Only combine "make
install UNINST=1" and local::lib if you understand these possible consequences.

=head1 LIMITATIONS

=over 4

=item * Directory names with spaces in them are not well supported by the perl
toolchain and the programs it uses.  Pure-perl distributions should support
spaces, but problems are more likely with dists that require compilation. A
workaround you can do is moving your local::lib to a directory with spaces
B<after> you installed all modules inside your local::lib bootstrap. But be
aware that you can't update or install CPAN modules after the move.

=item * Rather basic shell detection. Right now anything with csh in its name is
assumed to be a C shell or something compatible, and everything else is assumed
to be Bourne, except on Win32 systems. If the C<SHELL> environment variable is
not set, a Bourne-compatible shell is assumed.

=item * Kills any existing PERL_MM_OPT or PERL_MB_OPT.

=item * Should probably auto-fixup CPAN config if not already done.

=item * On VMS and MacOS Classic (pre-OS X), local::lib loads L<File::Spec>.
This means any L<File::Spec> version installed in the local::lib will be
ignored by scripts using local::lib.  A workaround for this is using
C<use lib "$local_lib/lib/perl5";> instead of using C<local::lib> directly.

=item * Conflicts with L<ExtUtils::MakeMaker>'s C<PREFIX> option.
C<local::lib> uses the C<INSTALL_BASE> option, as it has more predictable and
sane behavior.  If something attempts to use the C<PREFIX> option when running
a F<Makefile.PL>, L<ExtUtils::MakeMaker> will refuse to run, as the two
options conflict.  This can be worked around by temporarily unsetting the
C<PERL_MM_OPT> environment variable.

=item * Conflicts with L<Module::Build>'s C<--prefix> option.  Similar to the
previous limitation, but any C<--prefix> option specified will be ignored.
This can be worked around by temporarily unsetting the C<PERL_MB_OPT>
environment variable.

=back

Patches very much welcome for any of the above.

=over 4

=item * On Win32 systems, does not have a way to write the created environment
variables to the registry, so that they can persist through a reboot.

=back

=head1 TROUBLESHOOTING

If you've configured local::lib to install CPAN modules somewhere in to your
home directory, and at some point later you try to install a module with C<cpan
-i Foo::Bar>, but it fails with an error like: C<Warning: You do not have
permissions to install into /usr/lib64/perl5/site_perl/5.8.8/x86_64-linux at
/usr/lib64/perl5/5.8.8/Foo/Bar.pm> and buried within the install log is an
error saying C<'INSTALL_BASE' is not a known MakeMaker parameter name>, then
you've somehow lost your updated ExtUtils::MakeMaker module.

To remedy this situation, rerun the bootstrapping procedure documented above.

Then, run C<rm -r ~/.cpan/build/Foo-Bar*>

Finally, re-run C<cpan -i Foo::Bar> and it should install without problems.

=head1 ENVIRONMENT

=over 4

=item SHELL

=item COMSPEC

local::lib looks at the user's C<SHELL> environment variable when printing out
commands to add to the shell configuration file.

On Win32 systems, C<COMSPEC> is also examined.

=back

=head1 SEE ALSO

=over 4

=item * L<Perl Advent article, 2011|http://perladvent.org/2011/2011-12-01.html>

=back

=head1 SUPPORT

IRC:

    Join #toolchain on irc.perl.org.

=head1 AUTHOR

Matt S Trout <mst@shadowcat.co.uk> http://www.shadowcat.co.uk/

auto_install fixes kindly sponsored by http://www.takkle.com/

=head1 CONTRIBUTORS

Patches to correctly output commands for csh style shells, as well as some
documentation additions, contributed by Christopher Nehren <apeiron@cpan.org>.

Doc patches for a custom local::lib directory, more cleanups in the english
documentation and a L<german documentation|POD2::DE::local::lib> contributed by
Torsten Raudssus <torsten@raudssus.de>.

Hans Dieter Pearcey <hdp@cpan.org> sent in some additional tests for ensuring
things will install properly, submitted a fix for the bug causing problems with
writing Makefiles during bootstrapping, contributed an example program, and
submitted yet another fix to ensure that local::lib can install and bootstrap
properly. Many, many thanks!

pattern of Freenode IRC contributed the beginnings of the Troubleshooting
section. Many thanks!

Patch to add Win32 support contributed by Curtis Jewell <csjewell@cpan.org>.

Warnings for missing PATH/PERL5LIB (as when not running interactively) silenced
by a patch from Marco Emilio Poleggi.

Mark Stosberg <mark@summersault.com> provided the code for the now deleted
'--self-contained' option.

Documentation patches to make win32 usage clearer by
David Mertens <dcmertens.perl@gmail.com> (run4flat).

Brazilian L<portuguese translation|POD2::PT_BR::local::lib> and minor doc
patches contributed by Breno G. de Oliveira <garu@cpan.org>.

Improvements to stacking multiple local::lib dirs and removing them from the
environment later on contributed by Andrew Rodland <arodland@cpan.org>.

Patch for Carp version mismatch contributed by Hakim Cassimally
<osfameron@cpan.org>.

Rewrite of internals and numerous bug fixes and added features contributed by
Graham Knop <haarg@haarg.org>.

=head1 COPYRIGHT

Copyright (c) 2007 - 2013 the local::lib L</AUTHOR> and L</CONTRIBUTORS> as
listed above.

=head1 LICENSE

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

=cut
PK1N%[UD��Nperl5/x86_64-linux-thread-multi/.meta/LWP-UserAgent-DNS-Hosts-0.14/MYMETA.jsonnu��6�${
   "abstract" : "Override LWP HTTP/HTTPS request's host like /etc/hosts",
   "author" : [
      "NAKAGAWA Masaki <masaki@cpan.org>"
   ],
   "dynamic_config" : 0,
   "generated_by" : "Minilla/v3.1.10, CPAN::Meta::Converter version 2.150010",
   "license" : [
      "perl_5"
   ],
   "meta-spec" : {
      "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
      "version" : 2
   },
   "name" : "LWP-UserAgent-DNS-Hosts",
   "no_index" : {
      "directory" : [
         "t",
         "xt",
         "inc",
         "share",
         "eg",
         "examples",
         "author",
         "builder"
      ]
   },
   "optional_features" : {
      "https" : {
         "description" : "SSL support",
         "prereqs" : {
            "runtime" : {
               "recommends" : {
                  "LWP::Protocol::https" : "0"
               }
            },
            "test" : {
               "requires" : {
                  "HTTP::Daemon::SSL" : "0"
               }
            }
         }
      }
   },
   "prereqs" : {
      "configure" : {
         "requires" : {
            "Module::Build::Tiny" : "0.035"
         }
      },
      "develop" : {
         "requires" : {
            "Test::CPAN::Meta" : "0",
            "Test::MinimumVersion::Fast" : "0.04",
            "Test::PAUSE::Permissions" : "0.07",
            "Test::Pod" : "1.41",
            "Test::Spellunker" : "v0.2.7"
         }
      },
      "runtime" : {
         "requires" : {
            "LWP::Protocol" : "0",
            "LWP::Protocol::http" : "0",
            "Scope::Guard" : "0",
            "parent" : "0",
            "perl" : "5.008001"
         }
      },
      "test" : {
         "requires" : {
            "File::Temp" : "0",
            "LWP::UserAgent" : "0",
            "Test::Fake::HTTPD" : "0.08",
            "Test::More" : "0.98",
            "Test::UseAllModules" : "0"
         }
      }
   },
   "provides" : {
      "LWP::Protocol::http::hosts" : {
         "file" : "lib/LWP/Protocol/http/hosts.pm"
      },
      "LWP::Protocol::https::hosts" : {
         "file" : "lib/LWP/Protocol/https/hosts.pm"
      },
      "LWP::UserAgent::DNS::Hosts" : {
         "file" : "lib/LWP/UserAgent/DNS/Hosts.pm",
         "version" : "0.14"
      }
   },
   "release_status" : "stable",
   "resources" : {
      "bugtracker" : {
         "web" : "https://github.com/masaki/p5-LWP-UserAgent-DNS-Hosts/issues"
      },
      "homepage" : "https://github.com/masaki/p5-LWP-UserAgent-DNS-Hosts",
      "repository" : {
         "type" : "git",
         "url" : "git://github.com/masaki/p5-LWP-UserAgent-DNS-Hosts.git",
         "web" : "https://github.com/masaki/p5-LWP-UserAgent-DNS-Hosts"
      }
   },
   "version" : "0.14",
   "x_authority" : "cpan:MASAKI",
   "x_contributors" : [
      "Anirvan Chatterjee <anirvan@users.noreply.github.com>",
      "Masaki Nakagawa <masaki.nakagawa@gmail.com>",
      "Petr Písař <ppisar@redhat.com>",
      "Tatsuhiko Miyagawa <miyagawa@bulknews.net>"
   ],
   "x_serialization_backend" : "JSON::PP version 2.97001",
   "x_static_install" : 1
}
PK1N%[�
�ٴ�Operl5/x86_64-linux-thread-multi/.meta/LWP-UserAgent-DNS-Hosts-0.14/install.jsonnu��6�${"pathname":"M/MA/MASAKI/LWP-UserAgent-DNS-Hosts-0.14.tar.gz","dist":"LWP-UserAgent-DNS-Hosts-0.14","name":"LWP::UserAgent::DNS::Hosts","version":"0.14","target":"LWP::UserAgent::DNS::Hosts","provides":{"LWP::UserAgent::DNS::Hosts":{"file":"lib/LWP/UserAgent/DNS/Hosts.pm","version":"0.14"},"LWP::Protocol::http::hosts":{"file":"lib/LWP/Protocol/http/hosts.pm"},"LWP::Protocol::https::hosts":{"file":"lib/LWP/Protocol/https/hosts.pm"}}}PK1N%[P��U??Cperl5/x86_64-linux-thread-multi/.meta/common-sense-3.75/MYMETA.jsonnu��6�${
   "abstract" : "unknown",
   "author" : [
      "unknown"
   ],
   "dynamic_config" : 0,
   "generated_by" : "ExtUtils::MakeMaker version 7.34, CPAN::Meta::Converter version 2.150001, CPAN::Meta::Converter version 2.150010",
   "license" : [
      "unknown"
   ],
   "meta-spec" : {
      "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
      "version" : 2
   },
   "name" : "common-sense",
   "no_index" : {
      "directory" : [
         "t",
         "inc"
      ]
   },
   "prereqs" : {
      "build" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "configure" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      }
   },
   "release_status" : "stable",
   "version" : 3.75,
   "x_serialization_backend" : "JSON::PP version 2.97001"
}
PK1N%[�*��Dperl5/x86_64-linux-thread-multi/.meta/common-sense-3.75/install.jsonnu��6�${"name":"common::sense","dist":"common-sense-3.75","version":3.75,"target":"common::sense","provides":{"common::sense":{"file":"sense.pm.PL","version":3.75}},"pathname":"M/ML/MLEHMANN/common-sense-3.75.tar.gz"}PK1N%[Q^����@perl5/x86_64-linux-thread-multi/.meta/YAML-Syck-1.34/MYMETA.jsonnu��6�${
   "abstract" : "Fast, lightweight YAML loader and dumper",
   "author" : [
      "Todd Rinaldo <toddr@cpan.org>"
   ],
   "dynamic_config" : 0,
   "generated_by" : "ExtUtils::MakeMaker version 7.44, CPAN::Meta::Converter version 2.150010",
   "license" : [
      "mit"
   ],
   "meta-spec" : {
      "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
      "version" : 2
   },
   "name" : "YAML-Syck",
   "no_index" : {
      "directory" : [
         "t",
         "inc"
      ]
   },
   "prereqs" : {
      "build" : {
         "requires" : {
            "Test::More" : "0"
         }
      },
      "configure" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "runtime" : {
         "requires" : {
            "perl" : "5.006"
         }
      }
   },
   "release_status" : "stable",
   "resources" : {
      "bugtracker" : {
         "web" : "https://github.com/toddr/YAML-Syck/issues"
      },
      "homepage" : "http://github.com/toddr/YAML-Syck",
      "license" : [
         "http://dev.perl.org/licenses/"
      ],
      "repository" : {
         "url" : "http://github.com/toddr/YAML-Syck"
      }
   },
   "version" : "1.34",
   "x_serialization_backend" : "JSON::PP version 2.97001"
}
PK1N%[ˊo�mmAperl5/x86_64-linux-thread-multi/.meta/YAML-Syck-1.34/install.jsonnu��6�${"name":"YAML::Syck","dist":"YAML-Syck-1.34","version":1.34,"target":"YAML::Syck","provides":{"YAML::Syck":{"version":1.34,"file":"lib/YAML/Syck.pm"},"YAML::Loader::Syck":{"file":"lib/YAML/Loader/Syck.pm"},"JSON::Syck":{"file":"lib/JSON/Syck.pm","version":1.34},"YAML::Dumper::Syck":{"file":"lib/YAML/Dumper/Syck.pm"}},"pathname":"T/TO/TODDR/YAML-Syck-1.34.tar.gz"}PK1N%[I~�UoUoCperl5/x86_64-linux-thread-multi/.meta/HTTP-Cookies-6.11/MYMETA.jsonnu��6�${
   "abstract" : "HTTP cookie jars",
   "author" : [
      "Gisle Aas <gisle@activestate.com>"
   ],
   "dynamic_config" : 0,
   "generated_by" : "Dist::Zilla version 6.031, CPAN::Meta::Converter version 2.150010",
   "license" : [
      "perl_5"
   ],
   "meta-spec" : {
      "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
      "version" : 2
   },
   "name" : "HTTP-Cookies",
   "no_index" : {
      "directory" : [
         "examples",
         "t",
         "xt"
      ]
   },
   "prereqs" : {
      "build" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "configure" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "develop" : {
         "requires" : {
            "Pod::Coverage::TrustPod" : "0",
            "Test::CPAN::Changes" : "0.19",
            "Test::EOL" : "0",
            "Test::Mojibake" : "0",
            "Test::More" : "0.96",
            "Test::Pod" : "1.41",
            "Test::Pod::Coverage" : "1.08",
            "Test::Portability::Files" : "0",
            "Test::Version" : "1",
            "warnings" : "0"
         }
      },
      "runtime" : {
         "requires" : {
            "Carp" : "0",
            "HTTP::Date" : "6",
            "HTTP::Headers::Util" : "6",
            "HTTP::Request" : "0",
            "locale" : "0",
            "perl" : "5.008001",
            "strict" : "0"
         }
      },
      "test" : {
         "recommends" : {
            "CPAN::Meta" : "2.120900"
         },
         "requires" : {
            "ExtUtils::MakeMaker" : "0",
            "File::Spec" : "0",
            "HTTP::Response" : "0",
            "Test::More" : "0",
            "URI" : "0",
            "warnings" : "0"
         }
      }
   },
   "release_status" : "stable",
   "resources" : {
      "bugtracker" : {
         "web" : "https://github.com/libwww-perl/HTTP-Cookies/issues"
      },
      "homepage" : "https://github.com/libwww-perl/HTTP-Cookies",
      "repository" : {
         "type" : "git",
         "url" : "https://github.com/libwww-perl/HTTP-Cookies.git",
         "web" : "https://github.com/libwww-perl/HTTP-Cookies"
      }
   },
   "version" : "6.11",
   "x_Dist_Zilla" : {
      "perl" : {
         "version" : "5.034000"
      },
      "plugins" : [
         {
            "class" : "Dist::Zilla::Plugin::Encoding",
            "name" : "Encoding",
            "version" : "6.031"
         },
         {
            "class" : "Dist::Zilla::Plugin::OSPrereqs",
            "config" : {
               "Dist::Zilla::Plugin::OSPrereqs" : {
                  "os" : "MSWin32"
               }
            },
            "name" : "MSWin32",
            "version" : "0.011"
         },
         {
            "class" : "Dist::Zilla::Plugin::AutoPrereqs",
            "name" : "AutoPrereqs",
            "version" : "6.031"
         },
         {
            "class" : "Dist::Zilla::Plugin::Prereqs",
            "config" : {
               "Dist::Zilla::Plugin::Prereqs" : {
                  "phase" : "runtime",
                  "type" : "requires"
               }
            },
            "name" : "Prereqs",
            "version" : "6.031"
         },
         {
            "class" : "Dist::Zilla::Plugin::PromptIfStale",
            "config" : {
               "Dist::Zilla::Plugin::PromptIfStale" : {
                  "check_all_plugins" : 0,
                  "check_all_prereqs" : 0,
                  "modules" : [
                     "Dist::Zilla::PluginBundle::Author::OALDERS"
                  ],
                  "phase" : "build",
                  "run_under_travis" : 0,
                  "skip" : []
               }
            },
            "name" : "@Author::OALDERS/stale modules, build",
            "version" : "0.058"
         },
         {
            "class" : "Dist::Zilla::Plugin::PromptIfStale",
            "config" : {
               "Dist::Zilla::Plugin::PromptIfStale" : {
                  "check_all_plugins" : 1,
                  "check_all_prereqs" : 1,
                  "modules" : [],
                  "phase" : "release",
                  "run_under_travis" : 0,
                  "skip" : []
               }
            },
            "name" : "@Author::OALDERS/stale modules, release",
            "version" : "0.058"
         },
         {
            "class" : "Dist::Zilla::Plugin::CheckChangesHasContent",
            "name" : "@Author::OALDERS/CheckChangesHasContent",
            "version" : "0.011"
         },
         {
            "class" : "Dist::Zilla::Plugin::MakeMaker",
            "config" : {
               "Dist::Zilla::Role::TestRunner" : {
                  "default_jobs" : "8"
               }
            },
            "name" : "@Author::OALDERS/MakeMaker",
            "version" : "6.031"
         },
         {
            "class" : "Dist::Zilla::Plugin::CPANFile",
            "name" : "@Author::OALDERS/CPANFile",
            "version" : "6.031"
         },
         {
            "class" : "Dist::Zilla::Plugin::ContributorsFile",
            "name" : "@Author::OALDERS/ContributorsFile",
            "version" : "0.3.0"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaJSON",
            "name" : "@Author::OALDERS/MetaJSON",
            "version" : "6.031"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaYAML",
            "name" : "@Author::OALDERS/MetaYAML",
            "version" : "6.031"
         },
         {
            "class" : "Dist::Zilla::Plugin::Manifest",
            "name" : "@Author::OALDERS/Manifest",
            "version" : "6.031"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaNoIndex",
            "name" : "@Author::OALDERS/MetaNoIndex",
            "version" : "6.031"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaConfig",
            "name" : "@Author::OALDERS/MetaConfig",
            "version" : "6.031"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaResources",
            "name" : "@Author::OALDERS/MetaResources",
            "version" : "6.031"
         },
         {
            "class" : "Dist::Zilla::Plugin::License",
            "name" : "@Author::OALDERS/License",
            "version" : "6.031"
         },
         {
            "class" : "Dist::Zilla::Plugin::InstallGuide",
            "config" : {
               "Dist::Zilla::Role::ModuleMetadata" : {
                  "Module::Metadata" : "1.000037",
                  "version" : "0.006"
               }
            },
            "name" : "@Author::OALDERS/InstallGuide",
            "version" : "1.200014"
         },
         {
            "class" : "Dist::Zilla::Plugin::ExecDir",
            "name" : "@Author::OALDERS/ExecDir",
            "version" : "6.031"
         },
         {
            "class" : "Dist::Zilla::Plugin::MojibakeTests",
            "name" : "@Author::OALDERS/MojibakeTests",
            "version" : "0.8"
         },
         {
            "class" : "Dist::Zilla::Plugin::PodSyntaxTests",
            "name" : "@Author::OALDERS/PodSyntaxTests",
            "version" : "6.031"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::CPAN::Changes",
            "config" : {
               "Dist::Zilla::Plugin::Test::CPAN::Changes" : {
                  "changelog" : "Changes"
               }
            },
            "name" : "@Author::OALDERS/Test::CPAN::Changes",
            "version" : "0.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::EOL",
            "config" : {
               "Dist::Zilla::Plugin::Test::EOL" : {
                  "filename" : "xt/author/eol.t",
                  "finder" : [
                     ":ExecFiles",
                     ":InstallModules",
                     ":TestFiles"
                  ],
                  "trailing_whitespace" : 1
               }
            },
            "name" : "@Author::OALDERS/Test::EOL",
            "version" : "0.19"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::Pod::Coverage::Configurable",
            "name" : "@Author::OALDERS/Test::Pod::Coverage::Configurable",
            "version" : "0.07"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::Portability",
            "config" : {
               "Dist::Zilla::Plugin::Test::Portability" : {
                  "options" : ""
               }
            },
            "name" : "@Author::OALDERS/Test::Portability",
            "version" : "2.001001"
         },
         {
            "class" : "Dist::Zilla::Plugin::TestRelease",
            "name" : "@Author::OALDERS/TestRelease",
            "version" : "6.031"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::ReportPrereqs",
            "name" : "@Author::OALDERS/Test::ReportPrereqs",
            "version" : "0.029"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::Version",
            "name" : "@Author::OALDERS/Test::Version",
            "version" : "1.09"
         },
         {
            "class" : "Dist::Zilla::Plugin::RunExtraTests",
            "config" : {
               "Dist::Zilla::Role::TestRunner" : {
                  "default_jobs" : "8"
               }
            },
            "name" : "@Author::OALDERS/RunExtraTests",
            "version" : "0.029"
         },
         {
            "class" : "Dist::Zilla::Plugin::PodWeaver",
            "config" : {
               "Dist::Zilla::Plugin::PodWeaver" : {
                  "finder" : [
                     ":InstallModules",
                     ":PerlExecFiles"
                  ],
                  "plugins" : [
                     {
                        "class" : "Pod::Weaver::Plugin::EnsurePod5",
                        "name" : "@CorePrep/EnsurePod5",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Plugin::H1Nester",
                        "name" : "@CorePrep/H1Nester",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Plugin::SingleEncoding",
                        "name" : "@Default/SingleEncoding",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Name",
                        "name" : "@Default/Name",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Version",
                        "name" : "@Default/Version",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Region",
                        "name" : "@Default/prelude",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Generic",
                        "name" : "SYNOPSIS",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Generic",
                        "name" : "DESCRIPTION",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Generic",
                        "name" : "OVERVIEW",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Collect",
                        "name" : "ATTRIBUTES",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Collect",
                        "name" : "METHODS",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Collect",
                        "name" : "FUNCTIONS",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Leftovers",
                        "name" : "@Default/Leftovers",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Region",
                        "name" : "@Default/postlude",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Authors",
                        "name" : "@Default/Authors",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Legal",
                        "name" : "@Default/Legal",
                        "version" : "4.019"
                     }
                  ]
               }
            },
            "name" : "@Author::OALDERS/PodWeaver",
            "version" : "4.010"
         },
         {
            "class" : "Dist::Zilla::Plugin::PruneCruft",
            "name" : "@Author::OALDERS/PruneCruft",
            "version" : "6.031"
         },
         {
            "class" : "Dist::Zilla::Plugin::CopyFilesFromBuild",
            "name" : "@Author::OALDERS/CopyFilesFromBuild",
            "version" : "0.170880"
         },
         {
            "class" : "Dist::Zilla::Plugin::GithubMeta",
            "name" : "@Author::OALDERS/GithubMeta",
            "version" : "0.58"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::GatherDir",
            "config" : {
               "Dist::Zilla::Plugin::GatherDir" : {
                  "exclude_filename" : [
                     "Install",
                     "LICENSE",
                     "META.json",
                     "Makefile.PL",
                     "README.md",
                     "cpanfile"
                  ],
                  "exclude_match" : [],
                  "follow_symlinks" : 0,
                  "include_dotfiles" : 0,
                  "prefix" : "",
                  "prune_directory" : [],
                  "root" : "."
               },
               "Dist::Zilla::Plugin::Git::GatherDir" : {
                  "include_untracked" : 0
               }
            },
            "name" : "@Author::OALDERS/Git::GatherDir",
            "version" : "2.048"
         },
         {
            "class" : "Dist::Zilla::Plugin::CopyFilesFromRelease",
            "config" : {
               "Dist::Zilla::Plugin::CopyFilesFromRelease" : {
                  "filename" : [
                     "Install"
                  ],
                  "match" : []
               }
            },
            "name" : "@Author::OALDERS/CopyFilesFromRelease",
            "version" : "0.007"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::Check",
            "config" : {
               "Dist::Zilla::Plugin::Git::Check" : {
                  "untracked_files" : "die"
               },
               "Dist::Zilla::Role::Git::DirtyFiles" : {
                  "allow_dirty" : [
                     "Changes",
                     "Install",
                     "LICENSE",
                     "META.json",
                     "Makefile.PL",
                     "README.md",
                     "cpanfile",
                     "dist.ini"
                  ],
                  "allow_dirty_match" : [],
                  "changelog" : "Changes"
               },
               "Dist::Zilla::Role::Git::Repo" : {
                  "git_version" : "2.34.1",
                  "repo_root" : "."
               }
            },
            "name" : "@Author::OALDERS/Git::Check",
            "version" : "2.048"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::Contributors",
            "config" : {
               "Dist::Zilla::Plugin::Git::Contributors" : {
                  "git_version" : "2.34.1",
                  "include_authors" : 0,
                  "include_releaser" : 1,
                  "order_by" : "name",
                  "paths" : []
               }
            },
            "name" : "@Author::OALDERS/Git::Contributors",
            "version" : "0.036"
         },
         {
            "class" : "Dist::Zilla::Plugin::ReadmeAnyFromPod",
            "config" : {
               "Dist::Zilla::Role::FileWatcher" : {
                  "version" : "0.006"
               }
            },
            "name" : "@Author::OALDERS/ReadmeMdInBuild",
            "version" : "0.163250"
         },
         {
            "class" : "Dist::Zilla::Plugin::StaticInstall",
            "config" : {
               "Dist::Zilla::Plugin::StaticInstall" : {
                  "dry_run" : 0,
                  "mode" : "off"
               }
            },
            "name" : "@Author::OALDERS/StaticInstall",
            "version" : "0.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::ShareDir",
            "name" : "@Author::OALDERS/ShareDir",
            "version" : "6.031"
         },
         {
            "class" : "Dist::Zilla::Plugin::CheckIssues",
            "name" : "@Author::OALDERS/CheckIssues",
            "version" : "0.011"
         },
         {
            "class" : "Dist::Zilla::Plugin::ConfirmRelease",
            "name" : "@Author::OALDERS/ConfirmRelease",
            "version" : "6.031"
         },
         {
            "class" : "Dist::Zilla::Plugin::UploadToCPAN",
            "name" : "@Author::OALDERS/UploadToCPAN",
            "version" : "6.031"
         },
         {
            "class" : "Dist::Zilla::Plugin::RewriteVersion::Transitional",
            "config" : {
               "Dist::Zilla::Plugin::RewriteVersion" : {
                  "add_tarball_name" : 0,
                  "finders" : [
                     ":ExecFiles",
                     ":InstallModules"
                  ],
                  "global" : 0,
                  "skip_version_provider" : 0
               },
               "Dist::Zilla::Plugin::RewriteVersion::Transitional" : {}
            },
            "name" : "@Author::OALDERS/@Git::VersionManager/RewriteVersion::Transitional",
            "version" : "0.009"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaProvides::Update",
            "name" : "@Author::OALDERS/@Git::VersionManager/MetaProvides::Update",
            "version" : "0.007"
         },
         {
            "class" : "Dist::Zilla::Plugin::CopyFilesFromRelease",
            "config" : {
               "Dist::Zilla::Plugin::CopyFilesFromRelease" : {
                  "filename" : [
                     "Changes"
                  ],
                  "match" : []
               }
            },
            "name" : "@Author::OALDERS/@Git::VersionManager/CopyFilesFromRelease",
            "version" : "0.007"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::Commit",
            "config" : {
               "Dist::Zilla::Plugin::Git::Commit" : {
                  "add_files_in" : [],
                  "commit_msg" : "v%V%n%n%c",
                  "signoff" : 0
               },
               "Dist::Zilla::Role::Git::DirtyFiles" : {
                  "allow_dirty" : [
                     "Changes",
                     "Install",
                     "LICENSE",
                     "META.json",
                     "Makefile.PL",
                     "README.md",
                     "cpanfile",
                     "dist.ini"
                  ],
                  "allow_dirty_match" : [],
                  "changelog" : "Changes"
               },
               "Dist::Zilla::Role::Git::Repo" : {
                  "git_version" : "2.34.1",
                  "repo_root" : "."
               },
               "Dist::Zilla::Role::Git::StringFormatter" : {
                  "time_zone" : "local"
               }
            },
            "name" : "@Author::OALDERS/@Git::VersionManager/release snapshot",
            "version" : "2.048"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::Tag",
            "config" : {
               "Dist::Zilla::Plugin::Git::Tag" : {
                  "branch" : null,
                  "changelog" : "Changes",
                  "signed" : 0,
                  "tag" : "v6.11",
                  "tag_format" : "v%V",
                  "tag_message" : "v%V"
               },
               "Dist::Zilla::Role::Git::Repo" : {
                  "git_version" : "2.34.1",
                  "repo_root" : "."
               },
               "Dist::Zilla::Role::Git::StringFormatter" : {
                  "time_zone" : "local"
               }
            },
            "name" : "@Author::OALDERS/@Git::VersionManager/Git::Tag",
            "version" : "2.048"
         },
         {
            "class" : "Dist::Zilla::Plugin::BumpVersionAfterRelease::Transitional",
            "config" : {
               "Dist::Zilla::Plugin::BumpVersionAfterRelease" : {
                  "finders" : [
                     ":ExecFiles",
                     ":InstallModules"
                  ],
                  "global" : 0,
                  "munge_makefile_pl" : 1
               },
               "Dist::Zilla::Plugin::BumpVersionAfterRelease::Transitional" : {}
            },
            "name" : "@Author::OALDERS/@Git::VersionManager/BumpVersionAfterRelease::Transitional",
            "version" : "0.009"
         },
         {
            "class" : "Dist::Zilla::Plugin::NextRelease",
            "name" : "@Author::OALDERS/@Git::VersionManager/NextRelease",
            "version" : "6.031"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::Commit",
            "config" : {
               "Dist::Zilla::Plugin::Git::Commit" : {
                  "add_files_in" : [],
                  "commit_msg" : "increment $VERSION after %v release",
                  "signoff" : 0
               },
               "Dist::Zilla::Role::Git::DirtyFiles" : {
                  "allow_dirty" : [
                     "Build.PL",
                     "Changes",
                     "Makefile.PL"
                  ],
                  "allow_dirty_match" : [
                     "(?^:^lib/.*\\.pm$)"
                  ],
                  "changelog" : "Changes"
               },
               "Dist::Zilla::Role::Git::Repo" : {
                  "git_version" : "2.34.1",
                  "repo_root" : "."
               },
               "Dist::Zilla::Role::Git::StringFormatter" : {
                  "time_zone" : "local"
               }
            },
            "name" : "@Author::OALDERS/@Git::VersionManager/post-release commit",
            "version" : "2.048"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::Push",
            "config" : {
               "Dist::Zilla::Plugin::Git::Push" : {
                  "push_to" : [
                     "origin"
                  ],
                  "remotes_must_exist" : 1
               },
               "Dist::Zilla::Role::Git::Repo" : {
                  "git_version" : "2.34.1",
                  "repo_root" : "."
               }
            },
            "name" : "@Author::OALDERS/Git::Push",
            "version" : "2.048"
         },
         {
            "class" : "Dist::Zilla::Plugin::BumpVersionAfterRelease",
            "config" : {
               "Dist::Zilla::Plugin::BumpVersionAfterRelease" : {
                  "finders" : [
                     ":ExecFiles",
                     ":InstallModules"
                  ],
                  "global" : 0,
                  "munge_makefile_pl" : 1
               }
            },
            "name" : "BumpVersionAfterRelease",
            "version" : "0.018"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":InstallModules",
            "version" : "6.031"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":IncModules",
            "version" : "6.031"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":TestFiles",
            "version" : "6.031"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":ExtraTestFiles",
            "version" : "6.031"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":ExecFiles",
            "version" : "6.031"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":PerlExecFiles",
            "version" : "6.031"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":ShareFiles",
            "version" : "6.031"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":MainModule",
            "version" : "6.031"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":AllFiles",
            "version" : "6.031"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":NoFiles",
            "version" : "6.031"
         }
      ],
      "zilla" : {
         "class" : "Dist::Zilla::Dist::Builder",
         "config" : {
            "is_trial" : 0
         },
         "version" : "6.031"
      }
   },
   "x_contributors" : [
      "Adam Kennedy <adamk@cpan.org>",
      "Adam Sjogren <asjo@koldfront.dk>",
      "Alexey Tourbin <at@altlinux.ru>",
      "Alex Kapranoff <ka@nadoby.ru>",
      "Alex Peters <alex@peters.net>",
      "Alex Peters <lxp@cpan.org>",
      "amire80 <amir.aharoni@gmail.com>",
      "Andreas J. Koenig <andreas.koenig@anima.de>",
      "Bernhard M. Wiedemann <bwiedemann@suse.de>",
      "Bill Mann <wfmann@alum.mit.edu>",
      "Bron Gondwana <brong@fastmail.fm>",
      "Charlie Hothersall-Thomas <me@charlie.ht>",
      "Chase Whitener <capoeirab@cpan.org>",
      "Colin Newell <c.newell@cv-library.co.uk>",
      "Colin Newell <colin.newell@gmail.com>",
      "Daniel Hedlund <Daniel.Hedlund@eprize.com>",
      "Dave Menninger <dave.menninger@online-rewards.com>",
      "David E. Wheeler <david@justatheory.com>",
      "DAVIDRW <davidrw@cpan.org>",
      "Father Chrysostomos <sprout@cpan.org>",
      "FWILES <FWILES@cpan.org>",
      "Gavin Peters <gpeters@deepsky.com>",
      "George Grozdev <g.grozdev@cv-library.co.uk>",
      "Graeme Thompson <Graeme.Thompson@mobilecohesion.com>",
      "Hans-H. Froehlich <hfroehlich@co-de-co.de>",
      "Ian Kilgore <iank@cpan.org>",
      "Jacob J <waif@chaos2.org>",
      "James McCoy <vega.james@gmail.com>",
      "James Raspass <jraspass@gmail.com>",
      "jefflee <shaohua@gmail.com>",
      "john9art <john9art@yahoo.com>",
      "Mark Raymond <m.raymond@cv-library.co.uk>",
      "Mark Stosberg <MARKSTOS@cpan.org>",
      "Mike Schilli <m@perlmeiser.com>",
      "Mohammad S Anwar <mohammad.anwar@yahoo.com>",
      "murphy <murphy@genome.chop.edu>",
      "Olaf Alders <olaf@wundersolutions.com>",
      "Ondrej Hanak <ondrej.hanak@ubs.com>",
      "Perlover <perlover@perlover.com>",
      "Peter Rabbitson <ribasushi@cpan.org>",
      "Philip J. Ludlam <p.ludlam@cv-library.co.uk>",
      "phrstbrn <phrstbrn@gmail.com>",
      "Robert Stone <talby@trap.mtview.ca.us>",
      "robnagler <github@q33.us>",
      "Rolf Grossmann <rg@progtech.net>",
      "ruff <ruff@ukrpost.net>",
      "sasao <sasao@yugen.org>",
      "Sean M. Burke <sburke@cpan.org>",
      "simbabque <simbabque@cpan.org>",
      "Slaven Rezic <slaven@rezic.de>",
      "Spiros Denaxas <s.denaxas@gmail.com>",
      "Steve Hay <SteveHay@planit.com>",
      "Todd Lipcon <todd@amiestreet.com>",
      "Tom Hukins <tom@eborcom.com>",
      "Tony Finch <dot@dotat.at>",
      "Toru Yamaguchi <zigorou@cpan.org>",
      "Ville Skyttä <ville.skytta@iki.fi>",
      "Yuri Karaban <tech@askold.net>",
      "Zefram <zefram@fysh.org>"
   ],
   "x_generated_by_perl" : "v5.34.0",
   "x_serialization_backend" : "JSON::PP version 2.97001",
   "x_spdx_expression" : "Artistic-1.0-Perl OR GPL-1.0-or-later",
   "x_static_install" : 0
}
PK1N%[�B҇}}Dperl5/x86_64-linux-thread-multi/.meta/HTTP-Cookies-6.11/install.jsonnu��6�${"name":"HTTP::Cookies","target":"HTTP::Cookies","version":6.11,"provides":{"HTTP::Cookies::Microsoft":{"version":6.11,"file":"lib/HTTP/Cookies/Microsoft.pm"},"HTTP::Cookies":{"version":6.11,"file":"lib/HTTP/Cookies.pm"},"HTTP::Cookies::Netscape":{"version":6.11,"file":"lib/HTTP/Cookies/Netscape.pm"}},"pathname":"O/OA/OALDERS/HTTP-Cookies-6.11.tar.gz","dist":"HTTP-Cookies-6.11"}PK2N%[����==Cperl5/x86_64-linux-thread-multi/.meta/Capture-Tiny-0.50/MYMETA.jsonnu��6�${
   "abstract" : "Capture STDOUT and STDERR from Perl, XS or external programs",
   "author" : [
      "David Golden <dagolden@cpan.org>"
   ],
   "dynamic_config" : 0,
   "generated_by" : "Dist::Zilla version 6.032, CPAN::Meta::Converter version 2.150010",
   "license" : [
      "apache_2_0"
   ],
   "meta-spec" : {
      "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
      "version" : 2
   },
   "name" : "Capture-Tiny",
   "no_index" : {
      "directory" : [
         "corpus",
         "examples",
         "t",
         "xt"
      ],
      "package" : [
         "DB"
      ]
   },
   "prereqs" : {
      "build" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "configure" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "6.17"
         }
      },
      "develop" : {
         "requires" : {
            "Dist::Zilla" : "5",
            "Dist::Zilla::Plugin::OSPrereqs" : "0",
            "Dist::Zilla::Plugin::Prereqs" : "0",
            "Dist::Zilla::Plugin::ReleaseStatus::FromVersion" : "0",
            "Dist::Zilla::Plugin::RemovePrereqs" : "0",
            "Dist::Zilla::PluginBundle::DAGOLDEN" : "0.072",
            "File::Spec" : "0",
            "File::Temp" : "0",
            "IO::Handle" : "0",
            "IPC::Open3" : "0",
            "Pod::Coverage::TrustPod" : "0",
            "Pod::Wordlist" : "0",
            "Software::License::Apache_2_0" : "0",
            "Test::CPAN::Meta" : "0",
            "Test::MinimumVersion" : "0",
            "Test::More" : "0",
            "Test::Perl::Critic" : "0",
            "Test::Pod" : "1.41",
            "Test::Pod::Coverage" : "1.08",
            "Test::Portability::Files" : "0",
            "Test::Spelling" : "0.17",
            "Test::Version" : "1"
         }
      },
      "runtime" : {
         "requires" : {
            "Carp" : "0",
            "Exporter" : "0",
            "File::Spec" : "0",
            "File::Temp" : "0",
            "IO::Handle" : "0",
            "Scalar::Util" : "0",
            "perl" : "5.006",
            "strict" : "0",
            "warnings" : "0"
         }
      },
      "test" : {
         "recommends" : {
            "CPAN::Meta" : "2.120900"
         },
         "requires" : {
            "ExtUtils::MakeMaker" : "0",
            "File::Spec" : "0",
            "IO::File" : "0",
            "Test::More" : "0.62",
            "lib" : "0"
         }
      }
   },
   "provides" : {
      "Capture::Tiny" : {
         "file" : "lib/Capture/Tiny.pm",
         "version" : "0.50"
      }
   },
   "release_status" : "stable",
   "resources" : {
      "bugtracker" : {
         "web" : "https://github.com/dagolden/Capture-Tiny/issues"
      },
      "homepage" : "https://github.com/dagolden/Capture-Tiny",
      "repository" : {
         "type" : "git",
         "url" : "https://github.com/dagolden/Capture-Tiny.git",
         "web" : "https://github.com/dagolden/Capture-Tiny"
      }
   },
   "version" : "0.50",
   "x_authority" : "cpan:DAGOLDEN",
   "x_contributors" : [
      "Dagfinn Ilmari Mannsåker <ilmari@ilmari.org>",
      "David E. Wheeler <david@justatheory.com>",
      "Ed Sabol <esabol@users.noreply.github.com>",
      "fecundf <not.com+github@gmail.com>",
      "Graham Knop <haarg@haarg.org>",
      "Karen Etheridge <ether@cpan.org>",
      "Mohammad S Anwar <mohammad.anwar@yahoo.com>",
      "Peter Rabbitson <ribasushi@cpan.org>",
      "Sven Kirmess <sven.kirmess@kzone.ch>"
   ],
   "x_generated_by_perl" : "v5.36.0",
   "x_serialization_backend" : "JSON::PP version 2.97001",
   "x_spdx_expression" : "Apache-2.0"
}
PK2N%[�;/���Dperl5/x86_64-linux-thread-multi/.meta/Capture-Tiny-0.50/install.jsonnu��6�${"provides":{"Capture::Tiny":{"file":"lib/Capture/Tiny.pm","version":"0.50"}},"name":"Capture::Tiny","dist":"Capture-Tiny-0.50","target":"Capture::Tiny","pathname":"D/DA/DAGOLDEN/Capture-Tiny-0.50.tar.gz","version":"0.50"}PK2N%[��"Kperl5/x86_64-linux-thread-multi/.meta/XML-NamespaceSupport-1.12/MYMETA.jsonnu��6�${
   "abstract" : "A simple generic namespace processor",
   "author" : [
      "Robin Berjon <robin@knowscape.com>",
      "Chris Prather <chris@prather.org>"
   ],
   "dynamic_config" : 0,
   "generated_by" : "Dist::Zilla version 6.009, CPAN::Meta::Converter version 2.150005, CPAN::Meta::Converter version 2.150010",
   "license" : [
      "perl_5"
   ],
   "meta-spec" : {
      "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
      "version" : 2
   },
   "name" : "XML-NamespaceSupport",
   "no_index" : {
      "directory" : [
         "corpus",
         "examples",
         "t",
         "xt"
      ],
      "package" : [
         "DB"
      ]
   },
   "prereqs" : {
      "build" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "configure" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "6.17"
         }
      },
      "develop" : {
         "requires" : {
            "Dist::Zilla" : "5",
            "Dist::Zilla::Plugin::Authority" : "0",
            "Dist::Zilla::Plugin::AutoPrereqs" : "0",
            "Dist::Zilla::Plugin::CPANFile" : "0",
            "Dist::Zilla::Plugin::CheckChangesHasContent" : "0",
            "Dist::Zilla::Plugin::CheckMetaResources" : "0",
            "Dist::Zilla::Plugin::CheckPrereqsIndexed" : "0",
            "Dist::Zilla::Plugin::ConfirmRelease" : "0",
            "Dist::Zilla::Plugin::CopyFilesFromBuild" : "0",
            "Dist::Zilla::Plugin::ExecDir" : "0",
            "Dist::Zilla::Plugin::Git::Check" : "0",
            "Dist::Zilla::Plugin::Git::CheckFor::CorrectBranch" : "0",
            "Dist::Zilla::Plugin::Git::Commit" : "0",
            "Dist::Zilla::Plugin::Git::Contributors" : "0",
            "Dist::Zilla::Plugin::Git::GatherDir" : "0",
            "Dist::Zilla::Plugin::Git::NextVersion" : "0",
            "Dist::Zilla::Plugin::Git::Push" : "0",
            "Dist::Zilla::Plugin::Git::Tag" : "0",
            "Dist::Zilla::Plugin::GithubMeta" : "0",
            "Dist::Zilla::Plugin::InsertCopyright" : "0",
            "Dist::Zilla::Plugin::License" : "0",
            "Dist::Zilla::Plugin::MakeMaker" : "0",
            "Dist::Zilla::Plugin::Manifest" : "0",
            "Dist::Zilla::Plugin::ManifestSkip" : "0",
            "Dist::Zilla::Plugin::MetaJSON" : "0",
            "Dist::Zilla::Plugin::MetaNoIndex" : "0",
            "Dist::Zilla::Plugin::MetaProvides::Package" : "0",
            "Dist::Zilla::Plugin::MetaYAML" : "0",
            "Dist::Zilla::Plugin::MinimumPerl" : "0",
            "Dist::Zilla::Plugin::NextRelease" : "0",
            "Dist::Zilla::Plugin::OurPkgVersion" : "0",
            "Dist::Zilla::Plugin::PodWeaver" : "0",
            "Dist::Zilla::Plugin::Prereqs::AuthorDeps" : "0",
            "Dist::Zilla::Plugin::PromptIfStale" : "0",
            "Dist::Zilla::Plugin::PruneCruft" : "0",
            "Dist::Zilla::Plugin::RunExtraTests" : "0",
            "Dist::Zilla::Plugin::ShareDir" : "0",
            "Dist::Zilla::Plugin::TestRelease" : "0",
            "Dist::Zilla::Plugin::UploadToCPAN" : "0",
            "Software::License::Perl_5" : "0"
         }
      },
      "runtime" : {
         "requires" : {
            "constant" : "0",
            "perl" : "5.006",
            "strict" : "0",
            "vars" : "0",
            "warnings" : "0"
         }
      },
      "test" : {
         "requires" : {
            "Test::More" : "0"
         }
      }
   },
   "provides" : {
      "XML::NamespaceSupport" : {
         "file" : "lib/XML/NamespaceSupport.pm",
         "version" : "1.12"
      }
   },
   "release_status" : "stable",
   "resources" : {
      "bugtracker" : {
         "web" : "https://github.com/perigrin/xml-namespacesupport/issues"
      },
      "homepage" : "https://github.com/perigrin/xml-namespacesupport",
      "repository" : {
         "type" : "git",
         "url" : "https://github.com/perigrin/xml-namespacesupport.git",
         "web" : "https://github.com/perigrin/xml-namespacesupport"
      }
   },
   "version" : "1.12",
   "x_authority" : "cpan:PERIGRIN",
   "x_contributors" : [
      "Chris Prather <cprather@hdpublishing.com>",
      "David Steinbrunner <dsteinbrunner@pobox.com>",
      "Paul Cochrane <paul@liekut.de>",
      "Paulo Custodio <pauloscustodio@gmail.com>"
   ],
   "x_serialization_backend" : "JSON::PP version 2.97001"
}
PK2N%[���Lperl5/x86_64-linux-thread-multi/.meta/XML-NamespaceSupport-1.12/install.jsonnu��6�${"version":"1.12","provides":{"XML::NamespaceSupport":{"file":"lib/XML/NamespaceSupport.pm","version":"1.12"}},"pathname":"P/PE/PERIGRIN/XML-NamespaceSupport-1.12.tar.gz","dist":"XML-NamespaceSupport-1.12","name":"XML::NamespaceSupport","target":"XML::NamespaceSupport"}PK2N%[aE�|ppEperl5/x86_64-linux-thread-multi/.meta/HTTP-Negotiate-6.01/MYMETA.jsonnu��6�${
   "abstract" : "choose a variant to serve",
   "author" : [
      "Gisle Aas <gisle@activestate.com>"
   ],
   "dynamic_config" : 0,
   "generated_by" : "ExtUtils::MakeMaker version 6.57_05, CPAN::Meta::Converter version 2.150010",
   "license" : [
      "perl_5"
   ],
   "meta-spec" : {
      "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
      "version" : 2
   },
   "name" : "HTTP-Negotiate",
   "no_index" : {
      "directory" : [
         "t",
         "inc"
      ]
   },
   "prereqs" : {
      "build" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "configure" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "runtime" : {
         "requires" : {
            "HTTP::Headers" : "6",
            "perl" : "5.008001"
         }
      }
   },
   "release_status" : "stable",
   "resources" : {
      "repository" : {
         "url" : "http://github.com/gisle/http-negotiate"
      },
      "x_MailingList" : "mailto:libwww@perl.org"
   },
   "version" : "6.01",
   "x_serialization_backend" : "JSON::PP version 2.97001"
}
PK2N%[��ϧ��Fperl5/x86_64-linux-thread-multi/.meta/HTTP-Negotiate-6.01/install.jsonnu��6�${"target":"HTTP::Negotiate","name":"HTTP::Negotiate","pathname":"G/GA/GAAS/HTTP-Negotiate-6.01.tar.gz","provides":{"HTTP::Negotiate":{"version":6.01,"file":"lib/HTTP/Negotiate.pm"}},"version":6.01,"dist":"HTTP-Negotiate-6.01"}PK2N%[Y�lm��Bperl5/x86_64-linux-thread-multi/.meta/libwww-perl-6.78/MYMETA.jsonnu��6�${
   "abstract" : "The World-Wide Web library for Perl",
   "author" : [
      "Gisle Aas <gisle@activestate.com>"
   ],
   "dynamic_config" : 0,
   "generated_by" : "Dist::Zilla version 6.032, CPAN::Meta::Converter version 2.150010",
   "license" : [
      "perl_5"
   ],
   "meta-spec" : {
      "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
      "version" : 2
   },
   "name" : "libwww-perl",
   "no_index" : {
      "directory" : [
         "t",
         "xt"
      ]
   },
   "prereqs" : {
      "build" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "configure" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0",
            "File::Copy" : "0",
            "Getopt::Long" : "0"
         },
         "suggests" : {
            "JSON::PP" : "2.27300"
         }
      },
      "develop" : {
         "recommends" : {
            "Dist::Zilla::PluginBundle::Git::VersionManager" : "0.007"
         },
         "requires" : {
            "Authen::NTLM" : "1.02",
            "File::Spec" : "0",
            "IO::Handle" : "0",
            "IPC::Open3" : "0",
            "Pod::Coverage::TrustPod" : "0",
            "Pod::Spell" : "1.25",
            "Test::EOL" : "2.00",
            "Test::LeakTrace" : "0.16",
            "Test::MinimumVersion" : "0",
            "Test::Mojibake" : "0",
            "Test::More" : "0.94",
            "Test::Pod" : "1.41",
            "Test::Pod::Coverage" : "1.08",
            "Test::Portability::Files" : "0",
            "Test::Spelling" : "0.17",
            "Test::Version" : "1"
         }
      },
      "runtime" : {
         "requires" : {
            "Digest::MD5" : "0",
            "Encode" : "2.12",
            "Encode::Locale" : "0",
            "File::Copy" : "0",
            "File::Listing" : "6",
            "File::Temp" : "0",
            "Getopt::Long" : "0",
            "HTML::Entities" : "0",
            "HTML::HeadParser" : "3.71",
            "HTTP::Cookies" : "6",
            "HTTP::Date" : "6",
            "HTTP::Negotiate" : "6",
            "HTTP::Request" : "6.18",
            "HTTP::Request::Common" : "6.18",
            "HTTP::Response" : "6.18",
            "HTTP::Status" : "6.18",
            "IO::Select" : "0",
            "IO::Socket" : "0",
            "LWP::MediaTypes" : "6",
            "MIME::Base64" : "2.1",
            "Module::Load" : "0",
            "Net::FTP" : "2.58",
            "Net::HTTP" : "6.18",
            "Scalar::Util" : "0",
            "Try::Tiny" : "0",
            "URI" : "1.10",
            "URI::Escape" : "0",
            "WWW::RobotRules" : "6",
            "parent" : "0.217",
            "perl" : "5.008001",
            "strict" : "0",
            "warnings" : "0"
         },
         "suggests" : {
            "Authen::NTLM" : "1.02",
            "Data::Dump" : "1.13",
            "IO::Socket::INET" : "0",
            "LWP::Protocol::https" : "6.02"
         }
      },
      "test" : {
         "recommends" : {
            "CPAN::Meta" : "2.120900",
            "Test::LeakTrace" : "0"
         },
         "requires" : {
            "ExtUtils::MakeMaker" : "0",
            "File::Spec" : "0",
            "FindBin" : "0",
            "HTTP::CookieJar::LWP" : "0",
            "HTTP::Daemon" : "6.12",
            "Test::Fatal" : "0",
            "Test::More" : "0.96",
            "Test::Needs" : "0",
            "Test::RequiresInternet" : "0"
         }
      }
   },
   "provides" : {
      "LWP" : {
         "file" : "lib/LWP.pm",
         "version" : "6.78"
      },
      "LWP::Authen::Basic" : {
         "file" : "lib/LWP/Authen/Basic.pm",
         "version" : "6.78"
      },
      "LWP::Authen::Digest" : {
         "file" : "lib/LWP/Authen/Digest.pm",
         "version" : "6.78"
      },
      "LWP::Authen::Ntlm" : {
         "file" : "lib/LWP/Authen/Ntlm.pm",
         "version" : "6.78"
      },
      "LWP::ConnCache" : {
         "file" : "lib/LWP/ConnCache.pm",
         "version" : "6.78"
      },
      "LWP::Debug" : {
         "file" : "lib/LWP/Debug.pm",
         "version" : "6.78",
         "x_deprecated" : 1
      },
      "LWP::Debug::TraceHTTP" : {
         "file" : "lib/LWP/Debug/TraceHTTP.pm",
         "version" : "6.78"
      },
      "LWP::DebugFile" : {
         "file" : "lib/LWP/DebugFile.pm",
         "version" : "6.78"
      },
      "LWP::MemberMixin" : {
         "file" : "lib/LWP/MemberMixin.pm",
         "version" : "6.78"
      },
      "LWP::Protocol" : {
         "file" : "lib/LWP/Protocol.pm",
         "version" : "6.78"
      },
      "LWP::Protocol::cpan" : {
         "file" : "lib/LWP/Protocol/cpan.pm",
         "version" : "6.78"
      },
      "LWP::Protocol::data" : {
         "file" : "lib/LWP/Protocol/data.pm",
         "version" : "6.78"
      },
      "LWP::Protocol::file" : {
         "file" : "lib/LWP/Protocol/file.pm",
         "version" : "6.78"
      },
      "LWP::Protocol::ftp" : {
         "file" : "lib/LWP/Protocol/ftp.pm",
         "version" : "6.78"
      },
      "LWP::Protocol::gopher" : {
         "file" : "lib/LWP/Protocol/gopher.pm",
         "version" : "6.78"
      },
      "LWP::Protocol::http" : {
         "file" : "lib/LWP/Protocol/http.pm",
         "version" : "6.78"
      },
      "LWP::Protocol::loopback" : {
         "file" : "lib/LWP/Protocol/loopback.pm",
         "version" : "6.78"
      },
      "LWP::Protocol::mailto" : {
         "file" : "lib/LWP/Protocol/mailto.pm",
         "version" : "6.78"
      },
      "LWP::Protocol::nntp" : {
         "file" : "lib/LWP/Protocol/nntp.pm",
         "version" : "6.78"
      },
      "LWP::Protocol::nogo" : {
         "file" : "lib/LWP/Protocol/nogo.pm",
         "version" : "6.78"
      },
      "LWP::RobotUA" : {
         "file" : "lib/LWP/RobotUA.pm",
         "version" : "6.78"
      },
      "LWP::Simple" : {
         "file" : "lib/LWP/Simple.pm",
         "version" : "6.78"
      },
      "LWP::UserAgent" : {
         "file" : "lib/LWP/UserAgent.pm",
         "version" : "6.78"
      }
   },
   "release_status" : "stable",
   "resources" : {
      "bugtracker" : {
         "web" : "https://github.com/libwww-perl/libwww-perl/issues"
      },
      "homepage" : "https://github.com/libwww-perl/libwww-perl",
      "repository" : {
         "type" : "git",
         "url" : "https://github.com/libwww-perl/libwww-perl.git",
         "web" : "https://github.com/libwww-perl/libwww-perl"
      },
      "x_IRC" : "irc://irc.perl.org/#lwp",
      "x_MailingList" : "mailto:libwww@perl.org"
   },
   "version" : "6.78",
   "x_Dist_Zilla" : {
      "perl" : {
         "version" : "5.038002"
      },
      "plugins" : [
         {
            "class" : "Dist::Zilla::Plugin::Git::GatherDir",
            "config" : {
               "Dist::Zilla::Plugin::GatherDir" : {
                  "exclude_filename" : [
                     "LICENSE",
                     "META.json",
                     "README.md"
                  ],
                  "exclude_match" : [],
                  "include_dotfiles" : 0,
                  "prefix" : "",
                  "prune_directory" : [],
                  "root" : "."
               },
               "Dist::Zilla::Plugin::Git::GatherDir" : {
                  "include_untracked" : 0
               }
            },
            "name" : "Git::GatherDir",
            "version" : "2.051"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaConfig",
            "name" : "MetaConfig",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaProvides::Package",
            "config" : {
               "Dist::Zilla::Plugin::MetaProvides::Package" : {
                  "finder_objects" : [
                     {
                        "class" : "Dist::Zilla::Plugin::FinderCode",
                        "name" : "MetaProvides::Package/AUTOVIV/:InstallModulesPM",
                        "version" : "6.032"
                     }
                  ],
                  "include_underscores" : 0
               },
               "Dist::Zilla::Role::MetaProvider::Provider" : {
                  "$Dist::Zilla::Role::MetaProvider::Provider::VERSION" : "2.002004",
                  "inherit_missing" : 1,
                  "inherit_version" : 1,
                  "meta_noindex" : 1
               },
               "Dist::Zilla::Role::ModuleMetadata" : {
                  "Module::Metadata" : "1.000037",
                  "version" : "0.006"
               }
            },
            "name" : "MetaProvides::Package",
            "version" : "2.004003"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaNoIndex",
            "name" : "MetaNoIndex",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaYAML",
            "name" : "MetaYAML",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaJSON",
            "name" : "MetaJSON",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaResources",
            "name" : "MetaResources",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::Deprecated",
            "config" : {
               "Dist::Zilla::Plugin::Deprecated" : {
                  "all" : 0,
                  "modules" : [
                     "LWP::Debug"
                  ]
               }
            },
            "name" : "Deprecated",
            "version" : "0.007"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::Contributors",
            "config" : {
               "Dist::Zilla::Plugin::Git::Contributors" : {
                  "git_version" : "2.43.0",
                  "include_authors" : 0,
                  "include_releaser" : 1,
                  "order_by" : "name",
                  "paths" : []
               }
            },
            "name" : "Git::Contributors",
            "version" : "0.037"
         },
         {
            "class" : "Dist::Zilla::Plugin::GithubMeta",
            "name" : "GithubMeta",
            "version" : "0.58"
         },
         {
            "class" : "Dist::Zilla::Plugin::Manifest",
            "name" : "Manifest",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::License",
            "name" : "License",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::InstallGuide",
            "config" : {
               "Dist::Zilla::Role::ModuleMetadata" : {
                  "Module::Metadata" : "1.000037",
                  "version" : "0.006"
               }
            },
            "name" : "InstallGuide",
            "version" : "1.200014"
         },
         {
            "class" : "Dist::Zilla::Plugin::ExecDir",
            "name" : "ExecDir",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::Prereqs::FromCPANfile",
            "name" : "Prereqs::FromCPANfile",
            "version" : "0.08"
         },
         {
            "class" : "Dist::Zilla::Plugin::MakeMaker::Awesome",
            "config" : {
               "Dist::Zilla::Plugin::MakeMaker" : {
                  "make_path" : "make",
                  "version" : "6.032"
               },
               "Dist::Zilla::Role::TestRunner" : {
                  "default_jobs" : "8",
                  "version" : "6.032"
               }
            },
            "name" : "MakeMaker::Awesome",
            "version" : "0.49"
         },
         {
            "class" : "Dist::Zilla::Plugin::MojibakeTests",
            "name" : "MojibakeTests",
            "version" : "0.8"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::Version",
            "name" : "Test::Version",
            "version" : "1.09"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::ReportPrereqs",
            "name" : "Test::ReportPrereqs",
            "version" : "0.029"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::Compile",
            "config" : {
               "Dist::Zilla::Plugin::Test::Compile" : {
                  "bail_out_on_fail" : "1",
                  "fail_on_warning" : "author",
                  "fake_home" : 0,
                  "filename" : "xt/author/00-compile.t",
                  "module_finder" : [
                     ":InstallModules"
                  ],
                  "needs_display" : 0,
                  "phase" : "develop",
                  "script_finder" : [
                     ":PerlExecFiles"
                  ],
                  "skips" : [],
                  "switch" : []
               }
            },
            "name" : "Test::Compile",
            "version" : "2.058"
         },
         {
            "class" : "Dist::Zilla::Plugin::Substitute",
            "name" : "00-compile.t",
            "version" : "0.008"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::Portability",
            "config" : {
               "Dist::Zilla::Plugin::Test::Portability" : {
                  "options" : ""
               }
            },
            "name" : "Test::Portability",
            "version" : "2.001003"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::EOL",
            "config" : {
               "Dist::Zilla::Plugin::Test::EOL" : {
                  "filename" : "xt/author/eol.t",
                  "finder" : [
                     ":ExecFiles",
                     ":InstallModules",
                     ":TestFiles"
                  ],
                  "trailing_whitespace" : 1
               }
            },
            "name" : "Test::EOL",
            "version" : "0.19"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::MinimumVersion",
            "config" : {
               "Dist::Zilla::Plugin::Test::MinimumVersion" : {
                  "max_target_perl" : null
               }
            },
            "name" : "Test::MinimumVersion",
            "version" : "2.000011"
         },
         {
            "class" : "Dist::Zilla::Plugin::PodSyntaxTests",
            "name" : "PodSyntaxTests",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::Pod::Coverage::Configurable",
            "name" : "Test::Pod::Coverage::Configurable",
            "version" : "0.07"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::PodSpelling",
            "config" : {
               "Dist::Zilla::Plugin::Test::PodSpelling" : {
                  "directories" : [
                     "bin",
                     "lib"
                  ],
                  "spell_cmd" : "aspell --master=en_US list",
                  "stopwords" : [
                     "Accomazzi",
                     "Alexandre",
                     "Andreas",
                     "Asplund",
                     "Betts",
                     "Bochner",
                     "BooK",
                     "Buenzli",
                     "CGI",
                     "CPAN",
                     "Chamas",
                     "Coppit",
                     "Dalgleish",
                     "Dubois",
                     "Dunkin",
                     "Duret",
                     "Dvornik",
                     "Eldridge",
                     "Gertjan",
                     "Graaff",
                     "Greab",
                     "Guenther",
                     "Gurusamy",
                     "Gustafsson",
                     "Hakanson",
                     "Harald",
                     "Hedlund",
                     "Hoblitt",
                     "Hwa",
                     "INOUE",
                     "Joao",
                     "Joerg",
                     "KONISHI",
                     "Kaminsky",
                     "Kartik",
                     "Katsuhiro",
                     "Kebsch",
                     "Keiichiro",
                     "Kilzer",
                     "Klar",
                     "Koster",
                     "Kronengold",
                     "Krüger",
                     "Kubb",
                     "König",
                     "Laker",
                     "Langfeldt",
                     "Langheinrich",
                     "Liam",
                     "Lindley",
                     "Lotterer",
                     "Lutz",
                     "MacEachern",
                     "Macdonald",
                     "Mailto",
                     "Marko",
                     "Markus",
                     "Martijn",
                     "McCauley",
                     "Melchner",
                     "Moshe",
                     "Murrell",
                     "NNTP",
                     "NTLM",
                     "Nagano",
                     "Newby",
                     "Nicolai",
                     "Nierstrasz",
                     "Olly",
                     "Oosten",
                     "Panchenko",
                     "Pimlott",
                     "Pon",
                     "Quaranta",
                     "Radoslaw",
                     "Radu",
                     "Rai",
                     "Rezic",
                     "RobotUA",
                     "Sarathy",
                     "Schilli",
                     "Schinder",
                     "Shirazi",
                     "Skyttä",
                     "Slaven",
                     "Spafford",
                     "Stosberg",
                     "Subbarao",
                     "TCP",
                     "Takanori",
                     "Thoennes",
                     "Thurn",
                     "Tilly",
                     "UA",
                     "Ugai",
                     "Unger",
                     "UserAgent",
                     "VanHeyningen",
                     "Vandewege",
                     "Ville",
                     "WireShark",
                     "Yee",
                     "Yitzchak",
                     "Yoshinari",
                     "Zajac",
                     "Zakharevich",
                     "Zielinski",
                     "Zoest",
                     "afPuUsSedvhx",
                     "de",
                     "erik",
                     "getprint",
                     "getstore",
                     "instantiation",
                     "peterm",
                     "shildreth"
                  ],
                  "wordlist" : "Pod::Wordlist"
               }
            },
            "name" : "Test::PodSpelling",
            "version" : "2.007006"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::Check",
            "config" : {
               "Dist::Zilla::Plugin::Git::Check" : {
                  "untracked_files" : "die"
               },
               "Dist::Zilla::Role::Git::DirtyFiles" : {
                  "allow_dirty" : [],
                  "allow_dirty_match" : [],
                  "changelog" : "Changes"
               },
               "Dist::Zilla::Role::Git::Repo" : {
                  "git_version" : "2.43.0",
                  "repo_root" : "."
               }
            },
            "name" : "Git::Check",
            "version" : "2.051"
         },
         {
            "class" : "Dist::Zilla::Plugin::CheckStrictVersion",
            "name" : "CheckStrictVersion",
            "version" : "0.001"
         },
         {
            "class" : "Dist::Zilla::Plugin::RunExtraTests",
            "config" : {
               "Dist::Zilla::Role::TestRunner" : {
                  "default_jobs" : "8"
               }
            },
            "name" : "RunExtraTests",
            "version" : "0.029"
         },
         {
            "class" : "Dist::Zilla::Plugin::CheckChangeLog",
            "name" : "CheckChangeLog",
            "version" : "0.05"
         },
         {
            "class" : "Dist::Zilla::Plugin::CheckChangesHasContent",
            "name" : "CheckChangesHasContent",
            "version" : "0.011"
         },
         {
            "class" : "Dist::Zilla::Plugin::TestRelease",
            "name" : "TestRelease",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::UploadToCPAN",
            "name" : "UploadToCPAN",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::ReadmeAnyFromPod",
            "config" : {
               "Dist::Zilla::Role::FileWatcher" : {
                  "version" : "0.006"
               }
            },
            "name" : "Markdown_Readme",
            "version" : "0.163250"
         },
         {
            "class" : "Dist::Zilla::Plugin::CopyFilesFromRelease",
            "config" : {
               "Dist::Zilla::Plugin::CopyFilesFromRelease" : {
                  "filename" : [
                     "LICENSE",
                     "META.json"
                  ],
                  "match" : []
               }
            },
            "name" : "CopyFilesFromRelease",
            "version" : "0.007"
         },
         {
            "class" : "Dist::Zilla::Plugin::Prereqs",
            "config" : {
               "Dist::Zilla::Plugin::Prereqs" : {
                  "phase" : "develop",
                  "type" : "recommends"
               }
            },
            "name" : "@Git::VersionManager/pluginbundle version",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::RewriteVersion::Transitional",
            "config" : {
               "Dist::Zilla::Plugin::RewriteVersion" : {
                  "add_tarball_name" : 0,
                  "finders" : [
                     ":ExecFiles",
                     ":InstallModules"
                  ],
                  "global" : 0,
                  "skip_version_provider" : 0
               },
               "Dist::Zilla::Plugin::RewriteVersion::Transitional" : {}
            },
            "name" : "@Git::VersionManager/RewriteVersion::Transitional",
            "version" : "0.009"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaProvides::Update",
            "name" : "@Git::VersionManager/MetaProvides::Update",
            "version" : "0.007"
         },
         {
            "class" : "Dist::Zilla::Plugin::CopyFilesFromRelease",
            "config" : {
               "Dist::Zilla::Plugin::CopyFilesFromRelease" : {
                  "filename" : [
                     "Changes"
                  ],
                  "match" : []
               }
            },
            "name" : "@Git::VersionManager/CopyFilesFromRelease",
            "version" : "0.007"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::Commit",
            "config" : {
               "Dist::Zilla::Plugin::Git::Commit" : {
                  "add_files_in" : [],
                  "commit_msg" : "v%V%n%n%c",
                  "signoff" : 0
               },
               "Dist::Zilla::Role::Git::DirtyFiles" : {
                  "allow_dirty" : [
                     "Changes",
                     "LICENSE",
                     "META.json",
                     "README.md"
                  ],
                  "allow_dirty_match" : [],
                  "changelog" : "Changes"
               },
               "Dist::Zilla::Role::Git::Repo" : {
                  "git_version" : "2.43.0",
                  "repo_root" : "."
               },
               "Dist::Zilla::Role::Git::StringFormatter" : {
                  "time_zone" : "local"
               }
            },
            "name" : "@Git::VersionManager/release snapshot",
            "version" : "2.051"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::Tag",
            "config" : {
               "Dist::Zilla::Plugin::Git::Tag" : {
                  "branch" : null,
                  "changelog" : "Changes",
                  "signed" : 0,
                  "tag" : "v6.78",
                  "tag_format" : "v%V",
                  "tag_message" : "v%V"
               },
               "Dist::Zilla::Role::Git::Repo" : {
                  "git_version" : "2.43.0",
                  "repo_root" : "."
               },
               "Dist::Zilla::Role::Git::StringFormatter" : {
                  "time_zone" : "local"
               }
            },
            "name" : "@Git::VersionManager/Git::Tag",
            "version" : "2.051"
         },
         {
            "class" : "Dist::Zilla::Plugin::BumpVersionAfterRelease::Transitional",
            "config" : {
               "Dist::Zilla::Plugin::BumpVersionAfterRelease" : {
                  "finders" : [
                     ":ExecFiles",
                     ":InstallModules"
                  ],
                  "global" : 0,
                  "munge_makefile_pl" : 1
               },
               "Dist::Zilla::Plugin::BumpVersionAfterRelease::Transitional" : {}
            },
            "name" : "@Git::VersionManager/BumpVersionAfterRelease::Transitional",
            "version" : "0.009"
         },
         {
            "class" : "Dist::Zilla::Plugin::NextRelease",
            "name" : "@Git::VersionManager/NextRelease",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::Commit",
            "config" : {
               "Dist::Zilla::Plugin::Git::Commit" : {
                  "add_files_in" : [],
                  "commit_msg" : "increment $VERSION after %v release",
                  "signoff" : 0
               },
               "Dist::Zilla::Role::Git::DirtyFiles" : {
                  "allow_dirty" : [
                     "Build.PL",
                     "Changes",
                     "Makefile.PL"
                  ],
                  "allow_dirty_match" : [
                     "(?^:^lib/.*\\.pm$)"
                  ],
                  "changelog" : "Changes"
               },
               "Dist::Zilla::Role::Git::Repo" : {
                  "git_version" : "2.43.0",
                  "repo_root" : "."
               },
               "Dist::Zilla::Role::Git::StringFormatter" : {
                  "time_zone" : "local"
               }
            },
            "name" : "@Git::VersionManager/post-release commit",
            "version" : "2.051"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::Push",
            "config" : {
               "Dist::Zilla::Plugin::Git::Push" : {
                  "push_to" : [
                     "origin"
                  ],
                  "remotes_must_exist" : 1
               },
               "Dist::Zilla::Role::Git::Repo" : {
                  "git_version" : "2.43.0",
                  "repo_root" : "."
               }
            },
            "name" : "Git::Push",
            "version" : "2.051"
         },
         {
            "class" : "Dist::Zilla::Plugin::ConfirmRelease",
            "name" : "ConfirmRelease",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":InstallModules",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":IncModules",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":TestFiles",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":ExtraTestFiles",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":ExecFiles",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":PerlExecFiles",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":ShareFiles",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":MainModule",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":AllFiles",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":NoFiles",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : "MetaProvides::Package/AUTOVIV/:InstallModulesPM",
            "version" : "6.032"
         }
      ],
      "zilla" : {
         "class" : "Dist::Zilla::Dist::Builder",
         "config" : {
            "is_trial" : 0
         },
         "version" : "6.032"
      }
   },
   "x_contributors" : [
      "Adam Kennedy <adamk@cpan.org>",
      "Adam Sjogren <asjo@koldfront.dk>",
      "Alexey Tourbin <at@altlinux.ru>",
      "Alex Kapranoff <ka@nadoby.ru>",
      "amire80 <amir.aharoni@gmail.com>",
      "Andreas J. Koenig <andreas.koenig@anima.de>",
      "Andrew Grangaard <granny-github@ofb.net>",
      "Andrew Hewus Fresh <andrew@afresh1.com>",
      "Anirvan Chatterjee <anirvan@users.noreply.github.com>",
      "Arne Johannessen <git@arne.johannessen.de>",
      "Austin Hill <austin.hill@grantstreet.com>",
      "Axel Burri <axel@tty0.ch>",
      "BGMNT <freeerider@mailinator.com>",
      "Bill Mann <wfmann@alum.mit.edu>",
      "Bron Gondwana <brong@fastmail.fm>",
      "Bryan Cardillo <bryan.cardillo@gmail.com>",
      "Burak Gursoy <burak@cpan.org>",
      "Chase Whitener <capoeirab@cpan.org>",
      "Christopher J. Madsen <cjm@cpan.org>",
      "Colin Newell <colin.newell@gmail.com>",
      "Daina Pettit <dpettit@bluehost.com>",
      "Daniel Hedlund <Daniel.Hedlund@eprize.com>",
      "David E. Wheeler <david@justatheory.com>",
      "DAVIDRW <davidrw@cpan.org>",
      "David Standish <dnstandish@gmail.com>",
      "David Steinbrunner <dsteinbrunner@MountainBook-Pro.local>",
      "dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
      "Desmond Daignault <nawglan@cpan.org>",
      "Dmitriy Shamatrin <dshamatrin@cloudbees.com>",
      "Doug Bell <doug@preaction.me>",
      "Eric Johnson <eric.git@iijo.org>",
      "Fabian Zeindler <faz@open.ch>",
      "Father Chrysostomos <sprout@cpan.org>",
      "Frank Maas <maas.frank@gmail.com>",
      "FWILES <FWILES@cpan.org>",
      "Galen Huntington <galen@alumni.reed.edu>",
      "Gavin Peters <gpeters@deepsky.com>",
      "Gerhard Poul <gerhard.poul@gmail.com>",
      "Gianni Ceccarelli <gianni.ceccarelli@broadbean.com>",
      "Gisle Aas <gisle@aas.no>",
      "Graeme Thompson <Graeme.Thompson@mobilecohesion.com>",
      "Graham Knop <haarg@haarg.org>",
      "Gregory Oschwald <oschwald@gmail.com>",
      "grr <grr@users.noreply.github.com>",
      "Hans-H. Froehlich <hfroehlich@co-de-co.de>",
      "Ian Kilgore <iank@cpan.org>",
      "Jacob J <waif@chaos2.org>",
      "Jakub Wilk <jwilk@jwilk.net>",
      "James Raspass <jraspass@gmail.com>",
      "Jason A Fesler <jfesler@gigo.com>",
      "Javier Puche <javier.puche@educa.madrid.org>",
      "jefflee <shaohua@gmail.com>",
      "Jeremy Mates <jmates@cpan.org>",
      "Joe Atzberger <ohiocore@gmail.com>",
      "john9art <john9art@yahoo.com>",
      "John Wittkoski <jwittkoski@gmail.com>",
      "Jonathan Dahan <jonathan@augwa.com>",
      "Julien Fiegehenn <simbabque@cpan.org>",
      "Kacper Gutowski <mwgamera@gmail.com>",
      "Karen Etheridge <ether@cpan.org>",
      "Katarina Durechova <katarina.durechova@nic.cz>",
      "leedo <leedo@users.noreply.github.com>",
      "Mark Fowler <mark@twoshortplanks.com>",
      "Mark Stosberg <mark@stosberg.com>",
      "Martin H. Sluka <martin@sluka.de>",
      "Matthew Horsfall <wolfsage@gmail.com>",
      "Max Maischein <corion@corion.net>",
      "michael gong <michealgong@126.com>",
      "Michael G. Schwern <schwern@pobox.com>",
      "Michal Josef Špaček <mspacek@redhat.com>",
      "Michiel Beijen <michiel.beijen@otrs.com>",
      "Mike Schilli <github@perlmeister.com>",
      "Moritz Onken <onken@netcubed.de>",
      "murphy <murphy@genome.chop.edu>",
      "Naveed Massjouni <naveedm9@gmail.com>",
      "Nigel Gregoire <nigelgregoire@gmail.com>",
      "Nik LaBelle <nalabelle@gmail.com>",
      "Niko Tyni <ntyni@debian.org>",
      "Olaf Alders <olaf@wundersolutions.com>",
      "Ondrej Hanak <ondrej.hanak@ubs.com>",
      "Patrik Lundin <patrik.lundin@su.se>",
      "Peter Rabbitson <ribasushi@cpan.org>",
      "phrstbrn <phrstbrn@gmail.com>",
      "Piotr Roszatycki <piotr.roszatycki@gmail.com>",
      "Robert Stone <talby@trap.mtview.ca.us>",
      "Rolf Grossmann <rg@progtech.net>",
      "Roman Galeev <roman.galeev@gooddata.com>",
      "ruff <ruff@ukrpost.net>",
      "Russell Shingleton <reshingleton@gmail.com>",
      "sasao <sasao@yugen.org>",
      "Sean M. Burke <sburke@cpan.org>",
      "Sebastian Paaske Tørholm <Eckankar@gmail.com>",
      "Sergey Romanov <sromanov-dev@yandex.ru>",
      "Shoichi Kaji <skaji@cpan.org>",
      "Slaven Rezic <slaven@rezic.de>",
      "Slaven Rezic <slaven.rezic@idealo.de>",
      "Spiros Denaxas <s.denaxas@gmail.com>",
      "Steffen Ullrich <Steffen_Ullrich@genua.de>",
      "Steve Hay <SteveHay@planit.com>",
      "Takumi Akiyama <t.akiym@gmail.com>",
      "Theodore Robert Campbell Jr <trcjr@stupidfoot.com>",
      "Theo van Hoesel <Th.J.v.Hoesel+GitHub@gmail.com>",
      "Tim Couzins <tim.couzins@sophos.com>",
      "Todd Lipcon <todd@amiestreet.com>",
      "Tomasz Konojacki <me@xenu.pl>",
      "Tom Hukins <tom@eborcom.com>",
      "Tony Finch <dot@dotat.at>",
      "Toru Yamaguchi <zigorou@cpan.org>",
      "turugina <turugina@floralcompany.jp>",
      "uid39246 <uid39246>",
      "Ville Skyttä <ville.skytta@iki.fi>",
      "Vyacheslav Matyukhin <mmcleric@yandex-team.ru>",
      "Yuri Karaban <tech@askold.net>",
      "Yury Zavarin <yury.zavarin@gmail.com>",
      "Yves Orton <yves.orton@booking.com>",
      "Zefram <zefram@fysh.org>"
   ],
   "x_generated_by_perl" : "v5.38.2",
   "x_serialization_backend" : "JSON::PP version 2.97001",
   "x_spdx_expression" : "Artistic-1.0-Perl OR GPL-1.0-or-later"
}
PK2N%[hh�Cperl5/x86_64-linux-thread-multi/.meta/libwww-perl-6.78/install.jsonnu��6�${"target":"LWP::UserAgent","name":"LWP","dist":"libwww-perl-6.78","pathname":"O/OA/OALDERS/libwww-perl-6.78.tar.gz","provides":{"LWP::Authen::Digest":{"file":"lib/LWP/Authen/Digest.pm","version":"6.78"},"LWP::Protocol::nogo":{"file":"lib/LWP/Protocol/nogo.pm","version":"6.78"},"LWP::RobotUA":{"version":"6.78","file":"lib/LWP/RobotUA.pm"},"LWP::Protocol::cpan":{"file":"lib/LWP/Protocol/cpan.pm","version":"6.78"},"LWP::Authen::Ntlm":{"file":"lib/LWP/Authen/Ntlm.pm","version":"6.78"},"LWP":{"version":"6.78","file":"lib/LWP.pm"},"LWP::ConnCache":{"file":"lib/LWP/ConnCache.pm","version":"6.78"},"LWP::Protocol::file":{"file":"lib/LWP/Protocol/file.pm","version":"6.78"},"LWP::Debug":{"file":"lib/LWP/Debug.pm","x_deprecated":1,"version":"6.78"},"LWP::DebugFile":{"version":"6.78","file":"lib/LWP/DebugFile.pm"},"LWP::Protocol::ftp":{"version":"6.78","file":"lib/LWP/Protocol/ftp.pm"},"LWP::Simple":{"version":"6.78","file":"lib/LWP/Simple.pm"},"LWP::Protocol::data":{"version":"6.78","file":"lib/LWP/Protocol/data.pm"},"LWP::Protocol::http":{"version":"6.78","file":"lib/LWP/Protocol/http.pm"},"LWP::Protocol::mailto":{"file":"lib/LWP/Protocol/mailto.pm","version":"6.78"},"LWP::Protocol::nntp":{"version":"6.78","file":"lib/LWP/Protocol/nntp.pm"},"LWP::Authen::Basic":{"version":"6.78","file":"lib/LWP/Authen/Basic.pm"},"LWP::Protocol":{"version":"6.78","file":"lib/LWP/Protocol.pm"},"LWP::MemberMixin":{"version":"6.78","file":"lib/LWP/MemberMixin.pm"},"LWP::Protocol::gopher":{"file":"lib/LWP/Protocol/gopher.pm","version":"6.78"},"LWP::UserAgent":{"file":"lib/LWP/UserAgent.pm","version":"6.78"},"LWP::Debug::TraceHTTP":{"version":"6.78","file":"lib/LWP/Debug/TraceHTTP.pm"},"LWP::Protocol::loopback":{"version":"6.78","file":"lib/LWP/Protocol/loopback.pm"}},"version":"6.78"}PK2N%[R�<��@perl5/x86_64-linux-thread-multi/.meta/version-0.9933/MYMETA.jsonnu��6�${
   "abstract" : "Structured version objects",
   "author" : [
      "John Peacock <jpeacock@cpan.org>"
   ],
   "dynamic_config" : 0,
   "generated_by" : "ExtUtils::MakeMaker version 7.70, CPAN::Meta::Converter version 2.150010",
   "license" : [
      "perl_5"
   ],
   "meta-spec" : {
      "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
      "version" : 2
   },
   "name" : "version",
   "no_index" : {
      "directory" : [
         "t",
         "inc"
      ],
      "package" : [
         "charstar"
      ]
   },
   "prereqs" : {
      "build" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "configure" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "runtime" : {
         "requires" : {
            "perl" : "5.006002"
         }
      },
      "test" : {
         "requires" : {
            "File::Temp" : "0.13",
            "Test::More" : "0.45",
            "base" : "0"
         }
      }
   },
   "release_status" : "stable",
   "resources" : {
      "bugtracker" : {
         "mailto" : "bug-version@rt.cpan.org",
         "web" : "https://rt.cpan.org/Public/Dist/Display.html?Name=version"
      },
      "repository" : {
         "type" : "git",
         "url" : "git://github.com/Perl/version.pm.git",
         "web" : "https://github.com/Perl/version.pm"
      }
   },
   "version" : "0.9933",
   "x_serialization_backend" : "JSON::PP version 2.97001"
}
PK2N%[5:��||Aperl5/x86_64-linux-thread-multi/.meta/version-0.9933/install.jsonnu��6�${"dist":"version-0.9933","version":0.9933,"name":"version","pathname":"L/LE/LEONT/version-0.9933.tar.gz","target":"version","provides":{"version":{"file":"lib/version.pm","version":0.9933},"version::vxs":{"file":"vutil/lib/version/vxs.pm","version":0.9933},"version::regex":{"version":0.9933,"file":"lib/version/regex.pm"},"version::vpp":{"version":0.9933,"file":"vperl/vpp.pm"}}}PK2N%[{�9����?perl5/x86_64-linux-thread-multi/.meta/Try-Tiny-0.32/MYMETA.jsonnu��6�${
   "abstract" : "Minimal try/catch with proper preservation of $@",
   "author" : [
      "יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org>",
      "Jesse Luehrs <doy@tozt.net>"
   ],
   "dynamic_config" : 0,
   "generated_by" : "Dist::Zilla version 6.032, CPAN::Meta::Converter version 2.150010",
   "license" : [
      "mit"
   ],
   "meta-spec" : {
      "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
      "version" : 2
   },
   "name" : "Try-Tiny",
   "no_index" : {
      "directory" : [
         "t",
         "xt"
      ]
   },
   "prereqs" : {
      "build" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "configure" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         },
         "suggests" : {
            "JSON::PP" : "2.27300"
         }
      },
      "develop" : {
         "recommends" : {
            "Dist::Zilla::PluginBundle::Author::ETHER" : "0.163",
            "Dist::Zilla::PluginBundle::Git::VersionManager" : "0.007"
         },
         "requires" : {
            "Capture::Tiny" : "0.12",
            "Encode" : "0",
            "File::Spec" : "0",
            "IO::Handle" : "0",
            "IPC::Open3" : "0",
            "Pod::Coverage::TrustPod" : "0",
            "Pod::Wordlist" : "0",
            "Sub::Name" : "0.08",
            "Sub::Util" : "0",
            "Test::CPAN::Changes" : "0.19",
            "Test::CPAN::Meta" : "0",
            "Test::EOL" : "0",
            "Test::Kwalitee" : "1.21",
            "Test::MinimumVersion" : "0",
            "Test::Mojibake" : "0",
            "Test::More" : "0.96",
            "Test::NoTabs" : "0",
            "Test::Pod" : "1.41",
            "Test::Pod::Coverage" : "1.08",
            "Test::Pod::No404s" : "0",
            "Test::Portability::Files" : "0",
            "Test::Spelling" : "0.12"
         }
      },
      "runtime" : {
         "requires" : {
            "Carp" : "0",
            "Exporter" : "5.57",
            "constant" : "0",
            "perl" : "5.006",
            "strict" : "0",
            "warnings" : "0"
         },
         "suggests" : {
            "Sub::Name" : "0.08",
            "Sub::Util" : "0"
         }
      },
      "test" : {
         "recommends" : {
            "CPAN::Meta" : "2.120900"
         },
         "requires" : {
            "ExtUtils::MakeMaker" : "0",
            "File::Spec" : "0",
            "Test::More" : "0",
            "if" : "0"
         },
         "suggests" : {
            "CPAN::Meta::Check" : "0.011",
            "CPAN::Meta::Requirements" : "0",
            "Capture::Tiny" : "0.12"
         }
      },
      "x_Dist_Zilla" : {
         "requires" : {
            "Dist::Zilla" : "5",
            "Dist::Zilla::Plugin::Authority" : "1.009",
            "Dist::Zilla::Plugin::AutoMetaResources" : "0",
            "Dist::Zilla::Plugin::AutoPrereqs" : "5.038",
            "Dist::Zilla::Plugin::Breaks" : "0",
            "Dist::Zilla::Plugin::BumpVersionAfterRelease::Transitional" : "0.004",
            "Dist::Zilla::Plugin::CheckIssues" : "0",
            "Dist::Zilla::Plugin::CheckMetaResources" : "0",
            "Dist::Zilla::Plugin::CheckPrereqsIndexed" : "0.019",
            "Dist::Zilla::Plugin::CheckSelfDependency" : "0",
            "Dist::Zilla::Plugin::CheckStrictVersion" : "0",
            "Dist::Zilla::Plugin::ConfirmRelease" : "0",
            "Dist::Zilla::Plugin::CopyFilesFromRelease" : "0",
            "Dist::Zilla::Plugin::EnsureLatestPerl" : "0",
            "Dist::Zilla::Plugin::FileFinder::ByName" : "0",
            "Dist::Zilla::Plugin::FileFinder::Filter" : "0",
            "Dist::Zilla::Plugin::GenerateFile::FromShareDir" : "0",
            "Dist::Zilla::Plugin::Git::Check" : "0",
            "Dist::Zilla::Plugin::Git::CheckFor::CorrectBranch" : "0.004",
            "Dist::Zilla::Plugin::Git::CheckFor::MergeConflicts" : "0",
            "Dist::Zilla::Plugin::Git::Commit" : "2.020",
            "Dist::Zilla::Plugin::Git::Contributors" : "0.029",
            "Dist::Zilla::Plugin::Git::Describe" : "0.004",
            "Dist::Zilla::Plugin::Git::GatherDir" : "2.016",
            "Dist::Zilla::Plugin::Git::Push" : "0",
            "Dist::Zilla::Plugin::Git::Remote::Check" : "0",
            "Dist::Zilla::Plugin::Git::Tag" : "0",
            "Dist::Zilla::Plugin::GitHub::Update" : "0.40",
            "Dist::Zilla::Plugin::GithubMeta" : "0.54",
            "Dist::Zilla::Plugin::InstallGuide" : "1.200005",
            "Dist::Zilla::Plugin::Keywords" : "0.004",
            "Dist::Zilla::Plugin::License" : "5.038",
            "Dist::Zilla::Plugin::MakeMaker" : "0",
            "Dist::Zilla::Plugin::Manifest" : "0",
            "Dist::Zilla::Plugin::MetaConfig" : "0",
            "Dist::Zilla::Plugin::MetaJSON" : "0",
            "Dist::Zilla::Plugin::MetaNoIndex" : "0",
            "Dist::Zilla::Plugin::MetaProvides::Package" : "1.15000002",
            "Dist::Zilla::Plugin::MetaTests" : "0",
            "Dist::Zilla::Plugin::MetaYAML" : "0",
            "Dist::Zilla::Plugin::MinimumPerl" : "1.006",
            "Dist::Zilla::Plugin::MojibakeTests" : "0.8",
            "Dist::Zilla::Plugin::NextRelease" : "5.033",
            "Dist::Zilla::Plugin::OnlyCorePrereqs" : "0",
            "Dist::Zilla::Plugin::PodCoverageTests" : "5.040",
            "Dist::Zilla::Plugin::PodSyntaxTests" : "5.040",
            "Dist::Zilla::Plugin::PodWeaver" : "4.008",
            "Dist::Zilla::Plugin::Prereqs" : "0",
            "Dist::Zilla::Plugin::Prereqs::AuthorDeps" : "0.006",
            "Dist::Zilla::Plugin::Prereqs::Soften" : "0",
            "Dist::Zilla::Plugin::PromptIfStale" : "0",
            "Dist::Zilla::Plugin::Readme" : "0",
            "Dist::Zilla::Plugin::ReadmeAnyFromPod" : "0.142180",
            "Dist::Zilla::Plugin::RewriteVersion::Transitional" : "0.006",
            "Dist::Zilla::Plugin::Run::AfterBuild" : "0.041",
            "Dist::Zilla::Plugin::Run::AfterRelease" : "0.038",
            "Dist::Zilla::Plugin::RunExtraTests" : "0.024",
            "Dist::Zilla::Plugin::StaticInstall" : "0.005",
            "Dist::Zilla::Plugin::Substitute" : "0",
            "Dist::Zilla::Plugin::Test::CPAN::Changes" : "0.012",
            "Dist::Zilla::Plugin::Test::ChangesHasContent" : "0",
            "Dist::Zilla::Plugin::Test::CheckBreaks" : "0.018",
            "Dist::Zilla::Plugin::Test::Compile" : "2.039",
            "Dist::Zilla::Plugin::Test::EOL" : "0.17",
            "Dist::Zilla::Plugin::Test::Kwalitee" : "2.10",
            "Dist::Zilla::Plugin::Test::MinimumVersion" : "2.000010",
            "Dist::Zilla::Plugin::Test::NoTabs" : "0.08",
            "Dist::Zilla::Plugin::Test::Pod::No404s" : "1.003",
            "Dist::Zilla::Plugin::Test::PodSpelling" : "2.006003",
            "Dist::Zilla::Plugin::Test::Portability" : "2.000007",
            "Dist::Zilla::Plugin::Test::ReportPrereqs" : "0.022",
            "Dist::Zilla::Plugin::TestRelease" : "0",
            "Dist::Zilla::Plugin::UploadToCPAN" : "0",
            "Dist::Zilla::Plugin::UseUnsafeInc" : "0",
            "Dist::Zilla::PluginBundle::Author::ETHER" : "0.136",
            "Dist::Zilla::PluginBundle::Git::VersionManager" : "0.007",
            "Software::License::MIT" : "0"
         }
      }
   },
   "provides" : {
      "Try::Tiny" : {
         "file" : "lib/Try/Tiny.pm",
         "version" : "0.32"
      }
   },
   "release_status" : "stable",
   "resources" : {
      "bugtracker" : {
         "mailto" : "bug-Try-Tiny@rt.cpan.org",
         "web" : "https://rt.cpan.org/Public/Dist/Display.html?Name=Try-Tiny"
      },
      "homepage" : "https://github.com/p5sagit/Try-Tiny",
      "repository" : {
         "type" : "git",
         "url" : "https://github.com/p5sagit/Try-Tiny.git",
         "web" : "https://github.com/p5sagit/Try-Tiny"
      }
   },
   "version" : "0.32",
   "x_Dist_Zilla" : {
      "perl" : {
         "version" : "5.041002"
      },
      "plugins" : [
         {
            "class" : "Dist::Zilla::Plugin::FileFinder::Filter",
            "name" : "all_files_but_using_5.10_features",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::Prereqs",
            "config" : {
               "Dist::Zilla::Plugin::Prereqs" : {
                  "phase" : "develop",
                  "type" : "recommends"
               }
            },
            "name" : "@Author::ETHER/pluginbundle version",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::PromptIfStale",
            "config" : {
               "Dist::Zilla::Plugin::PromptIfStale" : {
                  "check_all_plugins" : 0,
                  "check_all_prereqs" : 0,
                  "modules" : [
                     "Dist::Zilla::PluginBundle::Author::ETHER"
                  ],
                  "phase" : "build",
                  "run_under_travis" : 0,
                  "skip" : []
               }
            },
            "name" : "@Author::ETHER/stale modules, build",
            "version" : "0.060"
         },
         {
            "class" : "Dist::Zilla::Plugin::FileFinder::ByName",
            "name" : "@Author::ETHER/Examples",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::GatherDir",
            "config" : {
               "Dist::Zilla::Plugin::GatherDir" : {
                  "exclude_filename" : [
                     "CONTRIBUTING",
                     "INSTALL",
                     "LICENCE",
                     "README.pod"
                  ],
                  "exclude_match" : [],
                  "include_dotfiles" : 0,
                  "prefix" : "",
                  "prune_directory" : [],
                  "root" : "."
               },
               "Dist::Zilla::Plugin::Git::GatherDir" : {
                  "include_untracked" : 0
               }
            },
            "name" : "@Author::ETHER/Git::GatherDir",
            "version" : "2.051"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaYAML",
            "name" : "@Author::ETHER/MetaYAML",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaJSON",
            "name" : "@Author::ETHER/MetaJSON",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::Readme",
            "name" : "@Author::ETHER/Readme",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::Manifest",
            "name" : "@Author::ETHER/Manifest",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::License",
            "name" : "@Author::ETHER/License",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::GenerateFile::FromShareDir",
            "config" : {
               "Dist::Zilla::Plugin::GenerateFile::FromShareDir" : {
                  "destination_filename" : "CONTRIBUTING",
                  "dist" : "Dist-Zilla-PluginBundle-Author-ETHER",
                  "encoding" : "UTF-8",
                  "has_xs" : 0,
                  "location" : "build",
                  "source_filename" : "CONTRIBUTING"
               },
               "Dist::Zilla::Role::RepoFileInjector" : {
                  "allow_overwrite" : 1,
                  "repo_root" : ".",
                  "version" : "0.009"
               }
            },
            "name" : "@Author::ETHER/generate CONTRIBUTING",
            "version" : "0.015"
         },
         {
            "class" : "Dist::Zilla::Plugin::InstallGuide",
            "config" : {
               "Dist::Zilla::Role::ModuleMetadata" : {
                  "Module::Metadata" : "1.000038",
                  "version" : "0.006"
               }
            },
            "name" : "@Author::ETHER/InstallGuide",
            "version" : "1.200014"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::Compile",
            "config" : {
               "Dist::Zilla::Plugin::Test::Compile" : {
                  "bail_out_on_fail" : 1,
                  "fail_on_warning" : "author",
                  "fake_home" : 0,
                  "filename" : "xt/author/00-compile.t",
                  "module_finder" : [
                     ":InstallModules"
                  ],
                  "needs_display" : 0,
                  "phase" : "develop",
                  "script_finder" : [
                     ":PerlExecFiles",
                     "@Author::ETHER/Examples"
                  ],
                  "skips" : [],
                  "switch" : []
               }
            },
            "name" : "@Author::ETHER/Test::Compile",
            "version" : "2.058"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::NoTabs",
            "config" : {
               "Dist::Zilla::Plugin::Test::NoTabs" : {
                  "filename" : "xt/author/no-tabs.t",
                  "finder" : [
                     ":InstallModules",
                     ":ExecFiles",
                     "@Author::ETHER/Examples",
                     ":TestFiles",
                     ":ExtraTestFiles"
                  ]
               }
            },
            "name" : "@Author::ETHER/Test::NoTabs",
            "version" : "0.15"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::EOL",
            "config" : {
               "Dist::Zilla::Plugin::Test::EOL" : {
                  "filename" : "xt/author/eol.t",
                  "finder" : [
                     ":ExecFiles",
                     ":ExtraTestFiles",
                     ":InstallModules",
                     ":TestFiles",
                     "@Author::ETHER/Examples"
                  ],
                  "trailing_whitespace" : 1
               }
            },
            "name" : "@Author::ETHER/Test::EOL",
            "version" : "0.19"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaTests",
            "name" : "@Author::ETHER/MetaTests",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::CPAN::Changes",
            "config" : {
               "Dist::Zilla::Plugin::Test::CPAN::Changes" : {
                  "changelog" : "Changes"
               }
            },
            "name" : "@Author::ETHER/Test::CPAN::Changes",
            "version" : "0.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::ChangesHasContent",
            "name" : "@Author::ETHER/Test::ChangesHasContent",
            "version" : "0.011"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::MinimumVersion",
            "config" : {
               "Dist::Zilla::Plugin::Test::MinimumVersion" : {
                  "max_target_perl" : "5.006"
               }
            },
            "name" : "@Author::ETHER/Test::MinimumVersion",
            "version" : "2.000010"
         },
         {
            "class" : "Dist::Zilla::Plugin::PodSyntaxTests",
            "name" : "@Author::ETHER/PodSyntaxTests",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::PodCoverageTests",
            "name" : "@Author::ETHER/PodCoverageTests",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::PodSpelling",
            "config" : {
               "Dist::Zilla::Plugin::Test::PodSpelling" : {
                  "directories" : [
                     "examples",
                     "lib",
                     "script",
                     "t",
                     "xt"
                  ],
                  "spell_cmd" : "",
                  "stopwords" : [
                     "irc"
                  ],
                  "wordlist" : "Pod::Wordlist"
               }
            },
            "name" : "@Author::ETHER/Test::PodSpelling",
            "version" : "2.007005"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::Pod::No404s",
            "name" : "@Author::ETHER/Test::Pod::No404s",
            "version" : "1.004"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::Kwalitee",
            "config" : {
               "Dist::Zilla::Plugin::Test::Kwalitee" : {
                  "filename" : "xt/author/kwalitee.t",
                  "skiptest" : []
               }
            },
            "name" : "@Author::ETHER/Test::Kwalitee",
            "version" : "2.12"
         },
         {
            "class" : "Dist::Zilla::Plugin::MojibakeTests",
            "name" : "@Author::ETHER/MojibakeTests",
            "version" : "0.8"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::ReportPrereqs",
            "name" : "@Author::ETHER/Test::ReportPrereqs",
            "version" : "0.029"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::Portability",
            "config" : {
               "Dist::Zilla::Plugin::Test::Portability" : {
                  "options" : ""
               }
            },
            "name" : "@Author::ETHER/Test::Portability",
            "version" : "2.001001"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::Describe",
            "name" : "@Author::ETHER/Git::Describe",
            "version" : "0.008"
         },
         {
            "class" : "Dist::Zilla::Plugin::PodWeaver",
            "config" : {
               "Dist::Zilla::Plugin::PodWeaver" : {
                  "config_plugins" : [
                     "@Author::ETHER"
                  ],
                  "finder" : [
                     ":InstallModules",
                     ":PerlExecFiles"
                  ],
                  "plugins" : [
                     {
                        "class" : "Pod::Weaver::Plugin::EnsurePod5",
                        "name" : "@Author::ETHER/EnsurePod5",
                        "version" : "4.020"
                     },
                     {
                        "class" : "Pod::Weaver::Plugin::H1Nester",
                        "name" : "@Author::ETHER/H1Nester",
                        "version" : "4.020"
                     },
                     {
                        "class" : "Pod::Weaver::Plugin::SingleEncoding",
                        "name" : "@Author::ETHER/SingleEncoding",
                        "version" : "4.020"
                     },
                     {
                        "class" : "Pod::Weaver::Plugin::Transformer",
                        "name" : "@Author::ETHER/List",
                        "version" : "4.020"
                     },
                     {
                        "class" : "Pod::Weaver::Plugin::Transformer",
                        "name" : "@Author::ETHER/Verbatim",
                        "version" : "4.020"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Region",
                        "name" : "@Author::ETHER/header",
                        "version" : "4.020"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Name",
                        "name" : "@Author::ETHER/Name",
                        "version" : "4.020"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Version",
                        "name" : "@Author::ETHER/Version",
                        "version" : "4.020"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Region",
                        "name" : "@Author::ETHER/prelude",
                        "version" : "4.020"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Generic",
                        "name" : "SYNOPSIS",
                        "version" : "4.020"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Generic",
                        "name" : "DESCRIPTION",
                        "version" : "4.020"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Generic",
                        "name" : "OVERVIEW",
                        "version" : "4.020"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Collect",
                        "name" : "ATTRIBUTES",
                        "version" : "4.020"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Collect",
                        "name" : "METHODS",
                        "version" : "4.020"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Collect",
                        "name" : "FUNCTIONS",
                        "version" : "4.020"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Collect",
                        "name" : "TYPES",
                        "version" : "4.020"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Leftovers",
                        "name" : "@Author::ETHER/Leftovers",
                        "version" : "4.020"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Region",
                        "name" : "@Author::ETHER/postlude",
                        "version" : "4.020"
                     },
                     {
                        "class" : "Pod::Weaver::Section::GenerateSection",
                        "name" : "@Author::ETHER/generate SUPPORT",
                        "version" : "4.020"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Authors",
                        "name" : "@Author::ETHER/Authors",
                        "version" : "4.020"
                     },
                     {
                        "class" : "Pod::Weaver::Section::AllowOverride",
                        "name" : "@Author::ETHER/allow override AUTHOR",
                        "version" : "0.05"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Contributors",
                        "name" : "@Author::ETHER/Contributors",
                        "version" : "0.009"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Legal",
                        "name" : "@Author::ETHER/Legal",
                        "version" : "4.020"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Region",
                        "name" : "@Author::ETHER/footer",
                        "version" : "4.020"
                     }
                  ]
               }
            },
            "name" : "@Author::ETHER/PodWeaver",
            "version" : "4.010"
         },
         {
            "class" : "Dist::Zilla::Plugin::GithubMeta",
            "name" : "@Author::ETHER/GithubMeta",
            "version" : "0.58"
         },
         {
            "class" : "Dist::Zilla::Plugin::AutoMetaResources",
            "name" : "@Author::ETHER/AutoMetaResources",
            "version" : "1.21"
         },
         {
            "class" : "Dist::Zilla::Plugin::Authority",
            "name" : "@Author::ETHER/Authority",
            "version" : "1.009"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaNoIndex",
            "name" : "@Author::ETHER/MetaNoIndex",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaProvides::Package",
            "config" : {
               "Dist::Zilla::Plugin::MetaProvides::Package" : {
                  "finder" : [
                     ":InstallModules"
                  ],
                  "finder_objects" : [
                     {
                        "class" : "Dist::Zilla::Plugin::FinderCode",
                        "name" : ":InstallModules",
                        "version" : "6.032"
                     }
                  ],
                  "include_underscores" : 0
               },
               "Dist::Zilla::Role::MetaProvider::Provider" : {
                  "$Dist::Zilla::Role::MetaProvider::Provider::VERSION" : "2.002004",
                  "inherit_missing" : 0,
                  "inherit_version" : 0,
                  "meta_noindex" : 1
               },
               "Dist::Zilla::Role::ModuleMetadata" : {
                  "Module::Metadata" : "1.000038",
                  "version" : "0.006"
               }
            },
            "name" : "@Author::ETHER/MetaProvides::Package",
            "version" : "2.004003"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaConfig",
            "name" : "@Author::ETHER/MetaConfig",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::Keywords",
            "config" : {
               "Dist::Zilla::Plugin::Keywords" : {
                  "keywords" : []
               }
            },
            "name" : "@Author::ETHER/Keywords",
            "version" : "0.007"
         },
         {
            "class" : "Dist::Zilla::Plugin::UseUnsafeInc",
            "config" : {
               "Dist::Zilla::Plugin::UseUnsafeInc" : {
                  "dot_in_INC" : 0
               }
            },
            "name" : "@Author::ETHER/UseUnsafeInc",
            "version" : "0.002"
         },
         {
            "class" : "Dist::Zilla::Plugin::AutoPrereqs",
            "name" : "@Author::ETHER/AutoPrereqs",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::Prereqs::AuthorDeps",
            "name" : "@Author::ETHER/Prereqs::AuthorDeps",
            "version" : "0.007"
         },
         {
            "class" : "Dist::Zilla::Plugin::MinimumPerl",
            "name" : "@Author::ETHER/MinimumPerl",
            "version" : "1.006"
         },
         {
            "class" : "Dist::Zilla::Plugin::MakeMaker",
            "config" : {
               "Dist::Zilla::Role::TestRunner" : {
                  "default_jobs" : 9
               }
            },
            "name" : "@Author::ETHER/MakeMaker",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::Contributors",
            "config" : {
               "Dist::Zilla::Plugin::Git::Contributors" : {
                  "git_version" : "2.45.2",
                  "include_authors" : 0,
                  "include_releaser" : 1,
                  "order_by" : "commits",
                  "paths" : []
               }
            },
            "name" : "@Author::ETHER/Git::Contributors",
            "version" : "0.037"
         },
         {
            "class" : "Dist::Zilla::Plugin::StaticInstall",
            "config" : {
               "Dist::Zilla::Plugin::StaticInstall" : {
                  "dry_run" : 1,
                  "mode" : "auto"
               }
            },
            "name" : "@Author::ETHER/StaticInstall",
            "version" : "0.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::RunExtraTests",
            "config" : {
               "Dist::Zilla::Role::TestRunner" : {
                  "default_jobs" : 9
               }
            },
            "name" : "@Author::ETHER/RunExtraTests",
            "version" : "0.029"
         },
         {
            "class" : "Dist::Zilla::Plugin::CheckSelfDependency",
            "config" : {
               "Dist::Zilla::Plugin::CheckSelfDependency" : {
                  "finder" : [
                     ":InstallModules"
                  ]
               },
               "Dist::Zilla::Role::ModuleMetadata" : {
                  "Module::Metadata" : "1.000038",
                  "version" : "0.006"
               }
            },
            "name" : "@Author::ETHER/CheckSelfDependency",
            "version" : "0.011"
         },
         {
            "class" : "Dist::Zilla::Plugin::Run::AfterBuild",
            "config" : {
               "Dist::Zilla::Plugin::Run::Role::Runner" : {
                  "fatal_errors" : 1,
                  "quiet" : 1,
                  "run" : [
                     "bash -c \"test -e .ackrc && grep -q -- '--ignore-dir=.latest' .ackrc || echo '--ignore-dir=.latest' >> .ackrc; if [[ `dirname '%d'` != .build ]]; then test -e .ackrc && grep -q -- '--ignore-dir=%d' .ackrc || echo '--ignore-dir=%d' >> .ackrc; fi\""
                  ],
                  "version" : "0.050"
               }
            },
            "name" : "@Author::ETHER/.ackrc",
            "version" : "0.050"
         },
         {
            "class" : "Dist::Zilla::Plugin::Run::AfterBuild",
            "config" : {
               "Dist::Zilla::Plugin::Run::Role::Runner" : {
                  "eval" : [
                     "if ('%d' =~ /^%n-[.[:xdigit:]]+$/) { unlink '.latest'; symlink '%d', '.latest'; }"
                  ],
                  "fatal_errors" : 0,
                  "quiet" : 1,
                  "version" : "0.050"
               }
            },
            "name" : "@Author::ETHER/.latest",
            "version" : "0.050"
         },
         {
            "class" : "Dist::Zilla::Plugin::CheckStrictVersion",
            "name" : "@Author::ETHER/CheckStrictVersion",
            "version" : "0.001"
         },
         {
            "class" : "Dist::Zilla::Plugin::CheckMetaResources",
            "name" : "@Author::ETHER/CheckMetaResources",
            "version" : "0.001"
         },
         {
            "class" : "Dist::Zilla::Plugin::EnsureLatestPerl",
            "config" : {
               "Dist::Zilla::Plugin::EnsureLatestPerl" : {
                  "Module::CoreList" : "5.20240720"
               }
            },
            "name" : "@Author::ETHER/EnsureLatestPerl",
            "version" : "0.010"
         },
         {
            "class" : "Dist::Zilla::Plugin::PromptIfStale",
            "config" : {
               "Dist::Zilla::Plugin::PromptIfStale" : {
                  "check_all_plugins" : 1,
                  "check_all_prereqs" : 1,
                  "modules" : [],
                  "phase" : "release",
                  "run_under_travis" : 0,
                  "skip" : []
               }
            },
            "name" : "@Author::ETHER/stale modules, release",
            "version" : "0.060"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::Check",
            "config" : {
               "Dist::Zilla::Plugin::Git::Check" : {
                  "untracked_files" : "die"
               },
               "Dist::Zilla::Role::Git::DirtyFiles" : {
                  "allow_dirty" : [],
                  "allow_dirty_match" : [],
                  "changelog" : "Changes"
               },
               "Dist::Zilla::Role::Git::Repo" : {
                  "git_version" : "2.45.2",
                  "repo_root" : "."
               }
            },
            "name" : "@Author::ETHER/initial check",
            "version" : "2.051"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::CheckFor::MergeConflicts",
            "config" : {
               "Dist::Zilla::Role::Git::Repo" : {
                  "git_version" : "2.45.2",
                  "repo_root" : "."
               }
            },
            "name" : "@Author::ETHER/Git::CheckFor::MergeConflicts",
            "version" : "0.014"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::CheckFor::CorrectBranch",
            "config" : {
               "Dist::Zilla::Role::Git::Repo" : {
                  "git_version" : "2.45.2",
                  "repo_root" : "."
               }
            },
            "name" : "@Author::ETHER/Git::CheckFor::CorrectBranch",
            "version" : "0.014"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::Remote::Check",
            "name" : "@Author::ETHER/Git::Remote::Check",
            "version" : "0.1.2"
         },
         {
            "class" : "Dist::Zilla::Plugin::CheckPrereqsIndexed",
            "name" : "@Author::ETHER/CheckPrereqsIndexed",
            "version" : "0.022"
         },
         {
            "class" : "Dist::Zilla::Plugin::TestRelease",
            "name" : "@Author::ETHER/TestRelease",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::Check",
            "config" : {
               "Dist::Zilla::Plugin::Git::Check" : {
                  "untracked_files" : "die"
               },
               "Dist::Zilla::Role::Git::DirtyFiles" : {
                  "allow_dirty" : [],
                  "allow_dirty_match" : [],
                  "changelog" : "Changes"
               },
               "Dist::Zilla::Role::Git::Repo" : {
                  "git_version" : "2.45.2",
                  "repo_root" : "."
               }
            },
            "name" : "@Author::ETHER/after tests",
            "version" : "2.051"
         },
         {
            "class" : "Dist::Zilla::Plugin::CheckIssues",
            "name" : "@Author::ETHER/CheckIssues",
            "version" : "0.011"
         },
         {
            "class" : "Dist::Zilla::Plugin::UploadToCPAN",
            "name" : "@Author::ETHER/UploadToCPAN",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::CopyFilesFromRelease",
            "config" : {
               "Dist::Zilla::Plugin::CopyFilesFromRelease" : {
                  "filename" : [
                     "CONTRIBUTING",
                     "INSTALL",
                     "LICENCE",
                     "LICENSE",
                     "ppport.h"
                  ],
                  "match" : []
               }
            },
            "name" : "@Author::ETHER/copy generated files",
            "version" : "0.007"
         },
         {
            "class" : "Dist::Zilla::Plugin::ReadmeAnyFromPod",
            "config" : {
               "Dist::Zilla::Role::FileWatcher" : {
                  "version" : "0.006"
               }
            },
            "name" : "@Author::ETHER/ReadmeAnyFromPod",
            "version" : "0.163250"
         },
         {
            "class" : "Dist::Zilla::Plugin::Prereqs",
            "config" : {
               "Dist::Zilla::Plugin::Prereqs" : {
                  "phase" : "develop",
                  "type" : "recommends"
               }
            },
            "name" : "@Author::ETHER/@Git::VersionManager/pluginbundle version",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::RewriteVersion::Transitional",
            "config" : {
               "Dist::Zilla::Plugin::RewriteVersion" : {
                  "add_tarball_name" : 0,
                  "finders" : [
                     ":ExecFiles",
                     ":InstallModules"
                  ],
                  "global" : 1,
                  "skip_version_provider" : 0
               },
               "Dist::Zilla::Plugin::RewriteVersion::Transitional" : {}
            },
            "name" : "@Author::ETHER/@Git::VersionManager/RewriteVersion::Transitional",
            "version" : "0.009"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaProvides::Update",
            "name" : "@Author::ETHER/@Git::VersionManager/MetaProvides::Update",
            "version" : "0.007"
         },
         {
            "class" : "Dist::Zilla::Plugin::CopyFilesFromRelease",
            "config" : {
               "Dist::Zilla::Plugin::CopyFilesFromRelease" : {
                  "filename" : [
                     "Changes"
                  ],
                  "match" : []
               }
            },
            "name" : "@Author::ETHER/@Git::VersionManager/CopyFilesFromRelease",
            "version" : "0.007"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::Commit",
            "config" : {
               "Dist::Zilla::Plugin::Git::Commit" : {
                  "add_files_in" : [
                     "."
                  ],
                  "commit_msg" : "%N-%v%t%n%n%c",
                  "signoff" : 0
               },
               "Dist::Zilla::Role::Git::DirtyFiles" : {
                  "allow_dirty" : [
                     "CONTRIBUTING",
                     "Changes",
                     "INSTALL",
                     "LICENCE",
                     "README.pod"
                  ],
                  "allow_dirty_match" : [],
                  "changelog" : "Changes"
               },
               "Dist::Zilla::Role::Git::Repo" : {
                  "git_version" : "2.45.2",
                  "repo_root" : "."
               },
               "Dist::Zilla::Role::Git::StringFormatter" : {
                  "time_zone" : "local"
               }
            },
            "name" : "@Author::ETHER/@Git::VersionManager/release snapshot",
            "version" : "2.051"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::Tag",
            "config" : {
               "Dist::Zilla::Plugin::Git::Tag" : {
                  "branch" : null,
                  "changelog" : "Changes",
                  "signed" : 0,
                  "tag" : "v0.32",
                  "tag_format" : "v%V",
                  "tag_message" : "v%v%t"
               },
               "Dist::Zilla::Role::Git::Repo" : {
                  "git_version" : "2.45.2",
                  "repo_root" : "."
               },
               "Dist::Zilla::Role::Git::StringFormatter" : {
                  "time_zone" : "local"
               }
            },
            "name" : "@Author::ETHER/@Git::VersionManager/Git::Tag",
            "version" : "2.051"
         },
         {
            "class" : "Dist::Zilla::Plugin::BumpVersionAfterRelease::Transitional",
            "config" : {
               "Dist::Zilla::Plugin::BumpVersionAfterRelease" : {
                  "finders" : [
                     ":InstallModules"
                  ],
                  "global" : 1,
                  "munge_makefile_pl" : 1
               },
               "Dist::Zilla::Plugin::BumpVersionAfterRelease::Transitional" : {}
            },
            "name" : "@Author::ETHER/@Git::VersionManager/BumpVersionAfterRelease::Transitional",
            "version" : "0.009"
         },
         {
            "class" : "Dist::Zilla::Plugin::NextRelease",
            "name" : "@Author::ETHER/@Git::VersionManager/NextRelease",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::Commit",
            "config" : {
               "Dist::Zilla::Plugin::Git::Commit" : {
                  "add_files_in" : [],
                  "commit_msg" : "increment $VERSION after %v release",
                  "signoff" : 0
               },
               "Dist::Zilla::Role::Git::DirtyFiles" : {
                  "allow_dirty" : [
                     "Build.PL",
                     "Changes",
                     "Makefile.PL"
                  ],
                  "allow_dirty_match" : [
                     "(?^:^lib/.*\\.pm$)"
                  ],
                  "changelog" : "Changes"
               },
               "Dist::Zilla::Role::Git::Repo" : {
                  "git_version" : "2.45.2",
                  "repo_root" : "."
               },
               "Dist::Zilla::Role::Git::StringFormatter" : {
                  "time_zone" : "local"
               }
            },
            "name" : "@Author::ETHER/@Git::VersionManager/post-release commit",
            "version" : "2.051"
         },
         {
            "class" : "Dist::Zilla::Plugin::Prereqs",
            "config" : {
               "Dist::Zilla::Plugin::Prereqs" : {
                  "phase" : "x_Dist_Zilla",
                  "type" : "requires"
               }
            },
            "name" : "@Author::ETHER/@Git::VersionManager/prereqs for @Git::VersionManager",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::Push",
            "config" : {
               "Dist::Zilla::Plugin::Git::Push" : {
                  "push_to" : [
                     "origin"
                  ],
                  "remotes_must_exist" : 1
               },
               "Dist::Zilla::Role::Git::Repo" : {
                  "git_version" : "2.45.2",
                  "repo_root" : "."
               }
            },
            "name" : "@Author::ETHER/Git::Push",
            "version" : "2.051"
         },
         {
            "class" : "Dist::Zilla::Plugin::GitHub::Update",
            "config" : {
               "Dist::Zilla::Plugin::GitHub::Update" : {
                  "metacpan" : 1
               }
            },
            "name" : "@Author::ETHER/GitHub::Update",
            "version" : "0.49"
         },
         {
            "class" : "Dist::Zilla::Plugin::Run::AfterRelease",
            "config" : {
               "Dist::Zilla::Plugin::Run::Role::Runner" : {
                  "fatal_errors" : 0,
                  "quiet" : 0,
                  "run" : [
                     "REDACTED"
                  ],
                  "version" : "0.050"
               }
            },
            "name" : "@Author::ETHER/install release",
            "version" : "0.050"
         },
         {
            "class" : "Dist::Zilla::Plugin::Run::AfterRelease",
            "config" : {
               "Dist::Zilla::Plugin::Run::Role::Runner" : {
                  "eval" : [
                     "print \"release complete!\\xa\""
                  ],
                  "fatal_errors" : 1,
                  "quiet" : 1,
                  "version" : "0.050"
               }
            },
            "name" : "@Author::ETHER/release complete",
            "version" : "0.050"
         },
         {
            "class" : "Dist::Zilla::Plugin::ConfirmRelease",
            "name" : "@Author::ETHER/ConfirmRelease",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::Prereqs",
            "config" : {
               "Dist::Zilla::Plugin::Prereqs" : {
                  "phase" : "x_Dist_Zilla",
                  "type" : "requires"
               }
            },
            "name" : "@Author::ETHER/prereqs for @Author::ETHER",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::Substitute",
            "name" : "Substitute",
            "version" : "0.007"
         },
         {
            "class" : "Dist::Zilla::Plugin::Prereqs::Soften",
            "config" : {
               "Dist::Zilla::Plugin::Prereqs::Soften" : {
                  "copy_to" : [
                     "develop.requires"
                  ],
                  "modules" : [
                     "Capture::Tiny",
                     "Sub::Name",
                     "Sub::Util"
                  ],
                  "modules_from_features" : null,
                  "to_relationship" : "suggests"
               }
            },
            "name" : "Prereqs::Soften",
            "version" : "0.006003"
         },
         {
            "class" : "Dist::Zilla::Plugin::OnlyCorePrereqs",
            "config" : {
               "Dist::Zilla::Plugin::OnlyCorePrereqs" : {
                  "also_disallow" : [],
                  "check_dual_life_versions" : 0,
                  "deprecated_ok" : 0,
                  "phases" : [
                     "build",
                     "configure",
                     "runtime",
                     "test"
                  ],
                  "skips" : [],
                  "starting_version" : "to be determined from perl prereq"
               }
            },
            "name" : "OnlyCorePrereqs",
            "version" : "0.025"
         },
         {
            "class" : "Dist::Zilla::Plugin::Breaks",
            "name" : "Breaks",
            "version" : "0.004"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::CheckBreaks",
            "config" : {
               "Dist::Zilla::Plugin::Test::CheckBreaks" : {
                  "conflicts_module" : [],
                  "no_forced_deps" : 1
               },
               "Dist::Zilla::Role::ModuleMetadata" : {
                  "Module::Metadata" : "1.000038",
                  "version" : "0.006"
               }
            },
            "name" : "Test::CheckBreaks",
            "version" : "0.019"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":InstallModules",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":IncModules",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":TestFiles",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":ExtraTestFiles",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":ExecFiles",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":PerlExecFiles",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":ShareFiles",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":MainModule",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":AllFiles",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":NoFiles",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::VerifyPhases",
            "name" : "@Author::ETHER/PHASE VERIFICATION",
            "version" : "0.016"
         }
      ],
      "zilla" : {
         "class" : "Dist::Zilla::Dist::Builder",
         "config" : {
            "is_trial" : 0
         },
         "version" : "6.032"
      }
   },
   "x_authority" : "cpan:NUFFIN",
   "x_breaks" : {
      "Try::Tiny::Except" : "<= 0.01"
   },
   "x_contributors" : [
      "Karen Etheridge <ether@cpan.org>",
      "Peter Rabbitson <ribasushi@cpan.org>",
      "Ricardo Signes <rjbs@cpan.org>",
      "Mark Fowler <mark@twoshortplanks.com>",
      "Graham Knop <haarg@haarg.org>",
      "Aristotle Pagaltzis <pagaltzis@gmx.de>",
      "Dagfinn Ilmari Mannsåker <ilmari@ilmari.org>",
      "Lukas Mai <l.mai@web.de>",
      "Alex <alex@koban.(none)>",
      "anaxagoras <walkeraj@gmail.com>",
      "Andrew Yates <ayates@haddock.local>",
      "awalker <awalker@sourcefire.com>",
      "chromatic <chromatic@wgz.org>",
      "cm-perl <cm-perl@users.noreply.github.com>",
      "David Lowe <davidl@lokku.com>",
      "Glenn Fowler <cebjyre@cpan.org>",
      "Hans Dieter Pearcey <hdp@weftsoar.net>",
      "Jens Berthold <jens@jebecs.de>",
      "Jonathan Yu <JAWNSY@cpan.org>",
      "Marc Mims <marc@questright.com>",
      "Mark Stosberg <mark@stosberg.com>",
      "Pali <pali@cpan.org>",
      "Paul Howarth <paul@city-fan.org>",
      "Rudolf Leermakers <rudolf@hatsuseno.org>"
   ],
   "x_generated_by_perl" : "v5.41.2",
   "x_serialization_backend" : "JSON::PP version 2.97001",
   "x_spdx_expression" : "MIT",
   "x_use_unsafe_inc" : 0
}
PK2N%[�f^Z��@perl5/x86_64-linux-thread-multi/.meta/Try-Tiny-0.32/install.jsonnu��6�${"target":"Try::Tiny","provides":{"Try::Tiny":{"version":"0.32","file":"lib/Try/Tiny.pm"}},"pathname":"E/ET/ETHER/Try-Tiny-0.32.tar.gz","name":"Try::Tiny","version":"0.32","dist":"Try-Tiny-0.32"}PK2N%[�OS�w�w@perl5/x86_64-linux-thread-multi/.meta/HTTP-Date-6.06/MYMETA.jsonnu��6�${
   "abstract" : "HTTP::Date - date conversion routines",
   "author" : [
      "Gisle Aas <gisle@activestate.com>"
   ],
   "dynamic_config" : 0,
   "generated_by" : "Dist::Zilla version 6.030, CPAN::Meta::Converter version 2.150010",
   "license" : [
      "perl_5"
   ],
   "meta-spec" : {
      "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
      "version" : 2
   },
   "name" : "HTTP-Date",
   "no_index" : {
      "directory" : [
         "examples",
         "t",
         "xt"
      ]
   },
   "prereqs" : {
      "configure" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         },
         "suggests" : {
            "JSON::PP" : "2.27300"
         }
      },
      "develop" : {
         "recommends" : {
            "Dist::Zilla::PluginBundle::Git::VersionManager" : "0.007"
         },
         "requires" : {
            "Code::TidyAll" : "0.71",
            "Code::TidyAll::Plugin::SortLines::Naturally" : "0.000003",
            "Code::TidyAll::Plugin::Test::Vars" : "0.04",
            "Code::TidyAll::Plugin::UniqueLines" : "0.000003",
            "Encode" : "0",
            "Parallel::ForkManager" : "1.19",
            "Perl::Critic" : "1.132",
            "Perl::Tidy" : "20180220",
            "Pod::Coverage::TrustPod" : "0",
            "Pod::Wordlist" : "0",
            "Test::CPAN::Changes" : "0.19",
            "Test::EOL" : "0",
            "Test::Mojibake" : "0",
            "Test::More" : "0.96",
            "Test::Pod" : "1.41",
            "Test::Pod::Coverage" : "1.08",
            "Test::Portability::Files" : "0",
            "Test::Spelling" : "0.12",
            "Test::Vars" : "0.014",
            "Test::Version" : "1",
            "warnings" : "0"
         }
      },
      "runtime" : {
         "requires" : {
            "Exporter" : "0",
            "Time::Local" : "1.28",
            "Time::Zone" : "0",
            "perl" : "5.006002",
            "strict" : "0"
         }
      },
      "test" : {
         "recommends" : {
            "CPAN::Meta" : "2.120900"
         },
         "requires" : {
            "ExtUtils::MakeMaker" : "0",
            "File::Spec" : "0",
            "IO::Handle" : "0",
            "IPC::Open3" : "0",
            "Test::More" : "0",
            "perl" : "5.006002",
            "warnings" : "0"
         }
      }
   },
   "release_status" : "stable",
   "resources" : {
      "bugtracker" : {
         "web" : "https://github.com/libwww-perl/HTTP-Date/issues"
      },
      "homepage" : "https://github.com/libwww-perl/HTTP-Date",
      "repository" : {
         "type" : "git",
         "url" : "https://github.com/libwww-perl/HTTP-Date.git",
         "web" : "https://github.com/libwww-perl/HTTP-Date"
      },
      "x_IRC" : "irc://irc.perl.org/#lwp",
      "x_MailingList" : "mailto:libwww@perl.org"
   },
   "version" : "6.06",
   "x_Dist_Zilla" : {
      "perl" : {
         "version" : "5.036000"
      },
      "plugins" : [
         {
            "class" : "Dist::Zilla::Plugin::PromptIfStale",
            "config" : {
               "Dist::Zilla::Plugin::PromptIfStale" : {
                  "check_all_plugins" : 0,
                  "check_all_prereqs" : 0,
                  "modules" : [
                     "Dist::Zilla::PluginBundle::Author::OALDERS"
                  ],
                  "phase" : "build",
                  "run_under_travis" : 0,
                  "skip" : []
               }
            },
            "name" : "@Author::OALDERS/stale modules, build",
            "version" : "0.058"
         },
         {
            "class" : "Dist::Zilla::Plugin::PromptIfStale",
            "config" : {
               "Dist::Zilla::Plugin::PromptIfStale" : {
                  "check_all_plugins" : 1,
                  "check_all_prereqs" : 1,
                  "modules" : [],
                  "phase" : "release",
                  "run_under_travis" : 0,
                  "skip" : []
               }
            },
            "name" : "@Author::OALDERS/stale modules, release",
            "version" : "0.058"
         },
         {
            "class" : "Dist::Zilla::Plugin::AutoPrereqs",
            "name" : "@Author::OALDERS/AutoPrereqs",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::CheckChangesHasContent",
            "name" : "@Author::OALDERS/CheckChangesHasContent",
            "version" : "0.011"
         },
         {
            "class" : "Dist::Zilla::Plugin::MakeMaker",
            "config" : {
               "Dist::Zilla::Role::TestRunner" : {
                  "default_jobs" : "8"
               }
            },
            "name" : "@Author::OALDERS/MakeMaker",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::CPANFile",
            "name" : "@Author::OALDERS/CPANFile",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::ContributorsFile",
            "name" : "@Author::OALDERS/ContributorsFile",
            "version" : "0.3.0"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaJSON",
            "name" : "@Author::OALDERS/MetaJSON",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaYAML",
            "name" : "@Author::OALDERS/MetaYAML",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::Manifest",
            "name" : "@Author::OALDERS/Manifest",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaNoIndex",
            "name" : "@Author::OALDERS/MetaNoIndex",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaConfig",
            "name" : "@Author::OALDERS/MetaConfig",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaResources",
            "name" : "@Author::OALDERS/MetaResources",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::License",
            "name" : "@Author::OALDERS/License",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::InstallGuide",
            "config" : {
               "Dist::Zilla::Role::ModuleMetadata" : {
                  "Module::Metadata" : "1.000037",
                  "version" : "0.006"
               }
            },
            "name" : "@Author::OALDERS/InstallGuide",
            "version" : "1.200014"
         },
         {
            "class" : "Dist::Zilla::Plugin::Prereqs",
            "config" : {
               "Dist::Zilla::Plugin::Prereqs" : {
                  "phase" : "develop",
                  "type" : "requires"
               }
            },
            "name" : "@Author::OALDERS/Modules for use with tidyall",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::ExecDir",
            "name" : "@Author::OALDERS/ExecDir",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::PodSpelling",
            "config" : {
               "Dist::Zilla::Plugin::Test::PodSpelling" : {
                  "directories" : [
                     "bin",
                     "lib"
                  ],
                  "spell_cmd" : "",
                  "stopwords" : [
                     "Alders",
                     "Alders'",
                     "TZ",
                     "YYYY"
                  ],
                  "wordlist" : "Pod::Wordlist"
               }
            },
            "name" : "@Author::OALDERS/Test::PodSpelling",
            "version" : "2.007005"
         },
         {
            "class" : "Dist::Zilla::Plugin::MojibakeTests",
            "name" : "@Author::OALDERS/MojibakeTests",
            "version" : "0.8"
         },
         {
            "class" : "Dist::Zilla::Plugin::PodSyntaxTests",
            "name" : "@Author::OALDERS/PodSyntaxTests",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::CPAN::Changes",
            "config" : {
               "Dist::Zilla::Plugin::Test::CPAN::Changes" : {
                  "changelog" : "Changes"
               }
            },
            "name" : "@Author::OALDERS/Test::CPAN::Changes",
            "version" : "0.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::EOL",
            "config" : {
               "Dist::Zilla::Plugin::Test::EOL" : {
                  "filename" : "xt/author/eol.t",
                  "finder" : [
                     ":ExecFiles",
                     ":InstallModules",
                     ":TestFiles"
                  ],
                  "trailing_whitespace" : 1
               }
            },
            "name" : "@Author::OALDERS/Test::EOL",
            "version" : "0.19"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::Pod::Coverage::Configurable",
            "name" : "@Author::OALDERS/Test::Pod::Coverage::Configurable",
            "version" : "0.07"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::Portability",
            "config" : {
               "Dist::Zilla::Plugin::Test::Portability" : {
                  "options" : ""
               }
            },
            "name" : "@Author::OALDERS/Test::Portability",
            "version" : "2.001001"
         },
         {
            "class" : "Dist::Zilla::Plugin::TestRelease",
            "name" : "@Author::OALDERS/TestRelease",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::ReportPrereqs",
            "name" : "@Author::OALDERS/Test::ReportPrereqs",
            "version" : "0.029"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::Version",
            "name" : "@Author::OALDERS/Test::Version",
            "version" : "1.09"
         },
         {
            "class" : "Dist::Zilla::Plugin::RunExtraTests",
            "config" : {
               "Dist::Zilla::Role::TestRunner" : {
                  "default_jobs" : "8"
               }
            },
            "name" : "@Author::OALDERS/RunExtraTests",
            "version" : "0.029"
         },
         {
            "class" : "Dist::Zilla::Plugin::PodWeaver",
            "config" : {
               "Dist::Zilla::Plugin::PodWeaver" : {
                  "finder" : [
                     ":InstallModules",
                     ":PerlExecFiles"
                  ],
                  "plugins" : [
                     {
                        "class" : "Pod::Weaver::Plugin::EnsurePod5",
                        "name" : "@CorePrep/EnsurePod5",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Plugin::H1Nester",
                        "name" : "@CorePrep/H1Nester",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Plugin::SingleEncoding",
                        "name" : "@Default/SingleEncoding",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Name",
                        "name" : "@Default/Name",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Version",
                        "name" : "@Default/Version",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Region",
                        "name" : "@Default/prelude",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Generic",
                        "name" : "SYNOPSIS",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Generic",
                        "name" : "DESCRIPTION",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Generic",
                        "name" : "OVERVIEW",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Collect",
                        "name" : "ATTRIBUTES",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Collect",
                        "name" : "METHODS",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Collect",
                        "name" : "FUNCTIONS",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Leftovers",
                        "name" : "@Default/Leftovers",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Region",
                        "name" : "@Default/postlude",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Authors",
                        "name" : "@Default/Authors",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Legal",
                        "name" : "@Default/Legal",
                        "version" : "4.019"
                     }
                  ]
               }
            },
            "name" : "@Author::OALDERS/PodWeaver",
            "version" : "4.010"
         },
         {
            "class" : "Dist::Zilla::Plugin::PruneCruft",
            "name" : "@Author::OALDERS/PruneCruft",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::CopyFilesFromBuild",
            "name" : "@Author::OALDERS/CopyFilesFromBuild",
            "version" : "0.170880"
         },
         {
            "class" : "Dist::Zilla::Plugin::GithubMeta",
            "name" : "@Author::OALDERS/GithubMeta",
            "version" : "0.58"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::GatherDir",
            "config" : {
               "Dist::Zilla::Plugin::GatherDir" : {
                  "exclude_filename" : [
                     "Install",
                     "LICENSE",
                     "META.json",
                     "Makefile.PL",
                     "README.md",
                     "cpanfile"
                  ],
                  "exclude_match" : [],
                  "follow_symlinks" : 0,
                  "include_dotfiles" : 0,
                  "prefix" : "",
                  "prune_directory" : [],
                  "root" : "."
               },
               "Dist::Zilla::Plugin::Git::GatherDir" : {
                  "include_untracked" : 0
               }
            },
            "name" : "@Author::OALDERS/Git::GatherDir",
            "version" : "2.048"
         },
         {
            "class" : "Dist::Zilla::Plugin::CopyFilesFromRelease",
            "config" : {
               "Dist::Zilla::Plugin::CopyFilesFromRelease" : {
                  "filename" : [
                     "Install"
                  ],
                  "match" : []
               }
            },
            "name" : "@Author::OALDERS/CopyFilesFromRelease",
            "version" : "0.007"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::Check",
            "config" : {
               "Dist::Zilla::Plugin::Git::Check" : {
                  "untracked_files" : "die"
               },
               "Dist::Zilla::Role::Git::DirtyFiles" : {
                  "allow_dirty" : [
                     "Changes",
                     "Install",
                     "LICENSE",
                     "META.json",
                     "Makefile.PL",
                     "README.md",
                     "cpanfile",
                     "dist.ini"
                  ],
                  "allow_dirty_match" : [],
                  "changelog" : "Changes"
               },
               "Dist::Zilla::Role::Git::Repo" : {
                  "git_version" : "2.41.0",
                  "repo_root" : "."
               }
            },
            "name" : "@Author::OALDERS/Git::Check",
            "version" : "2.048"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::Contributors",
            "config" : {
               "Dist::Zilla::Plugin::Git::Contributors" : {
                  "git_version" : "2.41.0",
                  "include_authors" : 0,
                  "include_releaser" : 1,
                  "order_by" : "name",
                  "paths" : []
               }
            },
            "name" : "@Author::OALDERS/Git::Contributors",
            "version" : "0.036"
         },
         {
            "class" : "Dist::Zilla::Plugin::ReadmeAnyFromPod",
            "config" : {
               "Dist::Zilla::Role::FileWatcher" : {
                  "version" : "0.006"
               }
            },
            "name" : "@Author::OALDERS/ReadmeMdInBuild",
            "version" : "0.163250"
         },
         {
            "class" : "Dist::Zilla::Plugin::StaticInstall",
            "config" : {
               "Dist::Zilla::Plugin::StaticInstall" : {
                  "dry_run" : 0,
                  "mode" : "on"
               }
            },
            "name" : "@Author::OALDERS/StaticInstall",
            "version" : "0.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::ShareDir",
            "name" : "@Author::OALDERS/ShareDir",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::CheckIssues",
            "name" : "@Author::OALDERS/CheckIssues",
            "version" : "0.011"
         },
         {
            "class" : "Dist::Zilla::Plugin::ConfirmRelease",
            "name" : "@Author::OALDERS/ConfirmRelease",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::UploadToCPAN",
            "name" : "@Author::OALDERS/UploadToCPAN",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::Prereqs",
            "config" : {
               "Dist::Zilla::Plugin::Prereqs" : {
                  "phase" : "develop",
                  "type" : "recommends"
               }
            },
            "name" : "@Author::OALDERS/@Git::VersionManager/pluginbundle version",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::RewriteVersion::Transitional",
            "config" : {
               "Dist::Zilla::Plugin::RewriteVersion" : {
                  "add_tarball_name" : 0,
                  "finders" : [
                     ":ExecFiles",
                     ":InstallModules"
                  ],
                  "global" : 0,
                  "skip_version_provider" : 0
               },
               "Dist::Zilla::Plugin::RewriteVersion::Transitional" : {}
            },
            "name" : "@Author::OALDERS/@Git::VersionManager/RewriteVersion::Transitional",
            "version" : "0.009"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaProvides::Update",
            "name" : "@Author::OALDERS/@Git::VersionManager/MetaProvides::Update",
            "version" : "0.007"
         },
         {
            "class" : "Dist::Zilla::Plugin::CopyFilesFromRelease",
            "config" : {
               "Dist::Zilla::Plugin::CopyFilesFromRelease" : {
                  "filename" : [
                     "Changes"
                  ],
                  "match" : []
               }
            },
            "name" : "@Author::OALDERS/@Git::VersionManager/CopyFilesFromRelease",
            "version" : "0.007"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::Commit",
            "config" : {
               "Dist::Zilla::Plugin::Git::Commit" : {
                  "add_files_in" : [],
                  "commit_msg" : "v%V%n%n%c",
                  "signoff" : 0
               },
               "Dist::Zilla::Role::Git::DirtyFiles" : {
                  "allow_dirty" : [
                     "Changes",
                     "Install",
                     "LICENSE",
                     "META.json",
                     "Makefile.PL",
                     "README.md",
                     "cpanfile",
                     "dist.ini"
                  ],
                  "allow_dirty_match" : [],
                  "changelog" : "Changes"
               },
               "Dist::Zilla::Role::Git::Repo" : {
                  "git_version" : "2.41.0",
                  "repo_root" : "."
               },
               "Dist::Zilla::Role::Git::StringFormatter" : {
                  "time_zone" : "local"
               }
            },
            "name" : "@Author::OALDERS/@Git::VersionManager/release snapshot",
            "version" : "2.048"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::Tag",
            "config" : {
               "Dist::Zilla::Plugin::Git::Tag" : {
                  "branch" : null,
                  "changelog" : "Changes",
                  "signed" : 0,
                  "tag" : "v6.06",
                  "tag_format" : "v%V",
                  "tag_message" : "v%V"
               },
               "Dist::Zilla::Role::Git::Repo" : {
                  "git_version" : "2.41.0",
                  "repo_root" : "."
               },
               "Dist::Zilla::Role::Git::StringFormatter" : {
                  "time_zone" : "local"
               }
            },
            "name" : "@Author::OALDERS/@Git::VersionManager/Git::Tag",
            "version" : "2.048"
         },
         {
            "class" : "Dist::Zilla::Plugin::BumpVersionAfterRelease::Transitional",
            "config" : {
               "Dist::Zilla::Plugin::BumpVersionAfterRelease" : {
                  "finders" : [
                     ":ExecFiles",
                     ":InstallModules"
                  ],
                  "global" : 0,
                  "munge_makefile_pl" : 1
               },
               "Dist::Zilla::Plugin::BumpVersionAfterRelease::Transitional" : {}
            },
            "name" : "@Author::OALDERS/@Git::VersionManager/BumpVersionAfterRelease::Transitional",
            "version" : "0.009"
         },
         {
            "class" : "Dist::Zilla::Plugin::NextRelease",
            "name" : "@Author::OALDERS/@Git::VersionManager/NextRelease",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::Commit",
            "config" : {
               "Dist::Zilla::Plugin::Git::Commit" : {
                  "add_files_in" : [],
                  "commit_msg" : "increment $VERSION after %v release",
                  "signoff" : 0
               },
               "Dist::Zilla::Role::Git::DirtyFiles" : {
                  "allow_dirty" : [
                     "Build.PL",
                     "Changes",
                     "Makefile.PL"
                  ],
                  "allow_dirty_match" : [
                     "(?^:^lib/.*\\.pm$)"
                  ],
                  "changelog" : "Changes"
               },
               "Dist::Zilla::Role::Git::Repo" : {
                  "git_version" : "2.41.0",
                  "repo_root" : "."
               },
               "Dist::Zilla::Role::Git::StringFormatter" : {
                  "time_zone" : "local"
               }
            },
            "name" : "@Author::OALDERS/@Git::VersionManager/post-release commit",
            "version" : "2.048"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::Push",
            "config" : {
               "Dist::Zilla::Plugin::Git::Push" : {
                  "push_to" : [
                     "origin"
                  ],
                  "remotes_must_exist" : 1
               },
               "Dist::Zilla::Role::Git::Repo" : {
                  "git_version" : "2.41.0",
                  "repo_root" : "."
               }
            },
            "name" : "@Author::OALDERS/Git::Push",
            "version" : "2.048"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaResources",
            "name" : "MetaResources",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::Prereqs",
            "config" : {
               "Dist::Zilla::Plugin::Prereqs" : {
                  "phase" : "runtime",
                  "type" : "requires"
               }
            },
            "name" : "Prereqs",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::ChangesHasContent",
            "name" : "Test::ChangesHasContent",
            "version" : "0.011"
         },
         {
            "class" : "Dist::Zilla::Plugin::Substitute",
            "name" : "changes_has_content.t",
            "version" : "0.007"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::Compile",
            "config" : {
               "Dist::Zilla::Plugin::Test::Compile" : {
                  "bail_out_on_fail" : 0,
                  "fail_on_warning" : "author",
                  "fake_home" : 0,
                  "filename" : "t/00-compile.t",
                  "module_finder" : [
                     ":InstallModules"
                  ],
                  "needs_display" : 0,
                  "phase" : "test",
                  "script_finder" : [
                     ":PerlExecFiles"
                  ],
                  "skips" : [],
                  "switch" : []
               }
            },
            "name" : "Test::Compile",
            "version" : "2.058"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":InstallModules",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":IncModules",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":TestFiles",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":ExtraTestFiles",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":ExecFiles",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":PerlExecFiles",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":ShareFiles",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":MainModule",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":AllFiles",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":NoFiles",
            "version" : "6.030"
         }
      ],
      "zilla" : {
         "class" : "Dist::Zilla::Dist::Builder",
         "config" : {
            "is_trial" : 0
         },
         "version" : "6.030"
      }
   },
   "x_contributors" : [
      "Adam Kennedy <adamk@cpan.org>",
      "Adam Sjogren <asjo@koldfront.dk>",
      "Alexey Tourbin <at@altlinux.ru>",
      "Alex Kapranoff <ka@nadoby.ru>",
      "amire80 <amir.aharoni@gmail.com>",
      "Andreas J. Koenig <andreas.koenig@anima.de>",
      "Bill Mann <wfmann@alum.mit.edu>",
      "Bron Gondwana <brong@fastmail.fm>",
      "Daniel Hedlund <Daniel.Hedlund@eprize.com>",
      "David E. Wheeler <david@justatheory.com>",
      "DAVIDRW <davidrw@cpan.org>",
      "Father Chrysostomos <sprout@cpan.org>",
      "FWILES <FWILES@cpan.org>",
      "Gavin Peters <gpeters@deepsky.com>",
      "Gisle Aas <aas@oslonett.no>",
      "Gisle Aas <gisle.aas@it.uib.no>",
      "Gisle Aas <gisle@aas.no>",
      "Gisle Aas <gisle@baux-2.lan>",
      "Graeme Thompson <Graeme.Thompson@mobilecohesion.com>",
      "Hans-H. Froehlich <hfroehlich@co-de-co.de>",
      "Ian Kilgore <iank@cpan.org>",
      "Jacob J <waif@chaos2.org>",
      "James Raspass <jraspass@gmail.com>",
      "jefflee <shaohua@gmail.com>",
      "john9art <john9art@yahoo.com>",
      "Kyle Wright <kyle.wright@grantstreet.com>",
      "Mark Stosberg <mark@stosberg.com>",
      "Mark Stosberg <MARKSTOS@cpan.org>",
      "Mark Stosberg <mark@summersault.com>",
      "Mike Schilli <mschilli@yahoo-inc.com>",
      "mschilli <github@perlmeister.com>",
      "murphy <murphy@genome.chop.edu>",
      "Olaf Alders <olaf@wundersolutions.com>",
      "Ondrej Hanak <ondrej.hanak@ubs.com>",
      "Peter Rabbitson <ribasushi@cpan.org>",
      "Philip J. Ludlam <p.ludlam@cv-library.co.uk>",
      "phrstbrn <phrstbrn@gmail.com>",
      "pnull <github@jamit.de>",
      "Robert Stone <talby@trap.mtview.ca.us>",
      "Rolf Grossmann <rg@progtech.net>",
      "ruff <ruff@ukrpost.net>",
      "sasao <sasao@yugen.org>",
      "Sean M. Burke <sburke@cpan.org>",
      "Slaven Rezic <slaven@rezic.de>",
      "Slaven Rezic <srezic@iconmobile.com>",
      "Spiros Denaxas <s.denaxas@gmail.com>",
      "Steve Hay <SteveHay@planit.com>",
      "Todd Lipcon <todd@amiestreet.com>",
      "Tom Hukins <tom@eborcom.com>",
      "Tony Finch <dot@dotat.at>",
      "Toru Yamaguchi <zigorou@cpan.org>",
      "uid39246 <uid39246>",
      "Ville Skyttä <ville.skytta@iki.fi>",
      "Yuri Karaban <tech@askold.net>",
      "Zefram <zefram@fysh.org>"
   ],
   "x_generated_by_perl" : "v5.36.0",
   "x_serialization_backend" : "JSON::PP version 2.97001",
   "x_spdx_expression" : "Artistic-1.0-Perl OR GPL-1.0-or-later",
   "x_static_install" : 1
}
PK2N%[��PK��Aperl5/x86_64-linux-thread-multi/.meta/HTTP-Date-6.06/install.jsonnu��6�${"target":"HTTP::Date","name":"HTTP::Date","provides":{"HTTP::Date":{"version":6.06,"file":"lib/HTTP/Date.pm"}},"pathname":"O/OA/OALDERS/HTTP-Date-6.06.tar.gz","version":6.06,"dist":"HTTP-Date-6.06"}PK2N%[����=perl5/x86_64-linux-thread-multi/.meta/Encode-3.21/MYMETA.jsonnu��6�${
   "abstract" : "character encodings in Perl",
   "author" : [
      "Dan Kogai <dankogai@dan.co.jp>"
   ],
   "dynamic_config" : 0,
   "generated_by" : "ExtUtils::MakeMaker version 7.70, CPAN::Meta::Converter version 2.150010",
   "license" : [
      "perl_5"
   ],
   "meta-spec" : {
      "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
      "version" : 2
   },
   "name" : "Encode",
   "no_index" : {
      "directory" : [
         "t",
         "inc"
      ]
   },
   "prereqs" : {
      "build" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "configure" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "runtime" : {
         "requires" : {
            "Exporter" : "5.57",
            "Storable" : "0",
            "parent" : "0.221"
         }
      },
      "test" : {
         "requires" : {
            "Test::More" : "0.92"
         }
      }
   },
   "release_status" : "stable",
   "resources" : {
      "repository" : {
         "url" : "https://github.com/dankogai/p5-encode"
      }
   },
   "version" : "3.21",
   "x_contributors" : [
      "Alex Davies <alex.davies@talktalk.net>",
      "Alex Kapranoff <alex@kapranoff.ru>",
      "Alex Vandiver <alex@chmrr.net>",
      "Andreas J. Koenig <andreas.koenig@anima.de>",
      "Andrew Pennebaker <andrew.pennebaker@networkedinsights.com>",
      "Andy Grundman <andyg@activestate.com>",
      "Anton Tagunov <tagunov@motor.ru>",
      "Autrijus Tang <autrijus@autrijus.org>",
      "Benjamin Goldberg <goldbb2@earthlink.net>",
      "Bjoern Hoehrmann <derhoermi@gmx.net>",
      "Bjoern Jacke <debianbugs@j3e.de>",
      "bulk88 <bulk88@hotmail.com>",
      "Craig A. Berry <craigberry@mac.com>",
      "Curtis Jewell <csjewell@cpan.org>",
      "Dan Kogai <dankogai@dan.co.jp>",
      "Dave Evans <dave@rudolf.org.uk>",
      "David Golden <dagolden@cpan.org>",
      "David Steinbrunner <dsteinbrunner@pobox.com>",
      "Deng Liu <dengliu@ntu.edu.tw>",
      "Dominic Dunlop <domo@computer.org>",
      "drry",
      "Elizabeth Mattijsen <liz@dijkmat.nl>",
      "Flavio Poletti <flavio@polettix.it>",
      "Gerrit P. Haase <gp@familiehaase.de>",
      "Gisle Aas <gisle@ActiveState.com>",
      "Graham Barr <gbarr@pobox.com>",
      "Graham Knop <haarg@haarg.org>",
      "Graham Ollis <perl@wdlabs.com>",
      "Gurusamy Sarathy <gsar@activestate.com>",
      "H.Merijn Brand <h.m.brand@xs4all.nl>",
      "Hugo van der Sanden <hv@crypt.org>",
      "chansen <chansen@cpan.org>",
      "Chris Nandor <pudge@pobox.com>",
      "Inaba Hiroto <inaba@st.rim.or.jp>",
      "Jarkko Hietaniemi <jhi@iki.fi>",
      "Jesse Vincent <jesse@fsck.com>",
      "Jungshik Shin <jshin@mailaps.org>",
      "Karen Etheridge <ether@cpan.org>",
      "Karl Williamson <khw@cpan.org>",
      "Kenichi Ishigaki <ishigaki@cpan.org>",
      "KONNO Hiroharu <hiroharu.konno@bowneglobal.co.jp>",
      "Laszlo Molnar <ml1050@freemail.hu>",
      "Makamaka <makamaka@donzoko.net>",
      "Mark-Jason Dominus <mjd@plover.com>",
      "Masahiro Iuchi <masahiro.iuchi@gmail.com>",
      "MATSUNO Tokuhiro <tokuhirom+cpan@gmail.com>",
      "Mattia Barbon <mbarbon@dsi.unive.it>",
      "Michael G Schwern <schwern@pobox.com>",
      "Michael LaGrasta <michael@lagrasta.com>",
      "Miron Cuperman <miron@hyper.to>",
      "Moritz Lenz <moritz@faui2k3.org>",
      "MORIYAMA Masayuki <msyk@mtg.biglobe.ne.jp>",
      "Nick Ing-Simmons <nick@ing-simmons.net>",
      "Nicholas Clark <nick@ccl4.org>",
      "Olivier Mengué <dolmen@cpan.org>",
      "otsune",
      "Pali <pali@cpan.org>",
      "Paul Marquess <paul_marquess@yahoo.co.uk>",
      "Peter Prymmer <pvhp@best.com>",
      "Peter Rabbitson <ribasushi@cpan.org>",
      "Philip Newton <pne@cpan.org>",
      "Piotr Fusik <pfusik@op.pl>",
      "Rafael Garcia-Suarez <rgarciasuarez@mandriva.com>",
      "Randy Stauner <randy@magnificent-tears.com>",
      "Reini Urban <rurban@cpan.org>",
      "Robin Barker <rmb1@cise.npl.co.uk>",
      "SADAHIRO Tomoyuki <SADAHIRO@cpan.org>",
      "Simon Cozens <simon@netthink.co.uk>",
      "Slaven Rezic <SREZIC@cpan.org>",
      "Spider Boardman <spider@web.zk3.dec.com>",
      "Steve Hay <steve.m.hay@googlemail.com>",
      "Steve Peters <steve@fisharerojo.org>",
      "SUGAWARA Hajime <sugawara@hdt.co.jp>",
      "SUZUKI Norio <ZAP00217@nifty.com>",
      "szr8 <blz.marcel@gmail.com>",
      "Tatsuhiko Miyagawa <miyagawa@bulknews.net>",
      "Tels <perl_dummy@bloodgate.com>",
      "Tony Cook <tony@develop-help.com>",
      "Vadim Konovalov <vkonovalov@peterstar.ru>",
      "Victor <victor@vsespb.ru>",
      "Ville Skyttä <ville.skytta@iki.fi>",
      "Vincent van Dam <vvandam@sandvine.com>",
      "Yitzchak Scott-Thoennes <sthoenna@efn.org>"
   ],
   "x_serialization_backend" : "JSON::PP version 2.97001"
}
PK2N%[A�=�SS>perl5/x86_64-linux-thread-multi/.meta/Encode-3.21/install.jsonnu��6�${"name":"Encode","target":"Encode","version":3.21,"pathname":"D/DA/DANKOGAI/Encode-3.21.tar.gz","provides":{"Encode::utf8":{"file":"Encode.pm","version":3.21},"Encode::KR::2022_KR":{"version":2.04,"file":"lib/Encode/KR/2022_KR.pm"},"Encode::Symbol":{"file":"Symbol/Symbol.pm","version":2.02},"Encode::Unicode::UTF7":{"version":"2.10","file":"lib/Encode/Unicode/UTF7.pm"},"Encode::TW":{"version":2.03,"file":"TW/TW.pm"},"Encode::CN::HZ":{"file":"lib/Encode/CN/HZ.pm","version":"2.10"},"Encode::Config":{"version":2.05,"file":"lib/Encode/Config.pm"},"Encode::Unicode":{"version":"2.20","file":"Unicode/Unicode.pm"},"Encode::MIME::Header::ISO_2022_JP":{"file":"lib/Encode/MIME/Header/ISO_2022_JP.pm","version":1.09},"Encode::KR":{"version":2.03,"file":"KR/KR.pm"},"Encode::JP::JIS7":{"version":2.08,"file":"lib/Encode/JP/JIS7.pm"},"Encode::UTF_EBCDIC":{"version":3.21,"file":"Encode.pm"},"Encode::EBCDIC":{"file":"EBCDIC/EBCDIC.pm","version":2.02},"Encode::Encoder":{"version":2.03,"file":"lib/Encode/Encoder.pm"},"Encode::Encoding":{"file":"lib/Encode/Encoding.pm","version":2.08},"Encode::Guess":{"file":"lib/Encode/Guess.pm","version":2.08},"Encode::XS":{"version":3.21,"file":"Encode.pm"},"Encode::CJKConstants":{"file":"lib/Encode/CJKConstants.pm","version":2.02},"Encode::MIME::Header":{"version":2.29,"file":"lib/Encode/MIME/Header.pm"},"Encode":{"file":"Encode.pm","version":3.21},"Encode::Byte":{"version":2.04,"file":"Byte/Byte.pm"},"Encode::GSM0338":{"version":"2.10","file":"lib/Encode/GSM0338.pm"},"encoding":{"version":"3.00","file":"encoding.pm"},"Encode::JP":{"version":2.05,"file":"JP/JP.pm"},"Encode::MIME::Name":{"version":1.03,"file":"lib/Encode/MIME/Name.pm"},"Encode::Alias":{"file":"lib/Encode/Alias.pm","version":2.25},"Encode::CN":{"file":"CN/CN.pm","version":2.03},"Encode::JP::H2Z":{"version":2.02,"file":"lib/Encode/JP/H2Z.pm"}},"dist":"Encode-3.21"}PK2N%[��;k�]�]Eperl5/x86_64-linux-thread-multi/.meta/LWP-MediaTypes-6.04/MYMETA.jsonnu��6�${
   "abstract" : "guess media type for a file or a URL",
   "author" : [
      "Gisle Aas <gisle@activestate.com>"
   ],
   "dynamic_config" : 0,
   "generated_by" : "Dist::Zilla version 6.012, CPAN::Meta::Converter version 2.150010",
   "license" : [
      "perl_5"
   ],
   "meta-spec" : {
      "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
      "version" : 2
   },
   "name" : "LWP-MediaTypes",
   "no_index" : {
      "directory" : [
         "t",
         "xt"
      ]
   },
   "prereqs" : {
      "build" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "configure" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "develop" : {
         "recommends" : {
            "Dist::Zilla::PluginBundle::Git::VersionManager" : "0.007"
         },
         "requires" : {
            "Encode" : "0",
            "File::Spec" : "0",
            "IO::Handle" : "0",
            "IPC::Open3" : "0",
            "Pod::Coverage::TrustPod" : "0",
            "Pod::Wordlist" : "0",
            "Test::EOL" : "0",
            "Test::MinimumVersion" : "0",
            "Test::Mojibake" : "0",
            "Test::More" : "0.94",
            "Test::Pod" : "1.41",
            "Test::Pod::Coverage" : "1.08",
            "Test::Portability::Files" : "0",
            "Test::Spelling" : "0.12",
            "Test::Version" : "1",
            "perl" : "5.006",
            "warnings" : "0"
         }
      },
      "runtime" : {
         "requires" : {
            "Carp" : "0",
            "Exporter" : "0",
            "File::Basename" : "0",
            "Scalar::Util" : "0",
            "perl" : "5.006002",
            "strict" : "0"
         }
      },
      "test" : {
         "recommends" : {
            "CPAN::Meta" : "2.120900"
         },
         "requires" : {
            "ExtUtils::MakeMaker" : "0",
            "File::Spec" : "0",
            "Test::Fatal" : "0",
            "Test::More" : "0",
            "overload" : "0",
            "warnings" : "0"
         }
      }
   },
   "provides" : {
      "LWP::MediaTypes" : {
         "file" : "lib/LWP/MediaTypes.pm",
         "version" : "6.04"
      }
   },
   "release_status" : "stable",
   "resources" : {
      "bugtracker" : {
         "web" : "https://github.com/libwww-perl/lwp-mediatypes/issues"
      },
      "homepage" : "https://github.com/libwww-perl/lwp-mediatypes",
      "repository" : {
         "type" : "git",
         "url" : "https://github.com/libwww-perl/lwp-mediatypes.git",
         "web" : "https://github.com/libwww-perl/lwp-mediatypes"
      },
      "x_IRC" : "irc://irc.perl.org/#lwp",
      "x_MailingList" : "mailto:libwww@perl.org"
   },
   "version" : "6.04",
   "x_Dist_Zilla" : {
      "perl" : {
         "version" : "5.026001"
      },
      "plugins" : [
         {
            "class" : "Dist::Zilla::Plugin::Git::GatherDir",
            "config" : {
               "Dist::Zilla::Plugin::GatherDir" : {
                  "exclude_filename" : [
                     "LICENSE",
                     "META.json",
                     "README.md",
                     "cpanfile"
                  ],
                  "exclude_match" : [],
                  "follow_symlinks" : 0,
                  "include_dotfiles" : 0,
                  "prefix" : "",
                  "prune_directory" : [],
                  "root" : "."
               },
               "Dist::Zilla::Plugin::Git::GatherDir" : {
                  "include_untracked" : 0
               }
            },
            "name" : "Git::GatherDir",
            "version" : "2.045"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaConfig",
            "name" : "MetaConfig",
            "version" : "6.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaProvides::Package",
            "config" : {
               "Dist::Zilla::Plugin::MetaProvides::Package" : {
                  "finder_objects" : [
                     {
                        "class" : "Dist::Zilla::Plugin::FinderCode",
                        "name" : "MetaProvides::Package/AUTOVIV/:InstallModulesPM",
                        "version" : "6.012"
                     }
                  ],
                  "include_underscores" : 0
               },
               "Dist::Zilla::Role::MetaProvider::Provider" : {
                  "$Dist::Zilla::Role::MetaProvider::Provider::VERSION" : "2.002004",
                  "inherit_missing" : 1,
                  "inherit_version" : 1,
                  "meta_noindex" : 1
               },
               "Dist::Zilla::Role::ModuleMetadata" : {
                  "Module::Metadata" : "1.000033",
                  "version" : "0.004"
               }
            },
            "name" : "MetaProvides::Package",
            "version" : "2.004003"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaNoIndex",
            "name" : "MetaNoIndex",
            "version" : "6.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaYAML",
            "name" : "MetaYAML",
            "version" : "6.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaJSON",
            "name" : "MetaJSON",
            "version" : "6.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaResources",
            "name" : "MetaResources",
            "version" : "6.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::Contributors",
            "config" : {
               "Dist::Zilla::Plugin::Git::Contributors" : {
                  "git_version" : "2.20.1",
                  "include_authors" : 0,
                  "include_releaser" : 1,
                  "order_by" : "name",
                  "paths" : []
               }
            },
            "name" : "Git::Contributors",
            "version" : "0.035"
         },
         {
            "class" : "Dist::Zilla::Plugin::GithubMeta",
            "name" : "GithubMeta",
            "version" : "0.58"
         },
         {
            "class" : "Dist::Zilla::Plugin::Authority",
            "name" : "Authority",
            "version" : "1.009"
         },
         {
            "class" : "Dist::Zilla::Plugin::Manifest",
            "name" : "Manifest",
            "version" : "6.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::License",
            "name" : "License",
            "version" : "6.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::InstallGuide",
            "name" : "InstallGuide",
            "version" : "1.200012"
         },
         {
            "class" : "Dist::Zilla::Plugin::ExecDir",
            "name" : "ExecDir",
            "version" : "6.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::Prereqs",
            "config" : {
               "Dist::Zilla::Plugin::Prereqs" : {
                  "phase" : "runtime",
                  "type" : "requires"
               }
            },
            "name" : "Prereqs",
            "version" : "6.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::AutoPrereqs",
            "name" : "AutoPrereqs",
            "version" : "6.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::CPANFile",
            "name" : "CPANFile",
            "version" : "6.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::MakeMaker",
            "config" : {
               "Dist::Zilla::Role::TestRunner" : {
                  "default_jobs" : 1
               }
            },
            "name" : "MakeMaker",
            "version" : "6.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::MojibakeTests",
            "name" : "MojibakeTests",
            "version" : "0.8"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::Version",
            "name" : "Test::Version",
            "version" : "1.09"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::ReportPrereqs",
            "name" : "Test::ReportPrereqs",
            "version" : "0.027"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::Compile",
            "config" : {
               "Dist::Zilla::Plugin::Test::Compile" : {
                  "bail_out_on_fail" : "1",
                  "fail_on_warning" : "author",
                  "fake_home" : 0,
                  "filename" : "xt/author/00-compile.t",
                  "module_finder" : [
                     ":InstallModules"
                  ],
                  "needs_display" : 0,
                  "phase" : "develop",
                  "script_finder" : [
                     ":PerlExecFiles"
                  ],
                  "skips" : [],
                  "switch" : []
               }
            },
            "name" : "Test::Compile",
            "version" : "2.058"
         },
         {
            "class" : "Dist::Zilla::Plugin::Substitute",
            "name" : "00-compile.t",
            "version" : "0.006"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::Portability",
            "config" : {
               "Dist::Zilla::Plugin::Test::Portability" : {
                  "options" : ""
               }
            },
            "name" : "Test::Portability",
            "version" : "2.001000"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::EOL",
            "config" : {
               "Dist::Zilla::Plugin::Test::EOL" : {
                  "filename" : "xt/author/eol.t",
                  "finder" : [
                     ":ExecFiles",
                     ":InstallModules",
                     ":TestFiles"
                  ],
                  "trailing_whitespace" : 1
               }
            },
            "name" : "Test::EOL",
            "version" : "0.19"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::ChangesHasContent",
            "name" : "Test::ChangesHasContent",
            "version" : "0.011"
         },
         {
            "class" : "Dist::Zilla::Plugin::Substitute",
            "name" : "changes_has_content.t",
            "version" : "0.006"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::MinimumVersion",
            "name" : "Test::MinimumVersion",
            "version" : "2.000008"
         },
         {
            "class" : "Dist::Zilla::Plugin::PodSyntaxTests",
            "name" : "PodSyntaxTests",
            "version" : "6.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::Pod::Coverage::Configurable",
            "name" : "Test::Pod::Coverage::Configurable",
            "version" : "0.07"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::PodSpelling",
            "config" : {
               "Dist::Zilla::Plugin::Test::PodSpelling" : {
                  "directories" : [
                     "bin",
                     "lib"
                  ],
                  "spell_cmd" : "aspell list",
                  "stopwords" : [
                     "eg"
                  ],
                  "wordlist" : "Pod::Wordlist"
               }
            },
            "name" : "Test::PodSpelling",
            "version" : "2.007005"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::Check",
            "config" : {
               "Dist::Zilla::Plugin::Git::Check" : {
                  "untracked_files" : "die"
               },
               "Dist::Zilla::Role::Git::DirtyFiles" : {
                  "allow_dirty" : [],
                  "allow_dirty_match" : [],
                  "changelog" : "Changes"
               },
               "Dist::Zilla::Role::Git::Repo" : {
                  "git_version" : "2.20.1",
                  "repo_root" : "."
               }
            },
            "name" : "Git::Check",
            "version" : "2.045"
         },
         {
            "class" : "Dist::Zilla::Plugin::CheckStrictVersion",
            "name" : "CheckStrictVersion",
            "version" : "0.001"
         },
         {
            "class" : "Dist::Zilla::Plugin::RunExtraTests",
            "config" : {
               "Dist::Zilla::Role::TestRunner" : {
                  "default_jobs" : 1
               }
            },
            "name" : "RunExtraTests",
            "version" : "0.029"
         },
         {
            "class" : "Dist::Zilla::Plugin::CheckChangeLog",
            "name" : "CheckChangeLog",
            "version" : "0.05"
         },
         {
            "class" : "Dist::Zilla::Plugin::CheckChangesHasContent",
            "name" : "CheckChangesHasContent",
            "version" : "0.011"
         },
         {
            "class" : "Dist::Zilla::Plugin::TestRelease",
            "name" : "TestRelease",
            "version" : "6.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::UploadToCPAN",
            "name" : "UploadToCPAN",
            "version" : "6.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::ReadmeAnyFromPod",
            "config" : {
               "Dist::Zilla::Role::FileWatcher" : {
                  "version" : "0.006"
               }
            },
            "name" : "Markdown_Readme",
            "version" : "0.163250"
         },
         {
            "class" : "Dist::Zilla::Plugin::CopyFilesFromRelease",
            "config" : {
               "Dist::Zilla::Plugin::CopyFilesFromRelease" : {
                  "filename" : [
                     "LICENSE",
                     "META.json",
                     "cpanfile"
                  ],
                  "match" : []
               }
            },
            "name" : "CopyFilesFromRelease",
            "version" : "0.006"
         },
         {
            "class" : "Dist::Zilla::Plugin::Prereqs",
            "config" : {
               "Dist::Zilla::Plugin::Prereqs" : {
                  "phase" : "develop",
                  "type" : "recommends"
               }
            },
            "name" : "@Git::VersionManager/pluginbundle version",
            "version" : "6.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::RewriteVersion::Transitional",
            "config" : {
               "Dist::Zilla::Plugin::RewriteVersion" : {
                  "add_tarball_name" : 0,
                  "finders" : [
                     ":ExecFiles",
                     ":InstallModules"
                  ],
                  "global" : 0,
                  "skip_version_provider" : 0
               },
               "Dist::Zilla::Plugin::RewriteVersion::Transitional" : {}
            },
            "name" : "@Git::VersionManager/RewriteVersion::Transitional",
            "version" : "0.009"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaProvides::Update",
            "name" : "@Git::VersionManager/MetaProvides::Update",
            "version" : "0.007"
         },
         {
            "class" : "Dist::Zilla::Plugin::CopyFilesFromRelease",
            "config" : {
               "Dist::Zilla::Plugin::CopyFilesFromRelease" : {
                  "filename" : [
                     "Changes"
                  ],
                  "match" : []
               }
            },
            "name" : "@Git::VersionManager/CopyFilesFromRelease",
            "version" : "0.006"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::Commit",
            "config" : {
               "Dist::Zilla::Plugin::Git::Commit" : {
                  "add_files_in" : [],
                  "commit_msg" : "v%v%n%n%c"
               },
               "Dist::Zilla::Role::Git::DirtyFiles" : {
                  "allow_dirty" : [
                     "Changes",
                     "LICENSE",
                     "META.json",
                     "README.md",
                     "cpanfile"
                  ],
                  "allow_dirty_match" : [],
                  "changelog" : "Changes"
               },
               "Dist::Zilla::Role::Git::Repo" : {
                  "git_version" : "2.20.1",
                  "repo_root" : "."
               },
               "Dist::Zilla::Role::Git::StringFormatter" : {
                  "time_zone" : "local"
               }
            },
            "name" : "@Git::VersionManager/release snapshot",
            "version" : "2.045"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::Tag",
            "config" : {
               "Dist::Zilla::Plugin::Git::Tag" : {
                  "branch" : null,
                  "changelog" : "Changes",
                  "signed" : 0,
                  "tag" : "v6.04",
                  "tag_format" : "v%v",
                  "tag_message" : "v%v"
               },
               "Dist::Zilla::Role::Git::Repo" : {
                  "git_version" : "2.20.1",
                  "repo_root" : "."
               },
               "Dist::Zilla::Role::Git::StringFormatter" : {
                  "time_zone" : "local"
               }
            },
            "name" : "@Git::VersionManager/Git::Tag",
            "version" : "2.045"
         },
         {
            "class" : "Dist::Zilla::Plugin::BumpVersionAfterRelease::Transitional",
            "config" : {
               "Dist::Zilla::Plugin::BumpVersionAfterRelease" : {
                  "finders" : [
                     ":ExecFiles",
                     ":InstallModules"
                  ],
                  "global" : 0,
                  "munge_makefile_pl" : 1
               },
               "Dist::Zilla::Plugin::BumpVersionAfterRelease::Transitional" : {}
            },
            "name" : "@Git::VersionManager/BumpVersionAfterRelease::Transitional",
            "version" : "0.009"
         },
         {
            "class" : "Dist::Zilla::Plugin::NextRelease",
            "name" : "@Git::VersionManager/NextRelease",
            "version" : "6.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::Commit",
            "config" : {
               "Dist::Zilla::Plugin::Git::Commit" : {
                  "add_files_in" : [],
                  "commit_msg" : "increment $VERSION after %v release"
               },
               "Dist::Zilla::Role::Git::DirtyFiles" : {
                  "allow_dirty" : [
                     "Build.PL",
                     "Changes",
                     "Makefile.PL"
                  ],
                  "allow_dirty_match" : [
                     "(?^:^lib/.*\\.pm$)"
                  ],
                  "changelog" : "Changes"
               },
               "Dist::Zilla::Role::Git::Repo" : {
                  "git_version" : "2.20.1",
                  "repo_root" : "."
               },
               "Dist::Zilla::Role::Git::StringFormatter" : {
                  "time_zone" : "local"
               }
            },
            "name" : "@Git::VersionManager/post-release commit",
            "version" : "2.045"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::Push",
            "config" : {
               "Dist::Zilla::Plugin::Git::Push" : {
                  "push_to" : [
                     "origin"
                  ],
                  "remotes_must_exist" : 1
               },
               "Dist::Zilla::Role::Git::Repo" : {
                  "git_version" : "2.20.1",
                  "repo_root" : "."
               }
            },
            "name" : "Git::Push",
            "version" : "2.045"
         },
         {
            "class" : "Dist::Zilla::Plugin::ConfirmRelease",
            "name" : "ConfirmRelease",
            "version" : "6.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":InstallModules",
            "version" : "6.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":IncModules",
            "version" : "6.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":TestFiles",
            "version" : "6.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":ExtraTestFiles",
            "version" : "6.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":ExecFiles",
            "version" : "6.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":PerlExecFiles",
            "version" : "6.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":ShareFiles",
            "version" : "6.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":MainModule",
            "version" : "6.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":AllFiles",
            "version" : "6.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":NoFiles",
            "version" : "6.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : "MetaProvides::Package/AUTOVIV/:InstallModulesPM",
            "version" : "6.012"
         }
      ],
      "zilla" : {
         "class" : "Dist::Zilla::Dist::Builder",
         "config" : {
            "is_trial" : 0
         },
         "version" : "6.012"
      }
   },
   "x_authority" : "cpan:LWWWP",
   "x_contributors" : [
      "Adam Kennedy <adamk@cpan.org>",
      "Adam Sjogren <asjo@koldfront.dk>",
      "Alexey Tourbin <at@altlinux.ru>",
      "Alex Kapranoff <ka@nadoby.ru>",
      "amire80 <amir.aharoni@gmail.com>",
      "Andreas J. Koenig <andreas.koenig@anima.de>",
      "Bill Mann <wfmann@alum.mit.edu>",
      "Bron Gondwana <brong@fastmail.fm>",
      "Daniel Hedlund <Daniel.Hedlund@eprize.com>",
      "David E. Wheeler <david@justatheory.com>",
      "DAVIDRW <davidrw@cpan.org>",
      "Father Chrysostomos <sprout@cpan.org>",
      "FWILES <FWILES@cpan.org>",
      "Gavin Peters <gpeters@deepsky.com>",
      "Gisle Aas <aas@oslonett.no>",
      "Gisle Aas <gisle.aas@it.uib.no>",
      "Gisle Aas <gisle@aas.no>",
      "Gisle Aas <gisle@baux-2.lan>",
      "Graeme Thompson <Graeme.Thompson@mobilecohesion.com>",
      "Hans-H. Froehlich <hfroehlich@co-de-co.de>",
      "Ian Kilgore <iank@cpan.org>",
      "Jacob J <waif@chaos2.org>",
      "jefflee <shaohua@gmail.com>",
      "john9art <john9art@yahoo.com>",
      "Karen Etheridge <ether@cpan.org>",
      "Mark Stosberg <mark@stosberg.com>",
      "Mark Stosberg <MARKSTOS@cpan.org>",
      "Mark Stosberg <mark@summersault.com>",
      "Mike Schilli <mschilli@yahoo-inc.com>",
      "mschilli <github@perlmeister.com>",
      "murphy <murphy@genome.chop.edu>",
      "Olaf Alders <olaf@wundersolutions.com>",
      "Ondrej Hanak <ondrej.hanak@ubs.com>",
      "Peter Rabbitson <ribasushi@cpan.org>",
      "phrstbrn <phrstbrn@gmail.com>",
      "Robert Stone <talby@trap.mtview.ca.us>",
      "Rolf Grossmann <rg@progtech.net>",
      "ruff <ruff@ukrpost.net>",
      "sasao <sasao@yugen.org>",
      "Sean M. Burke <sburke@cpan.org>",
      "Slaven Rezic <slaven@rezic.de>",
      "Slaven Rezic <srezic@iconmobile.com>",
      "Spiros Denaxas <s.denaxas@gmail.com>",
      "Steve Hay <SteveHay@planit.com>",
      "Todd Lipcon <todd@amiestreet.com>",
      "Tom Hukins <tom@eborcom.com>",
      "Tony Finch <dot@dotat.at>",
      "Toru Yamaguchi <zigorou@cpan.org>",
      "uid39246 <uid39246>",
      "Ville Skytta <ville.skytta@iki.fi>",
      "Wesley Schwengle <wesley@schwengle.net>",
      "Yuri Karaban <tech@askold.net>",
      "Zefram <zefram@fysh.org>"
   ],
   "x_generated_by_perl" : "v5.26.1",
   "x_serialization_backend" : "JSON::PP version 2.97001"
}
PK2N%[��3B��Fperl5/x86_64-linux-thread-multi/.meta/LWP-MediaTypes-6.04/install.jsonnu��6�${"pathname":"O/OA/OALDERS/LWP-MediaTypes-6.04.tar.gz","provides":{"LWP::MediaTypes":{"version":"6.04","file":"lib/LWP/MediaTypes.pm"}},"version":"6.04","dist":"LWP-MediaTypes-6.04","target":"LWP::MediaTypes","name":"LWP::MediaTypes"}PK2N%[�{���Cperl5/x86_64-linux-thread-multi/.meta/File-Listing-6.16/MYMETA.jsonnu��6�${
   "abstract" : "Parse directory listing",
   "author" : [
      "Gisle Aas",
      "Graham Ollis <plicease@cpan.org>"
   ],
   "dynamic_config" : 0,
   "generated_by" : "Dist::Zilla version 6.029, CPAN::Meta::Converter version 2.150010",
   "license" : [
      "perl_5"
   ],
   "meta-spec" : {
      "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
      "version" : 2
   },
   "name" : "File-Listing",
   "no_index" : {
      "directory" : [
         "maint"
      ]
   },
   "prereqs" : {
      "build" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "configure" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "develop" : {
         "recommends" : {
            "Dist::Zilla::Plugin::Author::Plicease::Thanks" : "0",
            "Dist::Zilla::Plugin::Author::Plicease::Upload" : "0",
            "Dist::Zilla::Plugin::MetaNoIndex" : "0",
            "Dist::Zilla::Plugin::RemovePrereqs" : "0",
            "Dist::Zilla::PluginBundle::Author::Plicease" : "2.69",
            "Perl::Critic::Policy::BuiltinFunctions::ProhibitBooleanGrep" : "0",
            "Perl::Critic::Policy::BuiltinFunctions::ProhibitStringyEval" : "0",
            "Perl::Critic::Policy::BuiltinFunctions::ProhibitStringySplit" : "0",
            "Perl::Critic::Policy::BuiltinFunctions::ProhibitVoidGrep" : "0",
            "Perl::Critic::Policy::BuiltinFunctions::ProhibitVoidMap" : "0",
            "Perl::Critic::Policy::ClassHierarchies::ProhibitOneArgBless" : "0",
            "Perl::Critic::Policy::CodeLayout::ProhibitHardTabs" : "0",
            "Perl::Critic::Policy::CodeLayout::ProhibitTrailingWhitespace" : "0",
            "Perl::Critic::Policy::CodeLayout::RequireConsistentNewlines" : "0",
            "Perl::Critic::Policy::Community::ArrayAssignAref" : "0",
            "Perl::Critic::Policy::Community::BarewordFilehandles" : "0",
            "Perl::Critic::Policy::Community::ConditionalDeclarations" : "0",
            "Perl::Critic::Policy::Community::ConditionalImplicitReturn" : "0",
            "Perl::Critic::Policy::Community::DeprecatedFeatures" : "0",
            "Perl::Critic::Policy::Community::DiscouragedModules" : "0",
            "Perl::Critic::Policy::Community::DollarAB" : "0",
            "Perl::Critic::Policy::Community::Each" : "0",
            "Perl::Critic::Policy::Community::IndirectObjectNotation" : "0",
            "Perl::Critic::Policy::Community::LexicalForeachIterator" : "0",
            "Perl::Critic::Policy::Community::LoopOnHash" : "0",
            "Perl::Critic::Policy::Community::ModPerl" : "0",
            "Perl::Critic::Policy::Community::OpenArgs" : "0",
            "Perl::Critic::Policy::Community::OverloadOptions" : "0",
            "Perl::Critic::Policy::Community::POSIXImports" : "0",
            "Perl::Critic::Policy::Community::PackageMatchesFilename" : "0",
            "Perl::Critic::Policy::Community::PreferredAlternatives" : "0",
            "Perl::Critic::Policy::Community::StrictWarnings" : "0",
            "Perl::Critic::Policy::Community::Threads" : "0",
            "Perl::Critic::Policy::Community::Wantarray" : "0",
            "Perl::Critic::Policy::Community::WarningsSwitch" : "0",
            "Perl::Critic::Policy::Community::WhileDiamondDefaultAssignment" : "0",
            "Perl::Critic::Policy::ControlStructures::ProhibitLabelsWithSpecialBlockNames" : "0",
            "Perl::Critic::Policy::ControlStructures::ProhibitMutatingListFunctions" : "0",
            "Perl::Critic::Policy::ControlStructures::ProhibitUnreachableCode" : "0",
            "Perl::Critic::Policy::InputOutput::ProhibitBarewordFileHandles" : "0",
            "Perl::Critic::Policy::InputOutput::ProhibitJoinedReadline" : "0",
            "Perl::Critic::Policy::InputOutput::ProhibitTwoArgOpen" : "0",
            "Perl::Critic::Policy::Miscellanea::ProhibitFormats" : "0",
            "Perl::Critic::Policy::Miscellanea::ProhibitUselessNoCritic" : "0",
            "Perl::Critic::Policy::Modules::ProhibitConditionalUseStatements" : "0",
            "Perl::Critic::Policy::Modules::RequireNoMatchVarsWithUseEnglish" : "0",
            "Perl::Critic::Policy::Objects::ProhibitIndirectSyntax" : "0",
            "Perl::Critic::Policy::RegularExpressions::ProhibitUselessTopic" : "0",
            "Perl::Critic::Policy::Subroutines::ProhibitNestedSubs" : "0",
            "Perl::Critic::Policy::ValuesAndExpressions::ProhibitMixedBooleanOperators" : "0",
            "Perl::Critic::Policy::ValuesAndExpressions::ProhibitSpecialLiteralHeredocTerminator" : "0",
            "Perl::Critic::Policy::ValuesAndExpressions::RequireUpperCaseHeredocTerminator" : "0",
            "Perl::Critic::Policy::Variables::ProhibitPerl4PackageNames" : "0",
            "Perl::Critic::Policy::Variables::ProhibitUnusedVariables" : "0",
            "Software::License::Perl_5" : "0"
         },
         "requires" : {
            "File::Spec" : "0",
            "FindBin" : "0",
            "Perl::Critic" : "0",
            "Test2::Require::Module" : "0.000121",
            "Test2::Tools::PerlCritic" : "0",
            "Test2::V0" : "0.000121",
            "Test::CPAN::Changes" : "0",
            "Test::EOL" : "0",
            "Test::Fixme" : "0.07",
            "Test::More" : "0.98",
            "Test::NoTabs" : "0",
            "Test::Pod" : "0",
            "Test::Pod::Coverage" : "0",
            "Test::Pod::Spelling::CommonMistakes" : "0",
            "Test::Spelling" : "0",
            "Test::Strict" : "0",
            "YAML" : "0"
         }
      },
      "runtime" : {
         "requires" : {
            "Exporter" : "5.57",
            "HTTP::Date" : "0",
            "perl" : "5.006"
         }
      },
      "test" : {
         "requires" : {
            "Test::More" : "0.98"
         }
      }
   },
   "release_status" : "stable",
   "resources" : {
      "bugtracker" : {
         "web" : "https://github.com/PerlAlien/File-Listing/issues"
      },
      "homepage" : "https://metacpan.org/pod/File::Listing",
      "repository" : {
         "type" : "git",
         "url" : "git://github.com/PerlAlien/File-Listing.git",
         "web" : "https://github.com/PerlAlien/File-Listing"
      }
   },
   "version" : "6.16",
   "x_contributors" : [
      "Gisle Aas",
      "Graham Ollis <plicease@cpan.org>",
      "Adam Kennedy",
      "Adam Sjogren",
      "Alex Kapranoff",
      "Alexey Tourbin",
      "Andreas J. Koenig",
      "Bill Mann",
      "Bron Gondwana",
      "DAVIDRW",
      "Daniel Hedlund",
      "David E. Wheeler",
      "David Steinbrunner",
      "Erik Esterer",
      "FWILES",
      "Father Chrysostomos",
      "Gavin Peters",
      "Graeme Thompson",
      "Grant Street Group",
      "Hans-H. Froehlich",
      "Ian Kilgore",
      "Jacob J",
      "Mark Stosberg",
      "Mike Schilli",
      "Ondrej Hanak",
      "Peter John Acklam",
      "Peter Rabbitson",
      "Robert Stone",
      "Rolf Grossmann",
      "Sean M. Burke",
      "Simon Legner",
      "Slaven Rezic",
      "Spiros Denaxas",
      "Steve Hay",
      "Todd Lipcon",
      "Tom Hukins",
      "Tony Finch",
      "Toru Yamaguchi",
      "Ville Skyttä",
      "Yuri Karaban",
      "Zefram",
      "amire80",
      "jefflee",
      "john9art",
      "mschilli",
      "murphy",
      "phrstbrn",
      "ruff",
      "sasao",
      "uid39246"
   ],
   "x_generated_by_perl" : "v5.36.0",
   "x_serialization_backend" : "JSON::PP version 2.97001",
   "x_spdx_expression" : "Artistic-1.0-Perl OR GPL-1.0-or-later",
   "x_use_unsafe_inc" : 0
}
PK2N%[ҾIg44Dperl5/x86_64-linux-thread-multi/.meta/File-Listing-6.16/install.jsonnu��6�${"target":"File::Listing","name":"File::Listing","dist":"File-Listing-6.16","provides":{"File::Listing::vms":{"file":"lib/File/Listing.pm","version":6.16},"File::Listing::netware":{"file":"lib/File/Listing.pm","version":6.16},"File::Listing::apache":{"file":"lib/File/Listing.pm","version":6.16},"File::Listing::dosftp":{"version":6.16,"file":"lib/File/Listing.pm"},"File::Listing":{"version":6.16,"file":"lib/File/Listing.pm"},"File::Listing::unix":{"version":6.16,"file":"lib/File/Listing.pm"}},"pathname":"P/PL/PLICEASE/File-Listing-6.16.tar.gz","version":6.16}PK2N%[�����Dperl5/x86_64-linux-thread-multi/.meta/Alien-Libxml2-0.20/MYMETA.jsonnu��6�${
   "abstract" : "Install the C libxml2 library on your system",
   "author" : [
      "Graham Ollis <plicease@cpan.org>"
   ],
   "dynamic_config" : 0,
   "generated_by" : "Dist::Zilla version 6.032, CPAN::Meta::Converter version 2.150010",
   "license" : [
      "perl_5"
   ],
   "meta-spec" : {
      "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
      "version" : 2
   },
   "name" : "Alien-Libxml2",
   "prereqs" : {
      "build" : {
         "requires" : {
            "Alien::Build" : "2.37",
            "Alien::Build::MM" : "0.32",
            "ExtUtils::MakeMaker" : "6.52"
         }
      },
      "configure" : {
         "requires" : {
            "Alien::Build" : "2.37",
            "Alien::Build::MM" : "2.37",
            "Alien::Build::Plugin::Build::SearchDep" : "0.35",
            "Alien::Build::Plugin::Download::GitLab" : "0",
            "Alien::Build::Plugin::Prefer::BadVersion" : "1.05",
            "Alien::Build::Plugin::Probe::Vcpkg" : "0",
            "ExtUtils::CBuilder" : "0",
            "ExtUtils::MakeMaker" : "6.52"
         }
      },
      "develop" : {
         "recommends" : {
            "Alien::Build::Plugin::Probe::Vcpkg" : "0",
            "Dist::Zilla::Plugin::AlienBase::Doc" : "0",
            "Dist::Zilla::Plugin::AlienBuild" : "0.11",
            "Dist::Zilla::Plugin::Author::Plicease::Thanks" : "0",
            "Dist::Zilla::Plugin::Author::Plicease::Upload" : "0",
            "Dist::Zilla::Plugin::Prereqs" : "0",
            "Dist::Zilla::Plugin::PruneFiles" : "0",
            "Dist::Zilla::Plugin::RemovePrereqs" : "0",
            "Dist::Zilla::PluginBundle::Author::Plicease" : "2.79",
            "Perl::Critic::Policy::BuiltinFunctions::ProhibitBooleanGrep" : "0",
            "Perl::Critic::Policy::BuiltinFunctions::ProhibitStringyEval" : "0",
            "Perl::Critic::Policy::BuiltinFunctions::ProhibitStringySplit" : "0",
            "Perl::Critic::Policy::BuiltinFunctions::ProhibitVoidGrep" : "0",
            "Perl::Critic::Policy::BuiltinFunctions::ProhibitVoidMap" : "0",
            "Perl::Critic::Policy::ClassHierarchies::ProhibitExplicitISA" : "0",
            "Perl::Critic::Policy::ClassHierarchies::ProhibitOneArgBless" : "0",
            "Perl::Critic::Policy::CodeLayout::ProhibitHardTabs" : "0",
            "Perl::Critic::Policy::CodeLayout::ProhibitTrailingWhitespace" : "0",
            "Perl::Critic::Policy::CodeLayout::RequireConsistentNewlines" : "0",
            "Perl::Critic::Policy::ControlStructures::ProhibitLabelsWithSpecialBlockNames" : "0",
            "Perl::Critic::Policy::ControlStructures::ProhibitMutatingListFunctions" : "0",
            "Perl::Critic::Policy::ControlStructures::ProhibitUnreachableCode" : "0",
            "Perl::Critic::Policy::Freenode::ArrayAssignAref" : "0",
            "Perl::Critic::Policy::Freenode::BarewordFilehandles" : "0",
            "Perl::Critic::Policy::Freenode::ConditionalDeclarations" : "0",
            "Perl::Critic::Policy::Freenode::ConditionalImplicitReturn" : "0",
            "Perl::Critic::Policy::Freenode::DeprecatedFeatures" : "0",
            "Perl::Critic::Policy::Freenode::DiscouragedModules" : "0",
            "Perl::Critic::Policy::Freenode::DollarAB" : "0",
            "Perl::Critic::Policy::Freenode::Each" : "0",
            "Perl::Critic::Policy::Freenode::EmptyReturn" : "0",
            "Perl::Critic::Policy::Freenode::IndirectObjectNotation" : "0",
            "Perl::Critic::Policy::Freenode::LexicalForeachIterator" : "0",
            "Perl::Critic::Policy::Freenode::LoopOnHash" : "0",
            "Perl::Critic::Policy::Freenode::ModPerl" : "0",
            "Perl::Critic::Policy::Freenode::OpenArgs" : "0",
            "Perl::Critic::Policy::Freenode::OverloadOptions" : "0",
            "Perl::Critic::Policy::Freenode::POSIXImports" : "0",
            "Perl::Critic::Policy::Freenode::PackageMatchesFilename" : "0",
            "Perl::Critic::Policy::Freenode::PreferredAlternatives" : "0",
            "Perl::Critic::Policy::Freenode::StrictWarnings" : "0",
            "Perl::Critic::Policy::Freenode::Threads" : "0",
            "Perl::Critic::Policy::Freenode::Wantarray" : "0",
            "Perl::Critic::Policy::Freenode::WarningsSwitch" : "0",
            "Perl::Critic::Policy::Freenode::WhileDiamondDefaultAssignment" : "0",
            "Perl::Critic::Policy::InputOutput::ProhibitBarewordFileHandles" : "0",
            "Perl::Critic::Policy::InputOutput::ProhibitJoinedReadline" : "0",
            "Perl::Critic::Policy::InputOutput::ProhibitTwoArgOpen" : "0",
            "Perl::Critic::Policy::Miscellanea::ProhibitFormats" : "0",
            "Perl::Critic::Policy::Miscellanea::ProhibitUselessNoCritic" : "0",
            "Perl::Critic::Policy::Modules::ProhibitConditionalUseStatements" : "0",
            "Perl::Critic::Policy::Modules::RequireNoMatchVarsWithUseEnglish" : "0",
            "Perl::Critic::Policy::Objects::ProhibitIndirectSyntax" : "0",
            "Perl::Critic::Policy::RegularExpressions::ProhibitUselessTopic" : "0",
            "Perl::Critic::Policy::Subroutines::ProhibitNestedSubs" : "0",
            "Perl::Critic::Policy::ValuesAndExpressions::ProhibitLeadingZeros" : "0",
            "Perl::Critic::Policy::ValuesAndExpressions::ProhibitMixedBooleanOperators" : "0",
            "Perl::Critic::Policy::ValuesAndExpressions::ProhibitSpecialLiteralHeredocTerminator" : "0",
            "Perl::Critic::Policy::ValuesAndExpressions::RequireUpperCaseHeredocTerminator" : "0",
            "Perl::Critic::Policy::Variables::ProhibitPerl4PackageNames" : "0",
            "Perl::Critic::Policy::Variables::ProhibitUnusedVariables" : "0",
            "Software::License::Perl_5" : "0"
         },
         "requires" : {
            "File::Spec" : "0",
            "FindBin" : "0",
            "Perl::Critic" : "0",
            "Test2::Require::Module" : "0.000121",
            "Test2::Tools::PerlCritic" : "0",
            "Test2::V0" : "0.000121",
            "Test::CPAN::Changes" : "0",
            "Test::EOL" : "0",
            "Test::Fixme" : "0.07",
            "Test::More" : "0.98",
            "Test::NoTabs" : "0",
            "Test::Pod" : "0",
            "Test::Pod::Coverage" : "0",
            "Test::Pod::Spelling::CommonMistakes" : "0",
            "Test::Spelling" : "0",
            "Test::Strict" : "0",
            "YAML" : "0"
         }
      },
      "runtime" : {
         "requires" : {
            "Alien::Base" : "2.37",
            "Alien::Build" : "0.25",
            "perl" : "5.006"
         }
      },
      "test" : {
         "requires" : {
            "Test2::V0" : "0.000121",
            "Test::Alien" : "0"
         }
      }
   },
   "release_status" : "stable",
   "resources" : {
      "bugtracker" : {
         "web" : "https://github.com/PerlAlien/Alien-Libxml2/issues"
      },
      "homepage" : "https://metacpan.org/pod/Alien::Libxml2",
      "repository" : {
         "type" : "git",
         "url" : "git://github.com/PerlAlien/Alien-Libxml2.git",
         "web" : "https://github.com/PerlAlien/Alien-Libxml2"
      },
      "x_IRC" : "irc://irc.perl.org/#native"
   },
   "version" : "0.20",
   "x_alienfile" : {
      "generated_by" : "Dist::Zilla::Plugin::AlienBuild version 0.32",
      "requires" : {
         "share" : {
            "Config" : "0",
            "HTTP::Tiny" : "0.044",
            "IO::Socket::SSL" : "1.56",
            "Mozilla::CA" : "0",
            "Net::SSLeay" : "1.49",
            "URI" : "0"
         },
         "system" : {}
      }
   },
   "x_contributors" : [
      "Graham Ollis <plicease@cpan.org>",
      "Shlomi Fish (shlomif)",
      "Shawn Laffan (SLAFFAN)"
   ],
   "x_generated_by_perl" : "v5.40.0",
   "x_serialization_backend" : "JSON::PP version 2.97001",
   "x_spdx_expression" : "Artistic-1.0-Perl OR GPL-1.0-or-later",
   "x_use_unsafe_inc" : 0
}
PK2N%[����Eperl5/x86_64-linux-thread-multi/.meta/Alien-Libxml2-0.20/install.jsonnu��6�${"pathname":"P/PL/PLICEASE/Alien-Libxml2-0.20.tar.gz","name":"Alien::Libxml2","version":"0.20","dist":"Alien-Libxml2-0.20","provides":{"Alien::Libxml2":{"version":"0.20","file":"lib/Alien/Libxml2.pm"}},"target":"Alien::Libxml2"}PK2N%[���L�LBperl5/x86_64-linux-thread-multi/.meta/IO-Stringy-2.113/MYMETA.jsonnu��6�${
   "abstract" : "I/O on in-core objects like strings and arrays",
   "author" : [
      "Erik Dorfman <eryq@cpan.org>"
   ],
   "dynamic_config" : 0,
   "generated_by" : "Dist::Zilla version 6.012, CPAN::Meta::Converter version 2.150010",
   "license" : [
      "perl_5"
   ],
   "meta-spec" : {
      "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
      "version" : 2
   },
   "name" : "IO-Stringy",
   "no_index" : {
      "directory" : [
         "eg",
         "examples",
         "inc",
         "share",
         "t",
         "xt"
      ]
   },
   "prereqs" : {
      "build" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "configure" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "develop" : {
         "requires" : {
            "Dist::Zilla" : "0",
            "File::Spec" : "0",
            "IO::Handle" : "0",
            "IPC::Open3" : "0",
            "Pod::Coverage::TrustPod" : "0",
            "Test::CPAN::Changes" : "0.4",
            "Test::CheckManifest" : "1.29",
            "Test::Kwalitee" : "1.22",
            "Test::More" : "0.88",
            "Test::Pod" : "1.41",
            "Test::Pod::Coverage" : "1.08",
            "Test::Pod::Spelling::CommonMistakes" : "1.000",
            "Test::Spelling" : "0.12",
            "Test::TrailingSpace" : "0",
            "Test::Version" : "1"
         }
      },
      "runtime" : {
         "requires" : {
            "Carp" : "0",
            "Exporter" : "5.57",
            "File::Spec" : "0",
            "FileHandle" : "0",
            "IO::File" : "0",
            "IO::Handle" : "0",
            "Symbol" : "0",
            "overload" : "0",
            "parent" : "0",
            "strict" : "0",
            "warnings" : "0"
         }
      },
      "test" : {
         "recommends" : {
            "CPAN::Meta" : "2.120900"
         },
         "requires" : {
            "ExtUtils::MakeMaker" : "0",
            "File::Basename" : "0",
            "File::Spec" : "0",
            "File::Temp" : "0",
            "FileHandle" : "0",
            "IO::File" : "0",
            "IO::Handle" : "0",
            "Symbol" : "0",
            "Test::More" : "0.88",
            "Test::Tester" : "0",
            "strict" : "0",
            "warnings" : "0"
         }
      }
   },
   "provides" : {
      "IO::AtomicFile" : {
         "file" : "lib/IO/AtomicFile.pm",
         "version" : "2.113"
      },
      "IO::InnerFile" : {
         "file" : "lib/IO/InnerFile.pm",
         "version" : "2.113"
      },
      "IO::Lines" : {
         "file" : "lib/IO/Lines.pm",
         "version" : "2.113"
      },
      "IO::Scalar" : {
         "file" : "lib/IO/Scalar.pm",
         "version" : "2.113"
      },
      "IO::ScalarArray" : {
         "file" : "lib/IO/ScalarArray.pm",
         "version" : "2.113"
      },
      "IO::Stringy" : {
         "file" : "lib/IO/Stringy.pm",
         "version" : "2.113"
      },
      "IO::Wrap" : {
         "file" : "lib/IO/Wrap.pm",
         "version" : "2.113"
      },
      "IO::WrapTie" : {
         "file" : "lib/IO/WrapTie.pm",
         "version" : "2.113"
      }
   },
   "release_status" : "stable",
   "resources" : {
      "bugtracker" : {
         "web" : "https://github.com/genio/IO-Stringy/issues"
      },
      "homepage" : "https://github.com/genio/IO-Stringy",
      "repository" : {
         "type" : "git",
         "url" : "https://github.com/genio/IO-Stringy.git",
         "web" : "https://github.com/genio/IO-Stringy"
      }
   },
   "version" : "2.113",
   "x_Dist_Zilla" : {
      "perl" : {
         "version" : "5.030000"
      },
      "plugins" : [
         {
            "class" : "Dist::Zilla::Plugin::Git::GatherDir",
            "config" : {
               "Dist::Zilla::Plugin::GatherDir" : {
                  "exclude_filename" : [
                     "LICENSE",
                     "META.json",
                     "Makefile.PL",
                     "README.md",
                     "t/00-report-prereqs.t"
                  ],
                  "exclude_match" : [],
                  "follow_symlinks" : 0,
                  "include_dotfiles" : 0,
                  "prefix" : "",
                  "prune_directory" : [],
                  "root" : "."
               },
               "Dist::Zilla::Plugin::Git::GatherDir" : {
                  "include_untracked" : 0
               }
            },
            "name" : "Git::GatherDir",
            "version" : "2.046"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaYAML",
            "name" : "@Starter/MetaYAML",
            "version" : "6.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaJSON",
            "name" : "@Starter/MetaJSON",
            "version" : "6.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::License",
            "name" : "@Starter/License",
            "version" : "6.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::Pod2Readme",
            "name" : "@Starter/Pod2Readme",
            "version" : "0.004"
         },
         {
            "class" : "Dist::Zilla::Plugin::PodSyntaxTests",
            "name" : "@Starter/PodSyntaxTests",
            "version" : "6.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::ReportPrereqs",
            "name" : "@Starter/Test::ReportPrereqs",
            "version" : "0.027"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::Compile",
            "config" : {
               "Dist::Zilla::Plugin::Test::Compile" : {
                  "bail_out_on_fail" : 0,
                  "fail_on_warning" : "author",
                  "fake_home" : 0,
                  "filename" : "xt/author/00-compile.t",
                  "module_finder" : [
                     ":InstallModules"
                  ],
                  "needs_display" : 0,
                  "phase" : "develop",
                  "script_finder" : [
                     ":PerlExecFiles"
                  ],
                  "skips" : [],
                  "switch" : []
               }
            },
            "name" : "@Starter/Test::Compile",
            "version" : "2.058"
         },
         {
            "class" : "Dist::Zilla::Plugin::MakeMaker::Awesome",
            "config" : {
               "Dist::Zilla::Plugin::MakeMaker" : {
                  "make_path" : "gmake",
                  "version" : "6.012"
               },
               "Dist::Zilla::Role::TestRunner" : {
                  "default_jobs" : 1,
                  "version" : "6.012"
               }
            },
            "name" : "@Starter/MakeMaker::Awesome",
            "version" : "0.48"
         },
         {
            "class" : "Dist::Zilla::Plugin::Manifest",
            "name" : "@Starter/Manifest",
            "version" : "6.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::PruneCruft",
            "name" : "@Starter/PruneCruft",
            "version" : "6.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::ManifestSkip",
            "name" : "@Starter/ManifestSkip",
            "version" : "6.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::RunExtraTests",
            "config" : {
               "Dist::Zilla::Role::TestRunner" : {
                  "default_jobs" : 1
               }
            },
            "name" : "@Starter/RunExtraTests",
            "version" : "0.029"
         },
         {
            "class" : "Dist::Zilla::Plugin::RewriteVersion",
            "config" : {
               "Dist::Zilla::Plugin::RewriteVersion" : {
                  "add_tarball_name" : 0,
                  "finders" : [
                     ":ExecFiles",
                     ":InstallModules"
                  ],
                  "global" : 1,
                  "skip_version_provider" : 0
               }
            },
            "name" : "@Starter/RewriteVersion",
            "version" : "0.018"
         },
         {
            "class" : "Dist::Zilla::Plugin::NextRelease",
            "name" : "@Starter/NextRelease",
            "version" : "6.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::BumpVersionAfterRelease",
            "config" : {
               "Dist::Zilla::Plugin::BumpVersionAfterRelease" : {
                  "finders" : [
                     ":ExecFiles",
                     ":InstallModules"
                  ],
                  "global" : 0,
                  "munge_makefile_pl" : 1
               }
            },
            "name" : "@Starter/BumpVersionAfterRelease",
            "version" : "0.018"
         },
         {
            "class" : "Dist::Zilla::Plugin::TestRelease",
            "name" : "@Starter/TestRelease",
            "version" : "6.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::ConfirmRelease",
            "name" : "@Starter/ConfirmRelease",
            "version" : "6.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::UploadToCPAN",
            "name" : "@Starter/UploadToCPAN",
            "version" : "6.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaConfig",
            "name" : "@Starter/MetaConfig",
            "version" : "6.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaNoIndex",
            "name" : "@Starter/MetaNoIndex",
            "version" : "6.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaProvides::Package",
            "config" : {
               "Dist::Zilla::Plugin::MetaProvides::Package" : {
                  "finder_objects" : [
                     {
                        "class" : "Dist::Zilla::Plugin::FinderCode",
                        "name" : "@Starter/MetaProvides::Package/AUTOVIV/:InstallModulesPM",
                        "version" : "6.012"
                     }
                  ],
                  "include_underscores" : 0
               },
               "Dist::Zilla::Role::MetaProvider::Provider" : {
                  "$Dist::Zilla::Role::MetaProvider::Provider::VERSION" : "2.002004",
                  "inherit_missing" : 1,
                  "inherit_version" : 1,
                  "meta_noindex" : 1
               },
               "Dist::Zilla::Role::ModuleMetadata" : {
                  "Module::Metadata" : "1.000036",
                  "version" : "0.006"
               }
            },
            "name" : "@Starter/MetaProvides::Package",
            "version" : "2.004003"
         },
         {
            "class" : "Dist::Zilla::Plugin::ShareDir",
            "name" : "@Starter/ShareDir",
            "version" : "6.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::ExecDir",
            "name" : "@Starter/ExecDir",
            "version" : "6.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::ReadmeAnyFromPod",
            "config" : {
               "Dist::Zilla::Role::FileWatcher" : {
                  "version" : "0.006"
               }
            },
            "name" : "Markdown_Readme",
            "version" : "0.163250"
         },
         {
            "class" : "Dist::Zilla::Plugin::Prereqs::FromCPANfile",
            "name" : "Prereqs::FromCPANfile",
            "version" : "0.08"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::Contributors",
            "config" : {
               "Dist::Zilla::Plugin::Git::Contributors" : {
                  "git_version" : "2.16.1.windows.1",
                  "include_authors" : 0,
                  "include_releaser" : 1,
                  "order_by" : "name",
                  "paths" : []
               }
            },
            "name" : "Git::Contributors",
            "version" : "0.035"
         },
         {
            "class" : "Dist::Zilla::Plugin::GithubMeta",
            "name" : "GithubMeta",
            "version" : "0.58"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::Check",
            "config" : {
               "Dist::Zilla::Plugin::Git::Check" : {
                  "untracked_files" : "die"
               },
               "Dist::Zilla::Role::Git::DirtyFiles" : {
                  "allow_dirty" : [
                     "Changes",
                     "dist.ini"
                  ],
                  "allow_dirty_match" : [],
                  "changelog" : "Changes"
               },
               "Dist::Zilla::Role::Git::Repo" : {
                  "git_version" : "2.16.1.windows.1",
                  "repo_root" : "."
               }
            },
            "name" : "@Git/Check",
            "version" : "2.046"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::Commit",
            "config" : {
               "Dist::Zilla::Plugin::Git::Commit" : {
                  "add_files_in" : [],
                  "commit_msg" : "v%V%n%n%c"
               },
               "Dist::Zilla::Role::Git::DirtyFiles" : {
                  "allow_dirty" : [
                     "Changes",
                     "dist.ini"
                  ],
                  "allow_dirty_match" : [],
                  "changelog" : "Changes"
               },
               "Dist::Zilla::Role::Git::Repo" : {
                  "git_version" : "2.16.1.windows.1",
                  "repo_root" : "."
               },
               "Dist::Zilla::Role::Git::StringFormatter" : {
                  "time_zone" : "local"
               }
            },
            "name" : "@Git/Commit",
            "version" : "2.046"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::Tag",
            "config" : {
               "Dist::Zilla::Plugin::Git::Tag" : {
                  "branch" : null,
                  "changelog" : "Changes",
                  "signed" : 0,
                  "tag" : "v2.113",
                  "tag_format" : "v%V",
                  "tag_message" : "v%V"
               },
               "Dist::Zilla::Role::Git::Repo" : {
                  "git_version" : "2.16.1.windows.1",
                  "repo_root" : "."
               },
               "Dist::Zilla::Role::Git::StringFormatter" : {
                  "time_zone" : "local"
               }
            },
            "name" : "@Git/Tag",
            "version" : "2.046"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::Push",
            "config" : {
               "Dist::Zilla::Plugin::Git::Push" : {
                  "push_to" : [
                     "origin"
                  ],
                  "remotes_must_exist" : 1
               },
               "Dist::Zilla::Role::Git::Repo" : {
                  "git_version" : "2.16.1.windows.1",
                  "repo_root" : "."
               }
            },
            "name" : "@Git/Push",
            "version" : "2.046"
         },
         {
            "class" : "Dist::Zilla::Plugin::CheckChangeLog",
            "name" : "CheckChangeLog",
            "version" : "0.05"
         },
         {
            "class" : "Dist::Zilla::Plugin::CheckChangesHasContent",
            "name" : "CheckChangesHasContent",
            "version" : "0.011"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::ChangesHasContent",
            "name" : "Test::ChangesHasContent",
            "version" : "0.011"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::Kwalitee",
            "config" : {
               "Dist::Zilla::Plugin::Test::Kwalitee" : {
                  "filename" : "xt/release/kwalitee.t",
                  "skiptest" : [
                     "no_symlinks"
                  ]
               }
            },
            "name" : "Test::Kwalitee",
            "version" : "2.12"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::Version",
            "name" : "Test::Version",
            "version" : "1.09"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::Pod::Coverage::Configurable",
            "name" : "Test::Pod::Coverage::Configurable",
            "version" : "0.07"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::PodSpelling",
            "config" : {
               "Dist::Zilla::Plugin::Test::PodSpelling" : {
                  "directories" : [
                     "bin",
                     "lib"
                  ],
                  "spell_cmd" : "",
                  "stopwords" : [
                     "BUF",
                     "Doru",
                     "FOO",
                     "Foo",
                     "NBYTES",
                     "POS",
                     "SCALARREF",
                     "SLAVECLASS",
                     "ZeeGee",
                     "aref",
                     "dfs",
                     "getline",
                     "getlines",
                     "getpos",
                     "ing",
                     "reblessed",
                     "setpos",
                     "sref",
                     "tieable",
                     "wraphandle"
                  ],
                  "wordlist" : "Pod::Wordlist"
               }
            },
            "name" : "Test::PodSpelling",
            "version" : "2.007005"
         },
         {
            "class" : "Dist::Zilla::Plugin::CopyFilesFromBuild",
            "name" : "CopyFilesFromBuild",
            "version" : "0.170880"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":InstallModules",
            "version" : "6.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":IncModules",
            "version" : "6.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":TestFiles",
            "version" : "6.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":ExtraTestFiles",
            "version" : "6.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":ExecFiles",
            "version" : "6.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":PerlExecFiles",
            "version" : "6.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":ShareFiles",
            "version" : "6.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":MainModule",
            "version" : "6.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":AllFiles",
            "version" : "6.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":NoFiles",
            "version" : "6.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : "@Starter/MetaProvides::Package/AUTOVIV/:InstallModulesPM",
            "version" : "6.012"
         }
      ],
      "zilla" : {
         "class" : "Dist::Zilla::Dist::Builder",
         "config" : {
            "is_trial" : 0
         },
         "version" : "6.012"
      }
   },
   "x_contributors" : [
      "Chase Whitener <capoeirab@cpan.org>",
      "Dianne Skoll <dskoll@cpan.org>"
   ],
   "x_generated_by_perl" : "v5.30.0",
   "x_serialization_backend" : "JSON::PP version 2.97001"
}
PK2N%[�>�K��Cperl5/x86_64-linux-thread-multi/.meta/IO-Stringy-2.113/install.jsonnu��6�${"name":"IO::Stringy","target":"IO::Scalar","dist":"IO-Stringy-2.113","pathname":"C/CA/CAPOEIRAB/IO-Stringy-2.113.tar.gz","provides":{"IO::Stringy":{"version":"2.113","file":"lib/IO/Stringy.pm"},"IO::AtomicFile":{"version":"2.113","file":"lib/IO/AtomicFile.pm"},"IO::Wrap":{"file":"lib/IO/Wrap.pm","version":"2.113"},"IO::ScalarArray":{"file":"lib/IO/ScalarArray.pm","version":"2.113"},"IO::InnerFile":{"file":"lib/IO/InnerFile.pm","version":"2.113"},"IO::Lines":{"version":"2.113","file":"lib/IO/Lines.pm"},"IO::Scalar":{"version":"2.113","file":"lib/IO/Scalar.pm"},"IO::WrapTie":{"version":"2.113","file":"lib/IO/WrapTie.pm"}},"version":"2.113"}PK2N%[p�]`Z*Z*?perl5/x86_64-linux-thread-multi/.meta/IO-HTML-1.004/MYMETA.jsonnu��6�${
   "abstract" : "Open an HTML file with automatic charset detection",
   "author" : [
      "Christopher J. Madsen <perl@cjmweb.net>"
   ],
   "dynamic_config" : 0,
   "generated_by" : "Dist::Zilla version 6.015, CPAN::Meta::Converter version 2.150010",
   "license" : [
      "perl_5"
   ],
   "meta-spec" : {
      "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
      "version" : 2
   },
   "name" : "IO-HTML",
   "prereqs" : {
      "build" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "configure" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "develop" : {
         "requires" : {
            "Pod::Coverage::TrustPod" : "0",
            "Test::More" : "0",
            "Test::Pod" : "1.41",
            "Test::Pod::Coverage" : "1.08"
         }
      },
      "runtime" : {
         "requires" : {
            "Carp" : "0",
            "Encode" : "2.10",
            "Exporter" : "5.57",
            "perl" : "5.008"
         }
      },
      "test" : {
         "requires" : {
            "File::Temp" : "0",
            "Scalar::Util" : "0",
            "Test::More" : "0.88"
         }
      }
   },
   "release_status" : "stable",
   "resources" : {
      "repository" : {
         "type" : "git",
         "url" : "git://github.com/madsen/io-html.git",
         "web" : "https://github.com/madsen/io-html"
      }
   },
   "version" : "1.004",
   "x_Dist_Zilla" : {
      "perl" : {
         "version" : "5.030001"
      },
      "plugins" : [
         {
            "class" : "Dist::Zilla::Plugin::VersionFromModule",
            "name" : "CJM/VersionFromModule",
            "version" : "0.08"
         },
         {
            "class" : "Dist::Zilla::Plugin::GatherDir",
            "config" : {
               "Dist::Zilla::Plugin::GatherDir" : {
                  "exclude_filename" : [],
                  "exclude_match" : [],
                  "follow_symlinks" : 0,
                  "include_dotfiles" : 0,
                  "prefix" : "",
                  "prune_directory" : [],
                  "root" : "."
               }
            },
            "name" : "CJM/GatherDir",
            "version" : "6.015"
         },
         {
            "class" : "Dist::Zilla::Plugin::PruneCruft",
            "name" : "CJM/PruneCruft",
            "version" : "6.015"
         },
         {
            "class" : "Dist::Zilla::Plugin::ManifestSkip",
            "name" : "CJM/ManifestSkip",
            "version" : "6.015"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaJSON",
            "name" : "CJM/MetaJSON",
            "version" : "6.015"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaYAML",
            "name" : "CJM/MetaYAML",
            "version" : "6.015"
         },
         {
            "class" : "Dist::Zilla::Plugin::License",
            "name" : "CJM/License",
            "version" : "6.015"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::PrereqsFromMeta",
            "name" : "CJM/Test::PrereqsFromMeta",
            "version" : "4.23"
         },
         {
            "class" : "Dist::Zilla::Plugin::PodSyntaxTests",
            "name" : "CJM/PodSyntaxTests",
            "version" : "6.015"
         },
         {
            "class" : "Dist::Zilla::Plugin::PodCoverageTests",
            "name" : "CJM/PodCoverageTests",
            "version" : "6.015"
         },
         {
            "class" : "Dist::Zilla::Plugin::PodLoom",
            "config" : {
               "Pod::Loom version" : "0.08"
            },
            "name" : "CJM/PodLoom",
            "version" : "5.001"
         },
         {
            "class" : "Dist::Zilla::Plugin::MakeMaker",
            "config" : {
               "Dist::Zilla::Role::TestRunner" : {
                  "default_jobs" : 1
               }
            },
            "name" : "CJM/MakeMaker",
            "version" : "6.015"
         },
         {
            "class" : "Dist::Zilla::Plugin::RunExtraTests",
            "config" : {
               "Dist::Zilla::Role::TestRunner" : {
                  "default_jobs" : 1
               }
            },
            "name" : "CJM/RunExtraTests",
            "version" : "0.029"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaConfig",
            "name" : "CJM/MetaConfig",
            "version" : "6.015"
         },
         {
            "class" : "Dist::Zilla::Plugin::MatchManifest",
            "name" : "CJM/MatchManifest",
            "version" : "6.000"
         },
         {
            "class" : "Dist::Zilla::Plugin::RecommendedPrereqs",
            "name" : "CJM/RecommendedPrereqs",
            "version" : "4.21"
         },
         {
            "class" : "Dist::Zilla::Plugin::CheckPrereqsIndexed",
            "name" : "CJM/CheckPrereqsIndexed",
            "version" : "0.020"
         },
         {
            "class" : "Dist::Zilla::Plugin::GitVersionCheckCJM",
            "name" : "CJM/GitVersionCheckCJM",
            "version" : "4.27"
         },
         {
            "class" : "Dist::Zilla::Plugin::TemplateCJM",
            "name" : "CJM/TemplateCJM",
            "version" : "5.002"
         },
         {
            "class" : "Dist::Zilla::Plugin::Repository",
            "name" : "CJM/Repository",
            "version" : "0.24"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::Check",
            "config" : {
               "Dist::Zilla::Plugin::Git::Check" : {
                  "untracked_files" : "die"
               },
               "Dist::Zilla::Role::Git::DirtyFiles" : {
                  "allow_dirty" : [
                     "Changes"
                  ],
                  "allow_dirty_match" : [],
                  "changelog" : "Changes"
               },
               "Dist::Zilla::Role::Git::Repo" : {
                  "git_version" : "2.28.0",
                  "repo_root" : "."
               }
            },
            "name" : "CJM/@Git/Check",
            "version" : "2.047"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::Commit",
            "config" : {
               "Dist::Zilla::Plugin::Git::Commit" : {
                  "add_files_in" : [],
                  "commit_msg" : "Updated Changes for %{MMMM d, yyyy}d%{ trial}t release of %v",
                  "signoff" : 0
               },
               "Dist::Zilla::Role::Git::DirtyFiles" : {
                  "allow_dirty" : [
                     "Changes"
                  ],
                  "allow_dirty_match" : [],
                  "changelog" : "Changes"
               },
               "Dist::Zilla::Role::Git::Repo" : {
                  "git_version" : "2.28.0",
                  "repo_root" : "."
               },
               "Dist::Zilla::Role::Git::StringFormatter" : {
                  "time_zone" : "local"
               }
            },
            "name" : "CJM/@Git/Commit",
            "version" : "2.047"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::Tag",
            "config" : {
               "Dist::Zilla::Plugin::Git::Tag" : {
                  "branch" : null,
                  "changelog" : "Changes",
                  "signed" : 0,
                  "tag" : "1.004",
                  "tag_format" : "%v%t",
                  "tag_message" : "Tagged %N %v%{ (trial release)}t"
               },
               "Dist::Zilla::Role::Git::Repo" : {
                  "git_version" : "2.28.0",
                  "repo_root" : "."
               },
               "Dist::Zilla::Role::Git::StringFormatter" : {
                  "time_zone" : "local"
               }
            },
            "name" : "CJM/@Git/Tag",
            "version" : "2.047"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::Push",
            "config" : {
               "Dist::Zilla::Plugin::Git::Push" : {
                  "push_to" : [
                     "github master"
                  ],
                  "remotes_must_exist" : 1
               },
               "Dist::Zilla::Role::Git::Repo" : {
                  "git_version" : "2.28.0",
                  "repo_root" : "."
               }
            },
            "name" : "CJM/@Git/Push",
            "version" : "2.047"
         },
         {
            "class" : "Dist::Zilla::Plugin::TestRelease",
            "name" : "CJM/TestRelease",
            "version" : "6.015"
         },
         {
            "class" : "Dist::Zilla::Plugin::UploadToCPAN",
            "name" : "CJM/UploadToCPAN",
            "version" : "6.015"
         },
         {
            "class" : "Dist::Zilla::Plugin::ArchiveRelease",
            "name" : "CJM/ArchiveRelease",
            "version" : "6.000"
         },
         {
            "class" : "Dist::Zilla::Plugin::AutoPrereqs",
            "name" : "AutoPrereqs",
            "version" : "6.015"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":InstallModules",
            "version" : "6.015"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":IncModules",
            "version" : "6.015"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":TestFiles",
            "version" : "6.015"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":ExtraTestFiles",
            "version" : "6.015"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":ExecFiles",
            "version" : "6.015"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":PerlExecFiles",
            "version" : "6.015"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":ShareFiles",
            "version" : "6.015"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":MainModule",
            "version" : "6.015"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":AllFiles",
            "version" : "6.015"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":NoFiles",
            "version" : "6.015"
         }
      ],
      "zilla" : {
         "class" : "Dist::Zilla::Dist::Builder",
         "config" : {
            "is_trial" : 0
         },
         "version" : "6.015"
      }
   },
   "x_generated_by_perl" : "v5.30.1",
   "x_serialization_backend" : "JSON::PP version 2.97001",
   "x_spdx_expression" : "Artistic-1.0-Perl OR GPL-1.0-or-later"
}
PK2N%[�^,��@perl5/x86_64-linux-thread-multi/.meta/IO-HTML-1.004/install.jsonnu��6�${"dist":"IO-HTML-1.004","version":1.004,"pathname":"C/CJ/CJM/IO-HTML-1.004.tar.gz","provides":{"IO::HTML":{"version":1.004,"file":"lib/IO/HTML.pm"}},"name":"IO::HTML","target":"IO::HTML"}PK2N%[�bxg"g"Bperl5/x86_64-linux-thread-multi/.meta/Alien-Build-2.84/MYMETA.jsonnu��6�${
   "abstract" : "Build external dependencies for use in CPAN",
   "author" : [
      "Graham Ollis <plicease@cpan.org>",
      "Joel Berger <joel.a.berger@gmail.com>"
   ],
   "dynamic_config" : 0,
   "generated_by" : "Dist::Zilla version 6.032, CPAN::Meta::Converter version 2.150010",
   "license" : [
      "perl_5"
   ],
   "meta-spec" : {
      "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
      "version" : 2
   },
   "name" : "Alien-Build",
   "no_index" : {
      "directory" : [
         "corpus",
         "example",
         "maint"
      ]
   },
   "prereqs" : {
      "build" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "6.64"
         }
      },
      "configure" : {
         "requires" : {
            "ExtUtils::CBuilder" : "0",
            "ExtUtils::MakeMaker" : "6.64",
            "ExtUtils::ParseXS" : "3.30",
            "File::Which" : "0"
         }
      },
      "develop" : {
         "recommends" : {
            "Dist::Zilla::Plugin::Author::Plicease::Thanks" : "0",
            "Dist::Zilla::Plugin::Author::Plicease::Upload" : "0",
            "Dist::Zilla::Plugin::DynamicPrereqs" : "0",
            "Dist::Zilla::Plugin::GatherFile" : "0",
            "Dist::Zilla::Plugin::MetaNoIndex" : "0",
            "Dist::Zilla::Plugin::Prereqs" : "0",
            "Dist::Zilla::Plugin::PruneFiles" : "0",
            "Dist::Zilla::Plugin::RemovePrereqs" : "0",
            "Dist::Zilla::PluginBundle::Author::Plicease" : "2.75",
            "Perl::Critic::Policy::BuiltinFunctions::ProhibitBooleanGrep" : "0",
            "Perl::Critic::Policy::BuiltinFunctions::ProhibitStringyEval" : "0",
            "Perl::Critic::Policy::BuiltinFunctions::ProhibitStringySplit" : "0",
            "Perl::Critic::Policy::BuiltinFunctions::ProhibitVoidGrep" : "0",
            "Perl::Critic::Policy::BuiltinFunctions::ProhibitVoidMap" : "0",
            "Perl::Critic::Policy::ClassHierarchies::ProhibitExplicitISA" : "0",
            "Perl::Critic::Policy::ClassHierarchies::ProhibitOneArgBless" : "0",
            "Perl::Critic::Policy::CodeLayout::ProhibitHardTabs" : "0",
            "Perl::Critic::Policy::CodeLayout::ProhibitTrailingWhitespace" : "0",
            "Perl::Critic::Policy::CodeLayout::RequireConsistentNewlines" : "0",
            "Perl::Critic::Policy::Community::ArrayAssignAref" : "0",
            "Perl::Critic::Policy::Community::BarewordFilehandles" : "0",
            "Perl::Critic::Policy::Community::ConditionalDeclarations" : "0",
            "Perl::Critic::Policy::Community::ConditionalImplicitReturn" : "0",
            "Perl::Critic::Policy::Community::DeprecatedFeatures" : "0",
            "Perl::Critic::Policy::Community::DiscouragedModules" : "0",
            "Perl::Critic::Policy::Community::DollarAB" : "0",
            "Perl::Critic::Policy::Community::Each" : "0",
            "Perl::Critic::Policy::Community::EmptyReturn" : "0",
            "Perl::Critic::Policy::Community::IndirectObjectNotation" : "0",
            "Perl::Critic::Policy::Community::LexicalForeachIterator" : "0",
            "Perl::Critic::Policy::Community::LoopOnHash" : "0",
            "Perl::Critic::Policy::Community::ModPerl" : "0",
            "Perl::Critic::Policy::Community::OpenArgs" : "0",
            "Perl::Critic::Policy::Community::OverloadOptions" : "0",
            "Perl::Critic::Policy::Community::POSIXImports" : "0",
            "Perl::Critic::Policy::Community::PackageMatchesFilename" : "0",
            "Perl::Critic::Policy::Community::PreferredAlternatives" : "0",
            "Perl::Critic::Policy::Community::StrictWarnings" : "0",
            "Perl::Critic::Policy::Community::Threads" : "0",
            "Perl::Critic::Policy::Community::Wantarray" : "0",
            "Perl::Critic::Policy::Community::WarningsSwitch" : "0",
            "Perl::Critic::Policy::Community::WhileDiamondDefaultAssignment" : "0",
            "Perl::Critic::Policy::ControlStructures::ProhibitLabelsWithSpecialBlockNames" : "0",
            "Perl::Critic::Policy::ControlStructures::ProhibitMutatingListFunctions" : "0",
            "Perl::Critic::Policy::ControlStructures::ProhibitUnreachableCode" : "0",
            "Perl::Critic::Policy::InputOutput::ProhibitBarewordFileHandles" : "0",
            "Perl::Critic::Policy::InputOutput::ProhibitJoinedReadline" : "0",
            "Perl::Critic::Policy::InputOutput::ProhibitTwoArgOpen" : "0",
            "Perl::Critic::Policy::Miscellanea::ProhibitFormats" : "0",
            "Perl::Critic::Policy::Miscellanea::ProhibitUselessNoCritic" : "0",
            "Perl::Critic::Policy::Modules::ProhibitConditionalUseStatements" : "0",
            "Perl::Critic::Policy::Modules::RequireNoMatchVarsWithUseEnglish" : "0",
            "Perl::Critic::Policy::Objects::ProhibitIndirectSyntax" : "0",
            "Perl::Critic::Policy::RegularExpressions::ProhibitUselessTopic" : "0",
            "Perl::Critic::Policy::Subroutines::ProhibitNestedSubs" : "0",
            "Perl::Critic::Policy::ValuesAndExpressions::ProhibitLeadingZeros" : "0",
            "Perl::Critic::Policy::ValuesAndExpressions::ProhibitMixedBooleanOperators" : "0",
            "Perl::Critic::Policy::ValuesAndExpressions::ProhibitSpecialLiteralHeredocTerminator" : "0",
            "Perl::Critic::Policy::ValuesAndExpressions::RequireUpperCaseHeredocTerminator" : "0",
            "Perl::Critic::Policy::Variables::ProhibitPerl4PackageNames" : "0",
            "Perl::Critic::Policy::Variables::ProhibitUnusedVariables" : "0",
            "Software::License::Perl_5" : "0"
         },
         "requires" : {
            "FindBin" : "0",
            "Perl::Critic" : "0",
            "Test2::Require::EnvVar" : "0.000121",
            "Test2::Require::Module" : "0.000121",
            "Test2::Tools::PerlCritic" : "0",
            "Test2::V0" : "0.000121",
            "Test::CPAN::Changes" : "0",
            "Test::EOL" : "0",
            "Test::Fixme" : "0.07",
            "Test::More" : "0.98",
            "Test::NoTabs" : "0",
            "Test::Pod" : "0",
            "Test::Pod::Coverage" : "0",
            "Test::Pod::LinkCheck::Lite" : "0",
            "Test::Spelling" : "0"
         }
      },
      "runtime" : {
         "requires" : {
            "Capture::Tiny" : "0.17",
            "Digest::SHA" : "0",
            "ExtUtils::CBuilder" : "0",
            "ExtUtils::MakeMaker" : "6.64",
            "ExtUtils::ParseXS" : "3.30",
            "FFI::CheckLib" : "0.11",
            "File::Which" : "1.10",
            "File::chdir" : "0",
            "JSON::PP" : "0",
            "List::Util" : "1.33",
            "Path::Tiny" : "0.077",
            "Test2::API" : "1.302096",
            "Text::ParseWords" : "3.26",
            "parent" : "0",
            "perl" : "5.008004"
         },
         "suggests" : {
            "Archive::Tar" : "0"
         }
      },
      "test" : {
         "requires" : {
            "Test2::API" : "1.302096",
            "Test2::V0" : "0.000121"
         },
         "suggests" : {
            "Devel::Hide" : "0"
         }
      }
   },
   "release_status" : "stable",
   "resources" : {
      "bugtracker" : {
         "web" : "https://github.com/PerlAlien/Alien-Build/issues"
      },
      "homepage" : "https://metacpan.org/pod/Alien::Build",
      "repository" : {
         "type" : "git",
         "url" : "git://github.com/PerlAlien/Alien-Build.git",
         "web" : "https://github.com/PerlAlien/Alien-Build"
      },
      "x_IRC" : "irc://irc.perl.org/#native"
   },
   "version" : "2.84",
   "x_contributors" : [
      "Graham Ollis <plicease@cpan.org>",
      "Diab Jerius (DJERIUS)",
      "Roy Storey (KIWIROY)",
      "Ilya Pavlov",
      "David Mertens (run4flat)",
      "Mark Nunberg (mordy, mnunberg)",
      "Christian Walde (Mithaldu)",
      "Brian Wightman (MidLifeXis)",
      "Zaki Mughal (zmughal)",
      "mohawk (mohawk2, ETJ)",
      "Vikas N Kumar (vikasnkumar)",
      "Flavio Poletti (polettix)",
      "Salvador Fandiño (salva)",
      "Gianni Ceccarelli (dakkar)",
      "Pavel Shaydo (zwon, trinitum)",
      "Kang-min Liu (劉康民, gugod)",
      "Nicholas Shipp (nshp)",
      "Juan Julián Merelo Guervós (JJ)",
      "Joel Berger (JBERGER)",
      "Petr Písař (ppisar)",
      "Lance Wicks (LANCEW)",
      "Ahmad Fatoum (a3f, ATHREEF)",
      "José Joaquín Atria (JJATRIA)",
      "Duke Leto (LETO)",
      "Shoichi Kaji (SKAJI)",
      "Shawn Laffan (SLAFFAN)",
      "Paul Evans (leonerd, PEVANS)",
      "Håkon Hægland (hakonhagland, HAKONH)",
      "nick nauwelaerts (INPHOBIA)",
      "Florian Weimer"
   ],
   "x_generated_by_perl" : "v5.40.0",
   "x_serialization_backend" : "JSON::PP version 2.97001",
   "x_spdx_expression" : "Artistic-1.0-Perl OR GPL-1.0-or-later",
   "x_use_unsafe_inc" : 0
}
PK2N%[)�ٺ��Cperl5/x86_64-linux-thread-multi/.meta/Alien-Build-2.84/install.jsonnu��6�${"pathname":"P/PL/PLICEASE/Alien-Build-2.84.tar.gz","version":2.84,"target":"Alien::Build::Plugin::Prefer::BadVersion","provides":{"Alien::Build::Plugin::Prefer::BadVersion":{"version":2.84,"file":"lib/Alien/Build/Plugin/Prefer/BadVersion.pm"},"Test::Alien::CanPlatypus":{"version":2.84,"file":"lib/Test/Alien/CanPlatypus.pm"},"Alien::Build::Interpolate::Helper":{"version":2.84,"file":"lib/Alien/Build/Interpolate.pm"},"Alien::Build::Plugin::Build::MSYS":{"file":"lib/Alien/Build/Plugin/Build/MSYS.pm","version":2.84},"Alien::Build::Log::Abbreviate":{"version":2.84,"file":"lib/Alien/Build/Log/Abbreviate.pm"},"Alien::Build::Plugin::Extract::CommandLine":{"file":"lib/Alien/Build/Plugin/Extract/CommandLine.pm","version":2.84},"Test::Alien::CanCompile":{"file":"lib/Test/Alien/CanCompile.pm","version":2.84},"Alien::Build::PluginMeta":{"file":"lib/Alien/Build/Plugin.pm","version":2.84},"Alien::Build::Interpolate":{"version":2.84,"file":"lib/Alien/Build/Interpolate.pm"},"Alien::Build::Plugin::Prefer::SortVersions":{"version":2.84,"file":"lib/Alien/Build/Plugin/Prefer/SortVersions.pm"},"Alien::Build::MM":{"version":2.84,"file":"lib/Alien/Build/MM.pm"},"Alien::Build::Plugin::Build::SearchDep":{"version":2.84,"file":"lib/Alien/Build/Plugin/Build/SearchDep.pm"},"Alien::Build::Plugin::Build::Make":{"version":2.84,"file":"lib/Alien/Build/Plugin/Build/Make.pm"},"Alien::Build::Plugin::Extract::ArchiveZip":{"file":"lib/Alien/Build/Plugin/Extract/ArchiveZip.pm","version":2.84},"Alien::Build::Plugin::PkgConfig::MakeStatic":{"file":"lib/Alien/Build/Plugin/PkgConfig/MakeStatic.pm","version":2.84},"Alien::Build::Plugin::Fetch::NetFTP":{"file":"lib/Alien/Build/Plugin/Fetch/NetFTP.pm","version":2.84},"Alien::Build::Plugin::Core::Legacy":{"version":2.84,"file":"lib/Alien/Build/Plugin/Core/Legacy.pm"},"Alien::Base::Wrapper":{"version":2.84,"file":"lib/Alien/Base/Wrapper.pm"},"Alien::Build::Temp":{"file":"lib/Alien/Build/Temp.pm","version":2.84},"Alien::Build::Plugin::Extract::Negotiate":{"file":"lib/Alien/Build/Plugin/Extract/Negotiate.pm","version":2.84},"Alien::Build::Plugin::Core::Override":{"version":2.84,"file":"lib/Alien/Build/Plugin/Core/Override.pm"},"Alien::Build::Plugin::Prefer::GoodVersion":{"version":2.84,"file":"lib/Alien/Build/Plugin/Prefer/GoodVersion.pm"},"Alien::Build::Plugin::Test::Mock":{"version":2.84,"file":"lib/Alien/Build/Plugin/Test/Mock.pm"},"Alien::Build::Plugin::Build::Copy":{"version":2.84,"file":"lib/Alien/Build/Plugin/Build/Copy.pm"},"Alien::Build::Plugin::Digest::SHA":{"version":2.84,"file":"lib/Alien/Build/Plugin/Digest/SHA.pm"},"Alien::Build::Plugin::Core::Download":{"version":2.84,"file":"lib/Alien/Build/Plugin/Core/Download.pm"},"Alien::Build::TempDir":{"file":"lib/Alien/Build.pm","version":2.84},"Alien::Build::CommandSequence":{"version":2.84,"file":"lib/Alien/Build/CommandSequence.pm"},"Alien::Build::Plugin::Core::Gather":{"version":2.84,"file":"lib/Alien/Build/Plugin/Core/Gather.pm"},"Alien::Build::Plugin::Decode::HTML":{"version":2.84,"file":"lib/Alien/Build/Plugin/Decode/HTML.pm"},"Test::Alien":{"file":"lib/Test/Alien.pm","version":2.84},"Alien::Build::Plugin::Fetch::LWP":{"file":"lib/Alien/Build/Plugin/Fetch/LWP.pm","version":2.84},"Alien::Build::Plugin::Fetch::Local":{"file":"lib/Alien/Build/Plugin/Fetch/Local.pm","version":2.84},"Alien::Build::Plugin::Gather::IsolateDynamic":{"file":"lib/Alien/Build/Plugin/Gather/IsolateDynamic.pm","version":2.84},"Alien::Build::Plugin::Fetch::LocalDir":{"file":"lib/Alien/Build/Plugin/Fetch/LocalDir.pm","version":2.84},"Alien::Build::Plugin::Extract::Directory":{"version":2.84,"file":"lib/Alien/Build/Plugin/Extract/Directory.pm"},"Alien::Build":{"file":"lib/Alien/Build.pm","version":2.84},"Alien::Build::Util":{"version":2.84,"file":"lib/Alien/Build/Util.pm"},"Alien::Base::PkgConfig":{"file":"lib/Alien/Base/PkgConfig.pm","version":2.84},"Alien::Build::Plugin::Fetch::Wget":{"file":"lib/Alien/Build/Plugin/Fetch/Wget.pm","version":2.84},"Alien::Build::Plugin::Decode::DirListingFtpcopy":{"version":2.84,"file":"lib/Alien/Build/Plugin/Decode/DirListingFtpcopy.pm"},"Alien::Build::Plugin::Core::FFI":{"version":2.84,"file":"lib/Alien/Build/Plugin/Core/FFI.pm"},"Alien::Build::Plugin::Probe::CommandLine":{"file":"lib/Alien/Build/Plugin/Probe/CommandLine.pm","version":2.84},"Alien::Build::Plugin::Extract::ArchiveTar":{"file":"lib/Alien/Build/Plugin/Extract/ArchiveTar.pm","version":2.84},"Alien::Build::Plugin::Fetch::CurlCommand":{"file":"lib/Alien/Build/Plugin/Fetch/CurlCommand.pm","version":2.84},"Alien::Util":{"version":2.84,"file":"lib/Alien/Util.pm"},"Alien::Build::Plugin::Download::Negotiate":{"version":2.84,"file":"lib/Alien/Build/Plugin/Download/Negotiate.pm"},"Alien::Build::Plugin":{"file":"lib/Alien/Build/Plugin.pm","version":2.84},"Alien::Build::Helper":{"version":2.84,"file":"lib/Alien/Build/Interpolate.pm"},"Alien::Build::Plugin::Build::CMake":{"file":"lib/Alien/Build/Plugin/Build/CMake.pm","version":2.84},"Alien::Role":{"version":2.84,"file":"lib/Alien/Role.pm"},"Alien::Build::Plugin::Decode::DirListing":{"file":"lib/Alien/Build/Plugin/Decode/DirListing.pm","version":2.84},"Alien::Build::Plugin::PkgConfig::Negotiate":{"file":"lib/Alien/Build/Plugin/PkgConfig/Negotiate.pm","version":2.84},"Alien::Build::Plugin::Core::Setup":{"file":"lib/Alien/Build/Plugin/Core/Setup.pm","version":2.84},"Alien::Build::Version::Basic":{"file":"lib/Alien/Build/Version/Basic.pm","version":2.84},"Alien::Build::Plugin::Probe::CBuilder":{"version":2.84,"file":"lib/Alien/Build/Plugin/Probe/CBuilder.pm"},"Alien::Build::Log::Default":{"version":2.84,"file":"lib/Alien/Build/Log/Default.pm"},"Alien::Build::Meta":{"file":"lib/Alien/Build.pm","version":2.84},"Alien::Build::Plugin::Fetch::HTTPTiny":{"version":2.84,"file":"lib/Alien/Build/Plugin/Fetch/HTTPTiny.pm"},"Alien::Build::Plugin::PkgConfig::CommandLine":{"file":"lib/Alien/Build/Plugin/PkgConfig/CommandLine.pm","version":2.84},"Alien::Build::Plugin::Extract::File":{"version":2.84,"file":"lib/Alien/Build/Plugin/Extract/File.pm"},"alienfile":{"file":"lib/alienfile.pm","version":2.84},"Alien::Build::Interpolate::Default":{"version":2.84,"file":"lib/Alien/Build/Interpolate/Default.pm"},"Alien::Build::Plugin::PkgConfig::PP":{"version":2.84,"file":"lib/Alien/Build/Plugin/PkgConfig/PP.pm"},"Alien::Base":{"file":"lib/Alien/Base.pm","version":2.84},"Alien::Build::Log":{"file":"lib/Alien/Build/Log.pm","version":2.84},"Test::Alien::Synthetic":{"file":"lib/Test/Alien/Synthetic.pm","version":2.84},"Alien::Build::Plugin::Decode::Mojo":{"file":"lib/Alien/Build/Plugin/Decode/Mojo.pm","version":2.84},"Test::Alien::Build":{"file":"lib/Test/Alien/Build.pm","version":2.84},"Alien::Build::Plugin::Digest::Negotiate":{"version":2.84,"file":"lib/Alien/Build/Plugin/Digest/Negotiate.pm"},"Test::Alien::Run":{"version":2.84,"file":"lib/Test/Alien/Run.pm"},"Alien::Build::Plugin::Core::Tail":{"file":"lib/Alien/Build/Plugin/Core/Tail.pm","version":2.84},"Alien::Build::Plugin::Digest::SHAPP":{"file":"lib/Alien/Build/Plugin/Digest/SHAPP.pm","version":2.84},"Test::Alien::Diag":{"file":"lib/Test/Alien/Diag.pm","version":2.84},"Alien::Build::Plugin::Build::Autoconf":{"version":2.84,"file":"lib/Alien/Build/Plugin/Build/Autoconf.pm"},"Alien::Build::Plugin::PkgConfig::LibPkgConf":{"file":"lib/Alien/Build/Plugin/PkgConfig/LibPkgConf.pm","version":2.84},"Alien::Build::Plugin::Probe::Vcpkg":{"version":2.84,"file":"lib/Alien/Build/Plugin/Probe/Vcpkg.pm"},"Alien::Build::Plugin::Core::CleanInstall":{"version":2.84,"file":"lib/Alien/Build/Plugin/Core/CleanInstall.pm"},"Alien::Build::rc":{"file":"lib/Alien/Build.pm","version":2.84}},"name":"Alien::Build","dist":"Alien-Build-2.84"}PK2N%[���8��Cperl5/x86_64-linux-thread-multi/.meta/File-chdir-0.1011/MYMETA.jsonnu��6�${
   "abstract" : "a more sensible way to change directories",
   "author" : [
      "David Golden <dagolden@cpan.org>",
      "Michael G. Schwern <schwern@pobox.com>"
   ],
   "dynamic_config" : 0,
   "generated_by" : "Dist::Zilla version 6.008, CPAN::Meta::Converter version 2.150010",
   "license" : [
      "perl_5"
   ],
   "meta-spec" : {
      "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
      "version" : 2
   },
   "name" : "File-chdir",
   "no_index" : {
      "directory" : [
         "corpus",
         "examples",
         "t",
         "xt"
      ],
      "package" : [
         "DB"
      ]
   },
   "prereqs" : {
      "build" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "configure" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "6.17"
         }
      },
      "develop" : {
         "requires" : {
            "Dist::Zilla" : "5",
            "Dist::Zilla::PluginBundle::DAGOLDEN" : "0.072",
            "English" : "0",
            "File::Spec" : "0",
            "File::Temp" : "0",
            "IO::Handle" : "0",
            "IPC::Open3" : "0",
            "Pod::Coverage::TrustPod" : "0",
            "Pod::Wordlist" : "0",
            "Software::License::Perl_5" : "0",
            "Test::CPAN::Meta" : "0",
            "Test::More" : "0",
            "Test::Pod" : "1.41",
            "Test::Pod::Coverage" : "1.08",
            "Test::Portability::Files" : "0",
            "Test::Spelling" : "0.12",
            "Test::Version" : "1",
            "blib" : "1.01",
            "perl" : "5.006",
            "warnings" : "0"
         }
      },
      "runtime" : {
         "requires" : {
            "Carp" : "0",
            "Cwd" : "3.16",
            "Exporter" : "0",
            "File::Spec::Functions" : "3.27",
            "perl" : "5.006",
            "strict" : "0",
            "vars" : "0"
         }
      },
      "test" : {
         "recommends" : {
            "CPAN::Meta" : "2.120900"
         },
         "requires" : {
            "ExtUtils::MakeMaker" : "0",
            "File::Spec" : "0",
            "Test::More" : "0",
            "warnings" : "0"
         }
      }
   },
   "provides" : {
      "File::chdir" : {
         "file" : "lib/File/chdir.pm",
         "version" : "0.1011"
      },
      "File::chdir::ARRAY" : {
         "file" : "lib/File/chdir.pm",
         "version" : "0.1011"
      },
      "File::chdir::SCALAR" : {
         "file" : "lib/File/chdir.pm",
         "version" : "0.1011"
      }
   },
   "release_status" : "stable",
   "resources" : {
      "bugtracker" : {
         "web" : "https://github.com/dagolden/File-chdir/issues"
      },
      "homepage" : "https://github.com/dagolden/File-chdir",
      "repository" : {
         "type" : "git",
         "url" : "https://github.com/dagolden/File-chdir.git",
         "web" : "https://github.com/dagolden/File-chdir"
      }
   },
   "version" : "0.1011",
   "x_authority" : "cpan:DAGOLDEN",
   "x_contributors" : [
      "David Golden <xdg@xdg.me>",
      "Joel Berger <joel.a.berger@gmail.com>",
      "Philippe Bruhat (BooK) <book@cpan.org>"
   ],
   "x_serialization_backend" : "JSON::PP version 2.97001"
}
PK2N%[���eeDperl5/x86_64-linux-thread-multi/.meta/File-chdir-0.1011/install.jsonnu��6�${"version":"0.1011","pathname":"D/DA/DAGOLDEN/File-chdir-0.1011.tar.gz","target":"File::chdir","provides":{"File::chdir::ARRAY":{"file":"lib/File/chdir.pm","version":"0.1011"},"File::chdir::SCALAR":{"version":"0.1011","file":"lib/File/chdir.pm"},"File::chdir":{"version":"0.1011","file":"lib/File/chdir.pm"}},"dist":"File-chdir-0.1011","name":"File::chdir"}PK2N%[�Q�EGperl5/x86_64-linux-thread-multi/.meta/Canary-Stability-2013/MYMETA.jsonnu��6�${
   "abstract" : "unknown",
   "author" : [
      "unknown"
   ],
   "dynamic_config" : 0,
   "generated_by" : "ExtUtils::MakeMaker version 7.34, CPAN::Meta::Converter version 2.150010",
   "license" : [
      "unknown"
   ],
   "meta-spec" : {
      "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
      "version" : 2
   },
   "name" : "Canary-Stability",
   "no_index" : {
      "directory" : [
         "t",
         "inc"
      ]
   },
   "prereqs" : {
      "build" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "configure" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      }
   },
   "release_status" : "stable",
   "version" : "2013",
   "x_serialization_backend" : "JSON::PP version 2.97001"
}
PK2N%[.A����Hperl5/x86_64-linux-thread-multi/.meta/Canary-Stability-2013/install.jsonnu��6�${"version":2013,"dist":"Canary-Stability-2013","name":"Canary::Stability","pathname":"M/ML/MLEHMANN/Canary-Stability-2013.tar.gz","target":"Canary::Stability","provides":{"Canary::Stability":{"version":2013,"file":"Stability.pm"}}}PK2N%[e�����Bperl5/x86_64-linux-thread-multi/.meta/Scope-Guard-0.21/MYMETA.jsonnu��6�${
   "abstract" : "lexically-scoped resource management",
   "author" : [
      "chocolateboy <chocolate@cpan.org>"
   ],
   "dynamic_config" : 0,
   "generated_by" : "ExtUtils::MakeMaker version 7.0401, CPAN::Meta::Converter version 2.150005, CPAN::Meta::Converter version 2.150010",
   "license" : [
      "perl_5"
   ],
   "meta-spec" : {
      "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
      "version" : 2
   },
   "name" : "Scope-Guard",
   "no_index" : {
      "directory" : [
         "t",
         "inc"
      ]
   },
   "prereqs" : {
      "build" : {
         "requires" : {
            "Test::More" : "0"
         }
      },
      "configure" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "runtime" : {
         "requires" : {
            "perl" : "5.006001"
         }
      }
   },
   "release_status" : "stable",
   "resources" : {
      "bugtracker" : {
         "web" : "https://github.com/chocolateboy/Scope-Guard/issues"
      },
      "repository" : {
         "url" : "https://github.com/chocolateboy/Scope-Guard"
      }
   },
   "version" : "0.21",
   "x_serialization_backend" : "JSON::PP version 2.97001",
   "x_test_requires" : {
      "Test::More" : 0
   }
}
PK2N%[��\\��Cperl5/x86_64-linux-thread-multi/.meta/Scope-Guard-0.21/install.jsonnu��6�${"version":0.21,"target":"Scope::Guard","provides":{"Scope::Guard":{"file":"lib/Scope/Guard.pm","version":0.21}},"dist":"Scope-Guard-0.21","pathname":"C/CH/CHOCOLATE/Scope-Guard-0.21.tar.gz","name":"Scope::Guard"}PK2N%[V�Yperl5/x86_64-linux-thread-multi/.meta/Alien-Build-Plugin-Download-GitLab-0.01/MYMETA.jsonnu��6�${
   "abstract" : "Alien::Build plugin to download from GitLab",
   "author" : [
      "Graham Ollis <plicease@cpan.org>"
   ],
   "dynamic_config" : 0,
   "generated_by" : "Dist::Zilla version 6.025, CPAN::Meta::Converter version 2.150010",
   "license" : [
      "perl_5"
   ],
   "meta-spec" : {
      "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
      "version" : 2
   },
   "name" : "Alien-Build-Plugin-Download-GitLab",
   "prereqs" : {
      "build" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "configure" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "develop" : {
         "recommends" : {
            "Dist::Zilla::Plugin::Author::Plicease::Core" : "0",
            "Dist::Zilla::Plugin::Author::Plicease::Upload" : "0",
            "Dist::Zilla::PluginBundle::Author::Plicease" : "2.71",
            "Perl::Critic::Policy::BuiltinFunctions::ProhibitBooleanGrep" : "0",
            "Perl::Critic::Policy::BuiltinFunctions::ProhibitStringyEval" : "0",
            "Perl::Critic::Policy::BuiltinFunctions::ProhibitStringySplit" : "0",
            "Perl::Critic::Policy::BuiltinFunctions::ProhibitVoidGrep" : "0",
            "Perl::Critic::Policy::BuiltinFunctions::ProhibitVoidMap" : "0",
            "Perl::Critic::Policy::ClassHierarchies::ProhibitExplicitISA" : "0",
            "Perl::Critic::Policy::ClassHierarchies::ProhibitOneArgBless" : "0",
            "Perl::Critic::Policy::CodeLayout::ProhibitHardTabs" : "0",
            "Perl::Critic::Policy::CodeLayout::ProhibitTrailingWhitespace" : "0",
            "Perl::Critic::Policy::CodeLayout::RequireConsistentNewlines" : "0",
            "Perl::Critic::Policy::Community::ArrayAssignAref" : "0",
            "Perl::Critic::Policy::Community::BarewordFilehandles" : "0",
            "Perl::Critic::Policy::Community::ConditionalDeclarations" : "0",
            "Perl::Critic::Policy::Community::ConditionalImplicitReturn" : "0",
            "Perl::Critic::Policy::Community::DeprecatedFeatures" : "0",
            "Perl::Critic::Policy::Community::DiscouragedModules" : "0",
            "Perl::Critic::Policy::Community::DollarAB" : "0",
            "Perl::Critic::Policy::Community::Each" : "0",
            "Perl::Critic::Policy::Community::EmptyReturn" : "0",
            "Perl::Critic::Policy::Community::IndirectObjectNotation" : "0",
            "Perl::Critic::Policy::Community::LexicalForeachIterator" : "0",
            "Perl::Critic::Policy::Community::LoopOnHash" : "0",
            "Perl::Critic::Policy::Community::ModPerl" : "0",
            "Perl::Critic::Policy::Community::OpenArgs" : "0",
            "Perl::Critic::Policy::Community::OverloadOptions" : "0",
            "Perl::Critic::Policy::Community::POSIXImports" : "0",
            "Perl::Critic::Policy::Community::PackageMatchesFilename" : "0",
            "Perl::Critic::Policy::Community::PreferredAlternatives" : "0",
            "Perl::Critic::Policy::Community::StrictWarnings" : "0",
            "Perl::Critic::Policy::Community::Threads" : "0",
            "Perl::Critic::Policy::Community::Wantarray" : "0",
            "Perl::Critic::Policy::Community::WarningsSwitch" : "0",
            "Perl::Critic::Policy::Community::WhileDiamondDefaultAssignment" : "0",
            "Perl::Critic::Policy::ControlStructures::ProhibitLabelsWithSpecialBlockNames" : "0",
            "Perl::Critic::Policy::ControlStructures::ProhibitMutatingListFunctions" : "0",
            "Perl::Critic::Policy::ControlStructures::ProhibitUnreachableCode" : "0",
            "Perl::Critic::Policy::InputOutput::ProhibitBarewordFileHandles" : "0",
            "Perl::Critic::Policy::InputOutput::ProhibitJoinedReadline" : "0",
            "Perl::Critic::Policy::InputOutput::ProhibitTwoArgOpen" : "0",
            "Perl::Critic::Policy::Miscellanea::ProhibitFormats" : "0",
            "Perl::Critic::Policy::Miscellanea::ProhibitUselessNoCritic" : "0",
            "Perl::Critic::Policy::Modules::ProhibitConditionalUseStatements" : "0",
            "Perl::Critic::Policy::Modules::RequireNoMatchVarsWithUseEnglish" : "0",
            "Perl::Critic::Policy::Objects::ProhibitIndirectSyntax" : "0",
            "Perl::Critic::Policy::RegularExpressions::ProhibitUselessTopic" : "0",
            "Perl::Critic::Policy::Subroutines::ProhibitNestedSubs" : "0",
            "Perl::Critic::Policy::ValuesAndExpressions::ProhibitLeadingZeros" : "0",
            "Perl::Critic::Policy::ValuesAndExpressions::ProhibitMixedBooleanOperators" : "0",
            "Perl::Critic::Policy::ValuesAndExpressions::ProhibitSpecialLiteralHeredocTerminator" : "0",
            "Perl::Critic::Policy::ValuesAndExpressions::RequireUpperCaseHeredocTerminator" : "0",
            "Perl::Critic::Policy::Variables::ProhibitPerl4PackageNames" : "0",
            "Perl::Critic::Policy::Variables::ProhibitUnusedVariables" : "0",
            "Software::License::Perl_5" : "0"
         },
         "requires" : {
            "File::Spec" : "0",
            "FindBin" : "0",
            "Perl::Critic" : "0",
            "Test2::Require::Module" : "0.000121",
            "Test2::Tools::PerlCritic" : "0",
            "Test2::V0" : "0.000121",
            "Test::CPAN::Changes" : "0",
            "Test::EOL" : "0",
            "Test::Fixme" : "0.07",
            "Test::More" : "0.98",
            "Test::NoTabs" : "0",
            "Test::Pod" : "0",
            "Test::Pod::Coverage" : "0",
            "Test::Pod::Spelling::CommonMistakes" : "0",
            "Test::Spelling" : "0",
            "Test::Strict" : "0",
            "YAML" : "0"
         }
      },
      "runtime" : {
         "requires" : {
            "Alien::Build::Plugin" : "0",
            "JSON::PP" : "0",
            "Path::Tiny" : "0",
            "URI" : "0",
            "URI::Escape" : "0",
            "perl" : "5.008004"
         }
      },
      "test" : {
         "requires" : {
            "Test2::V0" : "0.000121"
         }
      }
   },
   "release_status" : "stable",
   "resources" : {
      "bugtracker" : {
         "web" : "https://github.com/PerlAlien/Alien-Build-Plugin-Download-GitLab/issues"
      },
      "homepage" : "https://metacpan.org/pod/Alien::Build::Plugin::Download::GitLab",
      "repository" : {
         "type" : "git",
         "url" : "git://github.com/PerlAlien/Alien-Build-Plugin-Download-GitLab.git",
         "web" : "https://github.com/PerlAlien/Alien-Build-Plugin-Download-GitLab"
      },
      "x_IRC" : "irc://irc.perl.org/#native"
   },
   "version" : "0.01",
   "x_generated_by_perl" : "v5.35.10",
   "x_serialization_backend" : "JSON::PP version 2.97001",
   "x_spdx_expression" : "Artistic-1.0-Perl OR GPL-1.0-or-later",
   "x_use_unsafe_inc" : 0
}
PK2N%[�؀�ggZperl5/x86_64-linux-thread-multi/.meta/Alien-Build-Plugin-Download-GitLab-0.01/install.jsonnu��6�${"dist":"Alien-Build-Plugin-Download-GitLab-0.01","name":"Alien::Build::Plugin::Download::GitLab","provides":{"Alien::Build::Plugin::Download::GitLab":{"file":"lib/Alien/Build/Plugin/Download/GitLab.pm","version":0.01}},"target":"Alien::Build::Plugin::Download::GitLab","version":0.01,"pathname":"P/PL/PLICEASE/Alien-Build-Plugin-Download-GitLab-0.01.tar.gz"}PK2N%[h�d�DDFperl5/x86_64-linux-thread-multi/.meta/CPAN-Meta-YAML-0.020/MYMETA.jsonnu��6�${
   "abstract" : "Read and write a subset of YAML for CPAN Meta files",
   "author" : [
      "Adam Kennedy <adamk@cpan.org>",
      "David Golden <dagolden@cpan.org>"
   ],
   "dynamic_config" : 0,
   "generated_by" : "Dist::Zilla version 6.032, CPAN::Meta::Converter version 2.150010",
   "license" : [
      "perl_5"
   ],
   "meta-spec" : {
      "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
      "version" : 2
   },
   "name" : "CPAN-Meta-YAML",
   "no_index" : {
      "directory" : [
         "corpus",
         "examples",
         "t",
         "xt"
      ],
      "package" : [
         "DB"
      ]
   },
   "prereqs" : {
      "build" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "configure" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "6.17"
         }
      },
      "develop" : {
         "requires" : {
            "Dist::Zilla" : "5",
            "Dist::Zilla::Plugin::AppendExternalData" : "0",
            "Dist::Zilla::Plugin::Authority" : "0",
            "Dist::Zilla::Plugin::AutoPrereqs" : "0",
            "Dist::Zilla::Plugin::CheckChangesHasContent" : "0",
            "Dist::Zilla::Plugin::CheckMetaResources" : "0",
            "Dist::Zilla::Plugin::CheckPrereqsIndexed" : "0",
            "Dist::Zilla::Plugin::ConfirmRelease" : "0",
            "Dist::Zilla::Plugin::Doppelgaenger" : "0.007",
            "Dist::Zilla::Plugin::Encoding" : "0",
            "Dist::Zilla::Plugin::Git::Check" : "0",
            "Dist::Zilla::Plugin::Git::CheckFor::CorrectBranch" : "0",
            "Dist::Zilla::Plugin::Git::Commit" : "0",
            "Dist::Zilla::Plugin::Git::Contributors" : "0",
            "Dist::Zilla::Plugin::Git::GatherDir" : "0",
            "Dist::Zilla::Plugin::Git::NextVersion" : "0",
            "Dist::Zilla::Plugin::Git::Push" : "0",
            "Dist::Zilla::Plugin::Git::Tag" : "0",
            "Dist::Zilla::Plugin::GithubMeta" : "0",
            "Dist::Zilla::Plugin::License" : "0",
            "Dist::Zilla::Plugin::MakeMaker" : "0",
            "Dist::Zilla::Plugin::MakeMaker::Highlander" : "0.003",
            "Dist::Zilla::Plugin::Manifest" : "0",
            "Dist::Zilla::Plugin::MetaJSON" : "0",
            "Dist::Zilla::Plugin::MetaNoIndex" : "0",
            "Dist::Zilla::Plugin::MetaProvides::Package" : "0",
            "Dist::Zilla::Plugin::MetaResources" : "0",
            "Dist::Zilla::Plugin::MetaTests" : "0",
            "Dist::Zilla::Plugin::MetaYAML" : "0",
            "Dist::Zilla::Plugin::MinimumPerl" : "0",
            "Dist::Zilla::Plugin::NextRelease" : "5.033",
            "Dist::Zilla::Plugin::PkgVersion" : "0",
            "Dist::Zilla::Plugin::Pod2Readme" : "0",
            "Dist::Zilla::Plugin::PodSyntaxTests" : "0",
            "Dist::Zilla::Plugin::PodWeaver" : "0",
            "Dist::Zilla::Plugin::Prereqs::AuthorDeps" : "0",
            "Dist::Zilla::Plugin::PromptIfStale" : "0",
            "Dist::Zilla::Plugin::RemovePrereqs" : "0",
            "Dist::Zilla::Plugin::RunExtraTests" : "0",
            "Dist::Zilla::Plugin::Test::Compile" : "0",
            "Dist::Zilla::Plugin::Test::ReportPrereqs" : "0",
            "Dist::Zilla::Plugin::Test::Version" : "0",
            "Dist::Zilla::Plugin::TestRelease" : "0",
            "Dist::Zilla::Plugin::UploadToCPAN" : "0",
            "File::Spec" : "0",
            "File::Temp" : "0",
            "IO::Handle" : "0",
            "IPC::Open3" : "0",
            "Software::License::Perl_5" : "0",
            "Test::CPAN::Meta" : "0",
            "Test::More" : "0",
            "Test::Pod" : "1.41",
            "Test::Version" : "1"
         }
      },
      "runtime" : {
         "requires" : {
            "B" : "0",
            "Carp" : "0",
            "Exporter" : "0",
            "Fcntl" : "0",
            "Scalar::Util" : "0",
            "perl" : "5.008001",
            "strict" : "0",
            "warnings" : "0"
         }
      },
      "test" : {
         "recommends" : {
            "CPAN::Meta" : "2.120900"
         },
         "requires" : {
            "ExtUtils::MakeMaker" : "0",
            "File::Basename" : "0",
            "File::Find" : "0",
            "File::Spec" : "0",
            "File::Spec::Functions" : "0",
            "File::Temp" : "0.19",
            "IO::Dir" : "0",
            "JSON::PP" : "0",
            "Test::More" : "0.88",
            "base" : "0",
            "lib" : "0",
            "open" : "0",
            "utf8" : "0",
            "vars" : "0"
         }
      }
   },
   "provides" : {
      "CPAN::Meta::YAML" : {
         "file" : "lib/CPAN/Meta/YAML.pm",
         "version" : "0.020"
      }
   },
   "release_status" : "stable",
   "resources" : {
      "bugtracker" : {
         "web" : "https://github.com/Perl-Toolchain-Gang/YAML-Tiny/issues"
      },
      "homepage" : "https://github.com/Perl-Toolchain-Gang/CPAN-Meta-YAML",
      "repository" : {
         "type" : "git",
         "url" : "https://github.com/Perl-Toolchain-Gang/CPAN-Meta-YAML.git",
         "web" : "https://github.com/Perl-Toolchain-Gang/CPAN-Meta-YAML"
      }
   },
   "version" : "0.020",
   "x_authority" : "cpan:DAGOLDEN",
   "x_contributors" : [
      "Karen Etheridge <ether@cpan.org>"
   ],
   "x_generated_by_perl" : "v5.41.6",
   "x_serialization_backend" : "JSON::PP version 2.97001",
   "x_spdx_expression" : "Artistic-1.0-Perl OR GPL-1.0-or-later"
}
PK2N%[|h�-��Gperl5/x86_64-linux-thread-multi/.meta/CPAN-Meta-YAML-0.020/install.jsonnu��6�${"version":"0.020","dist":"CPAN-Meta-YAML-0.020","name":"CPAN::Meta::YAML","pathname":"E/ET/ETHER/CPAN-Meta-YAML-0.020.tar.gz","provides":{"CPAN::Meta::YAML":{"file":"lib/CPAN/Meta/YAML.pm","version":"0.020"}},"target":"CPAN::Meta::YAML"}PK2N%[|��Wxx>perl5/x86_64-linux-thread-multi/.meta/XML-SAX-1.02/MYMETA.jsonnu��6�${
   "abstract" : "unknown",
   "author" : [
      "unknown"
   ],
   "dynamic_config" : 0,
   "generated_by" : "ExtUtils::MakeMaker version 7.0401, CPAN::Meta::Converter version 2.150005, CPAN::Meta::Converter version 2.150010",
   "license" : [
      "unknown"
   ],
   "meta-spec" : {
      "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
      "version" : 2
   },
   "name" : "XML-SAX",
   "no_index" : {
      "directory" : [
         "t",
         "inc"
      ]
   },
   "prereqs" : {
      "build" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "configure" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "runtime" : {
         "requires" : {
            "File::Temp" : "0",
            "XML::NamespaceSupport" : "0.03",
            "XML::SAX::Base" : "1.05"
         }
      }
   },
   "release_status" : "stable",
   "resources" : {
      "repository" : {
         "type" : "git",
         "web" : "https://github.com/grantm/xml-sax"
      }
   },
   "version" : "1.02",
   "x_serialization_backend" : "JSON::PP version 2.97001"
}
PK2N%[�q��?perl5/x86_64-linux-thread-multi/.meta/XML-SAX-1.02/install.jsonnu��6�${"provides":{"XML::SAX::PurePerl::Reader::URI":{"file":"lib/XML/SAX/PurePerl/Reader/URI.pm"},"XML::SAX::ParserFactory":{"file":"lib/XML/SAX/ParserFactory.pm","version":1.02},"XML::SAX::PurePerl::DebugHandler":{"file":"lib/XML/SAX/PurePerl/DebugHandler.pm"},"XML::SAX::PurePerl::Productions":{"file":"lib/XML/SAX/PurePerl/Productions.pm"},"XML::SAX::DocumentLocator":{"file":"lib/XML/SAX/DocumentLocator.pm"},"XML::SAX::PurePerl":{"version":1.02,"file":"lib/XML/SAX/PurePerl.pm"},"XML::SAX::PurePerl::Reader::String":{"file":"lib/XML/SAX/PurePerl/Reader/String.pm"},"XML::SAX::PurePerl::Exception":{"file":"lib/XML/SAX/PurePerl/Exception.pm"},"XML::SAX":{"version":1.02,"file":"lib/XML/SAX.pm"},"XML::SAX::PurePerl::Reader":{"file":"lib/XML/SAX/PurePerl/Reader.pm"},"XML::SAX::PurePerl::Reader::Stream":{"file":"lib/XML/SAX/PurePerl/Reader/Stream.pm"}},"pathname":"G/GR/GRANTM/XML-SAX-1.02.tar.gz","version":1.02,"dist":"XML-SAX-1.02","target":"XML::SAX","name":"XML::SAX"}PK2N%[��c/Aperl5/x86_64-linux-thread-multi/.meta/XML-Parser-2.47/MYMETA.jsonnu��6�${
   "abstract" : "A perl module for parsing XML documents",
   "author" : [
      "Clark Cooper (coopercc@netheaven.com)"
   ],
   "dynamic_config" : 0,
   "generated_by" : "ExtUtils::MakeMaker version 7.64, CPAN::Meta::Converter version 2.150010",
   "license" : [
      "perl_5"
   ],
   "meta-spec" : {
      "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
      "version" : 2
   },
   "name" : "XML-Parser",
   "no_index" : {
      "directory" : [
         "t",
         "inc"
      ]
   },
   "prereqs" : {
      "build" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "configure" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "runtime" : {
         "requires" : {
            "LWP::UserAgent" : "0",
            "perl" : "5.00405"
         }
      },
      "test" : {
         "requires" : {
            "Test::More" : "0",
            "warnings" : "0"
         }
      }
   },
   "release_status" : "stable",
   "resources" : {
      "bugtracker" : {
         "web" : "https://github.com/toddr/XML-Parser/issues"
      },
      "repository" : {
         "url" : "http://github.com/toddr/XML-Parser"
      }
   },
   "version" : "2.47",
   "x_serialization_backend" : "JSON::PP version 2.97001"
}
PK2N%[�L|�44Bperl5/x86_64-linux-thread-multi/.meta/XML-Parser-2.47/install.jsonnu��6�${"provides":{"XML::Parser::Style::Objects":{"file":"Parser/Style/Objects.pm"},"XML::Parser::Expat":{"version":2.47,"file":"Expat/Expat.pm"},"XML::Parser::Style::Subs":{"file":"Parser/Style/Subs.pm"},"XML::Parser::Style::Debug":{"file":"Parser/Style/Debug.pm"},"XML::Parser::Style::Stream":{"file":"Parser/Style/Stream.pm"},"XML::Parser::Style::Tree":{"file":"Parser/Style/Tree.pm"},"XML::Parser":{"version":2.47,"file":"Parser.pm"}},"pathname":"T/TO/TODDR/XML-Parser-2.47.tar.gz","version":2.47,"dist":"XML-Parser-2.47","target":"XML::Parser","name":"XML::Parser"}PK2N%[]��<perl5/x86_64-linux-thread-multi/.meta/Clone-0.47/MYMETA.jsonnu��6�${
   "abstract" : "recursively copy Perl datatypes",
   "author" : [
      "Ray Finch <rdf@cpan.org>"
   ],
   "dynamic_config" : 0,
   "generated_by" : "ExtUtils::MakeMaker version 7.64, CPAN::Meta::Converter version 2.150010",
   "license" : [
      "perl_5"
   ],
   "meta-spec" : {
      "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
      "version" : 2
   },
   "name" : "Clone",
   "no_index" : {
      "directory" : [
         "t",
         "inc"
      ]
   },
   "prereqs" : {
      "build" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "configure" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "test" : {
         "requires" : {
            "B::COW" : "0.004",
            "Test::More" : "0.88"
         }
      }
   },
   "release_status" : "stable",
   "resources" : {
      "bugtracker" : {
         "web" : "https://github.com/garu/Clone/issues"
      },
      "license" : [
         "http://dev.perl.org/licenses/"
      ],
      "repository" : {
         "url" : "http://github.com/garu/Clone"
      }
   },
   "version" : "0.47",
   "x_serialization_backend" : "JSON::PP version 2.97001"
}
PK2N%[�:���=perl5/x86_64-linux-thread-multi/.meta/Clone-0.47/install.jsonnu��6�${"name":"Clone","target":"Clone","dist":"Clone-0.47","version":0.47,"pathname":"A/AT/ATOOMIC/Clone-0.47.tar.gz","provides":{"Clone":{"file":"Clone.pm","version":0.47}}}PK2N%[i�47�y�yCperl5/x86_64-linux-thread-multi/.meta/HTTP-Message-7.00/MYMETA.jsonnu��6�${
   "abstract" : "HTTP style message (base class)",
   "author" : [
      "Gisle Aas <gisle@activestate.com>"
   ],
   "dynamic_config" : 0,
   "generated_by" : "Dist::Zilla version 6.032, CPAN::Meta::Converter version 2.150010",
   "license" : [
      "perl_5"
   ],
   "meta-spec" : {
      "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
      "version" : 2
   },
   "name" : "HTTP-Message",
   "no_index" : {
      "directory" : [
         "examples",
         "t",
         "xt"
      ]
   },
   "prereqs" : {
      "configure" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0",
            "perl" : "5.006"
         },
         "suggests" : {
            "JSON::PP" : "2.27300"
         }
      },
      "develop" : {
         "requires" : {
            "File::Spec" : "0",
            "IO::Handle" : "0",
            "IPC::Open3" : "0",
            "Test::CPAN::Changes" : "0.19",
            "Test::Mojibake" : "0",
            "Test::More" : "0.96",
            "Test::Pod" : "1.41",
            "Test::Portability::Files" : "0",
            "Test::Version" : "1",
            "perl" : "5.006"
         }
      },
      "runtime" : {
         "recommends" : {
            "IO::Compress::Brotli" : "0.004001",
            "IO::Uncompress::Brotli" : "0.004001"
         },
         "requires" : {
            "Carp" : "0",
            "Clone" : "0.46",
            "Compress::Raw::Bzip2" : "0",
            "Compress::Raw::Zlib" : "2.062",
            "Encode" : "3.01",
            "Encode::Locale" : "1",
            "Exporter" : "5.57",
            "File::Spec" : "0",
            "HTTP::Date" : "6",
            "IO::Compress::Bzip2" : "2.021",
            "IO::Compress::Deflate" : "0",
            "IO::Compress::Gzip" : "0",
            "IO::HTML" : "0",
            "IO::Uncompress::Inflate" : "0",
            "IO::Uncompress::RawInflate" : "0",
            "LWP::MediaTypes" : "6",
            "MIME::Base64" : "2.1",
            "MIME::QuotedPrint" : "0",
            "URI" : "1.10",
            "parent" : "0",
            "perl" : "5.008001",
            "strict" : "0",
            "warnings" : "0"
         }
      },
      "test" : {
         "recommends" : {
            "CPAN::Meta" : "2.120900",
            "IO::Compress::Brotli" : "0.004001",
            "IO::Uncompress::Brotli" : "0.004001"
         },
         "requires" : {
            "ExtUtils::MakeMaker" : "0",
            "File::Spec" : "0",
            "File::Temp" : "0",
            "PerlIO::encoding" : "0",
            "Test::More" : "0.88",
            "Test::Needs" : "0",
            "Time::Local" : "0",
            "Try::Tiny" : "0",
            "URI::URL" : "0",
            "lib" : "0",
            "overload" : "0",
            "perl" : "5.008001"
         }
      }
   },
   "release_status" : "stable",
   "resources" : {
      "bugtracker" : {
         "web" : "https://github.com/libwww-perl/HTTP-Message/issues"
      },
      "homepage" : "https://github.com/libwww-perl/HTTP-Message",
      "repository" : {
         "type" : "git",
         "url" : "https://github.com/libwww-perl/HTTP-Message.git",
         "web" : "https://github.com/libwww-perl/HTTP-Message"
      },
      "x_IRC" : "irc://irc.perl.org/#lwp",
      "x_MailingList" : "mailto:libwww@perl.org"
   },
   "version" : "7.00",
   "x_Dist_Zilla" : {
      "perl" : {
         "version" : "5.034000"
      },
      "plugins" : [
         {
            "class" : "Dist::Zilla::Plugin::MetaResources",
            "name" : "MetaResources",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::Prereqs",
            "config" : {
               "Dist::Zilla::Plugin::Prereqs" : {
                  "phase" : "runtime",
                  "type" : "requires"
               }
            },
            "name" : "Prereqs",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::PromptIfStale",
            "config" : {
               "Dist::Zilla::Plugin::PromptIfStale" : {
                  "check_all_plugins" : 0,
                  "check_all_prereqs" : 0,
                  "modules" : [
                     "Dist::Zilla::PluginBundle::Author::OALDERS"
                  ],
                  "phase" : "build",
                  "run_under_travis" : 0,
                  "skip" : []
               }
            },
            "name" : "@Author::OALDERS/stale modules, build",
            "version" : "0.060"
         },
         {
            "class" : "Dist::Zilla::Plugin::PromptIfStale",
            "config" : {
               "Dist::Zilla::Plugin::PromptIfStale" : {
                  "check_all_plugins" : 1,
                  "check_all_prereqs" : 1,
                  "modules" : [],
                  "phase" : "release",
                  "run_under_travis" : 0,
                  "skip" : []
               }
            },
            "name" : "@Author::OALDERS/stale modules, release",
            "version" : "0.060"
         },
         {
            "class" : "Dist::Zilla::Plugin::AutoPrereqs",
            "name" : "@Author::OALDERS/AutoPrereqs",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::CheckChangesHasContent",
            "name" : "@Author::OALDERS/CheckChangesHasContent",
            "version" : "0.011"
         },
         {
            "class" : "Dist::Zilla::Plugin::MakeMaker",
            "config" : {
               "Dist::Zilla::Role::TestRunner" : {
                  "default_jobs" : "8"
               }
            },
            "name" : "@Author::OALDERS/MakeMaker",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::CPANFile",
            "name" : "@Author::OALDERS/CPANFile",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::ContributorsFile",
            "name" : "@Author::OALDERS/ContributorsFile",
            "version" : "0.3.0"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaJSON",
            "name" : "@Author::OALDERS/MetaJSON",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaYAML",
            "name" : "@Author::OALDERS/MetaYAML",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::Manifest",
            "name" : "@Author::OALDERS/Manifest",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaNoIndex",
            "name" : "@Author::OALDERS/MetaNoIndex",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaConfig",
            "name" : "@Author::OALDERS/MetaConfig",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaResources",
            "name" : "@Author::OALDERS/MetaResources",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::License",
            "name" : "@Author::OALDERS/License",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::InstallGuide",
            "config" : {
               "Dist::Zilla::Role::ModuleMetadata" : {
                  "Module::Metadata" : "1.000037",
                  "version" : "0.006"
               }
            },
            "name" : "@Author::OALDERS/InstallGuide",
            "version" : "1.200014"
         },
         {
            "class" : "Dist::Zilla::Plugin::ExecDir",
            "name" : "@Author::OALDERS/ExecDir",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::MojibakeTests",
            "name" : "@Author::OALDERS/MojibakeTests",
            "version" : "0.8"
         },
         {
            "class" : "Dist::Zilla::Plugin::PodSyntaxTests",
            "name" : "@Author::OALDERS/PodSyntaxTests",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::CPAN::Changes",
            "config" : {
               "Dist::Zilla::Plugin::Test::CPAN::Changes" : {
                  "changelog" : "Changes"
               }
            },
            "name" : "@Author::OALDERS/Test::CPAN::Changes",
            "version" : "0.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::Portability",
            "config" : {
               "Dist::Zilla::Plugin::Test::Portability" : {
                  "options" : ""
               }
            },
            "name" : "@Author::OALDERS/Test::Portability",
            "version" : "2.001001"
         },
         {
            "class" : "Dist::Zilla::Plugin::TestRelease",
            "name" : "@Author::OALDERS/TestRelease",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::ReportPrereqs",
            "name" : "@Author::OALDERS/Test::ReportPrereqs",
            "version" : "0.029"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::Version",
            "name" : "@Author::OALDERS/Test::Version",
            "version" : "1.09"
         },
         {
            "class" : "Dist::Zilla::Plugin::RunExtraTests",
            "config" : {
               "Dist::Zilla::Role::TestRunner" : {
                  "default_jobs" : "8"
               }
            },
            "name" : "@Author::OALDERS/RunExtraTests",
            "version" : "0.029"
         },
         {
            "class" : "Dist::Zilla::Plugin::MinimumPerl",
            "name" : "@Author::OALDERS/MinimumPerl",
            "version" : "1.006"
         },
         {
            "class" : "Dist::Zilla::Plugin::PodWeaver",
            "config" : {
               "Dist::Zilla::Plugin::PodWeaver" : {
                  "finder" : [
                     ":InstallModules",
                     ":PerlExecFiles"
                  ],
                  "plugins" : [
                     {
                        "class" : "Pod::Weaver::Plugin::EnsurePod5",
                        "name" : "@CorePrep/EnsurePod5",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Plugin::H1Nester",
                        "name" : "@CorePrep/H1Nester",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Plugin::SingleEncoding",
                        "name" : "@Default/SingleEncoding",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Name",
                        "name" : "@Default/Name",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Version",
                        "name" : "@Default/Version",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Region",
                        "name" : "@Default/prelude",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Generic",
                        "name" : "SYNOPSIS",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Generic",
                        "name" : "DESCRIPTION",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Generic",
                        "name" : "OVERVIEW",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Collect",
                        "name" : "ATTRIBUTES",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Collect",
                        "name" : "METHODS",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Collect",
                        "name" : "FUNCTIONS",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Leftovers",
                        "name" : "@Default/Leftovers",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Region",
                        "name" : "@Default/postlude",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Authors",
                        "name" : "@Default/Authors",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Legal",
                        "name" : "@Default/Legal",
                        "version" : "4.019"
                     }
                  ]
               }
            },
            "name" : "@Author::OALDERS/PodWeaver",
            "version" : "4.010"
         },
         {
            "class" : "Dist::Zilla::Plugin::PruneCruft",
            "name" : "@Author::OALDERS/PruneCruft",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::CopyFilesFromBuild",
            "name" : "@Author::OALDERS/CopyFilesFromBuild",
            "version" : "0.170880"
         },
         {
            "class" : "Dist::Zilla::Plugin::GithubMeta",
            "name" : "@Author::OALDERS/GithubMeta",
            "version" : "0.58"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::GatherDir",
            "config" : {
               "Dist::Zilla::Plugin::GatherDir" : {
                  "exclude_filename" : [
                     "Install",
                     "LICENSE",
                     "META.json",
                     "Makefile.PL",
                     "README.md",
                     "cpanfile"
                  ],
                  "exclude_match" : [],
                  "include_dotfiles" : 0,
                  "prefix" : "",
                  "prune_directory" : [],
                  "root" : "."
               },
               "Dist::Zilla::Plugin::Git::GatherDir" : {
                  "include_untracked" : 0
               }
            },
            "name" : "@Author::OALDERS/Git::GatherDir",
            "version" : "2.051"
         },
         {
            "class" : "Dist::Zilla::Plugin::CopyFilesFromRelease",
            "config" : {
               "Dist::Zilla::Plugin::CopyFilesFromRelease" : {
                  "filename" : [
                     "Install"
                  ],
                  "match" : []
               }
            },
            "name" : "@Author::OALDERS/CopyFilesFromRelease",
            "version" : "0.007"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::Check",
            "config" : {
               "Dist::Zilla::Plugin::Git::Check" : {
                  "untracked_files" : "die"
               },
               "Dist::Zilla::Role::Git::DirtyFiles" : {
                  "allow_dirty" : [
                     "Changes",
                     "Install",
                     "LICENSE",
                     "META.json",
                     "Makefile.PL",
                     "README.md",
                     "cpanfile",
                     "dist.ini"
                  ],
                  "allow_dirty_match" : [],
                  "changelog" : "Changes"
               },
               "Dist::Zilla::Role::Git::Repo" : {
                  "git_version" : "2.34.1",
                  "repo_root" : "."
               }
            },
            "name" : "@Author::OALDERS/Git::Check",
            "version" : "2.051"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::Contributors",
            "config" : {
               "Dist::Zilla::Plugin::Git::Contributors" : {
                  "git_version" : "2.34.1",
                  "include_authors" : 0,
                  "include_releaser" : 1,
                  "order_by" : "name",
                  "paths" : []
               }
            },
            "name" : "@Author::OALDERS/Git::Contributors",
            "version" : "0.037"
         },
         {
            "class" : "Dist::Zilla::Plugin::ReadmeAnyFromPod",
            "config" : {
               "Dist::Zilla::Role::FileWatcher" : {
                  "version" : "0.006"
               }
            },
            "name" : "@Author::OALDERS/ReadmeMdInBuild",
            "version" : "0.163250"
         },
         {
            "class" : "Dist::Zilla::Plugin::StaticInstall",
            "config" : {
               "Dist::Zilla::Plugin::StaticInstall" : {
                  "dry_run" : 0,
                  "mode" : "on"
               }
            },
            "name" : "@Author::OALDERS/StaticInstall",
            "version" : "0.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::ShareDir",
            "name" : "@Author::OALDERS/ShareDir",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::CheckIssues",
            "name" : "@Author::OALDERS/CheckIssues",
            "version" : "0.011"
         },
         {
            "class" : "Dist::Zilla::Plugin::ConfirmRelease",
            "name" : "@Author::OALDERS/ConfirmRelease",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::UploadToCPAN",
            "name" : "@Author::OALDERS/UploadToCPAN",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::RewriteVersion::Transitional",
            "config" : {
               "Dist::Zilla::Plugin::RewriteVersion" : {
                  "add_tarball_name" : 0,
                  "finders" : [
                     ":ExecFiles",
                     ":InstallModules"
                  ],
                  "global" : 0,
                  "skip_version_provider" : 0
               },
               "Dist::Zilla::Plugin::RewriteVersion::Transitional" : {}
            },
            "name" : "@Author::OALDERS/@Git::VersionManager/RewriteVersion::Transitional",
            "version" : "0.009"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaProvides::Update",
            "name" : "@Author::OALDERS/@Git::VersionManager/MetaProvides::Update",
            "version" : "0.007"
         },
         {
            "class" : "Dist::Zilla::Plugin::CopyFilesFromRelease",
            "config" : {
               "Dist::Zilla::Plugin::CopyFilesFromRelease" : {
                  "filename" : [
                     "Changes"
                  ],
                  "match" : []
               }
            },
            "name" : "@Author::OALDERS/@Git::VersionManager/CopyFilesFromRelease",
            "version" : "0.007"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::Commit",
            "config" : {
               "Dist::Zilla::Plugin::Git::Commit" : {
                  "add_files_in" : [],
                  "commit_msg" : "v%V%n%n%c",
                  "signoff" : 0
               },
               "Dist::Zilla::Role::Git::DirtyFiles" : {
                  "allow_dirty" : [
                     "Changes",
                     "Install",
                     "LICENSE",
                     "META.json",
                     "Makefile.PL",
                     "README.md",
                     "cpanfile",
                     "dist.ini"
                  ],
                  "allow_dirty_match" : [],
                  "changelog" : "Changes"
               },
               "Dist::Zilla::Role::Git::Repo" : {
                  "git_version" : "2.34.1",
                  "repo_root" : "."
               },
               "Dist::Zilla::Role::Git::StringFormatter" : {
                  "time_zone" : "local"
               }
            },
            "name" : "@Author::OALDERS/@Git::VersionManager/release snapshot",
            "version" : "2.051"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::Tag",
            "config" : {
               "Dist::Zilla::Plugin::Git::Tag" : {
                  "branch" : null,
                  "changelog" : "Changes",
                  "signed" : 0,
                  "tag" : "v7.00",
                  "tag_format" : "v%V",
                  "tag_message" : "v%V"
               },
               "Dist::Zilla::Role::Git::Repo" : {
                  "git_version" : "2.34.1",
                  "repo_root" : "."
               },
               "Dist::Zilla::Role::Git::StringFormatter" : {
                  "time_zone" : "local"
               }
            },
            "name" : "@Author::OALDERS/@Git::VersionManager/Git::Tag",
            "version" : "2.051"
         },
         {
            "class" : "Dist::Zilla::Plugin::BumpVersionAfterRelease::Transitional",
            "config" : {
               "Dist::Zilla::Plugin::BumpVersionAfterRelease" : {
                  "finders" : [
                     ":ExecFiles",
                     ":InstallModules"
                  ],
                  "global" : 0,
                  "munge_makefile_pl" : 1
               },
               "Dist::Zilla::Plugin::BumpVersionAfterRelease::Transitional" : {}
            },
            "name" : "@Author::OALDERS/@Git::VersionManager/BumpVersionAfterRelease::Transitional",
            "version" : "0.009"
         },
         {
            "class" : "Dist::Zilla::Plugin::NextRelease",
            "name" : "@Author::OALDERS/@Git::VersionManager/NextRelease",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::Commit",
            "config" : {
               "Dist::Zilla::Plugin::Git::Commit" : {
                  "add_files_in" : [],
                  "commit_msg" : "increment $VERSION after %v release",
                  "signoff" : 0
               },
               "Dist::Zilla::Role::Git::DirtyFiles" : {
                  "allow_dirty" : [
                     "Build.PL",
                     "Changes",
                     "Makefile.PL"
                  ],
                  "allow_dirty_match" : [
                     "(?^:^lib/.*\\.pm$)"
                  ],
                  "changelog" : "Changes"
               },
               "Dist::Zilla::Role::Git::Repo" : {
                  "git_version" : "2.34.1",
                  "repo_root" : "."
               },
               "Dist::Zilla::Role::Git::StringFormatter" : {
                  "time_zone" : "local"
               }
            },
            "name" : "@Author::OALDERS/@Git::VersionManager/post-release commit",
            "version" : "2.051"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::Push",
            "config" : {
               "Dist::Zilla::Plugin::Git::Push" : {
                  "push_to" : [
                     "origin"
                  ],
                  "remotes_must_exist" : 1
               },
               "Dist::Zilla::Role::Git::Repo" : {
                  "git_version" : "2.34.1",
                  "repo_root" : "."
               }
            },
            "name" : "@Author::OALDERS/Git::Push",
            "version" : "2.051"
         },
         {
            "class" : "Dist::Zilla::Plugin::Prereqs::Soften",
            "config" : {
               "Dist::Zilla::Plugin::Prereqs::Soften" : {
                  "copy_to" : [
                     "test.recommends"
                  ],
                  "modules" : [
                     "IO::Compress::Brotli",
                     "IO::Uncompress::Brotli"
                  ],
                  "modules_from_features" : null,
                  "to_relationship" : "recommends"
               }
            },
            "name" : "Brotli",
            "version" : "0.006003"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::Compile",
            "config" : {
               "Dist::Zilla::Plugin::Test::Compile" : {
                  "bail_out_on_fail" : "1",
                  "fail_on_warning" : "author",
                  "fake_home" : 0,
                  "filename" : "xt/author/00-compile.t",
                  "module_finder" : [
                     ":InstallModules"
                  ],
                  "needs_display" : 0,
                  "phase" : "develop",
                  "script_finder" : [
                     ":PerlExecFiles"
                  ],
                  "skips" : [],
                  "switch" : []
               }
            },
            "name" : "Test::Compile",
            "version" : "2.058"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":InstallModules",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":IncModules",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":TestFiles",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":ExtraTestFiles",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":ExecFiles",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":PerlExecFiles",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":ShareFiles",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":MainModule",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":AllFiles",
            "version" : "6.032"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":NoFiles",
            "version" : "6.032"
         }
      ],
      "zilla" : {
         "class" : "Dist::Zilla::Dist::Builder",
         "config" : {
            "is_trial" : 0
         },
         "version" : "6.032"
      }
   },
   "x_contributors" : [
      "Adam Kennedy <adamk@cpan.org>",
      "Adam Sjogren <asjo@koldfront.dk>",
      "Alexey Tourbin <at@altlinux.ru>",
      "Alex Kapranoff <ka@nadoby.ru>",
      "amire80 <amir.aharoni@gmail.com>",
      "Andreas J. Koenig <andreas.koenig@anima.de>",
      "Andrei Grechkin <andrei.grechkin@booking.com>",
      "bayashi <bayashi@cpan.org>",
      "Bill Mann <wfmann@alum.mit.edu>",
      "Brendan Byrd <GitHub@ResonatorSoft.org>",
      "Bron Gondwana <brong@fastmail.fm>",
      "Chase Whitener <capoeirab@cpan.org>",
      "Christopher J. Madsen <cjm@cpan.org>",
      "chromatic <chromatic@wgz.org>",
      "Dan Book <grinnz@grinnz.com>",
      "Daniel Hedlund <Daniel.Hedlund@eprize.com>",
      "Daniel Trizen <trizen@protonmail.com>",
      "David E. Wheeler <david@justatheory.com>",
      "DAVIDRW <davidrw@cpan.org>",
      "David Steinbrunner <dsteinbrunner@MountainBook-Pro.local>",
      "dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
      "Dorian Taylor <dorian.taylor.lists@gmail.com>",
      "Eric Wastl <topaz.github@lt3.us>",
      "Father Chrysostomos <sprout@cpan.org>",
      "Felipe Gasper <felipe@felipegasper.com>",
      "FWILES <FWILES@cpan.org>",
      "Galen Huntington <galenhuntington@gmail.com>",
      "Gavin Peters <gpeters@deepsky.com>",
      "Gisle Aas <gisle@aas.no>",
      "Graeme Thompson <Graeme.Thompson@mobilecohesion.com>",
      "Graham Knop <haarg@haarg.org>",
      "Håkon Hægland <hakon.hagland@gmail.com>",
      "Hans-H. Froehlich <hfroehlich@co-de-co.de>",
      "Ian Kilgore <iank@cpan.org>",
      "Jacob J <waif@chaos2.org>",
      "Jakub Skory <jakub.skory@atos.net>",
      "Jakub Wilk <jwilk@jwilk.net>",
      "James Raspass <jraspass@gmail.com>",
      "jefflee <shaohua@gmail.com>",
      "Jerome Eteve <jerome@broadbean.com>",
      "john9art <john9art@yahoo.com>",
      "jonasbn <jonasbn@gmail.com>",
      "Julien Fiegehenn <simbabque@cpan.org>",
      "Karen Etheridge <ether@cpan.org>",
      "Lars Dɪᴇᴄᴋᴏᴡ 迪拉斯 <daxim@cpan.org>",
      "Mark Overmeer <mark@overmeer.net>",
      "Mark Stosberg <mark@stosberg.com>",
      "Martin H. Sluka <fany@cpan.org>",
      "Matthew Chae <mschae@cpan.org>",
      "Max Maischein <corion@corion.net>",
      "Michael Schout <mschout@gkg.net>",
      "Michal Josef Špaček <mspacek@redhat.com>",
      "Mickey Nasriachi <mickey@cpan.org>",
      "Mike Schilli <github@perlmeister.com>",
      "murphy <murphy@genome.chop.edu>",
      "nanto_vi, TOYAMA Nao <nanto@moon.email.ne.jp>",
      "Neil Bowers <neilb@neilb.org>",
      "Olaf Alders <olaf@wundersolutions.com>",
      "Olivier Mengué <dolmen@cpan.org>",
      "Ondrej Hanak <ondrej.hanak@ubs.com>",
      "openstrike <git@openstrike.co.uk>",
      "Peter Rabbitson <ribasushi@cpan.org>",
      "phrstbrn <phrstbrn@gmail.com>",
      "Robert Rothenberg <robrwo+github@gmail.com>",
      "Robert Rothenberg <rrwo@cpan.org>",
      "Robert Stone <talby@trap.mtview.ca.us>",
      "Rolf Grossmann <rg@progtech.net>",
      "ruff <ruff@ukrpost.net>",
      "sasao <sasao@yugen.org>",
      "Saturday Walkers Club <swc@walkingclub.org.uk>",
      "Sean M. Burke <sburke@cpan.org>",
      "Slaven Rezic <slaven@rezic.de>",
      "Spiros Denaxas <s.denaxas@gmail.com>",
      "Steve Hay <SteveHay@planit.com>",
      "Tatsuhiko Miyagawa <miyagawa@bulknews.net>",
      "Tatsuhiko Miyagawa <miyagawa@gmail.com>",
      "Theo van Hoesel <Th.J.v.Hoesel@THEMA-MEDIA.nl>",
      "Tigran <tigrankhachikyan@gmail.com>",
      "Tobias Leich <email@froggs.de>",
      "Todd Lipcon <todd@amiestreet.com>",
      "tokuhirom <tokuhirom@gmail.com>",
      "Tom Hukins <tom@eborcom.com>",
      "Tony Finch <dot@dotat.at>",
      "Toru Yamaguchi <zigorou@cpan.org>",
      "tzccinct <tzccinct@gmail.com>",
      "uid39246 <uid39246>",
      "Ville Skyttä <ville.skytta@iki.fi>",
      "Vít Strádal <vit.stradal@gooddata.com>",
      "Wesley Schwengle <waterkip@cpan.org>",
      "William Storey <wstorey@maxmind.com>",
      "Yuri Karaban <tech@askold.net>",
      "Zakariyya Mughal <zaki.mughal@gmail.com>",
      "Zefram <zefram@fysh.org>"
   ],
   "x_generated_by_perl" : "v5.34.0",
   "x_serialization_backend" : "JSON::PP version 2.97001",
   "x_spdx_expression" : "Artistic-1.0-Perl OR GPL-1.0-or-later",
   "x_static_install" : 1
}
PK2N%[�}�KKDperl5/x86_64-linux-thread-multi/.meta/HTTP-Message-7.00/install.jsonnu��6�${"name":"HTTP::Message","target":"HTTP::Headers","dist":"HTTP-Message-7.00","version":"7.00","provides":{"HTTP::Request":{"file":"lib/HTTP/Request.pm","version":"7.00"},"HTTP::Response":{"version":"7.00","file":"lib/HTTP/Response.pm"},"HTTP::Request::Common":{"file":"lib/HTTP/Request/Common.pm","version":"7.00"},"HTTP::Headers::Util":{"version":"7.00","file":"lib/HTTP/Headers/Util.pm"},"HTTP::Message":{"version":"7.00","file":"lib/HTTP/Message.pm"},"HTTP::Headers::ETag":{"file":"lib/HTTP/Headers/ETag.pm","version":"7.00"},"HTTP::Headers":{"version":"7.00","file":"lib/HTTP/Headers.pm"},"HTTP::Headers::Auth":{"version":"7.00","file":"lib/HTTP/Headers/Auth.pm"},"HTTP::Status":{"version":"7.00","file":"lib/HTTP/Status.pm"},"HTTP::Config":{"file":"lib/HTTP/Config.pm","version":"7.00"}},"pathname":"O/OA/OALDERS/HTTP-Message-7.00.tar.gz"}PK2N%[�d��Dperl5/x86_64-linux-thread-multi/.meta/XML-SAX-Expat-0.51/MYMETA.jsonnu��6�${
   "abstract" : "SAX Driver for Expat",
   "author" : [
      "Robin Berjon"
   ],
   "dynamic_config" : 0,
   "generated_by" : "ExtUtils::MakeMaker version 6.6302, CPAN::Meta::Converter version 2.132830, CPAN::Meta::Converter version 2.150010",
   "license" : [
      "perl_5"
   ],
   "meta-spec" : {
      "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
      "version" : 2
   },
   "name" : "XML-SAX-Expat",
   "no_index" : {
      "directory" : [
         "t",
         "inc"
      ]
   },
   "prereqs" : {
      "build" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "configure" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "runtime" : {
         "requires" : {
            "XML::NamespaceSupport" : "0.03",
            "XML::Parser" : "2.27",
            "XML::SAX" : "0.03",
            "XML::SAX::Base" : "1.00"
         }
      }
   },
   "release_status" : "stable",
   "resources" : {
      "repository" : {
         "url" : "https://github.com/hoehrmann/XML-SAX-Expat"
      }
   },
   "version" : "0.51",
   "x_serialization_backend" : "JSON::PP version 2.97001"
}
PK2N%[����Eperl5/x86_64-linux-thread-multi/.meta/XML-SAX-Expat-0.51/install.jsonnu��6�${"target":"XML::SAX::Expat","name":"XML::SAX::Expat","pathname":"B/BJ/BJOERN/XML-SAX-Expat-0.51.tar.gz","provides":{"XML::SAX::Expat":{"version":0.51,"file":"Expat.pm"}},"version":0.51,"dist":"XML-SAX-Expat-0.51"}PK2N%[��T@��Hperl5/x86_64-linux-thread-multi/.meta/Template-Toolkit-3.102/MYMETA.jsonnu��6�${
   "abstract" : "comprehensive template processing system",
   "author" : [
      "Andy Wardley <abw@wardley.org>"
   ],
   "dynamic_config" : 0,
   "generated_by" : "ExtUtils::MakeMaker version 7.64, CPAN::Meta::Converter version 2.150010",
   "license" : [
      "perl_5"
   ],
   "meta-spec" : {
      "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
      "version" : 2
   },
   "name" : "Template-Toolkit",
   "no_index" : {
      "directory" : [
         "t",
         "inc"
      ]
   },
   "prereqs" : {
      "build" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "configure" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "runtime" : {
         "requires" : {
            "AppConfig" : "1.56",
            "File::Spec" : "0.8",
            "File::Temp" : "0.12",
            "Scalar::Util" : "0"
         }
      },
      "test" : {
         "requires" : {
            "Test::LeakTrace" : "0"
         }
      }
   },
   "release_status" : "stable",
   "resources" : {
      "bugtracker" : {
         "web" : "https://github.com/abw/Template2/issues"
      },
      "homepage" : "http://www.template-toolkit.org",
      "repository" : {
         "type" : "git",
         "url" : "https://github.com/abw/Template2.git",
         "web" : "https://github.com/abw/Template2"
      }
   },
   "version" : "3.102",
   "x_serialization_backend" : "JSON::PP version 2.97001"
}
PK2N%[�
�UUIperl5/x86_64-linux-thread-multi/.meta/Template-Toolkit-3.102/install.jsonnu��6�${"provides":{"Template::Config":{"file":"lib/Template/Config.pm","version":"3.100"},"Template::App::ttree":{"version":2.91,"file":"lib/Template/App/ttree.pm"},"Template::Iterator":{"version":"3.100","file":"lib/Template/Iterator.pm"},"Template::Plugin::Format":{"file":"lib/Template/Plugin/Format.pm","version":"3.100"},"Template::Plugin::URL":{"file":"lib/Template/Plugin/URL.pm","version":"3.100"},"Template::Perl":{"version":"3.100","file":"lib/Template/Filters.pm"},"Template::Monad::Assert":{"version":"3.100","file":"lib/Template/Plugin/Assert.pm"},"Template::Plugin::Pod":{"version":"3.100","file":"lib/Template/Plugin/Pod.pm"},"Template::Document":{"version":"3.100","file":"lib/Template/Document.pm"},"Template::Plugin::Directory":{"version":"3.100","file":"lib/Template/Plugin/Directory.pm"},"Template::Plugin::HTML":{"version":"3.100","file":"lib/Template/Plugin/HTML.pm"},"Template::Context":{"version":"3.100","file":"lib/Template/Context.pm"},"Template::Plugin::String":{"file":"lib/Template/Plugin/String.pm","version":"3.100"},"Template::Monad::Scalar":{"file":"lib/Template/Plugin/Scalar.pm","version":"3.100"},"Template::Exception":{"file":"lib/Template/Exception.pm","version":"3.100"},"Template::Stash":{"file":"lib/Template/Stash.pm","version":"3.100"},"Template::Base":{"version":"3.100","file":"lib/Template/Base.pm"},"Template::Plugin::Image":{"version":"3.100","file":"lib/Template/Plugin/Image.pm"},"Template::View":{"version":"3.100","file":"lib/Template/View.pm"},"Template::Plugin":{"version":"3.100","file":"lib/Template/Plugin.pm"},"Template::Plugin::Dumper":{"file":"lib/Template/Plugin/Dumper.pm","version":"3.100"},"Template::Provider":{"version":"3.100","file":"lib/Template/Provider.pm"},"Template::Plugin::Date::Calc":{"version":"3.100","file":"lib/Template/Plugin/Date.pm"},"Template::Plugin::Date":{"version":"3.100","file":"lib/Template/Plugin/Date.pm"},"Template::Filters":{"file":"lib/Template/Filters.pm","version":"3.100"},"Template::Plugin::Filter":{"file":"lib/Template/Plugin/Filter.pm","version":"3.100"},"Template::Test":{"file":"lib/Template/Test.pm","version":"3.100"},"Template::Plugin::Iterator":{"version":"3.100","file":"lib/Template/Plugin/Iterator.pm"},"Template::Plugin::View":{"file":"lib/Template/Plugin/View.pm","version":"3.100"},"Template::VMethods":{"file":"lib/Template/VMethods.pm","version":"3.100"},"Template::Stash::Context":{"version":"3.100","file":"lib/Template/Stash/Context.pm"},"Template::Plugin::Table":{"file":"lib/Template/Plugin/Table.pm","version":"3.100"},"Template::Plugin::Math":{"file":"lib/Template/Plugin/Math.pm","version":"3.100"},"Template::Namespace::Constants":{"file":"lib/Template/Namespace/Constants.pm","version":"3.100"},"Template::Toolkit":{"file":"lib/Template/Toolkit.pm","version":"3.100"},"Template::TieString":{"file":"lib/Template/Config.pm","version":"3.100"},"Template::Service":{"file":"lib/Template/Service.pm","version":"3.100"},"Template::Constants":{"version":"3.100","file":"lib/Template/Constants.pm"},"Template::Parser":{"version":"3.100","file":"lib/Template/Parser.pm"},"Template::Plugin::Scalar":{"file":"lib/Template/Plugin/Scalar.pm","version":"3.100"},"Template::Plugin::Assert":{"version":"3.100","file":"lib/Template/Plugin/Assert.pm"},"Template::Directive":{"version":"3.100","file":"lib/Template/Directive.pm"},"Template::Grammar":{"file":"lib/Template/Grammar.pm","version":"3.100"},"Template::Plugin::Wrap":{"file":"lib/Template/Plugin/Wrap.pm","version":"3.100"},"Template::Plugin::Procedural":{"file":"lib/Template/Plugin/Procedural.pm","version":"3.100"},"Template::Stash::XS":{"file":"lib/Template/Stash/XS.pm"},"Template":{"version":3.102,"file":"lib/Template.pm"},"Template::Plugin::Datafile":{"file":"lib/Template/Plugin/Datafile.pm","version":"3.100"},"Template::Plugins":{"version":"3.100","file":"lib/Template/Plugins.pm"},"Template::Plugin::File":{"version":"3.100","file":"lib/Template/Plugin/File.pm"},"Template::Plugin::Date::Manip":{"version":"3.100","file":"lib/Template/Plugin/Date.pm"}},"version":3.102,"pathname":"T/TO/TODDR/Template-Toolkit-3.102.tar.gz","dist":"Template-Toolkit-3.102","name":"Template","target":"Template::Constants"}PK2N%[�"͟�Cperl5/x86_64-linux-thread-multi/.meta/FFI-CheckLib-0.31/MYMETA.jsonnu��6�${
   "abstract" : "Check that a library is available for FFI",
   "author" : [
      "Graham Ollis <plicease@cpan.org>"
   ],
   "dynamic_config" : 0,
   "generated_by" : "Dist::Zilla version 6.025, CPAN::Meta::Converter version 2.150010",
   "license" : [
      "perl_5"
   ],
   "meta-spec" : {
      "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
      "version" : 2
   },
   "name" : "FFI-CheckLib",
   "no_index" : {
      "directory" : [
         "corpus"
      ]
   },
   "prereqs" : {
      "build" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "configure" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "develop" : {
         "recommends" : {
            "Dist::Zilla::Plugin::Author::Plicease::Thanks" : "0",
            "Dist::Zilla::Plugin::Author::Plicease::Upload" : "0",
            "Dist::Zilla::Plugin::MetaNoIndex" : "0",
            "Dist::Zilla::Plugin::RemovePrereqs" : "0",
            "Dist::Zilla::PluginBundle::Author::Plicease" : "2.72",
            "Perl::Critic::Policy::BuiltinFunctions::ProhibitBooleanGrep" : "0",
            "Perl::Critic::Policy::BuiltinFunctions::ProhibitStringySplit" : "0",
            "Perl::Critic::Policy::BuiltinFunctions::ProhibitVoidGrep" : "0",
            "Perl::Critic::Policy::BuiltinFunctions::ProhibitVoidMap" : "0",
            "Perl::Critic::Policy::ClassHierarchies::ProhibitExplicitISA" : "0",
            "Perl::Critic::Policy::ClassHierarchies::ProhibitOneArgBless" : "0",
            "Perl::Critic::Policy::CodeLayout::ProhibitHardTabs" : "0",
            "Perl::Critic::Policy::CodeLayout::ProhibitTrailingWhitespace" : "0",
            "Perl::Critic::Policy::CodeLayout::RequireConsistentNewlines" : "0",
            "Perl::Critic::Policy::ControlStructures::ProhibitLabelsWithSpecialBlockNames" : "0",
            "Perl::Critic::Policy::ControlStructures::ProhibitMutatingListFunctions" : "0",
            "Perl::Critic::Policy::ControlStructures::ProhibitUnreachableCode" : "0",
            "Perl::Critic::Policy::Freenode::ArrayAssignAref" : "0",
            "Perl::Critic::Policy::Freenode::BarewordFilehandles" : "0",
            "Perl::Critic::Policy::Freenode::ConditionalDeclarations" : "0",
            "Perl::Critic::Policy::Freenode::ConditionalImplicitReturn" : "0",
            "Perl::Critic::Policy::Freenode::DeprecatedFeatures" : "0",
            "Perl::Critic::Policy::Freenode::DiscouragedModules" : "0",
            "Perl::Critic::Policy::Freenode::DollarAB" : "0",
            "Perl::Critic::Policy::Freenode::Each" : "0",
            "Perl::Critic::Policy::Freenode::IndirectObjectNotation" : "0",
            "Perl::Critic::Policy::Freenode::LexicalForeachIterator" : "0",
            "Perl::Critic::Policy::Freenode::LoopOnHash" : "0",
            "Perl::Critic::Policy::Freenode::ModPerl" : "0",
            "Perl::Critic::Policy::Freenode::OpenArgs" : "0",
            "Perl::Critic::Policy::Freenode::OverloadOptions" : "0",
            "Perl::Critic::Policy::Freenode::POSIXImports" : "0",
            "Perl::Critic::Policy::Freenode::PackageMatchesFilename" : "0",
            "Perl::Critic::Policy::Freenode::PreferredAlternatives" : "0",
            "Perl::Critic::Policy::Freenode::StrictWarnings" : "0",
            "Perl::Critic::Policy::Freenode::Threads" : "0",
            "Perl::Critic::Policy::Freenode::WarningsSwitch" : "0",
            "Perl::Critic::Policy::Freenode::WhileDiamondDefaultAssignment" : "0",
            "Perl::Critic::Policy::InputOutput::ProhibitBarewordFileHandles" : "0",
            "Perl::Critic::Policy::InputOutput::ProhibitJoinedReadline" : "0",
            "Perl::Critic::Policy::InputOutput::ProhibitTwoArgOpen" : "0",
            "Perl::Critic::Policy::Miscellanea::ProhibitFormats" : "0",
            "Perl::Critic::Policy::Miscellanea::ProhibitUselessNoCritic" : "0",
            "Perl::Critic::Policy::Modules::ProhibitConditionalUseStatements" : "0",
            "Perl::Critic::Policy::Modules::RequireNoMatchVarsWithUseEnglish" : "0",
            "Perl::Critic::Policy::Objects::ProhibitIndirectSyntax" : "0",
            "Perl::Critic::Policy::RegularExpressions::ProhibitUselessTopic" : "0",
            "Perl::Critic::Policy::Subroutines::ProhibitNestedSubs" : "0",
            "Perl::Critic::Policy::ValuesAndExpressions::ProhibitLeadingZeros" : "0",
            "Perl::Critic::Policy::ValuesAndExpressions::ProhibitMixedBooleanOperators" : "0",
            "Perl::Critic::Policy::ValuesAndExpressions::ProhibitSpecialLiteralHeredocTerminator" : "0",
            "Perl::Critic::Policy::ValuesAndExpressions::RequireUpperCaseHeredocTerminator" : "0",
            "Perl::Critic::Policy::Variables::ProhibitPerl4PackageNames" : "0",
            "Perl::Critic::Policy::Variables::ProhibitUnusedVariables" : "0",
            "Software::License::Perl_5" : "0"
         },
         "requires" : {
            "FindBin" : "0",
            "Perl::Critic" : "0",
            "Test2::Require::EnvVar" : "0.000121",
            "Test2::Require::Module" : "0.000121",
            "Test2::Tools::PerlCritic" : "0",
            "Test2::V0" : "0.000121",
            "Test::CPAN::Changes" : "0",
            "Test::EOL" : "0",
            "Test::Fixme" : "0.07",
            "Test::More" : "0.98",
            "Test::NoTabs" : "0",
            "Test::Pod" : "0",
            "Test::Pod::Coverage" : "0",
            "Test::Pod::LinkCheck::Lite" : "0",
            "Test::Pod::Spelling::CommonMistakes" : "0",
            "Test::Spelling" : "0",
            "Test::Strict" : "0",
            "YAML" : "0"
         }
      },
      "runtime" : {
         "requires" : {
            "File::Which" : "0",
            "List::Util" : "1.33",
            "perl" : "5.006"
         }
      },
      "test" : {
         "requires" : {
            "Test2::API" : "1.302015",
            "Test2::Require::EnvVar" : "0.000121",
            "Test2::Require::Module" : "0.000121",
            "Test2::V0" : "0.000121"
         }
      }
   },
   "release_status" : "stable",
   "resources" : {
      "bugtracker" : {
         "web" : "https://github.com/PerlFFI/FFI-CheckLib/issues"
      },
      "homepage" : "https://metacpan.org/pod/FFI::CheckLib",
      "repository" : {
         "type" : "git",
         "url" : "git://github.com/PerlFFI/FFI-CheckLib.git",
         "web" : "https://github.com/PerlFFI/FFI-CheckLib"
      },
      "x_IRC" : "irc://irc.perl.org/#native"
   },
   "version" : "0.31",
   "x_contributors" : [
      "Graham Ollis <plicease@cpan.org>",
      "Bakkiaraj Murugesan (bakkiaraj)",
      "Dan Book (grinnz, DBOOK)",
      "Ilya Pavlov (Ilya, ILUX)",
      "Shawn Laffan (SLAFFAN)",
      "Petr Písař (ppisar)",
      "Michael R. Davis (MRDVT)",
      "Shawn Laffan (SLAFFAN)",
      "Carlos D. Álvaro (cdalvaro)"
   ],
   "x_generated_by_perl" : "v5.36.0",
   "x_serialization_backend" : "JSON::PP version 2.97001",
   "x_spdx_expression" : "Artistic-1.0-Perl OR GPL-1.0-or-later",
   "x_use_unsafe_inc" : 0
}
PK2N%[pM6���Dperl5/x86_64-linux-thread-multi/.meta/FFI-CheckLib-0.31/install.jsonnu��6�${"version":0.31,"pathname":"P/PL/PLICEASE/FFI-CheckLib-0.31.tar.gz","target":"FFI::CheckLib","name":"FFI::CheckLib","dist":"FFI-CheckLib-0.31","provides":{"FFI::CheckLib":{"file":"lib/FFI/CheckLib.pm","version":0.31}}}PK2N%[�9�{?perl5/x86_64-linux-thread-multi/.meta/TimeDate-2.33/MYMETA.jsonnu��6�${
   "abstract" : "unknown",
   "author" : [
      "Graham Barr <gbarr@pobox.com>"
   ],
   "dynamic_config" : 0,
   "generated_by" : "ExtUtils::MakeMaker version 7.44, CPAN::Meta::Converter version 2.150010",
   "license" : [
      "perl_5"
   ],
   "meta-spec" : {
      "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
      "version" : 2
   },
   "name" : "TimeDate",
   "no_index" : {
      "directory" : [
         "t",
         "inc"
      ]
   },
   "prereqs" : {
      "build" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "configure" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      }
   },
   "release_status" : "stable",
   "resources" : {
      "bugtracker" : {
         "web" : "https://github.com/atoomic/perl-TimeDate/issues"
      },
      "repository" : {
         "url" : "https://github.com/atoomic/perl-TimeDate"
      }
   },
   "version" : "2.33",
   "x_serialization_backend" : "JSON::PP version 2.97001"
}
PK2N%[J�i@

@perl5/x86_64-linux-thread-multi/.meta/TimeDate-2.33/install.jsonnu��6�${"name":"Date::Parse","target":"Time::Zone","dist":"TimeDate-2.33","version":2.33,"pathname":"A/AT/ATOOMIC/TimeDate-2.33.tar.gz","provides":{"Date::Format":{"version":2.24,"file":"lib/Date/Format.pm"},"Date::Language":{"version":"1.10","file":"lib/Date/Language.pm"},"Date::Language::Gedeo":{"file":"lib/Date/Language/Gedeo.pm","version":0.99},"Date::Language::Bulgarian":{"version":1.01,"file":"lib/Date/Language/Bulgarian.pm"},"Date::Format::Generic":{"file":"lib/Date/Format.pm","version":2.24},"Date::Language::Chinese":{"file":"lib/Date/Language/Chinese.pm","version":"1.00"},"Date::Language::Sidama":{"file":"lib/Date/Language/Sidama.pm","version":0.99},"Date::Language::Finnish":{"file":"lib/Date/Language/Finnish.pm","version":1.01},"Date::Language::Tigrinya":{"version":"1.00","file":"lib/Date/Language/Tigrinya.pm"},"Date::Language::Icelandic":{"file":"lib/Date/Language/Icelandic.pm","version":1.01},"Date::Language::Austrian":{"version":1.01,"file":"lib/Date/Language/Austrian.pm"},"Date::Language::Russian":{"version":1.01,"file":"lib/Date/Language/Russian.pm"},"Date::Language::Dutch":{"file":"lib/Date/Language/Dutch.pm","version":1.02},"Date::Language::Somali":{"version":0.99,"file":"lib/Date/Language/Somali.pm"},"TimeDate":{"file":"lib/TimeDate.pm","version":1.21},"Date::Language::Afar":{"version":0.99,"file":"lib/Date/Language/Afar.pm"},"Date::Language::Hungarian":{"version":1.01,"file":"lib/Date/Language/Hungarian.pm"},"Date::Language::Amharic":{"file":"lib/Date/Language/Amharic.pm","version":"1.00"},"Date::Language::Chinese_GB":{"file":"lib/Date/Language/Chinese_GB.pm","version":1.01},"Date::Language::Norwegian":{"version":1.01,"file":"lib/Date/Language/Norwegian.pm"},"Date::Language::TigrinyaEthiopian":{"version":"1.00","file":"lib/Date/Language/TigrinyaEthiopian.pm"},"Date::Language::German":{"version":1.02,"file":"lib/Date/Language/German.pm"},"Date::Language::Spanish":{"version":"1.00","file":"lib/Date/Language/Spanish.pm"},"Date::Language::Swedish":{"file":"lib/Date/Language/Swedish.pm","version":1.01},"Date::Language::Czech":{"file":"lib/Date/Language/Czech.pm","version":1.01},"Date::Parse":{"version":2.33,"file":"lib/Date/Parse.pm"},"Date::Language::Russian_koi8r":{"version":1.01,"file":"lib/Date/Language/Russian_koi8r.pm"},"Date::Language::Oromo":{"file":"lib/Date/Language/Oromo.pm","version":0.99},"Date::Language::English":{"file":"lib/Date/Language/English.pm","version":1.01},"Date::Language::Turkish":{"file":"lib/Date/Language/Turkish.pm","version":"1.0"},"Date::Language::Italian":{"version":1.01,"file":"lib/Date/Language/Italian.pm"},"Date::Language::Brazilian":{"file":"lib/Date/Language/Brazilian.pm","version":1.01},"Date::Language::Occitan":{"version":1.04,"file":"lib/Date/Language/Occitan.pm"},"Date::Language::Danish":{"file":"lib/Date/Language/Danish.pm","version":1.01},"Date::Language::Russian_cp1251":{"file":"lib/Date/Language/Russian_cp1251.pm","version":1.01},"Date::Language::Romanian":{"file":"lib/Date/Language/Romanian.pm","version":1.01},"Date::Language::Greek":{"version":"1.00","file":"lib/Date/Language/Greek.pm"},"Date::Language::TigrinyaEritrean":{"version":"1.00","file":"lib/Date/Language/TigrinyaEritrean.pm"},"Date::Language::French":{"version":1.04,"file":"lib/Date/Language/French.pm"},"Time::Zone":{"version":2.24,"file":"lib/Time/Zone.pm"}}}PK2N%[��BЧ	�	;perl5/x86_64-linux-thread-multi/.meta/CPAN-2.38/MYMETA.jsonnu��6�${
   "abstract" : "query, download and build perl modules from CPAN sites",
   "author" : [
      "Andreas Koenig <andreas.koenig.gmwojprw@franz.ak.mind.de>"
   ],
   "dynamic_config" : 0,
   "generated_by" : "ExtUtils::MakeMaker version 7.34, CPAN::Meta::Converter version 2.150010",
   "keywords" : [
      "CPAN",
      "module",
      "module installation"
   ],
   "license" : [
      "perl_5"
   ],
   "meta-spec" : {
      "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
      "version" : 2
   },
   "name" : "CPAN",
   "no_index" : {
      "directory" : [
         "t",
         "inc"
      ]
   },
   "prereqs" : {
      "build" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "configure" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "runtime" : {
         "requires" : {
            "Archive::Tar" : "0",
            "Archive::Zip" : "0",
            "CPAN::Meta" : "0",
            "CPAN::Meta::Requirements" : "2.121",
            "CPAN::Meta::YAML" : "0",
            "Compress::Bzip2" : "0",
            "Compress::Zlib" : "0",
            "Data::Dumper" : "0",
            "Digest::MD5" : "0",
            "Digest::SHA" : "0",
            "Exporter" : "0",
            "Exporter::Heavy" : "0",
            "ExtUtils::CBuilder" : "0",
            "File::Copy" : "0",
            "File::HomeDir" : "0",
            "File::Spec" : "0",
            "File::Temp" : "0",
            "File::Which" : "0",
            "HTTP::Tiny" : "0.005",
            "IO::Compress::Base" : "0",
            "IO::Zlib" : "0",
            "JSON::PP" : "0",
            "MIME::Base64" : "0",
            "Module::Build" : "0",
            "Net::FTP" : "0",
            "Net::Ping" : "0",
            "Parse::CPAN::Meta" : "0",
            "Pod::Perldoc" : "0",
            "Pod::Perldoc::ToMan" : "0",
            "Scalar::Util" : "0",
            "Socket" : "0",
            "Term::ReadKey" : "0",
            "Test::Harness" : "2.62",
            "Test::More" : "0",
            "Text::Glob" : "0",
            "Text::ParseWords" : "0",
            "Text::Wrap" : "0",
            "perl" : "5.006002"
         }
      }
   },
   "release_status" : "stable",
   "resources" : {
      "repository" : {
         "type" : "git",
         "url" : "https://github.com/andk/cpanpm"
      }
   },
   "version" : "2.38",
   "x_serialization_backend" : "JSON::PP version 2.97001"
}
PK2N%[�0��
�
<perl5/x86_64-linux-thread-multi/.meta/CPAN-2.38/install.jsonnu��6�${"name":"CPAN","dist":"CPAN-2.38","version":2.38,"target":"CPAN","provides":{"CPAN::Queue":{"version":5.5003,"file":"lib/CPAN/Queue.pm"},"CPAN::Author":{"file":"lib/CPAN/Author.pm","version":5.5002},"CPAN::Index":{"version":2.29,"file":"lib/CPAN/Index.pm"},"CPAN::Tarzip":{"version":5.5013,"file":"lib/CPAN/Tarzip.pm"},"CPAN::URL":{"file":"lib/CPAN/URL.pm","version":5.5},"CPAN::Distroprefs::Result":{"version":6.0001,"file":"lib/CPAN/Distroprefs.pm"},"CPAN::Distroprefs":{"file":"lib/CPAN/Distroprefs.pm","version":6.0001},"CPAN::Complete":{"version":5.5001,"file":"lib/CPAN/Complete.pm"},"CPAN::Mirrors":{"file":"lib/CPAN/Mirrors.pm","version":2.27},"CPAN::LWP::UserAgent":{"version":1.9601,"file":"lib/CPAN/LWP/UserAgent.pm"},"CPAN::Version":{"version":5.5003,"file":"lib/CPAN/Version.pm"},"CPAN::HandleConfig":{"version":5.5013,"file":"lib/CPAN/HandleConfig.pm"},"CPAN::Exception::blocked_urllist":{"file":"lib/CPAN/Exception/blocked_urllist.pm","version":1.001},"CPAN::Distribution":{"file":"lib/CPAN/Distribution.pm","version":2.34},"CPAN::Distroprefs::Result::Warning":{"version":6.0001,"file":"lib/CPAN/Distroprefs.pm"},"CPAN::Exception::RecursiveDependency":{"version":5.5001,"file":"lib/CPAN/Exception/RecursiveDependency.pm"},"CPAN::FTP::netrc":{"version":1.01,"file":"lib/CPAN/FTP/netrc.pm"},"CPAN::HTTP::Client":{"file":"lib/CPAN/HTTP/Client.pm","version":1.9602},"CPAN":{"file":"lib/CPAN.pm","version":2.38},"CPAN::Queue::Item":{"file":"lib/CPAN/Queue.pm","version":5.5003},"CPAN::FTP":{"file":"lib/CPAN/FTP.pm","version":5.5016},"CPAN::Debug":{"version":5.5001,"file":"lib/CPAN/Debug.pm"},"CPAN::Admin":{"file":"lib/CPAN/Admin.pm","version":5.501},"CPAN::DeferredCode":{"file":"lib/CPAN/DeferredCode.pm","version":"5.50"},"App::Cpan":{"version":1.678,"file":"lib/App/Cpan.pm"},"CPAN::Distroprefs::Result::Error":{"file":"lib/CPAN/Distroprefs.pm","version":6.0001},"CPAN::Prompt":{"version":5.5,"file":"lib/CPAN/Prompt.pm"},"CPAN::Distrostatus":{"version":5.5,"file":"lib/CPAN/Distrostatus.pm"},"CPAN::Eval":{"file":"lib/CPAN/Distroprefs.pm","version":6.0001},"CPAN::Kwalify":{"version":"5.50","file":"lib/CPAN/Kwalify.pm"},"CPAN::Nox":{"version":5.5001,"file":"lib/CPAN/Nox.pm"},"CPAN::Distroprefs::Result::Success":{"file":"lib/CPAN/Distroprefs.pm","version":6.0001},"CPAN::FirstTime":{"version":5.5317,"file":"lib/CPAN/FirstTime.pm"},"CPAN::Exception::RecursiveDependency::na":{"version":5.5001,"file":"lib/CPAN/Exception/RecursiveDependency.pm"},"CPAN::Distroprefs::Result::Fatal":{"version":6.0001,"file":"lib/CPAN/Distroprefs.pm"},"CPAN::Exception::yaml_not_installed":{"file":"lib/CPAN/Exception/yaml_not_installed.pm","version":5.5},"CPAN::Shell":{"version":5.5009,"file":"lib/CPAN/Shell.pm"},"CPAN::Plugin::Specfile":{"file":"lib/CPAN/Plugin/Specfile.pm","version":0.02},"CPAN::Module":{"file":"lib/CPAN/Module.pm","version":5.5003},"CPAN::Distroprefs::Pref":{"file":"lib/CPAN/Distroprefs.pm","version":6.0001},"CPAN::HTTP::Credentials":{"file":"lib/CPAN/HTTP/Credentials.pm","version":1.9601},"CPAN::Mirrored::By":{"version":2.27,"file":"lib/CPAN/Mirrors.pm"},"CPAN::Plugin":{"file":"lib/CPAN/Plugin.pm","version":0.97},"CPAN::Distroprefs::Iterator":{"file":"lib/CPAN/Distroprefs.pm","version":6.0001},"CPAN::InfoObj":{"version":5.5,"file":"lib/CPAN/InfoObj.pm"},"CPAN::CacheMgr":{"version":5.5002,"file":"lib/CPAN/CacheMgr.pm"},"CPAN::Bundle":{"version":5.5005,"file":"lib/CPAN/Bundle.pm"},"CPAN::Exception::yaml_process_error":{"file":"lib/CPAN/Exception/yaml_process_error.pm","version":5.5}},"pathname":"A/AN/ANDK/CPAN-2.38.tar.gz"}PK2N%[��H��Aperl5/x86_64-linux-thread-multi/.meta/HTTP-Tiny-0.090/MYMETA.jsonnu��6�${
   "abstract" : "A small, simple, correct HTTP/1.1 client",
   "author" : [
      "Christian Hansen <chansen@cpan.org>",
      "David Golden <dagolden@cpan.org>"
   ],
   "dynamic_config" : 0,
   "generated_by" : "Dist::Zilla version 6.032, CPAN::Meta::Converter version 2.150010",
   "license" : [
      "perl_5"
   ],
   "meta-spec" : {
      "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
      "version" : 2
   },
   "name" : "HTTP-Tiny",
   "no_index" : {
      "directory" : [
         "corpus",
         "examples",
         "t",
         "xt"
      ],
      "package" : [
         "DB"
      ]
   },
   "prereqs" : {
      "build" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "configure" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "6.17"
         },
         "suggests" : {
            "JSON::PP" : "2.27300"
         }
      },
      "develop" : {
         "requires" : {
            "Dist::Zilla" : "5",
            "Dist::Zilla::Plugin::Prereqs" : "0",
            "Dist::Zilla::Plugin::ReleaseStatus::FromVersion" : "0",
            "Dist::Zilla::Plugin::RemovePrereqs" : "0",
            "Dist::Zilla::PluginBundle::DAGOLDEN" : "0.072",
            "File::Spec" : "0",
            "File::Temp" : "0",
            "IO::Handle" : "0",
            "IPC::Open3" : "0",
            "Perl::Critic::Policy::Lax::ProhibitStringyEval::ExceptForRequire" : "0",
            "Pod::Coverage::TrustPod" : "0",
            "Pod::Wordlist" : "0",
            "Software::License::Perl_5" : "0",
            "Test::CPAN::Meta" : "0",
            "Test::MinimumVersion" : "0",
            "Test::More" : "0",
            "Test::Perl::Critic" : "0",
            "Test::Pod" : "1.41",
            "Test::Pod::Coverage" : "1.08",
            "Test::Portability::Files" : "0",
            "Test::Spelling" : "0.17",
            "Test::Version" : "1",
            "perl" : "5.006"
         }
      },
      "runtime" : {
         "recommends" : {
            "HTTP::CookieJar" : "0.001",
            "IO::Socket::IP" : "0.32",
            "IO::Socket::SSL" : "1.968",
            "Net::SSLeay" : "1.49"
         },
         "requires" : {
            "Carp" : "0",
            "Fcntl" : "0",
            "IO::Socket" : "0",
            "MIME::Base64" : "0",
            "Socket" : "0",
            "Time::Local" : "0",
            "bytes" : "0",
            "perl" : "5.006",
            "strict" : "0",
            "warnings" : "0"
         }
      },
      "test" : {
         "recommends" : {
            "CPAN::Meta" : "2.120900"
         },
         "requires" : {
            "Data::Dumper" : "0",
            "Exporter" : "0",
            "ExtUtils::MakeMaker" : "0",
            "File::Basename" : "0",
            "File::Spec" : "0",
            "File::Temp" : "0",
            "IO::Dir" : "0",
            "IO::File" : "0",
            "IO::Socket::INET" : "0",
            "IPC::Cmd" : "0",
            "Test::More" : "0.96",
            "lib" : "0",
            "open" : "0"
         }
      }
   },
   "provides" : {
      "HTTP::Tiny" : {
         "file" : "lib/HTTP/Tiny.pm",
         "version" : "0.090"
      }
   },
   "release_status" : "stable",
   "resources" : {
      "bugtracker" : {
         "web" : "https://github.com/Perl-Toolchain-Gang/HTTP-Tiny/issues"
      },
      "homepage" : "https://github.com/Perl-Toolchain-Gang/HTTP-Tiny",
      "repository" : {
         "type" : "git",
         "url" : "https://github.com/Perl-Toolchain-Gang/HTTP-Tiny.git",
         "web" : "https://github.com/Perl-Toolchain-Gang/HTTP-Tiny"
      }
   },
   "version" : "0.090",
   "x_authority" : "cpan:DAGOLDEN",
   "x_contributors" : [
      "Alan Gardner <gardner@pythian.com>",
      "Alessandro Ghedini <al3xbio@gmail.com>",
      "A. Sinan Unur <nanis@cpan.org>",
      "Brad Gilbert <bgills@cpan.org>",
      "brian m. carlson <sandals@crustytoothpaste.net>",
      "Chris Nehren <apeiron@cpan.org>",
      "Chris Weyl <cweyl@alumni.drew.edu>",
      "Claes Jakobsson <claes@surfar.nu>",
      "Clinton Gormley <clint@traveljury.com>",
      "Craig A. Berry <craigberry@mac.com>",
      "David Golden <xdg@xdg.me>",
      "David Mitchell <davem@iabyn.com>",
      "Dean Pearce <pearce@pythian.com>",
      "Edward Zborowski <ed@rubensteintech.com>",
      "Felipe Gasper <felipe@felipegasper.com>",
      "Graham Knop <haarg@haarg.org>",
      "Greg Kennedy <kennedy.greg@gmail.com>",
      "James E Keenan <jkeenan@cpan.org>",
      "James Raspass <jraspass@gmail.com>",
      "Jeremy Mates <jmates@cpan.org>",
      "Jess Robinson <castaway@desert-island.me.uk>",
      "Karen Etheridge <ether@cpan.org>",
      "Lukas Eklund <leklund@gmail.com>",
      "Martin J. Evans <mjegh@ntlworld.com>",
      "Martin-Louis Bright <mlbright@gmail.com>",
      "Matthew Horsfall <wolfsage@gmail.com>",
      "Michael R. Davis <mrdvt92@users.noreply.github.com>",
      "Mike Doherty <doherty@cpan.org>",
      "Nicolas Rochelemagne <rochelemagne@cpanel.net>",
      "Olaf Alders <olaf@wundersolutions.com>",
      "Olivier Mengué <dolmen@cpan.org>",
      "Petr Písař <ppisar@redhat.com>",
      "sanjay-cpu <snjkmr32@gmail.com>",
      "Serguei Trouchelle <stro@cpan.org>",
      "Shoichi Kaji <skaji@cpan.org>",
      "SkyMarshal <skymarshal1729@gmail.com>",
      "Sören Kornetzki <soeren.kornetzki@delti.com>",
      "Steve Grazzini <steve.grazzini@grantstreet.com>",
      "Stig Palmquist <git@stig.io>",
      "Syohei YOSHIDA <syohex@gmail.com>",
      "Tatsuhiko Miyagawa <miyagawa@bulknews.net>",
      "Tom Hukins <tom@eborcom.com>",
      "Tony Cook <tony@develop-help.com>",
      "Xavier Guimard <yadd@debian.org>"
   ],
   "x_generated_by_perl" : "v5.38.2",
   "x_serialization_backend" : "JSON::PP version 2.97001",
   "x_spdx_expression" : "Artistic-1.0-Perl OR GPL-1.0-or-later"
}
PK2N%[)f��Bperl5/x86_64-linux-thread-multi/.meta/HTTP-Tiny-0.090/install.jsonnu��6�${"name":"HTTP::Tiny","dist":"HTTP-Tiny-0.090","version":"0.090","provides":{"HTTP::Tiny":{"version":"0.090","file":"lib/HTTP/Tiny.pm"}},"target":"HTTP::Tiny","pathname":"H/HA/HAARG/HTTP-Tiny-0.090.tar.gz"}PK2N%[|�	��>perl5/x86_64-linux-thread-multi/.meta/JSON-XS-4.03/MYMETA.jsonnu��6�${
   "abstract" : "unknown",
   "author" : [
      "unknown"
   ],
   "dynamic_config" : 0,
   "generated_by" : "ExtUtils::MakeMaker version 7.34, CPAN::Meta::Converter version 2.150001, CPAN::Meta::Converter version 2.150010",
   "license" : [
      "unknown"
   ],
   "meta-spec" : {
      "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
      "version" : 2
   },
   "name" : "JSON-XS",
   "no_index" : {
      "directory" : [
         "t",
         "inc"
      ]
   },
   "prereqs" : {
      "build" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "configure" : {
         "requires" : {
            "Canary::Stability" : "0",
            "ExtUtils::MakeMaker" : "6.52"
         }
      },
      "runtime" : {
         "requires" : {
            "Types::Serialiser" : "0",
            "common::sense" : "0"
         }
      }
   },
   "release_status" : "stable",
   "version" : "4.03",
   "x_serialization_backend" : "JSON::PP version 2.97001"
}
PK2N%[�:����?perl5/x86_64-linux-thread-multi/.meta/JSON-XS-4.03/install.jsonnu��6�${"version":4.03,"dist":"JSON-XS-4.03","name":"JSON::XS","pathname":"M/ML/MLEHMANN/JSON-XS-4.03.tar.gz","provides":{"JSON::XS":{"file":"XS.pm","version":4.03}},"target":"JSON::XS"}PK2N%[<����Eperl5/x86_64-linux-thread-multi/.meta/WWW-RobotRules-6.02/MYMETA.jsonnu��6�${
   "abstract" : "database of robots.txt-derived permissions",
   "author" : [
      "Gisle Aas <gisle@activestate.com>"
   ],
   "dynamic_config" : 0,
   "generated_by" : "ExtUtils::MakeMaker version 6.57_05, CPAN::Meta::Converter version 2.150010",
   "license" : [
      "perl_5"
   ],
   "meta-spec" : {
      "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
      "version" : 2
   },
   "name" : "WWW-RobotRules",
   "no_index" : {
      "directory" : [
         "t",
         "inc"
      ]
   },
   "prereqs" : {
      "build" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "configure" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "runtime" : {
         "requires" : {
            "AnyDBM_File" : "0",
            "Fcntl" : "0",
            "URI" : "1.10",
            "perl" : "5.008001"
         }
      }
   },
   "release_status" : "stable",
   "resources" : {
      "repository" : {
         "url" : "http://github.com/gisle/www-robotrules"
      },
      "x_MailingList" : "mailto:libwww@perl.org"
   },
   "version" : "6.02",
   "x_serialization_backend" : "JSON::PP version 2.97001"
}
PK2N%[�Ӕ��Fperl5/x86_64-linux-thread-multi/.meta/WWW-RobotRules-6.02/install.jsonnu��6�${"name":"WWW::RobotRules","target":"WWW::RobotRules","version":6.02,"pathname":"G/GA/GAAS/WWW-RobotRules-6.02.tar.gz","provides":{"WWW::RobotRules":{"file":"lib/WWW/RobotRules.pm","version":6.02},"WWW::RobotRules::AnyDBM_File":{"file":"lib/WWW/RobotRules/AnyDBM_File.pm","version":"6.00"},"WWW::RobotRules::InCore":{"version":6.02,"file":"lib/WWW/RobotRules.pm"}},"dist":"WWW-RobotRules-6.02"}PK3N%[|{�	�	Cperl5/x86_64-linux-thread-multi/.meta/XML-LibXML-2.0210/MYMETA.jsonnu��6�${
   "abstract" : "Interface to Gnome libxml2 xml parsing and DOM library",
   "author" : [
      "Petr Pajas <PAJAS@cpan.org>"
   ],
   "dynamic_config" : 0,
   "generated_by" : "ExtUtils::MakeMaker version 7.70, CPAN::Meta::Converter version 2.150010",
   "keywords" : [
      "dom",
      "html",
      "libxml",
      "object oriented",
      "oop",
      "parse",
      "parser",
      "parsing",
      "pullparser",
      "sax",
      "sgml",
      "xml",
      "xpath",
      "XPath",
      "xs"
   ],
   "license" : [
      "perl_5"
   ],
   "meta-spec" : {
      "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
      "version" : 2
   },
   "name" : "XML-LibXML",
   "no_index" : {
      "directory" : [
         "t",
         "inc",
         "xt"
      ]
   },
   "prereqs" : {
      "build" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "configure" : {
         "requires" : {
            "Alien::Base::Wrapper" : "0",
            "Alien::Libxml2" : "0.14",
            "Config" : "0",
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "runtime" : {
         "requires" : {
            "Carp" : "0",
            "DynaLoader" : "0",
            "Encode" : "0",
            "Exporter" : "5.57",
            "IO::Handle" : "0",
            "Scalar::Util" : "0",
            "Tie::Hash" : "0",
            "XML::NamespaceSupport" : "1.07",
            "XML::SAX" : "0.11",
            "XML::SAX::Base" : "0",
            "XML::SAX::DocumentLocator" : "0",
            "XML::SAX::Exception" : "0",
            "base" : "0",
            "constant" : "0",
            "overload" : "0",
            "parent" : "0",
            "perl" : "5.008001",
            "strict" : "0",
            "vars" : "0",
            "warnings" : "0"
         }
      },
      "test" : {
         "requires" : {
            "Config" : "0",
            "Errno" : "0",
            "IO::File" : "0",
            "IO::Handle" : "0",
            "POSIX" : "0",
            "Scalar::Util" : "0",
            "Test::More" : "0",
            "locale" : "0",
            "utf8" : "0"
         }
      }
   },
   "release_status" : "stable",
   "resources" : {
      "repository" : {
         "type" : "git",
         "url" : "https://github.com/shlomif/perl-XML-LibXML.git",
         "web" : "https://github.com/shlomif/perl-XML-LibXML"
      }
   },
   "version" : "2.0210",
   "x_serialization_backend" : "JSON::PP version 2.97001"
}
PK3N%[��aX�
�
Dperl5/x86_64-linux-thread-multi/.meta/XML-LibXML-2.0210/install.jsonnu��6�${"target":"XML::LibXML","dist":"XML-LibXML-2.0210","version":"2.0210","provides":{"XML::LibXML::XPathContext":{"version":"2.0210","file":"lib/XML/LibXML/XPathContext.pm"},"XML::LibXML::InputCallback":{"version":"2.0210","file":"LibXML.pm"},"XML::LibXML::Dtd":{"version":"2.0210","file":"LibXML.pm"},"XML::LibXML::Schema":{"version":"2.0210","file":"LibXML.pm"},"XML::LibXML::Boolean":{"file":"lib/XML/LibXML/Boolean.pm","version":"2.0210"},"XML::LibXML::Reader":{"version":"2.0210","file":"lib/XML/LibXML/Reader.pm"},"XML::LibXML::Error":{"version":"2.0210","file":"lib/XML/LibXML/Error.pm"},"XML::LibXML::SAX":{"version":"2.0210","file":"lib/XML/LibXML/SAX.pm"},"XML::LibXML":{"file":"LibXML.pm","version":"2.0210"},"XML::LibXML::ErrNo":{"version":"2.0210","file":"lib/XML/LibXML/ErrNo.pm"},"XML::LibXML::Attr":{"file":"LibXML.pm","version":"2.0210"},"XML::LibXML::Node":{"file":"LibXML.pm","version":"2.0210"},"XML::LibXML::Element":{"version":"2.0210","file":"LibXML.pm"},"XML::LibXML::XPathExpression":{"version":"2.0210","file":"LibXML.pm"},"XML::LibXML::Literal":{"file":"lib/XML/LibXML/Literal.pm","version":"2.0210"},"XML::LibXML::AttributeHash":{"version":"2.0210","file":"lib/XML/LibXML/AttributeHash.pm"},"XML::LibXML::SAX::Parser":{"version":"2.0210","file":"lib/XML/LibXML/SAX/Parser.pm"},"XML::LibXML::NodeList":{"version":"2.0210","file":"lib/XML/LibXML/NodeList.pm"},"XML::LibXML::Document":{"version":"2.0210","file":"LibXML.pm"},"XML::LibXML::Devel":{"file":"lib/XML/LibXML/Devel.pm","version":"2.0210"},"XML::LibXML::Comment":{"file":"LibXML.pm","version":"2.0210"},"XML::LibXML::Pattern":{"version":"2.0210","file":"LibXML.pm"},"XML::LibXML::RegExp":{"file":"LibXML.pm","version":"2.0210"},"XML::LibXML::DocumentFragment":{"file":"LibXML.pm","version":"2.0210"},"XML::LibXML::Namespace":{"version":"2.0210","file":"LibXML.pm"},"XML::LibXML::SAX::Generator":{"version":"2.0210","file":"lib/XML/LibXML/SAX/Generator.pm"},"XML::LibXML::RelaxNG":{"version":"2.0210","file":"LibXML.pm"},"XML::LibXML::Common":{"file":"lib/XML/LibXML/Common.pm","version":"2.0210"},"XML::LibXML::_SAXParser":{"version":"2.0210","file":"LibXML.pm"},"XML::LibXML::Number":{"version":"2.0210","file":"lib/XML/LibXML/Number.pm"},"XML::LibXML::SAX::AttributeNode":{"version":"2.0210","file":"lib/XML/LibXML/SAX/Generator.pm"},"XML::LibXML::NamedNodeMap":{"file":"LibXML.pm","version":"2.0210"},"XML::LibXML::PI":{"file":"LibXML.pm","version":"2.0210"},"XML::LibXML::CDATASection":{"version":"2.0210","file":"LibXML.pm"},"XML::LibXML::Text":{"file":"LibXML.pm","version":"2.0210"},"XML::LibXML::SAX::Builder":{"version":"2.0210","file":"lib/XML/LibXML/SAX/Builder.pm"}},"name":"XML::LibXML","pathname":"S/SH/SHLOMIF/XML-LibXML-2.0210.tar.gz"}PK3N%[VJ��Dperl5/x86_64-linux-thread-multi/.meta/local-lib-2.000029/MYMETA.jsonnu��6�${
   "abstract" : "create and use a local lib/ for perl modules with PERL5LIB",
   "author" : [
      "mst - Matt S. Trout (cpan:MSTROUT) <mst@shadowcat.co.uk>"
   ],
   "dynamic_config" : 0,
   "generated_by" : "ExtUtils::MakeMaker version 7.64, CPAN::Meta::Converter version 2.150010",
   "license" : [
      "perl_5"
   ],
   "meta-spec" : {
      "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
      "version" : 2
   },
   "name" : "local-lib",
   "no_index" : {
      "directory" : [
         "t",
         "inc"
      ]
   },
   "prereqs" : {
      "build" : {
         "requires" : {}
      },
      "configure" : {
         "requires" : {}
      },
      "develop" : {
         "requires" : {
            "Capture::Tiny" : "0",
            "Module::Build" : "0.36",
            "Test::CPAN::Changes" : "0",
            "Test::EOL" : "0",
            "Test::More" : "0.8101",
            "Test::NoTabs" : "0",
            "Test::Pod" : "0"
         }
      },
      "runtime" : {
         "requires" : {
            "perl" : "5.006"
         }
      },
      "test" : {
         "requires" : {
            "Test::More" : "0"
         }
      }
   },
   "release_status" : "stable",
   "resources" : {
      "bugtracker" : {
         "mailto" : "bug-local-lib@rt.cpan.org",
         "web" : "https://rt.cpan.org/Public/Dist/Display.html?Name=local-lib"
      },
      "license" : [
         "http://dev.perl.org/licenses/"
      ],
      "repository" : {
         "type" : "git",
         "url" : "git://github.com/Perl-Toolchain-Gang/local-lib",
         "web" : "https://github.com/Perl-Toolchain-Gang/local-lib"
      },
      "x_IRC" : "irc://irc.perl.org/#local-lib"
   },
   "version" : "2.000029",
   "x_serialization_backend" : "JSON::PP version 2.97001"
}
PK3N%[�CEperl5/x86_64-linux-thread-multi/.meta/local-lib-2.000029/install.jsonnu��6�${"target":"local::lib","provides":{"local::lib":{"version":2.000029,"file":"lib/local/lib.pm"},"lib::core::only":{"file":"lib/lib/core/only.pm"}},"pathname":"H/HA/HAARG/local-lib-2.000029.tar.gz","name":"local::lib","dist":"local-lib-2.000029","version":2.000029}PK3N%[ǽ��AA=perl5/x86_64-linux-thread-multi/.meta/IO-Tty-1.20/MYMETA.jsonnu��6�${
   "abstract" : "Pseudo ttys and constants",
   "author" : [
      "Roland Giersig <RGiersig@cpan.org>"
   ],
   "dynamic_config" : 0,
   "generated_by" : "ExtUtils::MakeMaker version 7.64, CPAN::Meta::Converter version 2.150010",
   "license" : [
      "perl_5"
   ],
   "meta-spec" : {
      "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
      "version" : 2
   },
   "name" : "IO-Tty",
   "no_index" : {
      "directory" : [
         "t",
         "inc"
      ]
   },
   "prereqs" : {
      "build" : {
         "requires" : {
            "Test::More" : "0"
         }
      },
      "configure" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      }
   },
   "release_status" : "stable",
   "resources" : {
      "bugtracker" : {
         "web" : "https://github.com/toddr/IO-Tty/issues"
      },
      "license" : [
         "http://dev.perl.org/licenses/"
      ],
      "repository" : {
         "url" : "https://github.com/toddr/IO-Tty"
      }
   },
   "version" : "1.20",
   "x_serialization_backend" : "JSON::PP version 2.97001"
}
PK3N%[I/�>perl5/x86_64-linux-thread-multi/.meta/IO-Tty-1.20/install.jsonnu��6�${"dist":"IO-Tty-1.20","version":"1.20","name":"IO::Tty","pathname":"T/TO/TODDR/IO-Tty-1.20.tar.gz","target":"IO::Tty","provides":{"IO::Tty::Constant":{"file":"Tty/Constant.pm","version":"1.20"},"IO::Tty":{"file":"Tty.pm","version":"1.20"},"IO::Pty":{"version":"1.20","file":"Pty.pm"}}}PK3N%[򃫴��Bperl5/x86_64-linux-thread-multi/.meta/HTML-Tagset-3.24/MYMETA.jsonnu��6�${
   "abstract" : "Data tables useful in parsing HTML",
   "author" : [
      "Andy Lester <andy@petdance.com>"
   ],
   "dynamic_config" : 0,
   "generated_by" : "ExtUtils::MakeMaker version 7.70, CPAN::Meta::Converter version 2.150010",
   "license" : [
      "artistic_2"
   ],
   "meta-spec" : {
      "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
      "version" : 2
   },
   "name" : "HTML-Tagset",
   "no_index" : {
      "directory" : [
         "t",
         "inc"
      ]
   },
   "prereqs" : {
      "build" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "6.46"
         }
      },
      "configure" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "6.46"
         }
      },
      "runtime" : {
         "requires" : {
            "perl" : "5.010001"
         }
      },
      "test" : {
         "requires" : {
            "Test::More" : "0.95"
         }
      }
   },
   "release_status" : "stable",
   "resources" : {
      "bugtracker" : {
         "web" : "https://github.com/petdance/html-tagset/issues"
      },
      "homepage" : "https://github.com/petdance/html-tagset",
      "license" : [
         "https://opensource.org/licenses/artistic-license-2.0"
      ],
      "repository" : {
         "url" : "https://github.com/petdance/html-tagset"
      }
   },
   "version" : "3.24",
   "x_serialization_backend" : "JSON::PP version 2.97001"
}
PK3N%[LM��Cperl5/x86_64-linux-thread-multi/.meta/HTML-Tagset-3.24/install.jsonnu��6�${"target":"HTML::Tagset","name":"HTML::Tagset","pathname":"P/PE/PETDANCE/HTML-Tagset-3.24.tar.gz","provides":{"HTML::Tagset":{"file":"lib/HTML/Tagset.pm","version":3.24}},"version":3.24,"dist":"HTML-Tagset-3.24"}PK3N%[�5�A��Bperl5/x86_64-linux-thread-multi/.meta/HTML-Parser-3.83/MYMETA.jsonnu��6�${
   "abstract" : "HTML parser class",
   "author" : [
      "Gisle Aas <gaas@cpan.org>"
   ],
   "dynamic_config" : 0,
   "generated_by" : "Dist::Zilla version 6.032, CPAN::Meta::Converter version 2.150010",
   "license" : [
      "perl_5"
   ],
   "meta-spec" : {
      "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
      "version" : 2
   },
   "name" : "HTML-Parser",
   "no_index" : {
      "directory" : [
         "eg",
         "examples",
         "inc",
         "share",
         "t",
         "xt"
      ]
   },
   "prereqs" : {
      "build" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "configure" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "6.52"
         },
         "suggests" : {
            "JSON::PP" : "2.27300"
         }
      },
      "develop" : {
         "requires" : {
            "Dist::Zilla" : "0",
            "Dist::Zilla::Plugin::MinimumPerl" : "0",
            "Dist::Zilla::PluginBundle::Starter" : "v4.0.0",
            "File::Spec" : "0",
            "IO::Handle" : "0",
            "IPC::Open3" : "0",
            "Pod::Coverage::TrustPod" : "0",
            "Test::CPAN::Changes" : "0.4",
            "Test::CPAN::Meta" : "0",
            "Test::CheckManifest" : "1.29",
            "Test::Kwalitee" : "1.22",
            "Test::More" : "0.88",
            "Test::Pod" : "1.41",
            "Test::Pod::Coverage" : "1.08",
            "Test::Pod::Spelling::CommonMistakes" : "1.000",
            "Test::Spelling" : "0.12",
            "Test::Version" : "2.00"
         }
      },
      "runtime" : {
         "requires" : {
            "Carp" : "0",
            "Exporter" : "0",
            "HTML::Tagset" : "0",
            "HTTP::Headers" : "0",
            "IO::File" : "0",
            "URI" : "0",
            "URI::URL" : "0",
            "XSLoader" : "0",
            "strict" : "0"
         }
      },
      "test" : {
         "recommends" : {
            "CPAN::Meta" : "2.120900"
         },
         "requires" : {
            "Config" : "0",
            "ExtUtils::MakeMaker" : "0",
            "File::Spec" : "0",
            "IO::File" : "0",
            "SelectSaver" : "0",
            "Test::More" : "0",
            "URI" : "0",
            "strict" : "0"
         }
      }
   },
   "provides" : {
      "HTML::Entities" : {
         "file" : "lib/HTML/Entities.pm",
         "version" : "3.83"
      },
      "HTML::Filter" : {
         "file" : "lib/HTML/Filter.pm",
         "version" : "3.83",
         "x_deprecated" : 1
      },
      "HTML::HeadParser" : {
         "file" : "lib/HTML/HeadParser.pm",
         "version" : "3.83"
      },
      "HTML::LinkExtor" : {
         "file" : "lib/HTML/LinkExtor.pm",
         "version" : "3.83"
      },
      "HTML::Parser" : {
         "file" : "lib/HTML/Parser.pm",
         "version" : "3.83"
      },
      "HTML::PullParser" : {
         "file" : "lib/HTML/PullParser.pm",
         "version" : "3.83"
      },
      "HTML::TokeParser" : {
         "file" : "lib/HTML/TokeParser.pm",
         "version" : "3.83"
      }
   },
   "release_status" : "stable",
   "resources" : {
      "bugtracker" : {
         "web" : "https://github.com/libwww-perl/HTML-Parser/issues"
      },
      "homepage" : "https://github.com/libwww-perl/HTML-Parser",
      "repository" : {
         "type" : "git",
         "url" : "https://github.com/libwww-perl/HTML-Parser.git",
         "web" : "https://github.com/libwww-perl/HTML-Parser"
      }
   },
   "version" : "3.83",
   "x_contributors" : [
      "Antonio Radici <antonio@dyne.org>",
      "Barbie <barbie@missbarbell.co.uk>",
      "bulk88 <bulk88@hotmail.com>",
      "Chase Whitener <capoeirab@cpan.org>",
      "Chip Salzenberg <chip@pobox.com>",
      "Damyan Ivanov <dmn@debian.org>",
      "David Steinbrunner <dsteinbrunner@pobox.com>",
      "dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
      "François Perrad <francois.perrad@gadz.org>",
      "Gisle Aas <gisle@aas.no>",
      "Graham Knop <haarg@haarg.org>",
      "Jacques Germishuys <jacquesg@striata.com>",
      "James Raspass <jraspass@gmail.com>",
      "Jess Robinson <castaway@desert-island.me.uk>",
      "Jon Jensen <jon@endpoint.com>",
      "Lukas Mai <lukasmai.403@gmail.com>",
      "Michal Josef Špaček <mspacek@redhat.com>",
      "Mike South <msouth@gmail.com>",
      "Nicholas Clark <nick@ccl4.org>",
      "Nicolas R <nicolas@atoomic.org>",
      "Olaf Alders <olaf@wundersolutions.com>",
      "Salvatore Bonaccorso <salvatore.bonaccorso@gmail.com>",
      "Todd Rinaldo <toddr@cpan.org>",
      "Ville Skyttä <ville.skytta@iki.fi>",
      "yoshikazusawa <883514+yoshikazusawa@users.noreply.github.com>",
      "Yves Orton <demerphq@gmail.com>",
      "Zefram <zefram@fysh.org>"
   ],
   "x_generated_by_perl" : "v5.34.0",
   "x_serialization_backend" : "JSON::PP version 2.97001",
   "x_spdx_expression" : "Artistic-1.0-Perl OR GPL-1.0-or-later"
}
PK3N%[�)�Հ�Cperl5/x86_64-linux-thread-multi/.meta/HTML-Parser-3.83/install.jsonnu��6�${"name":"HTML::Parser","target":"HTML::Entities","dist":"HTML-Parser-3.83","version":"3.83","provides":{"HTML::LinkExtor":{"version":"3.83","file":"lib/HTML/LinkExtor.pm"},"HTML::PullParser":{"file":"lib/HTML/PullParser.pm","version":"3.83"},"HTML::Filter":{"file":"lib/HTML/Filter.pm","x_deprecated":1,"version":"3.83"},"HTML::Parser":{"version":"3.83","file":"lib/HTML/Parser.pm"},"HTML::Entities":{"version":"3.83","file":"lib/HTML/Entities.pm"},"HTML::HeadParser":{"version":"3.83","file":"lib/HTML/HeadParser.pm"},"HTML::TokeParser":{"version":"3.83","file":"lib/HTML/TokeParser.pm"}},"pathname":"O/OA/OALDERS/HTML-Parser-3.83.tar.gz"}PK3N%[�!�66=perl5/x86_64-linux-thread-multi/.meta/Expect-1.38/MYMETA.jsonnu��6�${
   "abstract" : "automate interactions with command line programs that expose a text terminal interface.",
   "author" : [
      "Austin Schutz <ASchutz@users.sourceforge.net>",
      "Roland Giersig <RGiersig@cpan.org>",
      "Dave Jacoby <jacoby@cpan.org>"
   ],
   "dynamic_config" : 0,
   "generated_by" : "ExtUtils::MakeMaker version 7.62, CPAN::Meta::Converter version 2.150010",
   "license" : [
      "perl_5"
   ],
   "meta-spec" : {
      "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
      "version" : 2
   },
   "name" : "Expect",
   "no_index" : {
      "directory" : [
         "t",
         "inc"
      ]
   },
   "prereqs" : {
      "build" : {
         "requires" : {}
      },
      "configure" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "6.64"
         }
      },
      "runtime" : {
         "requires" : {
            "Carp" : "0",
            "Errno" : "0",
            "Exporter" : "0",
            "Fcntl" : "0",
            "IO::Handle" : "0",
            "IO::Pty" : "1.11",
            "IO::Tty" : "1.11",
            "POSIX" : "0",
            "perl" : "5.006000"
         }
      },
      "test" : {
         "requires" : {
            "File::Temp" : "0",
            "Test::More" : "1.00"
         }
      }
   },
   "release_status" : "stable",
   "resources" : {
      "repository" : {
         "type" : "git",
         "url" : "http://github.com/jacoby/expect.pm.git",
         "web" : "http://github.com/jacoby/expect.pm"
      }
   },
   "version" : "1.38",
   "x_serialization_backend" : "JSON::PP version 2.97001"
}
PK3N%[4}(g��>perl5/x86_64-linux-thread-multi/.meta/Expect-1.38/install.jsonnu��6�${"provides":{"Expect":{"file":"lib/Expect.pm","version":1.38}},"target":"Expect","pathname":"J/JA/JACOBY/Expect-1.38.tar.gz","name":"Expect","dist":"Expect-1.38","version":1.38}PK3N%[ِ֚^^@perl5/x86_64-linux-thread-multi/.meta/AppConfig-1.71/MYMETA.jsonnu��6�${
   "abstract" : "AppConfig is a bundle of Perl5 modules for reading configuration files and parsing command line arguments.",
   "author" : [
      "Andy Wardley <abw@wardley.org>"
   ],
   "dynamic_config" : 0,
   "generated_by" : "ExtUtils::MakeMaker version 7.02, CPAN::Meta::Converter version 2.143240, CPAN::Meta::Converter version 2.150010",
   "license" : [
      "perl_5"
   ],
   "meta-spec" : {
      "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
      "version" : 2
   },
   "name" : "AppConfig",
   "no_index" : {
      "directory" : [
         "t",
         "inc"
      ]
   },
   "prereqs" : {
      "build" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "configure" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "runtime" : {
         "requires" : {
            "Test::More" : "0",
            "perl" : "5.008008"
         }
      },
      "test" : {
         "requires" : {
            "Test::Pod" : "1.0"
         }
      }
   },
   "release_status" : "stable",
   "resources" : {
      "repository" : {
         "type" : "git",
         "url" : "git://github.com/neilbowers/AppConfig.git",
         "web" : "https://github.com/neilbowers/AppConfig"
      }
   },
   "version" : "1.71",
   "x_serialization_backend" : "JSON::PP version 2.97001"
}
PK3N%[��U�QQAperl5/x86_64-linux-thread-multi/.meta/AppConfig-1.71/install.jsonnu��6�${"target":"AppConfig","name":"AppConfig","dist":"AppConfig-1.71","pathname":"N/NE/NEILB/AppConfig-1.71.tar.gz","provides":{"AppConfig::CGI":{"version":1.71,"file":"lib/AppConfig/CGI.pm"},"AppConfig::File":{"file":"lib/AppConfig/File.pm","version":1.71},"AppConfig::State":{"version":1.71,"file":"lib/AppConfig/Getopt.pm"},"AppConfig::Getopt":{"version":1.71,"file":"lib/AppConfig/Getopt.pm"},"AppConfig":{"file":"lib/AppConfig.pm","version":1.71},"AppConfig::Args":{"file":"lib/AppConfig/Args.pm","version":1.71},"AppConfig::Sys":{"version":1.71,"file":"lib/AppConfig/Sys.pm"}},"version":1.71}PK3N%[��h��Aperl5/x86_64-linux-thread-multi/.meta/XML-Simple-2.25/MYMETA.jsonnu��6�${
   "abstract" : "An API for simple XML files",
   "author" : [
      "Grant McLean <grantm@cpan.org>"
   ],
   "dynamic_config" : 0,
   "generated_by" : "Dist::Zilla version 5.043, CPAN::Meta::Converter version 2.150005, CPAN::Meta::Converter version 2.150010",
   "license" : [
      "perl_5"
   ],
   "meta-spec" : {
      "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
      "version" : 2
   },
   "name" : "XML-Simple",
   "prereqs" : {
      "build" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "configure" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "develop" : {
         "requires" : {
            "Test::Pod" : "1.41"
         }
      },
      "runtime" : {
         "requires" : {
            "XML::NamespaceSupport" : "1.04",
            "XML::SAX" : "0.15",
            "XML::SAX::Expat" : "0",
            "perl" : "5.008"
         }
      },
      "test" : {
         "requires" : {
            "File::Temp" : "0",
            "Test::More" : "0.88"
         }
      }
   },
   "release_status" : "stable",
   "resources" : {
      "repository" : {
         "type" : "git",
         "url" : "git://github.com/grantm/xml-simple.git",
         "web" : "https://github.com/grantm/xml-simple"
      }
   },
   "version" : "2.25",
   "x_serialization_backend" : "JSON::PP version 2.97001"
}
PK3N%[eW����Bperl5/x86_64-linux-thread-multi/.meta/XML-Simple-2.25/install.jsonnu��6�${"name":"XML::Simple","target":"XML::Simple","dist":"XML-Simple-2.25","version":2.25,"provides":{"XML::Simple":{"version":2.25,"file":"lib/XML/Simple.pm"}},"pathname":"G/GR/GRANTM/XML-Simple-2.25.tar.gz"}PK3N%[&�9~~Nperl5/x86_64-linux-thread-multi/.meta/CPAN-Meta-Requirements-2.143/MYMETA.jsonnu��6�${
   "abstract" : "a set of version requirements for a CPAN dist",
   "author" : [
      "David Golden <dagolden@cpan.org>",
      "Ricardo Signes <rjbs@cpan.org>"
   ],
   "dynamic_config" : 0,
   "generated_by" : "Dist::Zilla version 6.030, CPAN::Meta::Converter version 2.150010",
   "license" : [
      "perl_5"
   ],
   "meta-spec" : {
      "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
      "version" : 2
   },
   "name" : "CPAN-Meta-Requirements",
   "no_index" : {
      "directory" : [
         "corpus",
         "examples",
         "t",
         "xt"
      ],
      "package" : [
         "DB"
      ]
   },
   "prereqs" : {
      "build" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "configure" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "6.17"
         }
      },
      "develop" : {
         "requires" : {
            "Dist::Zilla" : "5",
            "Dist::Zilla::Plugin::Authority" : "0",
            "Dist::Zilla::Plugin::AutoPrereqs" : "0",
            "Dist::Zilla::Plugin::BumpVersionAfterRelease" : "0",
            "Dist::Zilla::Plugin::CPANFile" : "0",
            "Dist::Zilla::Plugin::CheckChangesHasContent" : "0",
            "Dist::Zilla::Plugin::CheckMetaResources" : "0",
            "Dist::Zilla::Plugin::CheckPrereqsIndexed" : "0",
            "Dist::Zilla::Plugin::ConfirmRelease" : "0",
            "Dist::Zilla::Plugin::CopyFilesFromBuild::Filtered" : "0",
            "Dist::Zilla::Plugin::ExecDir" : "0",
            "Dist::Zilla::Plugin::Git::Check" : "0",
            "Dist::Zilla::Plugin::Git::CheckFor::CorrectBranch" : "0",
            "Dist::Zilla::Plugin::Git::Commit" : "0",
            "Dist::Zilla::Plugin::Git::Contributors" : "0",
            "Dist::Zilla::Plugin::Git::GatherDir" : "0",
            "Dist::Zilla::Plugin::Git::Push" : "0",
            "Dist::Zilla::Plugin::Git::Tag" : "0",
            "Dist::Zilla::Plugin::GithubMeta" : "0",
            "Dist::Zilla::Plugin::InsertCopyright" : "0",
            "Dist::Zilla::Plugin::License" : "0",
            "Dist::Zilla::Plugin::MakeMaker" : "0",
            "Dist::Zilla::Plugin::MakeMaker::Highlander" : "0.003",
            "Dist::Zilla::Plugin::Manifest" : "0",
            "Dist::Zilla::Plugin::ManifestSkip" : "0",
            "Dist::Zilla::Plugin::MetaJSON" : "0",
            "Dist::Zilla::Plugin::MetaNoIndex" : "0",
            "Dist::Zilla::Plugin::MetaProvides::Package" : "0",
            "Dist::Zilla::Plugin::MetaTests" : "0",
            "Dist::Zilla::Plugin::MetaYAML" : "0",
            "Dist::Zilla::Plugin::MinimumPerl" : "0",
            "Dist::Zilla::Plugin::NextRelease" : "0",
            "Dist::Zilla::Plugin::OnlyCorePrereqs" : "0.014",
            "Dist::Zilla::Plugin::Pod2Readme" : "0",
            "Dist::Zilla::Plugin::PodCoverageTests" : "0",
            "Dist::Zilla::Plugin::PodSyntaxTests" : "0",
            "Dist::Zilla::Plugin::Prereqs" : "0",
            "Dist::Zilla::Plugin::Prereqs::AuthorDeps" : "0",
            "Dist::Zilla::Plugin::PromptIfStale" : "0",
            "Dist::Zilla::Plugin::PruneCruft" : "0",
            "Dist::Zilla::Plugin::RewriteVersion" : "0",
            "Dist::Zilla::Plugin::RunExtraTests" : "0",
            "Dist::Zilla::Plugin::ShareDir" : "0",
            "Dist::Zilla::Plugin::SurgicalPodWeaver" : "0",
            "Dist::Zilla::Plugin::Test::Compile" : "0",
            "Dist::Zilla::Plugin::Test::MinimumVersion" : "0",
            "Dist::Zilla::Plugin::Test::Perl::Critic" : "0",
            "Dist::Zilla::Plugin::Test::PodSpelling" : "0",
            "Dist::Zilla::Plugin::Test::Portability" : "0",
            "Dist::Zilla::Plugin::Test::ReportPrereqs" : "0",
            "Dist::Zilla::Plugin::Test::Version" : "0",
            "Dist::Zilla::Plugin::TestRelease" : "0",
            "Dist::Zilla::Plugin::UploadToCPAN" : "0",
            "File::Spec" : "0",
            "File::Temp" : "0",
            "IO::Handle" : "0",
            "IPC::Open3" : "0",
            "Pod::Coverage::TrustPod" : "0",
            "Pod::Weaver::PluginBundle::DAGOLDEN" : "0",
            "Pod::Wordlist" : "0",
            "Software::License::Perl_5" : "0",
            "Test::CPAN::Meta" : "0",
            "Test::MinimumVersion" : "0",
            "Test::More" : "0",
            "Test::Perl::Critic" : "0",
            "Test::Pod" : "1.41",
            "Test::Pod::Coverage" : "1.08",
            "Test::Portability::Files" : "0",
            "Test::Spelling" : "0.12",
            "Test::Version" : "1"
         }
      },
      "runtime" : {
         "requires" : {
            "B" : "0",
            "Carp" : "0",
            "perl" : "5.010000",
            "strict" : "0",
            "version" : "0.88",
            "warnings" : "0"
         }
      },
      "test" : {
         "recommends" : {
            "CPAN::Meta" : "2.120900"
         },
         "requires" : {
            "ExtUtils::MakeMaker" : "0",
            "File::Spec" : "0",
            "Test::More" : "0.88",
            "version" : "0.88"
         }
      }
   },
   "provides" : {
      "CPAN::Meta::Requirements" : {
         "file" : "lib/CPAN/Meta/Requirements.pm",
         "version" : "2.143"
      },
      "CPAN::Meta::Requirements::Range" : {
         "file" : "lib/CPAN/Meta/Requirements/Range.pm",
         "version" : "2.143"
      }
   },
   "release_status" : "stable",
   "resources" : {
      "bugtracker" : {
         "web" : "https://github.com/Perl-Toolchain-Gang/CPAN-Meta-Requirements/issues"
      },
      "homepage" : "https://github.com/Perl-Toolchain-Gang/CPAN-Meta-Requirements",
      "repository" : {
         "type" : "git",
         "url" : "https://github.com/Perl-Toolchain-Gang/CPAN-Meta-Requirements.git",
         "web" : "https://github.com/Perl-Toolchain-Gang/CPAN-Meta-Requirements"
      }
   },
   "version" : "2.143",
   "x_authority" : "cpan:DAGOLDEN",
   "x_contributors" : [
      "Ed J <mohawk2@users.noreply.github.com>",
      "Graham Knop <haarg@haarg.org>",
      "Karen Etheridge <ether@cpan.org>",
      "Leon Timmermans <fawaka@gmail.com>",
      "Paul Howarth <paul@city-fan.org>",
      "Ricardo Signes <rjbs@semiotic.systems>",
      "robario <webmaster@robario.com>",
      "Tatsuhiko Miyagawa <miyagawa@bulknews.net>",
      "Tatsuhiko Miyagawa <miyagawa@gmail.com>"
   ],
   "x_generated_by_perl" : "v5.37.10",
   "x_serialization_backend" : "JSON::PP version 2.97001",
   "x_spdx_expression" : "Artistic-1.0-Perl OR GPL-1.0-or-later"
}
PK3N%[.���Operl5/x86_64-linux-thread-multi/.meta/CPAN-Meta-Requirements-2.143/install.jsonnu��6�${"provides":{"CPAN::Meta::Requirements":{"file":"lib/CPAN/Meta/Requirements.pm","version":"2.143"},"CPAN::Meta::Requirements::Range":{"file":"lib/CPAN/Meta/Requirements/Range.pm","version":"2.143"}},"target":"CPAN::Meta::Requirements","pathname":"R/RJ/RJBS/CPAN-Meta-Requirements-2.143.tar.gz","name":"CPAN::Meta::Requirements","version":"2.143","dist":"CPAN-Meta-Requirements-2.143"}PK3N%[�V����Gperl5/x86_64-linux-thread-multi/.meta/Types-Serialiser-1.01/MYMETA.jsonnu��6�${
   "abstract" : "unknown",
   "author" : [
      "unknown"
   ],
   "dynamic_config" : 0,
   "generated_by" : "ExtUtils::MakeMaker version 7.34, CPAN::Meta::Converter version 2.150001, CPAN::Meta::Converter version 2.150010",
   "license" : [
      "unknown"
   ],
   "meta-spec" : {
      "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
      "version" : 2
   },
   "name" : "Types-Serialiser",
   "no_index" : {
      "directory" : [
         "t",
         "inc"
      ]
   },
   "prereqs" : {
      "build" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "configure" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "runtime" : {
         "requires" : {
            "common::sense" : "0"
         }
      }
   },
   "release_status" : "stable",
   "version" : "1.01",
   "x_serialization_backend" : "JSON::PP version 2.97001"
}
PK3N%[�R���Hperl5/x86_64-linux-thread-multi/.meta/Types-Serialiser-1.01/install.jsonnu��6�${"version":1.01,"dist":"Types-Serialiser-1.01","name":"Types::Serialiser","pathname":"M/ML/MLEHMANN/Types-Serialiser-1.01.tar.gz","target":"Types::Serialiser","provides":{"Types::Serialiser::Error":{"file":"Serialiser.pm","version":1.01},"JSON::PP::Boolean":{"version":1.01,"file":"Serialiser.pm"},"Types::Serialiser":{"version":1.01,"file":"Serialiser.pm"},"Types::Serialiser::BooleanBase":{"file":"Serialiser.pm","version":1.01}}}PK3N%[f�/qq?perl5/x86_64-linux-thread-multi/.meta/Net-HTTP-6.23/MYMETA.jsonnu��6�${
   "abstract" : "Low-level HTTP connection (client)",
   "author" : [
      "Gisle Aas <gisle@activestate.com>"
   ],
   "dynamic_config" : 0,
   "generated_by" : "Dist::Zilla version 6.030, CPAN::Meta::Converter version 2.150010",
   "license" : [
      "perl_5"
   ],
   "meta-spec" : {
      "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
      "version" : 2
   },
   "name" : "Net-HTTP",
   "no_index" : {
      "directory" : [
         "examples",
         "t",
         "xt"
      ]
   },
   "prereqs" : {
      "configure" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         },
         "suggests" : {
            "JSON::PP" : "2.27300"
         }
      },
      "develop" : {
         "requires" : {
            "Pod::Coverage::TrustPod" : "0",
            "Test::EOL" : "0",
            "Test::Mojibake" : "0",
            "Test::More" : "0.88",
            "Test::Pod" : "1.41",
            "Test::Pod::Coverage" : "1.08",
            "Test::Portability::Files" : "0",
            "Test::Version" : "1"
         }
      },
      "runtime" : {
         "requires" : {
            "Carp" : "0",
            "Compress::Raw::Zlib" : "0",
            "IO::Socket::INET" : "0",
            "IO::Uncompress::Gunzip" : "0",
            "URI" : "0",
            "base" : "0",
            "perl" : "5.006002",
            "strict" : "0",
            "warnings" : "0"
         },
         "suggests" : {
            "IO::Socket" : "0",
            "IO::Socket::INET6" : "0",
            "IO::Socket::IP" : "0",
            "IO::Socket::SSL" : "2.012",
            "Symbol" : "0"
         }
      },
      "test" : {
         "recommends" : {
            "CPAN::Meta" : "2.120900"
         },
         "requires" : {
            "Data::Dumper" : "0",
            "ExtUtils::MakeMaker" : "0",
            "File::Spec" : "0",
            "IO::Select" : "0",
            "Socket" : "0",
            "Test::More" : "0"
         }
      }
   },
   "release_status" : "stable",
   "resources" : {
      "bugtracker" : {
         "web" : "https://github.com/libwww-perl/Net-HTTP/issues"
      },
      "homepage" : "https://github.com/libwww-perl/Net-HTTP",
      "repository" : {
         "type" : "git",
         "url" : "https://github.com/libwww-perl/Net-HTTP.git",
         "web" : "https://github.com/libwww-perl/Net-HTTP"
      },
      "x_IRC" : "irc://irc.perl.org/#lwp",
      "x_MailingList" : "mailto:libwww@perl.org"
   },
   "version" : "6.23",
   "x_Dist_Zilla" : {
      "perl" : {
         "version" : "5.036000"
      },
      "plugins" : [
         {
            "class" : "Dist::Zilla::Plugin::MetaResources",
            "name" : "MetaResources",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::Prereqs",
            "config" : {
               "Dist::Zilla::Plugin::Prereqs" : {
                  "phase" : "runtime",
                  "type" : "requires"
               }
            },
            "name" : "Prereqs",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::PromptIfStale",
            "config" : {
               "Dist::Zilla::Plugin::PromptIfStale" : {
                  "check_all_plugins" : 0,
                  "check_all_prereqs" : 0,
                  "modules" : [
                     "Dist::Zilla::PluginBundle::Author::OALDERS"
                  ],
                  "phase" : "build",
                  "run_under_travis" : 0,
                  "skip" : []
               }
            },
            "name" : "@Author::OALDERS/stale modules, build",
            "version" : "0.058"
         },
         {
            "class" : "Dist::Zilla::Plugin::PromptIfStale",
            "config" : {
               "Dist::Zilla::Plugin::PromptIfStale" : {
                  "check_all_plugins" : 1,
                  "check_all_prereqs" : 1,
                  "modules" : [],
                  "phase" : "release",
                  "run_under_travis" : 0,
                  "skip" : []
               }
            },
            "name" : "@Author::OALDERS/stale modules, release",
            "version" : "0.058"
         },
         {
            "class" : "Dist::Zilla::Plugin::MakeMaker",
            "config" : {
               "Dist::Zilla::Role::TestRunner" : {
                  "default_jobs" : "8"
               }
            },
            "name" : "@Author::OALDERS/MakeMaker",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::CPANFile",
            "name" : "@Author::OALDERS/CPANFile",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::ContributorsFile",
            "name" : "@Author::OALDERS/ContributorsFile",
            "version" : "0.3.0"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaJSON",
            "name" : "@Author::OALDERS/MetaJSON",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaYAML",
            "name" : "@Author::OALDERS/MetaYAML",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::Manifest",
            "name" : "@Author::OALDERS/Manifest",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaNoIndex",
            "name" : "@Author::OALDERS/MetaNoIndex",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaConfig",
            "name" : "@Author::OALDERS/MetaConfig",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaResources",
            "name" : "@Author::OALDERS/MetaResources",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::License",
            "name" : "@Author::OALDERS/License",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::InstallGuide",
            "config" : {
               "Dist::Zilla::Role::ModuleMetadata" : {
                  "Module::Metadata" : "1.000037",
                  "version" : "0.006"
               }
            },
            "name" : "@Author::OALDERS/InstallGuide",
            "version" : "1.200014"
         },
         {
            "class" : "Dist::Zilla::Plugin::ExecDir",
            "name" : "@Author::OALDERS/ExecDir",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::MojibakeTests",
            "name" : "@Author::OALDERS/MojibakeTests",
            "version" : "0.8"
         },
         {
            "class" : "Dist::Zilla::Plugin::PodSyntaxTests",
            "name" : "@Author::OALDERS/PodSyntaxTests",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::EOL",
            "config" : {
               "Dist::Zilla::Plugin::Test::EOL" : {
                  "filename" : "xt/author/eol.t",
                  "finder" : [
                     ":ExecFiles",
                     ":InstallModules",
                     ":TestFiles"
                  ],
                  "trailing_whitespace" : 1
               }
            },
            "name" : "@Author::OALDERS/Test::EOL",
            "version" : "0.19"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::Portability",
            "config" : {
               "Dist::Zilla::Plugin::Test::Portability" : {
                  "options" : ""
               }
            },
            "name" : "@Author::OALDERS/Test::Portability",
            "version" : "2.001001"
         },
         {
            "class" : "Dist::Zilla::Plugin::TestRelease",
            "name" : "@Author::OALDERS/TestRelease",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::ReportPrereqs",
            "name" : "@Author::OALDERS/Test::ReportPrereqs",
            "version" : "0.029"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::Version",
            "name" : "@Author::OALDERS/Test::Version",
            "version" : "1.09"
         },
         {
            "class" : "Dist::Zilla::Plugin::RunExtraTests",
            "config" : {
               "Dist::Zilla::Role::TestRunner" : {
                  "default_jobs" : "8"
               }
            },
            "name" : "@Author::OALDERS/RunExtraTests",
            "version" : "0.029"
         },
         {
            "class" : "Dist::Zilla::Plugin::PodWeaver",
            "config" : {
               "Dist::Zilla::Plugin::PodWeaver" : {
                  "finder" : [
                     ":InstallModules",
                     ":PerlExecFiles"
                  ],
                  "plugins" : [
                     {
                        "class" : "Pod::Weaver::Plugin::EnsurePod5",
                        "name" : "@CorePrep/EnsurePod5",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Plugin::H1Nester",
                        "name" : "@CorePrep/H1Nester",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Plugin::SingleEncoding",
                        "name" : "@Default/SingleEncoding",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Name",
                        "name" : "@Default/Name",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Version",
                        "name" : "@Default/Version",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Region",
                        "name" : "@Default/prelude",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Generic",
                        "name" : "SYNOPSIS",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Generic",
                        "name" : "DESCRIPTION",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Generic",
                        "name" : "OVERVIEW",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Collect",
                        "name" : "ATTRIBUTES",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Collect",
                        "name" : "METHODS",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Collect",
                        "name" : "FUNCTIONS",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Leftovers",
                        "name" : "@Default/Leftovers",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Region",
                        "name" : "@Default/postlude",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Authors",
                        "name" : "@Default/Authors",
                        "version" : "4.019"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Legal",
                        "name" : "@Default/Legal",
                        "version" : "4.019"
                     }
                  ]
               }
            },
            "name" : "@Author::OALDERS/PodWeaver",
            "version" : "4.010"
         },
         {
            "class" : "Dist::Zilla::Plugin::PruneCruft",
            "name" : "@Author::OALDERS/PruneCruft",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::CopyFilesFromBuild",
            "name" : "@Author::OALDERS/CopyFilesFromBuild",
            "version" : "0.170880"
         },
         {
            "class" : "Dist::Zilla::Plugin::GithubMeta",
            "name" : "@Author::OALDERS/GithubMeta",
            "version" : "0.58"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::GatherDir",
            "config" : {
               "Dist::Zilla::Plugin::GatherDir" : {
                  "exclude_filename" : [
                     "Install",
                     "LICENSE",
                     "META.json",
                     "Makefile.PL",
                     "README.md",
                     "cpanfile"
                  ],
                  "exclude_match" : [],
                  "follow_symlinks" : 0,
                  "include_dotfiles" : 0,
                  "prefix" : "",
                  "prune_directory" : [],
                  "root" : "."
               },
               "Dist::Zilla::Plugin::Git::GatherDir" : {
                  "include_untracked" : 0
               }
            },
            "name" : "@Author::OALDERS/Git::GatherDir",
            "version" : "2.048"
         },
         {
            "class" : "Dist::Zilla::Plugin::CopyFilesFromRelease",
            "config" : {
               "Dist::Zilla::Plugin::CopyFilesFromRelease" : {
                  "filename" : [
                     "Install"
                  ],
                  "match" : []
               }
            },
            "name" : "@Author::OALDERS/CopyFilesFromRelease",
            "version" : "0.007"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::Check",
            "config" : {
               "Dist::Zilla::Plugin::Git::Check" : {
                  "untracked_files" : "die"
               },
               "Dist::Zilla::Role::Git::DirtyFiles" : {
                  "allow_dirty" : [
                     "Changes",
                     "Install",
                     "LICENSE",
                     "META.json",
                     "Makefile.PL",
                     "README.md",
                     "cpanfile",
                     "dist.ini"
                  ],
                  "allow_dirty_match" : [],
                  "changelog" : "Changes"
               },
               "Dist::Zilla::Role::Git::Repo" : {
                  "git_version" : "2.41.0",
                  "repo_root" : "."
               }
            },
            "name" : "@Author::OALDERS/Git::Check",
            "version" : "2.048"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::Contributors",
            "config" : {
               "Dist::Zilla::Plugin::Git::Contributors" : {
                  "git_version" : "2.41.0",
                  "include_authors" : 0,
                  "include_releaser" : 1,
                  "order_by" : "name",
                  "paths" : []
               }
            },
            "name" : "@Author::OALDERS/Git::Contributors",
            "version" : "0.036"
         },
         {
            "class" : "Dist::Zilla::Plugin::ReadmeAnyFromPod",
            "config" : {
               "Dist::Zilla::Role::FileWatcher" : {
                  "version" : "0.006"
               }
            },
            "name" : "@Author::OALDERS/ReadmeMdInBuild",
            "version" : "0.163250"
         },
         {
            "class" : "Dist::Zilla::Plugin::ShareDir",
            "name" : "@Author::OALDERS/ShareDir",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::CheckIssues",
            "name" : "@Author::OALDERS/CheckIssues",
            "version" : "0.011"
         },
         {
            "class" : "Dist::Zilla::Plugin::ConfirmRelease",
            "name" : "@Author::OALDERS/ConfirmRelease",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::UploadToCPAN",
            "name" : "@Author::OALDERS/UploadToCPAN",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::RewriteVersion::Transitional",
            "config" : {
               "Dist::Zilla::Plugin::RewriteVersion" : {
                  "add_tarball_name" : 0,
                  "finders" : [
                     ":ExecFiles",
                     ":InstallModules"
                  ],
                  "global" : 0,
                  "skip_version_provider" : 0
               },
               "Dist::Zilla::Plugin::RewriteVersion::Transitional" : {}
            },
            "name" : "@Author::OALDERS/@Git::VersionManager/RewriteVersion::Transitional",
            "version" : "0.009"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaProvides::Update",
            "name" : "@Author::OALDERS/@Git::VersionManager/MetaProvides::Update",
            "version" : "0.007"
         },
         {
            "class" : "Dist::Zilla::Plugin::CopyFilesFromRelease",
            "config" : {
               "Dist::Zilla::Plugin::CopyFilesFromRelease" : {
                  "filename" : [
                     "Changes"
                  ],
                  "match" : []
               }
            },
            "name" : "@Author::OALDERS/@Git::VersionManager/CopyFilesFromRelease",
            "version" : "0.007"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::Commit",
            "config" : {
               "Dist::Zilla::Plugin::Git::Commit" : {
                  "add_files_in" : [],
                  "commit_msg" : "v%V%n%n%c",
                  "signoff" : 0
               },
               "Dist::Zilla::Role::Git::DirtyFiles" : {
                  "allow_dirty" : [
                     "Changes",
                     "Install",
                     "LICENSE",
                     "META.json",
                     "Makefile.PL",
                     "README.md",
                     "cpanfile",
                     "dist.ini"
                  ],
                  "allow_dirty_match" : [],
                  "changelog" : "Changes"
               },
               "Dist::Zilla::Role::Git::Repo" : {
                  "git_version" : "2.41.0",
                  "repo_root" : "."
               },
               "Dist::Zilla::Role::Git::StringFormatter" : {
                  "time_zone" : "local"
               }
            },
            "name" : "@Author::OALDERS/@Git::VersionManager/release snapshot",
            "version" : "2.048"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::Tag",
            "config" : {
               "Dist::Zilla::Plugin::Git::Tag" : {
                  "branch" : null,
                  "changelog" : "Changes",
                  "signed" : 0,
                  "tag" : "v6.23",
                  "tag_format" : "v%V",
                  "tag_message" : "v%V"
               },
               "Dist::Zilla::Role::Git::Repo" : {
                  "git_version" : "2.41.0",
                  "repo_root" : "."
               },
               "Dist::Zilla::Role::Git::StringFormatter" : {
                  "time_zone" : "local"
               }
            },
            "name" : "@Author::OALDERS/@Git::VersionManager/Git::Tag",
            "version" : "2.048"
         },
         {
            "class" : "Dist::Zilla::Plugin::BumpVersionAfterRelease::Transitional",
            "config" : {
               "Dist::Zilla::Plugin::BumpVersionAfterRelease" : {
                  "finders" : [
                     ":ExecFiles",
                     ":InstallModules"
                  ],
                  "global" : 0,
                  "munge_makefile_pl" : 1
               },
               "Dist::Zilla::Plugin::BumpVersionAfterRelease::Transitional" : {}
            },
            "name" : "@Author::OALDERS/@Git::VersionManager/BumpVersionAfterRelease::Transitional",
            "version" : "0.009"
         },
         {
            "class" : "Dist::Zilla::Plugin::NextRelease",
            "name" : "@Author::OALDERS/@Git::VersionManager/NextRelease",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::Commit",
            "config" : {
               "Dist::Zilla::Plugin::Git::Commit" : {
                  "add_files_in" : [],
                  "commit_msg" : "increment $VERSION after %v release",
                  "signoff" : 0
               },
               "Dist::Zilla::Role::Git::DirtyFiles" : {
                  "allow_dirty" : [
                     "Build.PL",
                     "Changes",
                     "Makefile.PL"
                  ],
                  "allow_dirty_match" : [
                     "(?^:^lib/.*\\.pm$)"
                  ],
                  "changelog" : "Changes"
               },
               "Dist::Zilla::Role::Git::Repo" : {
                  "git_version" : "2.41.0",
                  "repo_root" : "."
               },
               "Dist::Zilla::Role::Git::StringFormatter" : {
                  "time_zone" : "local"
               }
            },
            "name" : "@Author::OALDERS/@Git::VersionManager/post-release commit",
            "version" : "2.048"
         },
         {
            "class" : "Dist::Zilla::Plugin::Git::Push",
            "config" : {
               "Dist::Zilla::Plugin::Git::Push" : {
                  "push_to" : [
                     "origin"
                  ],
                  "remotes_must_exist" : 1
               },
               "Dist::Zilla::Role::Git::Repo" : {
                  "git_version" : "2.41.0",
                  "repo_root" : "."
               }
            },
            "name" : "@Author::OALDERS/Git::Push",
            "version" : "2.048"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::Pod::Coverage::Configurable",
            "name" : "Test::Pod::Coverage::Configurable",
            "version" : "0.07"
         },
         {
            "class" : "Dist::Zilla::Plugin::AutoPrereqs",
            "name" : "AutoPrereqs",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::Prereqs",
            "config" : {
               "Dist::Zilla::Plugin::Prereqs" : {
                  "phase" : "runtime",
                  "type" : "suggests"
               }
            },
            "name" : "RuntimeSuggests",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::Prereqs::Soften",
            "config" : {
               "Dist::Zilla::Plugin::Prereqs::Soften" : {
                  "copy_to" : [],
                  "modules" : [
                     "IO::Socket",
                     "IO::Socket::INET6",
                     "IO::Socket::IP",
                     "IO::Socket::SSL",
                     "Symbol"
                  ],
                  "modules_from_features" : null,
                  "to_relationship" : "suggests"
               }
            },
            "name" : "Prereqs::Soften",
            "version" : "0.006003"
         },
         {
            "class" : "Dist::Zilla::Plugin::StaticInstall",
            "config" : {
               "Dist::Zilla::Plugin::StaticInstall" : {
                  "dry_run" : 0,
                  "mode" : "on"
               }
            },
            "name" : "StaticInstall",
            "version" : "0.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":InstallModules",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":IncModules",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":TestFiles",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":ExtraTestFiles",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":ExecFiles",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":PerlExecFiles",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":ShareFiles",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":MainModule",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":AllFiles",
            "version" : "6.030"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":NoFiles",
            "version" : "6.030"
         }
      ],
      "zilla" : {
         "class" : "Dist::Zilla::Dist::Builder",
         "config" : {
            "is_trial" : 0
         },
         "version" : "6.030"
      }
   },
   "x_contributors" : [
      "Adam Kennedy <adamk@cpan.org>",
      "Adam Sjogren <asjo@koldfront.dk>",
      "Alexey Tourbin <at@altlinux.ru>",
      "Alex Kapranoff <ka@nadoby.ru>",
      "amire80 <amir.aharoni@gmail.com>",
      "Andreas J. Koenig <andreas.koenig@anima.de>",
      "Andy Grundman <andyg@activestate.com>",
      "Bill Mann <wfmann@alum.mit.edu>",
      "Bron Gondwana <brong@fastmail.fm>",
      "Chase Whitener <cwhitener@gmail.com>",
      "Dagfinn Ilmari Mannsåker <ilmari@ilmari.org>",
      "Daniel Hedlund <Daniel.Hedlund@eprize.com>",
      "Dave Rolsky <autarch@urth.org>",
      "David E. Wheeler <david@justatheory.com>",
      "DAVIDRW <davidrw@cpan.org>",
      "David Steinbrunner <dsteinbrunner@pobox.com>",
      "Eric Wong <normalperson@yhbt.net>",
      "Father Chrysostomos <sprout@cpan.org>",
      "FWILES <FWILES@cpan.org>",
      "Gavin Peters <gpeters@deepsky.com>",
      "Gisle Aas <aas@oslonett.no>",
      "Gisle Aas <gisle.aas@it.uib.no>",
      "Gisle Aas <gisle@aas.no>",
      "Gisle Aas <gisle@baux-2.lan>",
      "Graeme Thompson <Graeme.Thompson@mobilecohesion.com>",
      "Hans-H. Froehlich <hfroehlich@co-de-co.de>",
      "Ian Kilgore <iank@cpan.org>",
      "Jacob J <waif@chaos2.org>",
      "James Raspass <jraspass@gmail.com>",
      "Jason A Fesler <jfesler@badamount-lm.corp.yahoo.com>",
      "Jay Hannah <jay.hannah@iinteractive.com>",
      "Jean-Louis Martineau <martineau@zmanda.com>",
      "jefflee <shaohua@gmail.com>",
      "Jesse Luehrs <doy@tozt.net>",
      "john9art <john9art@yahoo.com>",
      "Karen Etheridge <ether@cpan.org>",
      "Kent Fredric <kentfredric@gmail.com>",
      "Lasse Makholm <lasse@unity3d.com>",
      "Marinos Yannikos <mjy@geizhals.at>",
      "Mark Overmeer <MARKOV@cpan.org>",
      "Mark Stosberg <mark@stosberg.com>",
      "Mark Stosberg <MARKSTOS@cpan.org>",
      "Mark Stosberg <mark@summersault.com>",
      "Mike Schilli <mschilli@yahoo-inc.com>",
      "Mohammad S Anwar <mohammad.anwar@yahoo.com>",
      "mschilli <github@perlmeister.com>",
      "murphy <murphy@genome.chop.edu>",
      "Olaf Alders <olaf@wundersolutions.com>",
      "Ondrej Hanak <ondrej.hanak@ubs.com>",
      "Paul Cochrane <paul.cochrane@posteo.de>",
      "Peter Rabbitson <ribasushi@cpan.org>",
      "phrstbrn <phrstbrn@gmail.com>",
      "Robert Stone <talby@trap.mtview.ca.us>",
      "Rolf Grossmann <rg@progtech.net>",
      "ruff <ruff@ukrpost.net>",
      "sasao <sasao@yugen.org>",
      "Sean M. Burke <sburke@cpan.org>",
      "Shoichi Kaji <skaji@cpan.org>",
      "Slaven Rezic <slaven@rezic.de>",
      "Slaven Rezic <srezic@iconmobile.com>",
      "Spiros Denaxas <s.denaxas@gmail.com>",
      "Steffen Ullrich <Steffen_Ullrich@genua.de>",
      "Steve Hay <SteveHay@planit.com>",
      "Todd Lipcon <todd@amiestreet.com>",
      "Tom Hukins <tom@eborcom.com>",
      "Tom Wyant <wyant@cpan.org>",
      "Tony Finch <dot@dotat.at>",
      "Toru Yamaguchi <zigorou@cpan.org>",
      "uid39246 <uid39246>",
      "Ville Skyttä <ville.skytta@iki.fi>",
      "Yuri Karaban <tech@askold.net>",
      "Zefram <zefram@fysh.org>"
   ],
   "x_generated_by_perl" : "v5.36.0",
   "x_serialization_backend" : "JSON::PP version 2.97001",
   "x_spdx_expression" : "Artistic-1.0-Perl OR GPL-1.0-or-later",
   "x_static_install" : 1
}
PK3N%[���}}@perl5/x86_64-linux-thread-multi/.meta/Net-HTTP-6.23/install.jsonnu��6�${"pathname":"O/OA/OALDERS/Net-HTTP-6.23.tar.gz","provides":{"Net::HTTP::NB":{"version":6.23,"file":"lib/Net/HTTP/NB.pm"},"Net::HTTP":{"version":6.23,"file":"lib/Net/HTTP.pm"},"Net::HTTPS":{"version":6.23,"file":"lib/Net/HTTPS.pm"},"Net::HTTP::Methods":{"file":"lib/Net/HTTP/Methods.pm","version":6.23}},"version":6.23,"dist":"Net-HTTP-6.23","target":"Net::HTTP","name":"Net::HTTP"}PK3N%[���GCperl5/x86_64-linux-thread-multi/.meta/XML-SAX-Base-1.09/MYMETA.jsonnu��6�${
   "abstract" : "Base class for SAX Drivers and Filters",
   "author" : [
      "Grant McLean <grantm@cpan.org>"
   ],
   "dynamic_config" : 0,
   "generated_by" : "Dist::Zilla version 5.022, CPAN::Meta::Converter version 2.142690, CPAN::Meta::Converter version 2.150010",
   "license" : [
      "perl_5"
   ],
   "meta-spec" : {
      "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
      "version" : 2
   },
   "name" : "XML-SAX-Base",
   "prereqs" : {
      "build" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "configure" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "develop" : {
         "requires" : {
            "Test::Pod" : "1.41"
         }
      },
      "runtime" : {
         "requires" : {
            "perl" : "5.008"
         }
      },
      "test" : {
         "requires" : {
            "Test::More" : "0.88"
         }
      }
   },
   "release_status" : "stable",
   "resources" : {
      "repository" : {
         "type" : "git",
         "url" : "git://github.com/grantm/XML-SAX-Base.git",
         "web" : "https://github.com/grantm/XML-SAX-Base"
      }
   },
   "version" : "1.09",
   "x_serialization_backend" : "JSON::PP version 2.97001"
}
PK3N%[����nnDperl5/x86_64-linux-thread-multi/.meta/XML-SAX-Base-1.09/install.jsonnu��6�${"dist":"XML-SAX-Base-1.09","version":1.09,"provides":{"XML::SAX::Exception":{"file":"lib/XML/SAX/Exception.pm","version":1.09},"XML::SAX::Base::NoHandler":{"file":"lib/XML/SAX/Base.pm","version":1.09},"XML::SAX::Base":{"version":1.09,"file":"lib/XML/SAX/Base.pm"}},"pathname":"G/GR/GRANTM/XML-SAX-Base-1.09.tar.gz","name":"XML::SAX::Base","target":"XML::SAX::Base"}PK3N%[�Zw�bbAperl5/x86_64-linux-thread-multi/.meta/Path-Tiny-0.148/MYMETA.jsonnu��6�${
   "abstract" : "File path utility",
   "author" : [
      "David Golden <dagolden@cpan.org>"
   ],
   "dynamic_config" : 0,
   "generated_by" : "Dist::Zilla version 6.032, CPAN::Meta::Converter version 2.150010",
   "license" : [
      "apache_2_0"
   ],
   "meta-spec" : {
      "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
      "version" : 2
   },
   "name" : "Path-Tiny",
   "no_index" : {
      "directory" : [
         "corpus",
         "examples",
         "t",
         "xt"
      ],
      "package" : [
         "DB",
         "flock"
      ]
   },
   "prereqs" : {
      "build" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "configure" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "6.17"
         },
         "suggests" : {
            "JSON::PP" : "2.27300"
         }
      },
      "develop" : {
         "requires" : {
            "Dist::Zilla" : "5",
            "Dist::Zilla::Plugin::MinimumPerl" : "0",
            "Dist::Zilla::Plugin::OnlyCorePrereqs" : "0",
            "Dist::Zilla::Plugin::Prereqs" : "0",
            "Dist::Zilla::Plugin::ReleaseStatus::FromVersion" : "0",
            "Dist::Zilla::Plugin::RemovePrereqs" : "0",
            "Dist::Zilla::PluginBundle::DAGOLDEN" : "0.072",
            "File::Spec" : "0",
            "File::Temp" : "0",
            "IO::Handle" : "0",
            "IPC::Open3" : "0",
            "Pod::Coverage::TrustPod" : "0",
            "Pod::Wordlist" : "0",
            "Software::License::Apache_2_0" : "0",
            "Test::CPAN::Meta" : "0",
            "Test::MinimumVersion" : "0",
            "Test::More" : "0",
            "Test::Perl::Critic" : "0",
            "Test::Pod" : "1.41",
            "Test::Pod::Coverage" : "1.08",
            "Test::Portability::Files" : "0",
            "Test::Spelling" : "0.17",
            "Test::Version" : "1"
         }
      },
      "runtime" : {
         "recommends" : {
            "Unicode::UTF8" : "0.58"
         },
         "requires" : {
            "Carp" : "0",
            "Cwd" : "0",
            "Digest" : "1.03",
            "Digest::SHA" : "5.45",
            "Encode" : "0",
            "Exporter" : "5.57",
            "Fcntl" : "0",
            "File::Compare" : "0",
            "File::Copy" : "0",
            "File::Glob" : "0",
            "File::Path" : "2.07",
            "File::Spec" : "0.86",
            "File::Temp" : "0.19",
            "File::stat" : "0",
            "constant" : "0",
            "overload" : "0",
            "perl" : "5.008001",
            "strict" : "0",
            "warnings" : "0",
            "warnings::register" : "0"
         }
      },
      "test" : {
         "recommends" : {
            "CPAN::Meta" : "2.120900",
            "Test::FailWarnings" : "0",
            "Test::MockRandom" : "0"
         },
         "requires" : {
            "Digest::MD5" : "0",
            "ExtUtils::MakeMaker" : "0",
            "File::Basename" : "0",
            "File::Spec" : "0.86",
            "File::Spec::Functions" : "0",
            "File::Spec::Unix" : "0",
            "File::Temp" : "0.19",
            "Test::More" : "0.96",
            "lib" : "0",
            "open" : "0"
         }
      }
   },
   "provides" : {
      "Path::Tiny" : {
         "file" : "lib/Path/Tiny.pm",
         "version" : "0.148"
      },
      "Path::Tiny::Error" : {
         "file" : "lib/Path/Tiny.pm",
         "version" : "0.148"
      }
   },
   "release_status" : "stable",
   "resources" : {
      "bugtracker" : {
         "web" : "https://github.com/dagolden/Path-Tiny/issues"
      },
      "homepage" : "https://github.com/dagolden/Path-Tiny",
      "repository" : {
         "type" : "git",
         "url" : "https://github.com/dagolden/Path-Tiny.git",
         "web" : "https://github.com/dagolden/Path-Tiny"
      }
   },
   "version" : "0.148",
   "x_authority" : "cpan:DAGOLDEN",
   "x_contributors" : [
      "Alex Efros <powerman@powerman.name>",
      "Aristotle Pagaltzis <pagaltzis@gmx.de>",
      "Chris Williams <bingos@cpan.org>",
      "Dan Book <grinnz@grinnz.com>",
      "Dave Rolsky <autarch@urth.org>",
      "David Steinbrunner <dsteinbrunner@pobox.com>",
      "Doug Bell <madcityzen@gmail.com>",
      "Elvin Aslanov <rwp.primary@gmail.com>",
      "Flavio Poletti <flavio@polettix.it>",
      "Gabor Szabo <szabgab@cpan.org>",
      "Gabriel Andrade <gabiruh@gmail.com>",
      "George Hartzell <hartzell@cpan.org>",
      "Geraud Continsouzas <geraud@scsi.nc>",
      "Goro Fuji <gfuji@cpan.org>",
      "Graham Knop <haarg@haarg.org>",
      "Graham Ollis <plicease@cpan.org>",
      "Ian Sillitoe <ian@sillit.com>",
      "James Hunt <james@niftylogic.com>",
      "John Karr <brainbuz@brainbuz.org>",
      "Karen Etheridge <ether@cpan.org>",
      "Mark Ellis <mark.ellis@cartridgesave.co.uk>",
      "Martin H. Sluka <fany@cpan.org>",
      "Martin Kjeldsen <mk@bluepipe.dk>",
      "Martin Sluka <martin@sluka.de>",
      "Mary Ehlers <regina.verb.ae@gmail.com>",
      "Michael G. Schwern <mschwern@cpan.org>",
      "NATARAJ (Nikolay Shaplov) <dhyan@nataraj.su>",
      "Nicolas R <nicolas@atoomic.org>",
      "Nicolas Rochelemagne <rochelemagne@cpanel.net>",
      "Nigel Gregoire <nigelgregoire@gmail.com>",
      "Philippe Bruhat (BooK) <book@cpan.org>",
      "regina-verbae <regina-verbae@users.noreply.github.com>",
      "Ricardo Signes <rjbs@semiotic.systems>",
      "Roy Ivy III <rivy@cpan.org>",
      "Shlomi Fish <shlomif@shlomifish.org>",
      "Smylers <Smylers@stripey.com>",
      "Tatsuhiko Miyagawa <miyagawa@bulknews.net>",
      "Toby Inkster <tobyink@cpan.org>",
      "Yanick Champoux <yanick@babyl.dyndns.org>",
      "yoshikazusawa <883514+yoshikazusawa@users.noreply.github.com>",
      "김도형 - Keedi Kim <keedi@cpan.org>"
   ],
   "x_generated_by_perl" : "v5.40.0",
   "x_serialization_backend" : "JSON::PP version 2.97001",
   "x_spdx_expression" : "Apache-2.0"
}
PK4N%[q;gBperl5/x86_64-linux-thread-multi/.meta/Path-Tiny-0.148/install.jsonnu��6�${"target":"Path::Tiny","pathname":"D/DA/DAGOLDEN/Path-Tiny-0.148.tar.gz","version":"0.148","name":"Path::Tiny","dist":"Path-Tiny-0.148","provides":{"Path::Tiny":{"version":"0.148","file":"lib/Path/Tiny.pm"},"Path::Tiny::Error":{"version":"0.148","file":"lib/Path/Tiny.pm"}}}PK4N%[�?c��t�tperl5/Capture/Tiny.pmnu��6�$use 5.006;
use strict;
use warnings;
package Capture::Tiny;
# ABSTRACT: Capture STDOUT and STDERR from Perl, XS or external programs
our $VERSION = '0.50';
use Carp ();
use Exporter ();
use IO::Handle ();
use File::Spec ();
use File::Temp qw/tempfile tmpnam/;
use Scalar::Util qw/reftype blessed/;
# Get PerlIO or fake it
BEGIN {
  local $@;
  eval { require PerlIO; PerlIO->can('get_layers') }
    or *PerlIO::get_layers = sub { return () };
}

#--------------------------------------------------------------------------#
# create API subroutines and export them
# [do STDOUT flag, do STDERR flag, do merge flag, do tee flag]
#--------------------------------------------------------------------------#

my %api = (
  capture         => [1,1,0,0],
  capture_stdout  => [1,0,0,0],
  capture_stderr  => [0,1,0,0],
  capture_merged  => [1,1,1,0],
  tee             => [1,1,0,1],
  tee_stdout      => [1,0,0,1],
  tee_stderr      => [0,1,0,1],
  tee_merged      => [1,1,1,1],
);

for my $sub ( keys %api ) {
  my $args = join q{, }, @{$api{$sub}};
  eval "sub $sub(&;@) {unshift \@_, $args; goto \\&_capture_tee;}"; ## no critic
}

our @ISA = qw/Exporter/;
our @EXPORT_OK = keys %api;
our %EXPORT_TAGS = ( 'all' => \@EXPORT_OK );

#--------------------------------------------------------------------------#
# constants and fixtures
#--------------------------------------------------------------------------#

my $IS_WIN32 = $^O eq 'MSWin32';

##our $DEBUG = $ENV{PERL_CAPTURE_TINY_DEBUG};
##
##my $DEBUGFH;
##open $DEBUGFH, "> DEBUG" if $DEBUG;
##
##*_debug = $DEBUG ? sub(@) { print {$DEBUGFH} @_ } : sub(){0};

our $TIMEOUT = 30;

#--------------------------------------------------------------------------#
# command to tee output -- the argument is a filename that must
# be opened to signal that the process is ready to receive input.
# This is annoying, but seems to be the best that can be done
# as a simple, portable IPC technique
#--------------------------------------------------------------------------#
my @cmd = ($^X, '-C0', '-e', <<'HERE');
use Fcntl;
$SIG{HUP}=sub{exit};
if ( my $fn=shift ) {
    sysopen(my $fh, qq{$fn}, O_WRONLY|O_CREAT|O_EXCL) or die $!;
    print {$fh} $$;
    close $fh;
}
my $buf; while (sysread(STDIN, $buf, 2048)) {
    syswrite(STDOUT, $buf); syswrite(STDERR, $buf);
}
HERE

#--------------------------------------------------------------------------#
# filehandle manipulation
#--------------------------------------------------------------------------#

sub _relayer {
  my ($fh, $apply_layers) = @_;
  # _debug("# requested layers (@{$layers}) for @{[fileno $fh]}\n");

  # eliminate pseudo-layers
  binmode( $fh, ":raw" );
  # strip off real layers until only :unix is left
  while ( 1 < ( my $layers =()= PerlIO::get_layers( $fh, output => 1 ) ) ) {
      binmode( $fh, ":pop" );
  }
  # apply other layers
  my @to_apply = @$apply_layers;
  shift @to_apply; # eliminate initial :unix
  # _debug("# applying layers  (unix @to_apply) to @{[fileno $fh]}\n");
  binmode($fh, ":" . join(":",@to_apply));
}

sub _name {
  my $glob = shift;
  no strict 'refs'; ## no critic
  return *{$glob}{NAME};
}

sub _open {
  open $_[0], $_[1] or Carp::confess "Error from open(" . join(q{, }, @_) . "): $!";
  # _debug( "# open " . join( ", " , map { defined $_ ? _name($_) : 'undef' } @_ ) . " as " . fileno( $_[0] ) . "\n" );
}

sub _close {
  # _debug( "# closing " . ( defined $_[0] ? _name($_[0]) : 'undef' )  . " on " . fileno( $_[0] ) . "\n" );
  close $_[0] or Carp::confess "Error from close(" . join(q{, }, @_) . "): $!";
}

my %dup; # cache this so STDIN stays fd0
my %proxy_count;
sub _proxy_std {
  my %proxies;
  if ( ! defined fileno STDIN ) {
    $proxy_count{stdin}++;
    if (defined $dup{stdin}) {
      _open \*STDIN, "<&=" . fileno($dup{stdin});
      # _debug( "# restored proxy STDIN as " . (defined fileno STDIN ? fileno STDIN : 'undef' ) . "\n" );
    }
    else {
      _open \*STDIN, "<" . File::Spec->devnull;
      # _debug( "# proxied STDIN as " . (defined fileno STDIN ? fileno STDIN : 'undef' ) . "\n" );
      _open $dup{stdin} = IO::Handle->new, "<&=STDIN";
    }
    $proxies{stdin} = \*STDIN;
    binmode(STDIN, ':utf8') if $] >= 5.008; ## no critic
  }
  if ( ! defined fileno STDOUT ) {
    $proxy_count{stdout}++;
    if (defined $dup{stdout}) {
      _open \*STDOUT, ">&=" . fileno($dup{stdout});
      # _debug( "# restored proxy STDOUT as " . (defined fileno STDOUT ? fileno STDOUT : 'undef' ) . "\n" );
    }
    else {
      _open \*STDOUT, ">" . File::Spec->devnull;
       # _debug( "# proxied STDOUT as " . (defined fileno STDOUT ? fileno STDOUT : 'undef' ) . "\n" );
      _open $dup{stdout} = IO::Handle->new, ">&=STDOUT";
    }
    $proxies{stdout} = \*STDOUT;
    binmode(STDOUT, ':utf8') if $] >= 5.008; ## no critic
  }
  if ( ! defined fileno STDERR ) {
    $proxy_count{stderr}++;
    if (defined $dup{stderr}) {
      _open \*STDERR, ">&=" . fileno($dup{stderr});
       # _debug( "# restored proxy STDERR as " . (defined fileno STDERR ? fileno STDERR : 'undef' ) . "\n" );
    }
    else {
      _open \*STDERR, ">" . File::Spec->devnull;
       # _debug( "# proxied STDERR as " . (defined fileno STDERR ? fileno STDERR : 'undef' ) . "\n" );
      _open $dup{stderr} = IO::Handle->new, ">&=STDERR";
    }
    $proxies{stderr} = \*STDERR;
    binmode(STDERR, ':utf8') if $] >= 5.008; ## no critic
  }
  return %proxies;
}

sub _unproxy {
  my (%proxies) = @_;
  # _debug( "# unproxying: " . join(" ", keys %proxies) . "\n" );
  for my $p ( keys %proxies ) {
    $proxy_count{$p}--;
    # _debug( "# unproxied " . uc($p) . " ($proxy_count{$p} left)\n" );
    if ( ! $proxy_count{$p} ) {
      _close $proxies{$p};
      _close $dup{$p} unless $] < 5.008; # 5.6 will have already closed this as dup
      delete $dup{$p};
    }
  }
}

sub _copy_std {
  my %handles;
  for my $h ( qw/stdout stderr stdin/ ) {
    next if $h eq 'stdin' && ! $IS_WIN32; # WIN32 hangs on tee without STDIN copied
    my $redir = $h eq 'stdin' ? "<&" : ">&";
    _open $handles{$h} = IO::Handle->new(), $redir . uc($h); # ">&STDOUT" or "<&STDIN"
  }
  return \%handles;
}

# In some cases we open all (prior to forking) and in others we only open
# the output handles (setting up redirection)
sub _open_std {
  my ($handles) = @_;
  _open \*STDIN, "<&" . fileno $handles->{stdin} if defined $handles->{stdin};
  _open \*STDOUT, ">&" . fileno $handles->{stdout} if defined $handles->{stdout};
  _open \*STDERR, ">&" . fileno $handles->{stderr} if defined $handles->{stderr};
}

#--------------------------------------------------------------------------#
# private subs
#--------------------------------------------------------------------------#

sub _start_tee {
  my ($which, $stash) = @_; # $which is "stdout" or "stderr"
  # setup pipes
  $stash->{$_}{$which} = IO::Handle->new for qw/tee reader/;
  pipe $stash->{reader}{$which}, $stash->{tee}{$which};
  # _debug( "# pipe for $which\: " .  _name($stash->{tee}{$which}) . " " . fileno( $stash->{tee}{$which} ) . " => " . _name($stash->{reader}{$which}) . " " . fileno( $stash->{reader}{$which}) . "\n" );
  select((select($stash->{tee}{$which}), $|=1)[0]); # autoflush
  # setup desired redirection for parent and child
  $stash->{new}{$which} = $stash->{tee}{$which};
  $stash->{child}{$which} = {
    stdin   => $stash->{reader}{$which},
    stdout  => $stash->{old}{$which},
    stderr  => $stash->{capture}{$which},
  };
  # flag file is used to signal the child is ready
  $stash->{flag_files}{$which} = scalar( tmpnam() ) . $$;
  # execute @cmd as a separate process
  if ( $IS_WIN32 ) {
    my $old_eval_err=$@;
    undef $@;

    eval "use Win32API::File qw/GetOsFHandle SetHandleInformation fileLastError HANDLE_FLAG_INHERIT INVALID_HANDLE_VALUE/ ";
    # _debug( "# Win32API::File loaded\n") unless $@;
    my $os_fhandle = GetOsFHandle( $stash->{tee}{$which} );
    # _debug( "# Couldn't get OS handle: " . fileLastError() . "\n") if ! defined $os_fhandle || $os_fhandle == INVALID_HANDLE_VALUE();
    my $result = SetHandleInformation( $os_fhandle, HANDLE_FLAG_INHERIT(), 0);
    # _debug( $result ? "# set no-inherit flag on $which tee\n" : ("# can't disable tee handle flag inherit: " . fileLastError() . "\n"));
    _open_std( $stash->{child}{$which} );
    $stash->{pid}{$which} = system(1, @cmd, $stash->{flag_files}{$which});
    # not restoring std here as it all gets redirected again shortly anyway
    $@=$old_eval_err;
  }
  else { # use fork
    _fork_exec( $which, $stash );
  }
}

sub _fork_exec {
  my ($which, $stash) = @_; # $which is "stdout" or "stderr"
  my $pid = fork;
  if ( not defined $pid ) {
    Carp::confess "Couldn't fork(): $!";
  }
  elsif ($pid == 0) { # child
    # _debug( "# in child process ...\n" );
    untie *STDIN; untie *STDOUT; untie *STDERR;
    _close $stash->{tee}{$which};
    # _debug( "# redirecting handles in child ...\n" );
    _open_std( $stash->{child}{$which} );
    # _debug( "# calling exec on command ...\n" );
    exec @cmd, $stash->{flag_files}{$which};
  }
  $stash->{pid}{$which} = $pid
}

my $have_usleep = eval "use Time::HiRes 'usleep'; 1";
sub _files_exist {
  return 1 if @_ == grep { -f } @_;
  Time::HiRes::usleep(1000) if $have_usleep;
  return 0;
}

sub _wait_for_tees {
  my ($stash) = @_;
  my $start = time;
  my @files = values %{$stash->{flag_files}};
  my $timeout = defined $ENV{PERL_CAPTURE_TINY_TIMEOUT}
              ? $ENV{PERL_CAPTURE_TINY_TIMEOUT} : $TIMEOUT;
  1 until _files_exist(@files) || ($timeout && (time - $start > $timeout));
  Carp::confess "Timed out waiting for subprocesses to start" if ! _files_exist(@files);
  unlink $_ for @files;
}

sub _kill_tees {
  my ($stash) = @_;
  if ( $IS_WIN32 ) {
    # _debug( "# closing handles\n");
    close($_) for values %{ $stash->{tee} };
    # _debug( "# waiting for subprocesses to finish\n");
    my $start = time;
    1 until wait == -1 || (time - $start > 30);
  }
  else {
    _close $_ for values %{ $stash->{tee} };
    waitpid $_, 0 for values %{ $stash->{pid} };
  }
}

sub _slurp {
  my ($name, $stash) = @_;
  my ($fh, $pos) = map { $stash->{$_}{$name} } qw/capture pos/;
  # _debug( "# slurping captured $name from " . fileno($fh) . " at pos $pos with layers: @{[PerlIO::get_layers($fh)]}\n");
  seek( $fh, $pos, 0 ) or die "Couldn't seek on capture handle for $name\n";
  my $text = do { local $/; scalar readline $fh };
  return defined($text) ? $text : "";
}

#--------------------------------------------------------------------------#
# _capture_tee() -- generic main sub for capturing or teeing
#--------------------------------------------------------------------------#

sub _capture_tee {
  # _debug( "# starting _capture_tee with (@_)...\n" );
  my ($do_stdout, $do_stderr, $do_merge, $do_tee, $code, @opts) = @_;
  my %do = ($do_stdout ? (stdout => 1) : (),  $do_stderr ? (stderr => 1) : ());
  Carp::confess("Custom capture options must be given as key/value pairs\n")
    unless @opts % 2 == 0;
  my $stash = { capture => { @opts } };
  for ( keys %{$stash->{capture}} ) {
    my $fh = $stash->{capture}{$_};
    Carp::confess "Custom handle for $_ must be seekable\n"
      unless ref($fh) eq 'GLOB' || (blessed($fh) && $fh->isa("IO::Seekable"));
  }
  # save existing filehandles and setup captures
  local *CT_ORIG_STDIN  = *STDIN ;
  local *CT_ORIG_STDOUT = *STDOUT;
  local *CT_ORIG_STDERR = *STDERR;
  # find initial layers
  my %layers = (
    stdin   => [PerlIO::get_layers(\*STDIN) ],
    stdout  => [PerlIO::get_layers(\*STDOUT, output => 1)],
    stderr  => [PerlIO::get_layers(\*STDERR, output => 1)],
  );
  # _debug( "# existing layers for $_\: @{$layers{$_}}\n" ) for qw/stdin stdout stderr/;
  # get layers from underlying glob of tied filehandles if we can
  # (this only works for things that work like Tie::StdHandle)
  $layers{stdout} = [PerlIO::get_layers(tied *STDOUT)]
    if tied(*STDOUT) && (reftype tied *STDOUT eq 'GLOB');
  $layers{stderr} = [PerlIO::get_layers(tied *STDERR)]
    if tied(*STDERR) && (reftype tied *STDERR eq 'GLOB');
  # _debug( "# tied object corrected layers for $_\: @{$layers{$_}}\n" ) for qw/stdin stdout stderr/;
  # bypass scalar filehandles and tied handles
  # localize scalar STDIN to get a proxy to pick up FD0, then restore later to CT_ORIG_STDIN
  my %localize;
  $localize{stdin}++,  local(*STDIN)
    if grep { $_ eq 'scalar' } @{$layers{stdin}};
  $localize{stdout}++, local(*STDOUT)
    if $do_stdout && grep { $_ eq 'scalar' } @{$layers{stdout}};
  $localize{stderr}++, local(*STDERR)
    if ($do_stderr || $do_merge) && grep { $_ eq 'scalar' } @{$layers{stderr}};
  $localize{stdin}++, local(*STDIN), _open( \*STDIN, "<&=0")
    if tied *STDIN && $] >= 5.008;
  $localize{stdout}++, local(*STDOUT), _open( \*STDOUT, ">&=1")
    if $do_stdout && tied *STDOUT && $] >= 5.008;
  $localize{stderr}++, local(*STDERR), _open( \*STDERR, ">&=2")
    if ($do_stderr || $do_merge) && tied *STDERR && $] >= 5.008;
  # _debug( "# localized $_\n" ) for keys %localize;
  # proxy any closed/localized handles so we don't use fds 0, 1 or 2
  my %proxy_std = _proxy_std();
  # _debug( "# proxy std: @{ [%proxy_std] }\n" );
  # update layers after any proxying
  $layers{stdout} = [PerlIO::get_layers(\*STDOUT, output => 1)] if $proxy_std{stdout};
  $layers{stderr} = [PerlIO::get_layers(\*STDERR, output => 1)] if $proxy_std{stderr};
  # _debug( "# post-proxy layers for $_\: @{$layers{$_}}\n" ) for qw/stdin stdout stderr/;
  # store old handles and setup handles for capture
  $stash->{old} = _copy_std();
  $stash->{new} = { %{$stash->{old}} }; # default to originals
  for ( keys %do ) {
    $stash->{new}{$_} = ($stash->{capture}{$_} ||= File::Temp->new);
    seek( $stash->{capture}{$_}, 0, 2 ) or die "Could not seek on capture handle for $_\n";
    $stash->{pos}{$_} = tell $stash->{capture}{$_};
    # _debug("# will capture $_ on " . fileno($stash->{capture}{$_})."\n" );
    _start_tee( $_ => $stash ) if $do_tee; # tees may change $stash->{new}
  }
  _wait_for_tees( $stash ) if $do_tee;
  # finalize redirection
  $stash->{new}{stderr} = $stash->{new}{stdout} if $do_merge;
  # _debug( "# redirecting in parent ...\n" );
  _open_std( $stash->{new} );
  # execute user provided code
  my ($exit_code, $inner_error, $outer_error, $orig_pid, @result);
  {
    $orig_pid = $$;
    local *STDIN = *CT_ORIG_STDIN if $localize{stdin}; # get original, not proxy STDIN
    # _debug( "# finalizing layers ...\n" );
    _relayer(\*STDOUT, $layers{stdout}) if $do_stdout;
    _relayer(\*STDERR, $layers{stderr}) if $do_stderr;
    # _debug( "# running code $code ...\n" );
    my $old_eval_err=$@;
    undef $@;
    eval { @result = $code->(); $inner_error = $@ };
    $exit_code = $?; # save this for later
    $outer_error = $@; # save this for later
    STDOUT->flush if $do_stdout;
    STDERR->flush if $do_stderr;
    $@ = $old_eval_err;
  }
  # restore prior filehandles and shut down tees
  # _debug( "# restoring filehandles ...\n" );
  _open_std( $stash->{old} );
  _close( $_ ) for values %{$stash->{old}}; # don't leak fds
  # shouldn't need relayering originals, but see rt.perl.org #114404
  _relayer(\*STDOUT, $layers{stdout}) if $do_stdout;
  _relayer(\*STDERR, $layers{stderr}) if $do_stderr;
  _unproxy( %proxy_std );
  # _debug( "# killing tee subprocesses ...\n" ) if $do_tee;
  _kill_tees( $stash ) if $do_tee;
  # return captured output, but shortcut in void context
  # unless we have to echo output to tied/scalar handles;
  my %got;
  if ( $orig_pid == $$ and ( defined wantarray or ($do_tee && keys %localize) ) ) {
    for ( keys %do ) {
      _relayer($stash->{capture}{$_}, $layers{$_});
      $got{$_} = _slurp($_, $stash);
      # _debug("# slurped " . length($got{$_}) . " bytes from $_\n");
    }
    print CT_ORIG_STDOUT $got{stdout}
      if $do_stdout && $do_tee && $localize{stdout};
    print CT_ORIG_STDERR $got{stderr}
      if $do_stderr && $do_tee && $localize{stderr};
  }
  $? = $exit_code;
  $@ = $inner_error if $inner_error;
  die $outer_error if $outer_error;
  # _debug( "# ending _capture_tee with (@_)...\n" );
  return unless defined wantarray;
  my @return;
  push @return, $got{stdout} if $do_stdout;
  push @return, $got{stderr} if $do_stderr && ! $do_merge;
  push @return, @result;
  return wantarray ? @return : $return[0];
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Capture::Tiny - Capture STDOUT and STDERR from Perl, XS or external programs

=head1 VERSION

version 0.50

=head1 SYNOPSIS

  use Capture::Tiny ':all';

  # capture from external command

  ($stdout, $stderr, $exit) = capture {
    system( $cmd, @args );
  };

  # capture from arbitrary code (Perl or external)

  ($stdout, $stderr, @result) = capture {
    # your code here
  };

  # capture partial or merged output

  $stdout = capture_stdout { ... };
  $stderr = capture_stderr { ... };
  $merged = capture_merged { ... };

  # tee output

  ($stdout, $stderr) = tee {
    # your code here
  };

  $stdout = tee_stdout { ... };
  $stderr = tee_stderr { ... };
  $merged = tee_merged { ... };

=head1 DESCRIPTION

Capture::Tiny provides a simple, portable way to capture almost anything sent
to STDOUT or STDERR, regardless of whether it comes from Perl, from XS code or
from an external program.  Optionally, output can be teed so that it is
captured while being passed through to the original filehandles.  Yes, it even
works on Windows (usually).  Stop guessing which of a dozen capturing modules
to use in any particular situation and just use this one.

=head1 USAGE

The following functions are available.  None are exported by default.

=head2 capture

  ($stdout, $stderr, @result) = capture \&code;
  $stdout = capture \&code;

The C<capture> function takes a code reference and returns what is sent to
STDOUT and STDERR as well as any return values from the code reference.  In
scalar context, it returns only STDOUT.  If no output was received for a
filehandle, it returns an empty string for that filehandle.  Regardless of calling
context, all output is captured -- nothing is passed to the existing filehandles.

It is prototyped to take a subroutine reference as an argument. Thus, it
can be called in block form:

  ($stdout, $stderr) = capture {
    # your code here ...
  };

Note that the coderef is evaluated in list context.  If you wish to force
scalar context on the return value, you must use the C<scalar> keyword.

  ($stdout, $stderr, $count) = capture {
    my @list = qw/one two three/;
    return scalar @list; # $count will be 3
  };

Also note that within the coderef, the C<@_> variable will be empty.  So don't
use arguments from a surrounding subroutine without copying them to an array
first:

  sub wont_work {
    my ($stdout, $stderr) = capture { do_stuff( @_ ) };    # WRONG
    ...
  }

  sub will_work {
    my @args = @_;
    my ($stdout, $stderr) = capture { do_stuff( @args ) }; # RIGHT
    ...
  }

Captures are normally done to an anonymous temporary filehandle.  To
capture via a named file (e.g. to externally monitor a long-running capture),
provide custom filehandles as a trailing list of option pairs:

  my $out_fh = IO::File->new("out.txt", "w+");
  my $err_fh = IO::File->new("err.txt", "w+");
  capture { ... } stdout => $out_fh, stderr => $err_fh;

The filehandles must be read/write and seekable.  Modifying the files or
filehandles during a capture operation will give unpredictable results.
Existing IO layers on them may be changed by the capture.

When called in void context, C<capture> saves memory and time by
not reading back from the capture handles.

=head2 capture_stdout

  ($stdout, @result) = capture_stdout \&code;
  $stdout = capture_stdout \&code;

The C<capture_stdout> function works just like C<capture> except only
STDOUT is captured.  STDERR is not captured.

=head2 capture_stderr

  ($stderr, @result) = capture_stderr \&code;
  $stderr = capture_stderr \&code;

The C<capture_stderr> function works just like C<capture> except only
STDERR is captured.  STDOUT is not captured.

=head2 capture_merged

  ($merged, @result) = capture_merged \&code;
  $merged = capture_merged \&code;

The C<capture_merged> function works just like C<capture> except STDOUT and
STDERR are merged. (Technically, STDERR is redirected to the same capturing
handle as STDOUT before executing the function.)

Caution: STDOUT and STDERR output in the merged result are not guaranteed to be
properly ordered due to buffering.

=head2 tee

  ($stdout, $stderr, @result) = tee \&code;
  $stdout = tee \&code;

The C<tee> function works just like C<capture>, except that output is captured
as well as passed on to the original STDOUT and STDERR.

When called in void context, C<tee> saves memory and time by
not reading back from the capture handles, except when the
original STDOUT or STDERR were tied or opened to a scalar
handle.

=head2 tee_stdout

  ($stdout, @result) = tee_stdout \&code;
  $stdout = tee_stdout \&code;

The C<tee_stdout> function works just like C<tee> except only
STDOUT is teed.  STDERR is not teed (output goes to STDERR as usual).

=head2 tee_stderr

  ($stderr, @result) = tee_stderr \&code;
  $stderr = tee_stderr \&code;

The C<tee_stderr> function works just like C<tee> except only
STDERR is teed.  STDOUT is not teed (output goes to STDOUT as usual).

=head2 tee_merged

  ($merged, @result) = tee_merged \&code;
  $merged = tee_merged \&code;

The C<tee_merged> function works just like C<capture_merged> except that output
is captured as well as passed on to STDOUT.

Caution: STDOUT and STDERR output in the merged result are not guaranteed to be
properly ordered due to buffering.

=head1 LIMITATIONS

=head2 Portability

Portability is a goal, not a guarantee.  C<tee> requires fork, except on
Windows where C<system(1, @cmd)> is used instead.  Not tested on any
particularly esoteric platforms yet.  See the
L<CPAN Testers Matrix|http://matrix.cpantesters.org/?dist=Capture-Tiny>
for test result by platform.

=head2 PerlIO layers

Capture::Tiny does its best to preserve PerlIO layers such as ':utf8' or
':crlf' when capturing (only for Perl 5.8.1+) .  Layers should be applied to
STDOUT or STDERR I<before> the call to C<capture> or C<tee>.  This may not work
for tied filehandles (see below).

=head2 Modifying filehandles before capturing

Generally speaking, you should do little or no manipulation of the standard IO
filehandles prior to using Capture::Tiny.  In particular, closing, reopening,
localizing or tying standard filehandles prior to capture may cause a variety of
unexpected, undesirable and/or unreliable behaviors, as described below.
Capture::Tiny does its best to compensate for these situations, but the
results may not be what you desire.

=head3 Closed filehandles

Capture::Tiny will work even if STDIN, STDOUT or STDERR have been previously
closed.  However, since they will be reopened to capture or tee output, any
code within the captured block that depends on finding them closed will, of
course, not find them to be closed.  If they started closed, Capture::Tiny will
close them again when the capture block finishes.

Note that this reopening will happen even for STDIN or a filehandle not being
captured to ensure that the filehandle used for capture is not opened to file
descriptor 0, as this causes problems on various platforms.

Prior to Perl 5.12, closed STDIN combined with PERL_UNICODE=D leaks filehandles
and also breaks tee() for undiagnosed reasons.  So don't do that.

=head3 Localized filehandles

If code localizes any of Perl's standard filehandles before capturing, the capture
will affect the localized filehandles and not the original ones.  External system
calls are not affected by localizing a filehandle in Perl and will continue
to send output to the original filehandles (which will thus not be captured).

=head3 Scalar filehandles

If STDOUT or STDERR are reopened to scalar filehandles prior to the call to
C<capture> or C<tee>, then Capture::Tiny will override the output filehandle for
the duration of the C<capture> or C<tee> call and then, for C<tee>, send captured
output to the output filehandle after the capture is complete.  (Requires Perl
5.8)

Capture::Tiny attempts to preserve the semantics of STDIN opened to a scalar
reference, but note that external processes will not be able to read from such
a handle.  Capture::Tiny tries to ensure that external processes will read from
the null device instead, but this is not guaranteed.

=head3 Tied output filehandles

If STDOUT or STDERR are tied prior to the call to C<capture> or C<tee>, then
Capture::Tiny will attempt to override the tie for the duration of the
C<capture> or C<tee> call and then send captured output to the tied filehandle after
the capture is complete.  (Requires Perl 5.8)

Capture::Tiny may not succeed resending UTF-8 encoded data to a tied
STDOUT or STDERR filehandle.  Characters may appear as bytes.  If the tied filehandle
is based on L<Tie::StdHandle>, then Capture::Tiny will attempt to determine
appropriate layers like C<:utf8> from the underlying filehandle and do the right
thing.

=head3 Tied input filehandle

Capture::Tiny attempts to preserve the semantics of tied STDIN, but this
requires Perl 5.8 and is not entirely predictable.  External processes
will not be able to read from such a handle.

Unless having STDIN tied is crucial, it may be safest to localize STDIN when
capturing:

  my ($out, $err) = do { local *STDIN; capture { ... } };

=head2 Modifying filehandles during a capture

Attempting to modify STDIN, STDOUT or STDERR I<during> C<capture> or C<tee> is
almost certainly going to cause problems.  Don't do that.

=head3 Forking inside a capture

Forks aren't portable.  The behavior of filehandles during a fork is even
less so.  If Capture::Tiny detects that a fork has occurred within a
capture, it will shortcut in the child process and return empty strings for
captures.  Other problems may occur in the child or parent, as well.
Forking in a capture block is not recommended.

=head3 Using threads

Filehandles are global.  Mixing up I/O and captures in different threads
without coordination is going to cause problems.  Besides, threads are
officially discouraged.

=head3 Dropping privileges during a capture

If you drop privileges during a capture, temporary files created to
facilitate the capture may not be cleaned up afterwards.

=head2 No support for Perl 5.8.0

It's just too buggy when it comes to layers and UTF-8.  Perl 5.8.1 or later
is recommended.

=head2 Limited support for Perl 5.6

Perl 5.6 predates PerlIO.  UTF-8 data may not be captured correctly.

=head1 ENVIRONMENT

=head2 PERL_CAPTURE_TINY_TIMEOUT

Capture::Tiny uses subprocesses internally for C<tee>.  By default,
Capture::Tiny will timeout with an error if such subprocesses are not ready to
receive data within 30 seconds (or whatever is the value of
C<$Capture::Tiny::TIMEOUT>).  An alternate timeout may be specified by setting
the C<PERL_CAPTURE_TINY_TIMEOUT> environment variable.  Setting it to zero will
disable timeouts.  B<NOTE>, this does not timeout the code reference being
captured -- this only prevents Capture::Tiny itself from hanging your process
waiting for its child processes to be ready to proceed.

=head1 SEE ALSO

This module was inspired by L<IO::CaptureOutput>, which provides
similar functionality without the ability to tee output and with more
complicated code and API.  L<IO::CaptureOutput> does not handle layers
or most of the unusual cases described in the L</LIMITATIONS> section and
I no longer recommend it.

There are many other CPAN modules that provide some sort of output capture,
albeit with various limitations that make them appropriate only in particular
circumstances.  I'm probably missing some.  The long list is provided to show
why I felt Capture::Tiny was necessary.

=over 4

=item *

L<IO::Capture>

=item *

L<IO::Capture::Extended>

=item *

L<IO::CaptureOutput>

=item *

L<IPC::Capture>

=item *

L<IPC::Cmd>

=item *

L<IPC::Open2>

=item *

L<IPC::Open3>

=item *

L<IPC::Open3::Simple>

=item *

L<IPC::Open3::Utils>

=item *

L<IPC::Run>

=item *

L<IPC::Run::SafeHandles>

=item *

L<IPC::Run::Simple>

=item *

L<IPC::Run3>

=item *

L<IPC::System::Simple>

=item *

L<Tee>

=item *

L<IO::Tee>

=item *

L<File::Tee>

=item *

L<Filter::Handle>

=item *

L<Tie::STDERR>

=item *

L<Tie::STDOUT>

=item *

L<Test::Output>

=back

=for :stopwords cpan testmatrix url bugtracker rt cpants kwalitee diff irc mailto metadata placeholders metacpan

=head1 SUPPORT

=head2 Bugs / Feature Requests

Please report any bugs or feature requests through the issue tracker
at L<https://github.com/dagolden/Capture-Tiny/issues>.
You will be notified automatically of any progress on your issue.

=head2 Source Code

This is open source software.  The code repository is available for
public review and contribution under the terms of the license.

L<https://github.com/dagolden/Capture-Tiny>

  git clone https://github.com/dagolden/Capture-Tiny.git

=head1 AUTHOR

David Golden <dagolden@cpan.org>

=head1 CONTRIBUTORS

=for stopwords Dagfinn Ilmari Mannsåker David E. Wheeler Ed Sabol fecundf Graham Knop Karen Etheridge Mohammad S Anwar Peter Rabbitson Sven Kirmess

=over 4

=item *

Dagfinn Ilmari Mannsåker <ilmari@ilmari.org>

=item *

David E. Wheeler <david@justatheory.com>

=item *

Ed Sabol <esabol@users.noreply.github.com>

=item *

fecundf <not.com+github@gmail.com>

=item *

Graham Knop <haarg@haarg.org>

=item *

Karen Etheridge <ether@cpan.org>

=item *

Mohammad S Anwar <mohammad.anwar@yahoo.com>

=item *

Peter Rabbitson <ribasushi@cpan.org>

=item *

Sven Kirmess <sven.kirmess@kzone.ch>

=back

=head1 COPYRIGHT AND LICENSE

This software is Copyright (c) 2009 by David Golden.

This is free software, licensed under:

  The Apache License, Version 2.0, January 2004

=cut
PK4N%[?��#�#perl5/Types/Serialiser.pmnu��6�$=head1 NAME

Types::Serialiser - simple data types for common serialisation formats

=encoding utf-8

=head1 SYNOPSIS

=head1 DESCRIPTION

This module provides some extra datatypes that are used by common
serialisation formats such as JSON or CBOR. The idea is to have a
repository of simple/small constants and containers that can be shared by
different implementations so they become interoperable between each other.

=cut

package Types::Serialiser;

use common::sense; # required to suppress annoying warnings

our $VERSION = '1.01';

=head1 SIMPLE SCALAR CONSTANTS

Simple scalar constants are values that are overloaded to act like simple
Perl values, but have (class) type to differentiate them from normal Perl
scalars. This is necessary because these have different representations in
the serialisation formats.

In the following, functions with zero or one arguments have a prototype of
C<()> and C<($)>, respectively, so act as constants and unary operators.

=head2 BOOLEANS (Types::Serialiser::Boolean class)

This type has only two instances, true and false. A natural representation
for these in Perl is C<1> and C<0>, but serialisation formats need to be
able to differentiate between them and mere numbers.

=over 4

=item $Types::Serialiser::true, Types::Serialiser::true

This value represents the "true" value. In most contexts is acts like
the number C<1>. It is up to you whether you use the variable form
(C<$Types::Serialiser::true>) or the constant form (C<Types::Serialiser::true>).

The constant is represented as a reference to a scalar containing C<1> -
implementations are allowed to directly test for this.

=item $Types::Serialiser::false, Types::Serialiser::false

This value represents the "false" value. In most contexts is acts like
the number C<0>. It is up to you whether you use the variable form
(C<$Types::Serialiser::false>) or the constant form (C<Types::Serialiser::false>).

The constant is represented as a reference to a scalar containing C<0> -
implementations are allowed to directly test for this.

=item Types::Serialiser::as_bool $value

Converts a Perl scalar into a boolean, which is useful syntactic
sugar. Strictly equivalent to:

   $value ? $Types::Serialiser::true : $Types::Serialiser::false

=item $is_bool = Types::Serialiser::is_bool $value

Returns true iff the C<$value> is either C<$Types::Serialiser::true> or
C<$Types::Serialiser::false>.

For example, you could differentiate between a perl true value and a
C<Types::Serialiser::true> by using this:

   $value && Types::Serialiser::is_bool $value

=item $is_true = Types::Serialiser::is_true $value

Returns true iff C<$value> is C<$Types::Serialiser::true>.

=item $is_false = Types::Serialiser::is_false $value

Returns false iff C<$value> is C<$Types::Serialiser::false>.

=back

=head2 ERROR (Types::Serialiser::Error class)

This class has only a single instance, C<error>. It is used to signal
an encoding or decoding error. In CBOR for example, and object that
couldn't be encoded will be represented by a CBOR undefined value, which
is represented by the error value in Perl.

=over 4

=item $Types::Serialiser::error, Types::Serialiser::error

This value represents the "error" value. Accessing values of this type
will throw an exception.

The constant is represented as a reference to a scalar containing C<undef>
- implementations are allowed to directly test for this.

=item $is_error = Types::Serialiser::is_error $value

Returns false iff C<$value> is C<$Types::Serialiser::error>.

=back

=cut

BEGIN {
   # for historical reasons, and to avoid extra dependencies in JSON::PP,
   # we alias *Types::Serialiser::Boolean with JSON::PP::Boolean.
   package JSON::PP::Boolean;

   *Types::Serialiser::Boolean:: = *JSON::PP::Boolean::;
}

{
   # this must done before blessing to work around bugs
   # in perl < 5.18 (it seems to be fixed in 5.18).
   package Types::Serialiser::BooleanBase;

   use overload
      "0+"     => sub { ${$_[0]} },
      "++"     => sub { $_[0] = ${$_[0]} + 1 },
      "--"     => sub { $_[0] = ${$_[0]} - 1 },
      fallback => 1;

   @Types::Serialiser::Boolean::ISA = Types::Serialiser::BooleanBase::;
}

our $true  = do { bless \(my $dummy = 1), Types::Serialiser::Boolean:: };
our $false = do { bless \(my $dummy = 0), Types::Serialiser::Boolean:: };
our $error = do { bless \(my $dummy    ), Types::Serialiser::Error::   };

sub true  () { $true  }
sub false () { $false }
sub error () { $error }

sub as_bool($) { $_[0] ? $true : $false }

sub is_bool  ($) {           UNIVERSAL::isa $_[0], Types::Serialiser::Boolean:: }
sub is_true  ($) {  $_[0] && UNIVERSAL::isa $_[0], Types::Serialiser::Boolean:: }
sub is_false ($) { !$_[0] && UNIVERSAL::isa $_[0], Types::Serialiser::Boolean:: }
sub is_error ($) {           UNIVERSAL::isa $_[0], Types::Serialiser::Error::   }

package Types::Serialiser::Error;

sub error {
   require Carp;
   Carp::croak ("caught attempt to use the Types::Serialiser::error value");
};

use overload
   "0+"     => \&error,
   "++"     => \&error,
   "--"     => \&error,
   fallback => 1;

=head1 NOTES FOR XS USERS

The recommended way to detect whether a scalar is one of these objects
is to check whether the stash is the C<Types::Serialiser::Boolean> or
C<Types::Serialiser::Error> stash, and then follow the scalar reference to
see if it's C<1> (true), C<0> (false) or C<undef> (error).

While it is possible to use an isa test, directly comparing stash pointers
is faster and guaranteed to work.

For historical reasons, the C<Types::Serialiser::Boolean> stash is
just an alias for C<JSON::PP::Boolean>. When printed, the classname
with usually be C<JSON::PP::Boolean>, but isa tests and stash pointer
comparison will normally work correctly (i.e. Types::Serialiser::true ISA
JSON::PP::Boolean, but also ISA Types::Serialiser::Boolean).

=head1 A GENERIC OBJECT SERIALIATION PROTOCOL

This section explains the object serialisation protocol used by
L<CBOR::XS>. It is meant to be generic enough to support any kind of
generic object serialiser.

This protocol is called "the Types::Serialiser object serialisation
protocol".

=head2 ENCODING

When the encoder encounters an object that it cannot otherwise encode (for
example, L<CBOR::XS> can encode a few special types itself, and will first
attempt to use the special C<TO_CBOR> serialisation protocol), it will
look up the C<FREEZE> method on the object.

Note that the C<FREEZE> method will normally be called I<during> encoding,
and I<MUST NOT> change the data structure that is being encoded in any
way, or it might cause memory corruption or worse.

If it exists, it will call it with two arguments: the object to serialise,
and a constant string that indicates the name of the data model. For
example L<CBOR::XS> uses C<CBOR>, and the L<JSON> and L<JSON::XS> modules
(or any other JSON serialiser), would use C<JSON> as second argument.

The C<FREEZE> method can then return zero or more values to identify the
object instance. The serialiser is then supposed to encode the class name
and all of these return values (which must be encodable in the format)
using the relevant form for Perl objects. In CBOR for example, there is a
registered tag number for encoded perl objects.

The values that C<FREEZE> returns must be serialisable with the serialiser
that calls it. Therefore, it is recommended to use simple types such as
strings and numbers, and maybe array references and hashes (basically, the
JSON data model). You can always use a more complex format for a specific
data model by checking the second argument, the data model.

The "data model" is not the same as the "data format" - the data model
indicates what types and kinds of return values can be returned from
C<FREEZE>. For example, in C<CBOR> it is permissible to return tagged CBOR
values, while JSON does not support these at all, so C<JSON> would be a
valid (but too limited) data model name for C<CBOR::XS>. similarly, a
serialising format that supports more or less the same data model as JSON
could use C<JSON> as data model without losing anything.

=head2 DECODING

When the decoder then encounters such an encoded perl object, it should
look up the C<THAW> method on the stored classname, and invoke it with the
classname, the constant string to identify the data model/data format, and
all the return values returned by C<FREEZE>.

=head2 EXAMPLES

See the C<OBJECT SERIALISATION> section in the L<CBOR::XS> manpage for
more details, an example implementation, and code examples.

Here is an example C<FREEZE>/C<THAW> method pair:

   sub My::Object::FREEZE {
      my ($self, $model) = @_;

      ($self->{type}, $self->{id}, $self->{variant})
   }

   sub My::Object::THAW {
      my ($class, $model, $type, $id, $variant) = @_;

      $class->new (type => $type, id => $id, variant => $variant)
   }

=head1 BUGS

The use of L<overload> makes this module much heavier than it should be
(on my system, this module: 4kB RSS, overload: 260kB RSS).

=head1 SEE ALSO

Currently, L<JSON::XS> and L<CBOR::XS> use these types.

=head1 AUTHOR

 Marc Lehmann <schmorp@schmorp.de>
 http://home.schmorp.de/

=cut

1

PK4N%[�Wy���perl5/Types/Serialiser/Error.pmnu��6�$=head1 NAME

Types::Serialiser::Error - dummy module for Types::Serialiser

=head1 SYNOPSIS

 # do not "use" yourself

=head1 DESCRIPTION

This module exists only to provide overload resolution for Storable and
similar modules that assume that class name equals module name. See
L<Types::Serialiser> for more info about this class.

=cut

use Types::Serialiser ();

=head1 AUTHOR

 Marc Lehmann <schmorp@schmorp.de>
 http://home.schmorp.de/

=cut

1

PK4N%[H���perl5/Date/Language/Sidama.pmnu��6�$##
## Sidama tables
##

package Date::Language::Sidama;

use Date::Language ();
use vars qw(@ISA @DoW @DoWs @MoY @MoYs @AMPM @Dsuf %MoY %DoW $VERSION);
@ISA = qw(Date::Language);
$VERSION = "0.99";

@DoW = qw(Sambata Sanyo Maakisanyo Roowe Hamuse Arbe Qidaame);
@MoY = qw(January February March April May June
          July August September October November December);
@DoWs = map { substr($_,0,3) } @DoW;
@MoYs = map { substr($_,0,3) } @MoY;
@AMPM = qw(soodo hawwaro);

@Dsuf = (qw(th st nd rd th th th th th th)) x 3;
@Dsuf[11,12,13] = qw(th th th);
@Dsuf[30,31] = qw(th st);

@MoY{@MoY}  = (0 .. scalar(@MoY));
@MoY{@MoYs} = (0 .. scalar(@MoYs));
@DoW{@DoW}  = (0 .. scalar(@DoW));
@DoW{@DoWs} = (0 .. scalar(@DoWs));

# Formatting routines

sub format_a { $DoWs[$_[0]->[6]] }
sub format_A { $DoW[$_[0]->[6]] }
sub format_b { $MoYs[$_[0]->[4]] }
sub format_B { $MoY[$_[0]->[4]] }
sub format_h { $MoYs[$_[0]->[4]] }
sub format_p { $_[0]->[2] >= 12 ?  $AMPM[1] : $AMPM[0] }

1;
PK4N%[ϣ��perl5/Date/Language/German.pmnu��6�$##
## German tables
##

package Date::Language::German;

use Date::Language ();
use vars qw(@ISA @DoW @DoWs @MoY @MoYs @AMPM @Dsuf %MoY %DoW $VERSION);
@ISA = qw(Date::Language);
$VERSION = "1.02";

@MoY  = qw(Januar Februar M�rz April Mai Juni
	   Juli August September Oktober November Dezember);
@MoYs = qw(Jan Feb M�r Apr Mai Jun Jul Aug Sep Okt Nov Dez);
@DoW  = qw(Sonntag Montag Dienstag Mittwoch Donnerstag Freitag Samstag);
@DoWs = qw(Son Mon Die Mit Don Fre Sam);

use Date::Language::English ();
@AMPM =   @{Date::Language::English::AMPM};
@Dsuf =   @{Date::Language::English::Dsuf};

@MoY{@MoY}  = (0 .. scalar(@MoY));
@MoY{@MoYs} = (0 .. scalar(@MoYs));
@DoW{@DoW}  = (0 .. scalar(@DoW));
@DoW{@DoWs} = (0 .. scalar(@DoWs));

# Formatting routines

sub format_a { $DoWs[$_[0]->[6]] }
sub format_A { $DoW[$_[0]->[6]] }
sub format_b { $MoYs[$_[0]->[4]] }
sub format_B { $MoY[$_[0]->[4]] }
sub format_h { $MoYs[$_[0]->[4]] }
sub format_p { $_[0]->[2] >= 12 ?  $AMPM[1] : $AMPM[0] }
sub format_o { sprintf("%2d.",$_[0]->[3]) }

1;
PK4N%[��C�

 perl5/Date/Language/Icelandic.pmnu��6�$##
## Icelandic tables
##

package Date::Language::Icelandic;

use Date::Language ();
use vars qw(@ISA @DoW @DoWs @MoY @MoYs @AMPM @Dsuf %MoY %DoW $VERSION);
@ISA = qw(Date::Language);
$VERSION = "1.01";

@MoY  = qw(Jan�ar Febr�ar Mars Apr�l Ma� J�ni
	   J�li �g�st September Okt�ber N�vember Desember);
@MoYs = qw(Jan Feb Mar Apr Ma� J�n J�l �g� Sep Okt N�v Des);
@DoW  = qw(Sunnudagur M�nudagur �ri�judagur Mi�vikudagur Fimmtudagur F�studagur Laugardagur Sunnudagur);
@DoWs = qw(Sun M�n �ri Mi� Fim F�s Lau Sun);

use Date::Language::English ();
@AMPM =   @{Date::Language::English::AMPM};
@Dsuf =   @{Date::Language::English::Dsuf};

@MoY{@MoY}  = (0 .. scalar(@MoY));
@MoY{@MoYs} = (0 .. scalar(@MoYs));
@DoW{@DoW}  = (0 .. scalar(@DoW));
@DoW{@DoWs} = (0 .. scalar(@DoWs));

# Formatting routines

sub format_a { $DoWs[$_[0]->[6]] }
sub format_A { $DoW[$_[0]->[6]] }
sub format_b { $MoYs[$_[0]->[4]] }
sub format_B { $MoY[$_[0]->[4]] }
sub format_h { $MoYs[$_[0]->[4]] }
sub format_p { $_[0]->[2] >= 12 ?  $AMPM[1] : $AMPM[0] }

1;
PK4N%[|p�0��perl5/Date/Language/Tigrinya.pmnu��6�$##
## Tigrinya tables
##

package Date::Language::Tigrinya;

use Date::Language ();
use vars qw(@ISA @DoW @DoWs @MoY @MoYs @AMPM @Dsuf %MoY %DoW $VERSION);
@ISA = qw(Date::Language);
$VERSION = "1.00";

@DoW = (
"\x{1230}\x{1295}\x{1260}\x{1275}",
"\x{1230}\x{1291}\x{12ed}",
"\x{1230}\x{1209}\x{1235}",
"\x{1228}\x{1261}\x{12d5}",
"\x{1213}\x{1219}\x{1235}",
"\x{12d3}\x{122d}\x{1262}",
"\x{1240}\x{12f3}\x{121d}"
);
@MoY = (
"\x{1303}\x{1295}\x{12e9}\x{12c8}\x{122a}",
"\x{134c}\x{1265}\x{1229}\x{12c8}\x{122a}",
"\x{121b}\x{122d}\x{127d}",
"\x{12a4}\x{1355}\x{1228}\x{120d}",
"\x{121c}\x{12ed}",
"\x{1301}\x{1295}",
"\x{1301}\x{120b}\x{12ed}",
"\x{12a6}\x{1308}\x{1235}\x{1275}",
"\x{1234}\x{1355}\x{1274}\x{121d}\x{1260}\x{122d}",
"\x{12a6}\x{12ad}\x{1270}\x{12cd}\x{1260}\x{122d}",
"\x{1296}\x{126c}\x{121d}\x{1260}\x{122d}",
"\x{12f2}\x{1234}\x{121d}\x{1260}\x{122d}"
);
@DoWs = map { substr($_,0,3) } @DoW;
@MoYs = map { substr($_,0,3) } @MoY;
@AMPM = (
"\x{1295}/\x{1230}",
"\x{12F5}/\x{1230}"
);

@Dsuf = ("\x{12ed}" x 31);

@MoY{@MoY}  = (0 .. scalar(@MoY));
@MoY{@MoYs} = (0 .. scalar(@MoYs));
@DoW{@DoW}  = (0 .. scalar(@DoW));
@DoW{@DoWs} = (0 .. scalar(@DoWs));

# Formatting routines

sub format_a { $DoWs[$_[0]->[6]] }
sub format_A { $DoW[$_[0]->[6]] }
sub format_b { $MoYs[$_[0]->[4]] }
sub format_B { $MoY[$_[0]->[4]] }
sub format_h { $MoYs[$_[0]->[4]] }
sub format_p { $_[0]->[2] >= 12 ?  $AMPM[1] : $AMPM[0] }

1;
PK4N%[U�!�>>perl5/Date/Language/Dutch.pmnu��6�$##
## Dutch tables
## Contributed by Johannes la Poutre <jlpoutre@corp.nl.home.com>
##

package Date::Language::Dutch;

use Date::Language ();
use vars qw(@ISA @DoW @DoWs @MoY @MoYs @AMPM @Dsuf %MoY %DoW $VERSION);
@ISA = qw(Date::Language);
$VERSION = "1.02";

@MoY  = qw(januari februari maart april mei juni juli
           augustus september oktober november december);
@MoYs = map(substr($_, 0, 3), @MoY);
$MoYs[2] = 'mrt'; # mrt is more common (Frank Maas)
@DoW  = map($_ . "dag", qw(zon maan dins woens donder vrij zater));
@DoWs = map(substr($_, 0, 2), @DoW);

# these aren't normally used...
@AMPM = qw(VM NM);
@Dsuf = ('e') x 31;


@MoY{@MoY}  = (0 .. scalar(@MoY));
@MoY{@MoYs} = (0 .. scalar(@MoYs));
@DoW{@DoW}  = (0 .. scalar(@DoW));
@DoW{@DoWs} = (0 .. scalar(@DoWs));

# Formatting routines

sub format_a { $DoWs[$_[0]->[6]] }
sub format_A { $DoW[$_[0]->[6]] }
sub format_b { $MoYs[$_[0]->[4]] }
sub format_B { $MoY[$_[0]->[4]] }
sub format_h { $MoYs[$_[0]->[4]] }
sub format_p { $_[0]->[2] >= 12 ?  $AMPM[1] : $AMPM[0] }
sub format_o { sprintf("%2de",$_[0]->[3]) }

1;
PK4N%[�t�qhhperl5/Date/Language/Russian.pmnu��6�$##
## Russian tables
##
## Contributed by Danil Pismenny <dapi@mail.ru>

package Date::Language::Russian;

use vars qw(@ISA @DoW @DoWs @MoY @MoYs @MoY2 @AMPM %MoY %DoW $VERSION);
@ISA = qw(Date::Language Date::Format::Generic);
$VERSION = "1.01";

@MoY = qw(����� ������ ��� ������ �� ��� ��� ������ �������� ������� ������ ������);
@MoY2 = qw(����� ������ ��� ������ �� ��� ��� ������ �������� ������� ������ ������);
@MoYs = qw(��� ��� ��� ��� �� �� �� ��� ��� ��� ��� ���);

@DoW = qw(����������� ������� ���� ������� ������ ������ �����������);
@DoWs = qw(�� �� �� �� �� �� ��);
@DoWs2 = qw(��� ��� ��� ��� ��� ��� ���);

@AMPM = qw(�� ��);

@MoY{@MoY}  = (0 .. scalar(@MoY));
@MoY{@MoYs} = (0 .. scalar(@MoYs));
@DoW{@DoW}  = (0 .. scalar(@DoW));
@DoW{@DoWs} = (0 .. scalar(@DoWs));

# Formatting routines

sub format_a { $DoWs[$_[0]->[6]] }
sub format_A { $DoW[$_[0]->[6]] }
sub format_b { $MoYs[$_[0]->[4]] }
sub format_B { $MoY[$_[0]->[4]] }
sub format_h { $MoYs[$_[0]->[4]] }
sub format_p { $_[0]->[2] >= 12 ?  $AMPM[1] : $AMPM[0] }

sub format_d { $_[0]->[3] }
sub format_m { $_[0]->[4] + 1 }
sub format_o { $_[0]->[3] . '.' }

sub format_Q { $MoY2[$_[0]->[4]] }

sub str2time {
  my ($self,$value) = @_;
  map {$value=~s/(\s|^)$DoWs2[$_](\s)/$DoWs[$_]$2/ig} (0..6);
  $value=~s/(\s+|^)��(\s+)/$1���$2/;
  return $self->SUPER::str2time($value);
}

1;
PK4N%[����perl5/Date/Language/English.pmnu��6�$##
## English tables
##

package Date::Language::English;

use Date::Language ();
use vars qw(@ISA @DoW @DoWs @MoY @MoYs @AMPM @Dsuf %MoY %DoW $VERSION);
@ISA = qw(Date::Language);
$VERSION = "1.01";

@DoW = qw(Sunday Monday Tuesday Wednesday Thursday Friday Saturday);
@MoY = qw(January February March April May June
	  July August September October November December);
@DoWs = map { substr($_,0,3) } @DoW;
@MoYs = map { substr($_,0,3) } @MoY;
@AMPM = qw(AM PM);

@Dsuf = (qw(th st nd rd th th th th th th)) x 3;
@Dsuf[11,12,13] = qw(th th th);
@Dsuf[30,31] = qw(th st);

@MoY{@MoY}  = (0 .. scalar(@MoY));
@MoY{@MoYs} = (0 .. scalar(@MoYs));
@DoW{@DoW}  = (0 .. scalar(@DoW));
@DoW{@DoWs} = (0 .. scalar(@DoWs));

# Formatting routines

sub format_a { $DoWs[$_[0]->[6]] }
sub format_A { $DoW[$_[0]->[6]] }
sub format_b { $MoYs[$_[0]->[4]] }
sub format_B { $MoY[$_[0]->[4]] }
sub format_h { $MoYs[$_[0]->[4]] }
sub format_p { $_[0]->[2] >= 12 ?  $AMPM[1] : $AMPM[0] }

1;
PK4N%[p½\��perl5/Date/Language/French.pmnu��6�$##
## French tables, contributed by Emmanuel Bataille (bem@residents.frmug.org)
##

package Date::Language::French;

use Date::Language ();
use vars qw(@ISA @DoW @DoWs @MoY @MoYs @AMPM @Dsuf %MoY %DoW $VERSION);
@ISA = qw(Date::Language);
$VERSION = "1.04";

@DoW = qw(dimanche lundi mardi mercredi jeudi vendredi samedi);
@MoY = qw(janvier f�vrier mars avril mai juin 
          juillet ao�t septembre octobre novembre d�cembre);
@DoWs = map { substr($_,0,3) } @DoW;
@MoYs = map { substr($_,0,3) } @MoY;
$MoYs[6] = 'jul';
@AMPM = qw(AM PM);

@Dsuf = ((qw(er e e e e e e e e e)) x 3, 'er');

@MoY{@MoY}  = (0 .. scalar(@MoY));
@MoY{@MoYs} = (0 .. scalar(@MoYs));
@DoW{@DoW}  = (0 .. scalar(@DoW));
@DoW{@DoWs} = (0 .. scalar(@DoWs));

# Formatting routines

sub format_a { $DoWs[$_[0]->[6]] }
sub format_A { $DoW[$_[0]->[6]] }
sub format_b { $MoYs[$_[0]->[4]] }
sub format_B { $MoY[$_[0]->[4]] }
sub format_h { $MoYs[$_[0]->[4]] }
sub format_p { $_[0]->[2] >= 12 ?  $AMPM[1] : $AMPM[0] }
sub format_o { $_[0]->[3] }

1;
PK4N%[d���perl5/Date/Language/Czech.pmnu��6�$##
## Czech tables
##
## Contributed by Honza Pazdziora 

package Date::Language::Czech;

use vars qw(@ISA @DoW @DoWs @MoY @MoYs @MoY2 @AMPM %MoY %DoW $VERSION);
@ISA = qw(Date::Language Date::Format::Generic);
$VERSION = "1.01";

@MoY = qw(leden �nor b�ezen duben kv�ten �erven �ervenec srpen z��
	      ��jen listopad prosinec);
@MoYs = qw(led �nor b�e dub kv� �vn �ec srp z�� ��j lis pro);
@MoY2 = @MoY;
for (@MoY2)
      { s!en$!na! or s!ec$!ce! or s!ad$!adu! or s!or$!ora!; }

@DoW = qw(ned�le pond�l� �ter� st�eda �tvrtek p�tek sobota);
@DoWs = qw(Ne Po �t St �t P� So);

@AMPM = qw(dop. odp.);

@MoY{@MoY}  = (0 .. scalar(@MoY));
@MoY{@MoYs} = (0 .. scalar(@MoYs));
@DoW{@DoW}  = (0 .. scalar(@DoW));
@DoW{@DoWs} = (0 .. scalar(@DoWs));

# Formatting routines

sub format_a { $DoWs[$_[0]->[6]] }
sub format_A { $DoW[$_[0]->[6]] }
sub format_b { $MoYs[$_[0]->[4]] }
sub format_B { $MoY[$_[0]->[4]] }
sub format_h { $MoYs[$_[0]->[4]] }
sub format_p { $_[0]->[2] >= 12 ?  $AMPM[1] : $AMPM[0] }

sub format_d { $_[0]->[3] }
sub format_m { $_[0]->[4] + 1 }
sub format_o { $_[0]->[3] . '.' }

sub format_Q { $MoY2[$_[0]->[4]] }

sub time2str {
      my $ref = shift;
      my @a = @_;
      $a[0] =~ s/(%[do]\.?\s?)%B/$1%Q/;
      $ref->SUPER::time2str(@a);
      }

sub strftime {
      my $ref = shift;
      my @a = @_;
      $a[0] =~ s/(%[do]\.?\s?)%B/$1%Q/;
      $ref->SUPER::time2str(@a);
      }

1;
PK4N%[f0���� perl5/Date/Language/Norwegian.pmnu��6�$##
## Norwegian tables
##

package Date::Language::Norwegian;

use Date::Language ();
use vars qw(@ISA @DoW @DoWs @MoY @MoYs @AMPM @Dsuf %MoY %DoW $VERSION);
@ISA = qw(Date::Language);
$VERSION = "1.01";

@MoY  = qw(Januar Februar Mars April Mai Juni
	   Juli August September Oktober November Desember);
@MoYs = qw(Jan Feb Mar Apr Mai Jun Jul Aug Sep Okt Nov Des);
@DoW  = qw(S�ndag Mandag Tirsdag Onsdag Torsdag Fredag L�rdag S�ndag);
@DoWs = qw(S�n Man Tir Ons Tor Fre L�r S�n);

use Date::Language::English ();
@AMPM =   @{Date::Language::English::AMPM};
@Dsuf =   @{Date::Language::English::Dsuf};

@MoY{@MoY}  = (0 .. scalar(@MoY));
@MoY{@MoYs} = (0 .. scalar(@MoYs));
@DoW{@DoW}  = (0 .. scalar(@DoW));
@DoW{@DoWs} = (0 .. scalar(@DoWs));

# Formatting routines

sub format_a { $DoWs[$_[0]->[6]] }
sub format_A { $DoW[$_[0]->[6]] }
sub format_b { $MoYs[$_[0]->[4]] }
sub format_B { $MoY[$_[0]->[4]] }
sub format_h { $MoYs[$_[0]->[4]] }
sub format_p { $_[0]->[2] >= 12 ?  $AMPM[1] : $AMPM[0] }

1;
PK4N%[�73��!perl5/Date/Language/Chinese_GB.pmnu��6�$##
## English tables
##

package Date::Language::Chinese_GB;

use Date::Language ();
use vars qw(@ISA @DoW @DoWs @MoY @MoYs @AMPM @Dsuf %MoY %DoW $VERSION);
@ISA = qw(Date::Language);
$VERSION = "1.01";

@DoW = qw(������ ����һ ���ڶ� ����� ������ ������ �����);
@MoY = qw(һ�� ���� ��� ���� ���� ����
	  ���� ���� ���� ʮ�� ʮһ�� ʮ����);
@DoWs = map { $_ } @DoW;
@MoYs = map { $_ } @MoY;
@AMPM = qw(���� ����);

@Dsuf = (qw(�� �� �� �� �� �� �� �� �� ��)) x 3;

@MoY{@MoY}  = (0 .. scalar(@MoY));
@MoY{@MoYs} = (0 .. scalar(@MoYs));
@DoW{@DoW}  = (0 .. scalar(@DoW));
@DoW{@DoWs} = (0 .. scalar(@DoWs));

# Formatting routines

sub format_a { $DoWs[$_[0]->[6]] }
sub format_A { $DoW[$_[0]->[6]] }
sub format_b { $MoYs[$_[0]->[4]] }
sub format_B { $MoY[$_[0]->[4]] }
sub format_h { $MoYs[$_[0]->[4]] }
sub format_p { $_[0]->[2] >= 12 ?  $AMPM[1] : $AMPM[0] }

sub format_o { sprintf("%2d%s",$_[0]->[3],"��") }
1;
PK4N%[7��m��perl5/Date/Language/Spanish.pmnu��6�$##
## Spanish tables
##

package Date::Language::Spanish;

use Date::Language ();
use vars qw(@ISA @DoW @DoWs @MoY @MoYs @AMPM @Dsuf %MoY %DoW $VERSION);
@ISA = qw(Date::Language);
$VERSION = "1.00";

@DoW = qw(domingo lunes martes mi�rcoles jueves viernes s�bado);
@MoY = qw(enero febrero marzo abril mayo junio
	  julio agosto septiembre octubre noviembre diciembre);
@DoWs = map { substr($_,0,3) } @DoW;
@MoYs = map { substr($_,0,3) } @MoY;
@AMPM = qw(AM PM);

@Dsuf = ((qw(ro do ro to to to mo vo no mo)) x 3, 'ro');

@MoY{@MoY}  = (0 .. scalar(@MoY));
@MoY{@MoYs} = (0 .. scalar(@MoYs));
@DoW{@DoW}  = (0 .. scalar(@DoW));
@DoW{@DoWs} = (0 .. scalar(@DoWs));

# Formatting routines

sub format_a { $DoWs[$_[0]->[6]] }
sub format_A { $DoW[$_[0]->[6]] }
sub format_b { $MoYs[$_[0]->[4]] }
sub format_B { $MoY[$_[0]->[4]] }
sub format_h { $MoYs[$_[0]->[4]] }
sub format_p { $_[0]->[2] >= 12 ?  $AMPM[1] : $AMPM[0] }

1;
PK4N%[����

 perl5/Date/Language/Bulgarian.pmnu��6�$##
## Bulgarian tables contributed by Krasimir Berov
##

package Date::Language::Bulgarian;
use strict;
use warnings;
use utf8;
use base qw(Date::Language);
our (@DoW, @DoWs, @MoY, @MoYs, @AMPM, @Dsuf, %MoY, %DoW, $VERSION);
$VERSION = "1.01";

@DoW = qw(неделя понеделник вторник сряда четвъртък петък събота);
@MoY = qw(януари февруари март април май юни
    юли август септември октомври ноември декември);
@DoWs = qw(нд пн вт ср чт пт сб);
@MoYs = map { substr($_,0,3) } @MoY;
@AMPM = qw(AM PM);

@Dsuf = (qw(ти ви ри ти ти ти ти ми ми ти)) x 3;
@Dsuf[11,12,13] = qw(ти ти ти);
@Dsuf[30,31] = qw(ти ви);

@MoY{@MoY}  = (0 .. scalar(@MoY));
@MoY{@MoYs} = (0 .. scalar(@MoYs));
@DoW{@DoW}  = (0 .. scalar(@DoW));
@DoW{@DoWs} = (0 .. scalar(@DoWs));

# Formatting routines

sub format_a { $DoWs[$_[0]->[6]] }
sub format_A { $DoW[$_[0]->[6]] }
sub format_b { $MoYs[$_[0]->[4]] }
sub format_B { $MoY[$_[0]->[4]] }
sub format_h { $MoYs[$_[0]->[4]] }
sub format_p { $_[0]->[2] >= 12 ?  $AMPM[1] : $AMPM[0] }
sub format_o { ($_[0]->[3]<10?' ':'').$_[0]->[3].$Dsuf[$_[0]->[3]] }

1;

__END__

=encoding utf8

=head1 NAME

Date::Language::Bulgarian - localization for Date::Format

=head1 DESCRIPTION

This is Bulgarian localization for Date::Format. 
It is important to note that this module source code is in utf8.
All strings which it outputs are in utf8, so it is safe to use it 
currently only with English. You are left alone to try and convert 
the output when using different Date::Language::* in the same application. 
This should be addresed in the future.

=head1 SYNOPSIS

    use strict; 
    use warnings;
    use Date::Language;
    local $\=$/;
    my $template ='%a %b %e %T %Y (%Y-%m-%d %H:%M:%S)';
    my $time=1290883821; #or just use time();
    my @lt = localtime($time);
    my %languages = qw(English GMT German EEST Bulgarian EET);
    binmode(select,':utf8');

    foreach my $l(keys %languages){
        my $lang = Date::Language->new($l);
        my $zone = $languages{$l};
        print $/. "$l $zone";
        print $lang->time2str($template, $time);
        print $lang->time2str($template, $time, $zone);

        print $lang->strftime($template, \@lt);
    }

=head1 AUTHOR

Krasimir Berov (berov@cpan.org)

=head1 COPYRIGHT

Copyright (c) 2010 Krasimir Berov. This program is free
software; you can redistribute it and/or modify it under the same terms
as Perl itself.

=cut


PK4N%[�_bperl5/Date/Language/Turkish.pmnu�7��m#----------------------------------------------------#
#
# Turkish tables
# Burak G�rsoy <burak@cpan.org>
# Last modified: Sat Nov 15 20:28:32 2003
#
# use Date::Language;
# my $turkish = Date::Language->new('Turkish');
# print $turkish->time2str("%e %b %Y, %a %T\n", time);
# print $turkish->str2time("25 Haz 1996 21:09:55 +0100");
#----------------------------------------------------#

package Date::Language::Turkish;
use Date::Language ();
use vars qw(@ISA @DoW @DoWs @MoY @MoYs @AMPM @Dsuf %MoY %DoW $VERSION %DsufMAP);
@ISA     = qw(Date::Language);
$VERSION = "1.0";

@DoW = qw(Pazar Pazartesi Sal� �ar�amba Per�embe Cuma Cumartesi);
@MoY = qw(Ocak �ubat Mart  Nisan May�s Haziran Temmuz A�ustos Eyl�l Ekim Kas�m Aral�k);
@DoWs     = map { substr($_,0,3) } @DoW;
$DoWs[1]  = 'Pzt'; # Since we'll get two 'Paz' s
$DoWs[-1] = 'Cmt'; # Since we'll get two 'Cum' s
@MoYs     = map { substr($_,0,3) } @MoY;
@AMPM     = ('',''); # no am-pm thingy

# not easy as in english... maybe we can just use a dot "." ? :)
%DsufMAP = (
(map {$_ => 'inci', $_+10 => 'inci', $_+20 => 'inci' } 1,2,5,8 ),
(map {$_ =>  'nci', $_+10 =>  'nci', $_+20 =>  'nci' } 7       ),
(map {$_ =>  'nci', $_+10 =>  'nci', $_+20 =>  'nci' } 2       ),
(map {$_ => '�nc�', $_+10 => '�nc�', $_+20 => '�nc�' } 3,4     ),
(map {$_ => 'uncu', $_+10 => 'uncu', $_+20 => 'uncu' } 9       ),
(map {$_ =>  'nc�', $_+10 =>  'nc�', $_+20 =>  'nc�' } 6       ),
(map {$_ => 'uncu',                                  } 10,30   ),
      20 =>  'nci',
      31 => 'inci',
);

@Dsuf       = map{ $DsufMAP{$_} } sort {$a <=> $b} keys %DsufMAP;
@MoY{@MoY}  = (0 .. scalar(@MoY));
@MoY{@MoYs} = (0 .. scalar(@MoYs));
@DoW{@DoW}  = (0 .. scalar(@DoW));
@DoW{@DoWs} = (0 .. scalar(@DoWs));

# Formatting routines

sub format_a { $DoWs[$_[0]->[6]] }
sub format_A { $DoW[ $_[0]->[6]] }
sub format_b { $MoYs[$_[0]->[4]] }
sub format_B { $MoY[ $_[0]->[4]] }
sub format_h { $MoYs[$_[0]->[4]] }
sub format_p { '' } # disable
sub format_P { '' } # disable
sub format_o { sprintf("%2d%s",$_[0]->[3],$Dsuf[$_[0]->[3]-1]) }

1;

__END__
PK4N%[��"h%perl5/Date/Language/Russian_cp1251.pmnu�7��m##
## Russian cp1251
##

package Date::Language::Russian_cp1251;

use Date::Language ();
use vars qw(@ISA @DoW @DoWs @MoY @MoYs @AMPM @Dsuf %MoY %DoW $VERSION);
@ISA = qw(Date::Language);
$VERSION = "1.01";

@DoW = qw(���������� ���������� ������� ����� ������� ����� �������);
@MoY = qw(����� ������ ���� ����� ��� ��
      �� ������ ������ ����� ���� ������);
@DoWs = qw(��� ��� ��� ��� ��� ��� ���);
#@DoWs = map { substr($_,0,3) } @DoW;
@MoYs = map { substr($_,0,3) } @MoY;
@AMPM = qw(AM PM);

@Dsuf = ('e') x 31;
#@Dsuf[11,12,13] = qw(� � �);
#@Dsuf[30,31] = qw(� �);

@MoY{@MoY}  = (0 .. scalar(@MoY));
@MoY{@MoYs} = (0 .. scalar(@MoYs));
@DoW{@DoW}  = (0 .. scalar(@DoW));
@DoW{@DoWs} = (0 .. scalar(@DoWs));

# Formatting routines

sub format_a { $DoWs[$_[0]->[6]] }
sub format_A { $DoW[$_[0]->[6]] }
sub format_b { $MoYs[$_[0]->[4]] }
sub format_B { $MoY[$_[0]->[4]] }
sub format_h { $MoYs[$_[0]->[4]] }
sub format_p { $_[0]->[2] >= 12 ?  $AMPM[1] : $AMPM[0] }
sub format_o { sprintf("%2de",$_[0]->[3]) }

1;
PK4N%[(!p

perl5/Date/Language/Greek.pmnu��6�$##
## Greek tables
##
## Traditional date format is: DoW DD{eta} MoY Year (%A %o %B %Y)
##
## Matthew Musgrove <muskrat@mindless.com>
## Translations gratiously provided by Menelaos Stamatelos <men@kwsn.net>
## This module returns unicode (utf8) encoded characters.  You will need to
## take the necessary steps for this to display correctly.
##

package Date::Language::Greek;

use utf8;
use Date::Language ();
use vars qw(@ISA @DoW @DoWs @MoY @MoYs @AMPM @Dsuf %MoY %DoW $VERSION);
@ISA = qw(Date::Language);
$VERSION = "1.00";

@DoW = (
"\x{039a}\x{03c5}\x{03c1}\x{03b9}\x{03b1}\x{03ba}\x{03ae}",
"\x{0394}\x{03b5}\x{03c5}\x{03c4}\x{03ad}\x{03c1}\x{03b1}",
"\x{03a4}\x{03c1}\x{03af}\x{03c4}\x{03b7}",
"\x{03a4}\x{03b5}\x{03c4}\x{03ac}\x{03c1}\x{03c4}\x{03b7}",
"\x{03a0}\x{03ad}\x{03bc}\x{03c0}\x{03c4}\x{03b7}",
"\x{03a0}\x{03b1}\x{03c1}\x{03b1}\x{03c3}\x{03ba}\x{03b5}\x{03c5}\x{03ae}",
"\x{03a3}\x{03ac}\x{03b2}\x{03b2}\x{03b1}\x{03c4}\x{03bf}",
);

@MoY = (
"\x{0399}\x{03b1}\x{03bd}\x{03bf}\x{03c5}\x{03b1}\x{03c1}\x{03af}\x{03bf}\x{03c5}",
"\x{03a6}\x{03b5}\x{03b2}\x{03c1}\x{03bf}\x{03c5}\x{03b1}\x{03c1}\x{03af}\x{03bf}\x{03c5}",
"\x{039c}\x{03b1}\x{03c1}\x{03c4}\x{03af}\x{03bf}\x{03c5}",
"\x{0391}\x{03c0}\x{03c1}\x{03b9}\x{03bb}\x{03af}\x{03c5}",
"\x{039c}\x{03b1}\x{0390}\x{03bf}\x{03c5}",
"\x{0399}\x{03bf}\x{03c5}\x{03bd}\x{03af}\x{03bf}\x{03c5}",
"\x{0399}\x{03bf}\x{03c5}\x{03bb}\x{03af}\x{03bf}\x{03c5}",
"\x{0391}\x{03c5}\x{03b3}\x{03bf}\x{03cd}\x{03c3}\x{03c4}\x{03bf}\x{03c5}",
"\x{03a3}\x{03b5}\x{03c0}\x{03c4}\x{03b5}\x{03bc}\x{03c4}\x{03bf}\x{03c5}",
"\x{039f}\x{03ba}\x{03c4}\x{03c9}\x{03b2}\x{03c1}\x{03af}\x{03bf}\x{03c5}",
"\x{039d}\x{03bf}\x{03b5}\x{03bc}\x{03b2}\x{03c1}\x{03af}\x{03bf}\x{03c5}",
"\x{0394}\x{03b5}\x{03ba}\x{03b5}\x{03bc}\x{03b2}\x{03c1}\x{03bf}\x{03c5}",
);

@DoWs = (
"\x{039a}\x{03c5}",
"\x{0394}\x{03b5}",
"\x{03a4}\x{03c1}",
"\x{03a4}\x{03b5}",
"\x{03a0}\x{03b5}",
"\x{03a0}\x{03b1}",
"\x{03a3}\x{03b1}",
);
@MoYs = (
"\x{0399}\x{03b1}\x{03bd}",
"\x{03a6}\x{03b5}",
"\x{039c}\x{03b1}\x{03c1}",
"\x{0391}\x{03c0}\x{03c1}",
"\x{039c}\x{03b1}",
"\x{0399}\x{03bf}\x{03c5}\x{03bd}",
"\x{0399}\x{03bf}\x{03c5}\x{03bb}",
"\x{0391}\x{03c5}\x{03b3}",
"\x{03a3}\x{03b5}\x{03c0}",
"\x{039f}\x{03ba}",
"\x{039d}\x{03bf}",
"\x{0394}\x{03b5}",
);

@AMPM = ("\x{03c0}\x{03bc}", "\x{03bc}\x{03bc}");

@Dsuf = ("\x{03b7}" x 31);

@MoY{@MoY}  = (0 .. scalar(@MoY));
@MoY{@MoYs} = (0 .. scalar(@MoYs));
@DoW{@DoW}  = (0 .. scalar(@DoW));
@DoW{@DoWs} = (0 .. scalar(@DoWs));

# Formatting routines

sub format_a { $DoWs[$_[0]->[6]] }
sub format_A { $DoW[$_[0]->[6]] }
sub format_b { $MoYs[$_[0]->[4]] }
sub format_B { $MoY[$_[0]->[4]] }
sub format_h { $MoYs[$_[0]->[4]] }
sub format_o { sprintf("%2d%s",$_[0]->[3],"\x{03b7}") }
sub format_p { $_[0]->[2] >= 12 ?  $AMPM[1] : $AMPM[0] }

1;



PK4N%[i[Wj��perl5/Date/Language/Somali.pmnu��6�$##
## Somali tables
##

package Date::Language::Somali;

use Date::Language ();
use vars qw(@ISA @DoW @DoWs @MoY @MoYs @AMPM @Dsuf %MoY %DoW $VERSION);
@ISA = qw(Date::Language);
$VERSION = "0.99";

@DoW = qw(Axad Isniin Salaaso Arbaco Khamiis Jimco Sabti);
@MoY = (
"Bisha Koobaad",
"Bisha Labaad",
"Bisha Saddexaad",
"Bisha Afraad",
"Bisha Shanaad",
"Bisha Lixaad",
"Bisha Todobaad",
"Bisha Sideedaad",
"Bisha Sagaalaad",
"Bisha Tobnaad",
"Bisha Kow iyo Tobnaad",
"Bisha Laba iyo Tobnaad"
);
@DoWs = map { substr($_,0,3) } @DoW;
@MoYs = (
"Kob",
"Lab",
"Sad",
"Afr",
"Sha",
"Lix",
"Tod",
"Sid",
"Sag",
"Tob",
"KIT",
"LIT"
);
@AMPM = qw(SN GN);

@Dsuf = (qw(th st nd rd th th th th th th)) x 3;
@Dsuf[11,12,13] = qw(th th th);
@Dsuf[30,31] = qw(th st);

@MoY{@MoY}  = (0 .. scalar(@MoY));
@MoY{@MoYs} = (0 .. scalar(@MoYs));
@DoW{@DoW}  = (0 .. scalar(@DoW));
@DoW{@DoWs} = (0 .. scalar(@DoWs));

# Formatting routines

sub format_a { $DoWs[$_[0]->[6]] }
sub format_A { $DoW[$_[0]->[6]] }
sub format_b { $MoYs[$_[0]->[4]] }
sub format_B { $MoY[$_[0]->[4]] }
sub format_h { $MoYs[$_[0]->[4]] }
sub format_p { $_[0]->[2] >= 12 ?  $AMPM[1] : $AMPM[0] }

1;
PK4N%[҅���perl5/Date/Language/Austrian.pmnu��6�$##
## Austrian tables
##

package Date::Language::Austrian;

use Date::Language ();
use vars qw(@ISA @DoW @DoWs @MoY @MoYs @AMPM @Dsuf %MoY %DoW $VERSION);
@ISA = qw(Date::Language);
$VERSION = "1.01";

@MoY  = qw(J�nner Feber M�rz April Mai Juni
	   Juli August September Oktober November Dezember);
@MoYs = qw(J�n Feb M�r Apr Mai Jun Jul Aug Sep Oct Nov Dez);
@DoW  = qw(Sonntag Montag Dienstag Mittwoch Donnerstag Freitag Samstag);
@DoWs = qw(Son Mon Die Mit Don Fre Sam);

use Date::Language::English ();
@AMPM = @{Date::Language::English::AMPM};
@Dsuf = @{Date::Language::English::Dsuf};

@MoY{@MoY}  = (0 .. scalar(@MoY));
@MoY{@MoYs} = (0 .. scalar(@MoYs));
@DoW{@DoW}  = (0 .. scalar(@DoW));
@DoW{@DoWs} = (0 .. scalar(@DoWs));

# Formatting routines

sub format_a { $DoWs[$_[0]->[6]] }
sub format_A { $DoW[$_[0]->[6]] }
sub format_b { $MoYs[$_[0]->[4]] }
sub format_B { $MoY[$_[0]->[4]] }
sub format_h { $MoYs[$_[0]->[4]] }
sub format_p { $_[0]->[2] >= 12 ?  $AMPM[1] : $AMPM[0] }

1;
PK4N%[ �9||perl5/Date/Language/Romanian.pmnu��6�$##
## Italian tables
##

package Date::Language::Romanian;

use Date::Language ();
use vars qw(@ISA @DoW @DoWs @MoY @MoYs @AMPM @Dsuf %MoY %DoW $VERSION);
@ISA = qw(Date::Language);
$VERSION = "1.01";

@MoY  = qw(ianuarie februarie martie aprilie mai iunie 
		iulie august septembrie octombrie noembrie decembrie);
@DoW  = qw(duminica luni marti miercuri joi vineri sambata);
@DoWs = map { substr($_,0,3) } @DoW;
@MoYs = map { substr($_,0,3) } @MoY;

@AMPM = qw(AM PM);

@Dsuf = ('') x 31;


@MoY{@MoY}  = (0 .. scalar(@MoY));
@MoY{@MoYs} = (0 .. scalar(@MoYs));
@DoW{@DoW}  = (0 .. scalar(@DoW));
@DoW{@DoWs} = (0 .. scalar(@DoWs));

# Formatting routines

sub format_a { $DoWs[$_[0]->[6]] }
sub format_A { $DoW[$_[0]->[6]] }
sub format_b { $MoYs[$_[0]->[4]] }
sub format_B { $MoY[$_[0]->[4]] }
sub format_h { $MoYs[$_[0]->[4]] }
sub format_p { $_[0]->[2] >= 12 ?  $AMPM[1] : $AMPM[0] }

1;
PK4N%[����perl5/Date/Language/Chinese.pmnu��6�$##
## English tables
##

package Date::Language::Chinese;

use Date::Language ();
use vars qw(@ISA @DoW @DoWs @MoY @MoYs @AMPM @Dsuf %MoY %DoW $VERSION);
@ISA = qw(Date::Language);
$VERSION = "1.00";

@DoW = qw(星期日 星期一 星期二 星期三 星期四 星期五 星期六);
@MoY = qw(一月 二月 三月 四月 五月 六月
	  七月 八月 九月 十月 十一月 十二月);
@DoWs = map { $_ } @DoW;
@MoYs = map { $_ } @MoY;
@AMPM = qw(上午 下午);

@Dsuf = (qw(日 日 日 日 日 日 日 日 日 日)) x 3;

@MoY{@MoY}  = (0 .. scalar(@MoY));
@MoY{@MoYs} = (0 .. scalar(@MoYs));
@DoW{@DoW}  = (0 .. scalar(@DoW));
@DoW{@DoWs} = (0 .. scalar(@DoWs));

# Formatting routines

sub format_a { $DoWs[$_[0]->[6]] }
sub format_A { $DoW[$_[0]->[6]] }
sub format_b { $MoYs[$_[0]->[4]] }
sub format_B { $MoY[$_[0]->[4]] }
sub format_h { $MoYs[$_[0]->[4]] }
sub format_p { $_[0]->[2] >= 12 ?  $AMPM[1] : $AMPM[0] }

sub format_o { sprintf("%2d%s",$_[0]->[3],"日") }
1;
PK4N%[���J��perl5/Date/Language/Amharic.pmnu��6�$##
## Amharic tables
##

package Date::Language::Amharic;

use Date::Language ();
use vars qw(@ISA @DoW @DoWs @MoY @MoYs @AMPM @Dsuf %MoY %DoW $VERSION);
@ISA = qw(Date::Language);
$VERSION = "1.00";

if ( $] >= 5.006 ) {
@DoW = (
"\x{12a5}\x{1211}\x{12f5}",
"\x{1230}\x{129e}",
"\x{121b}\x{12ad}\x{1230}\x{129e}",
"\x{1228}\x{1261}\x{12d5}",
"\x{1210}\x{1219}\x{1235}",
"\x{12d3}\x{122d}\x{1265}",
"\x{1245}\x{12f3}\x{121c}"
);
@MoY = (
"\x{1303}\x{1295}\x{12e9}\x{12c8}\x{122a}",
"\x{134c}\x{1265}\x{1229}\x{12c8}\x{122a}",
"\x{121b}\x{122d}\x{127d}",
"\x{12a4}\x{1355}\x{1228}\x{120d}",
"\x{121c}\x{12ed}",
"\x{1301}\x{1295}",
"\x{1301}\x{120b}\x{12ed}",
"\x{12a6}\x{1308}\x{1235}\x{1275}",
"\x{1234}\x{1355}\x{1274}\x{121d}\x{1260}\x{122d}",
"\x{12a6}\x{12ad}\x{1270}\x{12cd}\x{1260}\x{122d}",
"\x{1296}\x{126c}\x{121d}\x{1260}\x{122d}",
"\x{12f2}\x{1234}\x{121d}\x{1260}\x{122d}"
);
@DoWs = map { substr($_,0,3) } @DoW;
@MoYs = map { substr($_,0,3) } @MoY;
@AMPM = ( "\x{1320}\x{12cb}\x{1275}", "\x{12a8}\x{1230}\x{12d3}\x{1275}" );

@Dsuf = ("\x{129b}" x 31);
}
else {
@DoW = (
"እሑድ",
"ሰኞ",
"ማክሰኞ",
"ረቡዕ",
"ሐሙስ",
"ዓርብ",
"ቅዳሜ"
);
@MoY = (
"ጃንዩወሪ",
"ፌብሩወሪ",
"ማርች",
"ኤፕረል",
"ሜይ",
"ጁን",
"ጁላይ",
"ኦገስት",
"ሴፕቴምበር",
"ኦክተውበር",
"ኖቬምበር",
"ዲሴምበር"
);
@DoWs = map { substr($_,0,9) } @DoW;
@MoYs = map { substr($_,0,9) } @MoY;
@AMPM = ( "ጠዋት", "ከሰዓት" );

@Dsuf = ("ኛ" x 31);
}

@MoY{@MoY}  = (0 .. scalar(@MoY));
@MoY{@MoYs} = (0 .. scalar(@MoYs));
@DoW{@DoW}  = (0 .. scalar(@DoW));
@DoW{@DoWs} = (0 .. scalar(@DoWs));

# Formatting routines

sub format_a { $DoWs[$_[0]->[6]] }
sub format_A { $DoW[$_[0]->[6]] }
sub format_b { $MoYs[$_[0]->[4]] }
sub format_B { $MoY[$_[0]->[4]] }
sub format_h { $MoYs[$_[0]->[4]] }
sub format_p { $_[0]->[2] >= 12 ?  $AMPM[1] : $AMPM[0] }

1;
PK4N%[4E&S�� perl5/Date/Language/Brazilian.pmnu��6�$##
## Brazilian tables, contributed by Christian Tosta (tosta@cce.ufmg.br)
##

package Date::Language::Brazilian;

use Date::Language ();
use vars qw(@ISA @DoW @DoWs @MoY @MoYs @AMPM @Dsuf %MoY %DoW $VERSION);
@ISA = qw(Date::Language);
$VERSION = "1.01";

@DoW = qw(Domingo Segunda Ter�a Quarta Quinta Sexta S�bado);
@MoY = qw(Janeiro Fevereiro Mar�o Abril Maio Junho
	  Julho Agosto Setembro Outubro Novembro Dezembro);
@DoWs = map { substr($_,0,3) } @DoW;
@MoYs = map { substr($_,0,3) } @MoY;
@AMPM = qw(AM PM);

@Dsuf = (qw(mo ro do ro to to to mo vo no)) x 3;

@MoY{@MoY}  = (0 .. scalar(@MoY));
@MoY{@MoYs} = (0 .. scalar(@MoYs));
@DoW{@DoW}  = (0 .. scalar(@DoW));
@DoW{@DoWs} = (0 .. scalar(@DoWs));

# Formatting routines

sub format_a { $DoWs[$_[0]->[6]] }
sub format_A { $DoW[$_[0]->[6]] }
sub format_b { $MoYs[$_[0]->[4]] }
sub format_B { $MoY[$_[0]->[4]] }
sub format_h { $MoYs[$_[0]->[4]] }
sub format_p { $_[0]->[2] >= 12 ?  $AMPM[1] : $AMPM[0] }

1;
PK4N%[kEY4((perl5/Date/Language/Gedeo.pmnu��6�$##
## Gedeo tables
##

package Date::Language::Gedeo;

use Date::Language ();
use vars qw(@ISA @DoW @DoWs @MoY @MoYs @AMPM @Dsuf %MoY %DoW $VERSION);
@ISA = qw(Date::Language);
$VERSION = "0.99";

@DoW = qw( Sanbbattaa Sanno Masano Roobe Hamusse Arbe Qiddamme);
@MoY = (
"Oritto",
"Birre'a",
"Onkkollessa",
"Saddasa",
"Arrasa",
"Qammo",
"Ella",
"Waacibajje",
"Canissa",
"Addolessa",
"Bittitotessa",
"Hegeya"
);
@DoWs = map { substr($_,0,3) } @DoW;
$DoWs[0] = "Snb";
$DoWs[1] = "Sno";
@MoYs = map { substr($_,0,3) } @MoY;
@AMPM = qw(gorsa warreti-udumma);

@Dsuf = (qw(th st nd rd th th th th th th)) x 3;
@Dsuf[11,12,13] = qw(th th th);
@Dsuf[30,31] = qw(th st);

@MoY{@MoY}  = (0 .. scalar(@MoY));
@MoY{@MoYs} = (0 .. scalar(@MoYs));
@DoW{@DoW}  = (0 .. scalar(@DoW));
@DoW{@DoWs} = (0 .. scalar(@DoWs));

# Formatting routines

sub format_a { $DoWs[$_[0]->[6]] }
sub format_A { $DoW[$_[0]->[6]] }
sub format_b { $MoYs[$_[0]->[4]] }
sub format_B { $MoY[$_[0]->[4]] }
sub format_h { $MoYs[$_[0]->[4]] }
sub format_p { $_[0]->[2] >= 12 ?  $AMPM[1] : $AMPM[0] }

1;
PK4N%[��D`��perl5/Date/Language/Finnish.pmnu��6�$##
## Finnish tables
## Contributed by Matthew Musgrove <muskrat@mindless.com>
## Corrected by roke
##

package Date::Language::Finnish;

use Date::Language ();
use vars qw(@ISA @DoW @DoWs @MoY @MoYs @AMPM @Dsuf %MoY %DoW $VERSION);
@ISA = qw(Date::Language);
$VERSION = "1.01";

# In Finnish, the names of the months and days are only capitalized at the beginning of sentences.
@MoY  = map($_ . "kuu", qw(tammi helmi maalis huhti touko kes� hein� elo syys loka marras joulu));
@DoW  = qw(sunnuntai maanantai tiistai keskiviikko torstai perjantai lauantai);

# it is not customary to use abbreviated names of months or days
# per Graham's suggestion:
@MoYs = @MoY;
@DoWs = @DoW;

# the short form of ordinals
@Dsuf = ('.') x 31;

# doesn't look like this is normally used...
@AMPM = qw(ap ip);


@MoY{@MoY}  = (0 .. scalar(@MoY));
@MoY{@MoYs} = (0 .. scalar(@MoYs));
@DoW{@DoW}  = (0 .. scalar(@DoW));
@DoW{@DoWs} = (0 .. scalar(@DoWs));

# Formatting routines

sub format_a { $DoWs[$_[0]->[6]] }
sub format_A { $DoW[$_[0]->[6]] }
sub format_b { $MoYs[$_[0]->[4]] }
sub format_B { $MoY[$_[0]->[4]] }
sub format_h { $MoYs[$_[0]->[4]] }
sub format_p { $_[0]->[2] >= 12 ?  $AMPM[1] : $AMPM[0] }
sub format_o { sprintf("%2de",$_[0]->[3]) }

1;PK4N%[?�Obbperl5/Date/Language/Swedish.pmnu��6�$##
## Swedish tables
## Contributed by Matthew Musgrove <muskrat@mindless.com>
## Corrected by dempa
##

package Date::Language::Swedish;

use Date::Language ();
use vars qw(@ISA @DoW @DoWs @MoY @MoYs @AMPM @Dsuf %MoY %DoW $VERSION);
@ISA = qw(Date::Language);
$VERSION = "1.01";

@MoY  = qw(januari februari mars april maj juni juli augusti september oktober november december);
@MoYs = map { substr($_,0,3) } @MoY;
@DoW  = map($_ . "dagen", qw(s�n m�n tis ons tors fre l�r));
@DoWs = map { substr($_,0,2) } @DoW;

# the ordinals are not typically used in modern times
@Dsuf = ('a' x 2, 'e' x 29);

use Date::Language::English ();
@AMPM =   @{Date::Language::English::AMPM};


@MoY{@MoY}  = (0 .. scalar(@MoY));
@MoY{@MoYs} = (0 .. scalar(@MoYs));
@DoW{@DoW}  = (0 .. scalar(@DoW));
@DoW{@DoWs} = (0 .. scalar(@DoWs));

# Formatting routines

sub format_a { $DoWs[$_[0]->[6]] }
sub format_A { $DoW[$_[0]->[6]] }
sub format_b { $MoYs[$_[0]->[4]] }
sub format_B { $MoY[$_[0]->[4]] }
sub format_h { $MoYs[$_[0]->[4]] }
sub format_p { $_[0]->[2] >= 12 ?  $AMPM[1] : $AMPM[0] }
sub format_o { sprintf("%2de",$_[0]->[3]) }

1;
PK4N%[<6�pp'perl5/Date/Language/TigrinyaEritrean.pmnu��6�$##
## Tigrinya-Eritrean tables
##

package Date::Language::TigrinyaEritrean;

use Date::Language ();
use vars qw(@ISA @DoW @DoWs @MoY @MoYs @AMPM @Dsuf %MoY %DoW $VERSION);
@ISA = qw(Date::Language);
$VERSION = "1.00";

if ( $] >= 5.006 ) {
@DoW = (
"\x{1230}\x{1295}\x{1260}\x{1275}",
"\x{1230}\x{1291}\x{12ed}",
"\x{1230}\x{1209}\x{1235}",
"\x{1228}\x{1261}\x{12d5}",
"\x{1213}\x{1219}\x{1235}",
"\x{12d3}\x{122d}\x{1262}",
"\x{1240}\x{12f3}\x{121d}"
);
@MoY = (
"\x{1303}\x{1295}\x{12e9}\x{12c8}\x{122a}",
"\x{134c}\x{1265}\x{1229}\x{12c8}\x{122a}",
"\x{121b}\x{122d}\x{127d}",
"\x{12a4}\x{1355}\x{1228}\x{120d}",
"\x{121c}\x{12ed}",
"\x{1301}\x{1295}",
"\x{1301}\x{120b}\x{12ed}",
"\x{12a6}\x{1308}\x{1235}\x{1275}",
"\x{1234}\x{1355}\x{1274}\x{121d}\x{1260}\x{122d}",
"\x{12a6}\x{12ad}\x{1270}\x{12cd}\x{1260}\x{122d}",
"\x{1296}\x{126c}\x{121d}\x{1260}\x{122d}",
"\x{12f2}\x{1234}\x{121d}\x{1260}\x{122d}"
);
@DoWs = map { substr($_,0,3) } @DoW;
@MoYs = map { substr($_,0,3) } @MoY;
@AMPM = (
"\x{1295}/\x{1230}",
"\x{12F5}/\x{1230}"
);

@Dsuf = ("\x{12ed}" x 31);
}
else {
@DoW = (
"ሰንበት",
"ሰኑይ",
"ሰሉስ",
"ረቡዕ",
"ሓሙስ",
"ዓርቢ",
"ቀዳም"
);
@MoY = (
"ጥሪ",
"ለካቲት",
"መጋቢት",
"ሚያዝያ",
"ግንቦት",
"ሰነ",
"ሓምለ",
"ነሓሰ",
"መስከረም",
"ጥቅምቲ",
"ሕዳር",
"ታሕሳስ"
);
@DoWs = map { substr($_,0,9) } @DoW;
@MoYs = map { substr($_,0,9) } @MoY;
@AMPM = (
"ን/ሰ",
"ድ/ሰ"
);

@Dsuf = ("ይ" x 31);
}

@MoY{@MoY}  = (0 .. scalar(@MoY));
@MoY{@MoYs} = (0 .. scalar(@MoYs));
@DoW{@DoW}  = (0 .. scalar(@DoW));
@DoW{@DoWs} = (0 .. scalar(@DoWs));

# Formatting routines

sub format_a { $DoWs[$_[0]->[6]] }
sub format_A { $DoW[$_[0]->[6]] }
sub format_b { $MoYs[$_[0]->[4]] }
sub format_B { $MoY[$_[0]->[4]] }
sub format_h { $MoYs[$_[0]->[4]] }
sub format_p { $_[0]->[2] >= 12 ?  $AMPM[1] : $AMPM[0] }

1;
PK4N%[�po��(perl5/Date/Language/TigrinyaEthiopian.pmnu��6�$##
## Tigrinya-Ethiopian tables
##

package Date::Language::TigrinyaEthiopian;

use Date::Language ();
use vars qw(@ISA @DoW @DoWs @MoY @MoYs @AMPM @Dsuf %MoY %DoW $VERSION);
@ISA = qw(Date::Language);
$VERSION = "1.00";

if ( $] >= 5.006 ) {
@DoW = (
"\x{1230}\x{1295}\x{1260}\x{1275}",
"\x{1230}\x{1291}\x{12ed}",
"\x{1230}\x{1209}\x{1235}",
"\x{1228}\x{1261}\x{12d5}",
"\x{1213}\x{1219}\x{1235}",
"\x{12d3}\x{122d}\x{1262}",
"\x{1240}\x{12f3}\x{121d}"
);
@MoY = (
"\x{1303}\x{1295}\x{12e9}\x{12c8}\x{122a}",
"\x{134c}\x{1265}\x{1229}\x{12c8}\x{122a}",
"\x{121b}\x{122d}\x{127d}",
"\x{12a4}\x{1355}\x{1228}\x{120d}",
"\x{121c}\x{12ed}",
"\x{1301}\x{1295}",
"\x{1301}\x{120b}\x{12ed}",
"\x{12a6}\x{1308}\x{1235}\x{1275}",
"\x{1234}\x{1355}\x{1274}\x{121d}\x{1260}\x{122d}",
"\x{12a6}\x{12ad}\x{1270}\x{12cd}\x{1260}\x{122d}",
"\x{1296}\x{126c}\x{121d}\x{1260}\x{122d}",
"\x{12f2}\x{1234}\x{121d}\x{1260}\x{122d}"
);
@DoWs = map { substr($_,0,3) } @DoW;
@MoYs = map { substr($_,0,3) } @MoY;
@AMPM = (
"\x{1295}/\x{1230}",
"\x{12F5}/\x{1230}"
);

@Dsuf = ("\x{12ed}" x 31);
}
else {
@DoW = (
"ሰንበት",
"ሰኑይ",
"ሰሉስ",
"ረቡዕ",
"ሓሙስ",
"ዓርቢ",
"ቀዳም"
);
@MoY = (
"ጃንዩወሪ",
"ፌብሩወሪ",
"ማርች",
"ኤፕረል",
"ሜይ",
"ጁን",
"ጁላይ",
"ኦገስት",
"ሴፕቴምበር",
"ኦክተውበር",
"ኖቬምበር",
"ዲሴምበር"
);
@DoWs = map { substr($_,0,9) } @DoW;
@MoYs = map { substr($_,0,9) } @MoY;
@AMPM = (
"ን/ሰ",
"ድ/ሰ"
);

@Dsuf = ("ይ" x 31);
}

@MoY{@MoY}  = (0 .. scalar(@MoY));
@MoY{@MoYs} = (0 .. scalar(@MoYs));
@DoW{@DoW}  = (0 .. scalar(@DoW));
@DoW{@DoWs} = (0 .. scalar(@DoWs));

# Formatting routines

sub format_a { $DoWs[$_[0]->[6]] }
sub format_A { $DoW[$_[0]->[6]] }
sub format_b { $MoYs[$_[0]->[4]] }
sub format_B { $MoY[$_[0]->[4]] }
sub format_h { $MoYs[$_[0]->[4]] }
sub format_p { $_[0]->[2] >= 12 ?  $AMPM[1] : $AMPM[0] }

1;
PK4N%[���perl5/Date/Language/Danish.pmnu��6�$##
## Danish tables
##

package Date::Language::Danish;

use Date::Language ();
use vars qw(@ISA @DoW @DoWs @MoY @MoYs @AMPM @Dsuf %MoY %DoW $VERSION);
@ISA = qw(Date::Language);
$VERSION = "1.01";

@MoY  = qw(Januar Februar Marts April Maj Juni
	   Juli August September Oktober November December);
@MoYs = qw(Jan Feb Mar Apr Maj Jun Jul Aug Sep Okt Nov Dec);
@DoW  = qw(S�ndag Mandag Tirsdag Onsdag Torsdag Fredag L�rdag S�ndag);
@DoWs = qw(S�n Man Tir Ons Tor Fre L�r S�n);

use Date::Language::English ();
@AMPM =   @{Date::Language::English::AMPM};
@Dsuf =   @{Date::Language::English::Dsuf};

@MoY{@MoY}  = (0 .. scalar(@MoY));
@MoY{@MoYs} = (0 .. scalar(@MoYs));
@DoW{@DoW}  = (0 .. scalar(@DoW));
@DoW{@DoWs} = (0 .. scalar(@DoWs));

# Formatting routines

sub format_a { $DoWs[$_[0]->[6]] }
sub format_A { $DoW[$_[0]->[6]] }
sub format_b { $MoYs[$_[0]->[4]] }
sub format_B { $MoY[$_[0]->[4]] }
sub format_h { $MoYs[$_[0]->[4]] }
sub format_p { $_[0]->[2] >= 12 ?  $AMPM[1] : $AMPM[0] }

1;
PK4N%[{K�

$perl5/Date/Language/Russian_koi8r.pmnu�7��m##
## Russian koi8r
##

package Date::Language::Russian_koi8r;

use Date::Language ();
use vars qw(@ISA @DoW @DoWs @MoY @MoYs @AMPM @Dsuf %MoY %DoW $VERSION);
@ISA = qw(Date::Language);
$VERSION = "1.01";

@DoW = qw(����������� ����������� ������� ���� ������� ������ ������);
@MoY = qw(����� ������ ��� ������ �� ���
      ��� ������ �������� ������� ������ ������);
@DoWs = qw(��� ��� ��� ��� ��� ��� ���);
#@DoWs = map { substr($_,0,3) } @DoW;
@MoYs = map { substr($_,0,3) } @MoY;
@AMPM = qw(AM PM);

@Dsuf = ('e') x 31;
#@Dsuf[11,12,13] = qw(� � �);
#@Dsuf[30,31] = qw(� �);

@MoY{@MoY}  = (0 .. scalar(@MoY));
@MoY{@MoYs} = (0 .. scalar(@MoYs));
@DoW{@DoW}  = (0 .. scalar(@DoW));
@DoW{@DoWs} = (0 .. scalar(@DoWs));

# Formatting routines

sub format_a { $DoWs[$_[0]->[6]] }
sub format_A { $DoW[$_[0]->[6]] }
sub format_b { $MoYs[$_[0]->[4]] }
sub format_B { $MoY[$_[0]->[4]] }
sub format_h { $MoYs[$_[0]->[4]] }
sub format_p { $_[0]->[2] >= 12 ?  $AMPM[1] : $AMPM[0] }
sub format_o { sprintf("%2de",$_[0]->[3]) }

1;
PK4N%[N�zzperl5/Date/Language/Afar.pmnu��6�$##
## Afar tables
##

package Date::Language::Afar;

use Date::Language ();
use vars qw(@ISA @DoW @DoWs @MoY @MoYs @AMPM @Dsuf %MoY %DoW $VERSION);
@ISA = qw(Date::Language);
$VERSION = "0.99";

@DoW = qw(Acaada Etleeni Talaata Arbaqa Kamiisi Gumqata Sabti);
@MoY = (
"Qunxa Garablu",
"Kudo",
"Ciggilta Kudo",
"Agda Baxis",
"Caxah Alsa",
"Qasa Dirri",
"Qado Dirri",
"Liiqen",
"Waysu",
"Diteli",
"Ximoli",
"Kaxxa Garablu"
);
@DoWs = map { substr($_,0,3) } @DoW;
@MoYs = map { substr($_,0,3) } @MoY;
@AMPM = qw(saaku carra);

@Dsuf = (qw(th st nd rd th th th th th th)) x 3;
@Dsuf[11,12,13] = qw(th th th);
@Dsuf[30,31] = qw(th st);

@MoY{@MoY}  = (0 .. scalar(@MoY));
@MoY{@MoYs} = (0 .. scalar(@MoYs));
@DoW{@DoW}  = (0 .. scalar(@DoW));
@DoW{@DoWs} = (0 .. scalar(@DoWs));

# Formatting routines

sub format_a { $DoWs[$_[0]->[6]] }
sub format_A { $DoW[$_[0]->[6]] }
sub format_b { $MoYs[$_[0]->[4]] }
sub format_B { $MoY[$_[0]->[4]] }
sub format_h { $MoYs[$_[0]->[4]] }
sub format_p { $_[0]->[2] >= 12 ?  $AMPM[1] : $AMPM[0] }

1;
PK4N%[�1UUU perl5/Date/Language/Hungarian.pmnu��6�$##
## Hungarian tables based on English
##
#
# This is a just-because-I-stumbled-across-it
# -and-my-wife-is-Hungarian release: if Graham or
# someone adds to docs to Date::Format, I'd be
# glad to correct bugs and extend as neeed.
#

package Date::Language::Hungarian;

=head1 NAME

Date::Language::Hungarian - Magyar format for Date::Format

=head1 SYNOPSIS

	my $lang = Date::Language->new('Hungarian');
	print $lang->time2str("%a %b %e %T %Y", time);

	@lt = localtime(time);
	print $lang->time2str($template, time);
	print $lang->strftime($template, @lt);

	print $lang->time2str($template, time, $zone);
	print $lang->strftime($template, @lt, $zone);

	print $lang->ctime(time);
	print $lang->asctime(@lt);

	print $lang->ctime(time, $zone);
	print $lang->asctime(@lt, $zone);

See L<Date::Format>.

=head1 AUTHOR

Paula Goddard (paula -at- paulacska -dot- com)

=head1 LICENCE

Made available under the same terms as Perl itself.

=cut

use strict;
use warnings;
use base "Date::Language";
use vars qw( @DoW @DoWs @MoY @MoYs @AMPM @Dsuf %MoY %DoW $VERSION);
$VERSION = "1.01";

@DoW = qw(Vas�rnap H�tf� Kedd Szerda Cs�t�rt�k P�ntek Szombat);
@MoY = qw(Janu�r Febru�r M�rcius �prilis M�jus J�nius
	  J�lius Augusztus Szeptember Okt�ber November December);
@DoWs = map { substr($_,0,3) } @DoW;
@MoYs = map { substr($_,0,3) } @MoY;
@AMPM = qw(DE. DU.);

# There is no 'th or 'nd in Hungarian, just a dot
@Dsuf = (".") x 31;

@MoY{@MoY}  = (0 .. scalar(@MoY));
@MoY{@MoYs} = (0 .. scalar(@MoYs));
@DoW{@DoW}  = (0 .. scalar(@DoW));
@DoW{@DoWs} = (0 .. scalar(@DoWs));

# Formatting routines

sub format_a { $DoWs[$_[0]->[6]] }
sub format_A { $DoW[$_[0]->[6]] }
sub format_b { $MoYs[$_[0]->[4]] }
sub format_B { $MoY[$_[0]->[4]] }
sub format_h { $MoYs[$_[0]->[4]] }
sub format_p { $_[0]->[2] >= 12 ?  $AMPM[1] : $AMPM[0] }
sub format_P { lc($_[0]->[2] >= 12 ?  $AMPM[1] : $AMPM[0]) }
sub format_o { $_[0]->[3].'.' }



sub format_D { &format_y . "." . &format_m . "." . &format_d  }

sub format_y { sprintf("%02d",$_[0]->[5] % 100) }
sub format_d { sprintf("%02d",$_[0]->[3]) }
sub format_m { sprintf("%02d",$_[0]->[4] + 1) }


1;
PK4N%[���<��perl5/Date/Language/Italian.pmnu��6�$##
## Italian tables
##

package Date::Language::Italian;

use Date::Language ();
use vars qw(@ISA @DoW @DoWs @MoY @MoYs @AMPM @Dsuf %MoY %DoW $VERSION);
@ISA = qw(Date::Language);
$VERSION = "1.01";

@MoY  = qw(Gennaio Febbraio Marzo Aprile Maggio Giugno
	   Luglio Agosto Settembre Ottobre Novembre Dicembre);
@MoYs = qw(Gen Feb Mar Apr Mag Giu Lug Ago Set Ott Nov Dic);
@DoW  = qw(Domenica Lunedi Martedi Mercoledi Giovedi Venerdi Sabato);
@DoWs = qw(Dom Lun Mar Mer Gio Ven Sab);

use Date::Language::English ();
@AMPM =   @{Date::Language::English::AMPM};
@Dsuf =   @{Date::Language::English::Dsuf};

@MoY{@MoY}  = (0 .. scalar(@MoY));
@MoY{@MoYs} = (0 .. scalar(@MoYs));
@DoW{@DoW}  = (0 .. scalar(@DoW));
@DoW{@DoWs} = (0 .. scalar(@DoWs));

# Formatting routines

sub format_a { $DoWs[$_[0]->[6]] }
sub format_A { $DoW[$_[0]->[6]] }
sub format_b { $MoYs[$_[0]->[4]] }
sub format_B { $MoY[$_[0]->[4]] }
sub format_h { $MoYs[$_[0]->[4]] }
sub format_p { $_[0]->[2] >= 12 ?  $AMPM[1] : $AMPM[0] }

1;
PK4N%[Ŵ�-��perl5/Date/Language/Oromo.pmnu��6�$##
## Oromo tables
##

package Date::Language::Oromo;

use Date::Language ();
use vars qw(@ISA @DoW @DoWs @MoY @MoYs @AMPM @Dsuf %MoY %DoW $VERSION);
@ISA = qw(Date::Language);
$VERSION = "0.99";

@DoW = qw(Dilbata Wiixata Qibxata Roobii Kamiisa Jimaata Sanbata);
@MoY = qw(Amajjii Guraandhala Bitooteessa Elba Caamsa Waxabajjii
          Adooleessa Hagayya Fuulbana Onkololeessa Sadaasa Muddee);
@DoWs = map { substr($_,0,3) } @DoW;
@MoYs = map { substr($_,0,3) } @MoY;
@AMPM = qw(WD WB);

@Dsuf = (qw(th st nd rd th th th th th th)) x 3;
@Dsuf[11,12,13] = qw(th th th);
@Dsuf[30,31] = qw(th st);

@MoY{@MoY}  = (0 .. scalar(@MoY));
@MoY{@MoYs} = (0 .. scalar(@MoYs));
@DoW{@DoW}  = (0 .. scalar(@DoW));
@DoW{@DoWs} = (0 .. scalar(@DoWs));

# Formatting routines

sub format_a { $DoWs[$_[0]->[6]] }
sub format_A { $DoW[$_[0]->[6]] }
sub format_b { $MoYs[$_[0]->[4]] }
sub format_B { $MoY[$_[0]->[4]] }
sub format_h { $MoYs[$_[0]->[4]] }
sub format_p { $_[0]->[2] >= 12 ?  $AMPM[1] : $AMPM[0] }

1;
PK4N%['`=���perl5/Date/Language/Occitan.pmnu��6�$##
## Occitan tables, contributed by Quentn PAGÈS
##

package Date::Language::Occitan;

use Date::Language ();
use vars qw(@ISA @DoW @DoWs @MoY @MoYs @AMPM @Dsuf %MoY %DoW $VERSION);
@ISA = qw(Date::Language);
$VERSION = "1.04";

@DoW = qw(dimenge diluns dimars dimècres dijòus divendres dissabte);
@MoY = qw(genièr febrièr mars abrial mai junh 
          julhet agost octòbre novembre decembre);
@DoWs = map { substr($_,0,3) } @DoW;
@MoYs = map { substr($_,0,3) } @MoY;
$MoYs[6] = 'jul';
@AMPM = qw(AM PM);

@Dsuf = ((qw(er e e e e e e e e e)) x 3, 'er');

@MoY{@MoY}  = (0 .. scalar(@MoY));
@MoY{@MoYs} = (0 .. scalar(@MoYs));
@DoW{@DoW}  = (0 .. scalar(@DoW));
@DoW{@DoWs} = (0 .. scalar(@DoWs));

# Formatting routines

sub format_a { $DoWs[$_[0]->[6]] }
sub format_A { $DoW[$_[0]->[6]] }
sub format_b { $MoYs[$_[0]->[4]] }
sub format_B { $MoY[$_[0]->[4]] }
sub format_h { $MoYs[$_[0]->[4]] }
sub format_p { $_[0]->[2] >= 12 ?  $AMPM[1] : $AMPM[0] }

1;
PK4N%[�Y���%�%perl5/Date/Format.pmnu��6�$# Copyright (c) 1995-2009 Graham Barr. This program is free
# software; you can redistribute it and/or modify it under the same terms
# as Perl itself.

package Date::Format;

use     strict;
use     vars qw(@EXPORT @ISA $VERSION);
require Exporter;

$VERSION = "2.24";
@ISA     = qw(Exporter);
@EXPORT  = qw(time2str strftime ctime asctime);

sub time2str ($;$$)
{
 Date::Format::Generic->time2str(@_);
}

sub strftime ($\@;$)
{
 Date::Format::Generic->strftime(@_);
}

sub ctime ($;$)
{
 my($t,$tz) = @_;
 Date::Format::Generic->time2str("%a %b %e %T %Y\n", $t, $tz); 
}

sub asctime (\@;$)
{
 my($t,$tz) = @_;
 Date::Format::Generic->strftime("%a %b %e %T %Y\n", $t, $tz); 
}

##
##
##

package Date::Format::Generic;

use vars qw($epoch $tzname);
use Time::Zone;
use Time::Local;

sub ctime
{
 my($me,$t,$tz) = @_;
 $me->time2str("%a %b %e %T %Y\n", $t, $tz); 
}

sub asctime
{
 my($me,$t,$tz) = @_;
 $me->strftime("%a %b %e %T %Y\n", $t, $tz); 
}

sub _subs
{
 my $fn;
 $_[1] =~ s/
		%(O?[%a-zA-Z])
	   /
                ($_[0]->can("format_$1") || sub { $1 })->($_[0]);
	   /sgeox;

 $_[1];
}

sub strftime 
{
 my($pkg,$fmt,$time);

 ($pkg,$fmt,$time,$tzname) = @_;

 my $me = ref($pkg) ? $pkg : bless [];

 if(defined $tzname)
  {
   $tzname = uc $tzname;

   $tzname = sprintf("%+05d",$tzname)
	unless($tzname =~ /\D/);

   $epoch = timegm(@{$time}[0..5]);

   @$me = gmtime($epoch + tz_offset($tzname) - tz_offset());
  }
 else
  {
   @$me = @$time;
   undef $epoch;
  }

 _subs($me,$fmt);
}

sub time2str
{
 my($pkg,$fmt,$time);

 ($pkg,$fmt,$time,$tzname) = @_;

 my $me = ref($pkg) ? $pkg : bless [], $pkg;

 $epoch = $time;

 if(defined $tzname)
  {
   $tzname = uc $tzname;

   $tzname = sprintf("%+05d",$tzname)
	unless($tzname =~ /\D/);

   $time += tz_offset($tzname);
   @$me = gmtime($time);
  }
 else
  {
   @$me = localtime($time);
  }
 $me->[9] = $time;
 _subs($me,$fmt);
}

my(@DoW,@MoY,@DoWs,@MoYs,@AMPM,%format,@Dsuf);

@DoW = qw(Sunday Monday Tuesday Wednesday Thursday Friday Saturday);

@MoY = qw(January February March April May June
          July August September October November December);

@DoWs = map { substr($_,0,3) } @DoW;
@MoYs = map { substr($_,0,3) } @MoY;

@AMPM = qw(AM PM);

@Dsuf = (qw(th st nd rd th th th th th th)) x 3;
@Dsuf[11,12,13] = qw(th th th);
@Dsuf[30,31] = qw(th st);

%format = ('x' => "%m/%d/%y",
           'C' => "%a %b %e %T %Z %Y",
           'X' => "%H:%M:%S",
          );

my @locale;
my $locale = "/usr/share/lib/locale/LC_TIME/default";
local *LOCALE;

if(open(LOCALE,"$locale"))
 {
  chop(@locale = <LOCALE>);
  close(LOCALE);

  @MoYs = @locale[0 .. 11];
  @MoY  = @locale[12 .. 23];
  @DoWs = @locale[24 .. 30];
  @DoW  = @locale[31 .. 37];
  @format{"X","x","C"} =  @locale[38 .. 40];
  @AMPM = @locale[41 .. 42];
 }

sub wkyr {
    my($wstart, $wday, $yday) = @_;
    $wday = ($wday + 7 - $wstart) % 7;
    return int(($yday - $wday + 13) / 7 - 1);
}

##
## these 6 formatting routins need to be *copied* into the language
## specific packages
##

my @roman = ('',qw(I II III IV V VI VII VIII IX));
sub roman {
  my $n = shift;

  $n =~ s/(\d)$//;
  my $r = $roman[ $1 ];

  if($n =~ s/(\d)$//) {
    (my $t = $roman[$1]) =~ tr/IVX/XLC/;
    $r = $t . $r;
  }
  if($n =~ s/(\d)$//) {
    (my $t = $roman[$1]) =~ tr/IVX/CDM/;
    $r = $t . $r;
  }
  if($n =~ s/(\d)$//) {
    (my $t = $roman[$1]) =~ tr/IVX/M../;
    $r = $t . $r;
  }
  $r;
}

sub format_a { $DoWs[$_[0]->[6]] }
sub format_A { $DoW[$_[0]->[6]] }
sub format_b { $MoYs[$_[0]->[4]] }
sub format_B { $MoY[$_[0]->[4]] }
sub format_h { $MoYs[$_[0]->[4]] }
sub format_p { $_[0]->[2] >= 12 ?  $AMPM[1] : $AMPM[0] }
sub format_P { lc($_[0]->[2] >= 12 ?  $AMPM[1] : $AMPM[0]) }

sub format_d { sprintf("%02d",$_[0]->[3]) }
sub format_e { sprintf("%2d",$_[0]->[3]) }
sub format_H { sprintf("%02d",$_[0]->[2]) }
sub format_I { sprintf("%02d",$_[0]->[2] % 12 || 12)}
sub format_j { sprintf("%03d",$_[0]->[7] + 1) }
sub format_k { sprintf("%2d",$_[0]->[2]) }
sub format_l { sprintf("%2d",$_[0]->[2] % 12 || 12)}
sub format_L { $_[0]->[4] + 1 }
sub format_m { sprintf("%02d",$_[0]->[4] + 1) }
sub format_M { sprintf("%02d",$_[0]->[1]) }
sub format_q { sprintf("%01d",int($_[0]->[4] / 3) + 1) }
sub format_s { 
   $epoch = timelocal(@{$_[0]}[0..5])
	unless defined $epoch;
   sprintf("%d",$epoch) 
}
sub format_S { sprintf("%02d",$_[0]->[0]) }
sub format_U { wkyr(0, $_[0]->[6], $_[0]->[7]) }
sub format_w { $_[0]->[6] }
sub format_W { wkyr(1, $_[0]->[6], $_[0]->[7]) }
sub format_y { sprintf("%02d",$_[0]->[5] % 100) }
sub format_Y { sprintf("%04d",$_[0]->[5] + 1900) }

sub format_Z {
 my $o = tz_local_offset(timelocal(@{$_[0]}[0..5]));
 defined $tzname ? $tzname : uc tz_name($o, $_[0]->[8]);
}

sub format_z {
 my $t = timelocal(@{$_[0]}[0..5]);
 my $o = defined $tzname ? tz_offset($tzname, $t) : tz_offset(undef,$t);
 sprintf("%+03d%02d", int($o / 3600), int(abs($o) % 3600) / 60);
}

sub format_c { &format_x . " " . &format_X }
sub format_D { &format_m . "/" . &format_d . "/" . &format_y  }      
sub format_r { &format_I . ":" . &format_M . ":" . &format_S . " " . &format_p  }   
sub format_R { &format_H . ":" . &format_M }
sub format_T { &format_H . ":" . &format_M . ":" . &format_S }
sub format_t { "\t" }
sub format_n { "\n" }
sub format_o { sprintf("%2d%s",$_[0]->[3],$Dsuf[$_[0]->[3]]) }
sub format_x { my $f = $format{'x'}; _subs($_[0],$f); }
sub format_X { my $f = $format{'X'}; _subs($_[0],$f); }
sub format_C { my $f = $format{'C'}; _subs($_[0],$f); }

sub format_Od { roman(format_d(@_)) }
sub format_Oe { roman(format_e(@_)) }
sub format_OH { roman(format_H(@_)) }
sub format_OI { roman(format_I(@_)) }
sub format_Oj { roman(format_j(@_)) }
sub format_Ok { roman(format_k(@_)) }
sub format_Ol { roman(format_l(@_)) }
sub format_Om { roman(format_m(@_)) }
sub format_OM { roman(format_M(@_)) }
sub format_Oq { roman(format_q(@_)) }
sub format_Oy { roman(format_y(@_)) }
sub format_OY { roman(format_Y(@_)) }

sub format_G { int(($_[0]->[9] - 315993600) / 604800) }

1;
__END__

=head1 NAME

Date::Format - Date formating subroutines

=head1 SYNOPSIS

	use Date::Format;
	
	@lt = localtime(time);
	
	print time2str($template, time);
	print strftime($template, @lt);
	
	print time2str($template, time, $zone);
	print strftime($template, @lt, $zone);
	
	print ctime(time);
	print asctime(@lt);
	
	print ctime(time, $zone);
	print asctime(@lt, $zone);

=head1 DESCRIPTION

This module provides routines to format dates into ASCII strings. They
correspond to the C library routines C<strftime> and C<ctime>.

=over 4

=item time2str(TEMPLATE, TIME [, ZONE])

C<time2str> converts C<TIME> into an ASCII string using the conversion
specification given in C<TEMPLATE>. C<ZONE> if given specifies the zone
which the output is required to be in, C<ZONE> defaults to your current zone.


=item strftime(TEMPLATE, TIME [, ZONE])

C<strftime> is similar to C<time2str> with the exception that the time is
passed as an array, such as the array returned by C<localtime>.

=item ctime(TIME [, ZONE])

C<ctime> calls C<time2str> with the given arguments using the
conversion specification C<"%a %b %e %T %Y\n">

=item asctime(TIME [, ZONE])

C<asctime> calls C<time2str> with the given arguments using the
conversion specification C<"%a %b %e %T %Y\n">

=back

=head1 MULTI-LANGUAGE SUPPORT

Date::Format is capable of formating into several languages by creating
a language specific object and calling methods, see L<Date::Language>

	my $lang = Date::Language->new('German');
	$lang->time2str("%a %b %e %T %Y\n", time);

I am open to suggestions on this.

=head1 CONVERSION SPECIFICATION

Each conversion specification  is  replaced  by  appropriate
characters   as   described  in  the  following  list.   The
appropriate  characters  are  determined  by   the   LC_TIME
category of the program's locale.

	%%	PERCENT
	%a	day of the week abbr
	%A	day of the week
	%b	month abbr
	%B 	month
	%c	MM/DD/YY HH:MM:SS
	%C 	ctime format: Sat Nov 19 21:05:57 1994
	%d 	numeric day of the month, with leading zeros (eg 01..31)
	%e 	like %d, but a leading zero is replaced by a space (eg  1..32)
	%D 	MM/DD/YY
	%G	GPS week number (weeks since January 6, 1980)
	%h 	month abbr
	%H 	hour, 24 hour clock, leading 0's)
	%I 	hour, 12 hour clock, leading 0's)
	%j 	day of the year
	%k 	hour
	%l 	hour, 12 hour clock
	%L 	month number, starting with 1
	%m 	month number, starting with 01
	%M 	minute, leading 0's
	%n 	NEWLINE
	%o	ornate day of month -- "1st", "2nd", "25th", etc.
	%p 	AM or PM 
	%P 	am or pm (Yes %p and %P are backwards :)
	%q	Quarter number, starting with 1
	%r 	time format: 09:05:57 PM
	%R 	time format: 21:05
	%s	seconds since the Epoch, UCT
	%S 	seconds, leading 0's
	%t 	TAB
	%T 	time format: 21:05:57
	%U 	week number, Sunday as first day of week
	%w 	day of the week, numerically, Sunday == 0
	%W 	week number, Monday as first day of week
	%x 	date format: 11/19/94
	%X 	time format: 21:05:57
	%y	year (2 digits)
	%Y	year (4 digits)
	%Z 	timezone in ascii. eg: PST
	%z	timezone in format -/+0000

C<%d>, C<%e>, C<%H>, C<%I>, C<%j>, C<%k>, C<%l>, C<%m>, C<%M>, C<%q>,
C<%y> and C<%Y> can be output in Roman numerals by prefixing the letter
with C<O>, e.g. C<%OY> will output the year as roman numerals.

=head1 LIMITATION

The functions in this module are limited to the time range that can be
represented by the time_t data type, i.e. 1901-12-13 20:45:53 GMT to
2038-01-19 03:14:07 GMT.

=head1 AUTHOR

Graham Barr <gbarr@pobox.com>

=head1 COPYRIGHT

Copyright (c) 1995-2009 Graham Barr. This program is free
software; you can redistribute it and/or modify it under the same terms
as Perl itself.

=cut


PK4N%[U�N��#�#perl5/Date/Parse.pmnu��6�$# Copyright (c) 1995-2009 Graham Barr. This program is free
# software; you can redistribute it and/or modify it under the same terms
# as Perl itself.

package Date::Parse;

require 5.000;
use strict;
use vars qw($VERSION @ISA @EXPORT);
use Time::Local;
use Carp;
use Time::Zone;
use Exporter;

@ISA = qw(Exporter);
@EXPORT = qw(&strtotime &str2time &strptime);

$VERSION = "2.33";

my %month = (
	january		=> 0,
	february	=> 1,
	march		=> 2,
	april		=> 3,
	may		=> 4,
	june		=> 5,
	july		=> 6,
	august		=> 7,
	september	=> 8,
	sept		=> 8,
	october		=> 9,
	november	=> 10,
	december	=> 11,
	);

my %day = (
	sunday		=> 0,
	monday		=> 1,
	tuesday		=> 2,
	tues		=> 2,
	wednesday	=> 3,
	wednes		=> 3,
	thursday	=> 4,
	thur		=> 4,
	thurs		=> 4,
	friday		=> 5,
	saturday	=> 6,
	);

my @suf = (qw(th st nd rd th th th th th th)) x 3;
@suf[11,12,13] = qw(th th th);

#Abbreviations

map { $month{substr($_,0,3)} = $month{$_} } keys %month;
map { $day{substr($_,0,3)}   = $day{$_} }   keys %day;

my $strptime = <<'ESQ';
 my %month = map { lc $_ } %$mon_ref;
 my $daypat = join("|", map { lc $_ } reverse sort keys %$day_ref);
 my $monpat = join("|", reverse sort keys %month);
 my $sufpat = join("|", reverse sort map { lc $_ } @$suf_ref);

 my %ampm = (
	'a' => 0,  # AM
	'p' => 12, # PM
	);

 my($AM, $PM) = (0,12);

sub {

  my $dtstr = lc shift;
  my $merid = 24;

  my($century,$year,$month,$day,$hh,$mm,$ss,$zone,$dst,$frac);

  $zone = tz_offset(shift) if @_;

  1 while $dtstr =~ s#\([^\(\)]*\)# #o;

  $dtstr =~ s#(\A|\n|\Z)# #sog;

  # ignore day names
  $dtstr =~ s#([\d\w\s])[\.\,]\s#$1 #sog;
  $dtstr =~ s/,/ /g;
  $dtstr =~ s#($daypat)\s*(den\s)?\b# #o;
  # Time: 12:00 or 12:00:00 with optional am/pm

  return unless $dtstr =~ /\S/;
  
  if ($dtstr =~ s/\s(\d{4})([-:]?)(\d\d?)\2(\d\d?)(?:[-Tt ](\d\d?)(?:([-:]?)(\d\d?)(?:\6(\d\d?)(?:[.,](\d+))?)?)?)?(?=\D)/ /) {
    ($year,$month,$day,$hh,$mm,$ss,$frac) = ($1,$3-1,$4,$5,$7,$8,$9);
  }

  unless (defined $hh) {
    if ($dtstr =~ s#[:\s](\d\d?):(\d\d?)(:(\d\d?)(?:\.\d+)?)?(z)?\s*(?:([ap])\.?m?\.?)?\s# #o) {
      ($hh,$mm,$ss) = ($1,$2,$4);
      $zone = 0 if $5;
      $merid = $ampm{$6} if $6;
    }

    # Time: 12 am
    
    elsif ($dtstr =~ s#\s(\d\d?)\s*([ap])\.?m?\.?\s# #o) {
      ($hh,$mm,$ss) = ($1,0,0);
      $merid = $ampm{$2};
    }
  }
    
  if (defined $hh and $hh <= 12 and $dtstr =~ s# ([ap])\.?m?\.?\s# #o) {
    $merid = $ampm{$1};
  }


  unless (defined $year) {
    # Date: 12-June-96 (using - . or /)
    
    if ($dtstr =~ s#\s(\d\d?)([\-\./])($monpat)(\2(\d\d+))?\s# #o) {
      ($month,$day) = ($month{$3},$1);
      $year = $5 if $5;
    }
    
    # Date: 12-12-96 (using '-', '.' or '/' )
    
    elsif ($dtstr =~ s#\s(\d+)([\-\./])(\d\d?)(\2(\d+))?\s# #o) {
      ($month,$day) = ($1 - 1,$3);

      if ($5) {
	$year = $5;
	# Possible match for 1995-01-24 (short mainframe date format);
	($year,$month,$day) = ($1, $3 - 1, $5) if $month > 12;
	return if length($year) > 2 and $year < 1901;
      }
    }
    elsif ($dtstr =~ s#\s(\d+)\s*($sufpat)?\s*($monpat)# #o) {
      ($month,$day) = ($month{$3},$1);
    }
    elsif ($dtstr =~ s#($monpat)\s*(\d+)\s*($sufpat)?\s# #o) {
      ($month,$day) = ($month{$1},$2);
    }
    elsif ($dtstr =~ s#($monpat)([\/-])(\d+)[\/-]# #o) {
      ($month,$day) = ($month{$1},$3);
    }

    # Date: 961212

    elsif ($dtstr =~ s#\s(\d\d)(\d\d)(\d\d)\s# #o) {
      ($year,$month,$day) = ($1,$2-1,$3);
    }

    $year = $1 if !defined($year) and $dtstr =~ s#\s(\d{2}(\d{2})?)[\s\.,]# #o;

  }

  # Zone

  $dst = 1 if $dtstr =~ s#\bdst\b##o;

  if ($dtstr =~ s#\s"?([a-z]{3,4})(dst|\d+[a-z]*|_[a-z]+)?"?\s# #o) {
    $dst = 1 if $2 and $2 eq 'dst';
    $zone = tz_offset($1);
    return unless defined $zone;
  }
  elsif ($dtstr =~ s#\s([a-z]{3,4})?([\-\+]?)-?(\d\d?):?(\d\d)?(00)?\s# #o) {
    my $m = defined($4) ? "$2$4" : 0;
    my $h = "$2$3";
    $zone = defined($1) ? tz_offset($1) : 0;
    return unless defined $zone;
    $zone += 60 * ($m + (60 * $h));
  }

  if ($dtstr =~ /\S/) {
    # now for some dumb dates
    if ($dtstr =~ s/^\s*(ut?|z)\s*$//) {
      $zone = 0;
    }
    elsif ($dtstr =~ s#\s([a-z]{3,4})?([\-\+]?)-?(\d\d?)(\d\d)?(00)?\s# #o) {
      my $m = defined($4) ? "$2$4" : 0;
      my $h = "$2$3";
      $zone = defined($1) ? tz_offset($1) : 0;
      return unless defined $zone;
      $zone += 60 * ($m + (60 * $h));
    }

    return if $dtstr =~ /\S/o;
  }

  if (defined $hh) {
    if ($hh == 12) {
      $hh = 0 if $merid == $AM;
    }
    elsif ($merid == $PM) {
      $hh += 12;
    }
  }

  if (defined $year && $year > 1900) {
    $century = int($year / 100);
    $year -= 1900;
  }

  $zone += 3600 if defined $zone && $dst;
  $ss += "0.$frac" if $frac;

  return ($ss,$mm,$hh,$day,$month,$year,$zone,$century);
}
ESQ

use vars qw($day_ref $mon_ref $suf_ref $obj);

sub gen_parser
{
 local($day_ref,$mon_ref,$suf_ref,$obj) = @_;

 if($obj)
  {
   my $obj_strptime = $strptime;
   substr($obj_strptime,index($strptime,"sub")+6,0) = <<'ESQ';
 shift; # package
ESQ
   my $sub = eval "$obj_strptime" or die $@;
   return $sub;
  }

 eval "$strptime" or die $@;

}

*strptime = gen_parser(\%day,\%month,\@suf);

sub str2time
{
 my @t = strptime(@_);

 return undef
	unless @t;

 my($ss,$mm,$hh,$day,$month,$year,$zone, $century) = @t;
 my @lt  = localtime(time);

 $hh    ||= 0;
 $mm    ||= 0;
 $ss    ||= 0;

 my $frac = $ss - int($ss);
 $ss = int $ss;

 $month = $lt[4]
	unless(defined $month);

 $day  = $lt[3]
	unless(defined $day);

 $year = ($month > $lt[4]) ? ($lt[5] - 1) : $lt[5]
	unless(defined $year);

 # we were given a 4 digit year, so let's keep using those
 $year += 1900 if defined $century;

 return undef
	unless($month <= 11 && $day >= 1 && $day <= 31
		&& $hh <= 23 && $mm <= 59 && $ss <= 59);

 my $result;

 if (defined $zone) {
   $result = eval {
     local $SIG{__DIE__} = sub {}; # Ick!
     timegm($ss,$mm,$hh,$day,$month,$year);
   };
   return undef
     if !defined $result
        or $result == -1
           && join("",$ss,$mm,$hh,$day,$month,$year)
     	        ne "595923311169";
   $result -= $zone;
 }
 else {
   $result = eval {
     local $SIG{__DIE__} = sub {}; # Ick!
     timelocal($ss,$mm,$hh,$day,$month,$year);
   };
   return undef
     if !defined $result
        or $result == -1
           && join("",$ss,$mm,$hh,$day,$month,$year)
     	        ne join("",(localtime(-1))[0..5]);
 }

 return $result + $frac;
}

1;

__END__


=head1 NAME

Date::Parse - Parse date strings into time values

=head1 SYNOPSIS

	use Date::Parse;
	
	$time = str2time($date);
	
	($ss,$mm,$hh,$day,$month,$year,$zone) = strptime($date);

=head1 DESCRIPTION

C<Date::Parse> provides two routines for parsing date strings into time values.

=over 4

=item str2time(DATE [, ZONE])

C<str2time> parses C<DATE> and returns a unix time value, or undef upon failure.
C<ZONE>, if given, specifies the timezone to assume when parsing if the
date string does not specify a timezone.

=item strptime(DATE [, ZONE])

C<strptime> takes the same arguments as str2time but returns an array of
values C<($ss,$mm,$hh,$day,$month,$year,$zone,$century)>. Elements are only
defined if they could be extracted from the date string. The C<$zone> element
is the timezone offset in seconds from GMT. An empty array is returned upon
failure.

=back

=head1 MULTI-LANGUAGE SUPPORT

Date::Parse is capable of parsing dates in several languages, these include
English, French, German and Italian.

	$lang = Date::Language->new('German');
	$lang->str2time("25 Jun 1996 21:09:55 +0100");

=head1 EXAMPLE DATES

Below is a sample list of dates that are known to be parsable with Date::Parse

 1995:01:24T09:08:17.1823213           ISO-8601
 1995-01-24T09:08:17.1823213
 Wed, 16 Jun 94 07:29:35 CST           Comma and day name are optional 
 Thu, 13 Oct 94 10:13:13 -0700
 Wed, 9 Nov 1994 09:50:32 -0500 (EST)  Text in ()'s will be ignored.
 21 dec 17:05                          Will be parsed in the current time zone
 21-dec 17:05
 21/dec 17:05
 21/dec/93 17:05
 1999 10:02:18 "GMT"
 16 Nov 94 22:28:20 PST 

=head1 LIMITATION

Date::Parse uses L<Time::Local> internally, so is limited to only parsing dates
which result in valid values for Time::Local::timelocal. This generally means dates
between 1901-12-17 00:00:00 GMT and 2038-01-16 23:59:59 GMT

=head1 BUGS

When both the month and the date are specified in the date as numbers
they are always parsed assuming that the month number comes before the
date. This is the usual format used in American dates.

The reason why it is like this and not dynamic is that it must be
deterministic. Several people have suggested using the current locale,
but this will not work as the date being parsed may not be in the format
of the current locale.

My plans to address this, which will be in a future release, is to allow
the programmer to state what order they want these values parsed in.

=head1 AUTHOR

Graham Barr <gbarr@pobox.com>

=head1 COPYRIGHT

Copyright (c) 1995-2009 Graham Barr. This program is free
software; you can redistribute it and/or modify it under the same terms
as Perl itself.

=cut

PK4N%[�� Wl
l
perl5/Date/Language.pmnu��6�$
package Date::Language;

use     strict;
use     Time::Local;
use     Carp;
use     vars qw($VERSION @ISA);
require Date::Format;

$VERSION = "1.10";
@ISA     = qw(Date::Format::Generic);

sub new
{
 my $self = shift;
 my $type = shift || $self;

 $type =~ s/^(\w+)$/Date::Language::$1/;

 croak "Bad language"
	unless $type =~ /^[\w:]+$/;

 eval "require $type"
	or croak $@;

 bless [], $type;
}

# Stop AUTOLOAD being called ;-)
sub DESTROY {}

sub AUTOLOAD
{
 use vars qw($AUTOLOAD);

 if($AUTOLOAD =~ /::strptime\Z/o)
  {
   my $self = $_[0];
   my $type = ref($self) || $self;
   require Date::Parse;

   no strict 'refs';
   *{"${type}::strptime"} = Date::Parse::gen_parser(
	\%{"${type}::DoW"},
	\%{"${type}::MoY"},
	\@{"${type}::Dsuf"},
	1);

   goto &{"${type}::strptime"};
  }

 croak "Undefined method &$AUTOLOAD called";
}

sub str2time
{
 my $me = shift;
 my @t = $me->strptime(@_);

 return undef
	unless @t;

 my($ss,$mm,$hh,$day,$month,$year,$zone) = @t;
 my @lt  = localtime(time);

 $hh    ||= 0;
 $mm    ||= 0;
 $ss    ||= 0;

 $month = $lt[4]
	unless(defined $month);

 $day  = $lt[3]
	unless(defined $day);

 $year = ($month > $lt[4]) ? ($lt[5] - 1) : $lt[5]
	unless(defined $year);

 return defined $zone ? timegm($ss,$mm,$hh,$day,$month,$year) - $zone
    	    	      : timelocal($ss,$mm,$hh,$day,$month,$year);
}

1;

__END__


=head1 NAME

Date::Language - Language specific date formating and parsing

=head1 SYNOPSIS

  use Date::Language;

  my $lang = Date::Language->new('German');
  $lang->time2str("%a %b %e %T %Y\n", time);

=head1 DESCRIPTION

L<Date::Language> provides objects to parse and format dates for specific languages. Available languages are

  Afar                    French                  Russian_cp1251
  Amharic                 Gedeo                   Russian_koi8r
  Austrian                German                  Sidama
  Brazilian               Greek                   Somali
  Chinese                 Hungarian               Spanish
  Chinese_GB              Icelandic               Swedish
  Czech                   Italian                 Tigrinya
  Danish                  Norwegian               TigrinyaEritrean
  Dutch                   Oromo                   TigrinyaEthiopian
  English                 Romanian                Turkish
  Finnish                 Russian                 Bulgarian
  Occitan

=head1 METHODS

=over

=item time2str

See L<Date::Format/time2str>

=item strftime

See L<Date::Format/strftime>

=item ctime

See L<Date::Format/ctime>

=item asctime

See L<Date::Format/asctime>

=item str2time

See L<Date::Parse/str2time>

=item strptime

See L<Date::Parse/strptime>

=back

PK4N%[�Q�����perl5/App/Cpan.pmnu��6�$package App::Cpan;

use strict;
use warnings;
use vars qw($VERSION);

use if $] < 5.008 => 'IO::Scalar';

$VERSION = '1.678';

=head1 NAME

App::Cpan - easily interact with CPAN from the command line

=head1 SYNOPSIS

	# with arguments and no switches, installs specified modules
	cpan module_name [ module_name ... ]

	# with switches, installs modules with extra behavior
	cpan [-cfFimtTw] module_name [ module_name ... ]

	# use local::lib
	cpan -I module_name [ module_name ... ]

	# one time mirror override for faster mirrors
	cpan -p ...

	# with just the dot, install from the distribution in the
	# current directory
	cpan .

	# without arguments, starts CPAN.pm shell
	cpan

	# without arguments, but some switches
	cpan [-ahpruvACDLOPX]

=head1 DESCRIPTION

This script provides a command interface (not a shell) to CPAN. At the
moment it uses CPAN.pm to do the work, but it is not a one-shot command
runner for CPAN.pm.

=head2 Options

=over 4

=item -a

Creates a CPAN.pm autobundle with CPAN::Shell->autobundle.

=item -A module [ module ... ]

Shows the primary maintainers for the specified modules.

=item -c module

Runs a `make clean` in the specified module's directories.

=item -C module [ module ... ]

Show the F<Changes> files for the specified modules

=item -D module [ module ... ]

Show the module details. This prints one line for each out-of-date module
(meaning, modules locally installed but have newer versions on CPAN).
Each line has three columns: module name, local version, and CPAN
version.

=item -f

Force the specified action, when it normally would have failed. Use this
to install a module even if its tests fail. When you use this option,
-i is not optional for installing a module when you need to force it:

	% cpan -f -i Module::Foo

=item -F

Turn off CPAN.pm's attempts to lock anything. You should be careful with
this since you might end up with multiple scripts trying to muck in the
same directory. This isn't so much of a concern if you're loading a special
config with C<-j>, and that config sets up its own work directories.

=item -g module [ module ... ]

Downloads to the current directory the latest distribution of the module.

=item -G module [ module ... ]

UNIMPLEMENTED

Download to the current directory the latest distribution of the
modules, unpack each distribution, and create a git repository for each
distribution.

If you want this feature, check out Yanick Champoux's C<Git::CPAN::Patch>
distribution.

=item -h

Print a help message and exit. When you specify C<-h>, it ignores all
of the other options and arguments.

=item -i module [ module ... ]

Install the specified modules. With no other switches, this switch
is implied.

=item -I

Load C<local::lib> (think like C<-I> for loading lib paths). Too bad
C<-l> was already taken.

=item -j Config.pm

Load the file that has the CPAN configuration data. This should have the
same format as the standard F<CPAN/Config.pm> file, which defines
C<$CPAN::Config> as an anonymous hash.

If the file does not exist, C<cpan> dies.

=item -J

Dump the configuration in the same format that CPAN.pm uses. This is useful
for checking the configuration as well as using the dump as a starting point
for a new, custom configuration.

=item -l

List all installed modules with their versions

=item -L author [ author ... ]

List the modules by the specified authors.

=item -m

Make the specified modules.

=item -M mirror1,mirror2,...

A comma-separated list of mirrors to use for just this run. The C<-P>
option can find them for you automatically.

=item -n

Do a dry run, but don't actually install anything. (unimplemented)

=item -O

Show the out-of-date modules.

=item -p

Ping the configured mirrors and print a report

=item -P

Find the best mirrors you could be using and use them for the current
session.

=item -r

Recompiles dynamically loaded modules with CPAN::Shell->recompile.

=item -s

Drop in the CPAN.pm shell. This command does this automatically if you don't
specify any arguments.

=item -t module [ module ... ]

Run a `make test` on the specified modules.

=item -T

Do not test modules. Simply install them.

=item -u

Upgrade all installed modules. Blindly doing this can really break things,
so keep a backup.

=item -v

Print the script version and CPAN.pm version then exit.

=item -V

Print detailed information about the cpan client.

=item -w

UNIMPLEMENTED

Turn on cpan warnings. This checks various things, like directory permissions,
and tells you about problems you might have.

=item -x module [ module ... ]

Find close matches to the named modules that you think you might have
mistyped. This requires the optional installation of Text::Levenshtein or
Text::Levenshtein::Damerau.

=item -X

Dump all the namespaces to standard output.

=back

=head2 Examples

	# print a help message
	cpan -h

	# print the version numbers
	cpan -v

	# create an autobundle
	cpan -a

	# recompile modules
	cpan -r

	# upgrade all installed modules
	cpan -u

	# install modules ( sole -i is optional )
	cpan -i Netscape::Booksmarks Business::ISBN

	# force install modules ( must use -i )
	cpan -fi CGI::Minimal URI

	# install modules but without testing them
	cpan -Ti CGI::Minimal URI

=head2 Environment variables

There are several components in CPAN.pm that use environment variables.
The build tools, L<ExtUtils::MakeMaker> and L<Module::Build> use some,
while others matter to the levels above them. Some of these are specified
by the Perl Toolchain Gang:

Lancaster Consensus: L<https://github.com/Perl-Toolchain-Gang/toolchain-site/blob/master/lancaster-consensus.md>

Oslo Consensus: L<https://github.com/Perl-Toolchain-Gang/toolchain-site/blob/master/oslo-consensus.md>

=over 4

=item NONINTERACTIVE_TESTING

Assume no one is paying attention and skips prompts for distributions
that do that correctly. C<cpan(1)> sets this to C<1> unless it already
has a value (even if that value is false).

=item PERL_MM_USE_DEFAULT

Use the default answer for a prompted questions. C<cpan(1)> sets this
to C<1> unless it already has a value (even if that value is false).

=item CPAN_OPTS

As with C<PERL5OPT>, a string of additional C<cpan(1)> options to
add to those you specify on the command line.

=item CPANSCRIPT_LOGLEVEL

The log level to use, with either the embedded, minimal logger or
L<Log::Log4perl> if it is installed. Possible values are the same as
the C<Log::Log4perl> levels: C<TRACE>, C<DEBUG>, C<INFO>, C<WARN>,
C<ERROR>, and C<FATAL>. The default is C<INFO>.

=item GIT_COMMAND

The path to the C<git> binary to use for the Git features. The default
is C</usr/local/bin/git>.

=back

=head2 Methods

=over 4

=cut

use autouse Carp => qw(carp croak cluck);
use CPAN 1.80 (); # needs no test
use Config;
use autouse Cwd => qw(cwd);
use autouse 'Data::Dumper' => qw(Dumper);
use File::Spec::Functions qw(catfile file_name_is_absolute rel2abs);
use File::Basename;
use Getopt::Std;

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Internal constants
use constant TRUE  => 1;
use constant FALSE => 0;


# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# The return values
use constant HEY_IT_WORKED              =>   0;
use constant I_DONT_KNOW_WHAT_HAPPENED  =>   1; # 0b0000_0001
use constant ITS_NOT_MY_FAULT           =>   2;
use constant THE_PROGRAMMERS_AN_IDIOT   =>   4;
use constant A_MODULE_FAILED_TO_INSTALL =>   8;


# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# set up the order of options that we layer over CPAN::Shell
BEGIN { # most of this should be in methods
use vars qw( @META_OPTIONS $Default %CPAN_METHODS @CPAN_OPTIONS  @option_order
	%Method_table %Method_table_index );

@META_OPTIONS = qw( h v V I g G M: C A D O l L a r p P j: J w x X );

$Default = 'default';

%CPAN_METHODS = ( # map switches to method names in CPAN::Shell
	$Default => 'install',
	'c'      => 'clean',
	'f'      => 'force',
	'i'      => 'install',
	'm'      => 'make',
	't'      => 'test',
	'u'      => 'upgrade',
	'T'      => 'notest',
	's'      => 'shell',
	);
@CPAN_OPTIONS = grep { $_ ne $Default } sort keys %CPAN_METHODS;

@option_order = ( @META_OPTIONS, @CPAN_OPTIONS );


# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# map switches to the subroutines in this script, along with other information.
# use this stuff instead of hard-coded indices and values
sub NO_ARGS   () { 0 }
sub ARGS      () { 1 }
sub GOOD_EXIT () { 0 }

%Method_table = (
# key => [ sub ref, takes args?, exit value, description ]

	# options that do their thing first, then exit
	h =>  [ \&_print_help,          NO_ARGS, GOOD_EXIT, 'Printing help'                ],
	v =>  [ \&_print_version,       NO_ARGS, GOOD_EXIT, 'Printing version'             ],
	V =>  [ \&_print_details,       NO_ARGS, GOOD_EXIT, 'Printing detailed version'    ],
	X =>  [ \&_list_all_namespaces, NO_ARGS, GOOD_EXIT, 'Listing all namespaces'       ],

	# options that affect other options
	j =>  [ \&_load_config,          ARGS, GOOD_EXIT, 'Use specified config file'    ],
	J =>  [ \&_dump_config,       NO_ARGS, GOOD_EXIT, 'Dump configuration to stdout' ],
	F =>  [ \&_lock_lobotomy,     NO_ARGS, GOOD_EXIT, 'Turn off CPAN.pm lock files'  ],
	I =>  [ \&_load_local_lib,    NO_ARGS, GOOD_EXIT, 'Loading local::lib'           ],
	M =>  [ \&_use_these_mirrors,    ARGS, GOOD_EXIT, 'Setting per session mirrors'  ],
	P =>  [ \&_find_good_mirrors, NO_ARGS, GOOD_EXIT, 'Finding good mirrors'         ],
	w =>  [ \&_turn_on_warnings,  NO_ARGS, GOOD_EXIT, 'Turning on warnings'          ],

	# options that do their one thing
	g =>  [ \&_download,             ARGS, GOOD_EXIT, 'Download the latest distro'        ],
	G =>  [ \&_gitify,               ARGS, GOOD_EXIT, 'Down and gitify the latest distro' ],

	C =>  [ \&_show_Changes,         ARGS, GOOD_EXIT, 'Showing Changes file'         ],
	A =>  [ \&_show_Author,          ARGS, GOOD_EXIT, 'Showing Author'               ],
	D =>  [ \&_show_Details,         ARGS, GOOD_EXIT, 'Showing Details'              ],
	O =>  [ \&_show_out_of_date,  NO_ARGS, GOOD_EXIT, 'Showing Out of date'          ],
	l =>  [ \&_list_all_mods,     NO_ARGS, GOOD_EXIT, 'Listing all modules'          ],

	L =>  [ \&_show_author_mods,     ARGS, GOOD_EXIT, 'Showing author mods'          ],
	a =>  [ \&_create_autobundle, NO_ARGS, GOOD_EXIT, 'Creating autobundle'          ],
	p =>  [ \&_ping_mirrors,      NO_ARGS, GOOD_EXIT, 'Pinging mirrors'              ],

	r =>  [ \&_recompile,         NO_ARGS, GOOD_EXIT, 'Recompiling'                  ],
	u =>  [ \&_upgrade,           NO_ARGS, GOOD_EXIT, 'Running `make test`'          ],
	's' => [ \&_shell,            NO_ARGS, GOOD_EXIT, 'Drop into the CPAN.pm shell'  ],

	'x' => [ \&_guess_namespace,     ARGS, GOOD_EXIT, 'Guessing namespaces'          ],
	c =>  [ \&_default,              ARGS, GOOD_EXIT, 'Running `make clean`'         ],
	f =>  [ \&_default,              ARGS, GOOD_EXIT, 'Installing with force'        ],
	i =>  [ \&_default,              ARGS, GOOD_EXIT, 'Running `make install`'       ],
	'm' => [ \&_default,             ARGS, GOOD_EXIT, 'Running `make`'               ],
	t =>  [ \&_default,              ARGS, GOOD_EXIT, 'Running `make test`'          ],
	T =>  [ \&_default,              ARGS, GOOD_EXIT, 'Installing with notest'       ],
	);

%Method_table_index = (
	code        => 0,
	takes_args  => 1,
	exit_value  => 2,
	description => 3,
	);
}


# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# finally, do some argument processing

sub _stupid_interface_hack_for_non_rtfmers
	{
	no warnings 'uninitialized';
	shift @ARGV if( $ARGV[0] eq 'install' and @ARGV > 1 )
	}

sub _process_options
	{
	my %options;

	push @ARGV, grep $_, split /\s+/, $ENV{CPAN_OPTS} || '';

	# if no arguments, just drop into the shell
	if( 0 == @ARGV ) { CPAN::shell(); exit 0 }
	elsif (Getopt::Std::getopts(
		  join( '', @option_order ), \%options ))
		{
		 \%options;
		}
	else { exit 1 }
}

sub _process_setup_options
	{
	my( $class, $options ) = @_;

	if( $options->{j} )
		{
		$Method_table{j}[ $Method_table_index{code} ]->( $options->{j} );
		delete $options->{j};
		}
	elsif ( ! $options->{h} ) { # h "ignores all of the other options and arguments"
		# this is what CPAN.pm would do otherwise
		local $CPAN::Be_Silent = 1;
		CPAN::HandleConfig->load(
			# be_silent  => 1, deprecated
			write_file => 0,
			);
		}

	$class->_turn_off_testing if $options->{T};

	foreach my $o ( qw(F I w P M) )
		{
		next unless exists $options->{$o};
		$Method_table{$o}[ $Method_table_index{code} ]->( $options->{$o} );
		delete $options->{$o};
		}

	if( $options->{o} )
		{
		my @pairs = map { [ split /=/, $_, 2 ] } split /,/, $options->{o};
		foreach my $pair ( @pairs )
			{
			my( $setting, $value ) = @$pair;
			$CPAN::Config->{$setting} = $value;
		#	$logger->debug( "Setting [$setting] to [$value]" );
			}
		delete $options->{o};
		}

	my $option_count = grep { $options->{$_} } @option_order;
	no warnings 'uninitialized';

	# don't count options that imply installation
	foreach my $opt ( qw(f T) ) { # don't count force or notest
		$option_count -= $options->{$opt};
		}

	# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
	# if there are no options, set -i (this line fixes RT ticket 16915)
	$options->{i}++ unless $option_count;
	}

sub _setup_environment {
# should we override or set defaults? If this were a true interactive
# session, we'd be in the CPAN shell.

# https://github.com/Perl-Toolchain-Gang/toolchain-site/blob/master/lancaster-consensus.md
	$ENV{NONINTERACTIVE_TESTING} = 1 unless defined $ENV{NONINTERACTIVE_TESTING};
	$ENV{PERL_MM_USE_DEFAULT}    = 1 unless defined $ENV{PERL_MM_USE_DEFAULT};
	}

=item run( ARGS )

Just do it.

The C<run> method returns 0 on success and a positive number on
failure. See the section on EXIT CODES for details on the values.

=cut

my $logger;

sub run
	{
	my( $class, @args ) = @_;
	local @ARGV = @args;
	my $return_value = HEY_IT_WORKED; # assume that things will work

	$logger = $class->_init_logger;
	$logger->debug( "Using logger from @{[ref $logger]}" );

	$class->_hook_into_CPANpm_report;
	$logger->debug( "Hooked into output" );

	$class->_stupid_interface_hack_for_non_rtfmers;
	$logger->debug( "Patched cargo culting" );

	my $options = $class->_process_options;
	$logger->debug( "Options are @{[Dumper($options)]}" );

	$class->_process_setup_options( $options );

	$class->_setup_environment( $options );

	OPTION: foreach my $option ( @option_order )
		{
		next unless $options->{$option};

		my( $sub, $takes_args, $description ) =
			map { $Method_table{$option}[ $Method_table_index{$_} ] }
			qw( code takes_args description );

		unless( ref $sub eq ref sub {} )
			{
			$return_value = THE_PROGRAMMERS_AN_IDIOT;
			last OPTION;
			}

		$logger->info( "[$option] $description -- ignoring other arguments" )
			if( @ARGV && ! $takes_args );

		$return_value = $sub->( \ @ARGV, $options );

		last;
		}

	return $return_value;
	}

my $LEVEL;
{
package
  Local::Null::Logger; # hide from PAUSE

my @LOGLEVELS = qw(TRACE DEBUG INFO WARN ERROR FATAL);
$LEVEL        = uc($ENV{CPANSCRIPT_LOGLEVEL} || 'INFO');
my %LL        = map { $LOGLEVELS[$_] => $_ } 0..$#LOGLEVELS;
unless (defined $LL{$LEVEL}){
	warn "Unsupported loglevel '$LEVEL', setting to INFO";
	$LEVEL = 'INFO';
}
sub new { bless \ my $x, $_[0] }
sub AUTOLOAD {
	my $autoload = our $AUTOLOAD;
	$autoload =~ s/.*://;
	return if $LL{uc $autoload} < $LL{$LEVEL};
	$CPAN::Frontend->mywarn(">($autoload): $_\n")
		for split /[\r\n]+/, $_[1];
}
sub DESTROY { 1 }
}

# load a module without searching the default entry for the current
# directory
sub _safe_load_module {
	my $name = shift;

	local @INC = @INC;
	pop @INC if $INC[-1] eq '.';

	eval "require $name; 1";
}

sub _init_logger
	{
	my $log4perl_loaded = _safe_load_module("Log::Log4perl");

	unless( $log4perl_loaded )
		{
		print STDOUT "Loading internal logger. Log::Log4perl recommended for better logging\n";
		$logger = Local::Null::Logger->new;
		return $logger;
		}

	Log::Log4perl::init( \ <<"HERE" );
log4perl.rootLogger=$LEVEL, A1
log4perl.appender.A1=Log::Log4perl::Appender::Screen
log4perl.appender.A1.layout=PatternLayout
log4perl.appender.A1.layout.ConversionPattern=%m%n
HERE

	$logger = Log::Log4perl->get_logger( 'App::Cpan' );
	}

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
 # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

sub _default
	{
	my( $args, $options ) = @_;

	my $switch = '';

	# choose the option that we're going to use
	# we'll deal with 'f' (force) later, so skip it
	foreach my $option ( @CPAN_OPTIONS )
		{
		next if ( $option eq 'f' or $option eq 'T' );
		next unless $options->{$option};
		$switch = $option;
		last;
		}

	# 1. with no switches, but arguments, use the default switch (install)
	# 2. with no switches and no args, start the shell
	# 3. With a switch but no args, die! These switches need arguments.
	   if( not $switch and     @$args ) { $switch = $Default;  }
	elsif( not $switch and not @$args ) { return CPAN::shell() }
	elsif(     $switch and not @$args )
		{ die "Nothing to $CPAN_METHODS{$switch}!\n"; }

	# Get and check the method from CPAN::Shell
	my $method = $CPAN_METHODS{$switch};
	die "CPAN.pm cannot $method!\n" unless CPAN::Shell->can( $method );

	# call the CPAN::Shell method, with force or notest if specified
	my $action = do {
		   if( $options->{f} ) { sub { CPAN::Shell->force( $method, @_ )  } }
		elsif( $options->{T} ) { sub { CPAN::Shell->notest( $method, @_ ) } }
		else                   { sub { CPAN::Shell->$method( @_ )         } }
		};

	# How do I handle exit codes for multiple arguments?
	my @errors = ();

	$options->{x} or _disable_guessers();

	foreach my $arg ( @$args )
		{
		# check the argument and perhaps capture typos
		my $module = _expand_module( $arg ) or do {
			$logger->error( "Skipping $arg because I couldn't find a matching namespace." );
			next;
			};

		_clear_cpanpm_output();
		$action->( $arg );

		my $error = _cpanpm_output_indicates_failure();
		push @errors, $error if $error;
		}

	return do {
		if( @errors ) { $errors[0] }
		else { HEY_IT_WORKED }
		};

	}

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

=for comment

CPAN.pm sends all the good stuff either to STDOUT, or to a temp
file if $CPAN::Be_Silent is set. I have to intercept that output
so I can find out what happened.

=cut

BEGIN {
my $scalar = '';

sub _hook_into_CPANpm_report
	{
	no warnings 'redefine';

	*CPAN::Shell::myprint = sub {
		my($self,$what) = @_;
		$scalar .= $what if defined $what;
		$self->print_ornamented($what,
			$CPAN::Config->{colorize_print}||'bold blue on_white',
			);
		};

	*CPAN::Shell::mywarn = sub {
		my($self,$what) = @_;
		$scalar .= $what if defined $what;
		$self->print_ornamented($what,
			$CPAN::Config->{colorize_warn}||'bold red on_white'
			);
		};

	}

sub _clear_cpanpm_output { $scalar = '' }

sub _get_cpanpm_output   { $scalar }

# These are lines I don't care about in CPAN.pm output. If I can
# filter out the informational noise, I have a better chance to
# catch the error signal
my @skip_lines = (
	qr/^\QWarning \(usually harmless\)/,
	qr/\bwill not store persistent state\b/,
	qr(//hint//),
	qr/^\s+reports\s+/,
	qr/^Try the command/,
	qr/^\s+$/,
	qr/^to find objects/,
	qr/^\s*Database was generated on/,
	qr/^Going to read/,
	qr|^\s+i\s+/|,    # the i /Foo::Whatever/ line when it doesn't know
	);

sub _get_cpanpm_last_line
	{
	my $fh;

	if( $] < 5.008 ) {
		$fh = IO::Scalar->new( \ $scalar );
		}
	else {
		eval q{ open $fh, '<', \\ $scalar; };
		}

	my @lines = <$fh>;

	# This is a bit ugly. Once we examine a line, we have to
	# examine the line before it and go through all of the same
	# regexes. I could do something fancy, but this works.
	REGEXES: {
	foreach my $regex ( @skip_lines )
		{
		if( $lines[-1] =~ m/$regex/ )
			{
			pop @lines;
			redo REGEXES; # we have to go through all of them for every line!
			}
		}
	}

	$logger->debug( "Last interesting line of CPAN.pm output is:\n\t$lines[-1]" );

	$lines[-1];
	}
}

BEGIN {
my $epic_fail_words = join '|',
	qw( Error stop(?:ping)? problems force not unsupported
		fail(?:ed)? Cannot\s+install );

sub _cpanpm_output_indicates_failure
	{
	my $last_line = _get_cpanpm_last_line();

	my $result = $last_line =~ /\b(?:$epic_fail_words)\b/i;
	return A_MODULE_FAILED_TO_INSTALL if $last_line =~ /\b(?:Cannot\s+install)\b/i;

	$result || ();
	}
}

sub _cpanpm_output_indicates_success
	{
	my $last_line = _get_cpanpm_last_line();

	my $result = $last_line =~ /\b(?:\s+-- OK|PASS)\b/;
	$result || ();
	}

sub _cpanpm_output_is_vague
	{
	return FALSE if
		_cpanpm_output_indicates_failure() ||
		_cpanpm_output_indicates_success();

	return TRUE;
	}

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
sub _turn_on_warnings {
	carp "Warnings are implemented yet";
	return HEY_IT_WORKED;
	}

sub _turn_off_testing {
	$logger->debug( 'Trusting test report history' );
	$CPAN::Config->{trust_test_report_history} = 1;
	return HEY_IT_WORKED;
	}

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
sub _print_help
	{
	$logger->info( "Use perldoc to read the documentation" );
	my $HAVE_PERLDOC = eval { require Pod::Perldoc; 1; };
	if ($HAVE_PERLDOC) {
		system qq{"$^X" -e "require Pod::Perldoc; Pod::Perldoc->run()" $0};
		exit;
	} else {
		warn "Please install Pod::Perldoc, maybe try 'cpan -i Pod::Perldoc'\n";
		return HEY_IT_WORKED;
	}
	}

sub _print_version # -v
	{
	$logger->info(
		"$0 script version $VERSION, CPAN.pm version " . CPAN->VERSION );

	return HEY_IT_WORKED;
	}

sub _print_details # -V
	{
	_print_version();

	_check_install_dirs();

	$logger->info( '-' x 50 . "\nChecking configured mirrors..." );
	foreach my $mirror ( @{ $CPAN::Config->{urllist} } ) {
		_print_ping_report( $mirror );
		}

	$logger->info( '-' x 50 . "\nChecking for faster mirrors..." );

	{
	require CPAN::Mirrors;

	if ( $CPAN::Config->{connect_to_internet_ok} ) {
		$CPAN::Frontend->myprint(qq{Trying to fetch a mirror list from the Internet\n});
		eval { CPAN::FTP->localize('MIRRORED.BY',File::Spec->catfile($CPAN::Config->{keep_source_where},'MIRRORED.BY'),3,1) }
			or $CPAN::Frontend->mywarn(<<'HERE');
We failed to get a copy of the mirror list from the Internet.
You will need to provide CPAN mirror URLs yourself.
HERE
		$CPAN::Frontend->myprint("\n");
		}

	my $mirrors   = CPAN::Mirrors->new( _mirror_file() );
	my @continents = $mirrors->find_best_continents;

	my @mirrors   = $mirrors->get_mirrors_by_continents( $continents[0] );
	my @timings   = $mirrors->get_mirrors_timings( \@mirrors );

	foreach my $timing ( @timings ) {
		$logger->info( sprintf "%s (%0.2f ms)",
			$timing->hostname, $timing->rtt );
		}
	}

	return HEY_IT_WORKED;
	}

sub _check_install_dirs
	{
	my $makepl_arg   = $CPAN::Config->{makepl_arg};
	my $mbuildpl_arg = $CPAN::Config->{mbuildpl_arg};

	my @custom_dirs;
	# PERL_MM_OPT
	push @custom_dirs,
		$makepl_arg   =~ m/INSTALL_BASE\s*=\s*(\S+)/g,
		$mbuildpl_arg =~ m/--install_base\s*=\s*(\S+)/g;

	if( @custom_dirs ) {
		foreach my $dir ( @custom_dirs ) {
			_print_inc_dir_report( $dir );
			}
		}

	# XXX: also need to check makepl_args, etc

	my @checks = (
		[ 'core',         [ grep $_, @Config{qw(installprivlib installarchlib)}      ] ],
		[ 'vendor',       [ grep $_, @Config{qw(installvendorlib installvendorarch)} ] ],
		[ 'site',         [ grep $_, @Config{qw(installsitelib installsitearch)}     ] ],
		[ 'PERL5LIB',     _split_paths( $ENV{PERL5LIB} ) ],
		[ 'PERLLIB',      _split_paths( $ENV{PERLLIB} )  ],
		);

	$logger->info( '-' x 50 . "\nChecking install dirs..." );
	foreach my $tuple ( @checks ) {
		my( $label ) = $tuple->[0];

		$logger->info( "Checking $label" );
		$logger->info( "\tno directories for $label" ) unless @{ $tuple->[1] };
		foreach my $dir ( @{ $tuple->[1] } ) {
			_print_inc_dir_report( $dir );
			}
		}

	}

sub _split_paths
	{
	[ map { _expand_filename( $_ ) } split /$Config{path_sep}/, $_[0] || '' ];
	}


=pod

Stolen from File::Path::Expand

=cut

sub _expand_filename
	{
	my( $path ) = @_;
	no warnings 'uninitialized';
	$logger->debug( "Expanding path $path\n" );
	$path =~ s{\A~([^/]+)?}{
		_home_of( $1 || $> ) || "~$1"
		}e;
	return $path;
	}

sub _home_of
	{
	require User::pwent;
	my( $user ) = @_;
	my $ent = User::pwent::getpw($user) or return;
	return $ent->dir;
	}

sub _get_default_inc
	{
	require Config;

	[ @Config::Config{ _vars() }, '.' ];
	}

sub _vars {
	qw(
	installarchlib
	installprivlib
	installsitearch
	installsitelib
	);
	}

sub _ping_mirrors {
	my $urls   = $CPAN::Config->{urllist};
	require URI;

	foreach my $url ( @$urls ) {
		my( $obj ) = URI->new( $url );
		next unless _is_pingable_scheme( $obj );
		my $host = $obj->host;
		_print_ping_report( $obj );
		}

	}

sub _is_pingable_scheme {
	my( $uri ) = @_;

	$uri->scheme eq 'file'
	}

sub _mirror_file {
	my $file = do {
		my $file = 'MIRRORED.BY';
		my $local_path = File::Spec->catfile(
			$CPAN::Config->{keep_source_where}, $file );

		if( -e $local_path ) { $local_path }
		else {
			require CPAN::FTP;
			CPAN::FTP->localize( $file, $local_path, 3, 1 );
			$local_path;
			}
		};
	}

sub _find_good_mirrors {
	require CPAN::Mirrors;

	my $mirrors = CPAN::Mirrors->new( _mirror_file() );

	my @mirrors = $mirrors->best_mirrors(
		how_many   => 5,
		verbose    => 1,
		);

	foreach my $mirror ( @mirrors ) {
		next unless eval { $mirror->can( 'http' ) };
		_print_ping_report( $mirror->http );
		}

	$CPAN::Config->{urllist} = [
		map { $_->http } @mirrors
		];
	}

sub _print_inc_dir_report
	{
	my( $dir ) = shift;

	my $writeable = -w $dir ? '+' : '!!! (not writeable)';
	$logger->info( "\t$writeable $dir" );
	return -w $dir;
	}

sub _print_ping_report
	{
	my( $mirror ) = @_;

	my $rtt = eval { _get_ping_report( $mirror ) };
	my $result = $rtt ? sprintf "+ (%4d ms)", $rtt * 1000 : '!';

	$logger->info(
		sprintf "\t%s %s", $result, $mirror
		);
	}

sub _get_ping_report
	{
	require URI;
	my( $mirror ) = @_;
	my( $url ) = ref $mirror ? $mirror : URI->new( $mirror ); #XXX
	require Net::Ping;

	my $ping = Net::Ping->new( 'tcp', 1 );

	if( $url->scheme eq 'file' ) {
		return -e $url->file;
		}

	my( $port ) = $url->port;

	return unless $port;

	if ( $ping->can('port_number') ) {
		$ping->port_number($port);
		}
	else {
		$ping->{'port_num'} = $port;
		}

	$ping->hires(1) if $ping->can( 'hires' );
	my( $alive, $rtt ) = eval{ $ping->ping( $url->host ) };
	$alive ? $rtt : undef;
	}

sub _load_local_lib # -I
	{
	$logger->debug( "Loading local::lib" );

	my $rc = _safe_load_module("local::lib");
	unless( $rc ) {
		$logger->logdie( "Could not load local::lib" );
		}

	local::lib->import;

	return HEY_IT_WORKED;
	}

sub _use_these_mirrors # -M
	{
	$logger->debug( "Setting per session mirrors" );
	unless( $_[0] ) {
		$logger->logdie( "The -M switch requires a comma-separated list of mirrors" );
		}

	$CPAN::Config->{urllist} = [ split /,/, $_[0] ];

	$logger->debug( "Mirrors are @{$CPAN::Config->{urllist}}" );

	}

sub _create_autobundle
	{
	$logger->info(
		"Creating autobundle in $CPAN::Config->{cpan_home}/Bundle" );

	CPAN::Shell->autobundle;

	return HEY_IT_WORKED;
	}

sub _recompile
	{
	$logger->info( "Recompiling dynamically-loaded extensions" );

	CPAN::Shell->recompile;

	return HEY_IT_WORKED;
	}

sub _upgrade
	{
	$logger->info( "Upgrading all modules" );

	CPAN::Shell->upgrade();

	return HEY_IT_WORKED;
	}

sub _shell
	{
	$logger->info( "Dropping into shell" );

	CPAN::shell();

	return HEY_IT_WORKED;
	}

sub _load_config # -j
	{
	my $argument = shift;

	my $file = file_name_is_absolute( $argument ) ? $argument : rel2abs( $argument );
	croak( "cpan config file [$file] for -j does not exist!\n" ) unless -e $file;

	# should I clear out any existing config here?
	$CPAN::Config = {};
	delete $INC{'CPAN/Config.pm'};

	my $rc = eval "require '$file'";

	# CPAN::HandleConfig::require_myconfig_or_config looks for this
	$INC{'CPAN/MyConfig.pm'} = 'fake out!';

	# CPAN::HandleConfig::load looks for this
	$CPAN::Config_loaded = 'fake out';

	croak( "Could not load [$file]: $@\n") unless $rc;

	return HEY_IT_WORKED;
	}

sub _dump_config # -J
	{
	my $args = shift;
	require Data::Dumper;

	my $fh = $args->[0] || \*STDOUT;

	local $Data::Dumper::Sortkeys = 1;
	my $dd = Data::Dumper->new(
		[$CPAN::Config],
		['$CPAN::Config']
		);

	print $fh $dd->Dump, "\n1;\n__END__\n";

	return HEY_IT_WORKED;
	}

sub _lock_lobotomy # -F
	{
	no warnings 'redefine';

	*CPAN::_flock    = sub { 1 };
	*CPAN::checklock = sub { 1 };

	return HEY_IT_WORKED;
	}

sub _download
	{
	my $args = shift;

	local $CPAN::DEBUG = 1;

	my %paths;

	foreach my $arg ( @$args ) {
		$logger->info( "Checking $arg" );

		my $module = _expand_module( $arg ) or next;
		my $path = $module->cpan_file;

		$logger->debug( "Inst file would be $path\n" );

		$paths{$module} = _get_file( _make_path( $path ) );

		$logger->info( "Downloaded [$arg] to [$paths{$arg}]" );
		}

	return \%paths;
	}

sub _make_path { join "/", qw(authors id), $_[0] }

sub _get_file
	{
	my $path = shift;

	my $loaded = _safe_load_module("LWP::Simple");
	croak "You need LWP::Simple to use features that fetch files from CPAN\n"
		unless $loaded;

	my $file = substr $path, rindex( $path, '/' ) + 1;
	my $store_path = catfile( cwd(), $file );
	$logger->debug( "Store path is $store_path" );

	foreach my $site ( @{ $CPAN::Config->{urllist} } )
		{
		my $fetch_path = join "/", $site, $path;
		$logger->debug( "Trying $fetch_path" );
		my $status_code = LWP::Simple::getstore( $fetch_path, $store_path );
		last if( 200 <= $status_code and $status_code <= 300 );
		$logger->warn( "Could not get [$fetch_path]: Status code $status_code" );
		}

	return $store_path;
	}

sub _gitify
	{
	my $args = shift;

	my $loaded = _safe_load_module("Archive::Extract");
	croak "You need Archive::Extract to use features that gitify distributions\n"
		unless $loaded;

	my $starting_dir = cwd();

	foreach my $arg ( @$args )
		{
		$logger->info( "Checking $arg" );
		my $store_paths = _download( [ $arg ] );
		$logger->debug( "gitify Store path is $store_paths->{$arg}" );
		my $dirname = dirname( $store_paths->{$arg} );

		my $ae = Archive::Extract->new( archive => $store_paths->{$arg} );
		$ae->extract( to => $dirname );

		chdir $ae->extract_path;

		my $git = $ENV{GIT_COMMAND} || '/usr/local/bin/git';
		croak "Could not find $git"    unless -e $git;
		croak "$git is not executable" unless -x $git;

		# can we do this in Pure Perl?
		system( $git, 'init'    );
		system( $git, qw( add . ) );
		system( $git, qw( commit -a -m ), 'initial import' );
		}

	chdir $starting_dir;

	return HEY_IT_WORKED;
	}

sub _show_Changes
	{
	my $args = shift;

	foreach my $arg ( @$args )
		{
		$logger->info( "Checking $arg\n" );

		my $module = _expand_module( $arg ) or next;

		my $out = _get_cpanpm_output();

		next unless eval { $module->inst_file };
		#next if $module->uptodate;

		( my $id = $module->id() ) =~ s/::/\-/;

		my $url = "http://search.cpan.org/~" . lc( $module->userid ) . "/" .
			$id . "-" . $module->cpan_version() . "/";

		#print "URL: $url\n";
		_get_changes_file($url);
		}

	return HEY_IT_WORKED;
	}

sub _get_changes_file
	{
	croak "Reading Changes files requires LWP::Simple and URI\n"
		unless _safe_load_module("LWP::Simple") && _safe_load_module("URI");

	my $url = shift;

	my $content = LWP::Simple::get( $url );
	$logger->info( "Got $url ..." ) if defined $content;
	#print $content;

	my( $change_link ) = $content =~ m|<a href="(.*?)">Changes</a>|gi;

	my $changes_url = URI->new_abs( $change_link, $url );
	$logger->debug( "Change link is: $changes_url" );

	my $changes =  LWP::Simple::get( $changes_url );

	print $changes;

	return HEY_IT_WORKED;
	}

sub _show_Author
	{
	my $args = shift;

	foreach my $arg ( @$args )
		{
		my $module = _expand_module( $arg ) or next;

		unless( $module )
			{
			$logger->info( "Didn't find a $arg module, so no author!" );
			next;
			}

		my $author = CPAN::Shell->expand( "Author", $module->userid );

		next unless $module->userid;

		printf "%-25s %-8s %-25s %s\n",
			$arg, $module->userid, $author->email, $author->name;
		}

	return HEY_IT_WORKED;
	}

sub _show_Details
	{
	my $args = shift;

	foreach my $arg ( @$args )
		{
		my $module = _expand_module( $arg ) or next;
		my $author = CPAN::Shell->expand( "Author", $module->userid );

		next unless $module->userid;

		print "$arg\n", "-" x 73, "\n\t";
		print join "\n\t",
			$module->description ? $module->description : "(no description)",
			$module->cpan_file ? $module->cpan_file : "(no cpanfile)",
			$module->inst_file ? $module->inst_file :"(no installation file)" ,
			'Installed: ' . ($module->inst_version ? $module->inst_version : "not installed"),
			'CPAN:      ' . $module->cpan_version . '  ' .
				($module->uptodate ? "" : "Not ") . "up to date",
			$author->fullname . " (" . $module->userid . ")",
			$author->email;
		print "\n\n";

		}

	return HEY_IT_WORKED;
	}

BEGIN {
my $modules;
sub _get_all_namespaces
	{
	return $modules if $modules;
	$modules = [ map { $_->id } CPAN::Shell->expand( "Module", "/./" ) ];
	}
}

sub _show_out_of_date
	{
	my $modules = _get_all_namespaces();

	printf "%-40s  %6s  %6s\n", "Module Name", "Local", "CPAN";
	print "-" x 73, "\n";

	foreach my $module ( @$modules )
		{
		next unless $module = _expand_module($module);
		next unless $module->inst_file;
		next if $module->uptodate;
		printf "%-40s  %.4f  %.4f\n",
			$module->id,
			$module->inst_version ? $module->inst_version : '',
			$module->cpan_version;
		}

	return HEY_IT_WORKED;
	}

sub _show_author_mods
	{
	my $args = shift;

	my %hash = map { lc $_, 1 } @$args;

	my $modules = _get_all_namespaces();

	foreach my $module ( @$modules ) {
		next unless exists $hash{ lc $module->userid };
		print $module->id, "\n";
		}

	return HEY_IT_WORKED;
	}

sub _list_all_mods # -l
	{
	require File::Find;

	my $args = shift;


	my $fh = \*STDOUT;

	INC: foreach my $inc ( @INC )
		{
		my( $wanted, $reporter ) = _generator();
		File::Find::find( { wanted => $wanted }, $inc );

		my $count = 0;
		FILE: foreach my $file ( @{ $reporter->() } )
			{
			my $version = _parse_version_safely( $file );

			my $module_name = _path_to_module( $inc, $file );
			next FILE unless defined $module_name;

			print $fh "$module_name\t$version\n";

			#last if $count++ > 5;
			}
		}

	return HEY_IT_WORKED;
	}

sub _generator
	{
	my @files = ();

	sub { push @files,
		File::Spec->canonpath( $File::Find::name )
		if m/\A\w+\.pm\z/ },
	sub { \@files },
	}

sub _parse_version_safely # stolen from PAUSE's mldistwatch, but refactored
	{
	my( $file ) = @_;

	local $/ = "\n";
	local $_; # don't mess with the $_ in the map calling this

	return unless open FILE, "<$file";

	my $in_pod = 0;
	my $version;
	while( <FILE> )
		{
		chomp;
		$in_pod = /^=(?!cut)/ ? 1 : /^=cut/ ? 0 : $in_pod;
		next if $in_pod || /^\s*#/;

		next unless /([\$*])(([\w\:\']*)\bVERSION)\b.*\=/;
		my( $sigil, $var ) = ( $1, $2 );

		$version = _eval_version( $_, $sigil, $var );
		last;
		}
	close FILE;

	return 'undef' unless defined $version;

	return $version;
	}

sub _eval_version
	{
	my( $line, $sigil, $var ) = @_;

        # split package line to hide from PAUSE
	my $eval = qq{
		package
		  ExtUtils::MakeMaker::_version;

		local $sigil$var;
		\$$var=undef; do {
			$line
			}; \$$var
		};

	my $version = do {
		local $^W = 0;
		no strict;
		eval( $eval );
		};

	return $version;
	}

sub _path_to_module
	{
	my( $inc, $path ) = @_;
	return if length $path < length $inc;

	my $module_path = substr( $path, length $inc );
	$module_path =~ s/\.pm\z//;

	# XXX: this is cheating and doesn't handle everything right
	my @dirs = grep { ! /\W/ } File::Spec->splitdir( $module_path );
	shift @dirs;

	my $module_name = join "::", @dirs;

	return $module_name;
	}


sub _expand_module
	{
	my( $module ) = @_;

	my $expanded = CPAN::Shell->expandany( $module );
	return $expanded if $expanded;
	$expanded = CPAN::Shell->expand( "Module", $module );
	unless( defined $expanded ) {
		$logger->error( "Could not expand [$module]. Check the module name." );
		my $threshold = (
			grep { int }
			sort { length $a <=> length $b }
				length($module)/4, 4
			)[0];

		my $guesses = _guess_at_module_name( $module, $threshold );
		if( defined $guesses and @$guesses ) {
			$logger->info( "Perhaps you meant one of these:" );
			foreach my $guess ( @$guesses ) {
				$logger->info( "\t$guess" );
				}
			}
		return;
		}

	return $expanded;
	}

my $guessers = [
	[ qw( Text::Levenshtein::XS distance 7 1 ) ],
	[ qw( Text::Levenshtein::Damerau::XS     xs_edistance 7 1 ) ],

	[ qw( Text::Levenshtein     distance 7 1 ) ],
	[ qw( Text::Levenshtein::Damerau::PP     pp_edistance 7 1 ) ],

	];

sub _disable_guessers
	{
	$_->[-1] = 0 for @$guessers;
	}

# for -x
sub _guess_namespace
	{
	my $args = shift;

	foreach my $arg ( @$args )
		{
		$logger->debug( "Checking $arg" );
		my $guesses = _guess_at_module_name( $arg );

		foreach my $guess ( @$guesses ) {
			print $guess, "\n";
			}
		}

	return HEY_IT_WORKED;
	}

sub _list_all_namespaces {
	my $modules = _get_all_namespaces();

	foreach my $module ( @$modules ) {
		print $module, "\n";
		}
	}

BEGIN {
my $distance;
my $_threshold;
my $can_guess;
my $shown_help = 0;
sub _guess_at_module_name
	{
	my( $target, $threshold ) = @_;

	unless( defined $distance ) {
		foreach my $try ( @$guessers ) {
			$can_guess = eval "require $try->[0]; 1" or next;

			$try->[-1] or next; # disabled
			no strict 'refs';
			$distance = \&{ join "::", @$try[0,1] };
			$threshold ||= $try->[2];
			}
		}
	$_threshold ||= $threshold;

	unless( $distance ) {
		unless( $shown_help ) {
			my $modules = join ", ", map { $_->[0] } @$guessers;
			substr $modules, rindex( $modules, ',' ), 1, ', and';

			# Should this be colorized?
			if( $can_guess ) {
				$logger->info( "I can suggest names if you provide the -x option on invocation." );
				}
			else {
				$logger->info( "I can suggest names if you install one of $modules" );
				$logger->info( "and you provide the -x option on invocation." );
				}
			$shown_help++;
			}
		return;
		}

	my $modules = _get_all_namespaces();
	$logger->info( "Checking " . @$modules . " namespaces for close match suggestions" );

	my %guesses;
	foreach my $guess ( @$modules ) {
		my $distance = $distance->( $target, $guess );
		next if $distance > $_threshold;
		$guesses{$guess} = $distance;
		}

	my @guesses = sort { $guesses{$a} <=> $guesses{$b} } keys %guesses;
	return [ grep { defined } @guesses[0..9] ];
	}
}

1;

=back

=head1 EXIT VALUES

The script exits with zero if it thinks that everything worked, or a
positive number if it thinks that something failed. Note, however, that
in some cases it has to divine a failure by the output of things it does
not control. For now, the exit codes are vague:

	1	An unknown error

	2	The was an external problem

	4	There was an internal problem with the script

	8	A module failed to install

=head1 TO DO

* There is initial support for Log4perl if it is available, but I
haven't gone through everything to make the NullLogger work out
correctly if Log4perl is not installed.

* When I capture CPAN.pm output, I need to check for errors and
report them to the user.

* Warnings switch

* Check then exit

=head1 BUGS

* none noted

=head1 SEE ALSO

L<CPAN>, L<App::cpanminus>

=head1 SOURCE AVAILABILITY

This code is in Github in the CPAN.pm repository:

	https://github.com/andk/cpanpm

The source used to be tracked separately in another GitHub repo,
but the canonical source is now in the above repo.

=head1 CREDITS

Japheth Cleaver added the bits to allow a forced install (C<-f>).

Jim Brandt suggested and provided the initial implementation for the
up-to-date and Changes features.

Adam Kennedy pointed out that C<exit()> causes problems on Windows
where this script ends up with a .bat extension

David Golden helps integrate this into the C<CPAN.pm> repos.

Jim Keenan fixed up various issues with _download

=head1 AUTHOR

brian d foy, C<< <bdfoy@cpan.org> >>

=head1 COPYRIGHT

Copyright (c) 2001-2021, brian d foy, All Rights Reserved.

You may redistribute this under the same terms as Perl itself.

=cut

# Local Variables:
# mode: cperl
# indent-tabs-mode: t
# cperl-indent-level: 8
# cperl-continued-statement-offset: 8
# End:
PK4N%[CP��>�>perl5/POD2/PT_BR/local/lib.podnu��6�$=encoding utf8

=head1 NAME

local::lib~[pt_br] - crie e use um diretório lib/ local para módulos perl com PERL5LIB

=head1 SINOPSE

No código -

  use local::lib; # configura um lib local em ~/perl5

  use local::lib '~/foo'; # idem, mas ~/foo

  # Ou...
  use FindBin;
  use local::lib "$FindBin::Bin/../suporte";  # bibliotecas de suporte locais à aplicação

Pela linha de comando (shell) -

  # Instala o LWP e suas dependências não encontradas no diretório '~/perl5'
  perl -MCPAN -Mlocal::lib -e 'CPAN::install(LWP)'

  # Apenas exibe alguns comandos úteis para a shell
  $ perl -Mlocal::lib
  export PERL_MB_OPT='--install_base /home/username/perl5'
  export PERL_MM_OPT='INSTALL_BASE=/home/username/perl5'
  export PERL5LIB='/home/username/perl5/lib/perl5/i386-linux:/home/username/perl5/lib/perl5'
  export PATH="/home/username/perl5/bin:$PATH"

=head2 A técnica de 'bootstrapping'

Uma forma comum de instalar o local::lib é usando o que é conhecido como
técnica de "bootstrapping". É uma boa abordagem caso seu administrador de
sistemas não tenha instalado o local::lib. Nesse caso, você precisará
instalar o local::lib em seu diretório de usuário.

Caso você tenha privilégios de administrador, ainda assim deverá
configurar suas variáveis de ambiente, como discutido no passo 4, abaixo.
Sem elas, você ainda instalará módulos no CPAN do sistema e seus scripts
Perl não utilizarão o caminho para o lib/ que você definiu com o local::lib.

Por padrão, o local::lib instala os módulos do CPAN e a si próprio em ~/perl5.

Usuários do Windows devem ler L</Diferenças ao usar esse módulo em Win32>.

1. Baixe e descompacte o local::lib do CPAN (procure por "Download" na página
do CPAN sobre o local::lib). Faça isso como um usuário comum, não como root
ou administrador. Descompacte o arquivo em seu diretório de usuário ou em
qualquer outro local conveniente.

2. Execute isso:

  perl Makefile.PL --bootstrap

Caso o sistema pergunte se deve configurar tudo que puder automaticamente,
você provavelmente deve responder que sim (yes).

Para instalar o local::lib em um diretório que não o padrão, você precisará
especificá-lo ao chamar o bootstrap, da seguinte forma:

  perl Makefile.PL --bootstrap=~/foo

3. Execute isso: (local::lib assume que você possui o comando 'make'
instalado em seu sistema)

  make test && make install

4. Agora precisamos configurar as variáveis de ambiente apropriadas para
que o Perl use nosso recém-criado diretório lib/. Caso esteja usando bash
ou outra shell Bourne, você pode fazer isso adicionando a seguinte linha
em seu script de inicialização da shell:

  echo 'eval $(perl -I$HOME/perl5/lib/perl5 -Mlocal::lib)' >>~/.bashrc

Caso esteja usando a shell C, pode fazer da seguinte forma:

  /bin/csh
  echo $SHELL
  /bin/csh
  perl -I$HOME/perl5/lib/perl5 -Mlocal::lib >> ~/.cshrc

Caso tenha passado para o bootstrap um diretório que não o padrão, você
precisará indicá-lo na chamada ao local::lib, dessa forma:

  echo 'eval $(perl -I$HOME/foo/lib/perl5 -Mlocal::lib=$HOME/foo)' >>~/.bashrc

Após atualizar seu arquivo de configuração da shell, certifique-se de
processá-lo novamente para obter as modificações em sua shell atual.
Shells Bourne usam C<. ~/.bashrc> para isso, enquanto shells C
usam C<source ~/.cshrc>.

Se estiver em uma máquina lenta ou operando com grandes limitações de
espaço em disco, você pode desativar a geração automática de manpages a
partir do POD ao instalar módulos. Para isso, basta passar o argumento
C<--no-manpages> durante o bootstrap:

  perl Makefile.PL --bootstrap --no-manpages

Para evitar ter que fazer vários bootstraps para vários ambientes de
módulos Perl na mesma conta de usuário - por exemplo se você usa o
local::lib para desenvolver diferentes aplicativos independentes -
você pode utilizar uma única instalação bootstrap do local::lib para
instalar módulos em diretórios diferentes da seguinte forma:

  cd ~/meudir1
  perl -Mlocal::lib=./
  eval $(perl -Mlocal::lib=./)  ### Para configurar o ambiente apenas nessa shell
  printenv                      ### Veja que o ~/meudir1 está na PERL5LIB
  perl -MCPAN -e install ...    ### Os módulos que quiser
  cd ../meudir2
  ... REPITA ...

Para múltiplos ambientes destinados a múltiplos aplicativos, você pode
precisar incluir uma versão modificada das instruções de C<< use FindBin >>
no exemplo "No código" acima. Caso tenha feito algo como o que foi descrito
acima, terá um conjunto de módulos Perl em C<< ~/meudir1/lib >>. Caso
tenha um script em C<< ~/meudir1/scripts/meuscript.pl >>, você precisará
indicar a ele onde encontrar os módulos que instalou para ele
em C<< ~/meudir1/lib >>.

Em C<< ~/meudir1/scripts/meuscript.pl >>:

  use strict;
  use warnings;
  use local::lib "$FindBin::Bin/..";  ### aponta para ~/meudir1 e o local::lib acha o lib/
  use lib "$FindBin::Bin/../lib";     ### aponta para ~/meudir1/lib

Coloque isso antes de qualquer bloco BEGIN { ... } que precise dos módulos instalados.

=head2 Diferenças ao usar esse módulo em Win32

Para configurar as variáveis de ambiente apropriadas para sua sessão atual
do C<CMD.exe>, você pode fazer assim:

  C:\>perl -Mlocal::lib
  set PERL_MB_OPT=--install_base C:\DOCUME~1\ADMINI~1\perl5
  set PERL_MM_OPT=INSTALL_BASE=C:\DOCUME~1\ADMINI~1\perl5
  set PERL5LIB=C:\DOCUME~1\ADMINI~1\perl5\lib\perl5;C:\DOCUME~1\ADMINI~1\perl5\lib\perl5\MSWin32-x86-multi-thread
  set PATH=C:\DOCUME~1\ADMINI~1\perl5\bin;%PATH%

  ### Para configurar o ambiente apenas dessa shell
  C:\>perl -Mlocal::lib > %TEMP%\tmp.bat && %TEMP%\tmp.bat && del %TEMP%\temp.bat
  ### em vez de $(perl -Mlocal::lib=./)

Caso queira que as configurações do ambiente persistam, você precisará
adicioná-las em Painel de Controle -> Sistema, ou usar o L<App::local::lib::Win32Helper>.

O "~" é transformado no diretório do perfil do usuário (o diretório com o
nome do usuário dentro de "Documents and Settings" (Windows XP ou anterior)
ou "Usuários" (Windows Vista e mais recentes)) a menos que $ENV{HOME} exista.
Após isso, o nome do diretório é encurtado e os subdiretórios são criados
(o que significa que o diretório deve existir).

=head1 MOTIVAÇÃO

A versão de um pacote Perl na sua máquina nem sempre é a que você precisa.
Obviamente, a melhor coisa a fazer seria atualizá-la para a versão desejada.
No entanto, você pode estar em uma situação que o impede de fazer isso.
Talvez você não tenha privilégios de administrador do sistema; ou talvez
esteja usando um sistema de gerenciamento de pacotes como o do Debian,
e ainda não exista um pacote disponível na versão desejada.

local::lib resolve esse problema possibilitando a criação de seu próprio
diretório de pacotes Perl obtidos do CPAN (em sistemas multi-usuário, isso
normalmente fica dentro do diretório de seu usuário). A instalação do Perl
no sistema permanece inalterada; você simplesmente chama o Perl com opções
especiais para que ele use os pacotes em seu diretório local em vez dos
pacotes do sistema. O local::lib organiza as coisas para que versões dos
pacotes Perl instalados localmente tenham precedência sobre as do sistema.

Caso esteja usando um sistema de gerenciamento de pacote (como em sistemas
Debian), não precisará se preocupar com conflitos entre o Debian e o CPAN.
Sua versão local dos pacotes será instalada em um diretório completamente
diferente das versões instaladas pelo gerenciador de pacotes do sistema.

=head1 DESCRIÇÃO

Este módulo oferece uma forma rápida e conveniente para criar um repositório
de módulos locais ao usuário, dentro do diretório do mesmo. Ele também monta
e exibe para o usuário uma lista de variáveis de ambiente utilizando a
sintaxe da shell atual do usuário (conforme especificado pela variável
de ambiente C<SHELL>), pronta para ser adicionada diretamente no arquivo
de configuração da shell.

Generalizando, o local::lib permite a criação e uso de um diretório contendo
módulos Perl fora do C<@INC> do Perl. Isso facilita a produção de aplicações
com uma versão específica de determinado módulo, ou coleção de módulos.
Também é útil quando o mantenedor de um módulo não aplicou determinado patch
que você precisa para seu aplicativo.

Durante o C<import>, o local::lib define valores apropriados para as
seguintes variáveis de ambiente:

=over 4

=item PERL_MB_OPT

=item PERL_MM_OPT

=item PERL5LIB

=item PATH

valores serão anexados ao PATH, em vez de substituí-lo.

=back

Esses valores são então disponibilizados para referência por qualquer
outro código após o C<import>.

=head1 CRIANDO UM CONJUNTO AUTO-CONTIDO DE MÓDULOS

Veja L<lib::core::only|lib::core::only> para uma maneira de fazer isso - mas
note que há uma série de ressalvas na abordagem, e a melhor forma é sempre
fazer o 'build' contra uma versão limpa do perl (i.e. com 'site' e 'vendor'
o mais vazios possível).

=head1 MÉTODOS

=head2 ensure_dir_structure_for

=over 4

=item Argumentos: $caminho_do_diretorio

=item Valor de Retorno: Nenhum

=back

Tenta criar o caminho fornecido, e todos os diretórios superiores necessários. Gera uma exceção em caso de falha.

=head2 print_environment_vars_for

=over 4

=item Argumentos: $caminho_do_diretorio

=item Valor de Retorno: Nenhum

=back

Exibe na saída padrão as variáveis listadas acima, devidamente ajustadas
para utilizar o caminho fornecido como diretório base.

=head2 build_environment_vars_for

=over 4

=item Argumentos: $caminho_do_diretorio, $interpolar

=item Valor de Retorno: %variaveis_de_ambiente

=back

Retorna hash contendo as variáveis de ambiente listadas acima, devidamente
ajustadas para utilizar o caminho fornecido como diretório base.

=head2 setup_env_hash_for

=over 4

=item Argumentos: $caminho_do_diretorio

=item Valor de Retorno: Nenhum

=back

Constrói as chaves no C<%ENV> para o caminho fornecido, chamando
C<build_environment_vars_for>.

=head2 install_base_perl_path

=over 4

=item Argumentos: $caminho_do_diretorio

=item Valor de Retorno: $caminho_base_de_instalacao

=back

Retorna um caminho de diretório indicando onde instalar os módulos Perl
para essa instalação local de bibliotecas. Adiciona os diretórios C<lib>
e C<perl5> ao final do caminho fornecido.

=head2 install_base_arch_path

=over 4

=item Argumentos: $caminho_do_diretorio

=item Valor de Retorno: $caminho_base_de_instalacao_arch

=back

Retorna um caminho de diretório indicando onde instalar os módulos Perl
de arquiteturas específicas para essa instalação local de bibliotecas.
Baseia-se no valor de retorno do método L</install_base_perl_path>,
adicionando o valor de C<$Config{archname}>.

=head2 install_base_bin_path

=over 4

=item Argumentos: $caminho_do_diretorio

=item Valor de Retorno: $caminho_base_de_instalacao_bin

=back

Retorna um caminho de diretório indicando onde instalar programas executáveis
para essa instalação local de bibliotecas. Baseia-se no valor de retorno do
método L</install_base_perl_path>, adicionando o diretório C<bin>.

=head2 resolve_empty_path

=over 4

=item Argumentos: $caminho_do_diretorio

=item Valor de Retorno: $caminho_base_de_instalacao

=back

Cria e retorna o caminho de diretório raiz em que a instalação local de
módulos deve ser feita. O padrão é C<~/perl5>.

=head2 resolve_home_path

=over 4

=item Argumentos: $caminho_do_diretorio

=item Valor de Retorno: $caminho_para_home

=back

Procura pelo diretório padrão (home) do usuário.
Gera uma exceção caso não encontre
resultado definitivo.

=head2 resolve_relative_path

=over 4

=item Argumentos: $caminho_do_diretorio

=item Valor de Retorno: $caminho_absoluto

=back

Transforma o caminho fornecido em um caminho absoluto.

=head2 resolve_path

=over 4

=item Argumentos: $caminho_do_diretorio

=item Valor de Retorno: $caminho_absoluto

=back

Invoca os seguintes métodos em sequência, passando o resultado do método
anterior para o seguinte, na tentativa de descobrir onde configurar o
ambiente para a instalação local de bibliotecas: L</resolve_empty_path>,
L</resolve_home_path>, L</resolve_relative_path>. Passa o caminho de
diretório fornecido para L</resolve_empty_path> que retorna um resultado
que é passado para L</resolve_home_path>, que então tem seu resultado
passado para L</resolve_relative_path>. O resultado dessa chamada final
é então retornado pelo L</resolve_path>.

=head1 UM AVISO SOBRE UNINST=1

Tenha cuidado ao usar o local::lib em conjunto com "make install UNINST=1".
A idéia dessa opção é desinstalar a versão anterior de um módulo antes de
instalar a mais recente. No entanto ela não possui uma verificação de
segurança de que a versão antiga e a nova referem-se ao mesmo diretório.
Usada em combinação com o local::lib, você pode potencialmente apagar uma
versão globalmente acessível de um módulo e instalar a versão mais nova
no diretório local. Apenas utilize "make install UNINST=1" junto com o
local::lib se você entende essas possíveis consequências.

=head1 LIMITAÇÕES

As ferramentas auxiliares do perl não conseguem lidar com nomes de
diretórios contendo espaços, então não é possível fazer seu bootstrap
do local::lib em um diretório com espaços. O que você pode fazer é mover
seu local::lib para um diretório com espaços B<após> ter instalado todos
os módulos dentro dele. Mas esteja ciente que você não poderá atualizar
ou instalar outros módulos do CPAN nesse diretório local após a mudança.

A detecção da shell é relativamente básica. Neste momento, qualquer coisa
com csh no nome será tratada como a C shell ou compatível, e todo o resto
será tratado como Bourne, exceto em sistemas Win32. Caso a variável de
ambiente C<SHELL> não esteja disponível, assumiremos tratar-se de uma
shell compatível com a Bourne.

A técnica de bootstrap é um hack e usará o CPAN.pm para o ExtUtils::MakeMaker
mesmo que você tenha o CPANPLUS instalado.

Destrói qualquer valor pré-existente nas variáveis de ambiente PERL5LIB,
PERL_MM_OPT e PERL_MB_OPT.

Provavelmente deveria auto-configurar o CPAN caso isso ainda não tenha
sido feito.

Correções (patches) são muito bem-vindos para quaisquer dos itens acima.

Em sistemas Win32, não há uma forma de escrever no registro as variáveis
de ambiente criadas, para que elas persistam a uma reinicialização.

=head1 SOLUÇÃO DE PROBLEMAS

Se você configurou o local::lib para instalar módulos do CPAN em algum lugar
do seu 'home', e mais tarde tentou instalar um módulo fazendo C<cpan -i
Foo::Bar>, mas ele falhou com um erro como: C<Warning: You do not have
permissions to install into /usr/lib64/perl5/site_perl/5.8.8/x86_64-linux at
/usr/lib64/perl5/5.8.8/Foo/Bar.pm> e em algum lugar no seu log de instalação
houver um erro dizendo C<'INSTALL_BASE' is not a known MakeMaker parameter
name>, então você de alguma forma perdeu seu ExtUtils::MakeMaker atualizado.

Para remediar a situação, execute novamente o procedimento de bootstrap
descrito acima.

Então, execute C<rm -r ~/.cpan/build/Foo-Bar*>

Finalmente, execute novamente o C<cpan -i Foo::Bar> e ele deve instalar
sem problemas.

=head1 AMBIENTE

=over 4

=item SHELL

=item COMSPEC

O local::lib procura pela variável de ambiente C<SHELL> do usuário ao
processar e exibir os comandos a serem adicionados no arquivo de
configuração da shell.

Em sistemas Win32, C<COMSPEC> também será examinado.

=back

=head1 SUPORTE

IRC:

    Acesse #local-lib em irc.perl.org.

=head1 AUTOR DA TRADUÇÃO

Breno G. de Oliveira, C<< <garu at cpan.org> >>, após ter perdido uma aposta
para o L<Getty|http://search.cpan.org/~getty/> durante a Copa de 2010.


=head1 COPYRIGHT

Copyright (c) 2007 - 2010 L<local::lib/"AUTHOR">
e L<local::lib/"CONTRIBUTORS"> do local::lib como listados em L<local::lib>.

=head1 LICENÇA

Esta biblioteca é software livre e pode ser distribuída sob os mesmo termos
do perl.

PK4N%[��(	�@�@perl5/POD2/DE/local/lib.podnu��6�$=encoding utf8

=head1 NAME

local::lib~[de] - Erschaffen und benutzen von Perl Modulen in einem lokalen lib/ Verzeichnis mit PERL5LIB

=head1 SYNOPSIS

Im Code -

  use local::lib; # Benutzt das Verzeichnis ~/perl5 zum anlegen des lokalen lib/ Verzeichnisses

  use local::lib '~/foo'; # das selbe, aber mit ~/foo

  # Oder...
  use FindBin;
  use local::lib "$FindBin::Bin/../support";  # Applikationsspezifische Sammlung von Modulen

Von der Shell -

  # Installiert LWP und alle notwendigen Abhängigkeiten in das '~/perl5' Verzeichnis
  perl -MCPAN -Mlocal::lib -e 'CPAN::install(LWP)'

  # Gibt die Shell Kommandos aus um die Umgebung vorzubereiten
  $ perl -Mlocal::lib
  export PERL_MB_OPT='--install_base /home/username/perl5'
  export PERL_MM_OPT='INSTALL_BASE=/home/username/perl5'
  export PERL5LIB='/home/username/perl5/lib/perl5/i386-linux:/home/username/perl5/lib/perl5'
  export PATH="/home/username/perl5/bin:$PATH"

=head2 Die Bootstrapping Methode

Ein typischer Weg um local::lib zu benutzen ist die sogenannte "Bootstrapping" Methode.
Diese Methode wird benutzt wenn noch kein local::lib auf dem System installiert ist.
In diesem Fall kannst du einfach local::lib direkt in deinem Home-Verzeichnis installieren.

Selbst wenn du administrative Rechte hast, ist es wichtig das die Umgebungsvariablen von
Schritt 4 in deinem Shell Startup Skript gesetzt werden. Ohne diesen Schritt werden die
Module von CPAN weiterhin im System installiert und auch Perl Skripte die du startest
würden das von local::lib erstellte lib/ Verzeichnis nicht nutzen.

Standardmäßig installiert sich local::lib in ~/perl5.

Windows Benutzern müssen ausserdem dies hier lesen:
L</Unterschiede bei Benutzung dieses Module mit Win32>.

1. Lade das Tar-Archiv von CPAN runter (Suche nach "Download" auf der CPAN Seite von
local::lib) und entpacke es in einem beliebigem Verzeichnis. Um das obige Problem zu
vermeiden, sollte man dies als normaler User tun und nicht als root oder Administrator.

2. Starte in dem entstandenen Verzeichnis folgenden Befehl:

  perl Makefile.PL --bootstrap

Wenn das System dir vorschlägt gewisse Dinge eigenständig zu konfigurieren ist es in
fast allen Fällen vollkommen in Ordnung einfach "yes" zu antworten.

Falls du local::lib nicht in das Standard Verzeichnis installieren willst, musst du
dieses Verzeichnis als Parameter angeben:

  perl Makefile.PL --bootstrap=~/foo

3. Danach folgenden Befehl starten: (local::lib erwartet make auf dem System)

  make test && make install

4. Nun müssen wir die benötigten Umgebungsvariablen, damit Perl unser neu generiertes
lib/ Verzeichnis benutzt. Wenn du bash oder eine andere Bourne Shell benutzt, kannst
du es über diesen Weg zu deinem Shell Startup Skript hinzufügen:

  echo 'eval $(perl -I$HOME/perl5/lib/perl5 -Mlocal::lib)' >>~/.bashrc

Wenn du C Shell benutzt, du kannst das gleiche hiermit erreichen:

  /bin/csh
  echo $SHELL
  /bin/csh
  perl -I$HOME/perl5/lib/perl5 -Mlocal::lib >> ~/.cshrc

Wenn du beim bootstrappen ein anderes Verzeichnis benutzt als das Standardverzeichnis,
dann musst du dieses Verzeichnis als Parameter beim Laden des Modules local::lib angeben:

  echo 'eval $(perl -I$HOME/foo/lib/perl5 -Mlocal::lib=$HOME/foo)' >>~/.bashrc

Nachdem diese Änderungen in deinem Shell Startup Skript gemacht wurden, ist es nun wichtig
das diese Umgebungsvariablen auch gesetzt sind in deiner aktuellen Umgebung. In Bourne
Shells macht man dies z.B. mit C<. ~/.bashrc>, und in C Shell würde man es mit:
C<source ~/.cshrc> mit.

Wenn du eine sehr langsames System hast, oder du unter drakonischen Regulierungen des
Plattenplatz leben musst, kann man die automatische Generierung der manpages vom POD
bei der Installation des Moduls deaktivieren beim bootstrapping mit dem C<--no-manpages>
Parameter:

  perl Makefile.PL --bootstrap --no-manpages

Um zu vermeiden das man mehrere bootstraps macht um z.B. für verschiedene Applikationen
eigene local::lib Installationen zu nutzen, kann man eine dieser Umgebungen benutzen
um einfach in beliebigen anderen Verzeichnis Module zu installieren und somit weitere
eigenständige lib/ Umgebungen zu bekommen:

  cd ~/mydir1
  perl -Mlocal::lib=./
  eval $(perl -Mlocal::lib=./)  ### Um die Umgebungsvariablen für die
                                ### aktuelle Shell zusetzen

  printenv                      ### Hier kannst du sehen das ~/mydir1
                                ### in der PERL5LIB Umgebungsvariable
                                ### steht

  perl -MCPAN -e install ...    ### welche Module auch immer ...
  cd ../mydir2

  ... WIEDERHOLEN ...

Für mehrere Umgebungen in dieser Form brauch man eine Modifikation in der
Benutzung von C<< use FindBin >> in dem "Im Code" Beispiel oben.
Wenn du sowas machst, und du hast damit z.B. Perl Module nach C<<
~/mydir1/lib >> installiert und du hast ein Script in C<<
~/mydir1/scripts/myscript.pl >>, du musst dort angeben das die Module
die es braucht im Verzeichnis C<< ~/mydir1/lib >> liegen.

In C<< ~/mydir1/scripts/myscript.pl >> steht dann:

  use strict;
  use warnings;
  use local::lib "$FindBin::Bin/..";  ### zeigt auf ~/mydir1 und local::lib
                                      ### findet dort lib
  use lib "$FindBin::Bin/../lib";     ### zeigt auf ~/mydir1/lib

Setze das vor jeden BEGIN { ... } Block der die Module braucht die du
installiert hast.

=head2 Unterschiede bei Benutzung dieses Module mit Win32

Um die nötigen Umgebungsvariablen für diese Variablen in der derzeitigen
Sitzung mit C<CMD.EXE> zu setzen, kann man folgendes kommando nutzen:

  C:\>perl -Mlocal::lib
  set PERL_MB_OPT=--install_base C:\DOCUME~1\ADMINI~1\perl5
  set PERL_MM_OPT=INSTALL_BASE=C:\DOCUME~1\ADMINI~1\perl5
  set PERL5LIB=C:\DOCUME~1\ADMINI~1\perl5\lib\perl5;C:\DOCUME~1\ADMINI~1\perl5\lib\perl5\MSWin32-x86-multi-thread
  set PATH=C:\DOCUME~1\ADMINI~1\perl5\bin;%PATH%

  ### Um die Umgebungsvariablen für diese Shell alleine zu setzen
  C:\>perl -Mlocal::lib > %TEMP%\tmp.bat && %TEMP%\tmp.bat && del %TEMP%\temp.bat
  ### anstelle von $(perl -Mlocal::lib=./) in bash.

Wenn du willst das die Umgebungsvariablen dauerhaft gesetzt sind, musst du diese
in Systemsteuerung / System dauerhaft selber eintragen oder
L<App::local::lib::Win32Helper> benutzen.

Die "~" wird übersetzt zu dem Benutzer Profil Verzeichnis (das Verzeichnis was
beim User als "Dokumente und Einstellungen" bekannt ist unter Windows XP und
vorher oder das "Benutzer" Verzeichnis bei Windows Vista und später), solange
$ENV{HOME} nicht gesetzt ist. Das Verzeichnis wird hierbei zu dem korrekten
Kurznamen umgewandelt, und muss daher definitiv existieren, und wird um die
nötigen Unterverzeichnise erweitert.

=head1 GRUNDPRINZIP

Die Version von den Perl Paketen die man benötigt für spezifische Aufgaben sind
sehr häufig nicht die richtigen oder korrekten Versionen auf dem System
vorinstalliert. Ein Updaten von diesen Modulen ist in vielen Fällen einfach
nicht möglich weil die nötigen Rechte fehlen. Ausserdem ist es generell nicht
gut eigenständig die Versionen der Module auf dem System auszutauschen, weil
natürlich der Rest des Systems genau die Version erwartet die von der
Systemverwaltung auch installiert wurde.

local::lib löst dieses Problem, es erlaubt dir dein komplett eigenes Verzeichnis
für deine CPAN Module zu haben und bist so nicht genötigt die Module vom
System zu nutzen oder andersrum andere User nicht mit individuellen
Modulwünschen zu Überarbeitung ihres Codes zu zwingen, weil bestimmte Module
zentral für alle auf neuere Version upgedatet werden. Die Installation findet
hierbei dann z.B. im Home Verzeichnis statt. Es werden nur Umgebungsvariablen
gesetzt die das installierte Perl dazu bewegen die im Homeverzeichnis
installierten Module zu benutzen, zusätzlich und vorgezogen zu denen auf dem
System.

Daher muss man sich wenn man ein Paket System benutzt, wie z.b. Debian, garnicht
mehr Sorgen machen, irgendwas auf dem System zu verletzten nur durch die
Installation von Perl Modulen.

=head1 BESCHREIBUNG

Dieses Modul bietet eine schnelle und legitime Art und Weise ein sogenanntes
bootstrapping zu machen um in einem User Homeverzeichnis eine Sammlung von
Modulen zu installieren. Es erstellt auch die nötigen Umgebungsvariablen
die benötigt werden um diese Module zu nutzen, passend zu der Shell die der
User in der Umgebungsvariable C<SHELL> angegeben hat, um dann direkt passend
in die entsprechenden Konfigurationsdateien der Shell einfügt zu werden.

Weitergehend ist local::lib in der Lage Module zu nutzen die nicht im
standardmäßigen C<@INC> Pfad von Perl enthalten sind. Das macht es einfacher
für bestimmte Applikationen ein bestimmtes Set von Modulen zu installieren
ohne die anderen Module auf dem System in irgendeiner Art anzufassen.
Damit es z.B. auch sicherer Module zu installieren die vom Maintainer noch
nicht als Release verfügbar sind.

Beim Import setzt local::lib die folgenden Umgebungsvariablen zu den
nötigen Werten:

=over 4

=item PERL_MB_OPT

=item PERL_MM_OPT

=item PERL5LIB

=item PATH

Am PATH wird natürlich angehangen, und nicht ersetzt.

=back

Diese Werte sind dann verfügbar für jeden Code der danach importiert wurde.

=head1 ERSTELLEN EINES EIGENSTÄNDIGE SAMMLUNG VON MODULEN

Mit L<lib::core::only> besteht eine Möglichkeit dieses zutun, aber beachte das
hier eine Menge von Fallstricken und Problemen existieren, und man sollte
immer darauf achten das man auf einem Perl aufbaut was sowenig wie möglich
verändert wurde (d.h. site und vendor Verzeichnis so leer wie möglich).

=head1 METHODEN

=head2 ensure_dir_structure_for

=over 4

=item Parameter: $path

=item Rückgabewert: Keiner

=back

Versucht den angegebenen Pfad anzulegen, mit allen nötigen drüberliegenden
Verzeichnissen. Im Fehlerfall wird eine Exception geworfen.

=head2 print_environment_vars_for

=over 4

=item Parameter: $pfad

=item Rückgabewert: Keiner

=back

Gibt die Umgebungsvariablen aus, die benötigt werden um den angegebenen Pfad
als Basis Verzeichnis zu nutzen.

=head2 build_environment_vars_for

=over 4

=item Parameter: $pfad, $interpolate

=item Rückgabewert: \%umgebungs_variablen

=back

Gibt ein Hash zurück mit den Variablen die nötig sind in den Umgebungsvariablen
um eine Installation in dem gegebenen Pfad zu benutzen.

=head2 setup_env_hash_for

=over 4

=item Parameter: $pfad

=item Rückgabewert: Keiner

=back

Setzt die C<%ENV> Einträge basierend auf dem Aufruf von
L</build_environment_vars_for>.

=head2 install_base_perl_path

=over 4

=item Parameter: $pfad

=item Rückgabewert: $module_installations_pfad

=back

Gibt den Pfad zurück der benutzt wird um Perl Module zu installieren bei
dem gegebenen Pfad als Basis. Prinzipiell wird nur C<lib> und C<perl5> als
Pfadelemente angehangen.

=head2 install_base_arch_path

=over 4

=item Parameter: $pfad

=item Rückgabewert: $architektur_module_installations_pfad

=back

Gibt den Pfad zurück der benutzt wird um die Architektur-abhängigen Perl
Module zu installieren basirend auf dem angegebenen Pfad als Basis. Basierend
auf dem was L</install_base_perl_path> zurückgibt, and appends the value of
C<$Config{archname}>.asis.

=head2 install_base_bin_path

=over 4

=item Parameter: $pfad

=item Rückgabewert: $ausfuehrbare_programme_installations_pfad

=back

Gibt den Pfad zurück, wo ausführbare Programme installiert werden, basierend
auf der Basis des angegebenen Pfad. Basierend auf L</install_base_perl_path>
Rückgabewert, hängt diese Methode noch C<bin> an.

=head2 resolve_empty_path

=over 4

=item Parameter: $pfad

=item Rückgabewert: $basis_pfad

=back

Erstellt und gibt zurück den Pfad der benutzt wird als Basis zur Installation
der Module. Standardmäßig dies ist C<~/perl5>.

=head2 resolve_home_path( $path )

=over 4

=item Parameter: $pfad

=item Rückgabewert: $home

=back

Versucht das Home Verzeichnis vom aktullen User zu finden.
Es wird eine Exception geworfen, wenn
kein Home Verzeichnis ermittelt werden konnte.

=head2 resolve_relative_path

=over 4

=item Parameter: $pfad

=item Rückgabewert: $absoluter_pfad

=back

Macht aus dem angegebenen Pfad einen absoluten Pfad.

=head2 resolve_path

=over 4

=item Parameter: $pfad

=item Rückgabewert: $absoluter_pfad

=back

Hierbei wird der Pfad durch die folgende Methoden gegeben, wobei der Rückgabewert
der ersten an die nächste weitergeben wird, um die Umgebung zu konfigurieren
für die lokale Bibliotheks Installation: L</resolve_empty_path>,
L</resolve_home_path>, L</resolve_relative_path>.
Der daraus resultierende Pfad wird zu L</resolve_empty_path> übergeben, dessen
Resultat dann weitergegeben wird an L</resolve_home_path>, wessen Resultat dann
weitergegeben wird an L</resolve_relative_path>. Dieses Resultat wird dann final
an L</resolve_path> übergeben, welches dann den Rückgabewert stellt.

=head1 EINE WARNUNG VOR UNINST=1

Wenn man local::lib in Kombination mit "make install UNINST=1" benutzt, muss
man vorsichtig sein über die Tatsache das der Prozess über die Neuinstallation
eine nicht ausreichende Sicherheit hat bezüglich wo er nun installieren muss.
Hierdurch mann es passieren das beim deinstallieren eines Modul u.U. das
globale Modul deinstalliert wird (wenn die Rechte vorhanden sind) aber die
neue Version nur in der lokalen Version installiert ist. Es ist hier also sehr
wichtig das man "make install UNINST=1" und local::lib nur gleichzeitig
benutzt wenn man sehr sicher darüber ist welche Konsequenzen einem
entgegenkommen.

=head1 EINSCHRÄNKUNGEN

Die Werkzeuge von perl, die benutzt werden um die Pakete zu installieren
(die sogenannte toolchain), sind leider nicht in der Lage sauber mit
Verzeichnissen umzugehen die Leerzeichen enthalten und können daher local::lib
nicht direkt in ein solches Verzeichnis installieren. Was du machen kannst
ist B<nach> der Installation von local::lib und der Module die du in deiner
local::lib haben willst, das gesamte Verzeichnis dahin zu bewegen. local::lib
kann mit dem Verzeichnis mit Leerzeichen umgehen. Bitte aufpassen das natürlich
eine weitere Installation oder ein Erneuern von Paketen mit dem CPAN Programm
nicht mehr möglich ist.

Die Shell Erkennung ist sehr primitiv. Derzeit ist es so das alles was "csh"
im Namen hat auch als C Shell eingeordnet wird, und alles andere wird als
Bourne Shell betrachet, ausser auf Win32 Systemen. Wenn die C<SHELL> Variable
nicht gesetzt ist, eine Bourne Shell wird angenommen.

Bootstrap ist leider ein Hack, und wird auf jedenfall CPAN.pm benutzen für
ExtUtils::MakeMaker, auch wenn CPANPLUS installiert ist.

Es setzt definitiv PERL5LIB, PERL_MM_OPT und PERL_MB_OPT neu und vernichtet
jeden Wert der vorher gesetzt war.

Es sollte vielleicht eine automatische Korrektur der CPAN Config machen, wenn
das nicht schon gemacht wurde.

"Patches Welcome" - Patches sind immer willkommen beim Autor oder den anderen
Mitwirkenden.

Auf Win32 Systemen werden die Umgebungsvariablen nicht direkt in die Registrierung
geschrieben damit sie auch nach dem Neustarten erhalten bleiben.

=head1 FEHLERANALYSE

Wenn du local::lib konfiguriert hast CPAN Module in deinem Home Verzeichnis
zu installieren, und du danach versuchst mit C<cpan -i Foo::Bar> ein Modul
zu installieren, und dabei einen Fehler bekommst, wie: C<Warning: You do not
have permissions to install into /usr/lib64/perl5/site_perl/5.8.8/x86_64-linux at
/usr/lib64/perl5/5.8.8/Foo/Bar.pm> und in der installationsausgabe steht
irgendwo ein Fehler der sagt C<'INSTALL_BASE' is not a known MakeMaker parameter
name>, dann hast du aus irgendeinem Grund dein neue Version von ExtUtils::MakeMaker
verloren.

Um dies zu korrigieren, einfach nochmal die bootstrapping Methode laufen lassen,
wie oben beschrieben.

Dann starte C<rm -r ~/.cpan/build/Foo-Bar*>

Abschliessend dann nochmal mit C<cpan -i Foo::Bar> installieren und die Probleme
sollten verschwunden sein.

=head1 UMGEBUNGSVARIABLEN

=over 4

=item SHELL

=item COMSPEC

local::lib schaut in die C<SHELL> Umgebungsvariable um die korrekten Kommandos
zu der Shell Konfiguration hinzuzufügen.

Auf Win32 Systemen, C<COMSPEC> wird auch analysiert.

=back

=head1 SUPPORT

IRC:

    Wir sind im Channel #local-lib auf dem Server irc.perl.org.

=head1 AUTOR DER ÜBERSETZUNG

Torsten Raudssus <torsten@raudssus.de> http://www.raudssus.de/

=head1 URHEBERRECHT

Copyright (c) 2007 - 2010 von den local::lib L<local::lib/"AUTHOR">
und L<local::lib/"CONTRIBUTORS"> aufgelistet in L<local::lib|local::lib>.

=head1 LIZENZ

Diese Sammlung ist freie Software und kann unter der selben Lizenz verbreitet
werden wie Perl selber.

=cut

1;
PK4N%[q���perl5/cPanelUserConfig.pmnu�[���# cpanel - cPanelUserConfig.pm                  Copyright(c) 2021 cPanel, L.L.C.
#                                                           All Rights Reserved.
# copyright@cpanel.net                                         http://cpanel.net
# This code is subject to the cPanel license. Unauthorized copying is prohibited

if ( $> != 0 ) {
    my $b__dir = ( getpwuid($>) )[7] . '/perl';
    unshift @INC, $b__dir . '5/lib/perl5', $b__dir . '5/lib/perl5/x86_64-linux-thread-multi', map { $b__dir . $_ } grep {$_ ne '.'} @INC;
}

1;
PK4N%[vy�!�1�1perl5/HTML/Tagset.pmnu��6�$package HTML::Tagset;

use strict;

=head1 NAME

HTML::Tagset - data tables useful in parsing HTML

=head1 VERSION

Version 3.24

=cut

our $VERSION = '3.24';

=head1 SYNOPSIS

  use HTML::Tagset;
  # Then use any of the items in the HTML::Tagset package
  #  as need arises

=head1 DESCRIPTION

This module contains several data tables useful in various kinds of
HTML parsing operations.

Note that all tag names used are lowercase.

In the following documentation, a "hashset" is a hash being used as a
set -- the hash conveys that its keys are there, and the actual values
associated with the keys are not significant.  (But what values are
there, are always true.)

=head1 VARIABLES

Note that none of these variables are exported.

=head2 hashset %HTML::Tagset::emptyElement

This hashset has as values the tag-names (GIs) of elements that cannot
have content.  (For example, "base", "br", "hr".)  So
C<$HTML::Tagset::emptyElement{'hr'}> exists and is true.
C<$HTML::Tagset::emptyElement{'dl'}> does not exist, and so is not true.

=cut

our %emptyElement   = map { $_ => 1 } qw(
                                     base link meta isindex
                                     img br hr wbr
                                     input area param
                                     embed bgsound spacer
                                     basefont col frame
                                     ~comment ~literal
                                     ~declaration ~pi
                                    );
# The "~"-initial names are for pseudo-elements used by HTML::Entities
#  and TreeBuilder

=head2 hashset %HTML::Tagset::optionalEndTag

This hashset lists tag-names for elements that can have content, but whose
end-tags are generally, "safely", omissible.  Example:
C<$HTML::Tagset::emptyElement{'li'}> exists and is true.

=cut

our %optionalEndTag = map { $_ => 1 } qw(
    p li dt dd
); # option th tr td);

=head2 hash %HTML::Tagset::linkElements

Values in this hash are tagnames for elements that might contain
links, and the value for each is a reference to an array of the names
of attributes whose values can be links.

=cut

our %linkElements =
(
 'a'       => ['href'],
 'applet'  => ['archive', 'codebase', 'code'],
 'area'    => ['href'],
 'base'    => ['href'],
 'bgsound' => ['src'],
 'blockquote' => ['cite'],
 'body'    => ['background'],
 'del'     => ['cite'],
 'embed'   => ['pluginspage', 'src'],
 'form'    => ['action'],
 'frame'   => ['src', 'longdesc'],
 'iframe'  => ['src', 'longdesc'],
 'ilayer'  => ['background'],
 'img'     => ['src', 'lowsrc', 'longdesc', 'usemap'],
 'input'   => ['src', 'usemap'],
 'ins'     => ['cite'],
 'isindex' => ['action'],
 'head'    => ['profile'],
 'layer'   => ['background', 'src'],
 'link'    => ['href'],
 'object'  => ['classid', 'codebase', 'data', 'archive', 'usemap'],
 'q'       => ['cite'],
 'script'  => ['src', 'for'],
 'table'   => ['background'],
 'td'      => ['background'],
 'th'      => ['background'],
 'tr'      => ['background'],
 'xmp'     => ['href'],
);

=head2 hash %HTML::Tagset::boolean_attr

This hash (not hashset) lists what attributes of what elements can be
printed without showing the value (for example, the "noshade" attribute
of "hr" elements).  For elements with only one such attribute, its value
is simply that attribute name.  For elements with many such attributes,
the value is a reference to a hashset containing all such attributes.

=cut

our %boolean_attr = (
# TODO: make these all hashes
  'area'   => 'nohref',
  'dir'    => 'compact',
  'dl'     => 'compact',
  'hr'     => 'noshade',
  'img'    => 'ismap',
  'input'  => { 'checked' => 1, 'readonly' => 1, 'disabled' => 1 },
  'menu'   => 'compact',
  'ol'     => 'compact',
  'option' => 'selected',
  'select' => 'multiple',
  'td'     => 'nowrap',
  'th'     => 'nowrap',
  'ul'     => 'compact',
);

#==========================================================================
# List of all elements from Extensible HTML version 1.0 Transitional DTD:
#
#   a abbr acronym address applet area b base basefont bdo big
#   blockquote body br button caption center cite code col colgroup
#   dd del dfn dir div dl dt em fieldset font form h1 h2 h3 h4 h5 h6
#   head hr html i iframe img input ins isindex kbd label legend li
#   link map menu meta noframes noscript object ol optgroup option p
#   param pre q s samp script select small span strike strong style
#   sub sup table tbody td textarea tfoot th thead title tr tt u ul
#   var
#
# Varia from Mozilla source internal table of tags:
#   Implemented:
#     xmp listing wbr nobr frame frameset noframes ilayer
#     layer nolayer spacer embed multicol
#   But these are unimplemented:
#     sound??  keygen??  server??
# Also seen here and there:
#     marquee??  app??  (both unimplemented)
#==========================================================================

=head2 hashset %HTML::Tagset::isPhraseMarkup

This hashset contains all phrasal-level elements.

=cut

our %isPhraseMarkup = map { $_ => 1 } qw(
  span abbr acronym q sub sup
  cite code em kbd samp strong var dfn strike
  b i u s tt small big
  ins del
  a img br
  wbr nobr blink
  font basefont bdo
  spacer embed noembed
);  # had: center, hr, table


=head2 hashset %HTML::Tagset::is_Possible_Strict_P_Content

This hashset contains all phrasal-level elements that be content of a
P element, for a strict model of HTML.

=cut

our %isFormElement; # Forward declaration
our %is_Possible_Strict_P_Content = (
 %isPhraseMarkup,
 %isFormElement,
 map {; $_ => 1} qw( object script map )
  # I've no idea why there's these latter exceptions.
  # I'm just following the HTML4.01 DTD.
);

#from html4 strict:
#<!ENTITY % fontstyle "TT | I | B | BIG | SMALL">
#
#<!ENTITY % phrase "EM | STRONG | DFN | CODE |
#                   SAMP | KBD | VAR | CITE | ABBR | ACRONYM" >
#
#<!ENTITY % special
#   "A | IMG | OBJECT | BR | SCRIPT | MAP | Q | SUB | SUP | SPAN | BDO">
#
#<!ENTITY % formctrl "INPUT | SELECT | TEXTAREA | LABEL | BUTTON">
#
#<!-- %inline; covers inline or "text-level" elements -->
#<!ENTITY % inline "#PCDATA | %fontstyle; | %phrase; | %special; | %formctrl;">

=head2 hashset %HTML::Tagset::isHeadElement

This hashset contains all elements that elements that should be
present only in the 'head' element of an HTML document.

=cut

our %isHeadElement = map { $_ => 1 }
 qw(title base link meta isindex script style object bgsound);

=head2 hashset %HTML::Tagset::isList

This hashset contains all elements that can contain "li" elements.

=cut

our %isList = map { $_ => 1 } qw(
    ul ol dir menu
);

=head2 hashset %HTML::Tagset::isTableElement

This hashset contains all elements that are to be found only in/under
a "table" element.

=cut

our %isTableElement = map { $_ => 1 }
 qw(tr td th thead tbody tfoot caption col colgroup);

=head2 hashset %HTML::Tagset::isFormElement

This hashset contains all elements that are to be found only in/under
a "form" element.

=cut

# Declared earlier in the file
%isFormElement = map { $_ => 1 }
 qw(input select option optgroup textarea button label);

=head2 hashset %HTML::Tagset::isBodyElement

This hashset contains all elements that are to be found only in/under
the "body" element of an HTML document.

=cut

our %isBodyElement = map { $_ => 1 } qw(
  h1 h2 h3 h4 h5 h6
  p div pre plaintext address blockquote
  xmp listing
  center

  multicol
  iframe ilayer nolayer
  bgsound

  hr
  ol ul dir menu li
  dl dt dd
  ins del

  fieldset legend

  map area
  applet param object
  isindex script noscript
  table
  center
  form
 ),
 keys %isFormElement,
 keys %isPhraseMarkup,   # And everything phrasal
 keys %isTableElement,
;


=head2 hashset %HTML::Tagset::isHeadOrBodyElement

This hashset includes all elements that I notice can fall either in
the head or in the body.

=cut

our %isHeadOrBodyElement = map { $_ => 1 }
  qw(script isindex style object map area param noscript bgsound);
  # i.e., if we find 'script' in the 'body' or the 'head', don't freak out.


=head2 hashset %HTML::Tagset::isKnown

This hashset lists all known HTML elements.

=cut

our %isKnown = (%isHeadElement, %isBodyElement,
  map{ $_ => 1 }
   qw( head body html
       frame frameset noframes
       ~comment ~pi ~directive ~literal
));
 # that should be all known tags ever ever


=head2 hashset %HTML::Tagset::canTighten

This hashset lists elements that might have ignorable whitespace as
children or siblings.

=cut

our %canTighten = %isKnown;
delete @canTighten{
  keys(%isPhraseMarkup), 'input', 'select',
  'xmp', 'listing', 'plaintext', 'pre',
};
  # xmp, listing, plaintext, and pre  are untightenable, and
  #   in a really special way.
@canTighten{'hr','br'} = (1,1);
 # exceptional 'phrasal' things that ARE subject to tightening.

# The one case where I can think of my tightening rules failing is:
#  <p>foo bar<center> <em>baz quux</em> ...
#                    ^-- that would get deleted.
# But that's pretty gruesome code anyhow.  You gets what you pays for.

#==========================================================================

=head2 array @HTML::Tagset::p_closure_barriers

This array has a meaning that I have only seen a need for in
C<HTML::TreeBuilder>, but I include it here on the off chance that someone
might find it of use:

When we see a "E<lt>pE<gt>" token, we go lookup up the lineage for a p
element we might have to minimize.  At first sight, we might say that
if there's a p anywhere in the lineage of this new p, it should be
closed.  But that's wrong.  Consider this document:

  <html>
    <head>
      <title>foo</title>
    </head>
    <body>
      <p>foo
        <table>
          <tr>
            <td>
               foo
               <p>bar
            </td>
          </tr>
        </table>
      </p>
    </body>
  </html>

The second p is quite legally inside a much higher p.

My formalization of the reason why this is legal, but this:

  <p>foo<p>bar</p></p>

isn't, is that something about the table constitutes a "barrier" to
the application of the rule about what p must minimize.

So C<@HTML::Tagset::p_closure_barriers> is the list of all such
barrier-tags.

=cut

our @p_closure_barriers = qw(
  li blockquote
  ul ol menu dir
  dl dt dd
  td th tr table caption
  div
 );

# In an ideal world (i.e., XHTML) we wouldn't have to bother with any of this
# monkey business of barriers to minimization!

=head2 hashset %isCDATA_Parent

This hashset includes all elements whose content is CDATA.

=cut

our %isCDATA_Parent = map { $_ => 1 }
  qw(script style  xmp listing plaintext);

# TODO: there's nothing else that takes CDATA children, right?

# As the HTML3 DTD (Raggett 1995-04-24) noted:
#   The XMP, LISTING and PLAINTEXT tags are incompatible with SGML
#   and derive from very early versions of HTML. They require non-
#   standard parsers and will cause problems for processing
#   documents with standard SGML tools.


=head1 CAVEATS

You may find it useful to alter the behavior of modules (like
C<HTML::Element> or C<HTML::TreeBuilder>) that use C<HTML::Tagset>'s
data tables by altering the data tables themselves.  You are welcome
to try, but be careful; and be aware that different modules may or may
react differently to the data tables being changed.

Note that it may be inappropriate to use these tables for I<producing>
HTML -- for example, C<%isHeadOrBodyElement> lists the tagnames
for all elements that can appear either in the head or in the body,
such as "script".  That doesn't mean that I am saying your code that
produces HTML should feel free to put script elements in either place!
If you are producing programs that spit out HTML, you should be
I<intimately> familiar with the DTDs for HTML or XHTML (available at
C<http://www.w3.org/>), and you should slavishly obey them, not
the data tables in this document.

=head1 SEE ALSO

L<HTML::Element>, L<HTML::TreeBuilder>, L<HTML::LinkExtor>

=head1 COPYRIGHT & LICENSE

Copyright 1995-2000 Gisle Aas.

Copyright 2000-2005 Sean M. Burke.

Copyright 2005-2024 Andy Lester.

This library is free software; you can redistribute it and/or modify it
under the terms of the Artistic License version 2.0.

=head1 ACKNOWLEDGEMENTS

Most of the code/data in this module was adapted from code written
by Gisle Aas for C<HTML::Element>, C<HTML::TreeBuilder>, and
C<HTML::LinkExtor>.  Then it was maintained by Sean M. Burke.

=head1 AUTHOR

Current maintainer: Andy Lester, C<< <andy at petdance.com> >>

=head1 BUGS

Please report any bugs or feature requests to
C<bug-html-tagset at rt.cpan.org>, or through the web interface at
L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=HTML-Tagset>.  I will
be notified, and then you'll automatically be notified of progress on
your bug as I make changes.

=cut

1;
PK5N%[�H�[k?k?perl5/HTTP/Request/Common.pmnu��6�$package HTTP::Request::Common;

use strict;
use warnings;

our $VERSION = '7.00';

our $DYNAMIC_FILE_UPLOAD ||= 0;  # make it defined (don't know why)
our $READ_BUFFER_SIZE      = 8192;

use Exporter 5.57 'import';

our @EXPORT =qw(GET HEAD PUT PATCH POST OPTIONS);
our @EXPORT_OK = qw($DYNAMIC_FILE_UPLOAD DELETE);

require HTTP::Request;
use Carp();
use File::Spec;

my $CRLF = "\015\012";   # "\r\n" is not portable

sub GET  { _simple_req('GET',  @_); }
sub HEAD { _simple_req('HEAD', @_); }
sub DELETE { _simple_req('DELETE', @_); }
sub PATCH { request_type_with_data('PATCH', @_); }
sub POST { request_type_with_data('POST', @_); }
sub PUT { request_type_with_data('PUT', @_); }
sub OPTIONS { request_type_with_data('OPTIONS', @_); }

sub request_type_with_data
{
    my $type = shift;
    my $url  = shift;
    my $req = HTTP::Request->new($type => $url);
    my $content;
    $content = shift if @_ and ref $_[0];
    my($k, $v);
    while (($k,$v) = splice(@_, 0, 2)) {
	if (lc($k) eq 'content') {
	    $content = $v;
	}
	else {
	    $req->push_header($k, $v);
	}
    }
    my $ct = $req->header('Content-Type');
    unless ($ct) {
	$ct = 'application/x-www-form-urlencoded';
    }
    elsif ($ct eq 'form-data') {
	$ct = 'multipart/form-data';
    }

    if (ref $content) {
	if ($ct =~ m,^multipart/form-data\s*(;|$),i) {
	    require HTTP::Headers::Util;
	    my @v = HTTP::Headers::Util::split_header_words($ct);
	    Carp::carp("Multiple Content-Type headers") if @v > 1;
	    @v = @{$v[0]};

	    my $boundary;
	    my $boundary_index;
	    for (my @tmp = @v; @tmp;) {
		my($k, $v) = splice(@tmp, 0, 2);
		if ($k eq "boundary") {
		    $boundary = $v;
		    $boundary_index = @v - @tmp - 1;
		    last;
		}
	    }

	    ($content, $boundary) = form_data($content, $boundary, $req);

	    if ($boundary_index) {
		$v[$boundary_index] = $boundary;
	    }
	    else {
		push(@v, boundary => $boundary);
	    }

	    $ct = HTTP::Headers::Util::join_header_words(@v);
	}
	else {
	    # We use a temporary URI object to format
	    # the application/x-www-form-urlencoded content.
	    require URI;
	    my $url = URI->new('http:');
	    $url->query_form(ref($content) eq "HASH" ? %$content : @$content);
	    $content = $url->query;
	}
    }

    $req->header('Content-Type' => $ct);  # might be redundant
    if (defined($content)) {
	$req->header('Content-Length' =>
		     length($content)) unless ref($content);
	$req->content($content);
    }
    else {
        $req->header('Content-Length' => 0);
    }
    $req;
}


sub _simple_req
{
    my($method, $url) = splice(@_, 0, 2);
    my $req = HTTP::Request->new($method => $url);
    my($k, $v);
    my $content;
    while (($k,$v) = splice(@_, 0, 2)) {
	if (lc($k) eq 'content') {
	    $req->add_content($v);
            $content++;
	}
	else {
	    $req->push_header($k, $v);
	}
    }
    if ($content && !defined($req->header("Content-Length"))) {
        $req->header("Content-Length", length(${$req->content_ref}));
    }
    $req;
}


sub form_data   # RFC1867
{
    my($data, $boundary, $req) = @_;
    my @data = ref($data) eq "HASH" ? %$data : @$data;  # copy
    my $fhparts;
    my @parts;
    while (my ($k,$v) = splice(@data, 0, 2)) {
	if (!ref($v)) {
	    $k =~ s/([\\\"])/\\$1/g;  # escape quotes and backslashes
            no warnings 'uninitialized';
	    push(@parts,
		 qq(Content-Disposition: form-data; name="$k"$CRLF$CRLF$v));
	}
	else {
	    my($file, $usename, @headers) = @$v;
	    unless (defined $usename) {
		$usename = $file;
		$usename = (File::Spec->splitpath($usename))[-1] if defined($usename);
	    }
            $k =~ s/([\\\"])/\\$1/g;
	    my $disp = qq(form-data; name="$k");
            if (defined($usename) and length($usename)) {
                $usename =~ s/([\\\"])/\\$1/g;
                $disp .= qq(; filename="$usename");
            }
	    my $content = "";
	    my $h = HTTP::Headers->new(@headers);
	    if ($file) {
		open(my $fh, "<", $file) or Carp::croak("Can't open file $file: $!");
		binmode($fh);
		if ($DYNAMIC_FILE_UPLOAD) {
		    # will read file later, close it now in order to
                    # not accumulate to many open file handles
                    close($fh);
		    $content = \$file;
		}
		else {
		    local($/) = undef; # slurp files
		    $content = <$fh>;
		    close($fh);
		}
		unless ($h->header("Content-Type")) {
		    require LWP::MediaTypes;
		    LWP::MediaTypes::guess_media_type($file, $h);
		}
	    }
	    if ($h->header("Content-Disposition")) {
		# just to get it sorted first
		$disp = $h->header("Content-Disposition");
		$h->remove_header("Content-Disposition");
	    }
	    if ($h->header("Content")) {
		$content = $h->header("Content");
		$h->remove_header("Content");
	    }
	    my $head = join($CRLF, "Content-Disposition: $disp",
			           $h->as_string($CRLF),
			           "");
	    if (ref $content) {
		push(@parts, [$head, $$content]);
		$fhparts++;
	    }
	    else {
		push(@parts, $head . $content);
	    }
	}
    }
    return ("", "none") unless @parts;

    my $content;
    if ($fhparts) {
	$boundary = boundary(10) # hopefully enough randomness
	    unless $boundary;

	# add the boundaries to the @parts array
	for (1..@parts-1) {
	    splice(@parts, $_*2-1, 0, "$CRLF--$boundary$CRLF");
	}
	unshift(@parts, "--$boundary$CRLF");
	push(@parts, "$CRLF--$boundary--$CRLF");

	# See if we can generate Content-Length header
	my $length = 0;
	for (@parts) {
	    if (ref $_) {
	 	my ($head, $f) = @$_;
		my $file_size;
		unless ( -f $f && ($file_size = -s _) ) {
		    # The file is either a dynamic file like /dev/audio
		    # or perhaps a file in the /proc file system where
		    # stat may return a 0 size even though reading it
		    # will produce data.  So we cannot make
		    # a Content-Length header.
		    undef $length;
		    last;
		}
	    	$length += $file_size + length $head;
	    }
	    else {
		$length += length;
	    }
        }
        $length && $req->header('Content-Length' => $length);

	# set up a closure that will return content piecemeal
	$content = sub {
	    for (;;) {
		unless (@parts) {
		    defined $length && $length != 0 &&
		    	Carp::croak "length of data sent did not match calculated Content-Length header.  Probably because uploaded file changed in size during transfer.";
		    return;
		}
		my $p = shift @parts;
		unless (ref $p) {
		    $p .= shift @parts while @parts && !ref($parts[0]);
		    defined $length && ($length -= length $p);
		    return $p;
		}
		my($buf, $fh) = @$p;
                unless (ref($fh)) {
                    my $file = $fh;
                    undef($fh);
                    open($fh, "<", $file) || Carp::croak("Can't open file $file: $!");
                    binmode($fh);
                }
		my $buflength = length $buf;
		my $n = read($fh, $buf, $READ_BUFFER_SIZE, $buflength);
		if ($n) {
		    $buflength += $n;
		    unshift(@parts, ["", $fh]);
		}
		else {
		    close($fh);
		}
		if ($buflength) {
		    defined $length && ($length -= $buflength);
		    return $buf
	    	}
	    }
	};

    }
    else {
	$boundary = boundary() unless $boundary;

	my $bno = 0;
      CHECK_BOUNDARY:
	{
	    for (@parts) {
		if (index($_, $boundary) >= 0) {
		    # must have a better boundary
		    $boundary = boundary(++$bno);
		    redo CHECK_BOUNDARY;
		}
	    }
	    last;
	}
	$content = "--$boundary$CRLF" .
	           join("$CRLF--$boundary$CRLF", @parts) .
		   "$CRLF--$boundary--$CRLF";
    }

    wantarray ? ($content, $boundary) : $content;
}


sub boundary
{
    my $size = shift || return "xYzZY";
    require MIME::Base64;
    my $b = MIME::Base64::encode(join("", map chr(rand(256)), 1..$size*3), "");
    $b =~ s/[\W]/X/g;  # ensure alnum only
    $b;
}

1;

=pod

=encoding UTF-8

=head1 NAME

HTTP::Request::Common - Construct common HTTP::Request objects

=head1 VERSION

version 7.00

=head1 SYNOPSIS

  use HTTP::Request::Common;
  $ua = LWP::UserAgent->new;
  $ua->request(GET 'http://www.sn.no/');
  $ua->request(POST 'http://somewhere/foo', foo => bar, bar => foo);
  $ua->request(PATCH 'http://somewhere/foo', foo => bar, bar => foo);
  $ua->request(PUT 'http://somewhere/foo', foo => bar, bar => foo);
  $ua->request(OPTIONS 'http://somewhere/foo', foo => bar, bar => foo);

=head1 DESCRIPTION

This module provides functions that return newly created C<HTTP::Request>
objects.  These functions are usually more convenient to use than the
standard C<HTTP::Request> constructor for the most common requests.

Note that L<LWP::UserAgent> has several convenience methods, including
C<get>, C<head>, C<delete>, C<post> and C<put>.

The following functions are provided:

=over 4

=item GET $url

=item GET $url, Header => Value,...

The C<GET> function returns an L<HTTP::Request> object initialized with
the "GET" method and the specified URL.  It is roughly equivalent to the
following call

  HTTP::Request->new(
     GET => $url,
     HTTP::Headers->new(Header => Value,...),
  )

but is less cluttered.  What is different is that a header named
C<Content> will initialize the content part of the request instead of
setting a header field.  Note that GET requests should normally not
have a content, so this hack makes more sense for the C<PUT>, C<PATCH>
 and C<POST> functions described below.

The C<get(...)> method of L<LWP::UserAgent> exists as a shortcut for
C<< $ua->request(GET ...) >>.

=item HEAD $url

=item HEAD $url, Header => Value,...

Like GET() but the method in the request is "HEAD".

The C<head(...)>  method of L<LWP::UserAgent> exists as a shortcut for
C<< $ua->request(HEAD ...) >>.

=item DELETE $url

=item DELETE $url, Header => Value,...

Like C<GET> but the method in the request is C<DELETE>.  This function
is not exported by default.

=item PATCH $url

=item PATCH $url, Header => Value,...

=item PATCH $url, $form_ref, Header => Value,...

=item PATCH $url, Header => Value,..., Content => $form_ref

=item PATCH $url, Header => Value,..., Content => $content

The same as C<POST> below, but the method in the request is C<PATCH>.

=item PUT $url

=item PUT $url, Header => Value,...

=item PUT $url, $form_ref, Header => Value,...

=item PUT $url, Header => Value,..., Content => $form_ref

=item PUT $url, Header => Value,..., Content => $content

The same as C<POST> below, but the method in the request is C<PUT>

=item OPTIONS $url

=item OPTIONS $url, Header => Value,...

=item OPTIONS $url, $form_ref, Header => Value,...

=item OPTIONS $url, Header => Value,..., Content => $form_ref

=item OPTIONS $url, Header => Value,..., Content => $content

The same as C<POST> below, but the method in the request is C<OPTIONS>

This was added in version 6.21, so you should require that in your code:

 use HTTP::Request::Common 6.21;

=item POST $url

=item POST $url, Header => Value,...

=item POST $url, $form_ref, Header => Value,...

=item POST $url, Header => Value,..., Content => $form_ref

=item POST $url, Header => Value,..., Content => $content

C<POST>, C<PATCH> and C<PUT> all work with the same parameters.

  %data = ( title => 'something', body => something else' );
  $ua = LWP::UserAgent->new();
  $request = HTTP::Request::Common::POST( $url, [ %data ] );
  $response = $ua->request($request);

They take a second optional array or hash reference
parameter C<$form_ref>.  The content can also be specified
directly using the C<Content> pseudo-header, and you may also provide
the C<$form_ref> this way.

The C<Content> pseudo-header steals a bit of the header field namespace as
there is no way to directly specify a header that is actually called
"Content".  If you really need this you must update the request
returned in a separate statement.

The C<$form_ref> argument can be used to pass key/value pairs for the
form content.  By default we will initialize a request using the
C<application/x-www-form-urlencoded> content type.  This means that
you can emulate an HTML E<lt>form> POSTing like this:

  POST 'http://www.perl.org/survey.cgi',
       [ name   => 'Gisle Aas',
         email  => 'gisle@aas.no',
         gender => 'M',
         born   => '1964',
         perc   => '3%',
       ];

This will create an L<HTTP::Request> object that looks like this:

  POST http://www.perl.org/survey.cgi
  Content-Length: 66
  Content-Type: application/x-www-form-urlencoded

  name=Gisle%20Aas&email=gisle%40aas.no&gender=M&born=1964&perc=3%25

Multivalued form fields can be specified by either repeating the field
name or by passing the value as an array reference.

The POST method also supports the C<multipart/form-data> content used
for I<Form-based File Upload> as specified in RFC 1867.  You trigger
this content format by specifying a content type of C<'form-data'> as
one of the request headers.  If one of the values in the C<$form_ref> is
an array reference, then it is treated as a file part specification
with the following interpretation:

  [ $file, $filename, Header => Value... ]
  [ undef, $filename, Header => Value,..., Content => $content ]

The first value in the array ($file) is the name of a file to open.
This file will be read and its content placed in the request.  The
routine will croak if the file can't be opened.  Use an C<undef> as
$file value if you want to specify the content directly with a
C<Content> header.  The $filename is the filename to report in the
request.  If this value is undefined, then the basename of the $file
will be used.  You can specify an empty string as $filename if you
want to suppress sending the filename when you provide a $file value.

If a $file is provided by no C<Content-Type> header, then C<Content-Type>
and C<Content-Encoding> will be filled in automatically with the values
returned by C<LWP::MediaTypes::guess_media_type()>

Sending my F<~/.profile> to the survey used as example above can be
achieved by this:

  POST 'http://www.perl.org/survey.cgi',
       Content_Type => 'form-data',
       Content      => [ name  => 'Gisle Aas',
                         email => 'gisle@aas.no',
                         gender => 'M',
                         born   => '1964',
                         init   => ["$ENV{HOME}/.profile"],
                       ]

This will create an L<HTTP::Request> object that almost looks this (the
boundary and the content of your F<~/.profile> is likely to be
different):

  POST http://www.perl.org/survey.cgi
  Content-Length: 388
  Content-Type: multipart/form-data; boundary="6G+f"

  --6G+f
  Content-Disposition: form-data; name="name"

  Gisle Aas
  --6G+f
  Content-Disposition: form-data; name="email"

  gisle@aas.no
  --6G+f
  Content-Disposition: form-data; name="gender"

  M
  --6G+f
  Content-Disposition: form-data; name="born"

  1964
  --6G+f
  Content-Disposition: form-data; name="init"; filename=".profile"
  Content-Type: text/plain

  PATH=/local/perl/bin:$PATH
  export PATH

  --6G+f--

If you set the C<$DYNAMIC_FILE_UPLOAD> variable (exportable) to some TRUE
value, then you get back a request object with a subroutine closure as
the content attribute.  This subroutine will read the content of any
files on demand and return it in suitable chunks.  This allow you to
upload arbitrary big files without using lots of memory.  You can even
upload infinite files like F</dev/audio> if you wish; however, if
the file is not a plain file, there will be no C<Content-Length> header
defined for the request.  Not all servers (or server
applications) like this.  Also, if the file(s) change in size between
the time the C<Content-Length> is calculated and the time that the last
chunk is delivered, the subroutine will C<Croak>.

The C<post(...)>  method of L<LWP::UserAgent> exists as a shortcut for
C<< $ua->request(POST ...) >>.

=back

=head1 SEE ALSO

L<HTTP::Request>, L<LWP::UserAgent>

Also, there are some examples in L<HTTP::Request/"EXAMPLES"> that you might
find useful. For example, batch requests are explained there.

=head1 AUTHOR

Gisle Aas <gisle@activestate.com>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 1994 by Gisle Aas.

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

=cut

__END__


#ABSTRACT: Construct common HTTP::Request objects
PK5N%[�8o��>�>perl5/HTTP/Negotiate.pmnu��6�$package HTTP::Negotiate;

$VERSION = "6.01";
sub Version { $VERSION; }

require Exporter;
@ISA = qw(Exporter);
@EXPORT = qw(choose);

require HTTP::Headers;

$DEBUG = 0;

sub choose ($;$)
{
    my($variants, $request) = @_;
    my(%accept);

    unless (defined $request) {
	# Create a request object from the CGI environment variables
	$request = HTTP::Headers->new;
	$request->header('Accept', $ENV{HTTP_ACCEPT})
	  if $ENV{HTTP_ACCEPT};
	$request->header('Accept-Charset', $ENV{HTTP_ACCEPT_CHARSET})
	  if $ENV{HTTP_ACCEPT_CHARSET};
	$request->header('Accept-Encoding', $ENV{HTTP_ACCEPT_ENCODING})
	  if $ENV{HTTP_ACCEPT_ENCODING};
	$request->header('Accept-Language', $ENV{HTTP_ACCEPT_LANGUAGE})
	  if $ENV{HTTP_ACCEPT_LANGUAGE};
    }

    # Get all Accept values from the request.  Build a hash initialized
    # like this:
    #
    #   %accept = ( type =>     { 'audio/*'     => { q => 0.2, mbx => 20000 },
    #                             'audio/basic' => { q => 1 },
    #                           },
    #               language => { 'no'          => { q => 1 },
    #                           }
    #             );

    $request->scan(sub {
	my($key, $val) = @_;

	my $type;
	if ($key =~ s/^Accept-//) {
	    $type = lc($key);
	}
	elsif ($key eq "Accept") {
	    $type = "type";
	}
	else {
	    return;
	}

	$val =~ s/\s+//g;
	my $default_q = 1;
	for my $name (split(/,/, $val)) {
	    my(%param, $param);
	    if ($name =~ s/;(.*)//) {
		for $param (split(/;/, $1)) {
		    my ($pk, $pv) = split(/=/, $param, 2);
		    $param{lc $pk} = $pv;
		}
	    }
	    $name = lc $name;
	    if (defined $param{'q'}) {
		$param{'q'} = 1 if $param{'q'} > 1;
		$param{'q'} = 0 if $param{'q'} < 0;
	    }
	    else {
		$param{'q'} = $default_q;

		# This makes sure that the first ones are slightly better off
		# and therefore more likely to be chosen.
		$default_q -= 0.0001;
	    }
	    $accept{$type}{$name} = \%param;
	}
    });

    # Check if any of the variants specify a language.  We do this
    # because it influences how we treat those without (they default to
    # 0.5 instead of 1).
    my $any_lang = 0;
    for $var (@$variants) {
	if ($var->[5]) {
	    $any_lang = 1;
	    last;
	}
    }

    if ($DEBUG) {
	print "Negotiation parameters in the request\n";
	for $type (keys %accept) {
	    print " $type:\n";
	    for $name (keys %{$accept{$type}}) {
		print "    $name\n";
		for $pv (keys %{$accept{$type}{$name}}) {
		    print "      $pv = $accept{$type}{$name}{$pv}\n";
		}
	    }
	}
    }

    my @Q = ();  # This is where we collect the results of the
		 # quality calculations

    # Calculate quality for all the variants that are available.
    for (@$variants) {
	my($id, $qs, $ct, $enc, $cs, $lang, $bs) = @$_;
	$qs = 1 unless defined $qs;
        $ct = '' unless defined $ct;
	$bs = 0 unless defined $bs;
	$lang = lc($lang) if $lang; # lg tags are always case-insensitive
	if ($DEBUG) {
	    print "\nEvaluating $id (ct='$ct')\n";
	    printf "  qs   = %.3f\n", $qs;
	    print  "  enc  = $enc\n"  if $enc && !ref($enc);
	    print  "  enc  = @$enc\n" if $enc && ref($enc);
	    print  "  cs   = $cs\n"   if $cs;
	    print  "  lang = $lang\n" if $lang;
	    print  "  bs   = $bs\n"   if $bs;
	}

	# Calculate encoding quality
	my $qe = 1;
	# If the variant has no assigned Content-Encoding, or if no
	# Accept-Encoding field is present, then the value assigned
	# is "qe=1".  If *all* of the variant's content encodings
	# are listed in the Accept-Encoding field, then the value
	# assigned is "qw=1".  If *any* of the variant's content
	# encodings are not listed in the provided Accept-Encoding
	# field, then the value assigned is "qe=0"
	if (exists $accept{'encoding'} && $enc) {
	    my @enc = ref($enc) ? @$enc : ($enc);
	    for (@enc) {
		print "Is encoding $_ accepted? " if $DEBUG;
		unless(exists $accept{'encoding'}{$_}) {
		    print "no\n" if $DEBUG;
		    $qe = 0;
		    last;
		}
		else {
		    print "yes\n" if $DEBUG;
		}
	    }
	}

	# Calculate charset quality
	my $qc  = 1;
	# If the variant's media-type has no charset parameter,
	# or the variant's charset is US-ASCII, or if no Accept-Charset
	# field is present, then the value assigned is "qc=1".  If the
	# variant's charset is listed in the Accept-Charset field,
	# then the value assigned is "qc=1.  Otherwise, if the variant's
	# charset is not listed in the provided Accept-Encoding field,
	# then the value assigned is "qc=0".
	if (exists $accept{'charset'} && $cs && $cs ne 'us-ascii' ) {
	    $qc = 0 unless $accept{'charset'}{$cs};
	}

	# Calculate language quality
	my $ql  = 1;
	if ($lang && exists $accept{'language'}) {
	    my @lang = ref($lang) ? @$lang : ($lang);
	    # If any of the variant's content languages are listed
	    # in the Accept-Language field, the the value assigned is
	    # the largest of the "q" parameter values for those language
	    # tags.
	    my $q = undef;
	    for (@lang) {
		next unless exists $accept{'language'}{$_};
		my $this_q = $accept{'language'}{$_}{'q'};
		$q = $this_q unless defined $q;
		$q = $this_q if $this_q > $q;
	    }
	    if(defined $q) {
	        $DEBUG and print " -- Exact language match at q=$q\n";
	    }
	    else {
		# If there was no exact match and at least one of
		# the Accept-Language field values is a complete
		# subtag prefix of the content language tag(s), then
		# the "q" parameter value of the largest matching
		# prefix is used.
		$DEBUG and print " -- No exact language match\n";
		my $selected = undef;
		for $al (keys %{ $accept{'language'} }) {
		    if (index($al, "$lang-") == 0) {
		        # $lang starting with $al isn't enough, or else
		        #  Accept-Language: hu (Hungarian) would seem
		        #  to accept a document in hup (Hupa)
		        $DEBUG and print " -- $al ISA $lang\n";
			$selected = $al unless defined $selected;
			$selected = $al if length($al) > length($selected);
		    }
		    else {
		        $DEBUG and print " -- $lang  isn't a $al\n";
		    }
		}
		$q = $accept{'language'}{$selected}{'q'} if $selected;

		# If none of the variant's content language tags or
		# tag prefixes are listed in the provided
		# Accept-Language field, then the value assigned
		# is "ql=0.001"
		$q = 0.001 unless defined $q;
	    }
	    $ql = $q;
	}
	else {
	    $ql = 0.5 if $any_lang && exists $accept{'language'};
	}

	my $q   = 1;
	my $mbx = undef;
	# If no Accept field is given, then the value assigned is "q=1".
	# If at least one listed media range matches the variant's media
	# type, then the "q" parameter value assigned to the most specific
	# of those matched is used (e.g. "text/html;version=3.0" is more
	# specific than "text/html", which is more specific than "text/*",
	# which in turn is more specific than "*/*"). If not media range
	# in the provided Accept field matches the variant's media type,
	# then the value assigned is "q=0".
	if (exists $accept{'type'} && $ct) {
	    # First we clean up our content-type
	    $ct =~ s/\s+//g;
	    my $params = "";
	    $params = $1 if $ct =~ s/;(.*)//;
	    my($type, $subtype) = split("/", $ct, 2);
	    my %param = ();
	    for $param (split(/;/, $params)) {
		my($pk,$pv) = split(/=/, $param, 2);
		$param{$pk} = $pv;
	    }

	    my $sel_q = undef;
	    my $sel_mbx = undef;
	    my $sel_specificness = 0;

	    ACCEPT_TYPE:
	    for $at (keys %{ $accept{'type'} }) {
		print "Consider $at...\n" if $DEBUG;
		my($at_type, $at_subtype) = split("/", $at, 2);
		# Is it a match on the type
		next if $at_type    ne '*' && $at_type    ne $type;
		next if $at_subtype ne '*' && $at_subtype ne $subtype;
		my $specificness = 0;
		$specificness++ if $at_type ne '*';
		$specificness++ if $at_subtype ne '*';
		# Let's see if content-type parameters also match
		while (($pk, $pv) = each %param) {
		    print "Check if $pk = $pv is true\n" if $DEBUG;
		    next unless exists $accept{'type'}{$at}{$pk};
		    next ACCEPT_TYPE
		      unless $accept{'type'}{$at}{$pk} eq $pv;
		    print "yes it is!!\n" if $DEBUG;
		    $specificness++;
		}
		print "Hurray, type match with specificness = $specificness\n"
		  if $DEBUG;

		if (!defined($sel_q) || $sel_specificness < $specificness) {
		    $sel_q   = $accept{'type'}{$at}{'q'};
		    $sel_mbx = $accept{'type'}{$at}{'mbx'};
		    $sel_specificness = $specificness;
		}
	    }
	    $q   = $sel_q || 0;
	    $mbx = $sel_mbx;
	}

	my $Q;
	if (!defined($mbx) || $mbx >= $bs) {
	    $Q = $qs * $qe * $qc * $ql * $q;
	}
	else {
	    $Q = 0;
	    print "Variant's size is too large ==> Q=0\n" if $DEBUG;
	}

	if ($DEBUG) {
	    $mbx = "undef" unless defined $mbx;
	    printf "Q=%.4f", $Q;
	    print "  (q=$q, mbx=$mbx, qe=$qe, qc=$qc, ql=$ql, qs=$qs)\n";
	}

	push(@Q, [$id, $Q, $bs]);
    }


    @Q = sort { $b->[1] <=> $a->[1] || $a->[2] <=> $b->[2] } @Q;

    return @Q if wantarray;
    return undef unless @Q;
    return undef if $Q[0][1] == 0;
    $Q[0][0];
}

1;

__END__


=head1 NAME

HTTP::Negotiate - choose a variant to serve

=head1 SYNOPSIS

 use HTTP::Negotiate qw(choose);

 #  ID       QS     Content-Type   Encoding Char-Set        Lang   Size
 $variants =
  [['var1',  1.000, 'text/html',   undef,   'iso-8859-1',   'en',   3000],
   ['var2',  0.950, 'text/plain',  'gzip',  'us-ascii',     'no',    400],
   ['var3',  0.3,   'image/gif',   undef,   undef,          undef, 43555],
  ];

 @preferred = choose($variants, $request_headers);
 $the_one   = choose($variants);

=head1 DESCRIPTION

This module provides a complete implementation of the HTTP content
negotiation algorithm specified in F<draft-ietf-http-v11-spec-00.ps>
chapter 12.  Content negotiation allows for the selection of a
preferred content representation based upon attributes of the
negotiable variants and the value of the various Accept* header fields
in the request.

The variants are ordered by preference by calling the function
choose().

The first parameter is reference to an array of the variants to
choose among.
Each element in this array is an array with the values [$id, $qs,
$content_type, $content_encoding, $charset, $content_language,
$content_length] whose meanings are described
below. The $content_encoding and $content_language can be either a
single scalar value or an array reference if there are several values.

The second optional parameter is either a HTTP::Headers or a HTTP::Request
object which is searched for "Accept*" headers.  If this
parameter is missing, then the accept specification is initialized
from the CGI environment variables HTTP_ACCEPT, HTTP_ACCEPT_CHARSET,
HTTP_ACCEPT_ENCODING and HTTP_ACCEPT_LANGUAGE.

In an array context, choose() returns a list of [variant
identifier, calculated quality, size] tuples.  The values are sorted by
quality, highest quality first.  If the calculated quality is the same
for two variants, then they are sorted by size (smallest first). I<E.g.>:

  (['var1', 1, 2000], ['var2', 0.3, 512], ['var3', 0.3, 1024]);

Note that also zero quality variants are included in the return list
even if these should never be served to the client.

In a scalar context, it returns the identifier of the variant with the
highest score or C<undef> if none have non-zero quality.

If the $HTTP::Negotiate::DEBUG variable is set to TRUE, then a lot of
noise is generated on STDOUT during evaluation of choose().

=head1 VARIANTS

A variant is described by a list of the following values.  If the
attribute does not make sense or is unknown for a variant, then use
C<undef> instead.

=over 3

=item identifier

This is a string that you use as the name for the variant.  This
identifier for the preferred variants returned by choose().

=item qs

This is a number between 0.000 and 1.000 that describes the "source
quality".  This is what F<draft-ietf-http-v11-spec-00.ps> says about this
value:

Source quality is measured by the content provider as representing the
amount of degradation from the original source.  For example, a
picture in JPEG form would have a lower qs when translated to the XBM
format, and much lower qs when translated to an ASCII-art
representation.  Note, however, that this is a function of the source
- an original piece of ASCII-art may degrade in quality if it is
captured in JPEG form.  The qs values should be assigned to each
variant by the content provider; if no qs value has been assigned, the
default is generally "qs=1".

=item content-type

This is the media type of the variant.  The media type does not
include a charset attribute, but might contain other parameters.
Examples are:

  text/html
  text/html;version=2.0
  text/plain
  image/gif
  image/jpg

=item content-encoding

This is one or more content encodings that has been applied to the
variant.  The content encoding is generally used as a modifier to the
content media type.  The most common content encodings are:

  gzip
  compress

=item content-charset

This is the character set used when the variant contains text.
The charset value should generally be C<undef> or one of these:

  us-ascii
  iso-8859-1 ... iso-8859-9
  iso-2022-jp
  iso-2022-jp-2
  iso-2022-kr
  unicode-1-1
  unicode-1-1-utf-7
  unicode-1-1-utf-8

=item content-language

This describes one or more languages that are used in the variant.
Language is described like this in F<draft-ietf-http-v11-spec-00.ps>: A
language is in this context a natural language spoken, written, or
otherwise conveyed by human beings for communication of information to
other human beings.  Computer languages are explicitly excluded.

The language tags are defined by RFC 3066.  Examples
are:

  no               Norwegian
  en               International English
  en-US            US English
  en-cockney

=item content-length

This is the number of bytes used to represent the content.

=back

=head1 ACCEPT HEADERS

The following Accept* headers can be used for describing content
preferences in a request (This description is an edited extract from
F<draft-ietf-http-v11-spec-00.ps>):

=over 3

=item Accept

This header can be used to indicate a list of media ranges which are
acceptable as a response to the request.  The "*" character is used to
group media types into ranges, with "*/*" indicating all media types
and "type/*" indicating all subtypes of that type.

The parameter q is used to indicate the quality factor, which
represents the user's preference for that range of media types.  The
parameter mbx gives the maximum acceptable size of the response
content. The default values are: q=1 and mbx=infinity. If no Accept
header is present, then the client accepts all media types with q=1.

For example:

  Accept: audio/*;q=0.2;mbx=200000, audio/basic

would mean: "I prefer audio/basic (of any size), but send me any audio
type if it is the best available after an 80% mark-down in quality and
its size is less than 200000 bytes"


=item Accept-Charset

Used to indicate what character sets are acceptable for the response.
The "us-ascii" character set is assumed to be acceptable for all user
agents.  If no Accept-Charset field is given, the default is that any
charset is acceptable.  Example:

  Accept-Charset: iso-8859-1, unicode-1-1


=item Accept-Encoding

Restricts the Content-Encoding values which are acceptable in the
response.  If no Accept-Encoding field is present, the server may
assume that the client will accept any content encoding.  An empty
Accept-Encoding means that no content encoding is acceptable.  Example:

  Accept-Encoding: compress, gzip


=item Accept-Language

This field is similar to Accept, but restricts the set of natural
languages that are preferred in a response.  Each language may be
given an associated quality value which represents an estimate of the
user's comprehension of that language.  For example:

  Accept-Language: no, en-gb;q=0.8, de;q=0.55

would mean: "I prefer Norwegian, but will accept British English (with
80% comprehension) or German (with 55% comprehension).

=back


=head1 COPYRIGHT

Copyright 1996,2001 Gisle Aas.

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

=head1 AUTHOR

Gisle Aas <gisle@aas.no>

=cut
PK5N%[|�f�%.%.perl5/HTTP/Config.pmnu��6�$package HTTP::Config;

use strict;
use warnings;

our $VERSION = '7.00';

use URI;

sub new {
    my $class = shift;
    return bless [], $class;
}

sub entries {
    my $self = shift;
    @$self;
}

sub empty {
    my $self = shift;
    not @$self;
}

sub add {
    if (@_ == 2) {
        my $self = shift;
        push(@$self, shift);
        return;
    }
    my($self, %spec) = @_;
    push(@$self, \%spec);
    return;
}

sub find2 {
    my($self, %spec) = @_;
    my @found;
    my @rest;
 ITEM:
    for my $item (@$self) {
        for my $k (keys %spec) {
            no warnings 'uninitialized';
            if (!exists $item->{$k} || $spec{$k} ne $item->{$k}) {
                push(@rest, $item);
                next ITEM;
            }
        }
        push(@found, $item);
    }
    return \@found unless wantarray;
    return \@found, \@rest;
}

sub find {
    my $self = shift;
    my $f = $self->find2(@_);
    return @$f if wantarray;
    return $f->[0];
}

sub remove {
    my($self, %spec) = @_;
    my($removed, $rest) = $self->find2(%spec);
    @$self = @$rest if @$removed;
    return @$removed;
}

my %MATCH = (
    m_scheme => sub {
        my($v, $uri) = @_;
        return $uri->_scheme eq $v;  # URI known to be canonical
    },
    m_secure => sub {
        my($v, $uri) = @_;
        my $secure = $uri->can("secure") ? $uri->secure : $uri->_scheme eq "https";
        return $secure == !!$v;
    },
    m_host_port => sub {
        my($v, $uri) = @_;
        return unless $uri->can("host_port");
        return $uri->host_port eq $v, 7;
    },
    m_host => sub {
        my($v, $uri) = @_;
        return unless $uri->can("host");
        return $uri->host eq $v, 6;
    },
    m_port => sub {
        my($v, $uri) = @_;
        return unless $uri->can("port");
        return $uri->port eq $v;
    },
    m_domain => sub {
        my($v, $uri) = @_;
        return unless $uri->can("host");
        my $h = $uri->host;
        $h = "$h.local" unless $h =~ /\./;
        $v = ".$v" unless $v =~ /^\./;
        return length($v), 5 if substr($h, -length($v)) eq $v;
        return 0;
    },
    m_path => sub {
        my($v, $uri) = @_;
        return unless $uri->can("path");
        return $uri->path eq $v, 4;
    },
    m_path_prefix => sub {
        my($v, $uri) = @_;
        return unless $uri->can("path");
        my $path = $uri->path;
        my $len = length($v);
        return $len, 3 if $path eq $v;
        return 0 if length($path) <= $len;
        $v .= "/" unless $v =~ m,/\z,,;
        return $len, 3 if substr($path, 0, length($v)) eq $v;
        return 0;
    },
    m_path_match => sub {
        my($v, $uri) = @_;
        return unless $uri->can("path");
        return $uri->path =~ $v;
    },
    m_uri__ => sub {
        my($v, $k, $uri) = @_;
        return unless $uri->can($k);
        return 1 unless defined $v;
        return $uri->$k eq $v;
    },
    m_method => sub {
        my($v, $uri, $request) = @_;
        return $request && $request->method eq $v;
    },
    m_proxy => sub {
        my($v, $uri, $request) = @_;
        return $request && ($request->{proxy} || "") eq $v;
    },
    m_code => sub {
        my($v, $uri, $request, $response) = @_;
        $v =~ s/xx\z//;
        return unless $response;
        return length($v), 2 if substr($response->code, 0, length($v)) eq $v;
    },
    m_media_type => sub {  # for request too??
        my($v, $uri, $request, $response) = @_;
        return unless $response;
        return 1, 1 if $v eq "*/*";
        my $ct = $response->content_type;
        return 2, 1 if $v =~ s,/\*\z,, && $ct =~ m,^\Q$v\E/,;
        return 3, 1 if $v eq "html" && $response->content_is_html;
        return 4, 1 if $v eq "xhtml" && $response->content_is_xhtml;
        return 10, 1 if $v eq $ct;
        return 0;
    },
    m_header__ => sub {
        my($v, $k, $uri, $request, $response) = @_;
        return unless $request;
        my $req_header = $request->header($k);
        return 1 if defined($req_header) && $req_header eq $v;
        if ($response) {
            my $res_header = $response->header($k);
            return 1 if defined($res_header) && $res_header eq $v;
        }
        return 0;
    },
    m_response_attr__ => sub {
        my($v, $k, $uri, $request, $response) = @_;
        return unless $response;
        return 1 if !defined($v) && exists $response->{$k};
        return 0 unless exists $response->{$k};
        return 1 if $response->{$k} eq $v;
        return 0;
    },
);

sub matching {
    my $self = shift;
    if (@_ == 1) {
        if ($_[0]->can("request")) {
            unshift(@_, $_[0]->request);
            unshift(@_, undef) unless defined $_[0];
        }
        unshift(@_, $_[0]->uri_canonical) if $_[0] && $_[0]->can("uri_canonical");
    }
    my($uri, $request, $response) = @_;
    $uri = URI->new($uri) unless ref($uri);

    my @m;
 ITEM:
    for my $item (@$self) {
        my $order;
        for my $ikey (keys %$item) {
            my $mkey = $ikey;
            my $k;
            $k = $1 if $mkey =~ s/__(.*)/__/;
            if (my $m = $MATCH{$mkey}) {
                #print "$ikey $mkey\n";
                my($c, $o);
                my @arg = (
                    defined($k) ? $k : (),
                    $uri, $request, $response
                );
                my $v = $item->{$ikey};
                $v = [$v] unless ref($v) eq "ARRAY";
                for (@$v) {
                    ($c, $o) = $m->($_, @arg);
                    #print "  - $_ ==> $c $o\n";
                    last if $c;
                }
                next ITEM unless $c;
                $order->[$o || 0] += $c;
            }
        }
        $order->[7] ||= 0;
        $item->{_order} = join(".", reverse map sprintf("%03d", $_ || 0), @$order);
        push(@m, $item);
    }
    @m = sort { $b->{_order} cmp $a->{_order} } @m;
    delete $_->{_order} for @m;
    return @m if wantarray;
    return $m[0];
}

sub add_item {
    my $self = shift;
    my $item = shift;
    return $self->add(item => $item, @_);
}

sub remove_items {
    my $self = shift;
    return map $_->{item}, $self->remove(@_);
}

sub matching_items {
    my $self = shift;
    return map $_->{item}, $self->matching(@_);
}

1;

=pod

=encoding UTF-8

=head1 NAME

HTTP::Config - Configuration for request and response objects

=head1 VERSION

version 7.00

=head1 SYNOPSIS

 use HTTP::Config;
 my $c = HTTP::Config->new;
 $c->add(m_domain => ".example.com", m_scheme => "http", verbose => 1);
 
 use HTTP::Request;
 my $request = HTTP::Request->new(GET => "http://www.example.com");
 
 if (my @m = $c->matching($request)) {
    print "Yadayada\n" if $m[0]->{verbose};
 }

=head1 DESCRIPTION

An C<HTTP::Config> object is a list of entries that
can be matched against request or request/response pairs.  Its
purpose is to hold configuration data that can be looked up given a
request or response object.

Each configuration entry is a hash.  Some keys specify matching to
occur against attributes of request/response objects.  Other keys can
be used to hold user data.

The following methods are provided:

=over 4

=item $conf = HTTP::Config->new

Constructs a new empty C<HTTP::Config> object and returns it.

=item $conf->entries

Returns the list of entries in the configuration object.
In scalar context returns the number of entries.

=item $conf->empty

Return true if there are no entries in the configuration object.
This is just a shorthand for C<< not $conf->entries >>.

=item $conf->add( %matchspec, %other )

=item $conf->add( \%entry )

Adds a new entry to the configuration.
You can either pass separate key/value pairs or a hash reference.

=item $conf->remove( %spec )

Removes (and returns) the entries that have matches for all the key/value pairs in %spec.
If %spec is empty this will match all entries; so it will empty the configuration object.

=item $conf->matching( $uri, $request, $response )

=item $conf->matching( $uri )

=item $conf->matching( $request )

=item $conf->matching( $response )

Returns the entries that match the given $uri, $request and $response triplet.

If called with a single $request object then the $uri is obtained by calling its 'uri_canonical' method.
If called with a single $response object, then the request object is obtained by calling its 'request' method;
and then the $uri is obtained as if a single $request was provided.

The entries are returned with the most specific matches first.
In scalar context returns the most specific match or C<undef> in none match.

=item $conf->add_item( $item, %matchspec )

=item $conf->remove_items( %spec )

=item $conf->matching_items( $uri, $request, $response )

Wrappers that hides the entries themselves.

=back

=head2 Matching

The following keys on a configuration entry specify matching.  For all
of these you can provide an array of values instead of a single value.
The entry matches if at least one of the values in the array matches.

Entries that require match against a response object attribute will never match
unless a response object was provided.

=over

=item m_scheme => $scheme

Matches if the URI uses the specified scheme; e.g. "http".

=item m_secure => $bool

If $bool is TRUE; matches if the URI uses a secure scheme.  If $bool
is FALSE; matches if the URI does not use a secure scheme.  An example
of a secure scheme is "https".

=item m_host_port => "$hostname:$port"

Matches if the URI's host_port method return the specified value.

=item m_host => $hostname

Matches if the URI's host method returns the specified value.

=item m_port => $port

Matches if the URI's port method returns the specified value.

=item m_domain => ".$domain"

Matches if the URI's host method return a value that within the given
domain.  The hostname "www.example.com" will for instance match the
domain ".com".

=item m_path => $path

Matches if the URI's path method returns the specified value.

=item m_path_prefix => $path

Matches if the URI's path is the specified path or has the specified
path as prefix.

=item m_path_match => $Regexp

Matches if the regular expression matches the URI's path.  Eg. qr/\.html$/.

=item m_method => $method

Matches if the request method matches the specified value. Eg. "GET" or "POST".

=item m_code => $digit

=item m_code => $status_code

Matches if the response status code matches.  If a single digit is
specified; matches for all response status codes beginning with that digit.

=item m_proxy => $url

Matches if the request is to be sent to the given Proxy server.

=item m_media_type => "*/*"

=item m_media_type => "text/*"

=item m_media_type => "html"

=item m_media_type => "xhtml"

=item m_media_type => "text/html"

Matches if the response media type matches.

With a value of "html" matches if $response->content_is_html returns TRUE.
With a value of "xhtml" matches if $response->content_is_xhtml returns TRUE.

=item m_uri__I<$method> => undef

Matches if the URI object provides the method.

=item m_uri__I<$method> => $string

Matches if the URI's $method method returns the given value.

=item m_header__I<$field> => $string

Matches if either the request or the response have a header $field with the given value.

=item m_response_attr__I<$key> => undef

=item m_response_attr__I<$key> => $string

Matches if the response object has that key, or the entry has the given value.

=back

=head1 SEE ALSO

L<URI>, L<HTTP::Request>, L<HTTP::Response>

=head1 AUTHOR

Gisle Aas <gisle@activestate.com>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 1994 by Gisle Aas.

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

=cut

__END__


#ABSTRACT: Configuration for request and response objects

PK5N%[�68��"�"perl5/HTTP/Request.pmnu��6�$package HTTP::Request;

use strict;
use warnings;

our $VERSION = '7.00';

use parent 'HTTP::Message';

sub new
{
    my($class, $method, $uri, $header, $content) = @_;
    my $self = $class->SUPER::new($header, $content);
    $self->method($method);
    $self->uri($uri);
    $self;
}


sub parse
{
    my($class, $str) = @_;
    Carp::carp('Undefined argument to parse()') if $^W && ! defined $str;
    my $request_line;
    if (defined $str && $str =~ s/^(.*)\n//) {
	$request_line = $1;
    }
    else {
	$request_line = $str;
	$str = "";
    }

    my $self = $class->SUPER::parse($str);
    if (defined $request_line) {
        my($method, $uri, $protocol) = split(' ', $request_line);
        $self->method($method);
        $self->uri($uri) if defined($uri);
        $self->protocol($protocol) if $protocol;
    }
    $self;
}


sub clone
{
    my $self = shift;
    my $clone = bless $self->SUPER::clone, ref($self);
    $clone->method($self->method);
    $clone->uri($self->uri);
    $clone;
}


sub method
{
    shift->_elem('_method', @_);
}


sub uri
{
    my $self = shift;
    my $old = $self->{'_uri'};
    if (@_) {
	my $uri = shift;
	if (!defined $uri) {
	    # that's ok
	}
	elsif (ref $uri) {
	    Carp::croak("A URI can't be a " . ref($uri) . " reference")
		if ref($uri) eq 'HASH' or ref($uri) eq 'ARRAY';
	    Carp::croak("Can't use a " . ref($uri) . " object as a URI")
		unless $uri->can('scheme') && $uri->can('canonical');
	    $uri = $uri->clone;
	    unless ($HTTP::URI_CLASS eq "URI") {
		# Argh!! Hate this... old LWP legacy!
		eval { local $SIG{__DIE__}; $uri = $uri->abs; };
		die $@ if $@ && $@ !~ /Missing base argument/;
	    }
	}
	else {
	    $uri = $HTTP::URI_CLASS->new($uri);
	}
	$self->{'_uri'} = $uri;
        delete $self->{'_uri_canonical'};
    }
    $old;
}

*url = \&uri;  # legacy

sub uri_canonical
{
    my $self = shift;

    my $uri = $self->{_uri};

    if (defined (my $canon = $self->{_uri_canonical})) {
        # early bailout if these are the exact same string;
        # rely on stringification of the URI objects
        return $canon if $canon eq $uri;
    }

    # otherwise we need to refresh the memoized value
    $self->{_uri_canonical} = $uri->canonical;
}


sub accept_decodable
{
    my $self = shift;
    $self->header("Accept-Encoding", scalar($self->decodable));
}

sub as_string
{
    my $self = shift;
    my($eol) = @_;
    $eol = "\n" unless defined $eol;

    my $req_line = $self->method || "-";
    my $uri = $self->uri;
    $uri = (defined $uri) ? $uri->as_string : "-";
    $req_line .= " $uri";
    my $proto = $self->protocol;
    $req_line .= " $proto" if $proto;

    return join($eol, $req_line, $self->SUPER::as_string(@_));
}

sub dump
{
    my $self = shift;
    my @pre = ($self->method || "-", $self->uri || "-");
    if (my $prot = $self->protocol) {
	push(@pre, $prot);
    }

    return $self->SUPER::dump(
        preheader => join(" ", @pre),
	@_,
    );
}


1;

=pod

=encoding UTF-8

=head1 NAME

HTTP::Request - HTTP style request message

=head1 VERSION

version 7.00

=head1 SYNOPSIS

 require HTTP::Request;
 $request = HTTP::Request->new(GET => 'http://www.example.com/');

and usually used like this:

 $ua = LWP::UserAgent->new;
 $response = $ua->request($request);

=head1 DESCRIPTION

C<HTTP::Request> is a class encapsulating HTTP style requests,
consisting of a request line, some headers, and a content body. Note
that the LWP library uses HTTP style requests even for non-HTTP
protocols.  Instances of this class are usually passed to the
request() method of an C<LWP::UserAgent> object.

C<HTTP::Request> is a subclass of C<HTTP::Message> and therefore
inherits its methods.  The following additional methods are available:

=over 4

=item $r = HTTP::Request->new( $method, $uri )

=item $r = HTTP::Request->new( $method, $uri, $header )

=item $r = HTTP::Request->new( $method, $uri, $header, $content )

Constructs a new C<HTTP::Request> object describing a request on the
object $uri using method $method.  The $method argument must be a
string.  The $uri argument can be either a string, or a reference to a
C<URI> object.  The optional $header argument should be a reference to
an C<HTTP::Headers> object or a plain array reference of key/value
pairs.  The optional $content argument should be a string of bytes.

=item $r = HTTP::Request->parse( $str )

This constructs a new request object by parsing the given string.

=item $r->method

=item $r->method( $val )

This is used to get/set the method attribute.  The method should be a
short string like "GET", "HEAD", "PUT", "PATCH" or "POST".

=item $r->uri

=item $r->uri( $val )

This is used to get/set the uri attribute.  The $val can be a
reference to a URI object or a plain string.  If a string is given,
then it should be parsable as an absolute URI.

=item $r->header( $field )

=item $r->header( $field => $value )

This is used to get/set header values and it is inherited from
C<HTTP::Headers> via C<HTTP::Message>.  See L<HTTP::Headers> for
details and other similar methods that can be used to access the
headers.

=item $r->accept_decodable

This will set the C<Accept-Encoding> header to the list of encodings
that decoded_content() can decode.

=item $r->content

=item $r->content( $bytes )

This is used to get/set the content and it is inherited from the
C<HTTP::Message> base class.  See L<HTTP::Message> for details and
other methods that can be used to access the content.

Note that the content should be a string of bytes.  Strings in perl
can contain characters outside the range of a byte.  The C<Encode>
module can be used to turn such strings into a string of bytes.

=item $r->as_string

=item $r->as_string( $eol )

Method returning a textual representation of the request.

=back

=head1 EXAMPLES

Creating requests to be sent with L<LWP::UserAgent> or others can be easy. Here
are a few examples.

=head2 Simple POST

Here, we'll create a simple POST request that could be used to send JSON data
to an endpoint.

    #!/usr/bin/env perl

    use strict;
    use warnings;

    use HTTP::Request ();
    use JSON::MaybeXS qw(encode_json);

    my $url = 'https://www.example.com/api/user/123';
    my $header = ['Content-Type' => 'application/json; charset=UTF-8'];
    my $data = {foo => 'bar', baz => 'quux'};
    my $encoded_data = encode_json($data);

    my $r = HTTP::Request->new('POST', $url, $header, $encoded_data);
    # at this point, we could send it via LWP::UserAgent
    # my $ua = LWP::UserAgent->new();
    # my $res = $ua->request($r);

=head2 Batch POST Request

Some services, like Google, allow multiple requests to be sent in one batch.
L<https://developers.google.com/drive/v3/web/batch> for example. Using the
C<add_part> method from L<HTTP::Message> makes this simple.

    #!/usr/bin/env perl

    use strict;
    use warnings;

    use HTTP::Request ();
    use JSON::MaybeXS qw(encode_json);

    my $auth_token = 'auth_token';
    my $batch_url = 'https://www.googleapis.com/batch';
    my $url = 'https://www.googleapis.com/drive/v3/files/fileId/permissions?fields=id';
    my $url_no_email = 'https://www.googleapis.com/drive/v3/files/fileId/permissions?fields=id&sendNotificationEmail=false';

    # generate a JSON post request for one of the batch entries
    my $req1 = build_json_request($url, {
        emailAddress => 'example@appsrocks.com',
        role => "writer",
        type => "user",
    });

    # generate a JSON post request for one of the batch entries
    my $req2 = build_json_request($url_no_email, {
        domain => "appsrocks.com",
        role => "reader",
        type => "domain",
    });

    # generate a multipart request to send all of the other requests
    my $r = HTTP::Request->new('POST', $batch_url, [
        'Accept-Encoding' => 'gzip',
        # if we don't provide a boundary here, HTTP::Message will generate
        # one for us. We could use UUID::uuid() here if we wanted.
        'Content-Type' => 'multipart/mixed; boundary=END_OF_PART'
    ]);

    # add the two POST requests to the main request
    $r->add_part($req1, $req2);
    # at this point, we could send it via LWP::UserAgent
    # my $ua = LWP::UserAgent->new();
    # my $res = $ua->request($r);
    exit();

    sub build_json_request {
        my ($url, $href) = @_;
        my $header = ['Authorization' => "Bearer $auth_token", 'Content-Type' => 'application/json; charset=UTF-8'];
        return HTTP::Request->new('POST', $url, $header, encode_json($href));
    }

=head1 SEE ALSO

L<HTTP::Headers>, L<HTTP::Message>, L<HTTP::Request::Common>,
L<HTTP::Response>

=head1 AUTHOR

Gisle Aas <gisle@activestate.com>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 1994 by Gisle Aas.

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

=cut

__END__


#ABSTRACT: HTTP style request message
PK5N%[d�zE>E>perl5/HTTP/Tiny.pmnu��6�$# vim: ts=4 sts=4 sw=4 et:
package HTTP::Tiny;
use strict;
use warnings;
# ABSTRACT: A small, simple, correct HTTP/1.1 client

our $VERSION = '0.090';

sub _croak { require Carp; Carp::croak(@_) }

#pod =method new
#pod
#pod     $http = HTTP::Tiny->new( %attributes );
#pod
#pod This constructor returns a new HTTP::Tiny object.  Valid attributes include:
#pod
#pod =for :list
#pod * C<agent> — A user-agent string (defaults to 'HTTP-Tiny/$VERSION'). If
#pod   C<agent> — ends in a space character, the default user-agent string is
#pod   appended.
#pod * C<cookie_jar> — An instance of L<HTTP::CookieJar> — or equivalent class
#pod   that supports the C<add> and C<cookie_header> methods
#pod * C<default_headers> — A hashref of default headers to apply to requests
#pod * C<local_address> — The local IP address to bind to
#pod * C<keep_alive> — Whether to reuse the last connection (if for the same
#pod   scheme, host and port) (defaults to 1)
#pod * C<max_redirect> — Maximum number of redirects allowed (defaults to 5)
#pod * C<max_size> — Maximum response size in bytes (only when not using a data
#pod   callback).  If defined, requests with responses larger than this will return
#pod   a 599 status code.
#pod * C<http_proxy> — URL of a proxy server to use for HTTP connections
#pod   (default is C<$ENV{http_proxy}> — if set)
#pod * C<https_proxy> — URL of a proxy server to use for HTTPS connections
#pod   (default is C<$ENV{https_proxy}> — if set)
#pod * C<proxy> — URL of a generic proxy server for both HTTP and HTTPS
#pod   connections (default is C<$ENV{all_proxy}> — if set)
#pod * C<no_proxy> — List of domain suffixes that should not be proxied.  Must
#pod   be a comma-separated string or an array reference. (default is
#pod   C<$ENV{no_proxy}> —)
#pod * C<timeout> — Request timeout in seconds (default is 60) If a socket open,
#pod   read or write takes longer than the timeout, the request response status code
#pod   will be 599.
#pod * C<verify_SSL> — A boolean that indicates whether to validate the TLS/SSL
#pod   certificate of an C<https> — connection (default is true). Changed from false
#pod   to true in version 0.083.
#pod * C<SSL_options> — A hashref of C<SSL_*> — options to pass through to
#pod   L<IO::Socket::SSL>
#pod * C<$ENV{PERL_HTTP_TINY_SSL_INSECURE_BY_DEFAULT}> - Changes the default
#pod   certificate verification behavior to not check server identity if set to 1.
#pod   Only effective if C<verify_SSL> is not set. Added in version 0.083.
#pod
#pod
#pod An accessor/mutator method exists for each attribute.
#pod
#pod Passing an explicit C<undef> for C<proxy>, C<http_proxy> or C<https_proxy> will
#pod prevent getting the corresponding proxies from the environment.
#pod
#pod Errors during request execution will result in a pseudo-HTTP status code of 599
#pod and a reason of "Internal Exception". The content field in the response will
#pod contain the text of the error.
#pod
#pod The C<keep_alive> parameter enables a persistent connection, but only to a
#pod single destination scheme, host and port.  If any connection-relevant
#pod attributes are modified via accessor, or if the process ID or thread ID change,
#pod the persistent connection will be dropped.  If you want persistent connections
#pod across multiple destinations, use multiple HTTP::Tiny objects.
#pod
#pod See L</TLS/SSL SUPPORT> for more on the C<verify_SSL> and C<SSL_options>
#pod attributes.
#pod
#pod =cut

my @attributes;
BEGIN {
    @attributes = qw(
        cookie_jar default_headers http_proxy https_proxy keep_alive
        local_address max_redirect max_size proxy no_proxy
        SSL_options verify_SSL
    );
    my %persist_ok = map {; $_ => 1 } qw(
        cookie_jar default_headers max_redirect max_size
    );
    no strict 'refs';
    no warnings 'uninitialized';
    for my $accessor ( @attributes ) {
        *{$accessor} = sub {
            @_ > 1
                ? do {
                    delete $_[0]->{handle} if !$persist_ok{$accessor} && $_[1] ne $_[0]->{$accessor};
                    $_[0]->{$accessor} = $_[1]
                }
                : $_[0]->{$accessor};
        };
    }
}

sub agent {
    my($self, $agent) = @_;
    if( @_ > 1 ){
        $self->{agent} =
            (defined $agent && $agent =~ / $/) ? $agent . $self->_agent : $agent;
    }
    return $self->{agent};
}

sub timeout {
    my ($self, $timeout) = @_;
    if ( @_ > 1 ) {
        $self->{timeout} = $timeout;
        if ($self->{handle}) {
            $self->{handle}->timeout($timeout);
        }
    }
    return $self->{timeout};
}

sub new {
    my($class, %args) = @_;

    # Support lower case verify_ssl argument, but only if verify_SSL is not
    # true.
    if ( exists $args{verify_ssl} ) {
        $args{verify_SSL}  ||= $args{verify_ssl};
    }

    my $self = {
        max_redirect => 5,
        timeout      => defined $args{timeout} ? $args{timeout} : 60,
        keep_alive   => 1,
        verify_SSL   => defined $args{verify_SSL} ? $args{verify_SSL} : _verify_SSL_default(),
        no_proxy     => $ENV{no_proxy},
    };

    bless $self, $class;

    $class->_validate_cookie_jar( $args{cookie_jar} ) if $args{cookie_jar};

    for my $key ( @attributes ) {
        $self->{$key} = $args{$key} if exists $args{$key}
    }

    $self->agent( exists $args{agent} ? $args{agent} : $class->_agent );

    $self->_set_proxies;

    return $self;
}

sub _verify_SSL_default {
    my ($self) = @_;
    # Check if insecure default certificate verification behaviour has been
    # changed by the user by setting PERL_HTTP_TINY_SSL_INSECURE_BY_DEFAULT=1
    return (($ENV{PERL_HTTP_TINY_SSL_INSECURE_BY_DEFAULT} || '') eq '1') ? 0 : 1;
}

sub _set_proxies {
    my ($self) = @_;

    # get proxies from %ENV only if not provided; explicit undef will disable
    # getting proxies from the environment

    # generic proxy
    if (! exists $self->{proxy} ) {
        $self->{proxy} = $ENV{all_proxy} || $ENV{ALL_PROXY};
    }

    if ( defined $self->{proxy} ) {
        $self->_split_proxy( 'generic proxy' => $self->{proxy} ); # validate
    }
    else {
        delete $self->{proxy};
    }

    # http proxy
    if (! exists $self->{http_proxy} ) {
        # under CGI, bypass HTTP_PROXY as request sets it from Proxy header
        local $ENV{HTTP_PROXY} = ($ENV{CGI_HTTP_PROXY} || "") if $ENV{REQUEST_METHOD};
        $self->{http_proxy} = $ENV{http_proxy} || $ENV{HTTP_PROXY} || $self->{proxy};
    }

    if ( defined $self->{http_proxy} ) {
        $self->_split_proxy( http_proxy => $self->{http_proxy} ); # validate
        $self->{_has_proxy}{http} = 1;
    }
    else {
        delete $self->{http_proxy};
    }

    # https proxy
    if (! exists $self->{https_proxy} ) {
        $self->{https_proxy} = $ENV{https_proxy} || $ENV{HTTPS_PROXY} || $self->{proxy};
    }

    if ( $self->{https_proxy} ) {
        $self->_split_proxy( https_proxy => $self->{https_proxy} ); # validate
        $self->{_has_proxy}{https} = 1;
    }
    else {
        delete $self->{https_proxy};
    }

    # Split no_proxy to array reference if not provided as such
    unless ( ref $self->{no_proxy} eq 'ARRAY' ) {
        $self->{no_proxy} =
            (defined $self->{no_proxy}) ? [ split /\s*,\s*/, $self->{no_proxy} ] : [];
    }

    return;
}

#pod =method get|head|put|post|patch|delete
#pod
#pod     $response = $http->get($url);
#pod     $response = $http->get($url, \%options);
#pod     $response = $http->head($url);
#pod
#pod These methods are shorthand for calling C<request()> for the given method.  The
#pod URL must have unsafe characters escaped and international domain names encoded.
#pod See C<request()> for valid options and a description of the response.
#pod
#pod The C<success> field of the response will be true if the status code is 2XX.
#pod
#pod =cut

for my $sub_name ( qw/get head put post patch delete/ ) {
    my $req_method = uc $sub_name;
    no strict 'refs';
    eval <<"HERE"; ## no critic
    sub $sub_name {
        my (\$self, \$url, \$args) = \@_;
        \@_ == 2 || (\@_ == 3 && ref \$args eq 'HASH')
        or _croak(q/Usage: \$http->$sub_name(URL, [HASHREF])/ . "\n");
        return \$self->request('$req_method', \$url, \$args || {});
    }
HERE
}

#pod =method post_form
#pod
#pod     $response = $http->post_form($url, $form_data);
#pod     $response = $http->post_form($url, $form_data, \%options);
#pod
#pod This method executes a C<POST> request and sends the key/value pairs from a
#pod form data hash or array reference to the given URL with a C<content-type> of
#pod C<application/x-www-form-urlencoded>.  If data is provided as an array
#pod reference, the order is preserved; if provided as a hash reference, the terms
#pod are sorted by key for consistency.  See documentation for the
#pod C<www_form_urlencode> method for details on the encoding.
#pod
#pod The URL must have unsafe characters escaped and international domain names
#pod encoded.  See C<request()> for valid options and a description of the response.
#pod Any C<content-type> header or content in the options hashref will be ignored.
#pod
#pod The C<success> field of the response will be true if the status code is 2XX.
#pod
#pod =cut

sub post_form {
    my ($self, $url, $data, $args) = @_;
    (@_ == 3 || @_ == 4 && ref $args eq 'HASH')
        or _croak(q/Usage: $http->post_form(URL, DATAREF, [HASHREF])/ . "\n");

    my $headers = {};
    while ( my ($key, $value) = each %{$args->{headers} || {}} ) {
        $headers->{lc $key} = $value;
    }

    return $self->request('POST', $url, {
            # Any existing 'headers' key in $args will be overridden with a
            # normalized version below.
            %$args,
            content => $self->www_form_urlencode($data),
            headers => {
                %$headers,
                'content-type' => 'application/x-www-form-urlencoded'
            },
        }
    );
}

#pod =method mirror
#pod
#pod     $response = $http->mirror($url, $file, \%options)
#pod     if ( $response->{success} ) {
#pod         print "$file is up to date\n";
#pod     }
#pod
#pod Executes a C<GET> request for the URL and saves the response body to the file
#pod name provided.  The URL must have unsafe characters escaped and international
#pod domain names encoded.  If the file already exists, the request will include an
#pod C<If-Modified-Since> header with the modification timestamp of the file.  You
#pod may specify a different C<If-Modified-Since> header yourself in the C<<
#pod $options->{headers} >> hash.
#pod
#pod The C<success> field of the response will be true if the status code is 2XX
#pod or if the status code is 304 (unmodified).
#pod
#pod If the file was modified and the server response includes a properly
#pod formatted C<Last-Modified> header, the file modification time will
#pod be updated accordingly.
#pod
#pod =cut

sub mirror {
    my ($self, $url, $file, $args) = @_;
    @_ == 3 || (@_ == 4 && ref $args eq 'HASH')
      or _croak(q/Usage: $http->mirror(URL, FILE, [HASHREF])/ . "\n");

    if ( exists $args->{headers} ) {
        my $headers = {};
        while ( my ($key, $value) = each %{$args->{headers} || {}} ) {
            $headers->{lc $key} = $value;
        }
        $args->{headers} = $headers;
    }

    if ( -e $file and my $mtime = (stat($file))[9] ) {
        $args->{headers}{'if-modified-since'} ||= $self->_http_date($mtime);
    }
    my $tempfile = $file . int(rand(2**31));

    require Fcntl;
    sysopen my $fh, $tempfile, Fcntl::O_CREAT()|Fcntl::O_EXCL()|Fcntl::O_WRONLY()
       or _croak(qq/Error: Could not create temporary file $tempfile for downloading: $!\n/);
    binmode $fh;
    $args->{data_callback} = sub { print {$fh} $_[0] };
    my $response = $self->request('GET', $url, $args);
    close $fh
        or _croak(qq/Error: Caught error closing temporary file $tempfile: $!\n/);

    if ( $response->{success} ) {
        rename $tempfile, $file
            or _croak(qq/Error replacing $file with $tempfile: $!\n/);
        my $lm = $response->{headers}{'last-modified'};
        if ( $lm and my $mtime = $self->_parse_http_date($lm) ) {
            utime $mtime, $mtime, $file;
        }
    }
    $response->{success} ||= $response->{status} eq '304';
    unlink $tempfile;
    return $response;
}

#pod =method request
#pod
#pod     $response = $http->request($method, $url);
#pod     $response = $http->request($method, $url, \%options);
#pod
#pod Executes an HTTP request of the given method type ('GET', 'HEAD', 'POST',
#pod 'PUT', etc.) on the given URL.  The URL must have unsafe characters escaped and
#pod international domain names encoded.
#pod
#pod B<NOTE>: Method names are B<case-sensitive> per the HTTP/1.1 specification.
#pod Don't use C<get> when you really want C<GET>.  See L<LIMITATIONS> for
#pod how this applies to redirection.
#pod
#pod If the URL includes a "user:password" stanza, they will be used for Basic-style
#pod authorization headers.  (Authorization headers will not be included in a
#pod redirected request.) For example:
#pod
#pod     $http->request('GET', 'http://Aladdin:open sesame@example.com/');
#pod
#pod If the "user:password" stanza contains reserved characters, they must
#pod be percent-escaped:
#pod
#pod     $http->request('GET', 'http://john%40example.com:password@example.com/');
#pod
#pod A hashref of options may be appended to modify the request.
#pod
#pod Valid options are:
#pod
#pod =for :list
#pod * C<headers> —
#pod     A hashref containing headers to include with the request.  If the value for
#pod     a header is an array reference, the header will be output multiple times with
#pod     each value in the array.  These headers over-write any default headers.
#pod * C<content> —
#pod     A scalar to include as the body of the request OR a code reference
#pod     that will be called iteratively to produce the body of the request
#pod * C<trailer_callback> —
#pod     A code reference that will be called if it exists to provide a hashref
#pod     of trailing headers (only used with chunked transfer-encoding)
#pod * C<data_callback> —
#pod     A code reference that will be called for each chunks of the response
#pod     body received.
#pod * C<peer> —
#pod     Override host resolution and force all connections to go only to a
#pod     specific peer address, regardless of the URL of the request.  This will
#pod     include any redirections!  This options should be used with extreme
#pod     caution (e.g. debugging or very special circumstances). It can be given as
#pod     either a scalar or a code reference that will receive the hostname and
#pod     whose response will be taken as the address.
#pod
#pod The C<Host> header is generated from the URL in accordance with RFC 2616.  It
#pod is a fatal error to specify C<Host> in the C<headers> option.  Other headers
#pod may be ignored or overwritten if necessary for transport compliance.
#pod
#pod If the C<content> option is a code reference, it will be called iteratively
#pod to provide the content body of the request.  It should return the empty
#pod string or undef when the iterator is exhausted.
#pod
#pod If the C<content> option is the empty string, no C<content-type> or
#pod C<content-length> headers will be generated.
#pod
#pod If the C<data_callback> option is provided, it will be called iteratively until
#pod the entire response body is received.  The first argument will be a string
#pod containing a chunk of the response body, the second argument will be the
#pod in-progress response hash reference, as described below.  (This allows
#pod customizing the action of the callback based on the C<status> or C<headers>
#pod received prior to the content body.)
#pod
#pod Content data in the request/response is handled as "raw bytes".  Any
#pod encoding/decoding (with associated headers) are the responsibility of the
#pod caller.
#pod
#pod The C<request> method returns a hashref containing the response.  The hashref
#pod will have the following keys:
#pod
#pod =for :list
#pod * C<success> —
#pod     Boolean indicating whether the operation returned a 2XX status code
#pod * C<url> —
#pod     URL that provided the response. This is the URL of the request unless
#pod     there were redirections, in which case it is the last URL queried
#pod     in a redirection chain
#pod * C<status> —
#pod     The HTTP status code of the response
#pod * C<reason> —
#pod     The response phrase returned by the server
#pod * C<content> —
#pod     The body of the response.  If the response does not have any content
#pod     or if a data callback is provided to consume the response body,
#pod     this will be the empty string
#pod * C<headers> —
#pod     A hashref of header fields.  All header field names will be normalized
#pod     to be lower case. If a header is repeated, the value will be an arrayref;
#pod     it will otherwise be a scalar string containing the value
#pod * C<protocol> -
#pod     If this field exists, it is the protocol of the response
#pod     such as HTTP/1.0 or HTTP/1.1
#pod * C<redirects>
#pod     If this field exists, it is an arrayref of response hash references from
#pod     redirects in the same order that redirections occurred.  If it does
#pod     not exist, then no redirections occurred.
#pod
#pod On an error during the execution of the request, the C<status> field will
#pod contain 599, and the C<content> field will contain the text of the error.
#pod
#pod =cut

my %idempotent = map { $_ => 1 } qw/GET HEAD PUT DELETE OPTIONS TRACE/;

sub request {
    my ($self, $method, $url, $args) = @_;
    @_ == 3 || (@_ == 4 && ref $args eq 'HASH')
      or _croak(q/Usage: $http->request(METHOD, URL, [HASHREF])/ . "\n");
    $args ||= {}; # we keep some state in this during _request

    # RFC 2616 Section 8.1.4 mandates a single retry on broken socket
    my $response;
    for ( 0 .. 1 ) {
        $response = eval { $self->_request($method, $url, $args) };
        last unless $@ && $idempotent{$method}
            && $@ =~ m{^(?:Socket closed|Unexpected end|SSL read error)};
    }

    if (my $e = $@) {
        # maybe we got a response hash thrown from somewhere deep
        if ( ref $e eq 'HASH' && exists $e->{status} ) {
            $e->{redirects} = delete $args->{_redirects} if @{ $args->{_redirects} || []};
            return $e;
        }

        # otherwise, stringify it
        $e = "$e";
        $response = {
            url     => $url,
            success => q{},
            status  => 599,
            reason  => 'Internal Exception',
            content => $e,
            headers => {
                'content-type'   => 'text/plain',
                'content-length' => length $e,
            },
            ( @{$args->{_redirects} || []} ? (redirects => delete $args->{_redirects}) : () ),
        };
    }
    return $response;
}

#pod =method www_form_urlencode
#pod
#pod     $params = $http->www_form_urlencode( $data );
#pod     $response = $http->get("http://example.com/query?$params");
#pod
#pod This method converts the key/value pairs from a data hash or array reference
#pod into a C<x-www-form-urlencoded> string.  The keys and values from the data
#pod reference will be UTF-8 encoded and escaped per RFC 3986.  If a value is an
#pod array reference, the key will be repeated with each of the values of the array
#pod reference.  If data is provided as a hash reference, the key/value pairs in the
#pod resulting string will be sorted by key and value for consistent ordering.
#pod
#pod =cut

sub www_form_urlencode {
    my ($self, $data) = @_;
    (@_ == 2 && ref $data)
        or _croak(q/Usage: $http->www_form_urlencode(DATAREF)/ . "\n");
    (ref $data eq 'HASH' || ref $data eq 'ARRAY')
        or _croak("form data must be a hash or array reference\n");

    my @params
        = ref $data eq 'HASH'
        ? map { ($_ => $data->{$_}) } sort keys %$data
        : @$data;
    @params % 2 == 0
        or _croak("form data reference must have an even number of terms\n");

    my @terms;
    while( @params ) {
        my ($key, $value) = splice(@params, 0, 2);
        _croak("form data keys must not be undef")
            if !defined($key);
        if ( ref $value eq 'ARRAY' ) {
            unshift @params, map { $key => $_ } @$value;
        }
        else {
            push @terms, join("=", map { $self->_uri_escape($_) } $key, $value);
        }
    }

    return join("&", @terms);
}

#pod =method can_ssl
#pod
#pod     $ok         = HTTP::Tiny->can_ssl;
#pod     ($ok, $why) = HTTP::Tiny->can_ssl;
#pod     ($ok, $why) = $http->can_ssl;
#pod
#pod Indicates if SSL support is available.  When called as a class object, it
#pod checks for the correct version of L<Net::SSLeay> and L<IO::Socket::SSL>.
#pod When called as an object methods, if C<SSL_verify> is true or if C<SSL_verify_mode>
#pod is set in C<SSL_options>, it checks that a CA file is available.
#pod
#pod In scalar context, returns a boolean indicating if SSL is available.
#pod In list context, returns the boolean and a (possibly multi-line) string of
#pod errors indicating why SSL isn't available.
#pod
#pod =cut

sub can_ssl {
    my ($self) = @_;

    my($ok, $reason) = (1, '');

    # Need IO::Socket::SSL 1.968 for default_ca()
    local @INC = @INC;
    pop @INC if $INC[-1] eq '.';
    unless (eval {require IO::Socket::SSL; IO::Socket::SSL->VERSION(1.968)}) {
        $ok = 0;
        $reason .= qq/IO::Socket::SSL 1.968 or later must be installed for https support\n/;
    }

    # Need Net::SSLeay 1.49 for MODE_AUTO_RETRY
    unless (eval {require Net::SSLeay; Net::SSLeay->VERSION(1.49)}) {
        $ok = 0;
        $reason .= qq/Net::SSLeay 1.49 or later must be installed for https support\n/;
    }

    # If an object, check that SSL config lets us get a CA if necessary
    if ( ref($self) && ( $self->{verify_SSL} || $self->{SSL_options}{SSL_verify_mode} ) ) {
        my $handle = HTTP::Tiny::Handle->new(
            SSL_options => $self->{SSL_options},
            verify_SSL  => $self->{verify_SSL},
        );
        unless ( eval { $handle->_find_CA; 1 } ) {
            $ok = 0;
            $reason .= "$@";
        }
    }

    wantarray ? ($ok, $reason) : $ok;
}

#pod =method connected
#pod
#pod     $host = $http->connected;
#pod     ($host, $port) = $http->connected;
#pod
#pod Indicates if a connection to a peer is being kept alive, per the C<keep_alive>
#pod option.
#pod
#pod In scalar context, returns the peer host and port, joined with a colon, or
#pod C<undef> (if no peer is connected).
#pod In list context, returns the peer host and port or an empty list (if no peer
#pod is connected).
#pod
#pod B<Note>: This method cannot reliably be used to discover whether the remote
#pod host has closed its end of the socket.
#pod
#pod =cut

sub connected {
    my ($self) = @_;

    if ( $self->{handle} ) {
        return $self->{handle}->connected;
    }
    return;
}

#--------------------------------------------------------------------------#
# private methods
#--------------------------------------------------------------------------#

my %DefaultPort = (
    http => 80,
    https => 443,
);

sub _agent {
    my $class = ref($_[0]) || $_[0];
    (my $default_agent = $class) =~ s{::}{-}g;
    my $version = $class->VERSION;
    $default_agent .= "/$version" if defined $version;
    return $default_agent;
}

sub _request {
    my ($self, $method, $url, $args) = @_;

    my ($scheme, $host, $port, $path_query, $auth) = $self->_split_url($url);

    if ($scheme ne 'http' && $scheme ne 'https') {
      die(qq/Unsupported URL scheme '$scheme'\n/);
    }

    my $request = {
        method    => $method,
        scheme    => $scheme,
        host      => $host,
        port      => $port,
        host_port => ($port == $DefaultPort{$scheme} ? $host : "$host:$port"),
        uri       => $path_query,
        headers   => {},
    };

    my $peer = $args->{peer} || $host;

    # Allow 'peer' to be a coderef.
    if ('CODE' eq ref $peer) {
        $peer = $peer->($host);
    }

    # We remove the cached handle so it is not reused in the case of redirect.
    # If all is well, it will be recached at the end of _request.  We only
    # reuse for the same scheme, host and port
    my $handle = delete $self->{handle};
    if ( $handle ) {
        unless ( $handle->can_reuse( $scheme, $host, $port, $peer ) ) {
            $handle->close;
            undef $handle;
        }
    }
    $handle ||= $self->_open_handle( $request, $scheme, $host, $port, $peer );

    $self->_prepare_headers_and_cb($request, $args, $url, $auth);
    $handle->write_request($request);

    my $response;
    do { $response = $handle->read_response_header }
        until (substr($response->{status},0,1) ne '1');

    $self->_update_cookie_jar( $url, $response ) if $self->{cookie_jar};
    my @redir_args = $self->_maybe_redirect($request, $response, $args);

    my $known_message_length;
    if ($method eq 'HEAD' || $response->{status} =~ /^[23]04/) {
        # response has no message body
        $known_message_length = 1;
    }
    else {
        # Ignore any data callbacks during redirection.
        my $cb_args = @redir_args ? +{} : $args;
        my $data_cb = $self->_prepare_data_cb($response, $cb_args);
        $known_message_length = $handle->read_body($data_cb, $response);
    }

    if ( $self->{keep_alive}
        && $handle->connected
        && $known_message_length
        && $response->{protocol} eq 'HTTP/1.1'
        && ($response->{headers}{connection} || '') ne 'close'
    ) {
        $self->{handle} = $handle;
    }
    else {
        $handle->close;
    }

    $response->{success} = substr( $response->{status}, 0, 1 ) eq '2';
    $response->{url} = $url;

    # Push the current response onto the stack of redirects if redirecting.
    if (@redir_args) {
        push @{$args->{_redirects}}, $response;
        return $self->_request(@redir_args, $args);
    }

    # Copy the stack of redirects into the response before returning.
    $response->{redirects} = delete $args->{_redirects}
      if @{$args->{_redirects}};
    return $response;
}

sub _open_handle {
    my ($self, $request, $scheme, $host, $port, $peer) = @_;

    my $handle  = HTTP::Tiny::Handle->new(
        timeout         => $self->{timeout},
        SSL_options     => $self->{SSL_options},
        verify_SSL      => $self->{verify_SSL},
        local_address   => $self->{local_address},
        keep_alive      => $self->{keep_alive}
    );

    if ($self->{_has_proxy}{$scheme} && ! grep { $host =~ /\Q$_\E$/ } @{$self->{no_proxy}}) {
        return $self->_proxy_connect( $request, $handle );
    }
    else {
        return $handle->connect($scheme, $host, $port, $peer);
    }
}

sub _proxy_connect {
    my ($self, $request, $handle) = @_;

    my @proxy_vars;
    if ( $request->{scheme} eq 'https' ) {
        _croak(qq{No https_proxy defined}) unless $self->{https_proxy};
        @proxy_vars = $self->_split_proxy( https_proxy => $self->{https_proxy} );
        if ( $proxy_vars[0] eq 'https' ) {
            _croak(qq{Can't proxy https over https: $request->{uri} via $self->{https_proxy}});
        }
    }
    else {
        _croak(qq{No http_proxy defined}) unless $self->{http_proxy};
        @proxy_vars = $self->_split_proxy( http_proxy => $self->{http_proxy} );
    }

    my ($p_scheme, $p_host, $p_port, $p_auth) = @proxy_vars;

    if ( length $p_auth && ! defined $request->{headers}{'proxy-authorization'} ) {
        $self->_add_basic_auth_header( $request, 'proxy-authorization' => $p_auth );
    }

    $handle->connect($p_scheme, $p_host, $p_port, $p_host);

    if ($request->{scheme} eq 'https') {
        $self->_create_proxy_tunnel( $request, $handle );
    }
    else {
        # non-tunneled proxy requires absolute URI
        $request->{uri} = "$request->{scheme}://$request->{host_port}$request->{uri}";
    }

    return $handle;
}

sub _split_proxy {
    my ($self, $type, $proxy) = @_;

    my ($scheme, $host, $port, $path_query, $auth) = eval { $self->_split_url($proxy) };

    unless(
        defined($scheme) && length($scheme) && length($host) && length($port)
        && $path_query eq '/'
    ) {
        _croak(qq{$type URL must be in format http[s]://[auth@]<host>:<port>/\n});
    }

    return ($scheme, $host, $port, $auth);
}

sub _create_proxy_tunnel {
    my ($self, $request, $handle) = @_;

    $handle->_assert_ssl;

    my $agent = exists($request->{headers}{'user-agent'})
        ? $request->{headers}{'user-agent'} : $self->{agent};

    my $connect_request = {
        method    => 'CONNECT',
        uri       => "$request->{host}:$request->{port}",
        headers   => {
            host => "$request->{host}:$request->{port}",
            'user-agent' => $agent,
        }
    };

    if ( $request->{headers}{'proxy-authorization'} ) {
        $connect_request->{headers}{'proxy-authorization'} =
            delete $request->{headers}{'proxy-authorization'};
    }

    $handle->write_request($connect_request);
    my $response;
    do { $response = $handle->read_response_header }
        until (substr($response->{status},0,1) ne '1');

    # if CONNECT failed, throw the response so it will be
    # returned from the original request() method;
    unless (substr($response->{status},0,1) eq '2') {
        die $response;
    }

    # tunnel established, so start SSL handshake
    $handle->start_ssl( $request->{host} );

    return;
}

sub _prepare_headers_and_cb {
    my ($self, $request, $args, $url, $auth) = @_;

    for ($self->{default_headers}, $args->{headers}) {
        next unless defined;
        while (my ($k, $v) = each %$_) {
            $request->{headers}{lc $k} = $v;
            $request->{header_case}{lc $k} = $k;
        }
    }

    if (exists $request->{headers}{'host'}) {
        die(qq/The 'Host' header must not be provided as header option\n/);
    }

    $request->{headers}{'host'}         = $request->{host_port};
    $request->{headers}{'user-agent'} ||= $self->{agent};
    $request->{headers}{'connection'}   = "close"
        unless $self->{keep_alive};

    # Some servers error on an empty-body PUT/POST without a content-length
    if ( $request->{method} eq 'PUT' || $request->{method} eq 'POST' ) {
        if (!defined($args->{content}) || !length($args->{content}) ) {
            $request->{headers}{'content-length'} = 0;
        }
    }

    if ( defined $args->{content} ) {
        if ( ref $args->{content} eq 'CODE' ) {
            if ( exists $request->{'content-length'} && $request->{'content-length'} == 0 ) {
                $request->{cb} = sub { "" };
            }
            else {
                $request->{headers}{'content-type'} ||= "application/octet-stream";
                $request->{headers}{'transfer-encoding'} = 'chunked'
                  unless exists $request->{headers}{'content-length'}
                  || $request->{headers}{'transfer-encoding'};
                $request->{cb} = $args->{content};
            }
        }
        elsif ( length $args->{content} ) {
            my $content = $args->{content};
            if ( $] ge '5.008' ) {
                utf8::downgrade($content, 1)
                    or die(qq/Wide character in request message body\n/);
            }
            $request->{headers}{'content-type'} ||= "application/octet-stream";
            $request->{headers}{'content-length'} = length $content
              unless $request->{headers}{'content-length'}
                  || $request->{headers}{'transfer-encoding'};
            $request->{cb} = sub { substr $content, 0, length $content, '' };
        }
        $request->{trailer_cb} = $args->{trailer_callback}
            if ref $args->{trailer_callback} eq 'CODE';
    }

    ### If we have a cookie jar, then maybe add relevant cookies
    if ( $self->{cookie_jar} ) {
        my $cookies = $self->cookie_jar->cookie_header( $url );
        $request->{headers}{cookie} = $cookies if length $cookies;
    }

    # if we have Basic auth parameters, add them
    if ( length $auth && ! defined $request->{headers}{authorization} ) {
        $self->_add_basic_auth_header( $request, 'authorization' => $auth );
    }

    return;
}

sub _add_basic_auth_header {
    my ($self, $request, $header, $auth) = @_;
    require MIME::Base64;
    $request->{headers}{$header} =
        "Basic " . MIME::Base64::encode_base64($auth, "");
    return;
}

sub _prepare_data_cb {
    my ($self, $response, $args) = @_;
    my $data_cb = $args->{data_callback};
    $response->{content} = '';

    if (!$data_cb || $response->{status} !~ /^2/) {
        if (defined $self->{max_size}) {
            $data_cb = sub {
                $_[1]->{content} .= $_[0];
                die(qq/Size of response body exceeds the maximum allowed of $self->{max_size}\n/)
                  if length $_[1]->{content} > $self->{max_size};
            };
        }
        else {
            $data_cb = sub { $_[1]->{content} .= $_[0] };
        }
    }
    return $data_cb;
}

sub _update_cookie_jar {
    my ($self, $url, $response) = @_;

    my $cookies = $response->{headers}->{'set-cookie'};
    return unless defined $cookies;

    my @cookies = ref $cookies ? @$cookies : $cookies;

    $self->cookie_jar->add( $url, $_ ) for @cookies;

    return;
}

sub _validate_cookie_jar {
    my ($class, $jar) = @_;

    # duck typing
    for my $method ( qw/add cookie_header/ ) {
        _croak(qq/Cookie jar must provide the '$method' method\n/)
            unless ref($jar) && ref($jar)->can($method);
    }

    return;
}

sub _maybe_redirect {
    my ($self, $request, $response, $args) = @_;
    my $headers = $response->{headers};
    my ($status, $method) = ($response->{status}, $request->{method});
    $args->{_redirects} ||= [];

    if (($status eq '303' or ($status =~ /^30[1278]/ && $method =~ /^GET|HEAD$/))
        and $headers->{location}
        and @{$args->{_redirects}} < $self->{max_redirect}
    ) {
        my $location = ($headers->{location} =~ /^\//)
            ? "$request->{scheme}://$request->{host_port}$headers->{location}"
            : $headers->{location} ;
        return (($status eq '303' ? 'GET' : $method), $location);
    }
    return;
}

sub _split_url {
    my $url = pop;

    # URI regex adapted from the URI module
    my ($scheme, $host, $path_query) = $url =~ m<\A([^:/?#]+)://([^/?#]*)([^#]*)>
      or die(qq/Cannot parse URL: '$url'\n/);

    $scheme     = lc $scheme;
    $path_query = "/$path_query" unless $path_query =~ m<\A/>;

    my $auth = '';
    if ( (my $i = index $host, '@') != -1 ) {
        # user:pass@host
        $auth = substr $host, 0, $i, ''; # take up to the @ for auth
        substr $host, 0, 1, '';          # knock the @ off the host

        # userinfo might be percent escaped, so recover real auth info
        $auth =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg;
    }
    my $port = $host =~ s/:(\d*)\z// && length $1 ? $1
             : $scheme eq 'http'                  ? 80
             : $scheme eq 'https'                 ? 443
             : undef;

    return ($scheme, (length $host ? lc $host : "localhost") , $port, $path_query, $auth);
}

# Date conversions adapted from HTTP::Date
my $DoW = "Sun|Mon|Tue|Wed|Thu|Fri|Sat";
my $MoY = "Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec";
sub _http_date {
    my ($sec, $min, $hour, $mday, $mon, $year, $wday) = gmtime($_[1]);
    return sprintf("%s, %02d %s %04d %02d:%02d:%02d GMT",
        substr($DoW,$wday*4,3),
        $mday, substr($MoY,$mon*4,3), $year+1900,
        $hour, $min, $sec
    );
}

sub _parse_http_date {
    my ($self, $str) = @_;
    require Time::Local;
    my @tl_parts;
    if ($str =~ /^[SMTWF][a-z]+, +(\d{1,2}) ($MoY) +(\d\d\d\d) +(\d\d):(\d\d):(\d\d) +GMT$/) {
        @tl_parts = ($6, $5, $4, $1, (index($MoY,$2)/4), $3);
    }
    elsif ($str =~ /^[SMTWF][a-z]+, +(\d\d)-($MoY)-(\d{2,4}) +(\d\d):(\d\d):(\d\d) +GMT$/ ) {
        @tl_parts = ($6, $5, $4, $1, (index($MoY,$2)/4), $3);
    }
    elsif ($str =~ /^[SMTWF][a-z]+ +($MoY) +(\d{1,2}) +(\d\d):(\d\d):(\d\d) +(?:[^0-9]+ +)?(\d\d\d\d)$/ ) {
        @tl_parts = ($5, $4, $3, $2, (index($MoY,$1)/4), $6);
    }
    return eval {
        my $t = @tl_parts ? Time::Local::timegm(@tl_parts) : -1;
        $t < 0 ? undef : $t;
    };
}

# URI escaping adapted from URI::Escape
# c.f. http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.1
# perl 5.6 ready UTF-8 encoding adapted from JSON::PP
my %escapes = map { chr($_) => sprintf("%%%02X", $_) } 0..255;
$escapes{' '}="+";
my $unsafe_char = qr/[^A-Za-z0-9\-\._~]/;

sub _uri_escape {
    my ($self, $str) = @_;
    return "" if !defined $str;
    if ( $] ge '5.008' ) {
        utf8::encode($str);
    }
    else {
        $str = pack("U*", unpack("C*", $str)) # UTF-8 encode a byte string
            if ( length $str == do { use bytes; length $str } );
        $str = pack("C*", unpack("C*", $str)); # clear UTF-8 flag
    }
    $str =~ s/($unsafe_char)/$escapes{$1}/g;
    return $str;
}

package
    HTTP::Tiny::Handle; # hide from PAUSE/indexers
use strict;
use warnings;

use Errno      qw[EINTR EPIPE];
use IO::Socket qw[SOCK_STREAM];
use Socket     qw[SOL_SOCKET SO_KEEPALIVE];

# PERL_HTTP_TINY_IPV4_ONLY is a private environment variable to force old
# behavior if someone is unable to boostrap CPAN from a new perl install; it is
# not intended for general, per-client use and may be removed in the future
my $SOCKET_CLASS =
    $ENV{PERL_HTTP_TINY_IPV4_ONLY} ? 'IO::Socket::INET' :
    eval { require IO::Socket::IP; IO::Socket::IP->VERSION(0.32) } ? 'IO::Socket::IP' :
    'IO::Socket::INET';

sub BUFSIZE () { 32768 } ## no critic

my $Printable = sub {
    local $_ = shift;
    s/\r/\\r/g;
    s/\n/\\n/g;
    s/\t/\\t/g;
    s/([^\x20-\x7E])/sprintf('\\x%.2X', ord($1))/ge;
    $_;
};

my $Token = qr/[\x21\x23-\x27\x2A\x2B\x2D\x2E\x30-\x39\x41-\x5A\x5E-\x7A\x7C\x7E]/;
my $Field_Content = qr/[[:print:]]+ (?: [\x20\x09]+ [[:print:]]+ )*/x;

sub new {
    my ($class, %args) = @_;
    return bless {
        rbuf             => '',
        timeout          => 60,
        max_line_size    => 16384,
        max_header_lines => 64,
        verify_SSL       => HTTP::Tiny::_verify_SSL_default(),
        SSL_options      => {},
        %args
    }, $class;
}

sub timeout {
    my ($self, $timeout) = @_;
    if ( @_ > 1 ) {
        $self->{timeout} = $timeout;
        if ( $self->{fh} && $self->{fh}->can('timeout') ) {
            $self->{fh}->timeout($timeout);
        }
    }
    return $self->{timeout};
}

sub connect {
    @_ == 5 || die(q/Usage: $handle->connect(scheme, host, port, peer)/ . "\n");
    my ($self, $scheme, $host, $port, $peer) = @_;

    if ( $scheme eq 'https' ) {
        $self->_assert_ssl;
    }

    $self->{fh} = $SOCKET_CLASS->new(
        PeerHost  => $peer,
        PeerPort  => $port,
        $self->{local_address} ?
            ( LocalAddr => $self->{local_address} ) : (),
        Proto     => 'tcp',
        Type      => SOCK_STREAM,
        Timeout   => $self->{timeout},
    ) or die(qq/Could not connect to '$host:$port': $@\n/);

    binmode($self->{fh})
      or die(qq/Could not binmode() socket: '$!'\n/);

    if ( $self->{keep_alive} ) {
        unless ( defined( $self->{fh}->setsockopt( SOL_SOCKET, SO_KEEPALIVE, 1 ) ) ) {
            CORE::close($self->{fh});
            die(qq/Could not set SO_KEEPALIVE on socket: '$!'\n/);
        }
    }

    $self->start_ssl($host) if $scheme eq 'https';

    $self->{scheme} = $scheme;
    $self->{host} = $host;
    $self->{peer} = $peer;
    $self->{port} = $port;
    $self->{pid} = $$;
    $self->{tid} = _get_tid();

    return $self;
}

sub connected {
    my ($self) = @_;
    if ( $self->{fh} && $self->{fh}->connected ) {
        return wantarray
          ? ( $self->{fh}->peerhost, $self->{fh}->peerport )
          : join( ':', $self->{fh}->peerhost, $self->{fh}->peerport );
    }
    return;
}

sub start_ssl {
    my ($self, $host) = @_;

    # As this might be used via CONNECT after an SSL session
    # to a proxy, we shut down any existing SSL before attempting
    # the handshake
    if ( ref($self->{fh}) eq 'IO::Socket::SSL' ) {
        unless ( $self->{fh}->stop_SSL ) {
            my $ssl_err = IO::Socket::SSL->errstr;
            die(qq/Error halting prior SSL connection: $ssl_err/);
        }
    }

    my $ssl_args = $self->_ssl_args($host);
    IO::Socket::SSL->start_SSL(
        $self->{fh},
        %$ssl_args,
        SSL_create_ctx_callback => sub {
            my $ctx = shift;
            Net::SSLeay::CTX_set_mode($ctx, Net::SSLeay::MODE_AUTO_RETRY());
        },
    );

    unless ( ref($self->{fh}) eq 'IO::Socket::SSL' ) {
        my $ssl_err = IO::Socket::SSL->errstr;
        die(qq/SSL connection failed for $host: $ssl_err\n/);
    }
}

sub close {
    @_ == 1 || die(q/Usage: $handle->close()/ . "\n");
    my ($self) = @_;
    CORE::close($self->{fh})
      or die(qq/Could not close socket: '$!'\n/);
}

sub write {
    @_ == 2 || die(q/Usage: $handle->write(buf)/ . "\n");
    my ($self, $buf) = @_;

    if ( $] ge '5.008' ) {
        utf8::downgrade($buf, 1)
            or die(qq/Wide character in write()\n/);
    }

    my $len = length $buf;
    my $off = 0;

    local $SIG{PIPE} = 'IGNORE';

    while () {
        $self->can_write
          or die(qq/Timed out while waiting for socket to become ready for writing\n/);
        my $r = syswrite($self->{fh}, $buf, $len, $off);
        if (defined $r) {
            $len -= $r;
            $off += $r;
            last unless $len > 0;
        }
        elsif ($! == EPIPE) {
            die(qq/Socket closed by remote server: $!\n/);
        }
        elsif ($! != EINTR) {
            if ($self->{fh}->can('errstr')){
                my $err = $self->{fh}->errstr();
                die (qq/Could not write to SSL socket: '$err'\n /);
            }
            else {
                die(qq/Could not write to socket: '$!'\n/);
            }

        }
    }
    return $off;
}

sub read {
    @_ == 2 || @_ == 3 || die(q/Usage: $handle->read(len [, allow_partial])/ . "\n");
    my ($self, $len, $allow_partial) = @_;

    my $buf  = '';
    my $got = length $self->{rbuf};

    if ($got) {
        my $take = ($got < $len) ? $got : $len;
        $buf  = substr($self->{rbuf}, 0, $take, '');
        $len -= $take;
    }

    # Ignore SIGPIPE because SSL reads can result in writes that might error.
    # See "Expecting exactly the same behavior as plain sockets" in
    # https://metacpan.org/dist/IO-Socket-SSL/view/lib/IO/Socket/SSL.pod#Common-Usage-Errors
    local $SIG{PIPE} = 'IGNORE';

    while ($len > 0) {
        $self->can_read
          or die(q/Timed out while waiting for socket to become ready for reading/ . "\n");
        my $r = sysread($self->{fh}, $buf, $len, length $buf);
        if (defined $r) {
            last unless $r;
            $len -= $r;
        }
        elsif ($! != EINTR) {
            if ($self->{fh}->can('errstr')){
                my $err = $self->{fh}->errstr();
                die (qq/Could not read from SSL socket: '$err'\n /);
            }
            else {
                die(qq/Could not read from socket: '$!'\n/);
            }
        }
    }
    if ($len && !$allow_partial) {
        die(qq/Unexpected end of stream\n/);
    }
    return $buf;
}

sub readline {
    @_ == 1 || die(q/Usage: $handle->readline()/ . "\n");
    my ($self) = @_;

    while () {
        if ($self->{rbuf} =~ s/\A ([^\x0D\x0A]* \x0D?\x0A)//x) {
            return $1;
        }
        if (length $self->{rbuf} >= $self->{max_line_size}) {
            die(qq/Line size exceeds the maximum allowed size of $self->{max_line_size}\n/);
        }
        $self->can_read
          or die(qq/Timed out while waiting for socket to become ready for reading\n/);
        my $r = sysread($self->{fh}, $self->{rbuf}, BUFSIZE, length $self->{rbuf});
        if (defined $r) {
            last unless $r;
        }
        elsif ($! != EINTR) {
            if ($self->{fh}->can('errstr')){
                my $err = $self->{fh}->errstr();
                die (qq/Could not read from SSL socket: '$err'\n /);
            }
            else {
                die(qq/Could not read from socket: '$!'\n/);
            }
        }
    }
    die(qq/Unexpected end of stream while looking for line\n/);
}

sub read_header_lines {
    @_ == 1 || @_ == 2 || die(q/Usage: $handle->read_header_lines([headers])/ . "\n");
    my ($self, $headers) = @_;
    $headers ||= {};
    my $lines   = 0;
    my $val;

    while () {
         my $line = $self->readline;

         if (++$lines >= $self->{max_header_lines}) {
             die(qq/Header lines exceeds maximum number allowed of $self->{max_header_lines}\n/);
         }
         elsif ($line =~ /\A ([^\x00-\x1F\x7F:]+) : [\x09\x20]* ([^\x0D\x0A]*)/x) {
             my ($field_name) = lc $1;
             if (exists $headers->{$field_name}) {
                 for ($headers->{$field_name}) {
                     $_ = [$_] unless ref $_ eq "ARRAY";
                     push @$_, $2;
                     $val = \$_->[-1];
                 }
             }
             else {
                 $val = \($headers->{$field_name} = $2);
             }
         }
         elsif ($line =~ /\A [\x09\x20]+ ([^\x0D\x0A]*)/x) {
             $val
               or die(qq/Unexpected header continuation line\n/);
             next unless length $1;
             $$val .= ' ' if length $$val;
             $$val .= $1;
         }
         elsif ($line =~ /\A \x0D?\x0A \z/x) {
            last;
         }
         else {
            die(q/Malformed header line: / . $Printable->($line) . "\n");
         }
    }
    return $headers;
}

sub write_request {
    @_ == 2 || die(q/Usage: $handle->write_request(request)/ . "\n");
    my($self, $request) = @_;
    $self->write_request_header(@{$request}{qw/method uri headers header_case/});
    $self->write_body($request) if $request->{cb};
    return;
}

# Standard request header names/case from HTTP/1.1 RFCs
my @rfc_request_headers = qw(
  Accept Accept-Charset Accept-Encoding Accept-Language Authorization
  Cache-Control Connection Content-Length Expect From Host
  If-Match If-Modified-Since If-None-Match If-Range If-Unmodified-Since
  Max-Forwards Pragma Proxy-Authorization Range Referer TE Trailer
  Transfer-Encoding Upgrade User-Agent Via
);

my @other_request_headers = qw(
  Content-Encoding Content-MD5 Content-Type Cookie DNT Date Origin
  X-XSS-Protection
);

my %HeaderCase = map { lc($_) => $_ } @rfc_request_headers, @other_request_headers;

# to avoid multiple small writes and hence nagle, you can pass the method line or anything else to
# combine writes.
sub write_header_lines {
    (@_ >= 2 && @_ <= 4 && ref $_[1] eq 'HASH') || die(q/Usage: $handle->write_header_lines(headers, [header_case, prefix])/ . "\n");
    my($self, $headers, $header_case, $prefix_data) = @_;
    $header_case ||= {};

    my $buf = (defined $prefix_data ? $prefix_data : '');

    # Per RFC, control fields should be listed first
    my %seen;
    for my $k ( qw/host cache-control expect max-forwards pragma range te/ ) {
        next unless exists $headers->{$k};
        $seen{$k}++;
        my $field_name = $HeaderCase{$k};
        my $v = $headers->{$k};
        for (ref $v eq 'ARRAY' ? @$v : $v) {
            $_ = '' unless defined $_;
            $buf .= "$field_name: $_\x0D\x0A";
        }
    }

    # Other headers sent in arbitrary order
    while (my ($k, $v) = each %$headers) {
        my $field_name = lc $k;
        next if $seen{$field_name};
        if (exists $HeaderCase{$field_name}) {
            $field_name = $HeaderCase{$field_name};
        }
        else {
            if (exists $header_case->{$field_name}) {
                $field_name = $header_case->{$field_name};
            }
            else {
                $field_name =~ s/\b(\w)/\u$1/g;
            }
            $field_name =~ /\A $Token+ \z/xo
              or die(q/Invalid HTTP header field name: / . $Printable->($field_name) . "\n");
            $HeaderCase{lc $field_name} = $field_name;
        }
        for (ref $v eq 'ARRAY' ? @$v : $v) {
            # unwrap a field value if pre-wrapped by user
            s/\x0D?\x0A\s+/ /g;
            die(qq/Invalid HTTP header field value ($field_name): / . $Printable->($_). "\n")
              unless $_ eq '' || /\A $Field_Content \z/xo;
            $_ = '' unless defined $_;
            $buf .= "$field_name: $_\x0D\x0A";
        }
    }
    $buf .= "\x0D\x0A";
    return $self->write($buf);
}

# return value indicates whether message length was defined; this is generally
# true unless there was no content-length header and we just read until EOF.
# Other message length errors are thrown as exceptions
sub read_body {
    @_ == 3 || die(q/Usage: $handle->read_body(callback, response)/ . "\n");
    my ($self, $cb, $response) = @_;
    my $te = $response->{headers}{'transfer-encoding'} || '';
    my $chunked = grep { /chunked/i } ( ref $te eq 'ARRAY' ? @$te : $te ) ;
    return $chunked
        ? $self->read_chunked_body($cb, $response)
        : $self->read_content_body($cb, $response);
}

sub write_body {
    @_ == 2 || die(q/Usage: $handle->write_body(request)/ . "\n");
    my ($self, $request) = @_;
    if (exists $request->{headers}{'content-length'}) {
        return unless $request->{headers}{'content-length'};
        return $self->write_content_body($request);
    }
    else {
        return $self->write_chunked_body($request);
    }
}

sub read_content_body {
    @_ == 3 || @_ == 4 || die(q/Usage: $handle->read_content_body(callback, response, [read_length])/ . "\n");
    my ($self, $cb, $response, $content_length) = @_;
    $content_length ||= $response->{headers}{'content-length'};

    if ( defined $content_length ) {
        my $len = $content_length;
        while ($len > 0) {
            my $read = ($len > BUFSIZE) ? BUFSIZE : $len;
            $cb->($self->read($read, 0), $response);
            $len -= $read;
        }
        return length($self->{rbuf}) == 0;
    }

    my $chunk;
    $cb->($chunk, $response) while length( $chunk = $self->read(BUFSIZE, 1) );

    return;
}

sub write_content_body {
    @_ == 2 || die(q/Usage: $handle->write_content_body(request)/ . "\n");
    my ($self, $request) = @_;

    my ($len, $content_length) = (0, $request->{headers}{'content-length'});
    while () {
        my $data = $request->{cb}->();

        defined $data && length $data
          or last;

        if ( $] ge '5.008' ) {
            utf8::downgrade($data, 1)
                or die(qq/Wide character in write_content()\n/);
        }

        $len += $self->write($data);
    }

    $len == $content_length
      or die(qq/Content-Length mismatch (got: $len expected: $content_length)\n/);

    return $len;
}

sub read_chunked_body {
    @_ == 3 || die(q/Usage: $handle->read_chunked_body(callback, $response)/ . "\n");
    my ($self, $cb, $response) = @_;

    while () {
        my $head = $self->readline;

        $head =~ /\A ([A-Fa-f0-9]+)/x
          or die(q/Malformed chunk head: / . $Printable->($head) . "\n");

        my $len = hex($1)
          or last;

        $self->read_content_body($cb, $response, $len);

        $self->read(2) eq "\x0D\x0A"
          or die(qq/Malformed chunk: missing CRLF after chunk data\n/);
    }
    $self->read_header_lines($response->{headers});
    return 1;
}

sub write_chunked_body {
    @_ == 2 || die(q/Usage: $handle->write_chunked_body(request)/ . "\n");
    my ($self, $request) = @_;

    my $len = 0;
    while () {
        my $data = $request->{cb}->();

        defined $data && length $data
          or last;

        if ( $] ge '5.008' ) {
            utf8::downgrade($data, 1)
                or die(qq/Wide character in write_chunked_body()\n/);
        }

        $len += length $data;

        my $chunk  = sprintf '%X', length $data;
           $chunk .= "\x0D\x0A";
           $chunk .= $data;
           $chunk .= "\x0D\x0A";

        $self->write($chunk);
    }
    $self->write("0\x0D\x0A");
    if ( ref $request->{trailer_cb} eq 'CODE' ) {
        $self->write_header_lines($request->{trailer_cb}->())
    }
    else {
        $self->write("\x0D\x0A");
    }
    return $len;
}

sub read_response_header {
    @_ == 1 || die(q/Usage: $handle->read_response_header()/ . "\n");
    my ($self) = @_;

    my $line = $self->readline;

    $line =~ /\A (HTTP\/(0*\d+\.0*\d+)) [\x09\x20]+ ([0-9]{3}) (?: [\x09\x20]+ ([^\x0D\x0A]*) )? \x0D?\x0A/x
      or die(q/Malformed Status-Line: / . $Printable->($line). "\n");

    my ($protocol, $version, $status, $reason) = ($1, $2, $3, $4);
    $reason = "" unless defined $reason;

    die (qq/Unsupported HTTP protocol: $protocol\n/)
        unless $version =~ /0*1\.0*[01]/;

    return {
        status       => $status,
        reason       => $reason,
        headers      => $self->read_header_lines,
        protocol     => $protocol,
    };
}

sub write_request_header {
    @_ == 5 || die(q/Usage: $handle->write_request_header(method, request_uri, headers, header_case)/ . "\n");
    my ($self, $method, $request_uri, $headers, $header_case) = @_;

    return $self->write_header_lines($headers, $header_case, "$method $request_uri HTTP/1.1\x0D\x0A");
}

sub _do_timeout {
    my ($self, $type, $timeout) = @_;
    $timeout = $self->{timeout}
        unless defined $timeout && $timeout >= 0;

    my $fd = fileno $self->{fh};
    defined $fd && $fd >= 0
      or die(qq/select(2): 'Bad file descriptor'\n/);

    my $initial = time;
    my $pending = $timeout;
    my $nfound;

    vec(my $fdset = '', $fd, 1) = 1;

    while () {
        $nfound = ($type eq 'read')
            ? select($fdset, undef, undef, $pending)
            : select(undef, $fdset, undef, $pending) ;
        if ($nfound == -1) {
            $! == EINTR
              or die(qq/select(2): '$!'\n/);
            redo if !$timeout || ($pending = $timeout - (time - $initial)) > 0;
            $nfound = 0;
        }
        last;
    }
    $! = 0;
    return $nfound;
}

sub can_read {
    @_ == 1 || @_ == 2 || die(q/Usage: $handle->can_read([timeout])/ . "\n");
    my $self = shift;
    if ( ref($self->{fh}) eq 'IO::Socket::SSL' ) {
        return 1 if $self->{fh}->pending;
    }
    return $self->_do_timeout('read', @_)
}

sub can_write {
    @_ == 1 || @_ == 2 || die(q/Usage: $handle->can_write([timeout])/ . "\n");
    my $self = shift;
    return $self->_do_timeout('write', @_)
}

sub _assert_ssl {
    my($ok, $reason) = HTTP::Tiny->can_ssl();
    die $reason unless $ok;
}

sub can_reuse {
    my ($self,$scheme,$host,$port,$peer) = @_;
    return 0 if
        $self->{pid} != $$
        || $self->{tid} != _get_tid()
        || length($self->{rbuf})
        || $scheme ne $self->{scheme}
        || $host ne $self->{host}
        || $port ne $self->{port}
        || $peer ne $self->{peer}
        || eval { $self->can_read(0) }
        || $@ ;
        return 1;
}

sub _find_CA {
    my $self = shift;

    my $ca_file = $self->{SSL_options}->{SSL_ca_file};

    if ( defined $ca_file ) {
        unless ( -r $ca_file ) {
            die qq/SSL_ca_file '$ca_file' not found or not readable\n/;
        }
        return ( SSL_ca_file => $ca_file );
    }

    # Return default_ca() parameters from IO::Socket::SSL. It looks for the
    # default bundle and directory from Net::SSLeay, handles $ENV{SSL_CERT_FILE}
    # and $ENV{SSL_CERT_DIR}, and finally fails over to Mozilla::CA
    #
    my %default_ca = IO::Socket::SSL::default_ca();
    return %default_ca if %default_ca;

    # If IO::Socket::SSL::default_ca() was unable to find a CA bundle, look for
    # one in well known locations as a last resort. Cert list copied from golang
    # src/crypto/x509/root_unix.go
    #
    foreach my $ca_bundle (
        "/etc/ssl/certs/ca-certificates.crt",     # Debian/Ubuntu/Gentoo etc.
        "/etc/pki/tls/certs/ca-bundle.crt",       # Fedora/RHEL
        "/etc/ssl/ca-bundle.pem",                 # OpenSUSE
        "/etc/openssl/certs/ca-certificates.crt", # NetBSD
        "/etc/ssl/cert.pem",                      # OpenBSD
        "/usr/local/share/certs/ca-root-nss.crt", # FreeBSD/DragonFly
        "/etc/pki/tls/cacert.pem",                # OpenELEC
        "/etc/certs/ca-certificates.crt",         # Solaris 11.2+
    ) {
        return ( SSL_ca_file => $ca_bundle ) if -e $ca_bundle;
    }

    die qq/Couldn't find a CA bundle with which to verify the SSL certificate.\n/
      . qq/Try installing one from your OS vendor, or Mozilla::CA from CPAN\n/;
}

# not for internal use; backcompat shim only
sub _find_CA_file {
    my $self = shift;
    my %res = $self->_find_CA();
    return $res{SSL_ca_file};
}

# for thread safety, we need to know thread id if threads are loaded
sub _get_tid {
    no warnings 'reserved'; # for 'threads'
    return threads->can("tid") ? threads->tid : 0;
}

sub _ssl_args {
    my ($self, $host) = @_;

    my %ssl_args;

    # This test reimplements IO::Socket::SSL::can_client_sni(), which wasn't
    # added until IO::Socket::SSL 1.84
    if ( Net::SSLeay::OPENSSL_VERSION_NUMBER() >= 0x01000000 ) {
        $ssl_args{SSL_hostname} = $host,          # Sane SNI support
    }

    if ($self->{verify_SSL}) {
        $ssl_args{SSL_verifycn_scheme}  = 'http'; # enable CN validation
        $ssl_args{SSL_verifycn_name}    = $host;  # set validation hostname
        $ssl_args{SSL_verify_mode}      = 0x01;   # enable cert validation

        %ssl_args = ( %ssl_args, $self->_find_CA );
    }
    else {
        $ssl_args{SSL_verifycn_scheme}  = 'none'; # disable CN validation
        $ssl_args{SSL_verify_mode}      = 0x00;   # disable cert validation
    }

    # user options override settings from verify_SSL
    for my $k ( keys %{$self->{SSL_options}} ) {
        $ssl_args{$k} = $self->{SSL_options}{$k} if $k =~ m/^SSL_/;
    }

    return \%ssl_args;
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

HTTP::Tiny - A small, simple, correct HTTP/1.1 client

=head1 VERSION

version 0.090

=head1 SYNOPSIS

    use HTTP::Tiny;

    my $response = HTTP::Tiny->new->get('http://example.com/');

    die "Failed!\n" unless $response->{success};

    print "$response->{status} $response->{reason}\n";

    while (my ($k, $v) = each %{$response->{headers}}) {
        for (ref $v eq 'ARRAY' ? @$v : $v) {
            print "$k: $_\n";
        }
    }

    print $response->{content} if length $response->{content};

=head1 DESCRIPTION

This is a very simple HTTP/1.1 client, designed for doing simple
requests without the overhead of a large framework like L<LWP::UserAgent>.

It is more correct and more complete than L<HTTP::Lite>.  It supports
proxies and redirection.  It also correctly resumes after EINTR.

If L<IO::Socket::IP> 0.25 or later is installed, HTTP::Tiny will use it instead
of L<IO::Socket::INET> for transparent support for both IPv4 and IPv6.

Cookie support requires L<HTTP::CookieJar> or an equivalent class.

=head1 METHODS

=head2 new

    $http = HTTP::Tiny->new( %attributes );

This constructor returns a new HTTP::Tiny object.  Valid attributes include:

=over 4

=item *

C<agent> — A user-agent string (defaults to 'HTTP-Tiny/$VERSION'). If C<agent> — ends in a space character, the default user-agent string is appended.

=item *

C<cookie_jar> — An instance of L<HTTP::CookieJar> — or equivalent class that supports the C<add> and C<cookie_header> methods

=item *

C<default_headers> — A hashref of default headers to apply to requests

=item *

C<local_address> — The local IP address to bind to

=item *

C<keep_alive> — Whether to reuse the last connection (if for the same scheme, host and port) (defaults to 1)

=item *

C<max_redirect> — Maximum number of redirects allowed (defaults to 5)

=item *

C<max_size> — Maximum response size in bytes (only when not using a data callback).  If defined, requests with responses larger than this will return a 599 status code.

=item *

C<http_proxy> — URL of a proxy server to use for HTTP connections (default is C<$ENV{http_proxy}> — if set)

=item *

C<https_proxy> — URL of a proxy server to use for HTTPS connections (default is C<$ENV{https_proxy}> — if set)

=item *

C<proxy> — URL of a generic proxy server for both HTTP and HTTPS connections (default is C<$ENV{all_proxy}> — if set)

=item *

C<no_proxy> — List of domain suffixes that should not be proxied.  Must be a comma-separated string or an array reference. (default is C<$ENV{no_proxy}> —)

=item *

C<timeout> — Request timeout in seconds (default is 60) If a socket open, read or write takes longer than the timeout, the request response status code will be 599.

=item *

C<verify_SSL> — A boolean that indicates whether to validate the TLS/SSL certificate of an C<https> — connection (default is true). Changed from false to true in version 0.083.

=item *

C<SSL_options> — A hashref of C<SSL_*> — options to pass through to L<IO::Socket::SSL>

=item *

C<$ENV{PERL_HTTP_TINY_SSL_INSECURE_BY_DEFAULT}> - Changes the default certificate verification behavior to not check server identity if set to 1. Only effective if C<verify_SSL> is not set. Added in version 0.083.

=back

An accessor/mutator method exists for each attribute.

Passing an explicit C<undef> for C<proxy>, C<http_proxy> or C<https_proxy> will
prevent getting the corresponding proxies from the environment.

Errors during request execution will result in a pseudo-HTTP status code of 599
and a reason of "Internal Exception". The content field in the response will
contain the text of the error.

The C<keep_alive> parameter enables a persistent connection, but only to a
single destination scheme, host and port.  If any connection-relevant
attributes are modified via accessor, or if the process ID or thread ID change,
the persistent connection will be dropped.  If you want persistent connections
across multiple destinations, use multiple HTTP::Tiny objects.

See L</TLS/SSL SUPPORT> for more on the C<verify_SSL> and C<SSL_options>
attributes.

=head2 get|head|put|post|patch|delete

    $response = $http->get($url);
    $response = $http->get($url, \%options);
    $response = $http->head($url);

These methods are shorthand for calling C<request()> for the given method.  The
URL must have unsafe characters escaped and international domain names encoded.
See C<request()> for valid options and a description of the response.

The C<success> field of the response will be true if the status code is 2XX.

=head2 post_form

    $response = $http->post_form($url, $form_data);
    $response = $http->post_form($url, $form_data, \%options);

This method executes a C<POST> request and sends the key/value pairs from a
form data hash or array reference to the given URL with a C<content-type> of
C<application/x-www-form-urlencoded>.  If data is provided as an array
reference, the order is preserved; if provided as a hash reference, the terms
are sorted by key for consistency.  See documentation for the
C<www_form_urlencode> method for details on the encoding.

The URL must have unsafe characters escaped and international domain names
encoded.  See C<request()> for valid options and a description of the response.
Any C<content-type> header or content in the options hashref will be ignored.

The C<success> field of the response will be true if the status code is 2XX.

=head2 mirror

    $response = $http->mirror($url, $file, \%options)
    if ( $response->{success} ) {
        print "$file is up to date\n";
    }

Executes a C<GET> request for the URL and saves the response body to the file
name provided.  The URL must have unsafe characters escaped and international
domain names encoded.  If the file already exists, the request will include an
C<If-Modified-Since> header with the modification timestamp of the file.  You
may specify a different C<If-Modified-Since> header yourself in the C<<
$options->{headers} >> hash.

The C<success> field of the response will be true if the status code is 2XX
or if the status code is 304 (unmodified).

If the file was modified and the server response includes a properly
formatted C<Last-Modified> header, the file modification time will
be updated accordingly.

=head2 request

    $response = $http->request($method, $url);
    $response = $http->request($method, $url, \%options);

Executes an HTTP request of the given method type ('GET', 'HEAD', 'POST',
'PUT', etc.) on the given URL.  The URL must have unsafe characters escaped and
international domain names encoded.

B<NOTE>: Method names are B<case-sensitive> per the HTTP/1.1 specification.
Don't use C<get> when you really want C<GET>.  See L<LIMITATIONS> for
how this applies to redirection.

If the URL includes a "user:password" stanza, they will be used for Basic-style
authorization headers.  (Authorization headers will not be included in a
redirected request.) For example:

    $http->request('GET', 'http://Aladdin:open sesame@example.com/');

If the "user:password" stanza contains reserved characters, they must
be percent-escaped:

    $http->request('GET', 'http://john%40example.com:password@example.com/');

A hashref of options may be appended to modify the request.

Valid options are:

=over 4

=item *

C<headers> — A hashref containing headers to include with the request.  If the value for a header is an array reference, the header will be output multiple times with each value in the array.  These headers over-write any default headers.

=item *

C<content> — A scalar to include as the body of the request OR a code reference that will be called iteratively to produce the body of the request

=item *

C<trailer_callback> — A code reference that will be called if it exists to provide a hashref of trailing headers (only used with chunked transfer-encoding)

=item *

C<data_callback> — A code reference that will be called for each chunks of the response body received.

=item *

C<peer> — Override host resolution and force all connections to go only to a specific peer address, regardless of the URL of the request.  This will include any redirections!  This options should be used with extreme caution (e.g. debugging or very special circumstances). It can be given as either a scalar or a code reference that will receive the hostname and whose response will be taken as the address.

=back

The C<Host> header is generated from the URL in accordance with RFC 2616.  It
is a fatal error to specify C<Host> in the C<headers> option.  Other headers
may be ignored or overwritten if necessary for transport compliance.

If the C<content> option is a code reference, it will be called iteratively
to provide the content body of the request.  It should return the empty
string or undef when the iterator is exhausted.

If the C<content> option is the empty string, no C<content-type> or
C<content-length> headers will be generated.

If the C<data_callback> option is provided, it will be called iteratively until
the entire response body is received.  The first argument will be a string
containing a chunk of the response body, the second argument will be the
in-progress response hash reference, as described below.  (This allows
customizing the action of the callback based on the C<status> or C<headers>
received prior to the content body.)

Content data in the request/response is handled as "raw bytes".  Any
encoding/decoding (with associated headers) are the responsibility of the
caller.

The C<request> method returns a hashref containing the response.  The hashref
will have the following keys:

=over 4

=item *

C<success> — Boolean indicating whether the operation returned a 2XX status code

=item *

C<url> — URL that provided the response. This is the URL of the request unless there were redirections, in which case it is the last URL queried in a redirection chain

=item *

C<status> — The HTTP status code of the response

=item *

C<reason> — The response phrase returned by the server

=item *

C<content> — The body of the response.  If the response does not have any content or if a data callback is provided to consume the response body, this will be the empty string

=item *

C<headers> — A hashref of header fields.  All header field names will be normalized to be lower case. If a header is repeated, the value will be an arrayref; it will otherwise be a scalar string containing the value

=item *

C<protocol> - If this field exists, it is the protocol of the response such as HTTP/1.0 or HTTP/1.1

=item *

C<redirects> If this field exists, it is an arrayref of response hash references from redirects in the same order that redirections occurred.  If it does not exist, then no redirections occurred.

=back

On an error during the execution of the request, the C<status> field will
contain 599, and the C<content> field will contain the text of the error.

=head2 www_form_urlencode

    $params = $http->www_form_urlencode( $data );
    $response = $http->get("http://example.com/query?$params");

This method converts the key/value pairs from a data hash or array reference
into a C<x-www-form-urlencoded> string.  The keys and values from the data
reference will be UTF-8 encoded and escaped per RFC 3986.  If a value is an
array reference, the key will be repeated with each of the values of the array
reference.  If data is provided as a hash reference, the key/value pairs in the
resulting string will be sorted by key and value for consistent ordering.

=head2 can_ssl

    $ok         = HTTP::Tiny->can_ssl;
    ($ok, $why) = HTTP::Tiny->can_ssl;
    ($ok, $why) = $http->can_ssl;

Indicates if SSL support is available.  When called as a class object, it
checks for the correct version of L<Net::SSLeay> and L<IO::Socket::SSL>.
When called as an object methods, if C<SSL_verify> is true or if C<SSL_verify_mode>
is set in C<SSL_options>, it checks that a CA file is available.

In scalar context, returns a boolean indicating if SSL is available.
In list context, returns the boolean and a (possibly multi-line) string of
errors indicating why SSL isn't available.

=head2 connected

    $host = $http->connected;
    ($host, $port) = $http->connected;

Indicates if a connection to a peer is being kept alive, per the C<keep_alive>
option.

In scalar context, returns the peer host and port, joined with a colon, or
C<undef> (if no peer is connected).
In list context, returns the peer host and port or an empty list (if no peer
is connected).

B<Note>: This method cannot reliably be used to discover whether the remote
host has closed its end of the socket.

=for Pod::Coverage SSL_options
agent
cookie_jar
default_headers
http_proxy
https_proxy
keep_alive
local_address
max_redirect
max_size
no_proxy
proxy
timeout
verify_SSL

=head1 TLS/SSL SUPPORT

Direct C<https> connections are supported only if L<IO::Socket::SSL> 1.56 or
greater and L<Net::SSLeay> 1.49 or greater are installed. An error will occur
if new enough versions of these modules are not installed or if the TLS
encryption fails. You can also use C<HTTP::Tiny::can_ssl()> utility function
that returns boolean to see if the required modules are installed.

An C<https> connection may be made via an C<http> proxy that supports the CONNECT
command (i.e. RFC 2817).  You may not proxy C<https> via a proxy that itself
requires C<https> to communicate.

TLS/SSL provides two distinct capabilities:

=over 4

=item *

Encrypted communication channel

=item *

Verification of server identity

=back

B<By default, HTTP::Tiny verifies server identity>.

This was changed in version 0.083 due to security concerns. The previous default
behavior can be enabled by setting C<$ENV{PERL_HTTP_TINY_SSL_INSECURE_BY_DEFAULT}>
to 1.

Verification is done by checking that that the TLS/SSL connection has a valid
certificate corresponding to the host name of the connection and that the
certificate has been verified by a CA. Assuming you trust the CA, this will
protect against L<machine-in-the-middle
attacks|http://en.wikipedia.org/wiki/Machine-in-the-middle_attack>.

Certificate verification requires a file or directory containing trusted CA
certificates.

C<IO::Socket::SSL::default_ca()> is called to detect the default location of
your CA certificates. This also supports the environment variables
C<SSL_CERT_FILE> and C<SSL_CERT_DIR>, and will fail over to L<Mozilla::CA> if no
certs are found.

If C<IO::Socket::SSL::default_ca()> is not able to find usable CA certificates,
HTTP::Tiny will search several well-known system-specific default locations for
a CA certificate file as a last resort:

=over 4

=item *

/etc/ssl/certs/ca-certificates.crt

=item *

/etc/pki/tls/certs/ca-bundle.crt

=item *

/etc/ssl/ca-bundle.pem

=item *

/etc/openssl/certs/ca-certificates.crt

=item *

/etc/ssl/cert.pem

=item *

/usr/local/share/certs/ca-root-nss.crt

=item *

/etc/pki/tls/cacert.pem

=item *

/etc/certs/ca-certificates.crt

=back

An error will be occur if C<verify_SSL> is true and no CA certificate file
is available.

If you desire complete control over TLS/SSL connections, the C<SSL_options>
attribute lets you provide a hash reference that will be passed through to
C<IO::Socket::SSL::start_SSL()>, overriding any options set by HTTP::Tiny. For
example, to provide your own trusted CA file:

    SSL_options => {
        SSL_ca_file => $file_path,
    }

The C<SSL_options> attribute could also be used for such things as providing a
client certificate for authentication to a server or controlling the choice of
cipher used for the TLS/SSL connection. See L<IO::Socket::SSL> documentation for
details.

=head1 PROXY SUPPORT

HTTP::Tiny can proxy both C<http> and C<https> requests.  Only Basic proxy
authorization is supported and it must be provided as part of the proxy URL:
C<http://user:pass@proxy.example.com/>.

HTTP::Tiny supports the following proxy environment variables:

=over 4

=item *

http_proxy or HTTP_PROXY

=item *

https_proxy or HTTPS_PROXY

=item *

all_proxy or ALL_PROXY

=back

If the C<REQUEST_METHOD> environment variable is set, then this might be a CGI
process and C<HTTP_PROXY> would be set from the C<Proxy:> header, which is a
security risk.  If C<REQUEST_METHOD> is set, C<HTTP_PROXY> (the upper case
variant only) is ignored, but C<CGI_HTTP_PROXY> is considered instead.

Tunnelling C<https> over an C<http> proxy using the CONNECT method is
supported.  If your proxy uses C<https> itself, you can not tunnel C<https>
over it.

Be warned that proxying an C<https> connection opens you to the risk of a
man-in-the-middle attack by the proxy server.

The C<no_proxy> environment variable is supported in the format of a
comma-separated list of domain extensions proxy should not be used for.

Proxy arguments passed to C<new> will override their corresponding
environment variables.

=head1 LIMITATIONS

HTTP::Tiny is I<conditionally compliant> with the
L<HTTP/1.1 specifications|http://www.w3.org/Protocols/>:

=over 4

=item *

"Message Syntax and Routing" [RFC7230]

=item *

"Semantics and Content" [RFC7231]

=item *

"Conditional Requests" [RFC7232]

=item *

"Range Requests" [RFC7233]

=item *

"Caching" [RFC7234]

=item *

"Authentication" [RFC7235]

=back

It attempts to meet all "MUST" requirements of the specification, but does not
implement all "SHOULD" requirements.  (Note: it was developed against the
earlier RFC 2616 specification and may not yet meet the revised RFC 7230-7235
spec.) Additionally, HTTP::Tiny supports the C<PATCH> method of RFC 5789.

Some particular limitations of note include:

=over

=item *

HTTP::Tiny focuses on correct transport.  Users are responsible for ensuring
that user-defined headers and content are compliant with the HTTP/1.1
specification.

=item *

Users must ensure that URLs are properly escaped for unsafe characters and that
international domain names are properly encoded to ASCII. See L<URI::Escape>,
L<URI::_punycode> and L<Net::IDN::Encode>.

=item *

Redirection is very strict against the specification.  Redirection is only
automatic for response codes 301, 302, 307 and 308 if the request method is
'GET' or 'HEAD'.  Response code 303 is always converted into a 'GET'
redirection, as mandated by the specification.  There is no automatic support
for status 305 ("Use proxy") redirections.

=item *

There is no provision for delaying a request body using an C<Expect> header.
Unexpected C<1XX> responses are silently ignored as per the specification.

=item *

Only 'chunked' C<Transfer-Encoding> is supported.

=item *

There is no support for a Request-URI of '*' for the 'OPTIONS' request.

=item *

Headers mentioned in the RFCs and some other, well-known headers are
generated with their canonical case.  Other headers are sent in the
case provided by the user.  Except for control headers (which are sent first),
headers are sent in arbitrary order.

=back

Despite the limitations listed above, HTTP::Tiny is considered
feature-complete.  New feature requests should be directed to
L<HTTP::Tiny::UA>.

=head1 SEE ALSO

=over 4

=item *

L<HTTP::Tiny::UA> - Higher level UA features for HTTP::Tiny

=item *

L<HTTP::Thin> - HTTP::Tiny wrapper with L<HTTP::Request>/L<HTTP::Response> compatibility

=item *

L<HTTP::Tiny::Mech> - Wrap L<WWW::Mechanize> instance in HTTP::Tiny compatible interface

=item *

L<IO::Socket::IP> - Required for IPv6 support

=item *

L<IO::Socket::SSL> - Required for SSL support

=item *

L<LWP::UserAgent> - If HTTP::Tiny isn't enough for you, this is the "standard" way to do things

=item *

L<Net::SSLeay> - Required for SSL support

=back

=for :stopwords cpan testmatrix url bugtracker rt cpants kwalitee diff irc mailto metadata placeholders metacpan

=head1 SUPPORT

=head2 Bugs / Feature Requests

Please report any bugs or feature requests through the issue tracker
at L<https://github.com/Perl-Toolchain-Gang/HTTP-Tiny/issues>.
You will be notified automatically of any progress on your issue.

=head2 Source Code

This is open source software.  The code repository is available for
public review and contribution under the terms of the license.

L<https://github.com/Perl-Toolchain-Gang/HTTP-Tiny>

  git clone https://github.com/Perl-Toolchain-Gang/HTTP-Tiny.git

=head1 AUTHORS

=over 4

=item *

Christian Hansen <chansen@cpan.org>

=item *

David Golden <dagolden@cpan.org>

=back

=head1 CONTRIBUTORS

=for stopwords Alan Gardner Alessandro Ghedini A. Sinan Unur Brad Gilbert brian m. carlson Chris Nehren Weyl Claes Jakobsson Clinton Gormley Craig Berry David Golden Mitchell Dean Pearce Edward Zborowski Felipe Gasper Graham Knop Greg Kennedy James E Keenan Raspass Jeremy Mates Jess Robinson Karen Etheridge Lukas Eklund Martin J. Evans Martin-Louis Bright Matthew Horsfall Michael R. Davis Mike Doherty Nicolas Rochelemagne Olaf Alders Olivier Mengué Petr Písař sanjay-cpu Serguei Trouchelle Shoichi Kaji SkyMarshal Sören Kornetzki Steve Grazzini Stig Palmquist Syohei YOSHIDA Tatsuhiko Miyagawa Tom Hukins Tony Cook Xavier Guimard

=over 4

=item *

Alan Gardner <gardner@pythian.com>

=item *

Alessandro Ghedini <al3xbio@gmail.com>

=item *

A. Sinan Unur <nanis@cpan.org>

=item *

Brad Gilbert <bgills@cpan.org>

=item *

brian m. carlson <sandals@crustytoothpaste.net>

=item *

Chris Nehren <apeiron@cpan.org>

=item *

Chris Weyl <cweyl@alumni.drew.edu>

=item *

Claes Jakobsson <claes@surfar.nu>

=item *

Clinton Gormley <clint@traveljury.com>

=item *

Craig A. Berry <craigberry@mac.com>

=item *

David Golden <xdg@xdg.me>

=item *

David Mitchell <davem@iabyn.com>

=item *

Dean Pearce <pearce@pythian.com>

=item *

Edward Zborowski <ed@rubensteintech.com>

=item *

Felipe Gasper <felipe@felipegasper.com>

=item *

Graham Knop <haarg@haarg.org>

=item *

Greg Kennedy <kennedy.greg@gmail.com>

=item *

James E Keenan <jkeenan@cpan.org>

=item *

James Raspass <jraspass@gmail.com>

=item *

Jeremy Mates <jmates@cpan.org>

=item *

Jess Robinson <castaway@desert-island.me.uk>

=item *

Karen Etheridge <ether@cpan.org>

=item *

Lukas Eklund <leklund@gmail.com>

=item *

Martin J. Evans <mjegh@ntlworld.com>

=item *

Martin-Louis Bright <mlbright@gmail.com>

=item *

Matthew Horsfall <wolfsage@gmail.com>

=item *

Michael R. Davis <mrdvt92@users.noreply.github.com>

=item *

Mike Doherty <doherty@cpan.org>

=item *

Nicolas Rochelemagne <rochelemagne@cpanel.net>

=item *

Olaf Alders <olaf@wundersolutions.com>

=item *

Olivier Mengué <dolmen@cpan.org>

=item *

Petr Písař <ppisar@redhat.com>

=item *

sanjay-cpu <snjkmr32@gmail.com>

=item *

Serguei Trouchelle <stro@cpan.org>

=item *

Shoichi Kaji <skaji@cpan.org>

=item *

SkyMarshal <skymarshal1729@gmail.com>

=item *

Sören Kornetzki <soeren.kornetzki@delti.com>

=item *

Steve Grazzini <steve.grazzini@grantstreet.com>

=item *

Stig Palmquist <git@stig.io>

=item *

Syohei YOSHIDA <syohex@gmail.com>

=item *

Tatsuhiko Miyagawa <miyagawa@bulknews.net>

=item *

Tom Hukins <tom@eborcom.com>

=item *

Tony Cook <tony@develop-help.com>

=item *

Xavier Guimard <yadd@debian.org>

=back

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2024 by Christian Hansen.

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

=cut
PK5N%[���w�w�perl5/HTTP/Message.pmnu��6�$package HTTP::Message;

use strict;
use warnings;

our $VERSION = '7.00';

require HTTP::Headers;
require Carp;

our $MAXIMUM_BODY_SIZE;

my $CRLF = "\015\012";   # "\r\n" is not portable
unless ($HTTP::URI_CLASS) {
    if ($ENV{PERL_HTTP_URI_CLASS}
    &&  $ENV{PERL_HTTP_URI_CLASS} =~ /^([\w:]+)$/) {
        $HTTP::URI_CLASS = $1;
    } else {
        $HTTP::URI_CLASS = "URI";
    }
}
eval "require $HTTP::URI_CLASS"; die $@ if $@;

*_utf8_downgrade = defined(&utf8::downgrade) ?
    sub {
        utf8::downgrade($_[0], 1) or
            Carp::croak("HTTP::Message content must be bytes")
    }
    :
    sub {
    };

sub new
{
    my($class, $header, $content) = @_;
    if (defined $header) {
	Carp::croak("Bad header argument") unless ref $header;
        if (ref($header) eq "ARRAY") {
	    $header = HTTP::Headers->new(@$header);
	}
	else {
	    $header = $header->clone;
	}
    }
    else {
	$header = HTTP::Headers->new;
    }
    if (defined $content) {
        _utf8_downgrade($content);
    }
    else {
        $content = '';
    }

    bless {
	'_headers' => $header,
	'_content' => $content,
	'_max_body_size' => $HTTP::Message::MAXIMUM_BODY_SIZE,
    }, $class;
}

sub parse
{
    my($class, $str) = @_;

    my @hdr;
    while (1) {
	if ($str =~ s/^([^\s:]+)[ \t]*: ?(.*)\n?//) {
	    push(@hdr, $1, $2);
	    $hdr[-1] =~ s/\r\z//;
	}
	elsif (@hdr && $str =~ s/^([ \t].*)\n?//) {
	    $hdr[-1] .= "\n$1";
	    $hdr[-1] =~ s/\r\z//;
	}
	else {
	    $str =~ s/^\r?\n//;
	    last;
	}
    }
    local $HTTP::Headers::TRANSLATE_UNDERSCORE;
    new($class, \@hdr, $str);
}


sub clone
{
    my $self  = shift;
    my $clone = HTTP::Message->new($self->headers,
				   $self->content);
    $clone->protocol($self->protocol);
    $clone;
}


sub clear {
    my $self = shift;
    $self->{_headers}->clear;
    $self->content("");
    delete $self->{_parts};
    return;
}


sub protocol {
    shift->_elem('_protocol',  @_);
}

sub headers {
    my $self = shift;

    # recalculation of _content might change headers, so we
    # need to force it now
    $self->_content unless exists $self->{_content};

    $self->{_headers};
}

sub headers_as_string {
    shift->headers->as_string(@_);
}


sub content  {

    my $self = $_[0];
    if (defined(wantarray)) {
	$self->_content unless exists $self->{_content};
	my $old = $self->{_content};
	$old = $$old if ref($old) eq "SCALAR";
	&_set_content if @_ > 1;
	return $old;
    }

    if (@_ > 1) {
	&_set_content;
    }
    else {
	Carp::carp("Useless content call in void context") if $^W;
    }
}


sub _set_content {
    my $self = $_[0];
    _utf8_downgrade($_[1]);
    if (!ref($_[1]) && ref($self->{_content}) eq "SCALAR") {
	${$self->{_content}} = defined( $_[1] ) ? $_[1] : '';
    }
    else {
	die "Can't set content to be a scalar reference" if ref($_[1]) eq "SCALAR";
	$self->{_content} = defined( $_[1] ) ? $_[1] : '';
	delete $self->{_content_ref};
    }
    delete $self->{_parts} unless $_[2];
}


sub add_content
{
    my $self = shift;
    $self->_content unless exists $self->{_content};
    my $chunkref = \$_[0];
    $chunkref = $$chunkref if ref($$chunkref);  # legacy

    _utf8_downgrade($$chunkref);

    my $ref = ref($self->{_content});
    if (!$ref) {
	$self->{_content} .= $$chunkref;
    }
    elsif ($ref eq "SCALAR") {
	${$self->{_content}} .= $$chunkref;
    }
    else {
	Carp::croak("Can't append to $ref content");
    }
    delete $self->{_parts};
}

sub add_content_utf8 {
    my($self, $buf)  = @_;
    utf8::upgrade($buf);
    utf8::encode($buf);
    $self->add_content($buf);
}

sub content_ref
{
    my $self = shift;
    $self->_content unless exists $self->{_content};
    delete $self->{_parts};
    my $old = \$self->{_content};
    my $old_cref = $self->{_content_ref};
    if (@_) {
	my $new = shift;
	Carp::croak("Setting content_ref to a non-ref") unless ref($new);
	delete $self->{_content};  # avoid modifying $$old
	$self->{_content} = $new;
	$self->{_content_ref}++;
    }
    $old = $$old if $old_cref;
    return $old;
}


sub content_charset
{
    my $self = shift;
    if (my $charset = $self->content_type_charset) {
	return $charset;
    }

    # time to start guessing
    my $cref = $self->decoded_content(ref => 1, charset => "none");

    # Unicode BOM
    for ($$cref) {
	return "UTF-8"     if /^\xEF\xBB\xBF/;
	return "UTF-32LE" if /^\xFF\xFE\x00\x00/;
	return "UTF-32BE" if /^\x00\x00\xFE\xFF/;
	return "UTF-16LE" if /^\xFF\xFE/;
	return "UTF-16BE" if /^\xFE\xFF/;
    }

    if ($self->content_is_xml) {
	# http://www.w3.org/TR/2006/REC-xml-20060816/#sec-guessing
	# XML entity not accompanied by external encoding information and not
	# in UTF-8 or UTF-16 encoding must begin with an XML encoding declaration,
	# in which the first characters must be '<?xml'
	for ($$cref) {
	    return "UTF-32BE" if /^\x00\x00\x00</;
	    return "UTF-32LE" if /^<\x00\x00\x00/;
	    return "UTF-16BE" if /^(?:\x00\s)*\x00</;
	    return "UTF-16LE" if /^(?:\s\x00)*<\x00/;
	    if (/^\s*(<\?xml[^\x00]*?\?>)/) {
		if ($1 =~ /\sencoding\s*=\s*(["'])(.*?)\1/) {
		    my $enc = $2;
		    $enc =~ s/^\s+//; $enc =~ s/\s+\z//;
		    return $enc if $enc;
		}
	    }
	}
	return "UTF-8";
    }
    elsif ($self->content_is_html) {
	# look for <META charset="..."> or <META content="...">
	# http://dev.w3.org/html5/spec/Overview.html#determining-the-character-encoding
	require IO::HTML;
	# Use relaxed search to match previous versions of HTTP::Message:
	my $encoding = IO::HTML::find_charset_in($$cref, { encoding    => 1,
	                                                   need_pragma => 0 });
	return $encoding->mime_name if $encoding;
    }
    elsif ($self->content_type eq "application/json") {
	for ($$cref) {
	    # RFC 4627, ch 3
	    return "UTF-32BE" if /^\x00\x00\x00./s;
	    return "UTF-32LE" if /^.\x00\x00\x00/s;
	    return "UTF-16BE" if /^\x00.\x00./s;
	    return "UTF-16LE" if /^.\x00.\x00/s;
	    return "UTF-8";
	}
    }
    if ($self->content_type =~ /^text\//) {
	for ($$cref) {
	    if (length) {
		return "US-ASCII" unless /[\x80-\xFF]/;
		require Encode;
		eval {
		    Encode::decode_utf8($_, Encode::FB_CROAK() | Encode::LEAVE_SRC());
		};
		return "UTF-8" unless $@;
		return "ISO-8859-1";
	    }
	}
    }

    return undef;
}

sub max_body_size  {
    my $self = $_[0];
    my $old = $self->{_max_body_size};
    $self->_set_max_body_size($_[1]) if @_ > 1;
    return $old;
}

sub _set_max_body_size {
    my $self = $_[0];
    $self->{_max_body_size} = $_[1];
}

sub decoded_content
{
    my($self, %opt) = @_;
    my $content_ref;
    my $content_ref_iscopy;

    eval {
	$content_ref = $self->content_ref;
	die "Can't decode ref content" if ref($content_ref) ne "SCALAR";

	my $content_limit = exists $opt{ max_body_size } ? $opt{ max_body_size }
			: defined $self->max_body_size ? $self->max_body_size
			: undef
			;
	my %limiter_options;
	if( defined $content_limit ) {
	    %limiter_options = (LimitOutput => 1, Bufsize => $content_limit);
	};
	if (my $h = $self->header("Content-Encoding")) {
	    $h =~ s/^\s+//;
	    $h =~ s/\s+$//;
	    for my $ce (reverse split(/\s*,\s*/, lc($h))) {
		next unless $ce;
		next if $ce eq "identity" || $ce eq "none";
		if ($ce eq "gzip" || $ce eq "x-gzip") {
		    require Compress::Raw::Zlib; # 'WANT_GZIP_OR_ZLIB', 'Z_BUF_ERROR';

		    if( ! $content_ref_iscopy and keys %limiter_options) {
			# Create a copy of the input because Zlib will overwrite it
			# :-(
			my $input = "$$content_ref";
			$content_ref = \$input;
			$content_ref_iscopy++;
		    };
		    my ($i, $status) = Compress::Raw::Zlib::Inflate->new(
			%limiter_options,
			ConsumeInput => 0, # overridden by Zlib if we have %limiter_options :-(
			WindowBits => Compress::Raw::Zlib::WANT_GZIP_OR_ZLIB(),
		    );
		    my $res = $i->inflate( $content_ref, \my $output );
		    $res == Compress::Raw::Zlib::Z_BUF_ERROR()
			and Carp::croak("Decoded content would be larger than $content_limit octets");
		    $res == Compress::Raw::Zlib::Z_OK()
		    or $res == Compress::Raw::Zlib::Z_STREAM_END()
		    or die "Can't gunzip content: $res";
		    $content_ref = \$output;
		    $content_ref_iscopy++;
		}
		elsif ($ce eq 'br') {
		    require IO::Uncompress::Brotli;
		    my $bro = IO::Uncompress::Brotli->create;

		    my $output;
		    if( defined $content_limit ) {
			$output = eval { $bro->decompress( $$content_ref, $content_limit ); }
		    } else {
			$output = eval { $bro->decompress($$content_ref) };
		    }

		    $@ and die "Can't unbrotli content: $@";
		    $content_ref = \$output;
		    $content_ref_iscopy++;
		}
		elsif ($ce eq "x-bzip2" or $ce eq "bzip2") {
		    require Compress::Raw::Bzip2;

		    if( ! $content_ref_iscopy ) {
			# Create a copy of the input because Bzlib2 will overwrite it
			# :-(
			my $input = "$$content_ref";
			$content_ref = \$input;
			$content_ref_iscopy++;
		    };
		    my ($i, $status) = Compress::Raw::Bunzip2->new(
			1, # appendInput
			0, # consumeInput
			0, # small
			$limiter_options{ LimitOutput } || 0,
		    );
		    my $output;
		    $output = "\0" x $limiter_options{ Bufsize }
			if $limiter_options{ Bufsize };
		    my $res = $i->bzinflate( $content_ref, \$output );
		    $res == Compress::Raw::Bzip2::BZ_OUTBUFF_FULL()
			and Carp::croak("Decoded content would be larger than $content_limit octets");
		    $res == Compress::Raw::Bzip2::BZ_OK()
		    or $res == Compress::Raw::Bzip2::BZ_STREAM_END()
			or die "Can't bunzip content: $res";
			    $content_ref = \$output;
		    $content_ref_iscopy++;
		}
		elsif ($ce eq "deflate") {
		    require IO::Uncompress::Inflate;
		    my $output;
		    my $status = IO::Uncompress::Inflate::inflate($content_ref, \$output, Transparent => 0);
		    my $error = $IO::Uncompress::Inflate::InflateError;
		    unless ($status) {
			# "Content-Encoding: deflate" is supposed to mean the
			# "zlib" format of RFC 1950, but Microsoft got that
			# wrong, so some servers sends the raw compressed
			# "deflate" data.  This tries to inflate this format.
			$output = undef;
			require IO::Uncompress::RawInflate;
			unless (IO::Uncompress::RawInflate::rawinflate($content_ref, \$output)) {
			    $self->push_header("Client-Warning" =>
				"Could not raw inflate content: $IO::Uncompress::RawInflate::RawInflateError");
			    $output = undef;
			}
		    }
		    die "Can't inflate content: $error" unless defined $output;
		    $content_ref = \$output;
		    $content_ref_iscopy++;
		}
		elsif ($ce eq "compress" || $ce eq "x-compress") {
		    die "Can't uncompress content";
		}
		elsif ($ce eq "base64") {  # not really C-T-E, but should be harmless
		    require MIME::Base64;
		    $content_ref = \MIME::Base64::decode($$content_ref);
		    $content_ref_iscopy++;
		}
		elsif ($ce eq "quoted-printable") { # not really C-T-E, but should be harmless
		    require MIME::QuotedPrint;
		    $content_ref = \MIME::QuotedPrint::decode($$content_ref);
		    $content_ref_iscopy++;
		}
		else {
		    die "Don't know how to decode Content-Encoding '$ce'";
		}
	    }
	}

	if ($self->content_is_text || (my $is_xml = $self->content_is_xml)) {
	    my $charset = lc(
	        $opt{charset} ||
		$self->content_type_charset ||
		$opt{default_charset} ||
		$self->content_charset ||
		"ISO-8859-1"
	    );
	    if ($charset eq "none") {
		# leave it as is
	    }
	    elsif ($charset eq "us-ascii" || $charset eq "iso-8859-1") {
		if ($$content_ref =~ /[^\x00-\x7F]/ && defined &utf8::upgrade) {
		    unless ($content_ref_iscopy) {
			my $copy = $$content_ref;
			$content_ref = \$copy;
			$content_ref_iscopy++;
		    }
		    utf8::upgrade($$content_ref);
		}
	    }
	    else {
		require Encode;
		eval {
		    $content_ref = \Encode::decode($charset, $$content_ref,
			 ($opt{charset_strict} ? Encode::FB_CROAK() : 0) | Encode::LEAVE_SRC());
		};
		if ($@) {
		    my $retried;
		    if ($@ =~ /^Unknown encoding/) {
			my $alt_charset = lc($opt{alt_charset} || "");
			if ($alt_charset && $charset ne $alt_charset) {
			    # Retry decoding with the alternative charset
			    $content_ref = \Encode::decode($alt_charset, $$content_ref,
				 ($opt{charset_strict} ? Encode::FB_CROAK() : 0) | Encode::LEAVE_SRC())
			        unless $alt_charset eq "none";
			    $retried++;
			}
		    }
		    die unless $retried;
		}
		die "Encode::decode() returned undef improperly" unless defined $$content_ref;
		if ($is_xml) {
		    # Get rid of the XML encoding declaration if present
		    $$content_ref =~ s/^\x{FEFF}//;
		    if ($$content_ref =~ /^(\s*<\?xml[^\x00]*?\?>)/) {
			substr($$content_ref, 0, length($1)) =~ s/\sencoding\s*=\s*(["']).*?\1//;
		    }
		}
	    }
	}
    };
    if ($@) {
	Carp::croak($@) if $opt{raise_error};
	return undef;
    }

    return $opt{ref} ? $content_ref : $$content_ref;
}


sub decodable
{
    # should match the Content-Encoding values that decoded_content can deal with
    my $self = shift;
    my @enc;
    local $@;
    # XXX preferably we should determine if the modules are available without loading
    # them here
    eval {
        require Compress::Raw::Zlib;
        push(@enc, "gzip", "x-gzip");
    };
    eval {
        require IO::Uncompress::Inflate;
        require IO::Uncompress::RawInflate;
        push(@enc, "deflate");
    };
    eval {
        require Compress::Raw::Bzip2;
        push(@enc, "x-bzip2", "bzip2");
    };
    eval {
        require IO::Uncompress::Brotli;
        push(@enc, 'br');
    };
    # we don't care about announcing the 'identity', 'base64' and
    # 'quoted-printable' stuff
    return wantarray ? @enc : join(", ", @enc);
}


sub decode
{
    my $self = shift;
    return 1 unless $self->header("Content-Encoding");
    if (defined(my $content = $self->decoded_content(charset => "none"))) {
	$self->remove_header("Content-Encoding", "Content-Length", "Content-MD5");
	$self->content($content);
	return 1;
    }
    return 0;
}


sub encode
{
    my($self, @enc) = @_;

    Carp::croak("Can't encode multipart/* messages") if $self->content_type =~ m,^multipart/,;
    Carp::croak("Can't encode message/* messages") if $self->content_type =~ m,^message/,;

    return 1 unless @enc;  # nothing to do

    my $content = $self->content;
    for my $encoding (@enc) {
	if ($encoding eq "identity" || $encoding eq "none") {
	    # nothing to do
	}
	elsif ($encoding eq "base64") {
	    require MIME::Base64;
	    $content = MIME::Base64::encode($content);
	}
	elsif ($encoding eq "gzip" || $encoding eq "x-gzip") {
	    require IO::Compress::Gzip;
	    my $output;
	    IO::Compress::Gzip::gzip(\$content, \$output, Minimal => 1)
		or die "Can't gzip content: $IO::Compress::Gzip::GzipError";
	    $content = $output;
	}
	elsif ($encoding eq "deflate") {
	    require IO::Compress::Deflate;
	    my $output;
	    IO::Compress::Deflate::deflate(\$content, \$output)
		or die "Can't deflate content: $IO::Compress::Deflate::DeflateError";
	    $content = $output;
	}
	elsif ($encoding eq "x-bzip2" || $encoding eq "bzip2") {
	    require IO::Compress::Bzip2;
	    my $output;
	    IO::Compress::Bzip2::bzip2(\$content, \$output)
		or die "Can't bzip2 content: $IO::Compress::Bzip2::Bzip2Error";
	    $content = $output;
	}
	elsif ($encoding eq "br") {
		require IO::Compress::Brotli;
		my $output;
		eval { $output = IO::Compress::Brotli::bro($content) }
		or die "Can't brotli content: $@";
		$content = $output;
	}
	elsif ($encoding eq "rot13") {  # for the fun of it
	    $content =~ tr/A-Za-z/N-ZA-Mn-za-m/;
	}
	else {
	    return 0;
	}
    }
    my $h = $self->header("Content-Encoding");
    unshift(@enc, $h) if $h;
    $self->header("Content-Encoding", join(", ", @enc));
    $self->remove_header("Content-Length", "Content-MD5");
    $self->content($content);
    return 1;
}


sub as_string
{
    my($self, $eol) = @_;
    $eol = "\n" unless defined $eol;

    # The calculation of content might update the headers
    # so we need to do that first.
    my $content = $self->content;

    return join("", $self->{'_headers'}->as_string($eol),
		    $eol,
		    $content,
		    (@_ == 1 && length($content) &&
		     $content !~ /\n\z/) ? "\n" : "",
		);
}


sub dump
{
    my($self, %opt) = @_;
    my $content = $self->content;
    my $chopped = 0;
    if (!ref($content)) {
	my $maxlen = $opt{maxlength};
	$maxlen = 512 unless defined($maxlen);
	if ($maxlen && length($content) > $maxlen * 1.1 + 3) {
	    $chopped = length($content) - $maxlen;
	    $content = substr($content, 0, $maxlen) . "...";
	}

	$content =~ s/\\/\\\\/g;
	$content =~ s/\t/\\t/g;
	$content =~ s/\r/\\r/g;

	# no need for 3 digits in escape for these
	$content =~ s/([\0-\11\13-\037])(?!\d)/sprintf('\\%o',ord($1))/eg;

	$content =~ s/([\0-\11\13-\037\177-\377])/sprintf('\\x%02X',ord($1))/eg;
	$content =~ s/([^\12\040-\176])/sprintf('\\x{%X}',ord($1))/eg;

	# remaining whitespace
	$content =~ s/( +)\n/("\\40" x length($1)) . "\n"/eg;
	$content =~ s/(\n+)\n/("\\n" x length($1)) . "\n"/eg;
	$content =~ s/\n\z/\\n/;

	my $no_content = $opt{no_content};
	$no_content = "(no content)" unless defined $no_content;
	if ($content eq $no_content) {
	    # escape our $no_content marker
	    $content =~ s/^(.)/sprintf('\\x%02X',ord($1))/eg;
	}
	elsif ($content eq "") {
	    $content = $no_content;
	}
    }

    my @dump;
    push(@dump, $opt{preheader}) if $opt{preheader};
    push(@dump, $self->{_headers}->as_string, $content);
    push(@dump, "(+ $chopped more bytes not shown)") if $chopped;

    my $dump = join("\n", @dump, "");
    $dump =~ s/^/$opt{prefix}/gm if $opt{prefix};

    print $dump unless defined wantarray;
    return $dump;
}

# allow subclasses to override what will handle individual parts
sub _part_class {
    return __PACKAGE__;
}

sub parts {
    my $self = shift;
    if (defined(wantarray) && (!exists $self->{_parts} || ref($self->{_content}) eq "SCALAR")) {
	$self->_parts;
    }
    my $old = $self->{_parts};
    if (@_) {
	my @parts = map { ref($_) eq 'ARRAY' ? @$_ : $_ } @_;
	my $ct = $self->content_type || "";
	if ($ct =~ m,^message/,) {
	    Carp::croak("Only one part allowed for $ct content")
		if @parts > 1;
	}
	elsif ($ct !~ m,^multipart/,) {
	    $self->remove_content_headers;
	    $self->content_type("multipart/mixed");
	}
	$self->{_parts} = \@parts;
	_stale_content($self);
    }
    return @$old if wantarray;
    return $old->[0];
}

sub add_part {
    my $self = shift;
    if (($self->content_type || "") !~ m,^multipart/,) {
	my $p = $self->_part_class->new(
	    $self->remove_content_headers,
	    $self->content(""),
	);
	$self->content_type("multipart/mixed");
	$self->{_parts} = [];
        if ($p->headers->header_field_names || $p->content ne "") {
            push(@{$self->{_parts}}, $p);
        }
    }
    elsif (!exists $self->{_parts} || ref($self->{_content}) eq "SCALAR") {
	$self->_parts;
    }

    push(@{$self->{_parts}}, @_);
    _stale_content($self);
    return;
}

sub _stale_content {
    my $self = shift;
    if (ref($self->{_content}) eq "SCALAR") {
	# must recalculate now
	$self->_content;
    }
    else {
	# just invalidate cache
	delete $self->{_content};
	delete $self->{_content_ref};
    }
}

# delegate all other method calls to the headers object.
our $AUTOLOAD;

sub AUTOLOAD {
    my ( $package, $method ) = $AUTOLOAD =~ m/\A(.+)::([^:]*)\z/;
    my $code = $_[0]->can($method);
    Carp::croak(
        qq(Can't locate object method "$method" via package "$package"))
        unless $code;
    goto &$code;
}

sub can {
    my ( $self, $method ) = @_;

    if ( my $own_method = $self->SUPER::can($method) ) {
        return $own_method;
    }

    my $headers = ref($self) ? $self->headers : 'HTTP::Headers';
    if ( $headers->can($method) ) {

        # We create the function here so that it will not need to be
        # autoloaded or recreated the next time.
        no strict 'refs';
        *$method = sub {
            local $Carp::Internal{ +__PACKAGE__ } = 1;
            shift->headers->$method(@_);
        };
        return \&$method;
    }

    return undef;
}

sub DESTROY { }    # avoid AUTOLOADing it

# Private method to access members in %$self
sub _elem
{
    my $self = shift;
    my $elem = shift;
    my $old = $self->{$elem};
    $self->{$elem} = $_[0] if @_;
    return $old;
}


# Create private _parts attribute from current _content
sub _parts {
    my $self = shift;
    my $ct = $self->content_type;
    if ($ct =~ m,^multipart/,) {
	require HTTP::Headers::Util;
	my @h = HTTP::Headers::Util::split_header_words($self->header("Content-Type"));
	die "Assert" unless @h;
	my %h = @{$h[0]};
	if (defined(my $b = $h{boundary})) {
	    my $str = $self->content;
	    $str =~ s/\r?\n--\Q$b\E--.*//s;
	    if ($str =~ s/(^|.*?\r?\n)--\Q$b\E\r?\n//s) {
		$self->{_parts} = [map $self->_part_class->parse($_),
				   split(/\r?\n--\Q$b\E\r?\n/, $str)]
	    }
	}
    }
    elsif ($ct eq "message/http") {
	require HTTP::Request;
	require HTTP::Response;
	my $content = $self->content;
	my $class = ($content =~ m,^(HTTP/.*)\n,) ?
	    "HTTP::Response" : "HTTP::Request";
	$self->{_parts} = [$class->parse($content)];
    }
    elsif ($ct =~ m,^message/,) {
	$self->{_parts} = [ $self->_part_class->parse($self->content) ];
    }

    $self->{_parts} ||= [];
}


# Create private _content attribute from current _parts
sub _content {
    my $self = shift;
    my $ct = $self->{_headers}->header("Content-Type") || "multipart/mixed";
    if ($ct =~ m,^\s*message/,i) {
	_set_content($self, $self->{_parts}[0]->as_string($CRLF), 1);
	return;
    }

    require HTTP::Headers::Util;
    my @v = HTTP::Headers::Util::split_header_words($ct);
    Carp::carp("Multiple Content-Type headers") if @v > 1;
    @v = @{$v[0]};

    my $boundary;
    my $boundary_index;
    for (my @tmp = @v; @tmp;) {
	my($k, $v) = splice(@tmp, 0, 2);
	if ($k eq "boundary") {
	    $boundary = $v;
	    $boundary_index = @v - @tmp - 1;
	    last;
	}
    }

    my @parts = map $_->as_string($CRLF), @{$self->{_parts}};

    my $bno = 0;
    $boundary = _boundary() unless defined $boundary;
 CHECK_BOUNDARY:
    {
	for (@parts) {
	    if (index($_, $boundary) >= 0) {
		# must have a better boundary
		$boundary = _boundary(++$bno);
		redo CHECK_BOUNDARY;
	    }
	}
    }

    if ($boundary_index) {
	$v[$boundary_index] = $boundary;
    }
    else {
	push(@v, boundary => $boundary);
    }

    $ct = HTTP::Headers::Util::join_header_words(@v);
    $self->{_headers}->header("Content-Type", $ct);

    _set_content($self, "--$boundary$CRLF" .
	                join("$CRLF--$boundary$CRLF", @parts) .
			"$CRLF--$boundary--$CRLF",
                        1);
}


sub _boundary
{
    my $size = shift || return "xYzZY";
    require MIME::Base64;
    my $b = MIME::Base64::encode(join("", map chr(rand(256)), 1..$size*3), "");
    $b =~ s/[\W]/X/g;  # ensure alnum only
    $b;
}


1;

=pod

=encoding UTF-8

=head1 NAME

HTTP::Message - HTTP style message (base class)

=head1 VERSION

version 7.00

=head1 SYNOPSIS

 use parent 'HTTP::Message';

=head1 DESCRIPTION

An C<HTTP::Message> object contains some headers and a content body.
The following methods are available:

=over 4

=item $mess = HTTP::Message->new

=item $mess = HTTP::Message->new( $headers )

=item $mess = HTTP::Message->new( $headers, $content )

This constructs a new message object.  Normally you would want
construct C<HTTP::Request> or C<HTTP::Response> objects instead.

The optional $header argument should be a reference to an
C<HTTP::Headers> object or a plain array reference of key/value pairs.
If an C<HTTP::Headers> object is provided then a copy of it will be
embedded into the constructed message, i.e. it will not be owned and
can be modified afterwards without affecting the message.

The optional $content argument should be a string of bytes.

=item $mess = HTTP::Message->parse( $str )

This constructs a new message object by parsing the given string.

=item $mess->headers

Returns the embedded C<HTTP::Headers> object.

=item $mess->headers_as_string

=item $mess->headers_as_string( $eol )

Call the as_string() method for the headers in the
message.  This will be the same as

    $mess->headers->as_string

but it will make your program a whole character shorter :-)

=item $mess->content

=item $mess->content( $bytes )

The content() method sets the raw content if an argument is given.  If no
argument is given the content is not touched.  In either case the
original raw content is returned.

If the C<undef> argument is given, the content is reset to its default value,
which is an empty string.

Note that the content should be a string of bytes.  Strings in perl
can contain characters outside the range of a byte.  The C<Encode>
module can be used to turn such strings into a string of bytes.

=item $mess->add_content( $bytes )

The add_content() methods appends more data bytes to the end of the
current content buffer.

=item $mess->add_content_utf8( $string )

The add_content_utf8() method appends the UTF-8 bytes representing the
string to the end of the current content buffer.

=item $mess->content_ref

=item $mess->content_ref( \$bytes )

The content_ref() method will return a reference to content buffer string.
It can be more efficient to access the content this way if the content
is huge, and it can even be used for direct manipulation of the content,
for instance:

  ${$res->content_ref} =~ s/\bfoo\b/bar/g;

This example would modify the content buffer in-place.

If an argument is passed it will setup the content to reference some
external source.  The content() and add_content() methods
will automatically dereference scalar references passed this way.  For
other references content() will return the reference itself and
add_content() will refuse to do anything.

=item $mess->content_charset

This returns the charset used by the content in the message.  The
charset is either found as the charset attribute of the
C<Content-Type> header or by guessing.

See L<http://www.w3.org/TR/REC-html40/charset.html#spec-char-encoding>
for details about how charset is determined.

=item $mess->decoded_content( %options )

Returns the content with any C<Content-Encoding> undone and, for textual content
(C<Content-Type> values starting with C<text/>, exactly matching
C<application/xml>, or ending with C<+xml>), the raw content's character set
decoded into Perl's Unicode string format. Note that this
L<does not currently|https://github.com/libwww-perl/HTTP-Message/pull/99>
attempt to decode declared character sets for any other content types like
C<application/json> or C<application/javascript>.  If the C<Content-Encoding>
or C<charset> of the message is unknown, this method will fail by returning
C<undef>.

The following options can be specified.

=over

=item C<charset>

This overrides the charset parameter for text content.  The value
C<none> can used to suppress decoding of the charset.

=item C<default_charset>

This overrides the default charset guessed by content_charset() or
if that fails "ISO-8859-1".

=item C<alt_charset>

If decoding fails because the charset specified in the Content-Type header
isn't recognized by Perl's Encode module, then try decoding using this charset
instead of failing.  The C<alt_charset> might be specified as C<none> to simply
return the string without any decoding of charset as alternative.

=item C<charset_strict>

Abort decoding if malformed characters is found in the content.  By
default you get the substitution character ("\x{FFFD}") in place of
malformed characters.

=item C<raise_error>

If TRUE then raise an exception if not able to decode content.  Reason
might be that the specified C<Content-Encoding> or C<charset> is not
supported.  If this option is FALSE, then decoded_content() will return
C<undef> on errors, but will still set $@.

=item C<ref>

If TRUE then a reference to decoded content is returned.  This might
be more efficient in cases where the decoded content is identical to
the raw content as no data copying is required in this case.

=back

=item $mess->decodable

=item HTTP::Message::decodable()

This returns the encoding identifiers that decoded_content() can
process.  In scalar context returns a comma separated string of
identifiers.

This value is suitable for initializing the C<Accept-Encoding> request
header field.

=item $mess->decode

This method tries to replace the content of the message with the
decoded version and removes the C<Content-Encoding> header.  Returns
TRUE if successful and FALSE if not.

If the message does not have a C<Content-Encoding> header this method
does nothing and returns TRUE.

Note that the content of the message is still bytes after this method
has been called and you still need to call decoded_content() if you
want to process its content as a string.

=item $mess->encode( $encoding, ... )

Apply the given encodings to the content of the message.  Returns TRUE
if successful. The "identity" (non-)encoding is always supported; other
currently supported encodings, subject to availability of required
additional modules, are "gzip", "deflate", "x-bzip2", "base64" and "br".

A successful call to this function will set the C<Content-Encoding>
header.

Note that C<multipart/*> or C<message/*> messages can't be encoded and
this method will croak if you try.

=item $mess->parts

=item $mess->parts( @parts )

=item $mess->parts( \@parts )

Messages can be composite, i.e. contain other messages.  The composite
messages have a content type of C<multipart/*> or C<message/*>.  This
method give access to the contained messages.

The argumentless form will return a list of C<HTTP::Message> objects.
If the content type of $msg is not C<multipart/*> or C<message/*> then
this will return the empty list.  In scalar context only the first
object is returned.  The returned message parts should be regarded as
read-only (future versions of this library might make it possible
to modify the parent by modifying the parts).

If the content type of $msg is C<message/*> then there will only be
one part returned.

If the content type is C<message/http>, then the return value will be
either an C<HTTP::Request> or an C<HTTP::Response> object.

If a @parts argument is given, then the content of the message will be
modified. The array reference form is provided so that an empty list
can be provided.  The @parts array should contain C<HTTP::Message>
objects.  The @parts objects are owned by $mess after this call and
should not be modified or made part of other messages.

When updating the message with this method and the old content type of
$mess is not C<multipart/*> or C<message/*>, then the content type is
set to C<multipart/mixed> and all other content headers are cleared.

This method will croak if the content type is C<message/*> and more
than one part is provided.

=item $mess->add_part( $part )

This will add a part to a message.  The $part argument should be
another C<HTTP::Message> object.  If the previous content type of
$mess is not C<multipart/*> then the old content (together with all
content headers) will be made part #1 and the content type made
C<multipart/mixed> before the new part is added.  The $part object is
owned by $mess after this call and should not be modified or made part
of other messages.

There is no return value.

=item $mess->clear

Will clear the headers and set the content to the empty string.  There
is no return value

=item $mess->protocol

=item $mess->protocol( $proto )

Sets the HTTP protocol used for the message.  The protocol() is a string
like C<HTTP/1.0> or C<HTTP/1.1>.

=item $mess->clone

Returns a copy of the message object.

=item $mess->as_string

=item $mess->as_string( $eol )

Returns the message formatted as a single string.

The optional $eol parameter specifies the line ending sequence to use.
The default is "\n".  If no $eol is given then as_string will ensure
that the returned string is newline terminated (even when the message
content is not).  No extra newline is appended if an explicit $eol is
passed.

=item $mess->dump( %opt )

Returns the message formatted as a string.  In void context print the string.

This differs from C<< $mess->as_string >> in that it escapes the bytes
of the content so that it's safe to print them and it limits how much
content to print.  The escapes syntax used is the same as for Perl's
double quoted strings.  If there is no content the string "(no
content)" is shown in its place.

Options to influence the output can be passed as key/value pairs. The
following options are recognized:

=over

=item maxlength => $num

How much of the content to show.  The default is 512.  Set this to 0
for unlimited.

If the content is longer then the string is chopped at the limit and
the string "...\n(### more bytes not shown)" appended.

=item no_content => $str

Replaces the "(no content)" marker.

=item prefix => $str

A string that will be prefixed to each line of the dump.

=back

=back

All methods unknown to C<HTTP::Message> itself are delegated to the
C<HTTP::Headers> object that is part of every message.  This allows
convenient access to these methods.  Refer to L<HTTP::Headers> for
details of these methods:

    $mess->header( $field => $val )
    $mess->push_header( $field => $val )
    $mess->init_header( $field => $val )
    $mess->remove_header( $field )
    $mess->remove_content_headers
    $mess->header_field_names
    $mess->scan( \&doit )

    $mess->date
    $mess->expires
    $mess->if_modified_since
    $mess->if_unmodified_since
    $mess->last_modified
    $mess->content_type
    $mess->content_encoding
    $mess->content_length
    $mess->content_language
    $mess->title
    $mess->user_agent
    $mess->server
    $mess->from
    $mess->referer
    $mess->www_authenticate
    $mess->authorization
    $mess->proxy_authorization
    $mess->authorization_basic
    $mess->proxy_authorization_basic

=head1 AUTHOR

Gisle Aas <gisle@activestate.com>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 1994 by Gisle Aas.

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

=cut

__END__


#ABSTRACT: HTTP style message (base class)

PK5N%[mO��CCperl5/HTTP/Response.pmnu��6�$package HTTP::Response;

use strict;
use warnings;

our $VERSION = '7.00';

use parent 'HTTP::Message';

use HTTP::Status ();


sub new
{
    my($class, $rc, $msg, $header, $content) = @_;
    my $self = $class->SUPER::new($header, $content);
    $self->code($rc);
    $self->message($msg);
    $self;
}


sub parse
{
    my($class, $str) = @_;
    Carp::carp('Undefined argument to parse()') if $^W && ! defined $str;
    my $status_line;
    if (defined $str && $str =~ s/^(.*)\n//) {
	$status_line = $1;
    }
    else {
	$status_line = $str;
	$str = "";
    }

    $status_line =~ s/\r\z// if defined $status_line;

    my $self = $class->SUPER::parse($str);
    if (defined $status_line) {
        my($protocol, $code, $message);
        if ($status_line =~ /^\d{3} /) {
           # Looks like a response created by HTTP::Response->new
           ($code, $message) = split(' ', $status_line, 2);
        } else {
           ($protocol, $code, $message) = split(' ', $status_line, 3);
        }
        $self->protocol($protocol) if $protocol;
        $self->code($code) if defined($code);
        $self->message($message) if defined($message);
    }
    $self;
}


sub clone
{
    my $self = shift;
    my $clone = bless $self->SUPER::clone, ref($self);
    $clone->code($self->code);
    $clone->message($self->message);
    $clone->request($self->request->clone) if $self->request;
    # we don't clone previous
    $clone;
}


sub code      { shift->_elem('_rc',      @_); }
sub message   { shift->_elem('_msg',     @_); }
sub previous  { shift->_elem('_previous',@_); }
sub request   { shift->_elem('_request', @_); }


sub status_line
{
    my $self = shift;
    my $code = $self->{'_rc'}  || "000";
    my $mess = $self->{'_msg'} || HTTP::Status::status_message($code) || "Unknown code";
    return "$code $mess";
}


sub base
{
    my $self = shift;
    my $base = (
	$self->header('Content-Base'),        # used to be HTTP/1.1
	$self->header('Base'),                # HTTP/1.0
    )[0];
    if ($base && $base =~ /^$URI::scheme_re:/o) {
	# already absolute
	return $HTTP::URI_CLASS->new($base);
    }

    my $req = $self->request;
    if ($req) {
        # if $base is undef here, the return value is effectively
        # just a copy of $self->request->uri.
        return $HTTP::URI_CLASS->new_abs($base, $req->uri);
    }

    # can't find an absolute base
    return undef;
}


sub redirects {
    my $self = shift;
    my @r;
    my $r = $self;
    while (my $p = $r->previous) {
        push(@r, $p);
        $r = $p;
    }
    return @r unless wantarray;
    return reverse @r;
}


sub filename
{
    my $self = shift;
    my $file;

    my $cd = $self->header('Content-Disposition');
    if ($cd) {
	require HTTP::Headers::Util;
	if (my @cd = HTTP::Headers::Util::split_header_words($cd)) {
	    my ($disposition, undef, %cd_param) = @{$cd[-1]};
	    $file = $cd_param{filename};

	    # RFC 2047 encoded?
	    if ($file && $file =~ /^=\?(.+?)\?(.+?)\?(.+)\?=$/) {
		my $charset = $1;
		my $encoding = uc($2);
		my $encfile = $3;

		if ($encoding eq 'Q' || $encoding eq 'B') {
		    local($SIG{__DIE__});
		    eval {
			if ($encoding eq 'Q') {
			    $encfile =~ s/_/ /g;
			    require MIME::QuotedPrint;
			    $encfile = MIME::QuotedPrint::decode($encfile);
			}
			else { # $encoding eq 'B'
			    require MIME::Base64;
			    $encfile = MIME::Base64::decode($encfile);
			}

			require Encode;
			require Encode::Locale;
			Encode::from_to($encfile, $charset, "locale_fs");
		    };

		    $file = $encfile unless $@;
		}
	    }
	}
    }

    unless (defined($file) && length($file)) {
	my $uri;
	if (my $cl = $self->header('Content-Location')) {
	    $uri = URI->new($cl);
	}
	elsif (my $request = $self->request) {
	    $uri = $request->uri;
	}

	if ($uri) {
	    $file = ($uri->path_segments)[-1];
	}
    }

    if ($file) {
	$file =~ s,.*[\\/],,;  # basename
    }

    if ($file && !length($file)) {
	$file = undef;
    }

    $file;
}


sub as_string
{
    my $self = shift;
    my($eol) = @_;
    $eol = "\n" unless defined $eol;

    my $status_line = $self->status_line;
    my $proto = $self->protocol;
    $status_line = "$proto $status_line" if $proto;

    return join($eol, $status_line, $self->SUPER::as_string(@_));
}


sub dump
{
    my $self = shift;

    my $status_line = $self->status_line;
    my $proto = $self->protocol;
    $status_line = "$proto $status_line" if $proto;

    return $self->SUPER::dump(
	preheader => $status_line,
        @_,
    );
}


sub is_info     { HTTP::Status::is_info     (shift->{'_rc'}); }
sub is_success  { HTTP::Status::is_success  (shift->{'_rc'}); }
sub is_redirect { HTTP::Status::is_redirect (shift->{'_rc'}); }
sub is_error    { HTTP::Status::is_error    (shift->{'_rc'}); }
sub is_client_error { HTTP::Status::is_client_error (shift->{'_rc'}); }
sub is_server_error { HTTP::Status::is_server_error (shift->{'_rc'}); }


sub error_as_HTML
{
    my $self = shift;
    my $title = 'An Error Occurred';
    my $body  = $self->status_line;
    $body =~ s/&/&amp;/g;
    $body =~ s/</&lt;/g;
    return <<EOM;
<html>
<head><title>$title</title></head>
<body>
<h1>$title</h1>
<p>$body</p>
</body>
</html>
EOM
}


sub current_age
{
    my $self = shift;
    my $time = shift;

    # Implementation of RFC 2616 section 13.2.3
    # (age calculations)
    my $response_time = $self->client_date;
    my $date = $self->date;

    my $age = 0;
    if ($response_time && $date) {
	$age = $response_time - $date;  # apparent_age
	$age = 0 if $age < 0;
    }

    my $age_v = $self->header('Age');
    if ($age_v && $age_v > $age) {
	$age = $age_v;   # corrected_received_age
    }

    if ($response_time) {
	my $request = $self->request;
	if ($request) {
	    my $request_time = $request->date;
	    if ($request_time && $request_time < $response_time) {
		# Add response_delay to age to get 'corrected_initial_age'
		$age += $response_time - $request_time;
	    }
	}
	$age += ($time || time) - $response_time;
    }
    return $age;
}


sub freshness_lifetime
{
    my($self, %opt) = @_;

    # First look for the Cache-Control: max-age=n header
    for my $cc ($self->header('Cache-Control')) {
	for my $cc_dir (split(/\s*,\s*/, $cc)) {
	    return $1 if $cc_dir =~ /^max-age\s*=\s*(\d+)/i;
	}
    }

    # Next possibility is to look at the "Expires" header
    my $date = $self->date || $self->client_date || $opt{time} || time;
    if (my $expires = $self->expires) {
	return $expires - $date;
    }

    # Must apply heuristic expiration
    return undef if exists $opt{heuristic_expiry} && !$opt{heuristic_expiry};

    # Default heuristic expiration parameters
    $opt{h_min} ||= 60;
    $opt{h_max} ||= 24 * 3600;
    $opt{h_lastmod_fraction} ||= 0.10; # 10% since last-mod suggested by RFC2616
    $opt{h_default} ||= 3600;

    # Should give a warning if more than 24 hours according to
    # RFC 2616 section 13.2.4.  Here we just make this the default
    # maximum value.

    if (my $last_modified = $self->last_modified) {
	my $h_exp = ($date - $last_modified) * $opt{h_lastmod_fraction};
	return $opt{h_min} if $h_exp < $opt{h_min};
	return $opt{h_max} if $h_exp > $opt{h_max};
	return $h_exp;
    }

    # default when all else fails
    return $opt{h_min} if $opt{h_min} > $opt{h_default};
    return $opt{h_default};
}


sub is_fresh
{
    my($self, %opt) = @_;
    $opt{time} ||= time;
    my $f = $self->freshness_lifetime(%opt);
    return undef unless defined($f);
    return $f > $self->current_age($opt{time});
}


sub fresh_until
{
    my($self, %opt) = @_;
    $opt{time} ||= time;
    my $f = $self->freshness_lifetime(%opt);
    return undef unless defined($f);
    return $f - $self->current_age($opt{time}) + $opt{time};
}

1;

=pod

=encoding UTF-8

=head1 NAME

HTTP::Response - HTTP style response message

=head1 VERSION

version 7.00

=head1 SYNOPSIS

Response objects are returned by the request() method of the C<LWP::UserAgent>:

    # ...
    $response = $ua->request($request);
    if ($response->is_success) {
        print $response->decoded_content;
    }
    else {
        print STDERR $response->status_line, "\n";
    }

=head1 DESCRIPTION

The C<HTTP::Response> class encapsulates HTTP style responses.  A
response consists of a response line, some headers, and a content
body. Note that the LWP library uses HTTP style responses even for
non-HTTP protocol schemes.  Instances of this class are usually
created and returned by the request() method of an C<LWP::UserAgent>
object.

C<HTTP::Response> is a subclass of C<HTTP::Message> and therefore
inherits its methods.  The following additional methods are available:

=over 4

=item $r = HTTP::Response->new( $code )

=item $r = HTTP::Response->new( $code, $msg )

=item $r = HTTP::Response->new( $code, $msg, $header )

=item $r = HTTP::Response->new( $code, $msg, $header, $content )

Constructs a new C<HTTP::Response> object describing a response with
response code $code and optional message $msg.  The optional $header
argument should be a reference to an C<HTTP::Headers> object or a
plain array reference of key/value pairs.  The optional $content
argument should be a string of bytes.  The meanings of these arguments are
described below.

=item $r = HTTP::Response->parse( $str )

This constructs a new response object by parsing the given string.

=item $r->code

=item $r->code( $code )

This is used to get/set the code attribute.  The code is a 3 digit
number that encode the overall outcome of an HTTP response.  The
C<HTTP::Status> module provide constants that provide mnemonic names
for the code attribute.

=item $r->message

=item $r->message( $message )

This is used to get/set the message attribute.  The message is a short
human readable single line string that explains the response code.

=item $r->header( $field )

=item $r->header( $field => $value )

This is used to get/set header values and it is inherited from
C<HTTP::Headers> via C<HTTP::Message>.  See L<HTTP::Headers> for
details and other similar methods that can be used to access the
headers.

=item $r->content

=item $r->content( $bytes )

This is used to get/set the raw content and it is inherited from the
C<HTTP::Message> base class.  See L<HTTP::Message> for details and
other methods that can be used to access the content.

=item $r->decoded_content( %options )

This will return the content after any C<Content-Encoding> and
charsets have been decoded.  See L<HTTP::Message> for details.

=item $r->request

=item $r->request( $request )

This is used to get/set the request attribute.  The request attribute
is a reference to the request that caused this response.  It does
not have to be the same request passed to the $ua->request() method,
because there might have been redirects and authorization retries in
between.

=item $r->previous

=item $r->previous( $response )

This is used to get/set the previous attribute.  The previous
attribute is used to link together chains of responses.  You get
chains of responses if the first response is redirect or unauthorized.
The value is C<undef> if this is the first response in a chain.

Note that the method $r->redirects is provided as a more convenient
way to access the response chain.

=item $r->status_line

Returns the string "E<lt>code> E<lt>message>".  If the message attribute
is not set then the official name of E<lt>code> (see L<HTTP::Status>)
is substituted.

=item $r->base

Returns the base URI for this response.  The return value will be a
reference to a URI object.

The base URI is obtained from one the following sources (in priority
order):

=over 4

=item 1.

Embedded in the document content, for instance <BASE HREF="...">
in HTML documents.

=item 2.

A "Content-Base:" header in the response.

For backwards compatibility with older HTTP implementations we will
also look for the "Base:" header.

=item 3.

The URI used to request this response. This might not be the original
URI that was passed to $ua->request() method, because we might have
received some redirect responses first.

=back

If none of these sources provide an absolute URI, undef is returned.

B<Note>: previous versions of HTTP::Response would also consider
a "Content-Location:" header,
as L<RFC 2616|https://www.rfc-editor.org/rfc/rfc2616> said it should be.
But this was never widely implemented by browsers,
and now L<RFC 7231|https://www.rfc-editor.org/rfc/rfc7231>
says it should no longer be considered.

When the LWP protocol modules produce the HTTP::Response object, then any base
URI embedded in the document (step 1) will already have initialized the
"Content-Base:" header. (See L<LWP::UserAgent/parse_head>).  This means that
this method only performs the last 2 steps (the content is not always available
either).

=item $r->filename

Returns a filename for this response.  Note that doing sanity checks
on the returned filename (eg. removing characters that cannot be used
on the target filesystem where the filename would be used, and
laundering it for security purposes) are the caller's responsibility;
the only related thing done by this method is that it makes a simple
attempt to return a plain filename with no preceding path segments.

The filename is obtained from one the following sources (in priority
order):

=over 4

=item 1.

A "Content-Disposition:" header in the response.  Proper decoding of
RFC 2047 encoded filenames requires the C<MIME::QuotedPrint> (for "Q"
encoding), C<MIME::Base64> (for "B" encoding), and C<Encode> modules.

=item 2.

A "Content-Location:" header in the response.

=item 3.

The URI used to request this response. This might not be the original
URI that was passed to $ua->request() method, because we might have
received some redirect responses first.

=back

If a filename cannot be derived from any of these sources, undef is
returned.

=item $r->as_string

=item $r->as_string( $eol )

Returns a textual representation of the response.

=item $r->is_info

=item $r->is_success

=item $r->is_redirect

=item $r->is_error

=item $r->is_client_error

=item $r->is_server_error

These methods indicate if the response was informational, successful, a
redirection, or an error.  See L<HTTP::Status> for the meaning of these.

=item $r->error_as_HTML

Returns a string containing a complete HTML document indicating what
error occurred.  This method should only be called when $r->is_error
is TRUE.

=item $r->redirects

Returns the list of redirect responses that lead up to this response
by following the $r->previous chain.  The list order is oldest first.

In scalar context return the number of redirect responses leading up
to this one.

=item $r->current_age

Calculates the "current age" of the response as specified by RFC 2616
section 13.2.3.  The age of a response is the time since it was sent
by the origin server.  The returned value is a number representing the
age in seconds.

=item $r->freshness_lifetime( %opt )

Calculates the "freshness lifetime" of the response as specified by
RFC 2616 section 13.2.4.  The "freshness lifetime" is the length of
time between the generation of a response and its expiration time.
The returned value is the number of seconds until expiry.

If the response does not contain an "Expires" or a "Cache-Control"
header, then this function will apply some simple heuristic based on
the "Last-Modified" header to determine a suitable lifetime.  The
following options might be passed to control the heuristics:

=over

=item heuristic_expiry => $bool

If passed as a FALSE value, don't apply heuristics and just return
C<undef> when "Expires" or "Cache-Control" is lacking.

=item h_lastmod_fraction => $num

This number represent the fraction of the difference since the
"Last-Modified" timestamp to make the expiry time.  The default is
C<0.10>, the suggested typical setting of 10% in RFC 2616.

=item h_min => $sec

This is the lower limit of the heuristic expiry age to use.  The
default is C<60> (1 minute).

=item h_max => $sec

This is the upper limit of the heuristic expiry age to use.  The
default is C<86400> (24 hours).

=item h_default => $sec

This is the expiry age to use when nothing else applies.  The default
is C<3600> (1 hour) or "h_min" if greater.

=back

=item $r->is_fresh( %opt )

Returns TRUE if the response is fresh, based on the values of
freshness_lifetime() and current_age().  If the response is no longer
fresh, then it has to be re-fetched or re-validated by the origin
server.

Options might be passed to control expiry heuristics, see the
description of freshness_lifetime().

=item $r->fresh_until( %opt )

Returns the time (seconds since epoch) when this entity is no longer fresh.

Options might be passed to control expiry heuristics, see the
description of freshness_lifetime().

=back

=head1 SEE ALSO

L<HTTP::Headers>, L<HTTP::Message>, L<HTTP::Status>, L<HTTP::Request>

=head1 AUTHOR

Gisle Aas <gisle@activestate.com>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 1994 by Gisle Aas.

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

=cut

__END__


#ABSTRACT: HTTP style response message

PK5N%[����#�#perl5/HTTP/Cookies/Microsoft.pmnu��6�$package HTTP::Cookies::Microsoft;

use strict;

our $VERSION = '6.11';

require HTTP::Cookies;
our @ISA=qw(HTTP::Cookies);

sub load_cookies_from_file
{
    my ($file) = @_;
    my @cookies;

    open (my $fh, '<', $file) || return;

    while (my $key = <$fh>) {
        chomp $key;
        my ($value, $domain_path, $flags, $lo_expire, $hi_expire);
        my ($lo_create, $hi_create, $sep);
        chomp($value     = <$fh>);
        chomp($domain_path= <$fh>);
        chomp($flags     = <$fh>); # 0x0001 bit is for secure
        chomp($lo_expire = <$fh>);
        chomp($hi_expire = <$fh>);
        chomp($lo_create = <$fh>);
        chomp($hi_create = <$fh>);
        chomp($sep       = <$fh>);

        if (!defined($key) || !defined($value) || !defined($domain_path) ||
            !defined($flags) || !defined($hi_expire) || !defined($lo_expire) ||
            !defined($hi_create) || !defined($lo_create) || !defined($sep) ||
            ($sep ne '*'))
        {
            last;
        }

        if ($domain_path =~ /^([^\/]+)(\/.*)$/) {
            my $domain = $1;
            my $path = $2;

            push @cookies, {
                KEY => $key, VALUE => $value, DOMAIN => $domain,
                PATH => $path, FLAGS =>$flags, HIXP =>$hi_expire,
                LOXP => $lo_expire, HICREATE => $hi_create,
                LOCREATE => $lo_create
            };
        }
    }

    return \@cookies;
}

sub get_user_name
{
	use Win32;
	use locale;
	my $user = lc(Win32::LoginName());

	return $user;
}

# MSIE stores create and expire times as Win32 FILETIME,
# which is 64 bits of 100 nanosecond intervals since Jan 01 1601
#
# But Cookies code expects time in 32-bit value expressed
# in seconds since Jan 01 1970
#
sub epoch_time_offset_from_win32_filetime
{
	my ($high, $low) = @_;

	#--------------------------------------------------------
	# USEFUL CONSTANT
	#--------------------------------------------------------
	# 0x019db1de 0xd53e8000 is 1970 Jan 01 00:00:00 in Win32 FILETIME
	#
	# 100 nanosecond intervals == 0.1 microsecond intervals

	my $filetime_low32_1970 = 0xd53e8000;
	my $filetime_high32_1970 = 0x019db1de;

	#------------------------------------
	# ALGORITHM
	#------------------------------------
	# To go from 100 nanosecond intervals to seconds since 00:00 Jan 01 1970:
	#
	# 1. Adjust 100 nanosecond intervals to Jan 01 1970 base
	# 2. Divide by 10 to get to microseconds (1/millionth second)
	# 3. Divide by 1000000 (10 ^ 6) to get to seconds
	#
	# We can combine Step 2 & 3 into one divide.
	#
	# After much trial and error, I came up with the following code which
	# avoids using Math::BigInt or floating pt, but still gives correct answers

	# If the filetime is before the epoch, return 0
	if (($high < $filetime_high32_1970) ||
	    (($high == $filetime_high32_1970) && ($low < $filetime_low32_1970)))
    	{
		return 0;
	}

	# Can't multiply by 0x100000000, (1 << 32),
	# without Perl issuing an integer overflow warning
	#
	# So use two multiplies by 0x10000 instead of one multiply by 0x100000000
	#
	# The result is the same.
	#
	my $date1970 = (($filetime_high32_1970 * 0x10000) * 0x10000) + $filetime_low32_1970;
	my $time = (($high * 0x10000) * 0x10000) + $low;

	$time -= $date1970;
	$time /= 10000000;

	return $time;
}

sub load_cookie
{
	my($self, $file) = @_;
        my $now = time() - $HTTP::Cookies::EPOCH_OFFSET;
	my $cookie_data;

        if (-f $file)
        {
		# open the cookie file and get the data
		$cookie_data = load_cookies_from_file($file);

		foreach my $cookie (@{$cookie_data})
		{
			my $secure = ($cookie->{FLAGS} & 1) != 0;
			my $expires = epoch_time_offset_from_win32_filetime($cookie->{HIXP}, $cookie->{LOXP});

			$self->set_cookie(undef, $cookie->{KEY}, $cookie->{VALUE},
					  $cookie->{PATH}, $cookie->{DOMAIN}, undef,
					  0, $secure, $expires-$now, 0);
		}
	}
}

sub load
{
    my($self, $cookie_index) = @_;
    my $now = time() - $HTTP::Cookies::EPOCH_OFFSET;
    my $cookie_dir = '';
    my $delay_load = (defined($self->{'delayload'}) && $self->{'delayload'});
    my $user_name = get_user_name();
    my $data;

    $cookie_index ||= $self->{'file'} || return;
    if ($cookie_index =~ /[\\\/][^\\\/]+$/) {
        $cookie_dir = $` . "\\";
    }

    open (my $fh, '<:raw', $cookie_index) || return;
    if (256 != read($fh, $data, 256)) {
        warn "$cookie_index file is not large enough";
        return;
    }

    # Cookies' index.dat file starts with 32 bytes of signature
    # followed by an offset to the first record, stored as a little-endian DWORD
    my ($sig, $size) = unpack('a32 V', $data);

    # check that sig is valid (only tested in IE6.0)
    if (($sig !~ /^Client UrlCache MMF Ver 5\.2/) || (0x4000 != $size)) {
        warn "$cookie_index ['$sig' $size] does not seem to contain cookies";
        return;
    }

    # move the file ptr to start of the first record
    if (0 == seek($fh, $size, 0)) {
        return;
    }

    # Cookies are usually stored in 'URL ' records in two contiguous 0x80 byte sectors (256 bytes)
    # so read in two 0x80 byte sectors and adjust if not a Cookie.
    while (256 == read($fh, $data, 256)) {
        # each record starts with a 4-byte signature
        # and a count (little-endian DWORD) of 0x80 byte sectors for the record
        ($sig, $size) = unpack('a4 V', $data);

        # Cookies are found in 'URL ' records
        if ('URL ' ne $sig) {
            # skip over uninteresting record: I've seen 'HASH' and 'LEAK' records
            if (($sig eq 'HASH') || ($sig eq 'LEAK')) {
                # '-2' takes into account the two 0x80 byte sectors we've just read in
                if (($size > 0) && ($size != 2)) {
                    if (0 == seek($fh, ($size-2)*0x80, 1)) {
                        # Seek failed. Something's wrong. Gonna stop.
                        last;
                    }
                }
            }
            next;
        }

        #$REMOVE Need to check if URL records in Cookies' index.dat will
        #        ever use more than two 0x80 byte sectors
        if ($size > 2) {
            my $more_data = ($size-2)*0x80;

            if ($more_data != read($fh, $data, $more_data, 256)) {
                last;
            }
        }

        (my $user_name2 = $user_name) =~ s/ /_/g;
        if ($data =~ /Cookie:\Q$user_name\E@([\x21-\xFF]+).*?((?:\Q$user_name\E|\Q$user_name2\E)@[\x21-\xFF]+\.txt)/) {
            my $cookie_file = $cookie_dir . $2; # form full pathname

            if (!$delay_load) {
                $self->load_cookie($cookie_file);
            }
            else {
                my $domain = $1;

                # grab only the domain name, drop everything from the first dir sep on
                if ($domain =~ m{[\\/]}) {
                    $domain = $`;
                }

                # set the delayload cookie for this domain with
                # the cookie_file as cookie for later-loading info
                $self->set_cookie(undef, 'cookie', $cookie_file, '//+delayload', $domain, undef, 0, 0, $now+86_400, 0);
            }
        }
    }

    1;
}

1;

=pod

=encoding UTF-8

=head1 NAME

HTTP::Cookies::Microsoft - Access to Microsoft cookies files

=head1 VERSION

version 6.11

=head1 SYNOPSIS

 use LWP;
 use HTTP::Cookies::Microsoft;
 use Win32::TieRegistry(Delimiter => "/");
 my $cookies_dir = $Registry->
      {"CUser/Software/Microsoft/Windows/CurrentVersion/Explorer/Shell Folders/Cookies"};

 $cookie_jar = HTTP::Cookies::Microsoft->new(
                   file     => "$cookies_dir\\index.dat",
                   'delayload' => 1,
               );
 my $browser = LWP::UserAgent->new;
 $browser->cookie_jar( $cookie_jar );

=head1 DESCRIPTION

This is a subclass of C<HTTP::Cookies> which
loads Microsoft Internet Explorer 5.x and 6.x for Windows (MSIE)
cookie files.

See the documentation for L<HTTP::Cookies>.

=head1 METHODS

The following methods are provided:

=over 4

=item $cookie_jar = HTTP::Cookies::Microsoft->new;

The constructor takes hash style parameters. In addition
to the regular HTTP::Cookies parameters, HTTP::Cookies::Microsoft
recognizes the following:

  delayload:       delay loading of cookie data until a request
                   is actually made. This results in faster
                   runtime unless you use most of the cookies
                   since only the domain's cookie data
                   is loaded on demand.

=back

=head1 CAVEATS

Please note that the code DOESN'T support saving to the MSIE
cookie file format.

=head1 AUTHOR

Johnny Lee <typo_pl@hotmail.com>

=head1 COPYRIGHT

Copyright 2002 Johnny Lee

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

=head1 AUTHOR

Gisle Aas <gisle@activestate.com>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2002 by Gisle Aas.

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

=cut

__END__

#ABSTRACT: Access to Microsoft cookies files

PK5N%[rL�HK
K
perl5/HTTP/Cookies/Netscape.pmnu��6�$package HTTP::Cookies::Netscape;

use strict;

our $VERSION = '6.11';

require HTTP::Cookies;
our @ISA=qw(HTTP::Cookies);

sub load
{
    my ($self, $file) = @_;
    $file ||= $self->{'file'} || return;

    local $/ = "\n";  # make sure we got standard record separator
    open (my $fh, '<', $file) || return;
    my $magic = <$fh>;
    chomp $magic;
    unless ($magic =~ /^#(?: Netscape)? HTTP Cookie File/) {
        warn "$file does not look like a netscape cookies file";
        return;
    }

    my $now = time() - $HTTP::Cookies::EPOCH_OFFSET;
    while (my $line = <$fh>) {
        chomp($line);
        $line =~ s/\s*\#HttpOnly_//;
        next if $line =~ /^\s*\#/;
        next if $line =~ /^\s*$/;
        $line =~ tr/\n\r//d;
        my($domain,$bool1,$path,$secure, $expires,$key,$val) = split(/\t/, $line);
        $secure = ($secure eq "TRUE");
        $self->set_cookie(undef, $key, $val, $path, $domain, undef, 0, $secure, $expires-$now, 0);
    }
    1;
}

sub save
{
    my $self = shift;
    my %args = (
        file => $self->{'file'},
        ignore_discard => $self->{'ignore_discard'},
        @_ == 1 ? ( file => $_[0] ) : @_
    );
    Carp::croak('Unexpected argument to save method') if keys %args > 2;
    my $file = $args{'file'} || return;

    open(my $fh, '>', $file) || return;

    # Use old, now broken link to the old cookie spec just in case something
    # else (not us!) requires the comment block exactly this way.
    print {$fh} <<EOT;
# Netscape HTTP Cookie File
# http://www.netscape.com/newsref/std/cookie_spec.html
# This is a generated file!  Do not edit.

EOT

    my $now = time - $HTTP::Cookies::EPOCH_OFFSET;
    $self->scan(sub {
        my ($version, $key, $val, $path, $domain, $port, $path_spec, $secure, $expires, $discard, $rest) = @_;
        return if $discard && !$args{'ignore_discard'};
        $expires = $expires ? $expires - $HTTP::Cookies::EPOCH_OFFSET : 0;
        return if $now > $expires;
        $secure = $secure ? "TRUE" : "FALSE";
        my $bool = $domain =~ /^\./ ? "TRUE" : "FALSE";
        print {$fh} join("\t", $domain, $bool, $path, $secure, $expires, $key, $val), "\n";
    });
    1;
}

1;

=pod

=encoding UTF-8

=head1 NAME

HTTP::Cookies::Netscape - Access to Netscape cookies files

=head1 VERSION

version 6.11

=head1 SYNOPSIS

 use LWP;
 use HTTP::Cookies::Netscape;
 $cookie_jar = HTTP::Cookies::Netscape->new(
   file => "c:/program files/netscape/users/ZombieCharity/cookies.txt",
 );
 my $browser = LWP::UserAgent->new;
 $browser->cookie_jar( $cookie_jar );

=head1 DESCRIPTION

This is a subclass of C<HTTP::Cookies> that reads (and optionally
writes) Netscape/Mozilla cookie files.

See the documentation for L<HTTP::Cookies>.

=head1 CAVEATS

Please note that the Netscape/Mozilla cookie file format can't store
all the information available in the Set-Cookie2 headers, so you will
probably lose some information if you save in this format.

At time of writing, this module seems to work fine with Mozilla
Phoenix/Firebird.

=head1 SEE ALSO

L<HTTP::Cookies::Microsoft>

=head1 AUTHOR

Gisle Aas <gisle@activestate.com>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2002 by Gisle Aas.

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

=cut

__END__

#ABSTRACT: Access to Netscape cookies files

PK5N%[c`�L�^�^perl5/HTTP/Cookies.pmnu��6�$package HTTP::Cookies;

use strict;
use HTTP::Date qw(str2time parse_date time2str);
use HTTP::Headers::Util qw(_split_header_words join_header_words);

our $EPOCH_OFFSET;
our $VERSION = '6.11';

# Legacy: because "use "HTTP::Cookies" used be the ONLY way
#  to load the class HTTP::Cookies::Netscape.
require HTTP::Cookies::Netscape;

$EPOCH_OFFSET = 0;  # difference from Unix epoch

# A HTTP::Cookies object is a hash.  The main attribute is the
# COOKIES 3 level hash:  $self->{COOKIES}{$domain}{$path}{$key}.

sub new
{
    my $class = shift;
    my $self = bless {
	COOKIES => {},
    }, $class;
    my %cnf = @_;
    for (keys %cnf) {
	$self->{lc($_)} = $cnf{$_};
    }
    $self->load;
    $self;
}


sub add_cookie_header
{
    my $self = shift;
    my $request = shift || return;
    my $url = $request->uri;
    my $scheme = $url->scheme;
    unless ($scheme =~ /^https?\z/) {
	return;
    }

    my $domain = _host($request, $url);
    $domain = "$domain.local" unless $domain =~ /\./;
    my $secure_request = ($scheme eq "https");
    my $req_path = _url_path($url);
    my $req_port = $url->port;
    my $now = time();
    _normalize_path($req_path) if $req_path =~ /%/;

    my @cval;    # cookie values for the "Cookie" header
    my $set_ver;
    my $netscape_only = 0; # An exact domain match applies to any cookie

    while ($domain =~ /\./) {
        # Checking $domain for cookies"
	my $cookies = $self->{COOKIES}{$domain};
	next unless $cookies;
	if ($self->{delayload} && defined($cookies->{'//+delayload'})) {
	    my $cookie_data = $cookies->{'//+delayload'}{'cookie'};
	    delete $self->{COOKIES}{$domain};
	    $self->load_cookie($cookie_data->[1]);
	    $cookies = $self->{COOKIES}{$domain};
	    next unless $cookies;  # should not really happen
	}

	# Want to add cookies corresponding to the most specific paths
	# first (i.e. longest path first)
	my $path;
	for $path (sort {length($b) <=> length($a) } keys %$cookies) {
	    if (index($req_path, $path) != 0) {
		next;
	    }

	    my($key,$array);
	    while (($key,$array) = each %{$cookies->{$path}}) {
		my($version,$val,$port,$path_spec,$secure,$expires) = @$array;
		if ($secure && !$secure_request) {
		    next;
		}
		if ($expires && $expires < $now) {
		    next;
		}
		if ($port) {
		    my $found;
		    if ($port =~ s/^_//) {
			# The corresponding Set-Cookie attribute was empty
			$found++ if $port eq $req_port;
			$port = "";
		    }
		    else {
			my $p;
			for $p (split(/,/, $port)) {
			    $found++, last if $p eq $req_port;
			}
		    }
		    unless ($found) {
			next;
		    }
		}
		if ($version > 0 && $netscape_only) {
		    next;
		}

		# set version number of cookie header.
	        # XXX: What should it be if multiple matching
                #      Set-Cookie headers have different versions themselves
		if (!$set_ver++) {
		    if ($version >= 1) {
			push(@cval, "\$Version=$version");
		    }
		    elsif (!$self->{hide_cookie2}) {
			$request->header(Cookie2 => '$Version="1"');
		    }
		}

		# do we need to quote the value
		if ($val =~ /\W/ && $version) {
		    $val =~ s/([\\\"])/\\$1/g;
		    $val = qq("$val");
		}

		# and finally remember this cookie
		push(@cval, "$key=$val");
		if ($version >= 1) {
		    push(@cval, qq(\$Path="$path"))     if $path_spec;
		    push(@cval, qq(\$Domain="$domain")) if $domain =~ /^\./;
		    if (defined $port) {
			my $p = '$Port';
			$p .= qq(="$port") if length $port;
			push(@cval, $p);
		    }
		}

	    }
        }

    } continue {
	# Try with a more general domain, alternately stripping
	# leading name components and leading dots.  When this
	# results in a domain with no leading dot, it is for
	# Netscape cookie compatibility only:
	#
	# a.b.c.net	Any cookie
	# .b.c.net	Any cookie
	# b.c.net	Netscape cookie only
	# .c.net	Any cookie

	if ($domain =~ s/^\.+//) {
	    $netscape_only = 1;
	}
	else {
	    $domain =~ s/[^.]*//;
	    $netscape_only = 0;
	}
    }

    if (@cval) {
	if (my $old = $request->header("Cookie")) {
	    unshift(@cval, $old);
	}
	$request->header(Cookie => join("; ", @cval));
	if (my $hash = $request->{_http_cookies}) {
	    %$hash = (map split(/=/, $_, 2), @cval);
	}
    }

    $request;
}


sub get_cookies
{
    my $self = shift;
    my $url = shift;
    $url = "https://$url" unless $url =~ m,^[a-zA-Z][a-zA-Z0-9.+\-]*:,;
    require HTTP::Request;
    my $req = HTTP::Request->new(GET => $url);
    my $cookies = $req->{_http_cookies} = {};
    $self->add_cookie_header($req);
    if (@_) {
	return map $cookies->{$_}, @_ if wantarray;
	return $cookies->{$_[0]};
    }
    return $cookies;
}


sub extract_cookies
{
    my $self = shift;
    my $response = shift || return;

    my @set = _split_header_words($response->_header("Set-Cookie2"));
    my @ns_set = $response->_header("Set-Cookie");

    return $response unless @set || @ns_set;  # quick exit

    my $request = $response->request;
    my $url = $request->uri;
    my $req_host = _host($request, $url);
    $req_host = "$req_host.local" unless $req_host =~ /\./;
    my $req_port = $url->port;
    my $req_path = _url_path($url);
    _normalize_path($req_path) if $req_path =~ /%/;

    if (@ns_set) {
	# The old Netscape cookie format for Set-Cookie
	# http://curl.haxx.se/rfc/cookie_spec.html
	# can for instance contain an unquoted "," in the expires
	# field, so we have to use this ad-hoc parser.
	my $now = time();

	# Build a hash of cookies that was present in Set-Cookie2
	# headers.  We need to skip them if we also find them in a
	# Set-Cookie header.
	my %in_set2;
	for (@set) {
	    $in_set2{$_->[0]}++;
	}

	my $set;
	for $set (@ns_set) {
            $set =~ s/^\s+//;
	    my @cur;
	    my $param;
	    my $expires;
	    my $first_param = 1;
	    for $param (@{_split_text($set)}) {
                next unless length($param);
		my($k,$v) = split(/\s*=\s*/, $param, 2);
		if (defined $v) {
		    $v =~ s/\s+$//;
		    #print "$k => $v\n";
		}
		else {
		    $k =~ s/\s+$//;
		    #print "$k => undef";
		}
		if (!$first_param && lc($k) eq "expires") {
		    my $etime = str2time($v);
		    if (defined $etime) {
			push(@cur, "Max-Age" => $etime - $now);
			$expires++;
		    }
		    else {
			# parse_date can deal with years outside the range of time_t,
			my($year, $mon, $day, $hour, $min, $sec, $tz) = parse_date($v);
			if ($year) {
			    my $thisyear = (gmtime)[5] + 1900;
			    if ($year < $thisyear) {
				push(@cur, "Max-Age" => -1);  # any negative value will do
				$expires++;
			    }
			    elsif ($year >= $thisyear + 10) {
				# the date is at least 10 years into the future, just replace
				# it with something approximate
				push(@cur, "Max-Age" => 10 * 365 * 24 * 60 * 60);
				$expires++;
			    }
			}
		    }
		}
                elsif (!$first_param && lc($k) eq 'max-age') {
                    $expires++;
                }
                elsif (!$first_param && lc($k) =~ /^(?:version|discard|ns-cookie)/) {
                    # ignore
                }
		else {
		    push(@cur, $k => $v);
		}
		$first_param = 0;
	    }
            next unless @cur;
	    next if $in_set2{$cur[0]};

#	    push(@cur, "Port" => $req_port);
	    push(@cur, "Discard" => undef) unless $expires;
	    push(@cur, "Version" => 0);
	    push(@cur, "ns-cookie" => 1);
	    push(@set, \@cur);
	}
    }

  SET_COOKIE:
    for my $set (@set) {
	next unless @$set >= 2;

	my $key = shift @$set;
	my $val = shift @$set;

	my %hash;
	while (@$set) {
	    my $k = shift @$set;
	    my $v = shift @$set;
	    my $lc = lc($k);
	    # don't loose case distinction for unknown fields
	    $k = $lc if $lc =~ /^(?:discard|domain|max-age|
                                    path|port|secure|version)$/x;
	    if ($k eq "discard" || $k eq "secure") {
		$v = 1 unless defined $v;
	    }
	    next if exists $hash{$k};  # only first value is significant
	    $hash{$k} = $v;
	};

	my %orig_hash = %hash;
	my $version   = delete $hash{version};
	$version = 1 unless defined($version);
	my $discard   = delete $hash{discard};
	my $secure    = delete $hash{secure};
	my $maxage    = delete $hash{'max-age'};
	my $ns_cookie = delete $hash{'ns-cookie'};

	# Check domain
	my $domain  = delete $hash{domain};
	$domain = lc($domain) if defined $domain;
	if (defined($domain)
	    && $domain ne $req_host && $domain ne ".$req_host") {
	    if ($domain !~ /\./ && $domain ne "local") {
		next SET_COOKIE;
	    }
	    $domain = ".$domain" unless $domain =~ /^\./;
	    if ($domain =~ /\.\d+$/) {
		next SET_COOKIE;
	    }
	    my $len = length($domain);
	    unless (substr($req_host, -$len) eq $domain) {
		next SET_COOKIE;
	    }
	    my $hostpre = substr($req_host, 0, length($req_host) - $len);
	    if ($hostpre =~ /\./ && !$ns_cookie) {
		next SET_COOKIE;
	    }
	}
	else {
	    $domain = $req_host;
	}

	my $path = delete $hash{path};
	my $path_spec;
	if (defined $path && $path ne '') {
	    $path_spec++;
	    _normalize_path($path) if $path =~ /%/;
	    if (!$ns_cookie &&
                substr($req_path, 0, length($path)) ne $path) {
		next SET_COOKIE;
	    }
	}
	else {
	    $path = $req_path;
	    $path =~ s,/[^/]*$,,;
	    $path = "/" unless length($path);
	}

	my $port;
	if (exists $hash{port}) {
	    $port = delete $hash{port};
	    if (defined $port) {
		$port =~ s/\s+//g;
		my $found;
		for my $p (split(/,/, $port)) {
		    unless ($p =~ /^\d+$/) {
			next SET_COOKIE;
		    }
		    $found++ if $p eq $req_port;
		}
		unless ($found) {
		    next SET_COOKIE;
		}
	    }
	    else {
		$port = "_$req_port";
	    }
	}
	$self->set_cookie($version,$key,$val,$path,$domain,$port,$path_spec,$secure,$maxage,$discard, \%hash)
	    if $self->set_cookie_ok(\%orig_hash);
    }

    $response;
}

sub set_cookie_ok
{
    1;
}


sub set_cookie
{
    my $self = shift;
    my($version,
       $key, $val, $path, $domain, $port,
       $path_spec, $secure, $maxage, $discard, $rest) = @_;

    # path and key can not be empty (key can't start with '$')
    return $self if !defined($path) || $path !~ m,^/, ||
	            !defined($key)  || $key  =~ m,^\$,;

    # ensure legal port
    if (defined $port) {
	return $self unless $port =~ /^_?\d+(?:,\d+)*$/;
    }

    my $expires;
    if (defined $maxage) {
	if ($maxage <= 0) {
	    delete $self->{COOKIES}{$domain}{$path}{$key};
	    return $self;
	}
	$expires = time() + $maxage;
    }
    $version = 0 unless defined $version;

    my @array = ($version, $val,$port,
		 $path_spec,
		 $secure, $expires, $discard);
    push(@array, {%$rest}) if defined($rest) && %$rest;
    # trim off undefined values at end
    pop(@array) while !defined $array[-1];

    $self->{COOKIES}{$domain}{$path}{$key} = \@array;
    $self;
}


sub save
{
    my $self = shift;
    my %args = (
        file => $self->{'file'},
        ignore_discard => $self->{'ignore_discard'},
        @_ == 1 ? ( file => $_[0] ) : @_
    );
    Carp::croak('Unexpected argument to save method') if keys %args > 2;
    my $file = $args{'file'} || return;
    open(my $fh, '>', $file) or die "Can't open $file: $!";
    print {$fh} "#LWP-Cookies-1.0\n";
    print {$fh} $self->as_string(!$args{'ignore_discard'});
    close $fh or die "Can't close $file: $!";
    1;
}


sub load
{
    my $self = shift;
    my $file = shift || $self->{'file'} || return;

    local $/ = "\n";  # make sure we got standard record separator
    open(my $fh, '<', $file) or return;

    # check that we have the proper header
    my $magic = <$fh>;
    chomp $magic;
    unless ($magic =~ /^#LWP-Cookies-\d+\.\d+/) {
        warn "$file does not seem to contain cookies";
        return;
    }

    # go through the file
    while (my $line = <$fh>) {
        chomp $line;
        next unless $line =~ s/^Set-Cookie3:\s*//;
        my $cookie;
        for $cookie (_split_header_words($line)) {
            my($key,$val) = splice(@$cookie, 0, 2);
            my %hash;
            while (@$cookie) {
                my $k = shift @$cookie;
                my $v = shift @$cookie;
                $hash{$k} = $v;
            }
            my $version   = delete $hash{version};
            my $path      = delete $hash{path};
            my $domain    = delete $hash{domain};
            my $port      = delete $hash{port};
            my $expires   = str2time(delete $hash{expires});

            my $path_spec = exists $hash{path_spec}; delete $hash{path_spec};
            my $secure    = exists $hash{secure};    delete $hash{secure};
            my $discard   = exists $hash{discard};   delete $hash{discard};

            my @array = ($version, $val, $port, $path_spec, $secure, $expires,
                $discard);
            push(@array, \%hash) if %hash;
            $self->{COOKIES}{$domain}{$path}{$key} = \@array;
        }
    }
    1;
}


sub revert
{
    my $self = shift;
    $self->clear->load;
    $self;
}


sub clear
{
    my $self = shift;
    if (@_ == 0) {
	$self->{COOKIES} = {};
    }
    elsif (@_ == 1) {
	delete $self->{COOKIES}{$_[0]};
    }
    elsif (@_ == 2) {
	delete $self->{COOKIES}{$_[0]}{$_[1]};
    }
    elsif (@_ == 3) {
	delete $self->{COOKIES}{$_[0]}{$_[1]}{$_[2]};
    }
    else {
	require Carp;
        Carp::carp('Usage: $c->clear([domain [,path [,key]]])');
    }
    $self;
}


sub clear_temporary_cookies
{
    my($self) = @_;

    $self->scan(sub {
        if($_[9] or        # "Discard" flag set
           not $_[8]) {    # No expire field?
            $_[8] = -1;            # Set the expire/max_age field
            $self->set_cookie(@_); # Clear the cookie
        }
      });
}


sub DESTROY
{
    my $self = shift;
    local($., $@, $!, $^E, $?);
    $self->save if $self->{'autosave'};
}


sub scan
{
    my($self, $cb) = @_;
    my($domain,$path,$key);
    for $domain (sort keys %{$self->{COOKIES}}) {
	for $path (sort keys %{$self->{COOKIES}{$domain}}) {
	    for $key (sort keys %{$self->{COOKIES}{$domain}{$path}}) {
		my($version,$val,$port,$path_spec,
		   $secure,$expires,$discard,$rest) =
		       @{$self->{COOKIES}{$domain}{$path}{$key}};
		$rest = {} unless defined($rest);
		&$cb($version,$key,$val,$path,$domain,$port,
		     $path_spec,$secure,$expires,$discard,$rest);
	    }
	}
    }
}


sub as_string
{
    my($self, $skip_discard) = @_;
    my @res;
    $self->scan(sub {
	my($version,$key,$val,$path,$domain,$port,
	   $path_spec,$secure,$expires,$discard,$rest) = @_;
	return if $discard && $skip_discard;
	my @h = ($key, $val);
	push(@h, "path", $path);
	push(@h, "domain" => $domain);
	push(@h, "port" => $port) if defined $port;
	push(@h, "path_spec" => undef) if $path_spec;
	push(@h, "secure" => undef) if $secure;
	push(@h, "expires" => HTTP::Date::time2isoz($expires)) if $expires;
	push(@h, "discard" => undef) if $discard;
	my $k;
	for $k (sort keys %$rest) {
	    push(@h, $k, $rest->{$k});
	}
	push(@h, "version" => $version);
	push(@res, "Set-Cookie3: " . join_header_words(\@h));
    });
    join("\n", @res, "");
}

sub _host
{
    my($request, $url) = @_;
    if (my $h = $request->header("Host")) {
	$h =~ s/:\d+$//;  # might have a port as well
	return lc($h);
    }
    return lc($url->host);
}

sub _url_path
{
    my $url = shift;
    my $path;
    if($url->can('epath')) {
       $path = $url->epath;    # URI::URL method
    }
    else {
       $path = $url->path;           # URI::_generic method
    }
    $path = "/" unless length $path;
    $path;
}

sub _normalize_path  # so that plain string compare can be used
{
    my $x;
    $_[0] =~ s/%([0-9a-fA-F][0-9a-fA-F])/
	         $x = uc($1);
                 $x eq "2F" || $x eq "25" ? "%$x" :
                                            pack("C", hex($x));
              /eg;
    $_[0] =~ s/([\0-\x20\x7f-\xff])/sprintf("%%%02X",ord($1))/eg;
}

# deals with splitting values by ; and the fact that they could
# be in quotes which can also have escaping.
sub _split_text {
    my $val = shift;
    my @vals = grep { $_ ne q{} } split(/([;\\"])/, $val);
    my @chunks;
    # divide it up into chunks to be processed.
    my $in_string = 0;
    my @current_string;
    for(my $i = 0; $i < @vals; $i++) {
        my $chunk = $vals[$i];
        if($in_string) {
            if($chunk eq q{\\}) {
                # don't care about next char probably.
                # having said that, probably need to be appending to the chunks
                # just dropping this.
                $i++;
                if($i < @vals) {
                    push @current_string, $vals[$i];
                }
            } elsif($chunk eq q{"}) {
                $in_string = 0;
            }
            else {
                push @current_string, $chunk;
            }
        } else {
            if($chunk eq q{"}) {
                $in_string = 1;
            }
            elsif($chunk eq q{;}) {
                push @chunks, join(q{}, @current_string);
                @current_string = ();
            }
            else {
                push @current_string, $chunk;
            }
        }
    }
    push @chunks, join(q{}, @current_string) if @current_string;
    s/^\s+// for @chunks;
    return \@chunks;
}

1;

=pod

=encoding UTF-8

=head1 NAME

HTTP::Cookies - HTTP cookie jars

=head1 VERSION

version 6.11

=head1 SYNOPSIS

  use HTTP::Cookies;
  $cookie_jar = HTTP::Cookies->new(
    file => "$ENV{'HOME'}/lwp_cookies.dat",
    autosave => 1,
  );

  use LWP;
  my $browser = LWP::UserAgent->new;
  $browser->cookie_jar($cookie_jar);

Or for an empty and temporary cookie jar:

  use LWP;
  my $browser = LWP::UserAgent->new;
  $browser->cookie_jar( {} );

=head1 DESCRIPTION

This class is for objects that represent a "cookie jar" -- that is, a
database of all the HTTP cookies that a given LWP::UserAgent object
knows about.

Cookies are a general mechanism which server side connections can use
to both store and retrieve information on the client side of the
connection.  For more information about cookies refer to
L<Cookie Spec|http://curl.haxx.se/rfc/cookie_spec.html> and
L<Cookie Central|http://www.cookiecentral.com>.  This module also implements the
new style cookies described in L<RFC 2965|https://tools.ietf.org/html/rfc2965>.
The two variants of cookies are supposed to be able to coexist happily.

Instances of the class I<HTTP::Cookies> are able to store a collection
of Set-Cookie2: and Set-Cookie: headers and are able to use this
information to initialize Cookie-headers in I<HTTP::Request> objects.
The state of a I<HTTP::Cookies> object can be saved in and restored from
files.

=head1 LIMITATIONS

This module does not support L<< Public Suffix|https://publicsuffix.org/
>> encouraged by a more recent standard, L<< RFC
6265|https://tools.ietf.org/html/rfc6265 >>.

This module's shortcomings mean that a malicious Web site can set
cookies to track your user agent across all sites under a top level
domain.  See F<< t/publicsuffix.t >> in this module's distribution for
details.

L<< HTTP::CookieJar::LWP >> supports Public Suffix, but only provides a
limited subset of this module's functionality and L<< does not
support|HTTP::CookieJar/LIMITATIONS-AND-CAVEATS >> standards older than
I<RFC 6265>.

=head1 METHODS

The following methods are provided:

=over 4

=item $cookie_jar = HTTP::Cookies->new

The constructor takes hash style parameters.  The following
parameters are recognized:

  file:            name of the file to restore cookies from and save cookies to
  autosave:        save during destruction (bool)
  ignore_discard:  save even cookies that are requested to be discarded (bool)
  hide_cookie2:    do not add Cookie2 header to requests

Future parameters might include (not yet implemented):

  max_cookies               300
  max_cookies_per_domain    20
  max_cookie_size           4096

  no_cookies   list of domain names that we never return cookies to

=item $cookie_jar->get_cookies( $url_or_domain )

=item $cookie_jar->get_cookies( $url_or_domain, $cookie_key,... )

Returns a hash of the cookies that applies to the given URL. If a
domainname is given as argument, then a prefix of "https://" is assumed.

If one or more $cookie_key parameters are provided return the given values,
or C<undef> if the cookie isn't available.

=item $cookie_jar->add_cookie_header( $request )

The add_cookie_header() method will set the appropriate Cookie:-header
for the I<HTTP::Request> object given as argument.  The $request must
have a valid url attribute before this method is called.

=item $cookie_jar->extract_cookies( $response )

The extract_cookies() method will look for Set-Cookie: and
Set-Cookie2: headers in the I<HTTP::Response> object passed as
argument.  Any of these headers that are found are used to update
the state of the $cookie_jar.

=item $cookie_jar->set_cookie( $version, $key, $val, $path, $domain, $port, $path_spec, $secure, $maxage, $discard, \%rest )

The set_cookie() method updates the state of the $cookie_jar.  The
$key, $val, $domain, $port and $path arguments are strings.  The
$path_spec, $secure, $discard arguments are boolean values. The $maxage
value is a number indicating number of seconds that this cookie will
live.  A value of $maxage <= 0 will delete this cookie.  The $version argument
sets the version of the cookie; the default value is 0 ( original Netscape
spec ).  Setting $version to another value indicates the RFC to which the
cookie conforms (e.g. version 1 for RFC 2109).  %rest defines various other
attributes like "Comment" and "CommentURL".

=item $cookie_jar->save

=item $cookie_jar->save( $file )

=item $cookie_jar->save( file => $file, ignore_discard => $ignore_discard )

This method saves the state of the $cookie_jar to a file.
The state can then be restored later using the load() method.  If a
filename is not specified we will use the name specified during
construction.  If the $ignore_discard value is true (or not specified,
but attribute I<ignore_discard> was set at cookie jar construction),
then we will even save cookies that are marked to be discarded.

The default is to save a sequence of "Set-Cookie3" lines.
"Set-Cookie3" is a proprietary LWP format, not known to be compatible
with any browser.  The I<HTTP::Cookies::Netscape> sub-class can
be used to save in a format compatible with Netscape.

=item $cookie_jar->load

=item $cookie_jar->load( $file )

This method reads the cookies from the file and adds them to the
$cookie_jar.  The file must be in the format written by the save()
method.

=item $cookie_jar->revert

This method empties the $cookie_jar and re-loads the $cookie_jar
from the last save file.

=item $cookie_jar->clear

=item $cookie_jar->clear( $domain )

=item $cookie_jar->clear( $domain, $path )

=item $cookie_jar->clear( $domain, $path, $key )

Invoking this method without arguments will empty the whole
$cookie_jar.  If given a single argument only cookies belonging to
that domain will be removed.  If given two arguments, cookies
belonging to the specified path within that domain are removed.  If
given three arguments, then the cookie with the specified key, path
and domain is removed.

=item $cookie_jar->clear_temporary_cookies

Discard all temporary cookies. Scans for all cookies in the jar
with either no expire field or a true C<discard> flag. To be
called when the user agent shuts down according to RFC 2965.

=item $cookie_jar->scan( \&callback )

The argument is a subroutine that will be invoked for each cookie
stored in the $cookie_jar.  The subroutine will be invoked with
the following arguments:

  0  version
  1  key
  2  val
  3  path
  4  domain
  5  port
  6  path_spec
  7  secure
  8  expires
  9  discard
 10  hash

=item $cookie_jar->as_string

=item $cookie_jar->as_string( $skip_discardables )

The as_string() method will return the state of the $cookie_jar
represented as a sequence of "Set-Cookie3" header lines separated by
"\n".  If $skip_discardables is TRUE, it will not return lines for
cookies with the I<Discard> attribute.

=back

=head1 SEE ALSO

L<HTTP::Cookies::Netscape>, L<HTTP::Cookies::Microsoft>

=head1 AUTHOR

Gisle Aas <gisle@activestate.com>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2002 by Gisle Aas.

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

=cut

__END__
#ABSTRACT: HTTP cookie jars

PK5N%[�|H��a�aperl5/HTTP/Headers.pmnu��6�$package HTTP::Headers;

use strict;
use warnings;

our $VERSION = '7.00';

use Clone qw(clone);
use Carp ();

# The $TRANSLATE_UNDERSCORE variable controls whether '_' can be used
# as a replacement for '-' in header field names.
our $TRANSLATE_UNDERSCORE = 1 unless defined $TRANSLATE_UNDERSCORE;

# "Good Practice" order of HTTP message headers:
#    - General-Headers
#    - Request-Headers
#    - Response-Headers
#    - Entity-Headers

my @general_headers = qw(
    Cache-Control Connection Date Pragma Trailer Transfer-Encoding Upgrade
    Via Warning
);

my @request_headers = qw(
    Accept Accept-Charset Accept-Encoding Accept-Language
    Authorization Expect From Host
    If-Match If-Modified-Since If-None-Match If-Range If-Unmodified-Since
    Max-Forwards Proxy-Authorization Range Referer TE User-Agent
);

my @response_headers = qw(
    Accept-Ranges Age ETag Location Proxy-Authenticate Retry-After Server
    Vary WWW-Authenticate
);

my @entity_headers = qw(
    Allow Content-Encoding Content-Language Content-Length Content-Location
    Content-MD5 Content-Range Content-Type Expires Last-Modified
);

my %entity_header = map { lc($_) => 1 } @entity_headers;

my @header_order = (
    @general_headers,
    @request_headers,
    @response_headers,
    @entity_headers,
);

# Make alternative representations of @header_order.  This is used
# for sorting and case matching.
my %header_order;
my %standard_case;

{
    my $i = 0;
    for (@header_order) {
	my $lc = lc $_;
	$header_order{$lc} = ++$i;
	$standard_case{$lc} = $_;
    }
}



sub new
{
    my($class) = shift;
    my $self = bless {}, $class;
    $self->header(@_) if @_; # set up initial headers
    $self;
}


sub header
{
    my $self = shift;
    Carp::croak('Usage: $h->header($field, ...)') unless @_;
    my(@old);
    my %seen;
    while (@_) {
	my $field = shift;
        my $op = @_ ? ($seen{lc($field)}++ ? 'PUSH' : 'SET') : 'GET';
	@old = $self->_header($field, shift, $op);
    }
    return @old if wantarray;
    return $old[0] if @old <= 1;
    join(", ", @old);
}

sub clear
{
    my $self = shift;
    %$self = ();
}


sub push_header
{
    my $self = shift;
    return $self->_header(@_, 'PUSH_H') if @_ == 2;
    while (@_) {
	$self->_header(splice(@_, 0, 2), 'PUSH_H');
    }
}


sub init_header
{
    Carp::croak('Usage: $h->init_header($field, $val)') if @_ != 3;
    shift->_header(@_, 'INIT');
}


sub remove_header
{
    my($self, @fields) = @_;
    my $field;
    my @values;
    foreach $field (@fields) {
	$field =~ tr/_/-/ if $field !~ /^:/ && $TRANSLATE_UNDERSCORE;
	my $v = delete $self->{lc $field};
	push(@values, ref($v) eq 'ARRAY' ? @$v : $v) if defined $v;
    }
    return @values;
}

sub remove_content_headers
{
    my $self = shift;
    unless (defined(wantarray)) {
	# fast branch that does not create return object
	delete @$self{grep $entity_header{$_} || /^content-/, keys %$self};
	return;
    }

    my $c = ref($self)->new;
    for my $f (grep $entity_header{$_} || /^content-/, keys %$self) {
	$c->{$f} = delete $self->{$f};
    }
    if (exists $self->{'::std_case'}) {
	$c->{'::std_case'} = $self->{'::std_case'};
    }
    $c;
}


sub _header
{
    my($self, $field, $val, $op) = @_;

    Carp::croak("Illegal field name '$field'")
        if rindex($field, ':') > 1 || !length($field);

    unless ($field =~ /^:/) {
	$field =~ tr/_/-/ if $TRANSLATE_UNDERSCORE;
	my $old = $field;
	$field = lc $field;
	unless($standard_case{$field} || $self->{'::std_case'}{$field}) {
	    # generate a %std_case entry for this field
	    $old =~ s/\b(\w)/\u$1/g;
	    $self->{'::std_case'}{$field} = $old;
	}
    }

    $op ||= defined($val) ? 'SET' : 'GET';
    if ($op eq 'PUSH_H') {
	# Like PUSH but where we don't care about the return value
	if (exists $self->{$field}) {
	    my $h = $self->{$field};
	    if (ref($h) eq 'ARRAY') {
		push(@$h, ref($val) eq "ARRAY" ? @$val : $val);
	    }
	    else {
		$self->{$field} = [$h, ref($val) eq "ARRAY" ? @$val : $val]
	    }
	    return;
	}
	$self->{$field} = $val;
	return;
    }

    my $h = $self->{$field};
    my @old = ref($h) eq 'ARRAY' ? @$h : (defined($h) ? ($h) : ());

    unless ($op eq 'GET' || ($op eq 'INIT' && @old)) {
	if (defined($val)) {
	    my @new = ($op eq 'PUSH') ? @old : ();
	    if (ref($val) ne 'ARRAY') {
		push(@new, $val);
	    }
	    else {
		push(@new, @$val);
	    }
	    $self->{$field} = @new > 1 ? \@new : $new[0];
	}
	elsif ($op ne 'PUSH') {
	    delete $self->{$field};
	}
    }
    @old;
}


sub _sorted_field_names
{
    my $self = shift;
    return [ sort {
        ($header_order{$a} || 999) <=> ($header_order{$b} || 999) ||
         $a cmp $b
    } grep !/^::/, keys %$self ];
}


sub header_field_names {
    my $self = shift;
    return map $standard_case{$_} || $self->{'::std_case'}{$_} || $_, @{ $self->_sorted_field_names },
	if wantarray;
    return grep !/^::/, keys %$self;
}


sub scan
{
    my($self, $sub) = @_;
    my $key;
    for $key (@{ $self->_sorted_field_names }) {
	my $vals = $self->{$key};
	if (ref($vals) eq 'ARRAY') {
	    my $val;
	    for $val (@$vals) {
		$sub->($standard_case{$key} || $self->{'::std_case'}{$key} || $key, $val);
	    }
	}
	else {
	    $sub->($standard_case{$key} || $self->{'::std_case'}{$key} || $key, $vals);
	}
    }
}

sub flatten {
	my($self)=@_;

	(
		map {
			my $k = $_;
			map {
				( $k => $_ )
			} $self->header($_);
		} $self->header_field_names
	);
}

sub as_string
{
    my($self, $endl) = @_;
    $endl = "\n" unless defined $endl;

    my @result = ();
    for my $key (@{ $self->_sorted_field_names }) {
	next if index($key, '_') == 0;
	my $vals = $self->{$key};
	if ( ref($vals) eq 'ARRAY' ) {
	    for my $val (@$vals) {
		$val = '' if not defined $val;
		my $field = $standard_case{$key} || $self->{'::std_case'}{$key} || $key;
		$field =~ s/^://;
		if ( index($val, "\n") >= 0 ) {
		    $val = _process_newline($val, $endl);
		}
		push @result, $field . ': ' . $val;
	    }
	}
	else {
	    $vals = '' if not defined $vals;
	    my $field = $standard_case{$key} || $self->{'::std_case'}{$key} || $key;
	    $field =~ s/^://;
	    if ( index($vals, "\n") >= 0 ) {
		$vals = _process_newline($vals, $endl);
	    }
	    push @result, $field . ': ' . $vals;
	}
    }

    join($endl, @result, '');
}

sub _process_newline {
    local $_ = shift;
    my $endl = shift;
    # must handle header values with embedded newlines with care
    s/\s+$//;        # trailing newlines and space must go
    s/\n(\x0d?\n)+/\n/g;     # no empty lines
    s/\n([^\040\t])/\n $1/g; # initial space for continuation
    s/\n/$endl/g;    # substitute with requested line ending
    $_;
}


sub _date_header
{
    require HTTP::Date;
    my($self, $header, $time) = @_;
    my($old) = $self->_header($header);
    if (defined $time) {
	$self->_header($header, HTTP::Date::time2str($time));
    }
    $old =~ s/;.*// if defined($old);
    HTTP::Date::str2time($old);
}


sub date                { shift->_date_header('Date',                @_); }
sub expires             { shift->_date_header('Expires',             @_); }
sub if_modified_since   { shift->_date_header('If-Modified-Since',   @_); }
sub if_unmodified_since { shift->_date_header('If-Unmodified-Since', @_); }
sub last_modified       { shift->_date_header('Last-Modified',       @_); }

# This is used as a private LWP extension.  The Client-Date header is
# added as a timestamp to a response when it has been received.
sub client_date         { shift->_date_header('Client-Date',         @_); }

# The retry_after field is dual format (can also be a expressed as
# number of seconds from now), so we don't provide an easy way to
# access it until we have know how both these interfaces can be
# addressed.  One possibility is to return a negative value for
# relative seconds and a positive value for epoch based time values.
#sub retry_after       { shift->_date_header('Retry-After',       @_); }

sub content_type      {
    my $self = shift;
    my $ct = $self->{'content-type'};
    $self->{'content-type'} = shift if @_;
    $ct = $ct->[0] if ref($ct) eq 'ARRAY';
    return '' unless defined($ct) && length($ct);
    my @ct = split(/;\s*/, $ct, 2);
    for ($ct[0]) {
	s/\s+//g;
	$_ = lc($_);
    }
    wantarray ? @ct : $ct[0];
}

sub content_type_charset {
    my $self = shift;
    require HTTP::Headers::Util;
    my $h = $self->{'content-type'};
    $h = $h->[0] if ref($h);
    $h = "" unless defined $h;
    my @v = HTTP::Headers::Util::split_header_words($h);
    if (@v) {
	my($ct, undef, %ct_param) = @{$v[0]};
	my $charset = $ct_param{charset};
	if ($ct) {
	    $ct = lc($ct);
	    $ct =~ s/\s+//;
	}
	if ($charset) {
	    $charset = uc($charset);
	    $charset =~ s/^\s+//;  $charset =~ s/\s+\z//;
	    undef($charset) if $charset eq "";
	}
	return $ct, $charset if wantarray;
	return $charset;
    }
    return undef, undef if wantarray;
    return undef;
}

sub content_is_text {
    my $self = shift;
    return $self->content_type =~ m,^text/,;
}

sub content_is_html {
    my $self = shift;
    return $self->content_type eq 'text/html' || $self->content_is_xhtml;
}

sub content_is_xhtml {
    my $ct = shift->content_type;
    return $ct eq "application/xhtml+xml" ||
           $ct eq "application/vnd.wap.xhtml+xml";
}

sub content_is_xml {
    my $ct = shift->content_type;
    return 1 if $ct eq "text/xml";
    return 1 if $ct eq "application/xml";
    return 1 if $ct =~ /\+xml$/;
    return 0;
}

sub referer           {
    my $self = shift;
    if (@_ && $_[0] =~ /#/) {
	# Strip fragment per RFC 2616, section 14.36.
	my $uri = shift;
	if (ref($uri)) {
	    $uri = $uri->clone;
	    $uri->fragment(undef);
	}
	else {
	    $uri =~ s/\#.*//;
	}
	unshift @_, $uri;
    }
    ($self->_header('Referer', @_))[0];
}
*referrer = \&referer;  # on tchrist's request

sub title             { (shift->_header('Title',            @_))[0] }
sub content_encoding  { (shift->_header('Content-Encoding', @_))[0] }
sub content_language  { (shift->_header('Content-Language', @_))[0] }
sub content_length    { (shift->_header('Content-Length',   @_))[0] }

sub user_agent        { (shift->_header('User-Agent',       @_))[0] }
sub server            { (shift->_header('Server',           @_))[0] }

sub from              { (shift->_header('From',             @_))[0] }
sub warning           { (shift->_header('Warning',          @_))[0] }

sub www_authenticate  { (shift->_header('WWW-Authenticate', @_))[0] }
sub authorization     { (shift->_header('Authorization',    @_))[0] }

sub proxy_authenticate  { (shift->_header('Proxy-Authenticate',  @_))[0] }
sub proxy_authorization { (shift->_header('Proxy-Authorization', @_))[0] }

sub authorization_basic       { shift->_basic_auth("Authorization",       @_) }
sub proxy_authorization_basic { shift->_basic_auth("Proxy-Authorization", @_) }

sub _basic_auth {
    require MIME::Base64;
    my($self, $h, $user, $passwd) = @_;
    my($old) = $self->_header($h);
    if (defined $user) {
	Carp::croak("Basic authorization user name can't contain ':'")
	  if $user =~ /:/;
	$passwd = '' unless defined $passwd;
	$self->_header($h => 'Basic ' .
                             MIME::Base64::encode("$user:$passwd", ''));
    }
    if (defined $old && $old =~ s/^\s*Basic\s+//) {
	my $val = MIME::Base64::decode($old);
	return $val unless wantarray;
	return split(/:/, $val, 2);
    }
    return;
}


1;

=pod

=encoding UTF-8

=head1 NAME

HTTP::Headers - Class encapsulating HTTP Message headers

=head1 VERSION

version 7.00

=head1 SYNOPSIS

 require HTTP::Headers;
 $h = HTTP::Headers->new;

 $h->header('Content-Type' => 'text/plain');  # set
 $ct = $h->header('Content-Type');            # get
 $h->remove_header('Content-Type');           # delete

=head1 DESCRIPTION

The C<HTTP::Headers> class encapsulates HTTP-style message headers.
The headers consist of attribute-value pairs also called fields, which
may be repeated, and which are printed in a particular order.  The
field names are cases insensitive.

Instances of this class are usually created as member variables of the
C<HTTP::Request> and C<HTTP::Response> classes, internal to the
library.

The following methods are available:

=over 4

=item $h = HTTP::Headers->new

Constructs a new C<HTTP::Headers> object.  You might pass some initial
attribute-value pairs as parameters to the constructor.  I<E.g.>:

 $h = HTTP::Headers->new(
       Date         => 'Thu, 03 Feb 1994 00:00:00 GMT',
       Content_Type => 'text/html; version=3.2',
       Content_Base => 'http://www.perl.org/');

The constructor arguments are passed to the C<header> method which is
described below.

=item $h->clone

Returns a copy of this C<HTTP::Headers> object.

=item $h->header( $field )

=item $h->header( $field => $value )

=item $h->header( $f1 => $v1, $f2 => $v2, ... )

Get or set the value of one or more header fields.  The header field
name ($field) is not case sensitive.  To make the life easier for perl
users who wants to avoid quoting before the => operator, you can use
'_' as a replacement for '-' in header names.

The header() method accepts multiple ($field => $value) pairs, which
means that you can update several fields with a single invocation.

The $value argument may be a plain string or a reference to an array
of strings for a multi-valued field. If the $value is provided as
C<undef> then the field is removed.  If the $value is not given, then
that header field will remain unchanged. In addition to being a string,
$value may be something that stringifies.

The old value (or values) of the last of the header fields is returned.
If no such field exists C<undef> will be returned.

A multi-valued field will be returned as separate values in list
context and will be concatenated with ", " as separator in scalar
context.  The HTTP spec (RFC 2616) promises that joining multiple
values in this way will not change the semantic of a header field, but
in practice there are cases like old-style Netscape cookies (see
L<HTTP::Cookies>) where "," is used as part of the syntax of a single
field value.

Examples:

 $header->header(MIME_Version => '1.0',
		 User_Agent   => 'My-Web-Client/0.01');
 $header->header(Accept => "text/html, text/plain, image/*");
 $header->header(Accept => [qw(text/html text/plain image/*)]);
 @accepts = $header->header('Accept');  # get multiple values
 $accepts = $header->header('Accept');  # get values as a single string

=item $h->push_header( $field => $value )

=item $h->push_header( $f1 => $v1, $f2 => $v2, ... )

Add a new field value for the specified header field.  Previous values
for the same field are retained.

As for the header() method, the field name ($field) is not case
sensitive and '_' can be used as a replacement for '-'.

The $value argument may be a scalar or a reference to a list of
scalars.

 $header->push_header(Accept => 'image/jpeg');
 $header->push_header(Accept => [map "image/$_", qw(gif png tiff)]);

=item $h->init_header( $field => $value )

Set the specified header to the given value, but only if no previous
value for that field is set.

The header field name ($field) is not case sensitive and '_'
can be used as a replacement for '-'.

The $value argument may be a scalar or a reference to a list of
scalars.

=item $h->remove_header( $field, ... )

This function removes the header fields with the specified names.

The header field names ($field) are not case sensitive and '_'
can be used as a replacement for '-'.

The return value is the values of the fields removed.  In scalar
context the number of fields removed is returned.

Note that if you pass in multiple field names then it is generally not
possible to tell which of the returned values belonged to which field.

=item $h->remove_content_headers

This will remove all the header fields used to describe the content of
a message.  All header field names prefixed with C<Content-> fall
into this category, as well as C<Allow>, C<Expires> and
C<Last-Modified>.  RFC 2616 denotes these fields as I<Entity Header
Fields>.

The return value is a new C<HTTP::Headers> object that contains the
removed headers only.

=item $h->clear

This will remove all header fields.

=item $h->header_field_names

Returns the list of distinct names for the fields present in the
header.  The field names have case as suggested by HTTP spec, and the
names are returned in the recommended "Good Practice" order.

In scalar context return the number of distinct field names.

=item $h->scan( \&process_header_field )

Apply a subroutine to each header field in turn.  The callback routine
is called with two parameters; the name of the field and a single
value (a string).  If a header field is multi-valued, then the
routine is called once for each value.  The field name passed to the
callback routine has case as suggested by HTTP spec, and the headers
will be visited in the recommended "Good Practice" order.

Any return values of the callback routine are ignored.  The loop can
be broken by raising an exception (C<die>), but the caller of scan()
would have to trap the exception itself.

=item $h->flatten()

Returns the list of pairs of keys and values.

=item $h->as_string

=item $h->as_string( $eol )

Return the header fields as a formatted MIME header.  Since it
internally uses the C<scan> method to build the string, the result
will use case as suggested by HTTP spec, and it will follow
recommended "Good Practice" of ordering the header fields.  Long header
values are not folded.

The optional $eol parameter specifies the line ending sequence to
use.  The default is "\n".  Embedded "\n" characters in header field
values will be substituted with this line ending sequence.

=back

=head1 CONVENIENCE METHODS

The most frequently used headers can also be accessed through the
following convenience methods.  Most of these methods can both be used to read
and to set the value of a header.  The header value is set if you pass
an argument to the method.  The old header value is always returned.
If the given header did not exist then C<undef> is returned.

Methods that deal with dates/times always convert their value to system
time (seconds since Jan 1, 1970) and they also expect this kind of
value when the header value is set.

=over 4

=item $h->date

This header represents the date and time at which the message was
originated. I<E.g.>:

  $h->date(time);  # set current date

=item $h->expires

This header gives the date and time after which the entity should be
considered stale.

=item $h->if_modified_since

=item $h->if_unmodified_since

These header fields are used to make a request conditional.  If the requested
resource has (or has not) been modified since the time specified in this field,
then the server will return a C<304 Not Modified> response instead of
the document itself.

=item $h->last_modified

This header indicates the date and time at which the resource was last
modified. I<E.g.>:

  # check if document is more than 1 hour old
  if (my $last_mod = $h->last_modified) {
      if ($last_mod < time - 60*60) {
	  ...
      }
  }

=item $h->content_type

The Content-Type header field indicates the media type of the message
content. I<E.g.>:

  $h->content_type('text/html');

The value returned will be converted to lower case, and potential
parameters will be chopped off and returned as a separate value if in
an array context.  If there is no such header field, then the empty
string is returned.  This makes it safe to do the following:

  if ($h->content_type eq 'text/html') {
     # we enter this place even if the real header value happens to
     # be 'TEXT/HTML; version=3.0'
     ...
  }

=item $h->content_type_charset

Returns the upper-cased charset specified in the Content-Type header.  In list
context return the lower-cased bare content type followed by the upper-cased
charset.  Both values will be C<undef> if not specified in the header.

=item $h->content_is_text

Returns TRUE if the Content-Type header field indicate that the
content is textual.

=item $h->content_is_html

Returns TRUE if the Content-Type header field indicate that the
content is some kind of HTML (including XHTML).  This method can't be
used to set Content-Type.

=item $h->content_is_xhtml

Returns TRUE if the Content-Type header field indicate that the
content is XHTML.  This method can't be used to set Content-Type.

=item $h->content_is_xml

Returns TRUE if the Content-Type header field indicate that the
content is XML.  This method can't be used to set Content-Type.

=item $h->content_encoding

The Content-Encoding header field is used as a modifier to the
media type.  When present, its value indicates what additional
encoding mechanism has been applied to the resource.

=item $h->content_length

A decimal number indicating the size in bytes of the message content.

=item $h->content_language

The natural language(s) of the intended audience for the message
content.  The value is one or more language tags as defined by RFC
1766.  Eg. "no" for some kind of Norwegian and "en-US" for English the
way it is written in the US.

=item $h->title

The title of the document.  In libwww-perl this header will be
initialized automatically from the E<lt>TITLE>...E<lt>/TITLE> element
of HTML documents.  I<This header is no longer part of the HTTP
standard.>

=item $h->user_agent

This header field is used in request messages and contains information
about the user agent originating the request.  I<E.g.>:

  $h->user_agent('Mozilla/5.0 (compatible; MSIE 7.0; Windows NT 6.0)');

=item $h->server

The server header field contains information about the software being
used by the originating server program handling the request.

=item $h->from

This header should contain an Internet e-mail address for the human
user who controls the requesting user agent.  The address should be
machine-usable, as defined by RFC822.  E.g.:

  $h->from('King Kong <king@kong.com>');

I<This header is no longer part of the HTTP standard.>

=item $h->referer

Used to specify the address (URI) of the document from which the
requested resource address was obtained.

The "Free On-line Dictionary of Computing" as this to say about the
word I<referer>:

     <World-Wide Web> A misspelling of "referrer" which
     somehow made it into the {HTTP} standard.  A given {web
     page}'s referer (sic) is the {URL} of whatever web page
     contains the link that the user followed to the current
     page.  Most browsers pass this information as part of a
     request.

     (1998-10-19)

By popular demand C<referrer> exists as an alias for this method so you
can avoid this misspelling in your programs and still send the right
thing on the wire.

When setting the referrer, this method removes the fragment from the
given URI if it is present, as mandated by RFC2616.  Note that
the removal does I<not> happen automatically if using the header(),
push_header() or init_header() methods to set the referrer.

=item $h->www_authenticate

This header must be included as part of a C<401 Unauthorized> response.
The field value consist of a challenge that indicates the
authentication scheme and parameters applicable to the requested URI.

=item $h->proxy_authenticate

This header must be included in a C<407 Proxy Authentication Required>
response.

=item $h->authorization

=item $h->proxy_authorization

A user agent that wishes to authenticate itself with a server or a
proxy, may do so by including these headers.

=item $h->authorization_basic

This method is used to get or set an authorization header that use the
"Basic Authentication Scheme".  In array context it will return two
values; the user name and the password.  In scalar context it will
return I<"uname:password"> as a single string value.

When used to set the header value, it expects two arguments.  I<E.g.>:

  $h->authorization_basic($uname, $password);

The method will croak if the $uname contains a colon ':'.

=item $h->proxy_authorization_basic

Same as authorization_basic() but will set the "Proxy-Authorization"
header instead.

=back

=head1 NON-CANONICALIZED FIELD NAMES

The header field name spelling is normally canonicalized including the
'_' to '-' translation.  There are some application where this is not
appropriate.  Prefixing field names with ':' allow you to force a
specific spelling.  For example if you really want a header field name
to show up as C<foo_bar> instead of "Foo-Bar", you might set it like
this:

  $h->header(":foo_bar" => 1);

These field names are returned with the ':' intact for
$h->header_field_names and the $h->scan callback, but the colons do
not show in $h->as_string.

=head1 AUTHOR

Gisle Aas <gisle@activestate.com>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 1994 by Gisle Aas.

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

=cut

__END__


#ABSTRACT: Class encapsulating HTTP Message headers

PK5N%[�e��M7M7perl5/HTTP/Status.pmnu��6�$package HTTP::Status;

use strict;
use warnings;

our $VERSION = '7.00';

use Exporter 5.57 'import';

our @EXPORT = qw(is_info is_success is_redirect is_error status_message);
our @EXPORT_OK = qw(is_client_error is_server_error is_cacheable_by_default status_constant_name status_codes);

# Note also addition of mnemonics to @EXPORT below

# Unmarked codes are from RFC 7231 (2017-12-20)
# See also:
# https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml

my %StatusCode = (
    100 => 'Continue',
    101 => 'Switching Protocols',
    102 => 'Processing',                      # RFC 2518: WebDAV
    103 => 'Early Hints',                     # RFC 8297: Indicating Hints
#   104 .. 199
    200 => 'OK',
    201 => 'Created',
    202 => 'Accepted',
    203 => 'Non-Authoritative Information',
    204 => 'No Content',
    205 => 'Reset Content',
    206 => 'Partial Content',                 # RFC 7233: Range Requests
    207 => 'Multi-Status',                    # RFC 4918: WebDAV
    208 => 'Already Reported',                # RFC 5842: WebDAV bindings
#   209 .. 225
    226 => 'IM Used',                         # RFC 3229: Delta encoding
#   227 .. 299
    300 => 'Multiple Choices',
    301 => 'Moved Permanently',
    302 => 'Found',
    303 => 'See Other',
    304 => 'Not Modified',                    # RFC 7232: Conditional Request
    305 => 'Use Proxy',
    306 => '(Unused)',                        # RFC 9110: Previously used and reserved
    307 => 'Temporary Redirect',
    308 => 'Permanent Redirect',              # RFC 7528: Permanent Redirect
#   309 .. 399
    400 => 'Bad Request',
    401 => 'Unauthorized',                    # RFC 7235: Authentication
    402 => 'Payment Required',
    403 => 'Forbidden',
    404 => 'Not Found',
    405 => 'Method Not Allowed',
    406 => 'Not Acceptable',
    407 => 'Proxy Authentication Required',   # RFC 7235: Authentication
    408 => 'Request Timeout',
    409 => 'Conflict',
    410 => 'Gone',
    411 => 'Length Required',
    412 => 'Precondition Failed',             # RFC 7232: Conditional Request
    413 => 'Content Too Large',
    414 => 'URI Too Long',
    415 => 'Unsupported Media Type',
    416 => 'Range Not Satisfiable',           # RFC 7233: Range Requests
    417 => 'Expectation Failed',
    418 => "I'm a teapot",                    # RFC 2324: RFC9110 reserved it
#   419 .. 420
    421 => 'Misdirected Request',             # RFC 7540: HTTP/2
    422 => 'Unprocessable Content',           # RFC 9110: WebDAV
    423 => 'Locked',                          # RFC 4918: WebDAV
    424 => 'Failed Dependency',               # RFC 4918: WebDAV
    425 => 'Too Early',                       # RFC 8470: Using Early Data in HTTP
    426 => 'Upgrade Required',
#   427
    428 => 'Precondition Required',           # RFC 6585: Additional Codes
    429 => 'Too Many Requests',               # RFC 6585: Additional Codes
#   430
    431 => 'Request Header Fields Too Large', # RFC 6585: Additional Codes
#   432 .. 450
    451 => 'Unavailable For Legal Reasons',   # RFC 7725: Legal Obstacles
#   452 .. 499
    500 => 'Internal Server Error',
    501 => 'Not Implemented',
    502 => 'Bad Gateway',
    503 => 'Service Unavailable',
    504 => 'Gateway Timeout',
    505 => 'HTTP Version Not Supported',
    506 => 'Variant Also Negotiates',         # RFC 2295: Transparant Ngttn
    507 => 'Insufficient Storage',            # RFC 4918: WebDAV
    508 => 'Loop Detected',                   # RFC 5842: WebDAV bindings
#   509
    510 => 'Not Extended',                    # RFC 2774: Extension Framework
    511 => 'Network Authentication Required', # RFC 6585: Additional Codes

    # Keep some unofficial codes that used to be in this distribution
    449 => 'Retry with',                      #           microsoft
    509 => 'Bandwidth Limit Exceeded',        #           Apache / cPanel
);

my %StatusCodeName;
my $mnemonicCode = '';
my ($code, $message);
while (($code, $message) = each %StatusCode) {
    next if $message eq '(Unused)';
    # create mnemonic subroutines
    $message =~ s/I'm/I am/;
    $message =~ tr/a-z \-/A-Z__/;
    my $constant_name = "HTTP_".$message;
    $mnemonicCode .= "sub $constant_name () { $code }\n";
    $mnemonicCode .= "*RC_$message = \\&HTTP_$message;\n";  # legacy
    $mnemonicCode .= "push(\@EXPORT_OK, 'HTTP_$message');\n";
    $mnemonicCode .= "push(\@EXPORT, 'RC_$message');\n";
    $StatusCodeName{$code} = $constant_name
}
eval $mnemonicCode; # only one eval for speed
die if $@;

# backwards compatibility
*RC_MOVED_TEMPORARILY = \&RC_FOUND;  # 302 was renamed in the standard
push(@EXPORT, "RC_MOVED_TEMPORARILY");

my %compat = (
    UNPROCESSABLE_ENTITY          => \&HTTP_UNPROCESSABLE_CONTENT,
    PAYLOAD_TOO_LARGE             => \&HTTP_CONTENT_TOO_LARGE,
    REQUEST_ENTITY_TOO_LARGE      => \&HTTP_CONTENT_TOO_LARGE,
    REQUEST_URI_TOO_LARGE         => \&HTTP_URI_TOO_LONG,
    REQUEST_RANGE_NOT_SATISFIABLE => \&HTTP_RANGE_NOT_SATISFIABLE,
    NO_CODE                       => \&HTTP_TOO_EARLY,
    UNORDERED_COLLECTION          => \&HTTP_TOO_EARLY,
);

foreach my $name (keys %compat) {
    push(@EXPORT, "RC_$name");
    push(@EXPORT_OK, "HTTP_$name");
    no strict 'refs';
    *{"RC_$name"} = $compat{$name};
    *{"HTTP_$name"} = $compat{$name};
}

our %EXPORT_TAGS = (
   constants => [grep /^HTTP_/, @EXPORT_OK],
   is => [grep /^is_/, @EXPORT, @EXPORT_OK],
);


sub status_message  ($) { $StatusCode{$_[0]}; }
sub status_constant_name ($) {
    exists($StatusCodeName{$_[0]}) ? $StatusCodeName{$_[0]} : undef;
}

sub is_info                 ($) { $_[0] && $_[0] >= 100 && $_[0] < 200; }
sub is_success              ($) { $_[0] && $_[0] >= 200 && $_[0] < 300; }
sub is_redirect             ($) { $_[0] && $_[0] >= 300 && $_[0] < 400; }
sub is_error                ($) { $_[0] && $_[0] >= 400 && $_[0] < 600; }
sub is_client_error         ($) { $_[0] && $_[0] >= 400 && $_[0] < 500; }
sub is_server_error         ($) { $_[0] && $_[0] >= 500 && $_[0] < 600; }
sub is_cacheable_by_default ($) { $_[0] && ( $_[0] == 200 # OK
                                          || $_[0] == 203 # Non-Authoritative Information
                                          || $_[0] == 204 # No Content
                                          || $_[0] == 206 # Not Acceptable
                                          || $_[0] == 300 # Multiple Choices
                                          || $_[0] == 301 # Moved Permanently
                                          || $_[0] == 308 # Permanent Redirect
                                          || $_[0] == 404 # Not Found
                                          || $_[0] == 405 # Method Not Allowed
                                          || $_[0] == 410 # Gone
                                          || $_[0] == 414 # Request-URI Too Large
                                          || $_[0] == 451 # Unavailable For Legal Reasons
                                          || $_[0] == 501 # Not Implemented
                                            );
}

sub status_codes         { %StatusCode; }

1;

=pod

=encoding UTF-8

=head1 NAME

HTTP::Status - HTTP Status code processing

=head1 VERSION

version 7.00

=head1 SYNOPSIS

 use HTTP::Status qw(:constants :is status_message);

 if ($rc != HTTP_OK) {
     print status_message($rc), "\n";
 }

 if (is_success($rc)) { ... }
 if (is_error($rc)) { ... }
 if (is_redirect($rc)) { ... }

=head1 DESCRIPTION

I<HTTP::Status> is a library of routines for defining and
classifying HTTP status codes for libwww-perl.  Status codes are
used to encode the overall outcome of an HTTP response message.  Codes
correspond to those defined in RFC 2616 and RFC 2518.

=head1 CONSTANTS

The following constant functions can be used as mnemonic status code
names.  None of these are exported by default.  Use the C<:constants>
tag to import them all.

   HTTP_CONTINUE                        (100)
   HTTP_SWITCHING_PROTOCOLS             (101)
   HTTP_PROCESSING                      (102)
   HTTP_EARLY_HINTS                     (103)

   HTTP_OK                              (200)
   HTTP_CREATED                         (201)
   HTTP_ACCEPTED                        (202)
   HTTP_NON_AUTHORITATIVE_INFORMATION   (203)
   HTTP_NO_CONTENT                      (204)
   HTTP_RESET_CONTENT                   (205)
   HTTP_PARTIAL_CONTENT                 (206)
   HTTP_MULTI_STATUS                    (207)
   HTTP_ALREADY_REPORTED                (208)

   HTTP_IM_USED                         (226)

   HTTP_MULTIPLE_CHOICES                (300)
   HTTP_MOVED_PERMANENTLY               (301)
   HTTP_FOUND                           (302)
   HTTP_SEE_OTHER                       (303)
   HTTP_NOT_MODIFIED                    (304)
   HTTP_USE_PROXY                       (305)
   HTTP_TEMPORARY_REDIRECT              (307)
   HTTP_PERMANENT_REDIRECT              (308)

   HTTP_BAD_REQUEST                     (400)
   HTTP_UNAUTHORIZED                    (401)
   HTTP_PAYMENT_REQUIRED                (402)
   HTTP_FORBIDDEN                       (403)
   HTTP_NOT_FOUND                       (404)
   HTTP_METHOD_NOT_ALLOWED              (405)
   HTTP_NOT_ACCEPTABLE                  (406)
   HTTP_PROXY_AUTHENTICATION_REQUIRED   (407)
   HTTP_REQUEST_TIMEOUT                 (408)
   HTTP_CONFLICT                        (409)
   HTTP_GONE                            (410)
   HTTP_LENGTH_REQUIRED                 (411)
   HTTP_PRECONDITION_FAILED             (412)
   HTTP_CONTENT_TOO_LARGE               (413)
   HTTP_URI_TOO_LONG                    (414)
   HTTP_UNSUPPORTED_MEDIA_TYPE          (415)
   HTTP_RANGE_NOT_SATISFIABLE           (416)
   HTTP_EXPECTATION_FAILED              (417)
   HTTP_MISDIRECTED REQUEST             (421)
   HTTP_UNPROCESSABLE_CONTENT           (422)
   HTTP_LOCKED                          (423)
   HTTP_FAILED_DEPENDENCY               (424)
   HTTP_TOO_EARLY                       (425)
   HTTP_UPGRADE_REQUIRED                (426)
   HTTP_PRECONDITION_REQUIRED           (428)
   HTTP_TOO_MANY_REQUESTS               (429)
   HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE (431)
   HTTP_UNAVAILABLE_FOR_LEGAL_REASONS   (451)

   HTTP_INTERNAL_SERVER_ERROR           (500)
   HTTP_NOT_IMPLEMENTED                 (501)
   HTTP_BAD_GATEWAY                     (502)
   HTTP_SERVICE_UNAVAILABLE             (503)
   HTTP_GATEWAY_TIMEOUT                 (504)
   HTTP_HTTP_VERSION_NOT_SUPPORTED      (505)
   HTTP_VARIANT_ALSO_NEGOTIATES         (506)
   HTTP_INSUFFICIENT_STORAGE            (507)
   HTTP_LOOP_DETECTED                   (508)
   HTTP_NOT_EXTENDED                    (510)
   HTTP_NETWORK_AUTHENTICATION_REQUIRED (511)

=head1 FUNCTIONS

The following additional functions are provided.  Most of them are
exported by default.  The C<:is> import tag can be used to import all
the classification functions.

=over 4

=item status_message( $code )

The status_message() function will translate status codes to human
readable strings. The string is the same as found in the constant
names above.
For example, C<status_message(303)> will return C<"Not Found">.

If the $code is not registered in the L<list of IANA HTTP Status
Codes|https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml>
then C<undef> is returned.

=item status_constant_name( $code )

The status_constant_name() function will translate a status code
to a string which has the name of the constant for that status code.
For example, C<status_constant_name(404)> will return C<"HTTP_NOT_FOUND">.

If the C<$code> is not registered in the L<list of IANA HTTP Status
Codes|https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml>
then C<undef> is returned.

=item is_info( $code )

Return TRUE if C<$code> is an I<Informational> status code (1xx).  This
class of status code indicates a provisional response which can't have
any content.

=item is_success( $code )

Return TRUE if C<$code> is a I<Successful> status code (2xx).

=item is_redirect( $code )

Return TRUE if C<$code> is a I<Redirection> status code (3xx). This class of
status code indicates that further action needs to be taken by the
user agent in order to fulfill the request.

=item is_error( $code )

Return TRUE if C<$code> is an I<Error> status code (4xx or 5xx).  The function
returns TRUE for both client and server error status codes.

=item is_client_error( $code )

Return TRUE if C<$code> is a I<Client Error> status code (4xx). This class
of status code is intended for cases in which the client seems to have
erred.

This function is B<not> exported by default.

=item is_server_error( $code )

Return TRUE if C<$code> is a I<Server Error> status code (5xx). This class
of status codes is intended for cases in which the server is aware
that it has erred or is incapable of performing the request.

This function is B<not> exported by default.

=item is_cacheable_by_default( $code )

Return TRUE if C<$code> indicates that a response is cacheable by default, and
it can be reused by a cache with heuristic expiration. All other status codes
are not cacheable by default. See L<RFC 7231 - HTTP/1.1 Semantics and Content,
Section 6.1. Overview of Status Codes|https://tools.ietf.org/html/rfc7231#section-6.1>.

This function is B<not> exported by default.

=item status_codes

Returns a hash mapping numerical HTTP status code (e.g. 200) to text status messages (e.g. "OK")

This function is B<not> exported by default.

=back

=head1 SEE ALSO

L<IANA HTTP Status Codes|https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml>

=head1 BUGS

For legacy reasons all the C<HTTP_> constants are exported by default
with the prefix C<RC_>.  It's recommended to use explicit imports and
the C<:constants> tag instead of relying on this.

=head1 AUTHOR

Gisle Aas <gisle@activestate.com>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 1994 by Gisle Aas.

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

=cut

__END__


#ABSTRACT: HTTP Status code processing
PK5N%[�i�.	.	perl5/HTTP/Headers/Auth.pmnu��6�$package HTTP::Headers::Auth;

use strict;
use warnings;

our $VERSION = '7.00';

use HTTP::Headers;

package
    HTTP::Headers;

BEGIN {
    # we provide a new (and better) implementations below
    undef(&www_authenticate);
    undef(&proxy_authenticate);
}

require HTTP::Headers::Util;

sub _parse_authenticate
{
    my @ret;
    for (HTTP::Headers::Util::split_header_words(@_)) {
	if (!defined($_->[1])) {
	    # this is a new auth scheme
	    push(@ret, shift(@$_) => {});
	    shift @$_;
	}
	if (@ret) {
	    # this a new parameter pair for the last auth scheme
	    while (@$_) {
		my $k = shift @$_;
		my $v = shift @$_;
	        $ret[-1]{$k} = $v;
	    }
	}
	else {
	    # something wrong, parameter pair without any scheme seen
	    # IGNORE
	}
    }
    @ret;
}

sub _authenticate
{
    my $self = shift;
    my $header = shift;
    my @old = $self->_header($header);
    if (@_) {
	$self->remove_header($header);
	my @new = @_;
	while (@new) {
	    my $a_scheme = shift(@new);
	    if ($a_scheme =~ /\s/) {
		# assume complete valid value, pass it through
		$self->push_header($header, $a_scheme);
	    }
	    else {
		my @param;
		if (@new) {
		    my $p = $new[0];
		    if (ref($p) eq "ARRAY") {
			@param = @$p;
			shift(@new);
		    }
		    elsif (ref($p) eq "HASH") {
			@param = %$p;
			shift(@new);
		    }
		}
		my $val = ucfirst(lc($a_scheme));
		if (@param) {
		    my $sep = " ";
		    while (@param) {
			my $k = shift @param;
			my $v = shift @param;
			if ($v =~ /[^0-9a-zA-Z]/ || lc($k) eq "realm") {
			    # must quote the value
			    $v =~ s,([\\\"]),\\$1,g;
			    $v = qq("$v");
			}
			$val .= "$sep$k=$v";
			$sep = ", ";
		    }
		}
		$self->push_header($header, $val);
	    }
	}
    }
    return unless defined wantarray;
    wantarray ? _parse_authenticate(@old) : join(", ", @old);
}


sub www_authenticate    { shift->_authenticate("WWW-Authenticate", @_)   }
sub proxy_authenticate  { shift->_authenticate("Proxy-Authenticate", @_) }

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

HTTP::Headers::Auth

=head1 VERSION

version 7.00

=head1 AUTHOR

Gisle Aas <gisle@activestate.com>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 1994 by Gisle Aas.

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

=cut
PK5N%[��I��	�	perl5/HTTP/Headers/ETag.pmnu��6�$package HTTP::Headers::ETag;

use strict;
use warnings;

our $VERSION = '7.00';

require HTTP::Date;

require HTTP::Headers;
package
    HTTP::Headers;

sub _etags
{
    my $self = shift;
    my $header = shift;
    my @old = _split_etag_list($self->_header($header));
    if (@_) {
	$self->_header($header => join(", ", _split_etag_list(@_)));
    }
    wantarray ? @old : join(", ", @old);
}

sub etag          { shift->_etags("ETag", @_); }
sub if_match      { shift->_etags("If-Match", @_); }
sub if_none_match { shift->_etags("If-None-Match", @_); }

sub if_range {
    # Either a date or an entity-tag
    my $self = shift;
    my @old = $self->_header("If-Range");
    if (@_) {
	my $new = shift;
	if (!defined $new) {
	    $self->remove_header("If-Range");
	}
	elsif ($new =~ /^\d+$/) {
	    $self->_date_header("If-Range", $new);
	}
	else {
	    $self->_etags("If-Range", $new);
	}
    }
    return unless defined(wantarray);
    for (@old) {
	my $t = HTTP::Date::str2time($_);
	$_ = $t if $t;
    }
    wantarray ? @old : join(", ", @old);
}


# Split a list of entity tag values.  The return value is a list
# consisting of one element per entity tag.  Suitable for parsing
# headers like C<If-Match>, C<If-None-Match>.  You might even want to
# use it on C<ETag> and C<If-Range> entity tag values, because it will
# normalize them to the common form.
#
#  entity-tag	  = [ weak ] opaque-tag
#  weak		  = "W/"
#  opaque-tag	  = quoted-string


sub _split_etag_list
{
    my(@val) = @_;
    my @res;
    for (@val) {
        while (length) {
            my $weak = "";
	    $weak = "W/" if s,^\s*[wW]/,,;
            my $etag = "";
	    if (s/^\s*(\"[^\"\\]*(?:\\.[^\"\\]*)*\")//) {
		push(@res, "$weak$1");
            }
            elsif (s/^\s*,//) {
                push(@res, qq(W/"")) if $weak;
            }
            elsif (s/^\s*([^,\s]+)//) {
                $etag = $1;
		$etag =~ s/([\"\\])/\\$1/g;
	        push(@res, qq($weak"$etag"));
            }
            elsif (s/^\s+// || !length) {
                push(@res, qq(W/"")) if $weak;
            }
            else {
	 	die "This should not happen: '$_'";
            }
        }
   }
   @res;
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

HTTP::Headers::ETag

=head1 VERSION

version 7.00

=head1 AUTHOR

Gisle Aas <gisle@activestate.com>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 1994 by Gisle Aas.

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

=cut
PK5N%[�iq���perl5/HTTP/Headers/Util.pmnu��6�$package HTTP::Headers::Util;

use strict;
use warnings;

our $VERSION = '7.00';

use Exporter 5.57 'import';

our @EXPORT_OK=qw(split_header_words _split_header_words join_header_words);


sub split_header_words {
    my @res = &_split_header_words;
    for my $arr (@res) {
	for (my $i = @$arr - 2; $i >= 0; $i -= 2) {
	    $arr->[$i] = lc($arr->[$i]);
	}
    }
    return @res;
}

sub _split_header_words
{
    my(@val) = @_;
    my @res;
    for (@val) {
	my @cur;
	while (length) {
	    if (s/^\s*(=*[^\s=;,]+)//) {  # 'token' or parameter 'attribute'
		push(@cur, $1);
		# a quoted value
		if (s/^\s*=\s*\"([^\"\\]*(?:\\.[^\"\\]*)*)\"//) {
		    my $val = $1;
		    $val =~ s/\\(.)/$1/g;
		    push(@cur, $val);
		# some unquoted value
		}
		elsif (s/^\s*=\s*([^;,\s]*)//) {
		    my $val = $1;
		    $val =~ s/\s+$//;
		    push(@cur, $val);
		# no value, a lone token
		}
		else {
		    push(@cur, undef);
		}
	    }
	    elsif (s/^\s*,//) {
		push(@res, [@cur]) if @cur;
		@cur = ();
	    }
	    elsif (s/^\s*;// || s/^\s+// || s/^=//) {
		# continue
	    }
	    else {
		die "This should not happen: '$_'";
	    }
	}
	push(@res, \@cur) if @cur;
    }
    @res;
}


sub join_header_words
{
    @_ = ([@_]) if @_ && !ref($_[0]);
    my @res;
    for (@_) {
	my @cur = @$_;
	my @attr;
	while (@cur) {
	    my $k = shift @cur;
	    my $v = shift @cur;
	    if (defined $v) {
		if ($v =~ /[\x00-\x20()<>@,;:\\\"\/\[\]?={}\x7F-\xFF]/ || !length($v)) {
		    $v =~ s/([\"\\])/\\$1/g;  # escape " and \
		    $k .= qq(="$v");
		}
		else {
		    # token
		    $k .= "=$v";
		}
	    }
	    push(@attr, $k);
	}
	push(@res, join("; ", @attr)) if @attr;
    }
    join(", ", @res);
}


1;

=pod

=encoding UTF-8

=head1 NAME

HTTP::Headers::Util - Header value parsing utility functions

=head1 VERSION

version 7.00

=head1 SYNOPSIS

  use HTTP::Headers::Util qw(split_header_words);
  @values = split_header_words($h->header("Content-Type"));

=head1 DESCRIPTION

This module provides a few functions that helps parsing and
construction of valid HTTP header values.  None of the functions are
exported by default.

The following functions are available:

=over 4

=item split_header_words( @header_values )

This function will parse the header values given as argument into a
list of anonymous arrays containing key/value pairs.  The function
knows how to deal with ",", ";" and "=" as well as quoted values after
"=".  A list of space separated tokens are parsed as if they were
separated by ";".

If the @header_values passed as argument contains multiple values,
then they are treated as if they were a single value separated by
comma ",".

This means that this function is useful for parsing header fields that
follow this syntax (BNF as from the HTTP/1.1 specification, but we relax
the requirement for tokens).

  headers           = #header
  header            = (token | parameter) *( [";"] (token | parameter))

  token             = 1*<any CHAR except CTLs or separators>
  separators        = "(" | ")" | "<" | ">" | "@"
                    | "," | ";" | ":" | "\" | <">
                    | "/" | "[" | "]" | "?" | "="
                    | "{" | "}" | SP | HT

  quoted-string     = ( <"> *(qdtext | quoted-pair ) <"> )
  qdtext            = <any TEXT except <">>
  quoted-pair       = "\" CHAR

  parameter         = attribute "=" value
  attribute         = token
  value             = token | quoted-string

Each I<header> is represented by an anonymous array of key/value
pairs.  The keys will be all be forced to lower case.
The value for a simple token (not part of a parameter) is C<undef>.
Syntactically incorrect headers will not necessarily be parsed as you
would want.

This is easier to describe with some examples:

   split_header_words('foo="bar"; port="80,81"; DISCARD, BAR=baz');
   split_header_words('text/html; charset="iso-8859-1"');
   split_header_words('Basic realm="\\"foo\\\\bar\\""');

will return

   [foo=>'bar', port=>'80,81', discard=> undef], [bar=>'baz' ]
   ['text/html' => undef, charset => 'iso-8859-1']
   [basic => undef, realm => "\"foo\\bar\""]

If you don't want the function to convert tokens and attribute keys to
lower case you can call it as C<_split_header_words> instead (with a
leading underscore).

=item join_header_words( @arrays )

This will do the opposite of the conversion done by split_header_words().
It takes a list of anonymous arrays as arguments (or a list of
key/value pairs) and produces a single header value.  Attribute values
are quoted if needed.

Example:

   join_header_words(["text/plain" => undef, charset => "iso-8859/1"]);
   join_header_words("text/plain" => undef, charset => "iso-8859/1");

will both return the string:

   text/plain; charset="iso-8859/1"

=back

=head1 AUTHOR

Gisle Aas <gisle@activestate.com>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 1994 by Gisle Aas.

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

=cut

__END__


#ABSTRACT: Header value parsing utility functions

PK5N%[t8��.�.perl5/HTTP/Date.pmnu��6�$package HTTP::Date;

use strict;

our $VERSION = '6.06';

require Exporter;
our @ISA       = qw(Exporter);
our @EXPORT    = qw(time2str str2time);
our @EXPORT_OK = qw(parse_date time2iso time2isoz);

require Time::Local;

our ( @DoW, @MoY, %MoY );
@DoW       = qw(Sun Mon Tue Wed Thu Fri Sat);
@MoY       = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
@MoY{@MoY} = ( 1 .. 12 );

my %GMT_ZONE = ( GMT => 1, UTC => 1, UT => 1, Z => 1 );

sub time2str (;$) {
    my $time = shift;
    $time = time unless defined $time;
    my ( $sec, $min, $hour, $mday, $mon, $year, $wday ) = gmtime($time);
    sprintf(
        "%s, %02d %s %04d %02d:%02d:%02d GMT",
        $DoW[$wday],
        $mday, $MoY[$mon], $year + 1900,
        $hour, $min,       $sec
    );
}

sub str2time ($;$) {
    my $str = shift;
    return undef unless defined $str;

    # fast exit for strictly conforming string
    if ( $str
        =~ /^[SMTWF][a-z][a-z], (\d\d) ([JFMAJSOND][a-z][a-z]) (\d\d\d\d) (\d\d):(\d\d):(\d\d) GMT$/
    ) {
        return eval {
            my $t = Time::Local::timegm( $6, $5, $4, $1, $MoY{$2} - 1, $3 );
            $t < 0 ? undef : $t;
        };
    }

    my @d = parse_date($str);
    return undef unless @d;
    $d[1]--;    # month

    my $tz = pop(@d);
    unless ( defined $tz ) {
        unless ( defined( $tz = shift ) ) {
            return eval {
                my $frac = $d[-1];
                $frac -= ( $d[-1] = int($frac) );
                my $t = Time::Local::timelocal( reverse @d ) + $frac;
                $t < 0 ? undef : $t;
            };
        }
    }

    my $offset = 0;
    if ( $GMT_ZONE{ uc $tz } ) {

        # offset already zero
    }
    elsif ( $tz =~ /^([-+])?(\d\d?):?(\d\d)?$/ ) {
        $offset = 3600 * $2;
        $offset += 60 * $3 if $3;
        $offset *= -1      if $1 && $1 eq '-';
    }
    else {
        eval { require Time::Zone } || return undef;
        $offset = Time::Zone::tz_offset($tz);
        return undef unless defined $offset;
    }

    return eval {
        my $frac = $d[-1];
        $frac -= ( $d[-1] = int($frac) );
        my $t = Time::Local::timegm( reverse @d ) + $frac;
        $t < 0 ? undef : $t - $offset;
    };
}

sub parse_date ($) {
    local ($_) = shift;
    return unless defined;

    # More lax parsing below
    s/^\s+//;                                            # kill leading space
    s/^(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)[a-z]*,?\s*//i;    # Useless weekday

    my ( $day, $mon, $yr, $hr, $min, $sec, $tz, $ampm );

    # Then we are able to check for most of the formats with this regexp
    (
        ( $day, $mon, $yr, $hr, $min, $sec, $tz )
        = /^
     (\d\d?)               # day
        (?:\s+|[-\/])
     (\w+)                 # month
        (?:\s+|[-\/])
     (\d+)                 # year
     (?:
           (?:\s+|:)       # separator before clock
        (\d\d?):(\d\d)     # hour:min
        (?::(\d\d))?       # optional seconds
     )?                    # optional clock
        \s*
     ([-+]?\d{2,4}|(?![APap][Mm]\b)[A-Za-z]+)? # timezone
        \s*
     (?:\(\w+\)|\w{3,})?   # ASCII representation of timezone.
        \s*$
    /x
        )

        ||

        # Try the ctime and asctime format
        (
        ( $mon, $day, $hr, $min, $sec, $tz, $yr )
        = /^
     (\w{1,3})             # month
        \s+
     (\d\d?)               # day
        \s+
     (\d\d?):(\d\d)        # hour:min
     (?::(\d\d))?          # optional seconds
        \s+
     (?:([A-Za-z]+)\s+)?   # optional timezone
     (\d+)                 # year
        \s*$               # allow trailing whitespace
    /x
        )

        ||

        # Then the Unix 'ls -l' date format
        (
        ( $mon, $day, $yr, $hr, $min, $sec )
        = /^
     (\w{3})               # month
        \s+
     (\d\d?)               # day
        \s+
     (?:
        (\d\d\d\d) |       # year
        (\d{1,2}):(\d{2})  # hour:min
            (?::(\d\d))?       # optional seconds
     )
     \s*$
       /x
        )

        ||

        # ISO 8601 format '1996-02-29 12:00:00 -0100' and variants
        (
        ( $yr, $mon, $day, $hr, $min, $sec, $tz )
        = /^
      (\d{4})              # year
         [-\/]?
      (\d\d?)              # numerical month
         [-\/]?
      (\d\d?)              # day
     (?:
           (?:\s+|[-:Tt])  # separator before clock
        (\d\d?):?(\d\d)    # hour:min
        (?::?(\d\d(?:\.\d*)?))?  # optional seconds (and fractional)
     )?                    # optional clock
        \s*
     ([-+]?\d\d?:?(:?\d\d)?
      |Z|z)?               # timezone  (Z is "zero meridian", i.e. GMT)
        \s*$
    /x
        )

        ||

        # Windows 'dir': '11-12-96  03:52PM' and four-digit year variant
        (
        ( $mon, $day, $yr, $hr, $min, $ampm )
        = /^
          (\d{2})                # numerical month
             -
          (\d{2})                # day
             -
          (\d{2,4})              # year
             \s+
          (\d\d?):(\d\d)([APap][Mm])  # hour:min AM or PM
             \s*$
        /x
        )

        || return;    # unrecognized format

    # Translate month name to number
    $mon
        = $MoY{$mon}
        || $MoY{"\u\L$mon"}
        || ( $mon =~ /^\d\d?$/ && $mon >= 1 && $mon <= 12 && int($mon) )
        || return;

    # If the year is missing, we assume first date before the current,
    # because of the formats we support such dates are mostly present
    # on "ls -l" listings.
    unless ( defined $yr ) {
        my $cur_mon;
        ( $cur_mon, $yr ) = (localtime)[ 4, 5 ];
        $yr += 1900;
        $cur_mon++;
        $yr-- if $mon > $cur_mon;
    }
    elsif ( length($yr) < 3 ) {

        # Find "obvious" year
        my $cur_yr = (localtime)[5] + 1900;
        my $m      = $cur_yr % 100;
        my $tmp    = $yr;
        $yr += $cur_yr - $m;
        $m  -= $tmp;
        $yr += ( $m > 0 ) ? 100 : -100
            if abs($m) > 50;
    }

    # Make sure clock elements are defined
    $hr  = 0 unless defined($hr);
    $min = 0 unless defined($min);
    $sec = 0 unless defined($sec);

    # Compensate for AM/PM
    if ($ampm) {
        $ampm = uc $ampm;
        $hr   = 0 if $hr == 12 && $ampm eq 'AM';
        $hr += 12 if $ampm eq 'PM' && $hr != 12;
    }

    return ( $yr, $mon, $day, $hr, $min, $sec, $tz )
        if wantarray;

    if ( defined $tz ) {
        $tz = "Z" if $tz =~ /^(GMT|UTC?|[-+]?0+)$/;
    }
    else {
        $tz = "";
    }
    return sprintf(
        "%04d-%02d-%02d %02d:%02d:%02d%s",
        $yr, $mon, $day, $hr, $min, $sec, $tz
    );
}

sub time2iso (;$) {
    my $time = shift;
    $time = time unless defined $time;
    my ( $sec, $min, $hour, $mday, $mon, $year ) = localtime($time);
    sprintf(
        "%04d-%02d-%02d %02d:%02d:%02d",
        $year + 1900, $mon + 1, $mday, $hour, $min, $sec
    );
}

sub time2isoz (;$) {
    my $time = shift;
    $time = time unless defined $time;
    my ( $sec, $min, $hour, $mday, $mon, $year ) = gmtime($time);
    sprintf(
        "%04d-%02d-%02d %02d:%02d:%02dZ",
        $year + 1900, $mon + 1, $mday, $hour, $min, $sec
    );
}

1;

# ABSTRACT: HTTP::Date - date conversion routines
#

__END__

=pod

=encoding UTF-8

=head1 NAME

HTTP::Date - HTTP::Date - date conversion routines

=head1 VERSION

version 6.06

=head1 SYNOPSIS

 use HTTP::Date;

 $string = time2str($time);    # Format as GMT ASCII time
 $time = str2time($string);    # convert ASCII date to machine time

=head1 DESCRIPTION

This module provides functions that deal the date formats used by the
HTTP protocol (and then some more).  Only the first two functions,
time2str() and str2time(), are exported by default.

=over 4

=item time2str( [$time] )

The time2str() function converts a machine time (seconds since epoch)
to a string.  If the function is called without an argument or with an
undefined argument, it will use the current time.

The string returned is in the format preferred for the HTTP protocol.
This is a fixed length subset of the format defined by RFC 1123,
represented in Universal Time (GMT).  An example of a time stamp
in this format is:

   Sun, 06 Nov 1994 08:49:37 GMT

=item str2time( $str [, $zone] )

The str2time() function converts a string to machine time.  It returns
C<undef> if the format of $str is unrecognized, otherwise whatever the
C<Time::Local> functions can make out of the parsed time.  Dates
before the system's epoch may not work on all operating systems.  The
time formats recognized are the same as for parse_date().

The function also takes an optional second argument that specifies the
default time zone to use when converting the date.  This parameter is
ignored if the zone is found in the date string itself.  If this
parameter is missing, and the date string format does not contain any
zone specification, then the local time zone is assumed.

If the zone is not "C<GMT>" or numerical (like "C<-0800>" or
"C<+0100>"), then the C<Time::Zone> module must be installed in order
to get the date recognized.

=item parse_date( $str )

This function will try to parse a date string, and then return it as a
list of numerical values followed by a (possible undefined) time zone
specifier; ($year, $month, $day, $hour, $min, $sec, $tz).  The $year
will be the full 4-digit year, and $month numbers start with 1 (for January).

In scalar context the numbers are interpolated in a string of the
"YYYY-MM-DD hh:mm:ss TZ"-format and returned.

If the date is unrecognized, then the empty list is returned (C<undef> in
scalar context).

The function is able to parse the following formats:

 "Wed, 09 Feb 1994 22:23:32 GMT"       -- HTTP format
 "Thu Feb  3 17:03:55 GMT 1994"        -- ctime(3) format
 "Thu Feb  3 00:00:00 1994",           -- ANSI C asctime() format
 "Tuesday, 08-Feb-94 14:15:29 GMT"     -- old rfc850 HTTP format
 "Tuesday, 08-Feb-1994 14:15:29 GMT"   -- broken rfc850 HTTP format

 "03/Feb/1994:17:03:55 -0700"   -- common logfile format
 "09 Feb 1994 22:23:32 GMT"     -- HTTP format (no weekday)
 "08-Feb-94 14:15:29 GMT"       -- rfc850 format (no weekday)
 "08-Feb-1994 14:15:29 GMT"     -- broken rfc850 format (no weekday)

 "1994-02-03 14:15:29 -0100"    -- ISO 8601 format
 "1994-02-03 14:15:29"          -- zone is optional
 "1994-02-03"                   -- only date
 "1994-02-03T14:15:29"          -- Use T as separator
 "19940203T141529Z"             -- ISO 8601 compact format
 "19940203"                     -- only date

 "08-Feb-94"         -- old rfc850 HTTP format    (no weekday, no time)
 "08-Feb-1994"       -- broken rfc850 HTTP format (no weekday, no time)
 "09 Feb 1994"       -- proposed new HTTP format  (no weekday, no time)
 "03/Feb/1994"       -- common logfile format     (no time, no offset)

 "Feb  3  1994"      -- Unix 'ls -l' format
 "Feb  3 17:03"      -- Unix 'ls -l' format

 "11-15-96  03:52PM"   -- Windows 'dir' format
 "11-15-1996  03:52PM" -- Windows 'dir' format with four-digit year

The parser ignores leading and trailing whitespace.  It also allow the
seconds to be missing and the month to be numerical in most formats.

If the year is missing, then we assume that the date is the first
matching date I<before> current month.  If the year is given with only
2 digits, then parse_date() will select the century that makes the
year closest to the current date.

=item time2iso( [$time] )

Same as time2str(), but returns a "YYYY-MM-DD hh:mm:ss"-formatted
string representing time in the local time zone.

=item time2isoz( [$time] )

Same as time2str(), but returns a "YYYY-MM-DD hh:mm:ssZ"-formatted
string representing Universal Time.

=back

=head1 SEE ALSO

L<perlfunc/time>, L<Time::Zone>

=head1 AUTHOR

Gisle Aas <gisle@activestate.com>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 1995 by Gisle Aas.

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

=cut
PK5N%[����~�~perl5/AppConfig.pmnu��6�$#============================================================================
#
# AppConfig.pm
#
# Perl5 module for reading and parsing configuration files and command line 
# arguments.
#
# Written by Andy Wardley <abw@wardley.org>
#
# Copyright (C) 1997-2007 Andy Wardley.  All Rights Reserved.
# Copyright (C) 1997,1998 Canon Research Centre Europe Ltd.
#==========================================================================

package AppConfig;

use 5.006;
use strict;
use warnings;
use base 'Exporter';
our $VERSION = '1.71';

# variable expansion constants
use constant EXPAND_NONE   => 0;
use constant EXPAND_VAR    => 1;
use constant EXPAND_UID    => 2;
use constant EXPAND_ENV    => 4;
use constant EXPAND_ALL    => EXPAND_VAR | EXPAND_UID | EXPAND_ENV;
use constant EXPAND_WARN   => 8;

# argument count types
use constant ARGCOUNT_NONE => 0;
use constant ARGCOUNT_ONE  => 1;
use constant ARGCOUNT_LIST => 2;
use constant ARGCOUNT_HASH => 3;

# Exporter tagsets
our @EXPAND = qw(
    EXPAND_NONE
    EXPAND_VAR
    EXPAND_UID
    EXPAND_ENV 
    EXPAND_ALL
    EXPAND_WARN
);

our @ARGCOUNT = qw(
    ARGCOUNT_NONE
    ARGCOUNT_ONE
    ARGCOUNT_LIST
    ARGCOUNT_HASH
);

our @EXPORT_OK   = ( @EXPAND, @ARGCOUNT );
our %EXPORT_TAGS = (
    expand   => [ @EXPAND   ],
    argcount => [ @ARGCOUNT ],
);
our $AUTOLOAD;

require AppConfig::State;

#------------------------------------------------------------------------
# new(\%config, @vars)
#
# Module constructor.  All parameters passed are forwarded onto the 
# AppConfig::State constructor.  Returns a reference to a newly created 
# AppConfig object.
#------------------------------------------------------------------------

sub new {
    my $class = shift;
    bless {
        STATE => AppConfig::State->new(@_)
    }, $class;
}


#------------------------------------------------------------------------
# file(@files)
#
# The file() method is called to parse configuration files.  An 
# AppConfig::File object is instantiated and stored internally for
# use in subsequent calls to file().
#------------------------------------------------------------------------

sub file {
    my $self  = shift;
    my $state = $self->{ STATE };
    my $file;

    require AppConfig::File;

    # create an AppConfig::File object if one isn't defined 
    $file = $self->{ FILE } ||= AppConfig::File->new($state);

    # call on the AppConfig::File object to process files.
    $file->parse(@_);
}


#------------------------------------------------------------------------
# args(\@args)
#
# The args() method is called to parse command line arguments.  An 
# AppConfig::Args object is instantiated and then stored internally for
# use in subsequent calls to args().
#------------------------------------------------------------------------

sub args {
    my $self  = shift;
    my $state = $self->{ STATE };
    my $args;

    require AppConfig::Args;

    # create an AppConfig::Args object if one isn't defined
    $args = $self->{ ARGS } ||= AppConfig::Args->new($state);

    # call on the AppConfig::Args object to process arguments.
    $args->parse(shift);
}


#------------------------------------------------------------------------
# getopt(@config, \@args)
#
# The getopt() method is called to parse command line arguments.  The
# AppConfig::Getopt module is require()'d and an AppConfig::Getopt object
# is created to parse the arguments.
#------------------------------------------------------------------------

sub getopt {
    my $self  = shift;
    my $state = $self->{ STATE };
    my $getopt;

    require AppConfig::Getopt;

    # create an AppConfig::Getopt object if one isn't defined
    $getopt = $self->{ GETOPT } ||= AppConfig::Getopt->new($state);

    # call on the AppConfig::Getopt object to process arguments.
    $getopt->parse(@_);
}


#------------------------------------------------------------------------
# cgi($query)
#
# The cgi() method is called to parse a CGI query string.  An 
# AppConfig::CGI object is instantiated and then stored internally for
# use in subsequent calls to args().
#------------------------------------------------------------------------

sub cgi {
    my $self  = shift;
    my $state = $self->{ STATE };
    my $cgi;

    require AppConfig::CGI;

    # create an AppConfig::CGI object if one isn't defined
    $cgi = $self->{ CGI } ||= AppConfig::CGI->new($state);

    # call on the AppConfig::CGI object to process a query.
    $cgi->parse(shift);
}

#------------------------------------------------------------------------
# AUTOLOAD
#
# Autoload function called whenever an unresolved object method is 
# called.  All methods are delegated to the $self->{ STATE } 
# AppConfig::State object.
#
#------------------------------------------------------------------------

sub AUTOLOAD {
    my $self = shift;
    my $method;

    # splat the leading package name
    ($method = $AUTOLOAD) =~ s/.*:://;

    # ignore destructor
    $method eq 'DESTROY' && return;

    # delegate method call to AppConfig::State object in $self->{ STATE } 
    $self->{ STATE }->$method(@_);
}

1;

__END__

=head1 NAME

AppConfig - Perl5 module for reading configuration files and parsing command line arguments.

=head1 SYNOPSIS

    use AppConfig;

    # create a new AppConfig object
    my $config = AppConfig->new( \%cfg );

    # define a new variable
    $config->define( $varname => \%varopts );

    # create/define combined
    my $config = AppConfig->new( \%cfg, 
        $varname => \%varopts,
        $varname => \%varopts,
        ...
    );

    # set/get the value
    $config->set( $varname, $value );
    $config->get($varname);

    # shortcut form
    $config->varname($value);
    $config->varname;

    # read configuration file
    $config->file($file);

    # parse command line options
    $config->args(\@args);      # default to \@ARGV

    # advanced command line options with Getopt::Long
    $config->getopt(\@args);    # default to \@ARGV

    # parse CGI parameters (GET method)
    $config->cgi($query);       # default to $ENV{ QUERY_STRING }

=head1 OVERVIEW

AppConfig is a Perl5 module for managing application configuration 
information.  It maintains the state of any number of variables and 
provides methods for parsing configuration files, command line 
arguments and CGI script parameters.

Variables values may be set via configuration files.  Variables may be 
flags (On/Off), take a single value, or take multiple values stored as a
list or hash.  The number of arguments a variable expects is determined
by its configuration when defined.

    # flags
    verbose 
    nohelp
    debug = On

    # single value
    home  = /home/abw/

    # multiple list value
    file = /tmp/file1
    file = /tmp/file2

    # multiple hash value
    book  camel = Programming Perl
    book  llama = Learning Perl

The '-' prefix can be used to reset a variable to its default value and
the '+' prefix can be used to set it to 1

    -verbose
    +debug

Variable, environment variable and tilde (home directory) expansions
can be applied (selectively, if necessary) to the values read from 
configuration files:

    home = ~                    # home directory
    nntp = ${NNTPSERVER}        # environment variable
    html = $home/html           # internal variables
    img  = $html/images

Configuration files may be arranged in blocks as per the style of Win32 
"INI" files.

    [file]
    site = kfs
    src  = ~/websrc/docs/$site
    lib  = ~/websrc/lib
    dest = ~/public_html/$site

    [page]
    header = $lib/header
    footer = $lib/footer

You can also use Perl's "heredoc" syntax to define a large block of
text in a configuration file.

    multiline = <<FOOBAR
    line 1
    line 2
    FOOBAR

    paths  exe  = "${PATH}:${HOME}/.bin"
    paths  link = <<'FOO'
    ${LD_LIBARRAY_PATH}:${HOME}/lib
    FOO

Variables may also be set by parsing command line arguments.

    myapp -verbose -site kfs -file f1 -file f2

AppConfig provides a simple method (args()) for parsing command line 
arguments.  A second method (getopt()) allows more complex argument 
processing by delegation to Johan Vroman's Getopt::Long module.

AppConfig also allows variables to be set by parameters passed to a 
CGI script via the URL (GET method).

    http://www.nowhere.com/cgi-bin/myapp?verbose&site=kfs

=head1 PREREQUISITES

AppConfig requires Perl 5.005 or later.  

The L<Getopt::Long> and L<Test::More> modules should be installed.
If you are using a recent version of Perl (e.g. 5.8.0) then these
should already be installed.

=head1 OBTAINING AND INSTALLING THE AppConfig MODULE BUNDLE

The AppConfig module bundle is available from CPAN.  As the 'perlmod' 
manual page explains:

    CPAN stands for the Comprehensive Perl Archive Network.
    This is a globally replicated collection of all known Perl
    materials, including hundreds of unbundled modules.  

    [...]

    For an up-to-date listing of CPAN sites, see
    http://www.perl.com/perl/ or ftp://ftp.perl.com/perl/ .

Within the CPAN archive, AppConfig is in the category:

    12) Option, Argument, Parameter and Configuration File Processing

The module is available in the following directories:

    /modules/by-module/AppConfig/AppConfig-<version>.tar.gz
    /authors/id/ABW/AppConfig-<version>.tar.gz

AppConfig is distributed as a single gzipped tar archive file:

    AppConfig-<version>.tar.gz

Note that "<version>" represents the current AppConfig version
number, of the form "n.nn", e.g. "3.14".  See the REVISION section
below to determine the current version number for AppConfig.

Unpack the archive to create a AppConfig installation directory:

    gunzip AppConfig-<version>.tar.gz
    tar xvf AppConfig-<version>.tar

'cd' into that directory, make, test and install the modules:

    cd AppConfig-<version>
    perl Makefile.PL
    make
    make test
    make install

The 't' sub-directory contains a number of test scripts that are run when 
a 'make test' is run.

The 'make install' will install the module on your system.  You may need 
administrator privileges to perform this task.  If you install the module 
in a local directory (for example, by executing "perl Makefile.PL
LIB=~/lib" in the above - see C<perldoc MakeMaker> for full details), you
will need to ensure that the PERL5LIB environment variable is set to
include the location, or add a line to your scripts explicitly naming the
library location:

    use lib '/local/path/to/lib';

The 'examples' sub-directory contains some simple examples of using the 
AppConfig modules.

=head1 DESCRIPTION

=head2 USING THE AppConfig MODULE

To import and use the L<AppConfig> module the following line should 
appear in your Perl script:

     use AppConfig;

To import constants defined by the AppConfig module, specify the name of
one or more of the constant or tag sets as parameters to C<use>:

    use AppConfig qw(:expand :argcount);

See L<CONSTANT DEFINITIONS> below for more information on the constant
tagsets defined by AppConfig.

AppConfig is implemented using object-oriented methods.  A 
new AppConfig object is created and initialized using the 
new() method.  This returns a reference to a new AppConfig 
object.

    my $config = AppConfig->new();

This will create and return a reference to a new AppConfig object.

In doing so, the AppConfig object also creates an internal reference
to an AppConfig::State object in which to store variable state.  All 
arguments passed into the AppConfig constructor are passed directly
to the AppConfig::State constructor.  

The first (optional) parameter may be a reference to a hash array
containing configuration information.  

    my $config = AppConfig->new( {
            CASE   => 1,
            ERROR  => \&my_error,
            GLOBAL => { 
                    DEFAULT  => "<unset>", 
                    ARGCOUNT => ARGCOUNT_ONE,
                },
        } );

See L<AppConfig::State> for full details of the configuration options
available.  These are, in brief:

=over 4

=item CASE

Used to set case sensitivity for variable names (default: off).

=item CREATE

Used to indicate that undefined variables should be created automatically
(default: off).

=item GLOBAL 

Reference to a hash array of global values used by default when defining 
variables.  Valid global values are DEFAULT, ARGCOUNT, EXPAND, VALIDATE
and ACTION.

=item PEDANTIC

Used to indicate that command line and configuration file parsing routines
should return immediately on encountering an error.

=item ERROR

Used to provide a error handling routine.  Arguments as per printf().

=back

Subsequent parameters may be variable definitions.  These are passed 
to the define() method, described below in L<DEFINING VARIABLES>.

    my $config = AppConfig->new("foo", "bar", "baz");
    my $config = AppConfig->new( { CASE => 1 }, qw(foo bar baz) );

Note that any unresolved method calls to AppConfig are automatically 
delegated to the AppConfig::State object.  In practice, it means that
it is possible to treat the AppConfig object as if it were an 
AppConfig::State object:

    # create AppConfig
    my $config = AppConfig->new('foo', 'bar');

    # methods get passed through to internal AppConfig::State
    $config->foo(100);
    $config->set('bar', 200);
    $config->define('baz');
    $config->baz(300);

=head2 DEFINING VARIABLES

The C<define()> method (delegated to AppConfig::State) is used to 
pre-declare a variable and specify its configuration.

    $config->define("foo");

Variables may also be defined directly from the AppConfig new()
constructor.

    my $config = AppConfig->new("foo");

In both simple examples above, a new variable called "foo" is defined.  A 
reference to a hash array may also be passed to specify configuration 
information for the variable:

    $config->define("foo", {
            DEFAULT   => 99,
            ALIAS     => 'metavar1',
        });

Configuration items specified in the GLOBAL option to the module 
constructor are applied by default when variables are created.  e.g.

    my $config = AppConfig->new( { 
        GLOBAL => {
            DEFAULT  => "<undef>",
            ARGCOUNT => ARGCOUNT_ONE,
        }
    } );

    $config->define("foo");
    $config->define("bar", { ARGCOUNT => ARGCOUNT_NONE } );

is equivalent to:

    my $config = AppConfig->new();

    $config->define( "foo", {
        DEFAULT  => "<undef>",
        ARGCOUNT => ARGCOUNT_ONE,
    } );

    $config->define( "bar", 
        DEFAULT  => "<undef>",
        ARGCOUNT => ARGCOUNT_NONE,
    } );

Multiple variables may be defined in the same call to define().
Configuration hashes for variables can be omitted.

    $config->define("foo", "bar" => { ALIAS = "boozer" }, "baz");

See L<AppConfig::State> for full details of the configuration options
available when defining variables.  These are, in brief:

=over 

=item DEFAULT

The default value for the variable (default: undef).

=item ALIAS

One or more (list reference or "list|like|this") alternative names for the
variable.

=item ARGCOUNT

Specifies the number and type of arguments that the variable expects.
Constants in C<:expand> tag set define ARGCOUNT_NONE - simple on/off flag
(default), ARGCOUNT_ONE - single value, ARGCOUNT_LIST - multiple values
accessed via list reference, ARGCOUNT_HASH - hash table, "key=value",
accessed via hash reference.

=item ARGS 

Used to provide an argument specification string to pass to Getopt::Long 
via AppConfig::Getopt.  E.g. "=i", ":s", "=s@".  This can also be used to 
implicitly set the ARGCOUNT value (C</^!/> = ARGCOUNT_NONE, C</@/> = 
ARGCOUNT_LIST, C</%/> = ARGCOUNT_HASH, C</[=:].*/> = ARGCOUNT_ONE)

=item EXPAND

Specifies which variable expansion policies should be used when parsing 
configuration files.  Constants in C<:expand> tag set define:

    EXPAND_NONE - no expansion (default) 
    EXPAND_VAR  - expand C<$var> or C<$(var)> as other variables
    EXPAND_UID  - expand C<~> and C<~uid> as user's home directory 
    EXPAND_ENV - expand C<${var}> as environment variable
    EXPAND_ALL - do all expansions. 

=item VALIDATE

Regex which the intended variable value should match or code reference 
which returns 1 to indicate successful validation (variable may now be set).

=item ACTION

Code reference to be called whenever variable value changes.

=back

=head2 COMPACT FORMAT DEFINITION

Variables can be specified using a compact format.  This is identical to 
the specification format of Getopt::Long and is of the form:

    "name|alias|alias<argopts>"

The first element indicates the variable name and subsequent ALIAS 
values may be added, each separated by a vertical bar '|'.

The E<lt>argoptsE<gt> element indicates the ARGCOUNT value and may be one of 
the following;

    !                  ARGCOUNT_NONE
    =s                 ARGCOUNT_ONE
    =s@                ARGCOUNT_LIST
    =s%                ARGCOUNT_HASH

Additional constructs supported by Getopt::Long may be specified instead
of the "=s" element (e.g. "=f").  The entire E<lt>argoptsE<gt> element 
is stored in the ARGS parameter for the variable and is passed intact to 
Getopt::Long when the getopt() method is called.  

The following examples demonstrate use of the compact format, with their
equivalent full specifications:

    $config->define("foo|bar|baz!");

    $config->define(
            "foo" => { 
                ALIAS    => "bar|baz", 
                ARGCOUNT => ARGCOUNT_NONE,
            });

    $config->define("name=s");

    $config->define(
            "name" => { 
                ARGCOUNT => ARGCOUNT_ONE,
            });

    $config->define("file|filelist|f=s@");

    $config->define(
            "file" => { 
                ALIAS    => "filelist|f", 
                ARGCOUNT => ARGCOUNT_LIST,
            });

    $config->define("user|u=s%");

    $config->define(
            "user" => { 
                ALIAS    => "u", 
                ARGCOUNT => ARGCOUNT_HASH,
            });

Additional configuration options may be specified by hash reference, as per 
normal.  The compact definition format will override any configuration 
values provided for ARGS and ARGCOUNT.

    $config->define("file|filelist|f=s@", { VALIDATE => \&check_file } );

=head2 READING AND MODIFYING VARIABLE VALUES

AppConfig defines two methods (via AppConfig::State) to manipulate variable 
values

    set($variable, $value);
    get($variable);

Once defined, variables may be accessed directly as object methods where
the method name is the same as the variable name.  i.e.

    $config->set("verbose", 1);

is equivalent to 

    $config->verbose(1); 

Note that AppConfig defines the following methods:

    new();
    file();
    args();
    getopt();

And also, through delegation to AppConfig::State:

    define()
    get()
    set()
    varlist()

If you define a variable with one of the above names, you will not be able
to access it directly as an object method.  i.e.

    $config->file();

This will call the file() method, instead of returning the value of the 
'file' variable.  You can work around this by explicitly calling get() and 
set() on a variable whose name conflicts:

    $config->get('file');

or by defining a "safe" alias by which the variable can be accessed:

    $config->define("file", { ALIAS => "fileopt" });
or
    $config->define("file|fileopt");

    ...
    $config->fileopt();

Without parameters, the current value of the variable is returned.  If
a parameter is specified, the variable is set to that value and the 
result of the set() operation is returned.

    $config->age(29);        # sets 'age' to 29, returns 1 (ok)
    print $config->age();    # prints "29"

The varlist() method can be used to extract a number of variables into
a hash array.  The first parameter should be a regular expression 
used for matching against the variable names. 

    my %vars = $config->varlist("^file");   # all "file*" variables

A second parameter may be specified (any true value) to indicate that 
the part of the variable name matching the regex should be removed 
when copied to the target hash.

    $config->file_name("/tmp/file");
    $config->file_path("/foo:/bar:/baz");

    my %vars = $config->varlist("^file_", 1);

    # %vars:
    #    name => /tmp/file
    #    path => "/foo:/bar:/baz"


=head2 READING CONFIGURATION FILES

The AppConfig module provides a streamlined interface for reading 
configuration files with the AppConfig::File module.  The file() method
automatically loads the AppConfig::File module and creates an object 
to process the configuration file or files.  Variables stored in the 
internal AppConfig::State are automatically updated with values specified 
in the configuration file.  

    $config->file($filename);

Multiple files may be passed to file() and should indicate the file name 
or be a reference to an open file handle or glob.

    $config->file($filename, $filehandle, \*STDIN, ...);

The file may contain blank lines and comments (prefixed by '#') which 
are ignored.  Continutation lines may be marked by ending the line with 
a '\'.

    # this is a comment
    callsign = alpha bravo camel delta echo foxtrot golf hipowls \
               india juliet kilo llama mike november oscar papa  \
               quebec romeo sierra tango umbrella victor whiskey \
               x-ray yankee zebra

Variables that are simple flags and do not expect an argument (ARGCOUNT = 
ARGCOUNT_NONE) can be specified without any value.  They will be set with 
the value 1, with any value explicitly specified (except "0" and "off")
being ignored.  The variable may also be specified with a "no" prefix to 
implicitly set the variable to 0.

    verbose                              # on  (1)
    verbose = 1                          # on  (1)
    verbose = 0                          # off (0)
    verbose off                          # off (0)
    verbose on                           # on  (1)
    verbose mumble                       # on  (1)
    noverbose                            # off (0)

Variables that expect an argument (ARGCOUNT = ARGCOUNT_ONE) will be set to 
whatever follows the variable name, up to the end of the current line 
(including any continuation lines).  An optional equals sign may be inserted 
between the variable and value for clarity.

    room = /home/kitchen     
    room   /home/bedroom

Each subsequent re-definition of the variable value overwrites the previous
value.

    print $config->room();               # prints "/home/bedroom"

Variables may be defined to accept multiple values (ARGCOUNT = ARGCOUNT_LIST).
Each subsequent definition of the variable adds the value to the list of
previously set values for the variable.  

    drink = coffee
    drink = tea

A reference to a list of values is returned when the variable is requested.

    my $beverages = $config->drink();
    print join(", ", @$beverages);      # prints "coffee, tea"

Variables may also be defined as hash lists (ARGCOUNT = ARGCOUNT_HASH).
Each subsequent definition creates a new key and value in the hash array.

    alias l="ls -CF"
    alias e="emacs"

A reference to the hash is returned when the variable is requested.

    my $aliases = $config->alias();
    foreach my $k (keys %$aliases) {
        print "$k => $aliases->{ $k }\n";
    }

The '-' prefix can be used to reset a variable to its default value and
the '+' prefix can be used to set it to 1

    -verbose
    +debug

=head2 VARIABLE EXPANSION

Variable values may contain references to other AppConfig variables, 
environment variables and/or users' home directories.  These will be 
expanded depending on the EXPAND value for each variable or the GLOBAL
EXPAND value.

Three different expansion types may be applied:

    bin = ~/bin          # expand '~' to home dir if EXPAND_UID
    tmp = ~abw/tmp       # as above, but home dir for user 'abw'

    perl = $bin/perl     # expand value of 'bin' variable if EXPAND_VAR
    ripl = $(bin)/ripl   # as above with explicit parens

    home = ${HOME}       # expand HOME environment var if EXPAND_ENV

See L<AppConfig::State> for more information on expanding variable values.

The configuration files may have variables arranged in blocks.  A block 
header, consisting of the block name in square brackets, introduces a 
configuration block.  The block name and an underscore are then prefixed 
to the names of all variables subsequently referenced in that block.  The 
block continues until the next block definition or to the end of the current 
file.

    [block1]
    foo = 10             # block1_foo = 10

    [block2]
    foo = 20             # block2_foo = 20

=head2 PARSING COMMAND LINE OPTIONS

There are two methods for processing command line options.  The first, 
args(), is a small and efficient implementation which offers basic 
functionality.  The second, getopt(), offers a more powerful and complete
facility by delegating the task to Johan Vroman's Getopt::Long module.  
The trade-off between args() and getopt() is essentially one of speed/size
against flexibility.  Use as appropriate.  Both implement on-demand loading 
of modules and incur no overhead until used.  

The args() method is used to parse simple command line options.  It
automatically loads the AppConfig::Args module and creates an object 
to process the command line arguments.  Variables stored in the internal
AppConfig::State are automatically updated with values specified in the 
arguments.  

The method should be passed a reference to a list of arguments to parse.
The @ARGV array is used if args() is called without parameters.

    $config->args(\@myargs);
    $config->args();               # uses @ARGV

Arguments are read and shifted from the array until the first is
encountered that is not prefixed by '-' or '--'.  At that point, the
method returns 1 to indicate success, leaving any unprocessed arguments
remaining in the list.

Each argument should be the name or alias of a variable prefixed by 
'-' or '--'.  Arguments that are not prefixed as such (and are not an
additional parameter to a previous argument) will cause a warning to be
raised.  If the PEDANTIC option is set, the method will return 0 
immediately.  With PEDANTIC unset (default), the method will continue
to parse the rest of the arguments, returning 0 when done.

If the variable is a simple flag (ARGCOUNT = ARGCOUNT_NONE)
then it is set to the value 1.  The variable may be prefixed by "no" to
set its value to 0.

    myprog -verbose --debug -notaste     # $config->verbose(1)
                                         # $config->debug(1)
                                         # $config->taste(0)

Variables that expect an additional argument (ARGCOUNT != 0) will be set to 
the value of the argument following it.  

    myprog -f /tmp/myfile                # $config->file('/tmp/file');

Variables that expect multiple values (ARGCOUNT = ARGCOUNT_LIST or
ARGCOUNT_HASH) will have successive values added each time the option
is encountered.

    myprog -file /tmp/foo -file /tmp/bar # $config->file('/tmp/foo')
                                         # $config->file('/tmp/bar')

    # file => [ '/tmp/foo', '/tmp/bar' ]

    myprog -door "jim=Jim Morrison" -door "ray=Ray Manzarek"
                                    # $config->door("jim=Jim Morrison");
                                    # $config->door("ray=Ray Manzarek");

    # door => { 'jim' => 'Jim Morrison', 'ray' => 'Ray Manzarek' }

See L<AppConfig::Args> for further details on parsing command line
arguments.

The getopt() method provides a way to use the power and flexibility of
the Getopt::Long module to parse command line arguments and have the 
internal values of the AppConfig object updates automatically.

The first (non-list reference) parameters may contain a number of 
configuration string to pass to Getopt::Long::Configure.  A reference 
to a list of arguments may additionally be passed or @ARGV is used by 
default.

    $config->getopt();                       # uses @ARGV
    $config->getopt(\@myargs);
    $config->getopt(qw(auto_abbrev debug));  # uses @ARGV
    $config->getopt(qw(debug), \@myargs);

See Getopt::Long for details of the configuration options available.

The getopt() method constructs a specification string for each internal
variable and then initializes Getopt::Long with these values.  The
specification string is constructed from the name, any aliases (delimited
by a vertical bar '|') and the value of the ARGS parameter.

    $config->define("foo", {
        ARGS  => "=i",
        ALIAS => "bar|baz",
    });

    # Getopt::Long specification: "foo|bar|baz=i"

Errors and warning generated by the Getopt::Long module are trapped and 
handled by the AppConfig error handler.  This may be a user-defined 
routine installed with the ERROR configuration option.

Please note that the AppConfig::Getopt interface is still experimental
and may not be 100% operational.  This is almost undoubtedly due to 
problems in AppConfig::Getopt rather than Getopt::Long.

=head2 PARSING CGI PARAMETERS

The cgi() method provides an interface to the AppConfig::CGI module
for updating variable values based on the parameters appended to the
URL for a CGI script.  This is commonly known as the CGI 
"GET" method.  The CGI "POST" method is currently not supported.

Parameter definitions are separated from the CGI script name by a 
question mark and from each other by ampersands.  Where variables
have specific values, these are appended to the variable with an 
equals sign:

    http://www.here.com/cgi-bin/myscript?foo=bar&baz=qux&verbose

        # $config->foo('bar');
        # $config->baz('qux');
        # $config->verbose(1);

Certain values specified in a URL must be escaped in the appropriate 
manner (see CGI specifications at http://www.w3c.org/ for full details).  
The AppConfig::CGI module automatically unescapes the CGI query string
to restore the parameters to their intended values.

    http://where.com/mycgi?title=%22The+Wrong+Trousers%22

    # $config->title('"The Wrong Trousers"');

Please be considerate of the security implications of providing writable
access to script variables via CGI.

    http://rebel.alliance.com/cgi-bin/...
        .../send_report?file=%2Fetc%2Fpasswd&email=darth%40empire.com

To avoid any accidental or malicious changing of "private" variables, 
define only the "public" variables before calling the cgi() (or any 
other) method.  Further variables can subsequently be defined which 
can not be influenced by the CGI parameters.

    $config->define('verbose', 'debug')
    $config->cgi();             # can only set verbose and debug

    $config->define('email', 'file');
    $config->file($cfgfile);    # can set verbose, debug, email + file


=head1 CONSTANT DEFINITIONS

A number of constants are defined by the AppConfig module.  These may be
accessed directly (e.g. AppConfig::EXPAND_VARS) or by first importing them
into the caller's package.  Constants are imported by specifying their 
names as arguments to C<use AppConfig> or by importing a set of constants
identified by its "tag set" name.

    use AppConfig qw(ARGCOUNT_NONE ARGCOUNT_ONE);

    use AppConfig qw(:argcount);

The following tag sets are defined:

=over 4

=item :expand

The ':expand' tagset defines the following constants:

    EXPAND_NONE
    EXPAND_VAR
    EXPAND_UID 
    EXPAND_ENV
    EXPAND_ALL       # EXPAND_VAR | EXPAND_UID | EXPAND_ENV
    EXPAND_WARN

See AppConfig::File for full details of the use of these constants.

=item :argcount

The ':argcount' tagset defines the following constants:

    ARGCOUNT_NONE
    ARGCOUNT_ONE
    ARGCOUNT_LIST 
    ARGCOUNT_HASH

See AppConfig::State for full details of the use of these constants.

=back

=head1 REPOSITORY

L<https://github.com/neilbowers/AppConfig>

=head1 AUTHOR

Andy Wardley, E<lt>abw@wardley.orgE<gt>

With contributions from Dave Viner, Ijon Tichy, Axel Gerstmair and
many others whose names have been lost to the sands of time (reminders
welcome).

=head1 COPYRIGHT

Copyright (C) 1997-2007 Andy Wardley.  All Rights Reserved.

Copyright (C) 1997,1998 Canon Research Centre Europe Ltd.

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

=head1 SEE ALSO

L<AppConfig::State>, L<AppConfig::File>, L<AppConfig::Args>, L<AppConfig::Getopt>,
L<AppConfig::CGI>, L<Getopt::Long>

=cut
PK5N%[Y�8��R�Rperl5/Try/Tiny.pmnu��6�$package Try::Tiny; # git description: v0.31-2-gc8e3a47
use 5.006;
# ABSTRACT: Minimal try/catch with proper preservation of $@

our $VERSION = '0.32';

use strict;
use warnings;

use Exporter 5.57 'import';
our @EXPORT = our @EXPORT_OK = qw(try catch finally);

use Carp;
$Carp::Internal{+__PACKAGE__}++;

BEGIN {
  my $su = $INC{'Sub/Util.pm'} && defined &Sub::Util::set_subname;
  my $sn = $INC{'Sub/Name.pm'} && eval { Sub::Name->VERSION(0.08) };
  unless ($su || $sn) {
    $su = eval { require Sub::Util; } && defined &Sub::Util::set_subname;
    unless ($su) {
      $sn = eval { require Sub::Name; Sub::Name->VERSION(0.08) };
    }
  }

  *_subname = $su ? \&Sub::Util::set_subname
            : $sn ? \&Sub::Name::subname
            : sub { $_[1] };
  *_HAS_SUBNAME = ($su || $sn) ? sub(){1} : sub(){0};
}

my %_finally_guards;

# Need to prototype as @ not $$ because of the way Perl evaluates the prototype.
# Keeping it at $$ means you only ever get 1 sub because we need to eval in a list
# context & not a scalar one

sub try (&;@) {
  my ( $try, @code_refs ) = @_;

  # we need to save this here, the eval block will be in scalar context due
  # to $failed
  my $wantarray = wantarray;

  # work around perl bug by explicitly initializing these, due to the likelyhood
  # this will be used in global destruction (perl rt#119311)
  my ( $catch, @finally ) = ();

  # find labeled blocks in the argument list.
  # catch and finally tag the blocks by blessing a scalar reference to them.
  foreach my $code_ref (@code_refs) {

    if ( ref($code_ref) eq 'Try::Tiny::Catch' ) {
      croak 'A try() may not be followed by multiple catch() blocks'
        if $catch;
      $catch = ${$code_ref};
    } elsif ( ref($code_ref) eq 'Try::Tiny::Finally' ) {
      push @finally, ${$code_ref};
    } else {
      croak(
        'try() encountered an unexpected argument ('
      . ( defined $code_ref ? $code_ref : 'undef' )
      . ') - perhaps a missing semi-colon before or'
      );
    }
  }

  # FIXME consider using local $SIG{__DIE__} to accumulate all errors. It's
  # not perfect, but we could provide a list of additional errors for
  # $catch->();

  # name the blocks if we have Sub::Name installed
  _subname(caller().'::try {...} ' => $try)
    if _HAS_SUBNAME;

  # set up scope guards to invoke the finally blocks at the end.
  # this should really be a function scope lexical variable instead of
  # file scope + local but that causes issues with perls < 5.20 due to
  # perl rt#119311
  local $_finally_guards{guards} = [
    map Try::Tiny::ScopeGuard->_new($_),
    @finally
  ];

  # save the value of $@ so we can set $@ back to it in the beginning of the eval
  # and restore $@ after the eval finishes
  my $prev_error = $@;

  my ( @ret, $error );

  # failed will be true if the eval dies, because 1 will not be returned
  # from the eval body
  my $failed = not eval {
    $@ = $prev_error;

    # evaluate the try block in the correct context
    if ( $wantarray ) {
      @ret = $try->();
    } elsif ( defined $wantarray ) {
      $ret[0] = $try->();
    } else {
      $try->();
    };

    return 1; # properly set $failed to false
  };

  # preserve the current error and reset the original value of $@
  $error = $@;
  $@ = $prev_error;

  # at this point $failed contains a true value if the eval died, even if some
  # destructor overwrote $@ as the eval was unwinding.
  if ( $failed ) {
    # pass $error to the finally blocks
    push @$_, $error for @{$_finally_guards{guards}};

    # if we got an error, invoke the catch block.
    if ( $catch ) {
      # This works like given($error), but is backwards compatible and
      # sets $_ in the dynamic scope for the body of C<$catch>
      for ($error) {
        return $catch->($error);
      }

      # in case when() was used without an explicit return, the C<for>
      # loop will be aborted and there's no useful return value
    }

    return;
  } else {
    # no failure, $@ is back to what it was, everything is fine
    return $wantarray ? @ret : $ret[0];
  }
}

sub catch (&;@) {
  my ( $block, @rest ) = @_;

  croak 'Useless bare catch()' unless wantarray;

  _subname(caller().'::catch {...} ' => $block)
    if _HAS_SUBNAME;
  return (
    bless(\$block, 'Try::Tiny::Catch'),
    @rest,
  );
}

sub finally (&;@) {
  my ( $block, @rest ) = @_;

  croak 'Useless bare finally()' unless wantarray;

  _subname(caller().'::finally {...} ' => $block)
    if _HAS_SUBNAME;
  return (
    bless(\$block, 'Try::Tiny::Finally'),
    @rest,
  );
}

{
  package # hide from PAUSE
    Try::Tiny::ScopeGuard;

  use constant UNSTABLE_DOLLARAT => ("$]" < '5.013002') ? 1 : 0;

  sub _new {
    shift;
    bless [ @_ ];
  }

  sub DESTROY {
    my ($code, @args) = @{ $_[0] };

    local $@ if UNSTABLE_DOLLARAT;
    eval {
      $code->(@args);
      1;
    } or do {
      warn
        "Execution of finally() block $code resulted in an exception, which "
      . '*CAN NOT BE PROPAGATED* due to fundamental limitations of Perl. '
      . 'Your program will continue as if this event never took place. '
      . "Original exception text follows:\n\n"
      . (defined $@ ? $@ : '$@ left undefined...')
      . "\n"
      ;
    }
  }
}

__PACKAGE__

__END__

=pod

=encoding UTF-8

=head1 NAME

Try::Tiny - Minimal try/catch with proper preservation of $@

=head1 VERSION

version 0.32

=head1 SYNOPSIS

You can use Try::Tiny's C<try> and C<catch> to expect and handle exceptional
conditions, avoiding quirks in Perl and common mistakes:

  # handle errors with a catch handler
  try {
    die "foo";
  } catch {
    warn "caught error: $_"; # not $@
  };

You can also use it like a standalone C<eval> to catch and ignore any error
conditions.  Obviously, this is an extreme measure not to be undertaken
lightly:

  # just silence errors
  try {
    die "foo";
  };

=head1 DESCRIPTION

This module provides bare bones C<try>/C<catch>/C<finally> statements that are designed to
minimize common mistakes with eval blocks, and NOTHING else.

This is unlike L<TryCatch> which provides a nice syntax and avoids adding
another call stack layer, and supports calling C<return> from the C<try> block to
return from the parent subroutine. These extra features come at a cost of a few
dependencies, namely L<Devel::Declare> and L<Scope::Upper> which are
occasionally problematic, and the additional catch filtering uses L<Moose>
type constraints which may not be desirable either.

The main focus of this module is to provide simple and reliable error handling
for those having a hard time installing L<TryCatch>, but who still want to
write correct C<eval> blocks without 5 lines of boilerplate each time.

It's designed to work as correctly as possible in light of the various
pathological edge cases (see L</BACKGROUND>) and to be compatible with any style
of error values (simple strings, references, objects, overloaded objects, etc).

If the C<try> block dies, it returns the value of the last statement executed in
the C<catch> block, if there is one. Otherwise, it returns C<undef> in scalar
context or the empty list in list context. The following examples all
assign C<"bar"> to C<$x>:

  my $x = try { die "foo" } catch { "bar" };
  my $x = try { die "foo" } || "bar";
  my $x = (try { die "foo" }) // "bar";

  my $x = eval { die "foo" } || "bar";

You can add C<finally> blocks, yielding the following:

  my $x;
  try { die 'foo' } finally { $x = 'bar' };
  try { die 'foo' } catch { warn "Got a die: $_" } finally { $x = 'bar' };

C<finally> blocks are always executed making them suitable for cleanup code
which cannot be handled using local.  You can add as many C<finally> blocks to a
given C<try> block as you like.

Note that adding a C<finally> block without a preceding C<catch> block
suppresses any errors. This behaviour is consistent with using a standalone
C<eval>, but it is not consistent with C<try>/C<finally> patterns found in
other programming languages, such as Java, Python, Javascript or C#. If you
learned the C<try>/C<finally> pattern from one of these languages, watch out for
this.

=head1 EXPORTS

All functions are exported by default using L<Exporter>.

If you need to rename the C<try>, C<catch> or C<finally> keyword consider using
L<Sub::Import> to get L<Sub::Exporter>'s flexibility.

=over 4

=item try (&;@)

Takes one mandatory C<try> subroutine, an optional C<catch> subroutine and C<finally>
subroutine.

The mandatory subroutine is evaluated in the context of an C<eval> block.

If no error occurred the value from the first block is returned, preserving
list/scalar context.

If there was an error and the second subroutine was given it will be invoked
with the error in C<$_> (localized) and as that block's first and only
argument.

C<$@> does B<not> contain the error. Inside the C<catch> block it has the same
value it had before the C<try> block was executed.

Note that the error may be false, but if that happens the C<catch> block will
still be invoked.

Once all execution is finished then the C<finally> block, if given, will execute.

=item catch (&;@)

Intended to be used in the second argument position of C<try>.

Returns a reference to the subroutine it was given but blessed as
C<Try::Tiny::Catch> which allows try to decode correctly what to do
with this code reference.

  catch { ... }

Inside the C<catch> block the caught error is stored in C<$_>, while previous
value of C<$@> is still available for use.  This value may or may not be
meaningful depending on what happened before the C<try>, but it might be a good
idea to preserve it in an error stack.

For code that captures C<$@> when throwing new errors (i.e.
L<Class::Throwable>), you'll need to do:

  local $@ = $_;

=item finally (&;@)

  try     { ... }
  catch   { ... }
  finally { ... };

Or

  try     { ... }
  finally { ... };

Or even

  try     { ... }
  finally { ... }
  catch   { ... };

Intended to be the second or third element of C<try>. C<finally> blocks are always
executed in the event of a successful C<try> or if C<catch> is run. This allows
you to locate cleanup code which cannot be done via C<local()> e.g. closing a file
handle.

When invoked, the C<finally> block is passed the error that was caught.  If no
error was caught, it is passed nothing.  (Note that the C<finally> block does not
localize C<$_> with the error, since unlike in a C<catch> block, there is no way
to know if C<$_ == undef> implies that there were no errors.) In other words,
the following code does just what you would expect:

  try {
    die_sometimes();
  } catch {
    # ...code run in case of error
  } finally {
    if (@_) {
      print "The try block died with: @_\n";
    } else {
      print "The try block ran without error.\n";
    }
  };

B<You must always do your own error handling in the C<finally> block>. C<Try::Tiny> will
not do anything about handling possible errors coming from code located in these
blocks.

Furthermore B<exceptions in C<finally> blocks are not trappable and are unable
to influence the execution of your program>. This is due to limitation of
C<DESTROY>-based scope guards, which C<finally> is implemented on top of. This
may change in a future version of Try::Tiny.

In the same way C<catch()> blesses the code reference this subroutine does the same
except it bless them as C<Try::Tiny::Finally>.

=back

=head1 BACKGROUND

There are a number of issues with C<eval>.

=head2 Clobbering $@

When you run an C<eval> block and it succeeds, C<$@> will be cleared, potentially
clobbering an error that is currently being caught.

This causes action at a distance, clearing previous errors your caller may have
not yet handled.

C<$@> must be properly localized before invoking C<eval> in order to avoid this
issue.

More specifically,
L<before Perl version 5.14.0|perl5140delta/"Exception Handling">
C<$@> was clobbered at the beginning of the C<eval>, which
also made it impossible to capture the previous error before you die (for
instance when making exception objects with error stacks).

For this reason C<try> will actually set C<$@> to its previous value (the one
available before entering the C<try> block) in the beginning of the C<eval>
block.

=head2 Localizing $@ silently masks errors

Inside an C<eval> block, C<die> behaves sort of like:

  sub die {
    $@ = $_[0];
    return_undef_from_eval();
  }

This means that if you were polite and localized C<$@> you can't die in that
scope, or your error will be discarded (printing "Something's wrong" instead).

The workaround is very ugly:

  my $error = do {
    local $@;
    eval { ... };
    $@;
  };

  ...
  die $error;

=head2 $@ might not be a true value

This code is wrong:

  if ( $@ ) {
    ...
  }

because due to the previous caveats it may have been unset.

C<$@> could also be an overloaded error object that evaluates to false, but
that's asking for trouble anyway.

The classic failure mode (fixed in L<Perl 5.14.0|perl5140delta/"Exception Handling">) is:

  sub Object::DESTROY {
    eval { ... }
  }

  eval {
    my $obj = Object->new;

    die "foo";
  };

  if ( $@ ) {

  }

In this case since C<Object::DESTROY> is not localizing C<$@> but still uses
C<eval>, it will set C<$@> to C<"">.

The destructor is called when the stack is unwound, after C<die> sets C<$@> to
C<"foo at Foo.pm line 42\n">, so by the time C<if ( $@ )> is evaluated it has
been cleared by C<eval> in the destructor.

The workaround for this is even uglier than the previous ones. Even though we
can't save the value of C<$@> from code that doesn't localize, we can at least
be sure the C<eval> was aborted due to an error:

  my $failed = not eval {
    ...

    return 1;
  };

This is because an C<eval> that caught a C<die> will always return a false
value.

=head1 ALTERNATE SYNTAX

Using Perl 5.10 you can use L<perlsyn/"Switch statements"> (but please don't,
because that syntax has since been deprecated because there was too much
unexpected magical behaviour).

=for stopwords topicalizer

The C<catch> block is invoked in a topicalizer context (like a C<given> block),
but note that you can't return a useful value from C<catch> using the C<when>
blocks without an explicit C<return>.

This is somewhat similar to Perl 6's C<CATCH> blocks. You can use it to
concisely match errors:

  try {
    require Foo;
  } catch {
    when (/^Can't locate .*?\.pm in \@INC/) { } # ignore
    default { die $_ }
  };

=head1 CAVEATS

=over 4

=item *

C<@_> is not available within the C<try> block, so you need to copy your
argument list. In case you want to work with argument values directly via C<@_>
aliasing (i.e. allow C<$_[1] = "foo">), you need to pass C<@_> by reference:

  sub foo {
    my ( $self, @args ) = @_;
    try { $self->bar(@args) }
  }

or

  sub bar_in_place {
    my $self = shift;
    my $args = \@_;
    try { $_ = $self->bar($_) for @$args }
  }

=item *

C<return> returns from the C<try> block, not from the parent sub (note that
this is also how C<eval> works, but not how L<TryCatch> works):

  sub parent_sub {
    try {
      die;
    }
    catch {
      return;
    };

    say "this text WILL be displayed, even though an exception is thrown";
  }

Instead, you should capture the return value:

  sub parent_sub {
    my $success = try {
      die;
      1;
    };
    return unless $success;

    say "This text WILL NEVER appear!";
  }
  # OR
  sub parent_sub_with_catch {
    my $success = try {
      die;
      1;
    }
    catch {
      # do something with $_
      return undef; #see note
    };
    return unless $success;

    say "This text WILL NEVER appear!";
  }

Note that if you have a C<catch> block, it must return C<undef> for this to work,
since if a C<catch> block exists, its return value is returned in place of C<undef>
when an exception is thrown.

=item *

C<try> introduces another caller stack frame. L<Sub::Uplevel> is not used. L<Carp>
will not report this when using full stack traces, though, because
C<%Carp::Internal> is used. This lack of magic is considered a feature.

=for stopwords unhygienically

=item *

The value of C<$_> in the C<catch> block is not guaranteed to be the value of
the exception thrown (C<$@>) in the C<try> block.  There is no safe way to
ensure this, since C<eval> may be used unhygienically in destructors.  The only
guarantee is that the C<catch> will be called if an exception is thrown.

=item *

The return value of the C<catch> block is not ignored, so if testing the result
of the expression for truth on success, be sure to return a false value from
the C<catch> block:

  my $obj = try {
    MightFail->new;
  } catch {
    ...

    return; # avoid returning a true value;
  };

  return unless $obj;

=item *

C<$SIG{__DIE__}> is still in effect.

Though it can be argued that C<$SIG{__DIE__}> should be disabled inside of
C<eval> blocks, since it isn't people have grown to rely on it. Therefore in
the interests of compatibility, C<try> does not disable C<$SIG{__DIE__}> for
the scope of the error throwing code.

=item *

Lexical C<$_> may override the one set by C<catch>.

For example Perl 5.10's C<given> form uses a lexical C<$_>, creating some
confusing behavior:

  given ($foo) {
    when (...) {
      try {
        ...
      } catch {
        warn $_; # will print $foo, not the error
        warn $_[0]; # instead, get the error like this
      }
    }
  }

Note that this behavior was changed once again in
L<Perl5 version 18|https://metacpan.org/module/perldelta#given-now-aliases-the-global-_>.
However, since the entirety of lexical C<$_> is now L<considered experimental
|https://metacpan.org/module/perldelta#Lexical-_-is-now-experimental>, it
is unclear whether the new version 18 behavior is final.

=back

=head1 SEE ALSO

=over 4

=item L<Syntax::Keyword::Try>

Only available on perls >= 5.14, with a slightly different syntax (e.g. no trailing C<;> because
it's actually a keyword, not a sub, but this means you can C<return> and C<next> within it). Use
L<Feature::Compat::Try> to automatically switch to the native C<try> syntax in newer perls (when
available). See also L<Try Catch Exception Handling|perlsyn/Try-Catch-Exception-Handling>.

=item L<TryCatch>

Much more feature complete, more convenient semantics, but at the cost of
implementation complexity.

=item L<autodie>

Automatic error throwing for builtin functions and more. Also designed to
work well with C<given>/C<when>.

=item L<Throwable>

A lightweight role for rolling your own exception classes.

=item L<Error>

Exception object implementation with a C<try> statement. Does not localize
C<$@>.

=item L<Exception::Class::TryCatch>

Provides a C<catch> statement, but properly calling C<eval> is your
responsibility.

The C<try> keyword pushes C<$@> onto an error stack, avoiding some of the
issues with C<$@>, but you still need to localize to prevent clobbering.

=back

=head1 LIGHTNING TALK

I gave a lightning talk about this module, you can see the slides (Firefox
only):

L<http://web.archive.org/web/20100628040134/http://nothingmuch.woobling.org/talks/takahashi.xul>

Or read the source:

L<http://web.archive.org/web/20100305133605/http://nothingmuch.woobling.org/talks/yapc_asia_2009/try_tiny.yml>

=head1 SUPPORT

Bugs may be submitted through L<the RT bug tracker|https://rt.cpan.org/Public/Dist/Display.html?Name=Try-Tiny>
(or L<bug-Try-Tiny@rt.cpan.org|mailto:bug-Try-Tiny@rt.cpan.org>).

=head1 AUTHORS

=over 4

=item *

יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org>

=item *

Jesse Luehrs <doy@tozt.net>

=back

=head1 CONTRIBUTORS

=for stopwords Karen Etheridge Peter Rabbitson Ricardo Signes Mark Fowler Graham Knop Aristotle Pagaltzis Dagfinn Ilmari Mannsåker Lukas Mai Alex anaxagoras Andrew Yates awalker chromatic cm-perl David Lowe Glenn Hans Dieter Pearcey Jens Berthold Jonathan Yu Marc Mims Stosberg Pali Paul Howarth Rudolf Leermakers

=over 4

=item *

Karen Etheridge <ether@cpan.org>

=item *

Peter Rabbitson <ribasushi@cpan.org>

=item *

Ricardo Signes <rjbs@cpan.org>

=item *

Mark Fowler <mark@twoshortplanks.com>

=item *

Graham Knop <haarg@haarg.org>

=item *

Aristotle Pagaltzis <pagaltzis@gmx.de>

=item *

Dagfinn Ilmari Mannsåker <ilmari@ilmari.org>

=item *

Lukas Mai <l.mai@web.de>

=item *

Alex <alex@koban.(none)>

=item *

anaxagoras <walkeraj@gmail.com>

=item *

Andrew Yates <ayates@haddock.local>

=item *

awalker <awalker@sourcefire.com>

=item *

chromatic <chromatic@wgz.org>

=item *

cm-perl <cm-perl@users.noreply.github.com>

=item *

David Lowe <davidl@lokku.com>

=item *

Glenn Fowler <cebjyre@cpan.org>

=item *

Hans Dieter Pearcey <hdp@weftsoar.net>

=item *

Jens Berthold <jens@jebecs.de>

=item *

Jonathan Yu <JAWNSY@cpan.org>

=item *

Marc Mims <marc@questright.com>

=item *

Mark Stosberg <mark@stosberg.com>

=item *

Pali <pali@cpan.org>

=item *

Paul Howarth <paul@city-fan.org>

=item *

Rudolf Leermakers <rudolf@hatsuseno.org>

=back

=head1 COPYRIGHT AND LICENCE

This software is Copyright (c) 2009 by יובל קוג'מן (Yuval Kogman).

This is free software, licensed under:

  The MIT (X11) License

=cut
PK5N%[D�O��	�	perl5/Net/HTTP/NB.pmnu��6�$package Net::HTTP::NB;
our $VERSION = '6.23';
use strict;
use warnings;

use base 'Net::HTTP';

sub can_read {
    return 1;
}

sub sysread {
    my $self = $_[0];
    if (${*$self}{'httpnb_read_count'}++) {
	${*$self}{'http_buf'} = ${*$self}{'httpnb_save'};
	die "Multi-read\n";
    }
    my $buf;
    my $offset = $_[3] || 0;
    my $n = sysread($self, $_[1], $_[2], $offset);
    ${*$self}{'httpnb_save'} .= substr($_[1], $offset);
    return $n;
}

sub read_response_headers {
    my $self = shift;
    ${*$self}{'httpnb_read_count'} = 0;
    ${*$self}{'httpnb_save'} = ${*$self}{'http_buf'};
    my @h = eval { $self->SUPER::read_response_headers(@_) };
    if ($@) {
	return if $@ eq "Multi-read\n";
	die;
    }
    return @h;
}

sub read_entity_body {
    my $self = shift;
    ${*$self}{'httpnb_read_count'} = 0;
    ${*$self}{'httpnb_save'} = ${*$self}{'http_buf'};
    # XXX I'm not so sure this does the correct thing in case of
    # transfer-encoding transforms
    my $n = eval { $self->SUPER::read_entity_body(@_); };
    if ($@) {
	$_[0] = "";
	return -1;
    }
    return $n;
}

1;

=pod

=encoding UTF-8

=head1 NAME

Net::HTTP::NB - Non-blocking HTTP client

=head1 VERSION

version 6.23

=head1 SYNOPSIS

 use Net::HTTP::NB;
 my $s = Net::HTTP::NB->new(Host => "www.perl.com") || die $@;
 $s->write_request(GET => "/");

 use IO::Select;
 my $sel = IO::Select->new($s);

 READ_HEADER: {
    die "Header timeout" unless $sel->can_read(10);
    my($code, $mess, %h) = $s->read_response_headers;
    redo READ_HEADER unless $code;
 }

 while (1) {
    die "Body timeout" unless $sel->can_read(10);
    my $buf;
    my $n = $s->read_entity_body($buf, 1024);
    last unless $n;
    print $buf;
 }

=head1 DESCRIPTION

Same interface as C<Net::HTTP> but it will never try multiple reads
when the read_response_headers() or read_entity_body() methods are
invoked.  This make it possible to multiplex multiple Net::HTTP::NB
using select without risk blocking.

If read_response_headers() did not see enough data to complete the
headers an empty list is returned.

If read_entity_body() did not see new entity data in its read
the value -1 is returned.

=head1 SEE ALSO

L<Net::HTTP>

=head1 AUTHOR

Gisle Aas <gisle@activestate.com>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2001 by Gisle Aas.

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

=cut

__END__

#ABSTRACT: Non-blocking HTTP client

PK5N%[@��iVDVDperl5/Net/HTTP/Methods.pmnu��6�$package Net::HTTP::Methods;
our $VERSION = '6.23';
use strict;
use warnings;
use URI;

my $CRLF = "\015\012";   # "\r\n" is not portable

*_bytes = defined(&utf8::downgrade) ?
    sub {
        unless (utf8::downgrade($_[0], 1)) {
            require Carp;
            Carp::croak("Wide character in HTTP request (bytes required)");
        }
        return $_[0];
    }
    :
    sub {
        return $_[0];
    };


sub new {
    my $class = shift;
    unshift(@_, "Host") if @_ == 1;
    my %cnf = @_;
    require Symbol;
    my $self = bless Symbol::gensym(), $class;
    return $self->http_configure(\%cnf);
}

sub http_configure {
    my($self, $cnf) = @_;

    die "Listen option not allowed" if $cnf->{Listen};
    my $explicit_host = (exists $cnf->{Host});
    my $host = delete $cnf->{Host};
    # All this because $cnf->{PeerAddr} = 0 is actually valid.
    my $peer;
    for my $key (qw{PeerAddr PeerHost}) {
	next if !defined($cnf->{$key}) || q{} eq $cnf->{$key};
	$peer = $cnf->{$key};
	last;
    }
    if (!defined $peer) {
	die "No Host option provided" unless $host;
	$cnf->{PeerAddr} = $peer = $host;
    }

    # CONNECTIONS
    # PREFER: port number from PeerAddr, then PeerPort, then http_default_port
    my $peer_uri = URI->new("http://$peer");
    $cnf->{"PeerPort"} =  $peer_uri->_port || $cnf->{PeerPort} ||  $self->http_default_port;
    $cnf->{"PeerAddr"} = $peer_uri->host;

    # HOST header:
    # If specified but blank, ignore.
    # If specified with a value, add the port number
    # If not specified, set to PeerAddr and port number
    # ALWAYS: If IPv6 address, use [brackets]  (thanks to the URI package)
    # ALWAYS: omit port number if http_default_port
    if (($host) || (! $explicit_host)) {
        my $uri =  ($explicit_host) ? URI->new("http://$host") : $peer_uri->clone;
        if (!$uri->_port) {
            # Always use *our*  $self->http_default_port  instead of URI's  (Covers HTTP, HTTPS)
            $uri->port( $cnf->{PeerPort} ||  $self->http_default_port);
        }
        my $host_port = $uri->host_port;               # Returns host:port or [ipv6]:port
        my $remove = ":" . $self->http_default_port;   # we want to remove the default port number
        if (substr($host_port,0-length($remove)) eq $remove) {
            substr($host_port,0-length($remove)) = "";
        }
        $host = $host_port;
    }

    $cnf->{Proto} = 'tcp';

    my $keep_alive = delete $cnf->{KeepAlive};
    my $http_version = delete $cnf->{HTTPVersion};
    $http_version = "1.1" unless defined $http_version;
    my $peer_http_version = delete $cnf->{PeerHTTPVersion};
    $peer_http_version = "1.0" unless defined $peer_http_version;
    my $send_te = delete $cnf->{SendTE};
    my $max_line_length = delete $cnf->{MaxLineLength};
    $max_line_length = 8*1024 unless defined $max_line_length;
    my $max_header_lines = delete $cnf->{MaxHeaderLines};
    $max_header_lines = 128 unless defined $max_header_lines;

    return undef unless $self->http_connect($cnf);

    $self->host($host);
    $self->keep_alive($keep_alive);
    $self->send_te($send_te);
    $self->http_version($http_version);
    $self->peer_http_version($peer_http_version);
    $self->max_line_length($max_line_length);
    $self->max_header_lines($max_header_lines);

    ${*$self}{'http_buf'} = "";

    return $self;
}

sub http_default_port {
    80;
}

# set up property accessors
for my $method (qw(host keep_alive send_te max_line_length max_header_lines peer_http_version)) {
    my $prop_name = "http_" . $method;
    no strict 'refs';
    *$method = sub {
	my $self = shift;
	my $old = ${*$self}{$prop_name};
	${*$self}{$prop_name} = shift if @_;
	return $old;
    };
}

# we want this one to be a bit smarter
sub http_version {
    my $self = shift;
    my $old = ${*$self}{'http_version'};
    if (@_) {
	my $v = shift;
	$v = "1.0" if $v eq "1";  # float
	unless ($v eq "1.0" or $v eq "1.1") {
	    require Carp;
	    Carp::croak("Unsupported HTTP version '$v'");
	}
	${*$self}{'http_version'} = $v;
    }
    $old;
}

sub format_request {
    my $self = shift;
    my $method = shift;
    my $uri = shift;

    my $content = (@_ % 2) ? pop : "";

    for ($method, $uri) {
	require Carp;
	Carp::croak("Bad method or uri") if /\s/ || !length;
    }

    push(@{${*$self}{'http_request_method'}}, $method);
    my $ver = ${*$self}{'http_version'};
    my $peer_ver = ${*$self}{'http_peer_http_version'} || "1.0";

    my @h;
    my @connection;
    my %given = (host => 0, "content-length" => 0, "te" => 0);
    while (@_) {
	my($k, $v) = splice(@_, 0, 2);
	my $lc_k = lc($k);
	if ($lc_k eq "connection") {
	    $v =~ s/^\s+//;
	    $v =~ s/\s+$//;
	    push(@connection, split(/\s*,\s*/, $v));
	    next;
	}
	if (exists $given{$lc_k}) {
	    $given{$lc_k}++;
	}
	push(@h, "$k: $v");
    }

    if (length($content) && !$given{'content-length'}) {
	push(@h, "Content-Length: " . length($content));
    }

    my @h2;
    if ($given{te}) {
	push(@connection, "TE") unless grep lc($_) eq "te", @connection;
    }
    elsif ($self->send_te && gunzip_ok()) {
	# gzip is less wanted since the IO::Uncompress::Gunzip interface for
	# it does not really allow chunked decoding to take place easily.
	push(@h2, "TE: deflate,gzip;q=0.3");
	push(@connection, "TE");
    }

    unless (grep lc($_) eq "close", @connection) {
	if ($self->keep_alive) {
	    if ($peer_ver eq "1.0") {
		# from looking at Netscape's headers
		push(@h2, "Keep-Alive: 300");
		unshift(@connection, "Keep-Alive");
	    }
	}
	else {
	    push(@connection, "close") if $ver ge "1.1";
	}
    }
    push(@h2, "Connection: " . join(", ", @connection)) if @connection;
    unless ($given{host}) {
	my $h = ${*$self}{'http_host'};
	push(@h2, "Host: $h") if $h;
    }

    return _bytes(join($CRLF, "$method $uri HTTP/$ver", @h2, @h, "", $content));
}


sub write_request {
    my $self = shift;
    $self->print($self->format_request(@_));
}

sub format_chunk {
    my $self = shift;
    return $_[0] unless defined($_[0]) && length($_[0]);
    return _bytes(sprintf("%x", length($_[0])) . $CRLF . $_[0] . $CRLF);
}

sub write_chunk {
    my $self = shift;
    return 1 unless defined($_[0]) && length($_[0]);
    $self->print(_bytes(sprintf("%x", length($_[0])) . $CRLF . $_[0] . $CRLF));
}

sub format_chunk_eof {
    my $self = shift;
    my @h;
    while (@_) {
	push(@h, sprintf "%s: %s$CRLF", splice(@_, 0, 2));
    }
    return _bytes(join("", "0$CRLF", @h, $CRLF));
}

sub write_chunk_eof {
    my $self = shift;
    $self->print($self->format_chunk_eof(@_));
}


sub my_read {
    die if @_ > 3;
    my $self = shift;
    my $len = $_[1];
    for (${*$self}{'http_buf'}) {
	if (length) {
	    $_[0] = substr($_, 0, $len, "");
	    return length($_[0]);
	}
	else {
	    die "read timeout" unless $self->can_read;
	    return $self->sysread($_[0], $len);
	}
    }
}


sub my_readline {
    my $self = shift;
    my $what = shift;
    for (${*$self}{'http_buf'}) {
	my $max_line_length = ${*$self}{'http_max_line_length'};
	my $pos;
	while (1) {
	    # find line ending
	    $pos = index($_, "\012");
	    last if $pos >= 0;
	    die "$what line too long (limit is $max_line_length)"
		if $max_line_length && length($_) > $max_line_length;

	    # need to read more data to find a line ending
            my $new_bytes = 0;

          READ:
            {   # wait until bytes start arriving
                $self->can_read
                     or die "read timeout";

                # consume all incoming bytes
                my $bytes_read = $self->sysread($_, 1024, length);
                if(defined $bytes_read) {
                    $new_bytes += $bytes_read;
                }
                elsif($!{EINTR} || $!{EAGAIN} || $!{EWOULDBLOCK}) {
                    redo READ;
                }
                else {
                    # if we have already accumulated some data let's at
                    # least return that as a line
                    length or die "$what read failed: $!";
                }

                # no line-ending, no new bytes
                return length($_) ? substr($_, 0, length($_), "") : undef
                    if $new_bytes==0;
            }
	}
	die "$what line too long ($pos; limit is $max_line_length)"
	    if $max_line_length && $pos > $max_line_length;

	my $line = substr($_, 0, $pos+1, "");
	$line =~ s/(\015?\012)\z// || die "Assert";
	return wantarray ? ($line, $1) : $line;
    }
}


sub can_read {
    my $self = shift;
    return 1 unless defined(fileno($self));
    return 1 if $self->isa('IO::Socket::SSL') && $self->pending;
    return 1 if $self->isa('Net::SSL') && $self->can('pending') && $self->pending;

    # With no timeout, wait forever.  An explicit timeout of 0 can be
    # used to just check if the socket is readable without waiting.
    my $timeout = @_ ? shift : (${*$self}{io_socket_timeout} || undef);

    my $fbits = '';
    vec($fbits, fileno($self), 1) = 1;
  SELECT:
    {
        my $before;
        $before = time if $timeout;
        my $nfound = select($fbits, undef, undef, $timeout);
        if ($nfound < 0) {
            if ($!{EINTR} || $!{EAGAIN} || $!{EWOULDBLOCK}) {
                # don't really think EAGAIN/EWOULDBLOCK can happen here
                if ($timeout) {
                    $timeout -= time - $before;
                    $timeout = 0 if $timeout < 0;
                }
                redo SELECT;
            }
            die "select failed: $!";
        }
        return $nfound > 0;
    }
}


sub _rbuf {
    my $self = shift;
    if (@_) {
	for (${*$self}{'http_buf'}) {
	    my $old;
	    $old = $_ if defined wantarray;
	    $_ = shift;
	    return $old;
	}
    }
    else {
	return ${*$self}{'http_buf'};
    }
}

sub _rbuf_length {
    my $self = shift;
    return length ${*$self}{'http_buf'};
}


sub _read_header_lines {
    my $self = shift;
    my $junk_out = shift;

    my @headers;
    my $line_count = 0;
    my $max_header_lines = ${*$self}{'http_max_header_lines'};
    while (my $line = my_readline($self, 'Header')) {
	if ($line =~ /^(\S+?)\s*:\s*(.*)/s) {
	    push(@headers, $1, $2);
	}
	elsif (@headers && $line =~ s/^\s+//) {
	    $headers[-1] .= " " . $line;
	}
	elsif ($junk_out) {
	    push(@$junk_out, $line);
	}
	else {
	    die "Bad header: '$line'\n";
	}
	if ($max_header_lines) {
	    $line_count++;
	    if ($line_count >= $max_header_lines) {
		die "Too many header lines (limit is $max_header_lines)";
	    }
	}
    }
    return @headers;
}


sub read_response_headers {
    my($self, %opt) = @_;
    my $laxed = $opt{laxed};

    my($status, $eol) = my_readline($self, 'Status');
    unless (defined $status) {
	die "Server closed connection without sending any data back";
    }

    my($peer_ver, $code, $message) = split(/\s+/, $status, 3);
    if (!$peer_ver || $peer_ver !~ s,^HTTP/,, || $code !~ /^[1-5]\d\d$/) {
	die "Bad response status line: '$status'" unless $laxed;
	# assume HTTP/0.9
	${*$self}{'http_peer_http_version'} = "0.9";
	${*$self}{'http_status'} = "200";
	substr(${*$self}{'http_buf'}, 0, 0) = $status . ($eol || "");
	return 200 unless wantarray;
	return (200, "Assumed OK");
    };

    ${*$self}{'http_peer_http_version'} = $peer_ver;
    ${*$self}{'http_status'} = $code;

    my $junk_out;
    if ($laxed) {
	$junk_out = $opt{junk_out} || [];
    }
    my @headers = $self->_read_header_lines($junk_out);

    # pick out headers that read_entity_body might need
    my @te;
    my $content_length;
    for (my $i = 0; $i < @headers; $i += 2) {
	my $h = lc($headers[$i]);
	if ($h eq 'transfer-encoding') {
	    my $te = $headers[$i+1];
	    $te =~ s/^\s+//;
	    $te =~ s/\s+$//;
	    push(@te, $te) if length($te);
	}
	elsif ($h eq 'content-length') {
	    # ignore bogus and overflow values
	    if ($headers[$i+1] =~ /^\s*(\d{1,15})(?:\s|$)/) {
		$content_length = $1;
	    }
	}
    }
    ${*$self}{'http_te'} = join(",", @te);
    ${*$self}{'http_content_length'} = $content_length;
    ${*$self}{'http_first_body'}++;
    delete ${*$self}{'http_trailers'};
    return $code unless wantarray;
    return ($code, $message, @headers);
}


sub read_entity_body {
    my $self = shift;
    my $buf_ref = \$_[0];
    my $size = $_[1];
    die "Offset not supported yet" if $_[2];

    my $chunked;
    my $bytes;

    if (${*$self}{'http_first_body'}) {
	${*$self}{'http_first_body'} = 0;
	delete ${*$self}{'http_chunked'};
	delete ${*$self}{'http_bytes'};
	my $method = shift(@{${*$self}{'http_request_method'}});
	my $status = ${*$self}{'http_status'};
	if ($method eq "HEAD") {
	    # this response is always empty regardless of other headers
	    $bytes = 0;
	}
	elsif (my $te = ${*$self}{'http_te'}) {
	    my @te = split(/\s*,\s*/, lc($te));
	    die "Chunked must be last Transfer-Encoding '$te'"
		unless pop(@te) eq "chunked";
	    pop(@te) while @te && $te[-1] eq "chunked";  # ignore repeated chunked spec

	    for (@te) {
		if ($_ eq "deflate" && inflate_ok()) {
		    #require Compress::Raw::Zlib;
		    my ($i, $status) = Compress::Raw::Zlib::Inflate->new();
		    die "Can't make inflator: $status" unless $i;
		    $_ = sub { my $out; $i->inflate($_[0], \$out); $out }
		}
		elsif ($_ eq "gzip" && gunzip_ok()) {
		    #require IO::Uncompress::Gunzip;
		    my @buf;
		    $_ = sub {
			push(@buf, $_[0]);
			return "" unless $_[1];
			my $input = join("", @buf);
			my $output;
			IO::Uncompress::Gunzip::gunzip(\$input, \$output, Transparent => 0)
			    or die "Can't gunzip content: $IO::Uncompress::Gunzip::GunzipError";
			return \$output;
		    };
		}
		elsif ($_ eq "identity") {
		    $_ = sub { $_[0] };
		}
		else {
		    die "Can't handle transfer encoding '$te'";
		}
	    }

	    @te = reverse(@te);

	    ${*$self}{'http_te2'} = @te ? \@te : "";
	    $chunked = -1;
	}
	elsif (defined(my $content_length = ${*$self}{'http_content_length'})) {
	    $bytes = $content_length;
	}
        elsif ($status =~ /^(?:1|[23]04)/) {
            # RFC 2616 says that these responses should always be empty
            # but that does not appear to be true in practice [RT#17907]
            $bytes = 0;
        }
	else {
	    # XXX Multi-Part types are self delimiting, but RFC 2616 says we
	    # only has to deal with 'multipart/byteranges'

	    # Read until EOF
	}
    }
    else {
	$chunked = ${*$self}{'http_chunked'};
	$bytes   = ${*$self}{'http_bytes'};
    }

    if (defined $chunked) {
	# The state encoded in $chunked is:
	#   $chunked == 0:   read CRLF after chunk, then chunk header
        #   $chunked == -1:  read chunk header
	#   $chunked > 0:    bytes left in current chunk to read

	if ($chunked <= 0) {
	    my $line = my_readline($self, 'Entity body');
	    if ($chunked == 0) {
		die "Missing newline after chunk data: '$line'"
		    if !defined($line) || $line ne "";
		$line = my_readline($self, 'Entity body');
	    }
	    die "EOF when chunk header expected" unless defined($line);
	    my $chunk_len = $line;
	    $chunk_len =~ s/;.*//;  # ignore potential chunk parameters
	    unless ($chunk_len =~ /^([\da-fA-F]+)\s*$/) {
		die "Bad chunk-size in HTTP response: $line";
	    }
	    $chunked = hex($1);
	    ${*$self}{'http_chunked'} = $chunked;
	    if ($chunked == 0) {
		${*$self}{'http_trailers'} = [$self->_read_header_lines];
		$$buf_ref = "";

		my $n = 0;
		if (my $transforms = delete ${*$self}{'http_te2'}) {
		    for (@$transforms) {
			$$buf_ref = &$_($$buf_ref, 1);
		    }
		    $n = length($$buf_ref);
		}

		# in case somebody tries to read more, make sure we continue
		# to return EOF
		delete ${*$self}{'http_chunked'};
		${*$self}{'http_bytes'} = 0;

		return $n;
	    }
	}

	my $n = $chunked;
	$n = $size if $size && $size < $n;
	$n = my_read($self, $$buf_ref, $n);
	return undef unless defined $n;

	${*$self}{'http_chunked'} = $chunked - $n;

	if ($n > 0) {
	    if (my $transforms = ${*$self}{'http_te2'}) {
		for (@$transforms) {
		    $$buf_ref = &$_($$buf_ref, 0);
		}
		$n = length($$buf_ref);
		$n = -1 if $n == 0;
	    }
	}
	return $n;
    }
    elsif (defined $bytes) {
	unless ($bytes) {
	    $$buf_ref = "";
	    return 0;
	}
	my $n = $bytes;
	$n = $size if $size && $size < $n;
	$n = my_read($self, $$buf_ref, $n);
	${*$self}{'http_bytes'} = defined $n ? $bytes - $n : $bytes;
	return $n;
    }
    else {
	# read until eof
	$size ||= 8*1024;
	return my_read($self, $$buf_ref, $size);
    }
}

sub get_trailers {
    my $self = shift;
    @{${*$self}{'http_trailers'} || []};
}

BEGIN {
my $gunzip_ok;
my $inflate_ok;

sub gunzip_ok {
    return $gunzip_ok if defined $gunzip_ok;

    # Try to load IO::Uncompress::Gunzip.
    local $@;
    local $SIG{__DIE__};
    $gunzip_ok = 0;

    eval {
	require IO::Uncompress::Gunzip;
	$gunzip_ok++;
    };

    return $gunzip_ok;
}

sub inflate_ok {
    return $inflate_ok if defined $inflate_ok;

    # Try to load Compress::Raw::Zlib.
    local $@;
    local $SIG{__DIE__};
    $inflate_ok = 0;

    eval {
	require Compress::Raw::Zlib;
	$inflate_ok++;
    };

    return $inflate_ok;
}

} # BEGIN

1;

=pod

=encoding UTF-8

=head1 NAME

Net::HTTP::Methods - Methods shared by Net::HTTP and Net::HTTPS

=head1 VERSION

version 6.23

=head1 AUTHOR

Gisle Aas <gisle@activestate.com>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2001 by Gisle Aas.

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

=cut

__END__

# ABSTRACT: Methods shared by Net::HTTP and Net::HTTPS
PK5N%[����
�
perl5/Net/HTTPS.pmnu��6�$package Net::HTTPS;
our $VERSION = '6.23';
use strict;
use warnings;

# Figure out which SSL implementation to use
our $SSL_SOCKET_CLASS;
if ($SSL_SOCKET_CLASS) {
    # somebody already set it
}
elsif ($SSL_SOCKET_CLASS = $ENV{PERL_NET_HTTPS_SSL_SOCKET_CLASS}) {
    unless ($SSL_SOCKET_CLASS =~ /^(IO::Socket::SSL|Net::SSL)\z/) {
	die "Bad socket class [$SSL_SOCKET_CLASS]";
    }
    eval "require $SSL_SOCKET_CLASS";
    die $@ if $@;
}
elsif ($IO::Socket::SSL::VERSION) {
    $SSL_SOCKET_CLASS = "IO::Socket::SSL"; # it was already loaded
}
elsif ($Net::SSL::VERSION) {
    $SSL_SOCKET_CLASS = "Net::SSL";
}
else {
    eval { require IO::Socket::SSL; };
    if ($@) {
	my $old_errsv = $@;
	eval {
	    require Net::SSL;  # from Crypt-SSLeay
	};
	if ($@) {
	    $old_errsv =~ s/\s\(\@INC contains:.*\)/)/g;
	    die $old_errsv . $@;
	}
	$SSL_SOCKET_CLASS = "Net::SSL";
    }
    else {
	$SSL_SOCKET_CLASS = "IO::Socket::SSL";
    }
}

require Net::HTTP::Methods;

our @ISA=($SSL_SOCKET_CLASS, 'Net::HTTP::Methods');

sub configure {
    my($self, $cnf) = @_;
    $self->http_configure($cnf);
}

sub http_connect {
    my($self, $cnf) = @_;
    if ($self->isa("Net::SSL")) {
	if ($cnf->{SSL_verify_mode}) {
	    if (my $f = $cnf->{SSL_ca_file}) {
		$ENV{HTTPS_CA_FILE} = $f;
	    }
	    if (my $f = $cnf->{SSL_ca_path}) {
		$ENV{HTTPS_CA_DIR} = $f;
	    }
	}
	if ($cnf->{SSL_verifycn_scheme}) {
	    $@ = "Net::SSL from Crypt-SSLeay can't verify hostnames; either install IO::Socket::SSL or turn off verification by setting the PERL_LWP_SSL_VERIFY_HOSTNAME environment variable to 0";
	    return undef;
	}
    }
    $self->SUPER::configure($cnf);
}

sub http_default_port {
    443;
}

if ($SSL_SOCKET_CLASS eq "Net::SSL") {
    # The underlying SSLeay classes fails to work if the socket is
    # placed in non-blocking mode.  This override of the blocking
    # method makes sure it stays the way it was created.
    *blocking = sub { };
}

1;

=pod

=encoding UTF-8

=head1 NAME

Net::HTTPS - Low-level HTTP over SSL/TLS connection (client)

=head1 VERSION

version 6.23

=head1 DESCRIPTION

The C<Net::HTTPS> is a low-level HTTP over SSL/TLS client.  The interface is the same
as the interface for C<Net::HTTP>, but the constructor takes additional parameters
as accepted by L<IO::Socket::SSL>.  The C<Net::HTTPS> object is an C<IO::Socket::SSL>
too, which makes it inherit additional methods from that base class.

For historical reasons this module also supports using C<Net::SSL> (from the
Crypt-SSLeay distribution) as its SSL driver and base class.  This base is
automatically selected if available and C<IO::Socket::SSL> isn't.  You might
also force which implementation to use by setting $Net::HTTPS::SSL_SOCKET_CLASS
before loading this module.  If not set this variable is initialized from the
C<PERL_NET_HTTPS_SSL_SOCKET_CLASS> environment variable.

=head1 ENVIRONMENT

You might set the C<PERL_NET_HTTPS_SSL_SOCKET_CLASS> environment variable to the name
of the base SSL implementation (and Net::HTTPS base class) to use.  The default
is C<IO::Socket::SSL>.  Currently the only other supported value is C<Net::SSL>.

=head1 SEE ALSO

L<Net::HTTP>, L<IO::Socket::SSL>

=head1 AUTHOR

Gisle Aas <gisle@activestate.com>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2001 by Gisle Aas.

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

=cut

__END__

#ABSTRACT: Low-level HTTP over SSL/TLS connection (client)

PK5N%[K��((perl5/Net/HTTP.pmnu��6�$package Net::HTTP;
our $VERSION = '6.23';
use strict;
use warnings;

our $SOCKET_CLASS;
unless ($SOCKET_CLASS) {
    # Try several, in order of capability and preference
    if (eval { require IO::Socket::IP }) {
       $SOCKET_CLASS = "IO::Socket::IP";    # IPv4+IPv6
    } elsif (eval { require IO::Socket::INET6 }) {
       $SOCKET_CLASS = "IO::Socket::INET6"; # IPv4+IPv6
    } elsif (eval { require IO::Socket::INET }) {
       $SOCKET_CLASS = "IO::Socket::INET";  # IPv4 only
    } else {
       require IO::Socket;
       $SOCKET_CLASS = "IO::Socket::INET";
    }
}
require Net::HTTP::Methods;
require Carp;

our @ISA = ($SOCKET_CLASS, 'Net::HTTP::Methods');

sub new {
    my $class = shift;
    Carp::croak("No Host option provided") unless @_;
    $class->SUPER::new(@_);
}

sub configure {
    my($self, $cnf) = @_;
    $self->http_configure($cnf);
}

sub http_connect {
    my($self, $cnf) = @_;
    $self->SUPER::configure($cnf);
}

1;

=pod

=encoding UTF-8

=head1 NAME

Net::HTTP - Low-level HTTP connection (client)

=head1 VERSION

version 6.23

=head1 SYNOPSIS

 use Net::HTTP;
 my $s = Net::HTTP->new(Host => "www.perl.com") || die $@;
 $s->write_request(GET => "/", 'User-Agent' => "Mozilla/5.0");
 my($code, $mess, %h) = $s->read_response_headers;

 while (1) {
    my $buf;
    my $n = $s->read_entity_body($buf, 1024);
    die "read failed: $!" unless defined $n;
    last unless $n;
    print $buf;
 }

=head1 DESCRIPTION

The C<Net::HTTP> class is a low-level HTTP client.  An instance of the
C<Net::HTTP> class represents a connection to an HTTP server.  The
HTTP protocol is described in RFC 2616.  The C<Net::HTTP> class
supports C<HTTP/1.0> and C<HTTP/1.1>.

C<Net::HTTP> is a sub-class of one of C<IO::Socket::IP> (IPv6+IPv4),
C<IO::Socket::INET6> (IPv6+IPv4), or C<IO::Socket::INET> (IPv4 only).
You can mix the methods described below with reading and writing from the
socket directly.  This is not necessary a good idea, unless you know what
you are doing.

The following methods are provided (in addition to those of
C<IO::Socket::INET>):

=over

=item C<< $s = Net::HTTP->new( %options ) >>

The C<Net::HTTP> constructor method takes the same options as
C<IO::Socket::INET>'s as well as these:

  Host:            Initial host attribute value
  KeepAlive:       Initial keep_alive attribute value
  SendTE:          Initial send_te attribute_value
  HTTPVersion:     Initial http_version attribute value
  PeerHTTPVersion: Initial peer_http_version attribute value
  MaxLineLength:   Initial max_line_length attribute value
  MaxHeaderLines:  Initial max_header_lines attribute value

The C<Host> option is also the default for C<IO::Socket::INET>'s
C<PeerAddr>.  The C<PeerPort> defaults to 80 if not provided.
The C<PeerPort> specification can also be embedded in the C<PeerAddr>
by preceding it with a ":", and closing the IPv6 address on brackets "[]" if
necessary: "192.0.2.1:80","[2001:db8::1]:80","any.example.com:80".

The C<Listen> option provided by C<IO::Socket::INET>'s constructor
method is not allowed.

If unable to connect to the given HTTP server then the constructor
returns C<undef> and $@ contains the reason.  After a successful
connect, a C<Net:HTTP> object is returned.

=item C<< $s->host >>

Get/set the default value of the C<Host> header to send.  The $host
must not be set to an empty string (or C<undef>) for HTTP/1.1.

=item C<< $s->keep_alive >>

Get/set the I<keep-alive> value.  If this value is TRUE then the
request will be sent with headers indicating that the server should try
to keep the connection open so that multiple requests can be sent.

The actual headers set will depend on the value of the C<http_version>
and C<peer_http_version> attributes.

=item C<< $s->send_te >>

Get/set the a value indicating if the request will be sent with a "TE"
header to indicate the transfer encodings that the server can choose to
use.  The list of encodings announced as accepted by this client depends
on availability of the following modules: C<Compress::Raw::Zlib> for
I<deflate>, and C<IO::Compress::Gunzip> for I<gzip>.

=item C<< $s->http_version >>

Get/set the HTTP version number that this client should announce.
This value can only be set to "1.0" or "1.1".  The default is "1.1".

=item C<< $s->peer_http_version >>

Get/set the protocol version number of our peer.  This value will
initially be "1.0", but will be updated by a successful
read_response_headers() method call.

=item C<< $s->max_line_length >>

Get/set a limit on the length of response line and response header
lines.  The default is 8192.  A value of 0 means no limit.

=item C<< $s->max_header_length >>

Get/set a limit on the number of header lines that a response can
have.  The default is 128.  A value of 0 means no limit.

=item C<< $s->format_request($method, $uri, %headers, [$content]) >>

Format a request message and return it as a string.  If the headers do
not include a C<Host> header, then a header is inserted with the value
of the C<host> attribute.  Headers like C<Connection> and
C<Keep-Alive> might also be added depending on the status of the
C<keep_alive> attribute.

If $content is given (and it is non-empty), then a C<Content-Length>
header is automatically added unless it was already present.

=item C<< $s->write_request($method, $uri, %headers, [$content]) >>

Format and send a request message.  Arguments are the same as for
format_request().  Returns true if successful.

=item C<< $s->format_chunk( $data ) >>

Returns the string to be written for the given chunk of data.

=item C<< $s->write_chunk($data) >>

Will write a new chunk of request entity body data.  This method
should only be used if the C<Transfer-Encoding> header with a value of
C<chunked> was sent in the request.  Note, writing zero-length data is
a no-op.  Use the write_chunk_eof() method to signal end of entity
body data.

Returns true if successful.

=item C<< $s->format_chunk_eof( %trailers ) >>

Returns the string to be written for signaling EOF when a
C<Transfer-Encoding> of C<chunked> is used.

=item C<< $s->write_chunk_eof( %trailers ) >>

Will write eof marker for chunked data and optional trailers.  Note
that trailers should not really be used unless is was signaled
with a C<Trailer> header.

Returns true if successful.

=item C<< ($code, $mess, %headers) = $s->read_response_headers( %opts ) >>

Read response headers from server and return it.  The $code is the 3
digit HTTP status code (see L<HTTP::Status>) and $mess is the textual
message that came with it.  Headers are then returned as key/value
pairs.  Since key letter casing is not normalized and the same key can
even occur multiple times, assigning these values directly to a hash
is not wise.  Only the $code is returned if this method is called in
scalar context.

As a side effect this method updates the 'peer_http_version'
attribute.

Options might be passed in as key/value pairs.  There are currently
only two options supported; C<laxed> and C<junk_out>.

The C<laxed> option will make read_response_headers() more forgiving
towards servers that have not learned how to speak HTTP properly.  The
C<laxed> option is a boolean flag, and is enabled by passing in a TRUE
value.  The C<junk_out> option can be used to capture bad header lines
when C<laxed> is enabled.  The value should be an array reference.
Bad header lines will be pushed onto the array.

The C<laxed> option must be specified in order to communicate with
pre-HTTP/1.0 servers that don't describe the response outcome or the
data they send back with a header block.  For these servers
peer_http_version is set to "0.9" and this method returns (200,
"Assumed OK").

The method will raise an exception (die) if the server does not speak
proper HTTP or if the C<max_line_length> or C<max_header_length>
limits are reached.  If the C<laxed> option is turned on and
C<max_line_length> and C<max_header_length> checks are turned off,
then no exception will be raised and this method will always
return a response code.

=item C<< $n = $s->read_entity_body($buf, $size); >>

Reads chunks of the entity body content.  Basically the same interface
as for read() and sysread(), but the buffer offset argument is not
supported yet.  This method should only be called after a successful
read_response_headers() call.

The return value will be C<undef> on read errors, 0 on EOF, -1 if no data
could be returned this time, otherwise the number of bytes assigned
to $buf.  The $buf is set to "" when the return value is -1.

You normally want to retry this call if this function returns either
-1 or C<undef> with C<$!> as EINTR or EAGAIN (see L<Errno>).  EINTR
can happen if the application catches signals and EAGAIN can happen if
you made the socket non-blocking.

This method will raise exceptions (die) if the server does not speak
proper HTTP.  This can only happen when reading chunked data.

=item C<< %headers = $s->get_trailers >>

After read_entity_body() has returned 0 to indicate end of the entity
body, you might call this method to pick up any trailers.

=item C<< $s->_rbuf >>

Get/set the read buffer content.  The read_response_headers() and
read_entity_body() methods use an internal buffer which they will look
for data before they actually sysread more from the socket itself.  If
they read too much, the remaining data will be left in this buffer.

=item C<< $s->_rbuf_length >>

Returns the number of bytes in the read buffer.  This should always be
the same as:

    length($s->_rbuf)

but might be more efficient.

=back

=head1 SUBCLASSING

The read_response_headers() and read_entity_body() will invoke the
sysread() method when they need more data.  Subclasses might want to
override this method to control how reading takes place.

The object itself is a glob.  Subclasses should avoid using hash key
names prefixed with C<http_> and C<io_>.

=head1 SEE ALSO

L<LWP>, L<IO::Socket::INET>, L<Net::HTTP::NB>

=head1 AUTHOR

Gisle Aas <gisle@activestate.com>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2001 by Gisle Aas.

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

=cut

__END__

# ABSTRACT: Low-level HTTP connection (client)

PK5N%[����RRRRperl5/FFI/CheckLib.pmnu��6�$package FFI::CheckLib;

use strict;
use warnings;
use File::Spec;
use List::Util 1.33 qw( any );
use Carp qw( croak carp );
use Env qw( @FFI_CHECKLIB_PATH );
use base qw( Exporter );

our @EXPORT = qw(
  find_lib
  assert_lib
  check_lib
  check_lib_or_exit
  find_lib_or_exit
  find_lib_or_die
);

our @EXPORT_OK = qw(
  which
  where
  has_symbols
);

# ABSTRACT: Check that a library is available for FFI
our $VERSION = '0.31'; # VERSION


our $system_path = [];
our $os ||= $^O;
my $try_ld_on_text = 0;

sub _homebrew_lib_path {
  require File::Which;
  return undef unless File::Which::which('brew');
  chomp(my $brew_path = (qx`brew --prefix`)[0]);
  return "$brew_path/lib";
}

sub _macports_lib_path {
  require File::Which;
  my $port_path = File::Which::which('port');
  return undef unless $port_path;
  $port_path =~ s|bin/port|lib|;
  return $port_path;
}

sub _darwin_extra_paths {
  my $pkg_managers = lc( $ENV{FFI_CHECKLIB_PACKAGE} || 'homebrew,macports' );
  return () if $pkg_managers eq 'none';
  my $supported_managers = {
      homebrew => \&_homebrew_lib_path,
      macports => \&_macports_lib_path
  };
  my @extra_paths = ();
  foreach my $pkg_manager (split( /,/, $pkg_managers )) {
    if (my $lib_path = $supported_managers->{$pkg_manager}()) {
      push @extra_paths, $lib_path;
    }
  }
  return @extra_paths;
}

my @extra_paths = ();
if($os eq 'MSWin32' || $os eq 'msys')
{
  $system_path = eval {
    require Env;
    Env->import('@PATH');
    \our @PATH;
  };
  die $@ if $@;
}
else
{
  $system_path = eval {
    require DynaLoader;
    no warnings 'once';
    \@DynaLoader::dl_library_path;
  };
  die $@ if $@;
  @extra_paths = _darwin_extra_paths() if $os eq 'darwin';
}

our $pattern = [ qr{^lib(.*?)\.so(?:\.([0-9]+(?:\.[0-9]+)*))?$} ];
our $version_split = qr/\./;

if($os eq 'cygwin')
{
  push @$pattern, qr{^cyg(.*?)(?:-([0-9])+)?\.dll$};
}
elsif($os eq 'msys')
{
  # doesn't seem as though msys uses psudo libfoo.so files
  # in the way that cygwin sometimes does.  we can revisit
  # this if we find otherwise.
  $pattern = [ qr{^msys-(.*?)(?:-([0-9])+)?\.dll$} ];
}
elsif($os eq 'MSWin32')
{
  #  handle cases like libgeos-3-7-0___.dll, libproj_9_1.dll and libgtk-2.0-0.dll
  $pattern = [ qr{^(?:lib)?(\w+?)(?:[_-]([0-9\-\._]+))?_*\.dll$}i ];
  $version_split = qr/[_\-]/;
}
elsif($os eq 'darwin')
{
  push @$pattern, qr{^lib(.*?)(?:\.([0-9]+(?:\.[0-9]+)*))?\.(?:dylib|bundle)$};
}
elsif($os eq 'linux')
{
  if(-e '/etc/redhat-release' && -x '/usr/bin/ld')
  {
    $try_ld_on_text = 1;
  }
}

sub _matches
{
  my($filename, $path) = @_;

  foreach my $regex (@$pattern)
  {
    return [
      $1,                                            # 0    capture group 1 library name
      File::Spec->catfile($path, $filename),         # 1    full path to library
      defined $2 ? (split $version_split, $2) : (),  # 2... capture group 2 library version
    ] if $filename =~ $regex;
  }
  return ();
}

sub _cmp
{
  my($A,$B) = @_;

  return $A->[0] cmp $B->[0] if $A->[0] ne $B->[0];

  my $i=2;
  while(1)
  {
    return 0  if !defined($A->[$i]) && !defined($B->[$i]);
    return -1 if !defined $A->[$i];
    return 1  if !defined $B->[$i];
    return $B->[$i] <=> $A->[$i] if $A->[$i] != $B->[$i];
    $i++;
  }
}


my $diagnostic;

sub _is_binary
{
  -B $_[0]
}

sub find_lib
{
  my(%args) = @_;

  undef $diagnostic;
  croak "find_lib requires lib argument" unless defined $args{lib};

  my $recursive = $args{_r} || $args{recursive} || 0;

  # make arguments be lists.
  foreach my $arg (qw( lib libpath symbol verify alien ))
  {
    next if ref $args{$arg} eq 'ARRAY';
    if(defined $args{$arg})
    {
      $args{$arg} = [ $args{$arg} ];
    }
    else
    {
      $args{$arg} = [];
    }
  }

  if(defined $args{systempath} && !ref($args{systempath}))
  {
    $args{systempath} = [ $args{systempath} ];
  }

  my @path = @{ $args{libpath} };
  @path = map { _recurse($_) } @path if $recursive;

  if(defined $args{systempath})
  {
    push @path, grep { defined } @{ $args{systempath} }
  }
  else
  {
    # This is a little convaluted, but:
    # 1. These are modifications of what we consider the "system" path
    #    if systempath isn't explicitly passed in as systempath
    # 2. FFI_CHECKLIB_PATH is considered an authortative modification
    #    so it goes first and overrides FFI_CHECKLIB_PACKAGE
    # 3. otherwise FFI_CHECKLIB_PACKAGE does its thing and goes on
    #    the end because homebrew does a good job of not replacing
    #    anything in the system by default.
    # 4. We finally add what we consider the "system" path to the end of
    #    the search path so that libpath will be searched first.
    my @system_path = @$system_path;
    if($ENV{FFI_CHECKLIB_PATH})
    {
      @system_path = (@FFI_CHECKLIB_PATH, @system_path);
    }
    else
    {
      foreach my $extra_path (@extra_paths)
      {
        push @path, $extra_path unless any { $_ eq $extra_path } @path;
      }
    }
    push @path, @system_path;
  }

  my $any = any { $_ eq '*' } @{ $args{lib} };
  my %missing = map { $_ => 1 } @{ $args{lib} };
  my %symbols = map { $_ => 1 } @{ $args{symbol} };
  my @found;

  delete $missing{'*'};

  alien: foreach my $alien (reverse @{ $args{alien} })
  {
    unless($alien =~ /^([A-Za-z_][A-Za-z_0-9]*)(::[A-Za-z_][A-Za-z_0-9]*)*$/)
    {
      croak "Doesn't appear to be a valid Alien name $alien";
    }
    unless(eval { $alien->can('dynamic_libs') })
    {
      {
        my $pm = "$alien.pm";
        $pm =~ s/::/\//g;
        local $@ = '';
        eval { require $pm };
        next alien if $@;
      }
      unless(eval { $alien->can('dynamic_libs') })
      {
        croak "Alien $alien doesn't provide a dynamic_libs method";
      }
    }
    unshift @path, [$alien->dynamic_libs];
  }

  foreach my $path (@path)
  {
    next if ref $path ne 'ARRAY' && ! -d $path;

    my @maybe =
      # make determinist based on names and versions
      sort { _cmp($a,$b) }
      # Filter out the items that do not match the name that we are looking for
      # Filter out any broken symbolic links
      grep { ($any || $missing{$_->[0]} ) && (-e $_->[1]) }
      ref $path eq 'ARRAY'
        ? do {
          map {
            my($v, $d, $f) = File::Spec->splitpath($_);
            _matches($f, File::Spec->catpath($v,$d,''));
          } @$path;
        }
        : do {
          my $dh;
          opendir $dh, $path;
          # get [ name, full_path ] mapping,
          # each entry is a 2 element list ref
          map { _matches($_,$path) } readdir $dh;
        };

    if($try_ld_on_text && $args{try_linker_script})
    {
      # This is tested in t/ci.t only
      @maybe = map {
        -B $_->[1] ? $_ : do {
          my($name, $so) = @$_;
          my $output = `/usr/bin/ld -t $so -o /dev/null -shared`;
          $output =~ /\((.*?lib.*\.so.*?)\)/
            ? [$name, $1]
            : die "unable to parse ld output";
        }
      } @maybe;
    }

    midloop:
    foreach my $lib (@maybe)
    {
      next unless $any || $missing{$lib->[0]};

      foreach my $verify (@{ $args{verify} })
      {
        next midloop unless $verify->(@$lib);
      }

      delete $missing{$lib->[0]};

      if(%symbols)
      {
        require DynaLoader;
        my $dll = DynaLoader::dl_load_file($lib->[1],0);
        foreach my $symbol (keys %symbols)
        {
          if(DynaLoader::dl_find_symbol($dll, $symbol) ? 1 : 0)
          {
            delete $symbols{$symbol}
          }
        }
        DynaLoader::dl_unload_file($dll);
      }

      my $found = $lib->[1];

      unless($any)
      {
        while(-l $found)
        {
          require File::Basename;
          my $dir = File::Basename::dirname($found);
          $found = File::Spec->rel2abs( readlink($found), $dir );
        }
      }

      push @found, $found;
    }
  }

  if(%missing)
  {
    my @missing = sort keys %missing;
    if(@missing > 1)
    { $diagnostic = "libraries not found: @missing" }
    else
    { $diagnostic = "library not found: @missing" }
  }
  elsif(%symbols)
  {
    my @missing = sort keys %symbols;
    if(@missing > 1)
    { $diagnostic = "symbols not found: @missing" }
    else
    { $diagnostic = "symbol not found: @missing" }
  }

  return if %symbols;
  return $found[0] unless wantarray;
  return @found;
}

sub _recurse
{
  my($dir) = @_;
  return unless -d $dir;
  my $dh;
  opendir $dh, $dir;
  my @list = grep { -d $_ } map { File::Spec->catdir($dir, $_) } grep !/^\.\.?$/, readdir $dh;
  closedir $dh;
  ($dir, map { _recurse($_) } @list);
}


sub assert_lib
{
  croak $diagnostic || 'library not found' unless check_lib(@_);
}


sub check_lib_or_exit
{
  unless(check_lib(@_))
  {
    carp $diagnostic || 'library not found';
    exit;
  }
}


sub find_lib_or_exit
{
  my(@libs) = find_lib(@_);
  unless(@libs)
  {
    carp $diagnostic || 'library not found';
    exit;
  }
  return unless @libs;
  wantarray ? @libs : $libs[0];
}


sub find_lib_or_die
{
  my(@libs) = find_lib(@_);
  unless(@libs)
  {
    croak $diagnostic || 'library not found';
  }
  return unless @libs;
  wantarray ? @libs : $libs[0];
}


sub check_lib
{
  find_lib(@_) ? 1 : 0;
}


sub which
{
  my($name) = @_;
  croak("cannot which *") if $name eq '*';
  scalar find_lib( lib => $name );
}


sub where
{
  my($name) = @_;
  $name eq '*'
    ? find_lib(lib => '*')
    : find_lib(lib => '*', verify => sub { $_[0] eq $name });
}


sub has_symbols
{
  my($path, @symbols) = @_;
  require DynaLoader;
  my $dll = DynaLoader::dl_load_file($path, 0);

  my $ok = 1;

  foreach my $symbol (@symbols)
  {
    unless(DynaLoader::dl_find_symbol($dll, $symbol))
    {
      $ok = 0;
      last;
    }
  }

  DynaLoader::dl_unload_file($dll);

  $ok;
}


sub system_path
{
  $system_path;
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

FFI::CheckLib - Check that a library is available for FFI

=head1 VERSION

version 0.31

=head1 SYNOPSIS

 use FFI::CheckLib;
 
 check_lib_or_exit( lib => 'jpeg', symbol => 'jinit_memory_mgr' );
 check_lib_or_exit( lib => [ 'iconv', 'jpeg' ] );
 
 # or prompt for path to library and then:
 print "where to find jpeg library: ";
 my $path = <STDIN>;
 check_lib_or_exit( lib => 'jpeg', libpath => $path );

=head1 DESCRIPTION

This module checks whether a particular dynamic library is available for
FFI to use. It is modeled heavily on L<Devel::CheckLib>, but will find
dynamic libraries even when development packages are not installed.  It
also provides a L<find_lib|FFI::CheckLib#find_lib> function that will
return the full path to the found dynamic library, which can be feed
directly into L<FFI::Platypus> or another FFI system.

Although intended mainly for FFI modules via L<FFI::Platypus> and
similar, this module does not actually use any FFI to do its detection
and probing.  This module does not have any non-core runtime dependencies.
The test suite does depend on L<Test2::Suite>.

=head1 FUNCTIONS

All of these take the same named parameters and are exported by default.

=head2 find_lib

 my(@libs) = find_lib(%args);

This will return a list of dynamic libraries, or empty list if none were
found.

[version 0.05]

If called in scalar context it will return the first library found.

Arguments are key value pairs with these keys:

=over 4

=item lib

Must be either a string with the name of a single library or a reference
to an array of strings of library names.  Depending on your platform,
C<CheckLib> will prepend C<lib> or append C<.dll> or C<.so> when
searching.

[version 0.11]

As a special case, if C<*> is specified then any libs found will match.

=item libpath

A string or array of additional paths to search for libraries.

=item systempath

[version 0.11]

A string or array of system paths to search for instead of letting
L<FFI::CheckLib> determine the system path.  You can set this to C<[]>
in order to not search I<any> system paths.

=item symbol

A string or a list of symbol names that must be found.

=item verify

A code reference used to verify a library really is the one that you
want.  It should take two arguments, which is the name of the library
and the full path to the library pathname.  It should return true if it
is acceptable, and false otherwise.  You can use this in conjunction
with L<FFI::Platypus> to determine if it is going to meet your needs.
Example:

 use FFI::CheckLib;
 use FFI::Platypus;
 
 my($lib) = find_lib(
   lib => 'foo',
   verify => sub {
     my($name, $libpath) = @_;
 
     my $ffi = FFI::Platypus->new;
     $ffi->lib($libpath);
 
     my $f = $ffi->function('foo_version', [] => 'int');
 
     return $f->call() >= 500; # we accept version 500 or better
   },
 );

=item recursive

[version 0.11]

Recursively search for libraries in any non-system paths (those provided
via C<libpath> above).

=item try_linker_script

[version 0.24]

Some vendors provide C<.so> files that are linker scripts that point to
the real binary shared library.  These linker scripts can be used by gcc
or clang, but are not directly usable by L<FFI::Platypus> and friends.
On select platforms, this options will use the linker command (C<ld>)
to attempt to resolve the real C<.so> for non-binary files.  Since there
is extra overhead this is off by default.

An example is libyaml on Red Hat based Linux distributions.  On Debian
these are handled with symlinks and no trickery is required.

=item alien

[version 0.25]

If no libraries can be found, try the given aliens instead.  The Alien
classes specified must provide the L<Alien::Base> interface for dynamic
libraries, which is to say they should provide a method called
C<dynamic_libs> that returns a list of dynamic libraries.

[version 0.28]

In 0.28 and later, if the L<Alien> is not installed then it will be
ignored and this module will search in system or specified directories
only.  This module I<will> still throw an exception, if the L<Alien>
doesn't look like a module name or if it does not provide a C<dynamic_libs>
method (which is implemented by all L<Alien::Base> subclasses).

[version 0.30]
[breaking change]

Starting with version 0.30, libraries provided by L<Alien>s is preferred
over the system libraries.  The original thinking was that you want to
prefer the system libraries because they are more likely to get patched
with regular system updates.  Unfortunately, the reason a module needs to
install an Alien is likely because the system library is not new enough,
so we now prefer the L<Alien>s instead.

=back

=head2 assert_lib

 assert_lib(%args);

This behaves exactly the same as L<find_lib|FFI::CheckLib#find_lib>,
except that instead of returning empty list of failure it throws an
exception.

=head2 check_lib_or_exit

 check_lib_or_exit(%args);

This behaves exactly the same as L<assert_lib|FFI::CheckLib#assert_lib>,
except that instead of dying, it warns (with exactly the same error
message) and exists.  This is intended for use in C<Makefile.PL> or
C<Build.PL>

=head2 find_lib_or_exit

[version 0.05]

 my(@libs) = find_lib_or_exit(%args);

This behaves exactly the same as L<find_lib|FFI::CheckLib#find_lib>,
except that if the library is not found, it will call exit with an
appropriate diagnostic.

=head2 find_lib_or_die

[version 0.06]

 my(@libs) = find_lib_or_die(%args);

This behaves exactly the same as L<find_lib|FFI::CheckLib#find_lib>,
except that if the library is not found, it will die with an appropriate
diagnostic.

=head2 check_lib

 my $bool = check_lib(%args);

This behaves exactly the same as L<find_lib|FFI::CheckLib#find_lib>,
except that it returns true (1) on finding the appropriate libraries or
false (0) otherwise.

=head2 which

[version 0.17]

 my $path = which($name);

Return the path to the first library that matches the given name.

Not exported by default.

=head2 where

[version 0.17]

 my @paths = where($name);

Return the paths to all the libraries that match the given name.

Not exported by default.

=head2 has_symbols

[version 0.17]

 my $bool = has_symbols($path, @symbol_names);

Returns true if I<all> of the symbols can be found in the dynamic library located
at the given path.  Can be useful in conjunction with C<verify> with C<find_lib>
above.

Not exported by default.

=head2 system_path

[version 0.20]

 my $path = FFI::CheckLib::system_path;

Returns the system path as a list reference.  On some systems, this is C<PATH>
on others it might be C<LD_LIBRARY_PATH> on still others it could be something
completely different.  So although you I<may> add items to this list, you should
probably do some careful consideration before you do so.

This function is not exportable, even on request.

=head1 ENVIRONMENT

L<FFI::CheckLib> responds to these environment variables:

=over 4

=item FFI_CHECKLIB_PACKAGE

On macOS platforms with L<Homebrew|http://brew.sh> and/or L<MacPorts|https://www.macports.org>
installed, their corresponding lib paths will be automatically appended to C<$system_path>.
In case of having both managers installed, Homebrew will appear before.

This behaviour can be overridden using the environment variable C<FFI_CHECKLIB_PACKAGE>.

Allowed values are:

- C<none>: Won't use either Homebrew's path nor MacPorts
- C<homebrew>: Will append C<$(brew --prefix)/lib> to the system paths
- C<macports>: Will append C<port>'s default lib path

A comma separated list is also valid:

 export FFI_CHECKLIB_PACKAGE=macports,homebrew

Order matters. So in this example, MacPorts' lib path appears before Homebrew's path.

=item FFI_CHECKLIB_PATH

List of directories that will be considered by L<FFI::CheckLib> as additional "system
directories".  They will be searched before other system directories but after C<libpath>.
The variable is colon separated on Unix and semicolon separated on Windows.  If you
use this variable, C<FFI_CHECKLIB_PACKAGE> will be ignored.

=item PATH

On Windows the C<PATH> environment variable will be used as a search path for
libraries.

=back

On some operating systems C<LD_LIBRARY_PATH>, C<DYLD_LIBRARY_PATH>,
C<DYLD_FALLBACK_LIBRARY_PATH> or others I<may> be used as part of the search
for dynamic libraries and I<may> be used (indirectly) by L<FFI::CheckLib>
as well.

=head1 FAQ

=over 4

=item Why not just use C<dlopen>?

Calling C<dlopen> on a library name and then C<dlclose> immediately can tell
you if you have the exact name of a library available on a system.  It does
have a number of drawbacks as well.

=over 4

=item No absolute or relative path

It only tells you that the library is I<somewhere> on the system, not having
the absolute or relative path makes it harder to generate useful diagnostics.

=item POSIX only

This doesn't work on non-POSIX systems like Microsoft Windows. If you are
using a POSIX emulation layer on Windows that provides C<dlopen>, like
Cygwin, there are a number of gotchas there as well.  Having a layer written
in Perl handles this means that developers on Unix can develop FFI that will
more likely work on these platforms without special casing them.

=item inconsistent implementations

Even on POSIX systems you have inconsistent implementations.  OpenBSD for
example don't usually include symlinks for C<.so> files meaning you need
to know the exact C<.so> version.

=item non-system directories

By default C<dlopen> only works for libraries in the system paths.  Most
platforms have a way of configuring the search for different non-system
paths, but none of them are portable, and are usually discouraged anyway.
L<Alien> and friends need to do searches for dynamic libraries in
non-system directories for C<share> installs.

=back

=item My 64-bit Perl is misconfigured and has 32-bit libraries in its search path.  Is that a bug in L<FFI::CheckLib>?

Nope.

=item The way L<FFI::CheckLib> is implemented it won't work on AIX, HP-UX, OpenVMS or Plan 9.

I know for a fact that it doesn't work on AIX I<as currently implemented>
because I used to develop on AIX in the early 2000s, and I am aware of some
of the technical challenges.  There are probably other systems that it won't
work on.  I would love to add support for these platforms.  Realistically
these platforms have a tiny market share, and absent patches from users or
the companies that own these operating systems (patches welcome), or hardware
/ CPU time donations, these platforms are unsupportable anyway.

=back

=head1 SEE ALSO

=over 4

=item L<FFI::Platypus>

Call library functions dynamically without a compiler.

=item L<Dist::Zilla::Plugin::FFI::CheckLib>

L<Dist::Zilla> plugin for this module.

=back

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Bakkiaraj Murugesan (bakkiaraj)

Dan Book (grinnz, DBOOK)

Ilya Pavlov (Ilya, ILUX)

Shawn Laffan (SLAFFAN)

Petr Písař (ppisar)

Michael R. Davis (MRDVT)

Shawn Laffan (SLAFFAN)

Carlos D. Álvaro (cdalvaro)

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2014-2022 by Graham Ollis.

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

=cut
PK5N%[4;{g��perl5/lib/core/only.pmnu��6�$package lib::core::only;

use strict;
use warnings FATAL => 'all';
use Config;

sub import {
  @INC = @Config{qw(privlibexp archlibexp)};
  return
}

=head1 NAME

lib::core::only - Remove all non-core paths from @INC to avoid site/vendor dirs

=head1 SYNOPSIS

  use lib::core::only; # now @INC contains only the two core directories

To get only the core directories plus the ones for the local::lib in scope:

  $ perl -mlocal::lib -Mlib::core::only -Mlocal::lib=~/perl5 myscript.pl

To attempt to do a self-contained build (but note this will not reliably
propagate into subprocesses, see the CAVEATS below):

  $ PERL5OPT='-mlocal::lib -Mlib::core::only -Mlocal::lib=~/perl5' cpan

Please note that it is necessary to use C<local::lib> twice for this to work.
First so that C<lib::core::only> doesn't prevent C<local::lib> from loading
(it's not currently in core) and then again after C<lib::core::only> so that
the local paths are not removed.

=head1 DESCRIPTION

lib::core::only is simply a shortcut to say "please reduce my @INC to only
the core lib and archlib (architecture-specific lib) directories of this perl".

You might want to do this to ensure a local::lib contains only the code you
need, or to test an L<App::FatPacker|App::FatPacker> tree, or to avoid known
bad vendor packages.

You might want to use this to try and install a self-contained tree of perl
modules. Be warned that that probably won't work (see L</CAVEATS>).

This module was extracted from L<local::lib|local::lib>'s --self-contained
feature, and contains the only part that ever worked. I apologise to anybody
who thought anything else did.

=head1 CAVEATS

This does B<not> propagate properly across perl invocations like local::lib's
stuff does. It can't. It's only a module import, so it B<only affects the
specific perl VM instance in which you load and import() it>.

If you want to cascade it across invocations, you can set the PERL5OPT
environment variable to '-Mlib::core::only' and it'll sort of work. But be
aware that taint mode ignores this, so some modules' build and test code
probably will as well.

You also need to be aware that perl's command line options are not processed
in order - -I options take effect before -M options, so

  perl -Mlib::core::only -Ilib

is unlike to do what you want - it's exactly equivalent to:

  perl -Mlib::core::only

If you want to combine a core-only @INC with additional paths, you need to
add the additional paths using -M options and the L<lib|lib> module:

  perl -Mlib::core::only -Mlib=lib

  # or if you're trying to test compiled code:

  perl -Mlib::core::only -Mblib

For more information on the impossibility of sanely propagating this across
module builds without help from the build program, see
L<http://www.shadowcat.co.uk/blog/matt-s-trout/tainted-love> - and for ways
to achieve the old --self-contained feature's results, look at
L<App::FatPacker|App::FatPacker>'s tree function, and at
L<App::cpanminus|cpanm>'s --local-lib-contained feature.

=head1 AUTHOR

Matt S. Trout <mst@shadowcat.co.uk>

=head1 LICENSE

This library is free software under the same terms as perl itself.

=head1 COPYRIGHT

(c) 2010 the lib::core::only L</AUTHOR> as specified above.

=cut

1;
PK5N%[�perl5/TimeDate.pmnu��6�$package TimeDate;

use vars qw($VERSION);

$VERSION = "1.21";

=pod

This is an empty module which is just there to get ownership on TimeDate
using first-come permissions from PAUSE.

This was required during the release of 1.21 for transferring ownership.

=cut

1;
PK5N%[m���perl5/LWP/MediaTypes.pmnu��6�$package LWP::MediaTypes;

require Exporter;
@ISA = qw(Exporter);
@EXPORT = qw(guess_media_type media_suffix);
@EXPORT_OK = qw(add_type add_encoding read_media_types);
our $VERSION = '6.04';

use strict;
use Scalar::Util qw(blessed);
use Carp qw(croak);

# note: These hashes will also be filled with the entries found in
# the 'media.types' file.

my %suffixType = (
    'txt'   => 'text/plain',
    'html'  => 'text/html',
    'gif'   => 'image/gif',
    'jpg'   => 'image/jpeg',
    'xml'   => 'text/xml',
);

my %suffixExt = (
    'text/plain' => 'txt',
    'text/html'  => 'html',
    'image/gif'  => 'gif',
    'image/jpeg' => 'jpg',
    'text/xml'   => 'xml',
);

#XXX: there should be some way to define this in the media.types files.
my %suffixEncoding = (
    'Z'   => 'compress',
    'gz'  => 'gzip',
    'hqx' => 'x-hqx',
    'uu'  => 'x-uuencode',
    'z'   => 'x-pack',
    'bz2' => 'x-bzip2',
);

read_media_types();



sub guess_media_type
{
    my($file, $header) = @_;
    return undef unless defined $file;

    my $fullname;
    if (ref $file) {
        croak("Unable to determine filetype on unblessed refs") unless blessed($file);
        if ($file->can('path')) {
            $file = $file->path;
        }
        elsif ($file->can('filename')) {
            $fullname = $file->filename;
        }
        else {
            $fullname = "" . $file;
        }
    }
    else {
	$fullname = $file;  # enable peek at actual file
    }

    my @encoding = ();
    my $ct = undef;
    for (file_exts($file)) {
	# first check this dot part as encoding spec
	if (exists $suffixEncoding{$_}) {
	    unshift(@encoding, $suffixEncoding{$_});
	    next;
	}
	if (exists $suffixEncoding{lc $_}) {
	    unshift(@encoding, $suffixEncoding{lc $_});
	    next;
	}

	# check content-type
	if (exists $suffixType{$_}) {
	    $ct = $suffixType{$_};
	    last;
	}
	if (exists $suffixType{lc $_}) {
	    $ct = $suffixType{lc $_};
	    last;
	}

	# don't know nothing about this dot part, bail out
	last;
    }
    unless (defined $ct) {
	# Take a look at the file
	if (defined $fullname) {
	    $ct = (-T $fullname) ? "text/plain" : "application/octet-stream";
	}
	else {
	    $ct = "application/octet-stream";
	}
    }

    if ($header) {
	$header->header('Content-Type' => $ct);
	$header->header('Content-Encoding' => \@encoding) if @encoding;
    }

    wantarray ? ($ct, @encoding) : $ct;
}


sub media_suffix {
    if (!wantarray && @_ == 1 && $_[0] !~ /\*/) {
	return $suffixExt{lc $_[0]};
    }
    my(@type) = @_;
    my(@suffix, $ext, $type);
    foreach (@type) {
	if (s/\*/.*/) {
	    while(($ext,$type) = each(%suffixType)) {
		push(@suffix, $ext) if $type =~ /^$_$/i;
	    }
	}
	else {
	    my $ltype = lc $_;
	    while(($ext,$type) = each(%suffixType)) {
		push(@suffix, $ext) if lc $type eq $ltype;
	    }
	}
    }
    wantarray ? @suffix : $suffix[0];
}


sub file_exts
{
    require File::Basename;
    my @parts = reverse split(/\./, File::Basename::basename($_[0]));
    pop(@parts);        # never consider first part
    @parts;
}


sub add_type
{
    my($type, @exts) = @_;
    for my $ext (@exts) {
	$ext =~ s/^\.//;
	$suffixType{$ext} = $type;
    }
    $suffixExt{lc $type} = $exts[0] if @exts;
}


sub add_encoding
{
    my($type, @exts) = @_;
    for my $ext (@exts) {
	$ext =~ s/^\.//;
	$suffixEncoding{$ext} = $type;
    }
}


sub read_media_types
{
    my(@files) = @_;

    local($/, $_) = ("\n", undef);  # ensure correct $INPUT_RECORD_SEPARATOR

    my @priv_files = ();
    push(@priv_files, "$ENV{HOME}/.media.types", "$ENV{HOME}/.mime.types")
	if defined $ENV{HOME};  # Some doesn't have a home (for instance Win32)

    # Try to locate "media.types" file, and initialize %suffixType from it
    my $typefile;
    unless (@files) {
	@files = map {"$_/LWP/media.types"} @INC;
	push @files, @priv_files;
    }
    for $typefile (@files) {
	local(*TYPE);
	open(TYPE, $typefile) || next;
	while (<TYPE>) {
	    next if /^\s*#/; # comment line
	    next if /^\s*$/; # blank line
	    s/#.*//;         # remove end-of-line comments
	    my($type, @exts) = split(' ', $_);
	    add_type($type, @exts);
	}
	close(TYPE);
    }
}

1;


__END__

=head1 NAME

LWP::MediaTypes - guess media type for a file or a URL

=head1 SYNOPSIS

 use LWP::MediaTypes qw(guess_media_type);
 $type = guess_media_type("/tmp/foo.gif");

=head1 DESCRIPTION

This module provides functions for handling media (also known as
MIME) types and encodings.  The mapping from file extensions to media
types is defined by the F<media.types> file.  If the F<~/.media.types>
file exists it is used instead.
For backwards compatibility we will also look for F<~/.mime.types>.

The following functions are exported by default:

=over 4

=item guess_media_type( $filename )

=item guess_media_type( $uri )

=item guess_media_type( $filename_or_object, $header_to_modify )

This function tries to guess media type and encoding for a file or objects that
support the a C<path> or C<filename> method, eg, L<URI> or L<File::Temp> objects.
When an object does not support either method, it will be stringified to
determine the filename.
It returns the content type, which is a string like C<"text/html">.
In array context it also returns any content encodings applied (in the
order used to encode the file).  You can pass a URI object
reference, instead of the file name.

If the type can not be deduced from looking at the file name,
then guess_media_type() will let the C<-T> Perl operator take a look.
If this works (and C<-T> returns a TRUE value) then we return
I<text/plain> as the type, otherwise we return
I<application/octet-stream> as the type.

The optional second argument should be a reference to a HTTP::Headers
object or any object that implements the $obj->header method in a
similar way.  When it is present the values of the
'Content-Type' and 'Content-Encoding' will be set for this header.

=item media_suffix( $type, ... )

This function will return all suffixes that can be used to denote the
specified media type(s).  Wildcard types can be used.  In a scalar
context it will return the first suffix found. Examples:

  @suffixes = media_suffix('image/*', 'audio/basic');
  $suffix = media_suffix('text/html');

=back

The following functions are only exported by explicit request:

=over 4

=item add_type( $type, @exts )

Associate a list of file extensions with the given media type.
Example:

    add_type("x-world/x-vrml" => qw(wrl vrml));

=item add_encoding( $type, @ext )

Associate a list of file extensions with an encoding type.
Example:

 add_encoding("x-gzip" => "gz");

=item read_media_types( @files )

Parse media types files and add the type mappings found there.
Example:

    read_media_types("conf/mime.types");

=back

=head1 COPYRIGHT

Copyright 1995-1999 Gisle Aas.

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

PK5N%[)l5����perl5/LWP/media.typesnu��6�$# This file maps Internet media types to unique file extension(s).
# Although created for httpd, this file is used by many software systems
# and has been placed in the public domain for unlimited redisribution.
#
# The table below contains both registered and (common) unregistered types.
# A type that has no unique extension can be ignored -- they are listed
# here to guide configurations toward known types and to make it easier to
# identify "new" types.  File extensions are also commonly used to indicate
# content languages and encodings, so choose them carefully.
#
# Internet media types should be registered as described in RFC 4288.
# The registry is at <http://www.iana.org/assignments/media-types/>.
#
# MIME type (lowercased)			Extensions
# ============================================	==========
# application/1d-interleaved-parityfec
# application/3gpp-ims+xml
# application/activemessage
application/andrew-inset			ez
# application/applefile
application/applixware				aw
application/atom+xml				atom
application/atomcat+xml				atomcat
# application/atomicmail
application/atomsvc+xml				atomsvc
# application/auth-policy+xml
# application/batch-smtp
# application/beep+xml
# application/cals-1840
application/ccxml+xml				ccxml
application/cdmi-capability			cdmia
application/cdmi-container			cdmic
application/cdmi-domain				cdmid
application/cdmi-object				cdmio
application/cdmi-queue				cdmiq
# application/cea-2018+xml
# application/cellml+xml
# application/cfw
# application/cnrp+xml
# application/commonground
# application/conference-info+xml
# application/cpl+xml
# application/csta+xml
# application/cstadata+xml
application/cu-seeme				cu
# application/cybercash
application/davmount+xml			davmount
# application/dca-rft
# application/dec-dx
# application/dialog-info+xml
# application/dicom
# application/dns
# application/dskpp+xml
application/dssc+der				dssc
application/dssc+xml				xdssc
# application/dvcs
application/ecmascript				ecma
# application/edi-consent
# application/edi-x12
# application/edifact
application/emma+xml				emma
# application/epp+xml
application/epub+zip				epub
# application/eshop
# application/example
application/exi					exi
# application/fastinfoset
# application/fastsoap
# application/fits
application/font-tdpfr				pfr
# application/framework-attributes+xml
# application/h224
# application/held+xml
# application/http
application/hyperstudio				stk
# application/ibe-key-request+xml
# application/ibe-pkg-reply+xml
# application/ibe-pp-data
# application/iges
# application/im-iscomposing+xml
# application/index
# application/index.cmd
# application/index.obj
# application/index.response
# application/index.vnd
# application/iotp
application/ipfix				ipfix
# application/ipp
# application/isup
application/java-archive			jar
application/java-serialized-object		ser
application/java-vm				class
application/javascript				js
application/json				json
# application/kpml-request+xml
# application/kpml-response+xml
application/lost+xml				lostxml
application/mac-binhex40			hqx
application/mac-compactpro			cpt
# application/macwriteii
application/mads+xml				mads
application/marc				mrc
application/marcxml+xml				mrcx
application/mathematica				ma nb mb
# application/mathml-content+xml
# application/mathml-presentation+xml
application/mathml+xml				mathml
# application/mbms-associated-procedure-description+xml
# application/mbms-deregister+xml
# application/mbms-envelope+xml
# application/mbms-msk+xml
# application/mbms-msk-response+xml
# application/mbms-protection-description+xml
# application/mbms-reception-report+xml
# application/mbms-register+xml
# application/mbms-register-response+xml
# application/mbms-user-service-description+xml
application/mbox				mbox
# application/media_control+xml
application/mediaservercontrol+xml		mscml
application/metalink4+xml			meta4
application/mets+xml				mets
# application/mikey
application/mods+xml				mods
# application/moss-keys
# application/moss-signature
# application/mosskey-data
# application/mosskey-request
application/mp21				m21 mp21
application/mp4					mp4s
# application/mpeg4-generic
# application/mpeg4-iod
# application/mpeg4-iod-xmt
# application/msc-ivr+xml
# application/msc-mixer+xml
application/msword				doc dot
application/mxf					mxf
# application/nasdata
# application/news-checkgroups
# application/news-groupinfo
# application/news-transmission
# application/nss
# application/ocsp-request
# application/ocsp-response
application/octet-stream	bin dms lha lrf lzh so iso dmg dist distz pkg bpk dump elc deploy
application/oda					oda
application/oebps-package+xml			opf
application/ogg					ogx
application/onenote				onetoc onetoc2 onetmp onepkg
# application/parityfec
application/patch-ops-error+xml			xer
application/pdf					pdf
application/pgp-encrypted			pgp
# application/pgp-keys
application/pgp-signature			asc sig
application/pics-rules				prf
# application/pidf+xml
# application/pidf-diff+xml
application/pkcs10				p10
application/pkcs7-mime				p7m p7c
application/pkcs7-signature			p7s
application/pkcs8				p8
application/pkix-attr-cert			ac
application/pkix-cert				cer
application/pkix-crl				crl
application/pkix-pkipath			pkipath
application/pkixcmp				pki
application/pls+xml				pls
# application/poc-settings+xml
application/postscript				ai eps ps
# application/prs.alvestrand.titrax-sheet
application/prs.cww				cww
# application/prs.nprend
# application/prs.plucker
# application/prs.rdf-xml-crypt
# application/prs.xsf+xml
application/pskc+xml				pskcxml
# application/qsig
application/rdf+xml				rdf
application/reginfo+xml				rif
application/relax-ng-compact-syntax		rnc
# application/remote-printing
application/resource-lists+xml			rl
application/resource-lists-diff+xml		rld
# application/riscos
# application/rlmi+xml
application/rls-services+xml			rs
application/rsd+xml				rsd
application/rss+xml				rss
application/rtf					rtf
# application/rtx
# application/samlassertion+xml
# application/samlmetadata+xml
application/sbml+xml				sbml
application/scvp-cv-request			scq
application/scvp-cv-response			scs
application/scvp-vp-request			spq
application/scvp-vp-response			spp
application/sdp					sdp
# application/set-payment
application/set-payment-initiation		setpay
# application/set-registration
application/set-registration-initiation		setreg
# application/sgml
# application/sgml-open-catalog
application/shf+xml				shf
# application/sieve
# application/simple-filter+xml
# application/simple-message-summary
# application/simplesymbolcontainer
# application/slate
# application/smil
application/smil+xml				smi smil
# application/soap+fastinfoset
# application/soap+xml
application/sparql-query			rq
application/sparql-results+xml			srx
# application/spirits-event+xml
application/srgs				gram
application/srgs+xml				grxml
application/sru+xml				sru
application/ssml+xml				ssml
# application/tamp-apex-update
# application/tamp-apex-update-confirm
# application/tamp-community-update
# application/tamp-community-update-confirm
# application/tamp-error
# application/tamp-sequence-adjust
# application/tamp-sequence-adjust-confirm
# application/tamp-status-query
# application/tamp-status-response
# application/tamp-update
# application/tamp-update-confirm
application/tei+xml				tei teicorpus
application/thraud+xml				tfi
# application/timestamp-query
# application/timestamp-reply
application/timestamped-data			tsd
# application/tve-trigger
# application/ulpfec
# application/vemmi
# application/vividence.scriptfile
# application/vnd.3gpp.bsf+xml
application/vnd.3gpp.pic-bw-large		plb
application/vnd.3gpp.pic-bw-small		psb
application/vnd.3gpp.pic-bw-var			pvb
# application/vnd.3gpp.sms
# application/vnd.3gpp2.bcmcsinfo+xml
# application/vnd.3gpp2.sms
application/vnd.3gpp2.tcap			tcap
application/vnd.3m.post-it-notes		pwn
application/vnd.accpac.simply.aso		aso
application/vnd.accpac.simply.imp		imp
application/vnd.acucobol			acu
application/vnd.acucorp				atc acutc
application/vnd.adobe.air-application-installer-package+zip	air
application/vnd.adobe.fxp			fxp fxpl
# application/vnd.adobe.partial-upload
application/vnd.adobe.xdp+xml			xdp
application/vnd.adobe.xfdf			xfdf
# application/vnd.aether.imp
# application/vnd.ah-barcode
application/vnd.ahead.space			ahead
application/vnd.airzip.filesecure.azf		azf
application/vnd.airzip.filesecure.azs		azs
application/vnd.amazon.ebook			azw
application/vnd.americandynamics.acc		acc
application/vnd.amiga.ami			ami
# application/vnd.amundsen.maze+xml
application/vnd.android.package-archive		apk
application/vnd.anser-web-certificate-issue-initiation	cii
application/vnd.anser-web-funds-transfer-initiation	fti
application/vnd.antix.game-component		atx
application/vnd.apple.installer+xml		mpkg
application/vnd.apple.mpegurl			m3u8
# application/vnd.arastra.swi
application/vnd.aristanetworks.swi		swi
application/vnd.audiograph			aep
# application/vnd.autopackage
# application/vnd.avistar+xml
application/vnd.blueice.multipass		mpm
# application/vnd.bluetooth.ep.oob
application/vnd.bmi				bmi
application/vnd.businessobjects			rep
# application/vnd.cab-jscript
# application/vnd.canon-cpdl
# application/vnd.canon-lips
# application/vnd.cendio.thinlinc.clientconf
application/vnd.chemdraw+xml			cdxml
application/vnd.chipnuts.karaoke-mmd		mmd
application/vnd.cinderella			cdy
# application/vnd.cirpack.isdn-ext
application/vnd.claymore			cla
application/vnd.cloanto.rp9			rp9
application/vnd.clonk.c4group			c4g c4d c4f c4p c4u
application/vnd.cluetrust.cartomobile-config		c11amc
application/vnd.cluetrust.cartomobile-config-pkg	c11amz
# application/vnd.commerce-battelle
application/vnd.commonspace			csp
application/vnd.contact.cmsg			cdbcmsg
application/vnd.cosmocaller			cmc
application/vnd.crick.clicker			clkx
application/vnd.crick.clicker.keyboard		clkk
application/vnd.crick.clicker.palette		clkp
application/vnd.crick.clicker.template		clkt
application/vnd.crick.clicker.wordbank		clkw
application/vnd.criticaltools.wbs+xml		wbs
application/vnd.ctc-posml			pml
# application/vnd.ctct.ws+xml
# application/vnd.cups-pdf
# application/vnd.cups-postscript
application/vnd.cups-ppd			ppd
# application/vnd.cups-raster
# application/vnd.cups-raw
application/vnd.curl.car			car
application/vnd.curl.pcurl			pcurl
# application/vnd.cybank
application/vnd.data-vision.rdz			rdz
application/vnd.dece.data			uvf uvvf uvd uvvd
application/vnd.dece.ttml+xml			uvt uvvt
application/vnd.dece.unspecified		uvx uvvx
application/vnd.denovo.fcselayout-link		fe_launch
# application/vnd.dir-bi.plate-dl-nosuffix
application/vnd.dna				dna
application/vnd.dolby.mlp			mlp
# application/vnd.dolby.mobile.1
# application/vnd.dolby.mobile.2
application/vnd.dpgraph				dpg
application/vnd.dreamfactory			dfac
application/vnd.dvb.ait				ait
# application/vnd.dvb.dvbj
# application/vnd.dvb.esgcontainer
# application/vnd.dvb.ipdcdftnotifaccess
# application/vnd.dvb.ipdcesgaccess
# application/vnd.dvb.ipdcesgaccess2
# application/vnd.dvb.ipdcesgpdd
# application/vnd.dvb.ipdcroaming
# application/vnd.dvb.iptv.alfec-base
# application/vnd.dvb.iptv.alfec-enhancement
# application/vnd.dvb.notif-aggregate-root+xml
# application/vnd.dvb.notif-container+xml
# application/vnd.dvb.notif-generic+xml
# application/vnd.dvb.notif-ia-msglist+xml
# application/vnd.dvb.notif-ia-registration-request+xml
# application/vnd.dvb.notif-ia-registration-response+xml
# application/vnd.dvb.notif-init+xml
# application/vnd.dvb.pfr
application/vnd.dvb.service			svc
# application/vnd.dxr
application/vnd.dynageo				geo
# application/vnd.easykaraoke.cdgdownload
# application/vnd.ecdis-update
application/vnd.ecowin.chart			mag
# application/vnd.ecowin.filerequest
# application/vnd.ecowin.fileupdate
# application/vnd.ecowin.series
# application/vnd.ecowin.seriesrequest
# application/vnd.ecowin.seriesupdate
# application/vnd.emclient.accessrequest+xml
application/vnd.enliven				nml
application/vnd.epson.esf			esf
application/vnd.epson.msf			msf
application/vnd.epson.quickanime		qam
application/vnd.epson.salt			slt
application/vnd.epson.ssf			ssf
# application/vnd.ericsson.quickcall
application/vnd.eszigno3+xml			es3 et3
# application/vnd.etsi.aoc+xml
# application/vnd.etsi.cug+xml
# application/vnd.etsi.iptvcommand+xml
# application/vnd.etsi.iptvdiscovery+xml
# application/vnd.etsi.iptvprofile+xml
# application/vnd.etsi.iptvsad-bc+xml
# application/vnd.etsi.iptvsad-cod+xml
# application/vnd.etsi.iptvsad-npvr+xml
# application/vnd.etsi.iptvservice+xml
# application/vnd.etsi.iptvsync+xml
# application/vnd.etsi.iptvueprofile+xml
# application/vnd.etsi.mcid+xml
# application/vnd.etsi.overload-control-policy-dataset+xml
# application/vnd.etsi.sci+xml
# application/vnd.etsi.simservs+xml
# application/vnd.etsi.tsl+xml
# application/vnd.etsi.tsl.der
# application/vnd.eudora.data
application/vnd.ezpix-album			ez2
application/vnd.ezpix-package			ez3
# application/vnd.f-secure.mobile
application/vnd.fdf				fdf
application/vnd.fdsn.mseed			mseed
application/vnd.fdsn.seed			seed dataless
# application/vnd.ffsns
# application/vnd.fints
application/vnd.flographit			gph
application/vnd.fluxtime.clip			ftc
# application/vnd.font-fontforge-sfd
application/vnd.framemaker			fm frame maker book
application/vnd.frogans.fnc			fnc
application/vnd.frogans.ltf			ltf
application/vnd.fsc.weblaunch			fsc
application/vnd.fujitsu.oasys			oas
application/vnd.fujitsu.oasys2			oa2
application/vnd.fujitsu.oasys3			oa3
application/vnd.fujitsu.oasysgp			fg5
application/vnd.fujitsu.oasysprs		bh2
# application/vnd.fujixerox.art-ex
# application/vnd.fujixerox.art4
# application/vnd.fujixerox.hbpl
application/vnd.fujixerox.ddd			ddd
application/vnd.fujixerox.docuworks		xdw
application/vnd.fujixerox.docuworks.binder	xbd
# application/vnd.fut-misnet
application/vnd.fuzzysheet			fzs
application/vnd.genomatix.tuxedo		txd
# application/vnd.geocube+xml
application/vnd.geogebra.file			ggb
application/vnd.geogebra.tool			ggt
application/vnd.geometry-explorer		gex gre
application/vnd.geonext				gxt
application/vnd.geoplan				g2w
application/vnd.geospace			g3w
# application/vnd.globalplatform.card-content-mgt
# application/vnd.globalplatform.card-content-mgt-response
application/vnd.gmx				gmx
application/vnd.google-earth.kml+xml		kml
application/vnd.google-earth.kmz		kmz
application/vnd.grafeq				gqf gqs
# application/vnd.gridmp
application/vnd.groove-account			gac
application/vnd.groove-help			ghf
application/vnd.groove-identity-message		gim
application/vnd.groove-injector			grv
application/vnd.groove-tool-message		gtm
application/vnd.groove-tool-template		tpl
application/vnd.groove-vcard			vcg
application/vnd.hal+xml				hal
application/vnd.handheld-entertainment+xml	zmm
application/vnd.hbci				hbci
# application/vnd.hcl-bireports
application/vnd.hhe.lesson-player		les
application/vnd.hp-hpgl				hpgl
application/vnd.hp-hpid				hpid
application/vnd.hp-hps				hps
application/vnd.hp-jlyt				jlt
application/vnd.hp-pcl				pcl
application/vnd.hp-pclxl			pclxl
# application/vnd.httphone
application/vnd.hydrostatix.sof-data		sfd-hdstx
application/vnd.hzn-3d-crossword		x3d
# application/vnd.ibm.afplinedata
# application/vnd.ibm.electronic-media
application/vnd.ibm.minipay			mpy
application/vnd.ibm.modcap			afp listafp list3820
application/vnd.ibm.rights-management		irm
application/vnd.ibm.secure-container		sc
application/vnd.iccprofile			icc icm
application/vnd.igloader			igl
application/vnd.immervision-ivp			ivp
application/vnd.immervision-ivu			ivu
# application/vnd.informedcontrol.rms+xml
# application/vnd.informix-visionary
# application/vnd.infotech.project
# application/vnd.infotech.project+xml
application/vnd.insors.igm			igm
application/vnd.intercon.formnet		xpw xpx
application/vnd.intergeo			i2g
# application/vnd.intertrust.digibox
# application/vnd.intertrust.nncp
application/vnd.intu.qbo			qbo
application/vnd.intu.qfx			qfx
# application/vnd.iptc.g2.conceptitem+xml
# application/vnd.iptc.g2.knowledgeitem+xml
# application/vnd.iptc.g2.newsitem+xml
# application/vnd.iptc.g2.packageitem+xml
application/vnd.ipunplugged.rcprofile		rcprofile
application/vnd.irepository.package+xml		irp
application/vnd.is-xpr				xpr
application/vnd.isac.fcs			fcs
application/vnd.jam				jam
# application/vnd.japannet-directory-service
# application/vnd.japannet-jpnstore-wakeup
# application/vnd.japannet-payment-wakeup
# application/vnd.japannet-registration
# application/vnd.japannet-registration-wakeup
# application/vnd.japannet-setstore-wakeup
# application/vnd.japannet-verification
# application/vnd.japannet-verification-wakeup
application/vnd.jcp.javame.midlet-rms		rms
application/vnd.jisp				jisp
application/vnd.joost.joda-archive		joda
application/vnd.kahootz				ktz ktr
application/vnd.kde.karbon			karbon
application/vnd.kde.kchart			chrt
application/vnd.kde.kformula			kfo
application/vnd.kde.kivio			flw
application/vnd.kde.kontour			kon
application/vnd.kde.kpresenter			kpr kpt
application/vnd.kde.kspread			ksp
application/vnd.kde.kword			kwd kwt
application/vnd.kenameaapp			htke
application/vnd.kidspiration			kia
application/vnd.kinar				kne knp
application/vnd.koan				skp skd skt skm
application/vnd.kodak-descriptor		sse
application/vnd.las.las+xml			lasxml
# application/vnd.liberty-request+xml
application/vnd.llamagraphics.life-balance.desktop	lbd
application/vnd.llamagraphics.life-balance.exchange+xml	lbe
application/vnd.lotus-1-2-3			123
application/vnd.lotus-approach			apr
application/vnd.lotus-freelance			pre
application/vnd.lotus-notes			nsf
application/vnd.lotus-organizer			org
application/vnd.lotus-screencam			scm
application/vnd.lotus-wordpro			lwp
application/vnd.macports.portpkg		portpkg
# application/vnd.marlin.drm.actiontoken+xml
# application/vnd.marlin.drm.conftoken+xml
# application/vnd.marlin.drm.license+xml
# application/vnd.marlin.drm.mdcf
application/vnd.mcd				mcd
application/vnd.medcalcdata			mc1
application/vnd.mediastation.cdkey		cdkey
# application/vnd.meridian-slingshot
application/vnd.mfer				mwf
application/vnd.mfmp				mfm
application/vnd.micrografx.flo			flo
application/vnd.micrografx.igx			igx
application/vnd.mif				mif
# application/vnd.minisoft-hp3000-save
# application/vnd.mitsubishi.misty-guard.trustweb
application/vnd.mobius.daf			daf
application/vnd.mobius.dis			dis
application/vnd.mobius.mbk			mbk
application/vnd.mobius.mqy			mqy
application/vnd.mobius.msl			msl
application/vnd.mobius.plc			plc
application/vnd.mobius.txf			txf
application/vnd.mophun.application		mpn
application/vnd.mophun.certificate		mpc
# application/vnd.motorola.flexsuite
# application/vnd.motorola.flexsuite.adsi
# application/vnd.motorola.flexsuite.fis
# application/vnd.motorola.flexsuite.gotap
# application/vnd.motorola.flexsuite.kmr
# application/vnd.motorola.flexsuite.ttc
# application/vnd.motorola.flexsuite.wem
# application/vnd.motorola.iprm
application/vnd.mozilla.xul+xml			xul
application/vnd.ms-artgalry			cil
# application/vnd.ms-asf
application/vnd.ms-cab-compressed		cab
application/vnd.ms-excel			xls xlm xla xlc xlt xlw
application/vnd.ms-excel.addin.macroenabled.12		xlam
application/vnd.ms-excel.sheet.binary.macroenabled.12	xlsb
application/vnd.ms-excel.sheet.macroenabled.12		xlsm
application/vnd.ms-excel.template.macroenabled.12	xltm
application/vnd.ms-fontobject			eot
application/vnd.ms-htmlhelp			chm
application/vnd.ms-ims				ims
application/vnd.ms-lrm				lrm
# application/vnd.ms-office.activex+xml
application/vnd.ms-officetheme			thmx
application/vnd.ms-pki.seccat			cat
application/vnd.ms-pki.stl			stl
# application/vnd.ms-playready.initiator+xml
application/vnd.ms-powerpoint			ppt pps pot
application/vnd.ms-powerpoint.addin.macroenabled.12		ppam
application/vnd.ms-powerpoint.presentation.macroenabled.12	pptm
application/vnd.ms-powerpoint.slide.macroenabled.12		sldm
application/vnd.ms-powerpoint.slideshow.macroenabled.12		ppsm
application/vnd.ms-powerpoint.template.macroenabled.12		potm
application/vnd.ms-project			mpp mpt
# application/vnd.ms-tnef
# application/vnd.ms-wmdrm.lic-chlg-req
# application/vnd.ms-wmdrm.lic-resp
# application/vnd.ms-wmdrm.meter-chlg-req
# application/vnd.ms-wmdrm.meter-resp
application/vnd.ms-word.document.macroenabled.12	docm
application/vnd.ms-word.template.macroenabled.12	dotm
application/vnd.ms-works			wps wks wcm wdb
application/vnd.ms-wpl				wpl
application/vnd.ms-xpsdocument			xps
application/vnd.mseq				mseq
# application/vnd.msign
# application/vnd.multiad.creator
# application/vnd.multiad.creator.cif
# application/vnd.music-niff
application/vnd.musician			mus
application/vnd.muvee.style			msty
# application/vnd.ncd.control
# application/vnd.ncd.reference
# application/vnd.nervana
# application/vnd.netfpx
application/vnd.neurolanguage.nlu		nlu
application/vnd.noblenet-directory		nnd
application/vnd.noblenet-sealer			nns
application/vnd.noblenet-web			nnw
# application/vnd.nokia.catalogs
# application/vnd.nokia.conml+wbxml
# application/vnd.nokia.conml+xml
# application/vnd.nokia.isds-radio-presets
# application/vnd.nokia.iptv.config+xml
# application/vnd.nokia.landmark+wbxml
# application/vnd.nokia.landmark+xml
# application/vnd.nokia.landmarkcollection+xml
# application/vnd.nokia.n-gage.ac+xml
application/vnd.nokia.n-gage.data		ngdat
application/vnd.nokia.n-gage.symbian.install	n-gage
# application/vnd.nokia.ncd
# application/vnd.nokia.pcd+wbxml
# application/vnd.nokia.pcd+xml
application/vnd.nokia.radio-preset		rpst
application/vnd.nokia.radio-presets		rpss
application/vnd.novadigm.edm			edm
application/vnd.novadigm.edx			edx
application/vnd.novadigm.ext			ext
# application/vnd.ntt-local.file-transfer
# application/vnd.ntt-local.sip-ta_remote
# application/vnd.ntt-local.sip-ta_tcp_stream
application/vnd.oasis.opendocument.chart		odc
application/vnd.oasis.opendocument.chart-template	otc
application/vnd.oasis.opendocument.database		odb
application/vnd.oasis.opendocument.formula		odf
application/vnd.oasis.opendocument.formula-template	odft
application/vnd.oasis.opendocument.graphics		odg
application/vnd.oasis.opendocument.graphics-template	otg
application/vnd.oasis.opendocument.image		odi
application/vnd.oasis.opendocument.image-template	oti
application/vnd.oasis.opendocument.presentation		odp
application/vnd.oasis.opendocument.presentation-template	otp
application/vnd.oasis.opendocument.spreadsheet		ods
application/vnd.oasis.opendocument.spreadsheet-template	ots
application/vnd.oasis.opendocument.text			odt
application/vnd.oasis.opendocument.text-master		odm
application/vnd.oasis.opendocument.text-template	ott
application/vnd.oasis.opendocument.text-web		oth
# application/vnd.obn
# application/vnd.oipf.contentaccessdownload+xml
# application/vnd.oipf.contentaccessstreaming+xml
# application/vnd.oipf.cspg-hexbinary
# application/vnd.oipf.dae.svg+xml
# application/vnd.oipf.dae.xhtml+xml
# application/vnd.oipf.mippvcontrolmessage+xml
# application/vnd.oipf.pae.gem
# application/vnd.oipf.spdiscovery+xml
# application/vnd.oipf.spdlist+xml
# application/vnd.oipf.ueprofile+xml
# application/vnd.oipf.userprofile+xml
application/vnd.olpc-sugar			xo
# application/vnd.oma-scws-config
# application/vnd.oma-scws-http-request
# application/vnd.oma-scws-http-response
# application/vnd.oma.bcast.associated-procedure-parameter+xml
# application/vnd.oma.bcast.drm-trigger+xml
# application/vnd.oma.bcast.imd+xml
# application/vnd.oma.bcast.ltkm
# application/vnd.oma.bcast.notification+xml
# application/vnd.oma.bcast.provisioningtrigger
# application/vnd.oma.bcast.sgboot
# application/vnd.oma.bcast.sgdd+xml
# application/vnd.oma.bcast.sgdu
# application/vnd.oma.bcast.simple-symbol-container
# application/vnd.oma.bcast.smartcard-trigger+xml
# application/vnd.oma.bcast.sprov+xml
# application/vnd.oma.bcast.stkm
# application/vnd.oma.cab-address-book+xml
# application/vnd.oma.cab-pcc+xml
# application/vnd.oma.dcd
# application/vnd.oma.dcdc
application/vnd.oma.dd2+xml			dd2
# application/vnd.oma.drm.risd+xml
# application/vnd.oma.group-usage-list+xml
# application/vnd.oma.poc.detailed-progress-report+xml
# application/vnd.oma.poc.final-report+xml
# application/vnd.oma.poc.groups+xml
# application/vnd.oma.poc.invocation-descriptor+xml
# application/vnd.oma.poc.optimized-progress-report+xml
# application/vnd.oma.push
# application/vnd.oma.scidm.messages+xml
# application/vnd.oma.xcap-directory+xml
# application/vnd.omads-email+xml
# application/vnd.omads-file+xml
# application/vnd.omads-folder+xml
# application/vnd.omaloc-supl-init
application/vnd.openofficeorg.extension		oxt
# application/vnd.openxmlformats-officedocument.custom-properties+xml
# application/vnd.openxmlformats-officedocument.customxmlproperties+xml
# application/vnd.openxmlformats-officedocument.drawing+xml
# application/vnd.openxmlformats-officedocument.drawingml.chart+xml
# application/vnd.openxmlformats-officedocument.drawingml.chartshapes+xml
# application/vnd.openxmlformats-officedocument.drawingml.diagramcolors+xml
# application/vnd.openxmlformats-officedocument.drawingml.diagramdata+xml
# application/vnd.openxmlformats-officedocument.drawingml.diagramlayout+xml
# application/vnd.openxmlformats-officedocument.drawingml.diagramstyle+xml
# application/vnd.openxmlformats-officedocument.extended-properties+xml
# application/vnd.openxmlformats-officedocument.presentationml.commentauthors+xml
# application/vnd.openxmlformats-officedocument.presentationml.comments+xml
# application/vnd.openxmlformats-officedocument.presentationml.handoutmaster+xml
# application/vnd.openxmlformats-officedocument.presentationml.notesmaster+xml
# application/vnd.openxmlformats-officedocument.presentationml.notesslide+xml
application/vnd.openxmlformats-officedocument.presentationml.presentation	pptx
# application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml
# application/vnd.openxmlformats-officedocument.presentationml.presprops+xml
application/vnd.openxmlformats-officedocument.presentationml.slide	sldx
# application/vnd.openxmlformats-officedocument.presentationml.slide+xml
# application/vnd.openxmlformats-officedocument.presentationml.slidelayout+xml
# application/vnd.openxmlformats-officedocument.presentationml.slidemaster+xml
application/vnd.openxmlformats-officedocument.presentationml.slideshow	ppsx
# application/vnd.openxmlformats-officedocument.presentationml.slideshow.main+xml
# application/vnd.openxmlformats-officedocument.presentationml.slideupdateinfo+xml
# application/vnd.openxmlformats-officedocument.presentationml.tablestyles+xml
# application/vnd.openxmlformats-officedocument.presentationml.tags+xml
application/vnd.openxmlformats-officedocument.presentationml.template	potx
# application/vnd.openxmlformats-officedocument.presentationml.template.main+xml
# application/vnd.openxmlformats-officedocument.presentationml.viewprops+xml
# application/vnd.openxmlformats-officedocument.spreadsheetml.calcchain+xml
# application/vnd.openxmlformats-officedocument.spreadsheetml.chartsheet+xml
# application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml
# application/vnd.openxmlformats-officedocument.spreadsheetml.connections+xml
# application/vnd.openxmlformats-officedocument.spreadsheetml.dialogsheet+xml
# application/vnd.openxmlformats-officedocument.spreadsheetml.externallink+xml
# application/vnd.openxmlformats-officedocument.spreadsheetml.pivotcachedefinition+xml
# application/vnd.openxmlformats-officedocument.spreadsheetml.pivotcacherecords+xml
# application/vnd.openxmlformats-officedocument.spreadsheetml.pivottable+xml
# application/vnd.openxmlformats-officedocument.spreadsheetml.querytable+xml
# application/vnd.openxmlformats-officedocument.spreadsheetml.revisionheaders+xml
# application/vnd.openxmlformats-officedocument.spreadsheetml.revisionlog+xml
# application/vnd.openxmlformats-officedocument.spreadsheetml.sharedstrings+xml
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet	xlsx
# application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml
# application/vnd.openxmlformats-officedocument.spreadsheetml.sheetmetadata+xml
# application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml
# application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml
# application/vnd.openxmlformats-officedocument.spreadsheetml.tablesinglecells+xml
application/vnd.openxmlformats-officedocument.spreadsheetml.template	xltx
# application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml
# application/vnd.openxmlformats-officedocument.spreadsheetml.usernames+xml
# application/vnd.openxmlformats-officedocument.spreadsheetml.volatiledependencies+xml
# application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml
# application/vnd.openxmlformats-officedocument.theme+xml
# application/vnd.openxmlformats-officedocument.themeoverride+xml
# application/vnd.openxmlformats-officedocument.vmldrawing
# application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml
application/vnd.openxmlformats-officedocument.wordprocessingml.document	docx
# application/vnd.openxmlformats-officedocument.wordprocessingml.document.glossary+xml
# application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml
# application/vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml
# application/vnd.openxmlformats-officedocument.wordprocessingml.fonttable+xml
# application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml
# application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml
# application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml
# application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml
# application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml
application/vnd.openxmlformats-officedocument.wordprocessingml.template	dotx
# application/vnd.openxmlformats-officedocument.wordprocessingml.template.main+xml
# application/vnd.openxmlformats-officedocument.wordprocessingml.websettings+xml
# application/vnd.openxmlformats-package.core-properties+xml
# application/vnd.openxmlformats-package.digital-signature-xmlsignature+xml
# application/vnd.openxmlformats-package.relationships+xml
# application/vnd.quobject-quoxdocument
# application/vnd.osa.netdeploy
application/vnd.osgeo.mapguide.package		mgp
# application/vnd.osgi.bundle
application/vnd.osgi.dp				dp
# application/vnd.otps.ct-kip+xml
application/vnd.palm				pdb pqa oprc
# application/vnd.paos.xml
application/vnd.pawaafile			paw
application/vnd.pg.format			str
application/vnd.pg.osasli			ei6
# application/vnd.piaccess.application-licence
application/vnd.picsel				efif
application/vnd.pmi.widget			wg
# application/vnd.poc.group-advertisement+xml
application/vnd.pocketlearn			plf
application/vnd.powerbuilder6			pbd
# application/vnd.powerbuilder6-s
# application/vnd.powerbuilder7
# application/vnd.powerbuilder7-s
# application/vnd.powerbuilder75
# application/vnd.powerbuilder75-s
# application/vnd.preminet
application/vnd.previewsystems.box		box
application/vnd.proteus.magazine		mgz
application/vnd.publishare-delta-tree		qps
application/vnd.pvi.ptid1			ptid
# application/vnd.pwg-multiplexed
# application/vnd.pwg-xhtml-print+xml
# application/vnd.qualcomm.brew-app-res
application/vnd.quark.quarkxpress		qxd qxt qwd qwt qxl qxb
# application/vnd.radisys.moml+xml
# application/vnd.radisys.msml+xml
# application/vnd.radisys.msml-audit+xml
# application/vnd.radisys.msml-audit-conf+xml
# application/vnd.radisys.msml-audit-conn+xml
# application/vnd.radisys.msml-audit-dialog+xml
# application/vnd.radisys.msml-audit-stream+xml
# application/vnd.radisys.msml-conf+xml
# application/vnd.radisys.msml-dialog+xml
# application/vnd.radisys.msml-dialog-base+xml
# application/vnd.radisys.msml-dialog-fax-detect+xml
# application/vnd.radisys.msml-dialog-fax-sendrecv+xml
# application/vnd.radisys.msml-dialog-group+xml
# application/vnd.radisys.msml-dialog-speech+xml
# application/vnd.radisys.msml-dialog-transform+xml
# application/vnd.rainstor.data
# application/vnd.rapid
application/vnd.realvnc.bed			bed
application/vnd.recordare.musicxml		mxl
application/vnd.recordare.musicxml+xml		musicxml
# application/vnd.renlearn.rlprint
application/vnd.rig.cryptonote			cryptonote
application/vnd.rim.cod				cod
application/vnd.rn-realmedia			rm
application/vnd.route66.link66+xml		link66
# application/vnd.ruckus.download
# application/vnd.s3sms
application/vnd.sailingtracker.track		st
# application/vnd.sbm.cid
# application/vnd.sbm.mid2
# application/vnd.scribus
# application/vnd.sealed.3df
# application/vnd.sealed.csf
# application/vnd.sealed.doc
# application/vnd.sealed.eml
# application/vnd.sealed.mht
# application/vnd.sealed.net
# application/vnd.sealed.ppt
# application/vnd.sealed.tiff
# application/vnd.sealed.xls
# application/vnd.sealedmedia.softseal.html
# application/vnd.sealedmedia.softseal.pdf
application/vnd.seemail				see
application/vnd.sema				sema
application/vnd.semd				semd
application/vnd.semf				semf
application/vnd.shana.informed.formdata		ifm
application/vnd.shana.informed.formtemplate	itp
application/vnd.shana.informed.interchange	iif
application/vnd.shana.informed.package		ipk
application/vnd.simtech-mindmapper		twd twds
application/vnd.smaf				mmf
# application/vnd.smart.notebook
application/vnd.smart.teacher			teacher
# application/vnd.software602.filler.form+xml
# application/vnd.software602.filler.form-xml-zip
application/vnd.solent.sdkm+xml			sdkm sdkd
application/vnd.spotfire.dxp			dxp
application/vnd.spotfire.sfs			sfs
# application/vnd.sss-cod
# application/vnd.sss-dtf
# application/vnd.sss-ntf
application/vnd.stardivision.calc		sdc
application/vnd.stardivision.draw		sda
application/vnd.stardivision.impress		sdd
application/vnd.stardivision.math		smf
application/vnd.stardivision.writer		sdw vor
application/vnd.stardivision.writer-global	sgl
application/vnd.stepmania.stepchart		sm
# application/vnd.street-stream
application/vnd.sun.xml.calc			sxc
application/vnd.sun.xml.calc.template		stc
application/vnd.sun.xml.draw			sxd
application/vnd.sun.xml.draw.template		std
application/vnd.sun.xml.impress			sxi
application/vnd.sun.xml.impress.template	sti
application/vnd.sun.xml.math			sxm
application/vnd.sun.xml.writer			sxw
application/vnd.sun.xml.writer.global		sxg
application/vnd.sun.xml.writer.template		stw
# application/vnd.sun.wadl+xml
application/vnd.sus-calendar			sus susp
application/vnd.svd				svd
# application/vnd.swiftview-ics
application/vnd.symbian.install			sis sisx
application/vnd.syncml+xml			xsm
application/vnd.syncml.dm+wbxml			bdm
application/vnd.syncml.dm+xml			xdm
# application/vnd.syncml.dm.notification
# application/vnd.syncml.ds.notification
application/vnd.tao.intent-module-archive	tao
application/vnd.tmobile-livetv			tmo
application/vnd.trid.tpt			tpt
application/vnd.triscape.mxs			mxs
application/vnd.trueapp				tra
# application/vnd.truedoc
# application/vnd.ubisoft.webplayer
application/vnd.ufdl				ufd ufdl
application/vnd.uiq.theme			utz
application/vnd.umajin				umj
application/vnd.unity				unityweb
application/vnd.uoml+xml			uoml
# application/vnd.uplanet.alert
# application/vnd.uplanet.alert-wbxml
# application/vnd.uplanet.bearer-choice
# application/vnd.uplanet.bearer-choice-wbxml
# application/vnd.uplanet.cacheop
# application/vnd.uplanet.cacheop-wbxml
# application/vnd.uplanet.channel
# application/vnd.uplanet.channel-wbxml
# application/vnd.uplanet.list
# application/vnd.uplanet.list-wbxml
# application/vnd.uplanet.listcmd
# application/vnd.uplanet.listcmd-wbxml
# application/vnd.uplanet.signal
application/vnd.vcx				vcx
# application/vnd.vd-study
# application/vnd.vectorworks
# application/vnd.verimatrix.vcas
# application/vnd.vidsoft.vidconference
application/vnd.visio				vsd vst vss vsw
application/vnd.visionary			vis
# application/vnd.vividence.scriptfile
application/vnd.vsf				vsf
# application/vnd.wap.sic
# application/vnd.wap.slc
application/vnd.wap.wbxml			wbxml
application/vnd.wap.wmlc			wmlc
application/vnd.wap.wmlscriptc			wmlsc
application/vnd.webturbo			wtb
# application/vnd.wfa.wsc
# application/vnd.wmc
# application/vnd.wmf.bootstrap
# application/vnd.wolfram.mathematica
# application/vnd.wolfram.mathematica.package
application/vnd.wolfram.player			nbp
application/vnd.wordperfect			wpd
application/vnd.wqd				wqd
# application/vnd.wrq-hp3000-labelled
application/vnd.wt.stf				stf
# application/vnd.wv.csp+wbxml
# application/vnd.wv.csp+xml
# application/vnd.wv.ssp+xml
application/vnd.xara				xar
application/vnd.xfdl				xfdl
# application/vnd.xfdl.webform
# application/vnd.xmi+xml
# application/vnd.xmpie.cpkg
# application/vnd.xmpie.dpkg
# application/vnd.xmpie.plan
# application/vnd.xmpie.ppkg
# application/vnd.xmpie.xlim
application/vnd.yamaha.hv-dic			hvd
application/vnd.yamaha.hv-script		hvs
application/vnd.yamaha.hv-voice			hvp
application/vnd.yamaha.openscoreformat			osf
application/vnd.yamaha.openscoreformat.osfpvg+xml	osfpvg
# application/vnd.yamaha.remote-setup
application/vnd.yamaha.smaf-audio		saf
application/vnd.yamaha.smaf-phrase		spf
# application/vnd.yamaha.tunnel-udpencap
application/vnd.yellowriver-custom-menu		cmp
application/vnd.zul				zir zirz
application/vnd.zzazz.deck+xml			zaz
application/voicexml+xml			vxml
# application/vq-rtcpxr
# application/watcherinfo+xml
# application/whoispp-query
# application/whoispp-response
application/widget				wgt
application/winhlp				hlp
# application/wita
# application/wordperfect5.1
application/wsdl+xml				wsdl
application/wspolicy+xml			wspolicy
application/x-7z-compressed			7z
application/x-abiword				abw
application/x-ace-compressed			ace
application/x-authorware-bin			aab x32 u32 vox
application/x-authorware-map			aam
application/x-authorware-seg			aas
application/x-bcpio				bcpio
application/x-bittorrent			torrent
application/x-bzip				bz
application/x-bzip2				bz2 boz
application/x-cdlink				vcd
application/x-chat				chat
application/x-chess-pgn				pgn
# application/x-compress
application/x-cpio				cpio
application/x-csh				csh
application/x-debian-package			deb udeb
application/x-director			dir dcr dxr cst cct cxt w3d fgd swa
application/x-doom				wad
application/x-dtbncx+xml			ncx
application/x-dtbook+xml			dtb
application/x-dtbresource+xml			res
application/x-dvi				dvi
application/x-font-bdf				bdf
# application/x-font-dos
# application/x-font-framemaker
application/x-font-ghostscript			gsf
# application/x-font-libgrx
application/x-font-linux-psf			psf
application/x-font-otf				otf
application/x-font-pcf				pcf
application/x-font-snf				snf
# application/x-font-speedo
# application/x-font-sunos-news
application/x-font-ttf				ttf ttc
application/x-font-type1			pfa pfb pfm afm
application/x-font-woff				woff
# application/x-font-vfont
application/x-futuresplash			spl
application/x-gnumeric				gnumeric
application/x-gtar				gtar
# application/x-gzip
application/x-hdf				hdf
application/x-java-jnlp-file			jnlp
application/x-latex				latex
application/x-mobipocket-ebook			prc mobi
application/x-ms-application			application
application/x-ms-wmd				wmd
application/x-ms-wmz				wmz
application/x-ms-xbap				xbap
application/x-msaccess				mdb
application/x-msbinder				obd
application/x-mscardfile			crd
application/x-msclip				clp
application/x-msdownload			exe dll com bat msi
application/x-msmediaview			mvb m13 m14
application/x-msmetafile			wmf
application/x-msmoney				mny
application/x-mspublisher			pub
application/x-msschedule			scd
application/x-msterminal			trm
application/x-mswrite				wri
application/x-netcdf				nc cdf
application/x-pkcs12				p12 pfx
application/x-pkcs7-certificates		p7b spc
application/x-pkcs7-certreqresp			p7r
application/x-rar-compressed			rar
application/x-sh				sh
application/x-shar				shar
application/x-shockwave-flash			swf
application/x-silverlight-app			xap
application/x-stuffit				sit
application/x-stuffitx				sitx
application/x-sv4cpio				sv4cpio
application/x-sv4crc				sv4crc
application/x-tar				tar
application/x-tcl				tcl
application/x-tex				tex
application/x-tex-tfm				tfm
application/x-texinfo				texinfo texi
application/x-ustar				ustar
application/x-wais-source			src
application/x-x509-ca-cert			der crt
application/x-xfig				fig
application/x-xpinstall				xpi
# application/x400-bp
# application/xcap-att+xml
# application/xcap-caps+xml
application/xcap-diff+xml			xdf
# application/xcap-el+xml
# application/xcap-error+xml
# application/xcap-ns+xml
# application/xcon-conference-info-diff+xml
# application/xcon-conference-info+xml
application/xenc+xml				xenc
application/xhtml+xml				xhtml xht
# application/xhtml-voice+xml
application/xml					xml xsl
application/xml-dtd				dtd
# application/xml-external-parsed-entity
# application/xmpp+xml
application/xop+xml				xop
application/xslt+xml				xslt
application/xspf+xml				xspf
application/xv+xml				mxml xhvml xvml xvm
application/yang				yang
application/yin+xml				yin
application/zip					zip
# audio/1d-interleaved-parityfec
# audio/32kadpcm
# audio/3gpp
# audio/3gpp2
# audio/ac3
audio/adpcm					adp
# audio/amr
# audio/amr-wb
# audio/amr-wb+
# audio/asc
# audio/atrac-advanced-lossless
# audio/atrac-x
# audio/atrac3
audio/basic					au snd
# audio/bv16
# audio/bv32
# audio/clearmode
# audio/cn
# audio/dat12
# audio/dls
# audio/dsr-es201108
# audio/dsr-es202050
# audio/dsr-es202211
# audio/dsr-es202212
# audio/dvi4
# audio/eac3
# audio/evrc
# audio/evrc-qcp
# audio/evrc0
# audio/evrc1
# audio/evrcb
# audio/evrcb0
# audio/evrcb1
# audio/evrcwb
# audio/evrcwb0
# audio/evrcwb1
# audio/example
# audio/g719
# audio/g722
# audio/g7221
# audio/g723
# audio/g726-16
# audio/g726-24
# audio/g726-32
# audio/g726-40
# audio/g728
# audio/g729
# audio/g7291
# audio/g729d
# audio/g729e
# audio/gsm
# audio/gsm-efr
# audio/gsm-hr-08
# audio/ilbc
# audio/l16
# audio/l20
# audio/l24
# audio/l8
# audio/lpc
audio/midi					mid midi kar rmi
# audio/mobile-xmf
audio/mp4					mp4a
# audio/mp4a-latm
# audio/mpa
# audio/mpa-robust
audio/mpeg					mpga mp2 mp2a mp3 m2a m3a
# audio/mpeg4-generic
audio/ogg					oga ogg spx
# audio/parityfec
# audio/pcma
# audio/pcma-wb
# audio/pcmu-wb
# audio/pcmu
# audio/prs.sid
# audio/qcelp
# audio/red
# audio/rtp-enc-aescm128
# audio/rtp-midi
# audio/rtx
# audio/smv
# audio/smv0
# audio/smv-qcp
# audio/sp-midi
# audio/speex
# audio/t140c
# audio/t38
# audio/telephone-event
# audio/tone
# audio/uemclip
# audio/ulpfec
# audio/vdvi
# audio/vmr-wb
# audio/vnd.3gpp.iufp
# audio/vnd.4sb
# audio/vnd.audiokoz
# audio/vnd.celp
# audio/vnd.cisco.nse
# audio/vnd.cmles.radio-events
# audio/vnd.cns.anp1
# audio/vnd.cns.inf1
audio/vnd.dece.audio				uva uvva
audio/vnd.digital-winds				eol
# audio/vnd.dlna.adts
# audio/vnd.dolby.heaac.1
# audio/vnd.dolby.heaac.2
# audio/vnd.dolby.mlp
# audio/vnd.dolby.mps
# audio/vnd.dolby.pl2
# audio/vnd.dolby.pl2x
# audio/vnd.dolby.pl2z
# audio/vnd.dolby.pulse.1
audio/vnd.dra					dra
audio/vnd.dts					dts
audio/vnd.dts.hd				dtshd
# audio/vnd.everad.plj
# audio/vnd.hns.audio
audio/vnd.lucent.voice				lvp
audio/vnd.ms-playready.media.pya		pya
# audio/vnd.nokia.mobile-xmf
# audio/vnd.nortel.vbk
audio/vnd.nuera.ecelp4800			ecelp4800
audio/vnd.nuera.ecelp7470			ecelp7470
audio/vnd.nuera.ecelp9600			ecelp9600
# audio/vnd.octel.sbc
# audio/vnd.qcelp
# audio/vnd.rhetorex.32kadpcm
audio/vnd.rip					rip
# audio/vnd.sealedmedia.softseal.mpeg
# audio/vnd.vmx.cvsd
# audio/vorbis
# audio/vorbis-config
audio/webm					weba
audio/x-aac					aac
audio/x-aiff					aif aiff aifc
audio/x-mpegurl					m3u
audio/x-ms-wax					wax
audio/x-ms-wma					wma
audio/x-pn-realaudio				ram ra
audio/x-pn-realaudio-plugin			rmp
audio/x-wav					wav
chemical/x-cdx					cdx
chemical/x-cif					cif
chemical/x-cmdf					cmdf
chemical/x-cml					cml
chemical/x-csml					csml
# chemical/x-pdb
chemical/x-xyz					xyz
image/bmp					bmp
image/cgm					cgm
# image/example
# image/fits
image/g3fax					g3
image/gif					gif
image/ief					ief
# image/jp2
image/jpeg					jpeg jpg jpe
# image/jpm
# image/jpx
image/ktx					ktx
# image/naplps
image/png					png
image/prs.btif					btif
# image/prs.pti
image/svg+xml					svg svgz
# image/t38
image/tiff					tiff tif
# image/tiff-fx
image/vnd.adobe.photoshop			psd
# image/vnd.cns.inf2
image/vnd.dece.graphic				uvi uvvi uvg uvvg
image/vnd.dvb.subtitle				sub
image/vnd.djvu					djvu djv
image/vnd.dwg					dwg
image/vnd.dxf					dxf
image/vnd.fastbidsheet				fbs
image/vnd.fpx					fpx
image/vnd.fst					fst
image/vnd.fujixerox.edmics-mmr			mmr
image/vnd.fujixerox.edmics-rlc			rlc
# image/vnd.globalgraphics.pgb
# image/vnd.microsoft.icon
# image/vnd.mix
image/vnd.ms-modi				mdi
image/vnd.net-fpx				npx
# image/vnd.radiance
# image/vnd.sealed.png
# image/vnd.sealedmedia.softseal.gif
# image/vnd.sealedmedia.softseal.jpg
# image/vnd.svf
image/vnd.wap.wbmp				wbmp
image/vnd.xiff					xif
image/webp					webp
image/x-cmu-raster				ras
image/x-cmx					cmx
image/x-freehand				fh fhc fh4 fh5 fh7
image/x-icon					ico
image/x-pcx					pcx
image/x-pict					pic pct
image/x-portable-anymap				pnm
image/x-portable-bitmap				pbm
image/x-portable-graymap			pgm
image/x-portable-pixmap				ppm
image/x-rgb					rgb
image/x-xbitmap					xbm
image/x-xpixmap					xpm
image/x-xwindowdump				xwd
# message/cpim
# message/delivery-status
# message/disposition-notification
# message/example
# message/external-body
# message/feedback-report
# message/global
# message/global-delivery-status
# message/global-disposition-notification
# message/global-headers
# message/http
# message/imdn+xml
# message/news
# message/partial
message/rfc822					eml mime
# message/s-http
# message/sip
# message/sipfrag
# message/tracking-status
# message/vnd.si.simp
# model/example
model/iges					igs iges
model/mesh					msh mesh silo
model/vnd.collada+xml				dae
model/vnd.dwf					dwf
# model/vnd.flatland.3dml
model/vnd.gdl					gdl
# model/vnd.gs-gdl
# model/vnd.gs.gdl
model/vnd.gtw					gtw
# model/vnd.moml+xml
model/vnd.mts					mts
# model/vnd.parasolid.transmit.binary
# model/vnd.parasolid.transmit.text
model/vnd.vtu					vtu
model/vrml					wrl vrml
# multipart/alternative
# multipart/appledouble
# multipart/byteranges
# multipart/digest
# multipart/encrypted
# multipart/example
# multipart/form-data
# multipart/header-set
# multipart/mixed
# multipart/parallel
# multipart/related
# multipart/report
# multipart/signed
# multipart/voice-message
# text/1d-interleaved-parityfec
text/calendar					ics ifb
text/css					css
text/csv					csv
# text/directory
# text/dns
# text/ecmascript
# text/enriched
# text/example
text/html					html htm
# text/javascript
text/n3						n3
# text/parityfec
text/plain					txt text conf def list log in
# text/prs.fallenstein.rst
text/prs.lines.tag				dsc
# text/vnd.radisys.msml-basic-layout
# text/red
# text/rfc822-headers
text/richtext					rtx
# text/rtf
# text/rtp-enc-aescm128
# text/rtx
text/sgml					sgml sgm
# text/t140
text/tab-separated-values			tsv
text/troff					t tr roff man me ms
text/turtle					ttl
# text/ulpfec
text/uri-list					uri uris urls
# text/vnd.abc
text/vnd.curl					curl
text/vnd.curl.dcurl				dcurl
text/vnd.curl.scurl				scurl
text/vnd.curl.mcurl				mcurl
# text/vnd.dmclientscript
# text/vnd.esmertec.theme-descriptor
text/vnd.fly					fly
text/vnd.fmi.flexstor				flx
text/vnd.graphviz				gv
text/vnd.in3d.3dml				3dml
text/vnd.in3d.spot				spot
# text/vnd.iptc.newsml
# text/vnd.iptc.nitf
# text/vnd.latex-z
# text/vnd.motorola.reflex
# text/vnd.ms-mediapackage
# text/vnd.net2phone.commcenter.command
# text/vnd.si.uricatalogue
text/vnd.sun.j2me.app-descriptor		jad
# text/vnd.trolltech.linguist
# text/vnd.wap.si
# text/vnd.wap.sl
text/vnd.wap.wml				wml
text/vnd.wap.wmlscript				wmls
text/x-asm					s asm
text/x-c					c cc cxx cpp h hh dic
text/x-fortran					f for f77 f90
text/x-pascal					p pas
text/x-java-source				java
text/x-setext					etx
text/x-uuencode					uu
text/x-vcalendar				vcs
text/x-vcard					vcf
# text/xml
# text/xml-external-parsed-entity
# video/1d-interleaved-parityfec
video/3gpp					3gp
# video/3gpp-tt
video/3gpp2					3g2
# video/bmpeg
# video/bt656
# video/celb
# video/dv
# video/example
video/h261					h261
video/h263					h263
# video/h263-1998
# video/h263-2000
video/h264					h264
# video/h264-rcdo
# video/h264-svc
video/jpeg					jpgv
# video/jpeg2000
video/jpm					jpm jpgm
video/mj2					mj2 mjp2
# video/mp1s
# video/mp2p
# video/mp2t
video/mp4					mp4 mp4v mpg4
# video/mp4v-es
video/mpeg					mpeg mpg mpe m1v m2v
# video/mpeg4-generic
# video/mpv
# video/nv
video/ogg					ogv
# video/parityfec
# video/pointer
video/quicktime					qt mov
# video/raw
# video/rtp-enc-aescm128
# video/rtx
# video/smpte292m
# video/ulpfec
# video/vc1
# video/vnd.cctv
video/vnd.dece.hd				uvh uvvh
video/vnd.dece.mobile				uvm uvvm
# video/vnd.dece.mp4
video/vnd.dece.pd				uvp uvvp
video/vnd.dece.sd				uvs uvvs
video/vnd.dece.video				uvv uvvv
# video/vnd.directv.mpeg
# video/vnd.directv.mpeg-tts
# video/vnd.dlna.mpeg-tts
video/vnd.fvt					fvt
# video/vnd.hns.video
# video/vnd.iptvforum.1dparityfec-1010
# video/vnd.iptvforum.1dparityfec-2005
# video/vnd.iptvforum.2dparityfec-1010
# video/vnd.iptvforum.2dparityfec-2005
# video/vnd.iptvforum.ttsavc
# video/vnd.iptvforum.ttsmpeg2
# video/vnd.motorola.video
# video/vnd.motorola.videop
video/vnd.mpegurl				mxu m4u
video/vnd.ms-playready.media.pyv		pyv
# video/vnd.nokia.interleaved-multimedia
# video/vnd.nokia.videovoip
# video/vnd.objectvideo
# video/vnd.sealed.mpeg1
# video/vnd.sealed.mpeg4
# video/vnd.sealed.swf
# video/vnd.sealedmedia.softseal.mov
video/vnd.uvvu.mp4				uvu uvvu
video/vnd.vivo					viv
video/webm					webm
video/x-f4v					f4v
video/x-fli					fli
video/x-flv					flv
video/x-m4v					m4v
video/x-ms-asf					asf asx
video/x-ms-wm					wm
video/x-ms-wmv					wmv
video/x-ms-wmx					wmx
video/x-ms-wvx					wvx
video/x-msvideo					avi
video/x-sgi-movie				movie
x-conference/x-cooltalk				ice
PK5N%[}Q�bbperl5/LWP/Debug.pmnu��6�$package LWP::Debug;    # legacy

our $VERSION = '6.78';

require Exporter;
our @ISA       = qw(Exporter);
our @EXPORT_OK = qw(level trace debug conns);

use Carp ();

my @levels = qw(trace debug conns);
our %current_level = ();

sub import {
    my $pack    = shift;
    my $callpkg = caller(0);
    my @symbols = ();
    my @levels  = ();
    for (@_) {
        if (/^[-+]/) {
            push(@levels, $_);
        }
        else {
            push(@symbols, $_);
        }
    }
    Exporter::export($pack, $callpkg, @symbols);
    level(@levels);
}

sub level {
    for (@_) {
        if ($_ eq '+') {    # all on
                            # switch on all levels
            %current_level = map { $_ => 1 } @levels;
        }
        elsif ($_ eq '-') {    # all off
            %current_level = ();
        }
        elsif (/^([-+])(\w+)$/) {
            $current_level{$2} = $1 eq '+';
        }
        else {
            Carp::croak("Illegal level format $_");
        }
    }
}

sub trace { _log(@_) if $current_level{'trace'}; }
sub debug { _log(@_) if $current_level{'debug'}; }
sub conns { _log(@_) if $current_level{'conns'}; }

sub _log {
    my $msg = shift;
    $msg .= "\n" unless $msg =~ /\n$/;    # ensure trailing "\n"

    my ($package, $filename, $line, $sub) = caller(2);
    print STDERR "$sub: $msg";
}

1;

__END__

=pod

=head1 NAME

LWP::Debug - deprecated

=head1 DESCRIPTION

This module has been deprecated.  Please see L<LWP::ConsoleLogger> for your
debugging needs.

LWP::Debug is used to provide tracing facilities, but these are not used
by LWP any more.  The code in this module is kept around
(undocumented) so that 3rd party code that happens to use the old
interfaces continue to run.

One useful feature that LWP::Debug provided (in an imprecise and
troublesome way) was network traffic monitoring.  The following
section provides some hints about recommended replacements.

=head2 Network traffic monitoring

The best way to monitor the network traffic that LWP generates is to
use an external TCP monitoring program.  The
L<WireShark|http://www.wireshark.org/> program is highly recommended for this.

Another approach it to use a debugging HTTP proxy server and make
LWP direct all its traffic via this one.  Call C<< $ua->proxy >> to
set it up and then just use LWP as before.

For less precise monitoring needs just setting up a few simple
handlers might do.  The following example sets up handlers to dump the
request and response objects that pass through LWP:

  use LWP::UserAgent;
  $ua = LWP::UserAgent->new;
  $ua->default_header('Accept-Encoding' => scalar HTTP::Message::decodable());

  $ua->add_handler("request_send",  sub { shift->dump; return });
  $ua->add_handler("response_done", sub { shift->dump; return });

  $ua->get("http://www.example.com");

=head1 SEE ALSO

L<LWP::ConsoleLogger>, L<LWP::ConsoleLogger::Everywhere>, L<LWP::UserAgent>

=cut
PK6N%[����perl5/LWP/RobotUA.pmnu��6�$package LWP::RobotUA;

use parent qw(LWP::UserAgent);

our $VERSION = '6.78';

require WWW::RobotRules;
require HTTP::Request;
require HTTP::Response;

use Carp ();
use HTTP::Status ();
use HTTP::Date qw(time2str);
use strict;


#
# Additional attributes in addition to those found in LWP::UserAgent:
#
# $self->{'delay'}    Required delay between request to the same
#                     server in minutes.
#
# $self->{'rules'}     A WWW::RobotRules object
#

sub new
{
    my $class = shift;
    my %cnf;
    if (@_ < 4) {
	# legacy args
	@cnf{qw(agent from rules)} = @_;
    }
    else {
	%cnf = @_;
    }

    Carp::croak('LWP::RobotUA agent required') unless $cnf{agent};
    Carp::croak('LWP::RobotUA from address required')
	unless $cnf{from} && $cnf{from} =~ m/\@/;

    my $delay = delete $cnf{delay} || 1;
    my $use_sleep = delete $cnf{use_sleep};
    $use_sleep = 1 unless defined($use_sleep);
    my $rules = delete $cnf{rules};

    my $self = LWP::UserAgent->new(%cnf);
    $self = bless $self, $class;

    $self->{'delay'} = $delay;   # minutes
    $self->{'use_sleep'} = $use_sleep;

    if ($rules) {
	$rules->agent($cnf{agent});
	$self->{'rules'} = $rules;
    }
    else {
	$self->{'rules'} = WWW::RobotRules->new($cnf{agent});
    }

    $self;
}


sub delay     { shift->_elem('delay',     @_); }
sub use_sleep { shift->_elem('use_sleep', @_); }


sub agent
{
    my $self = shift;
    my $old = $self->SUPER::agent(@_);
    if (@_) {
	# Changing our name means to start fresh
	$self->{'rules'}->agent($self->{'agent'});
    }
    $old;
}


sub rules {
    my $self = shift;
    my $old = $self->_elem('rules', @_);
    $self->{'rules'}->agent($self->{'agent'}) if @_;
    $old;
}


sub no_visits
{
    my($self, $netloc) = @_;
    $self->{'rules'}->no_visits($netloc) || 0;
}

*host_count = \&no_visits;  # backwards compatibility with LWP-5.02


sub host_wait
{
    my($self, $netloc) = @_;
    return undef unless defined $netloc;
    my $last = $self->{'rules'}->last_visit($netloc);
    if ($last) {
	my $wait = int($self->{'delay'} * 60 - (time - $last));
	$wait = 0 if $wait < 0;
	return $wait;
    }
    return 0;
}


sub simple_request
{
    my($self, $request, $arg, $size) = @_;

    # Do we try to access a new server?
    my $allowed = $self->{'rules'}->allowed($request->uri);

    if ($allowed < 0) {
	# Host is not visited before, or robots.txt expired; fetch "robots.txt"
	my $robot_url = $request->uri->clone;
	$robot_url->path("robots.txt");
	$robot_url->query(undef);

	# make access to robot.txt legal since this will be a recursive call
	$self->{'rules'}->parse($robot_url, "");

	my $robot_req = HTTP::Request->new('GET', $robot_url);
	my $parse_head = $self->parse_head(0);
	my $robot_res = $self->request($robot_req);
	$self->parse_head($parse_head);
	my $fresh_until = $robot_res->fresh_until;
	my $content = "";
	if ($robot_res->is_success && $robot_res->content_is_text) {
	    $content = $robot_res->decoded_content;
	    $content = "" unless $content && $content =~ /^\s*Disallow\s*:/mi;
	}
	$self->{'rules'}->parse($robot_url, $content, $fresh_until);

	# recalculate allowed...
	$allowed = $self->{'rules'}->allowed($request->uri);
    }

    # Check rules
    unless ($allowed) {
	my $res = HTTP::Response->new(
	  HTTP::Status::RC_FORBIDDEN, 'Forbidden by robots.txt');
	$res->request( $request ); # bind it to that request
	return $res;
    }

    my $netloc = eval { local $SIG{__DIE__}; $request->uri->host_port; };
    my $wait = $self->host_wait($netloc);

    if ($wait) {
	if ($self->{'use_sleep'}) {
	    sleep($wait)
	}
	else {
	    my $res = HTTP::Response->new(
	      HTTP::Status::RC_SERVICE_UNAVAILABLE, 'Please, slow down');
	    $res->header('Retry-After', time2str(time + $wait));
	    $res->request( $request ); # bind it to that request
	    return $res;
	}
    }

    # Perform the request
    my $res = $self->SUPER::simple_request($request, $arg, $size);

    $self->{'rules'}->visit($netloc);

    $res;
}


sub as_string
{
    my $self = shift;
    my @s;
    push(@s, "Robot: $self->{'agent'} operated by $self->{'from'}  [$self]");
    push(@s, "    Minimum delay: " . int($self->{'delay'}*60) . "s");
    push(@s, "    Will sleep if too early") if $self->{'use_sleep'};
    push(@s, "    Rules = $self->{'rules'}");
    join("\n", @s, '');
}

1;


__END__

=pod

=head1 NAME

LWP::RobotUA - a class for well-behaved Web robots

=head1 SYNOPSIS

  use LWP::RobotUA;
  my $ua = LWP::RobotUA->new('my-robot/0.1', 'me@foo.com');
  $ua->delay(10);  # be very nice -- max one hit every ten minutes!
  ...

  # Then just use it just like a normal LWP::UserAgent:
  my $response = $ua->get('http://whatever.int/...');
  ...

=head1 DESCRIPTION

This class implements a user agent that is suitable for robot
applications.  Robots should be nice to the servers they visit.  They
should consult the F</robots.txt> file to ensure that they are welcomed
and they should not make requests too frequently.

But before you consider writing a robot, take a look at
L<http://www.robotstxt.org/>.

When you use an I<LWP::RobotUA> object as your user agent, then you do not
really have to think about these things yourself; C<robots.txt> files
are automatically consulted and obeyed, the server isn't queried
too rapidly, and so on.  Just send requests
as you do when you are using a normal I<LWP::UserAgent>
object (using C<< $ua->get(...) >>, C<< $ua->head(...) >>,
C<< $ua->request(...) >>, etc.), and this
special agent will make sure you are nice.

=head1 METHODS

The LWP::RobotUA is a sub-class of L<LWP::UserAgent> and implements the
same methods. In addition the following methods are provided:

=head2 new

    my $ua = LWP::RobotUA->new( %options )
    my $ua = LWP::RobotUA->new( $agent, $from )
    my $ua = LWP::RobotUA->new( $agent, $from, $rules )

The LWP::UserAgent options C<agent> and C<from> are mandatory.  The
options C<delay>, C<use_sleep> and C<rules> initialize attributes
private to the RobotUA.  If C<rules> are not provided, then
L<WWW::RobotRules> is instantiated providing an internal database of
F<robots.txt>.

It is also possible to just pass the value of C<agent>, C<from> and
optionally C<rules> as plain positional arguments.

=head2 delay

    my $delay = $ua->delay;
    $ua->delay( $minutes );

Get/set the minimum delay between requests to the same server, in
I<minutes>.  The default is C<1> minute.  Note that this number doesn't
have to be an integer; for example, this sets the delay to C<10> seconds:

    $ua->delay(10/60);

=head2 use_sleep

    my $bool = $ua->use_sleep;
    $ua->use_sleep( $boolean );

Get/set a value indicating whether the UA should L<LWP::RobotUA/sleep> if
requests arrive too fast, defined as C<< $ua->delay >> minutes not passed since
last request to the given server.  The default is true.  If this value is
false then an internal C<SERVICE_UNAVAILABLE> response will be generated.
It will have a C<Retry-After> header that indicates when it is OK to
send another request to this server.

=head2 rules

    my $rules = $ua->rules;
    $ua->rules( $rules );

Set/get which I<WWW::RobotRules> object to use.

=head2 no_visits

    my $num = $ua->no_visits( $netloc )

Returns the number of documents fetched from this server host. Yeah I
know, this method should probably have been named C<num_visits> or
something like that. :-(

=head2 host_wait

    my $num = $ua->host_wait( $netloc )

Returns the number of I<seconds> (from now) you must wait before you can
make a new request to this host.

=head2 as_string

    my $string = $ua->as_string;

Returns a string that describes the state of the UA.
Mainly useful for debugging.

=head1 SEE ALSO

L<LWP::UserAgent>, L<WWW::RobotRules>

=head1 COPYRIGHT

Copyright 1996-2004 Gisle Aas.

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

=cut
PK6N%[��^YYperl5/LWP/Debug/TraceHTTP.pmnu��6�$package LWP::Debug::TraceHTTP;

# Just call:
#
#   require LWP::Debug::TraceHTTP;
#   LWP::Protocol::implementor('http', 'LWP::Debug::TraceHTTP');
#
# to use this module to trace all calls to the HTTP socket object in
# programs that use LWP.

use strict;
use parent 'LWP::Protocol::http';

our $VERSION = '6.78';

package # hide from PAUSE
    LWP::Debug::TraceHTTP::Socket;

use Data::Dump 1.13;
use Data::Dump::Trace qw(autowrap mcall);

autowrap("LWP::Protocol::http::Socket" => "sock");

sub new {
    my $class = shift;
    return mcall("LWP::Protocol::http::Socket" => "new", undef, @_);
}

1;
PK6N%[R�perl5/LWP/Authen/Ntlm.pmnu��6�$package LWP::Authen::Ntlm;

use strict;

our $VERSION = '6.78';

use Authen::NTLM "1.02";
use MIME::Base64 "2.12";

sub authenticate {
    my($class, $ua, $proxy, $auth_param, $response,
       $request, $arg, $size) = @_;

    my($user, $pass) = $ua->get_basic_credentials($auth_param->{realm},
                                                  $request->uri, $proxy);

    unless(defined $user and defined $pass) {
		return $response;
	}

	if (!$ua->conn_cache()) {
		warn "The keep_alive option must be enabled for NTLM authentication to work.  NTLM authentication aborted.\n";
		return $response;
	}

	my($domain, $username) = split(/\\/, $user);

	ntlm_domain($domain);
	ntlm_user($username);
	ntlm_password($pass);

    my $auth_header = $proxy ? "Proxy-Authorization" : "Authorization";

	# my ($challenge) = $response->header('WWW-Authenticate');
	my $challenge;
	foreach ($response->header('WWW-Authenticate')) {
		last if /^NTLM/ && ($challenge=$_);
	}

	if ($challenge eq 'NTLM') {
		# First phase, send handshake
	    my $auth_value = "NTLM " . ntlm();
		ntlm_reset();

	    # Need to check this isn't a repeated fail!
	    my $r = $response;
		my $retry_count = 0;
	    while ($r) {
			my $auth = $r->request->header($auth_header);
			++$retry_count if ($auth && $auth eq $auth_value);
			if ($retry_count > 2) {
				    # here we know this failed before
				    $response->header("Client-Warning" =>
						      "Credentials for '$user' failed before");
				    return $response;
			}
			$r = $r->previous;
	    }

	    my $referral = $request->clone;
	    $referral->header($auth_header => $auth_value);
	    return $ua->request($referral, $arg, $size, $response);
	}

	else {
		# Second phase, use the response challenge (unless non-401 code
		#  was returned, in which case, we just send back the response
		#  object, as is
		my $auth_value;
		if ($response->code ne '401') {
			return $response;
		}
		else {
			my $challenge;
			foreach ($response->header('WWW-Authenticate')) {
				last if /^NTLM/ && ($challenge=$_);
			}
			$challenge =~ s/^NTLM //;
			ntlm();
			$auth_value = "NTLM " . ntlm($challenge);
			ntlm_reset();
		}

	    my $referral = $request->clone;
	    $referral->header($auth_header => $auth_value);
	    my $response2 = $ua->request($referral, $arg, $size, $response);
		return $response2;
	}
}

1;
__END__

=pod

=head1 NAME

LWP::Authen::Ntlm - Library for enabling NTLM authentication (Microsoft) in LWP

=head1 SYNOPSIS

 use LWP::UserAgent;
 use HTTP::Request::Common;
 my $url = 'http://www.company.com/protected_page.html';

 # Set up the ntlm client and then the base64 encoded ntlm handshake message
 my $ua = LWP::UserAgent->new(keep_alive=>1);
 $ua->credentials('www.company.com:80', '', "MyDomain\\MyUserCode", 'MyPassword');

 $request = GET $url;
 print "--Performing request now...-----------\n";
 $response = $ua->request($request);
 print "--Done with request-------------------\n";

 if ($response->is_success) {print "It worked!->" . $response->code . "\n"}
 else {print "It didn't work!->" . $response->code . "\n"}

=head1 DESCRIPTION

L<LWP::Authen::Ntlm> allows LWP to authenticate against servers that are using the
NTLM authentication scheme popularized by Microsoft.  This type of authentication is
common on intranets of Microsoft-centric organizations.

The module takes advantage of the Authen::NTLM module by Mark Bush.  Since there
is also another Authen::NTLM module available from CPAN by Yee Man Chan with an
entirely different interface, it is necessary to ensure that you have the correct
NTLM module.

In addition, there have been problems with incompatibilities between different
versions of L<Mime::Base64>, which Bush's L<Authen::NTLM> makes use of.  Therefore, it is
necessary to ensure that your Mime::Base64 module supports exporting of the
C<encode_base64> and C<decode_base64> functions.

=head1 USAGE

The module is used indirectly through LWP, rather than including it directly in your
code.  The LWP system will invoke the NTLM authentication when it encounters the
authentication scheme while attempting to retrieve a URL from a server.  In order
for the NTLM authentication to work, you must have a few things set up in your
code prior to attempting to retrieve the URL:

=over 4

=item *

Enable persistent HTTP connections

To do this, pass the C<< "keep_alive=>1" >> option to the L<LWP::UserAgent> when creating it, like this:

    my $ua = LWP::UserAgent->new(keep_alive=>1);

=item *

Set the credentials on the UserAgent object

The credentials must be set like this:

   $ua->credentials('www.company.com:80', '', "MyDomain\\MyUserCode", 'MyPassword');

Note that you cannot use the L<HTTP::Request> object's C<authorization_basic()> method to set
the credentials.  Note, too, that the C<'www.company.com:80'> portion only sets credentials
on the specified port AND it is case-sensitive (this is due to the way LWP is coded, and
has nothing to do with LWP::Authen::Ntlm)

=back

=head1 AVAILABILITY

General queries regarding LWP should be made to the LWP Mailing List.

Questions specific to LWP::Authen::Ntlm can be forwarded to jtillman@bigfoot.com

=head1 COPYRIGHT

Copyright (c) 2002 James Tillman. All rights reserved. This
program is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.

=head1 SEE ALSO

L<LWP>, L<LWP::UserAgent>, L<lwpcook>.

=cut
PK6N%[Zэ<
<
perl5/LWP/Authen/Basic.pmnu��6�$package LWP::Authen::Basic;

use strict;

our $VERSION = '6.78';

require Encode;
require MIME::Base64;

sub auth_header {
    my($class, $user, $pass, $request, $ua, $h) = @_;

    my $userpass = "$user:$pass";
    # https://tools.ietf.org/html/rfc7617#section-2.1
    my $charset = uc($h->{auth_param}->{charset} || "");
    $userpass = Encode::encode($charset, $userpass)
        if ($charset eq "UTF-8");

    return "Basic " . MIME::Base64::encode($userpass, "");
}

sub _reauth_requested {
    return 0;
}

sub authenticate
{
    my($class, $ua, $proxy, $auth_param, $response,
       $request, $arg, $size) = @_;

    my $realm = $auth_param->{realm} || "";
    my $url = $proxy ? $request->{proxy} : $request->uri_canonical;
    return $response unless $url;
    my $host_port = $url->host_port;
    my $auth_header = $proxy ? "Proxy-Authorization" : "Authorization";

    my @m = $proxy ? (m_proxy => $url) : (m_host_port => $host_port);
    push(@m, realm => $realm);

    my $h = $ua->get_my_handler("request_prepare", @m, sub {
        $_[0]{callback} = sub {
            my($req, $ua, $h) = @_;
            my($user, $pass) = $ua->credentials($host_port, $h->{realm});
	    if (defined $user) {
		my $auth_value = $class->auth_header($user, $pass, $req, $ua, $h);
		$req->header($auth_header => $auth_value);
	    }
        };
    });
    $h->{auth_param} = $auth_param;

    my $reauth_requested
        = $class->_reauth_requested($auth_param, $ua, $request, $auth_header);
    if (   !$proxy
        && (!$request->header($auth_header) || $reauth_requested)
        && $ua->credentials($host_port, $realm))
    {
        # we can make sure this handler applies and retry
        add_path($h, $url->path)
            unless $reauth_requested;  # Do not clobber up path list for retries
        return $ua->request($request->clone, $arg, $size, $response);
    }

    my($user, $pass) = $ua->get_basic_credentials($realm, $url, $proxy);
    unless (defined $user and defined $pass) {
	$ua->set_my_handler("request_prepare", undef, @m);  # delete handler
	return $response;
    }

    # check that the password has changed
    my ($olduser, $oldpass) = $ua->credentials($host_port, $realm);
    return $response if (defined $olduser and defined $oldpass and
                         $user eq $olduser and $pass eq $oldpass);

    $ua->credentials($host_port, $realm, $user, $pass);
    add_path($h, $url->path) unless $proxy;
    return $ua->request($request->clone, $arg, $size, $response);
}

sub add_path {
    my($h, $path) = @_;
    $path =~ s,[^/]+\z,,;
    push(@{$h->{m_path_prefix}}, $path);
}

1;
PK6N%[�s perl5/LWP/Authen/Digest.pmnu��6�$package LWP::Authen::Digest;

use strict;
use parent 'LWP::Authen::Basic';

our $VERSION = '6.78';

require Digest::MD5;

sub _reauth_requested {
    my ($class, $auth_param, $ua, $request, $auth_header) = @_;
    my $ret = defined($$auth_param{stale}) && lc($$auth_param{stale}) eq 'true';
    if ($ret) {
        my $hdr = $request->header($auth_header);
        $hdr =~ tr/,/;/;    # "," is used to separate auth-params!!
        ($hdr) = HTTP::Headers::Util::split_header_words($hdr);
        my $nonce = {@$hdr}->{nonce};
        delete $$ua{authen_md5_nonce_count}{$nonce};
    }
    return $ret;
}

sub auth_header {
    my($class, $user, $pass, $request, $ua, $h) = @_;

    my $auth_param = $h->{auth_param};

    my $nc = sprintf "%08X", ++$ua->{authen_md5_nonce_count}{$auth_param->{nonce}};
    my $cnonce = sprintf "%8x", time;

    my $uri = $request->uri->path_query;
    $uri = "/" unless length $uri;

    my $md5 = Digest::MD5->new;

    my(@digest);
    $md5->add(join(":", $user, $auth_param->{realm}, $pass));
    push(@digest, $md5->hexdigest);
    $md5->reset;

    push(@digest, $auth_param->{nonce});

    if ($auth_param->{qop}) {
	push(@digest, $nc, $cnonce, ($auth_param->{qop} =~ m|^auth[,;]auth-int$|) ? 'auth' : $auth_param->{qop});
    }

    $md5->add(join(":", $request->method, $uri));
    push(@digest, $md5->hexdigest);
    $md5->reset;

    $md5->add(join(":", @digest));
    my($digest) = $md5->hexdigest;
    $md5->reset;

    my %resp = map { $_ => $auth_param->{$_} } qw(realm nonce opaque);
    @resp{qw(username uri response algorithm)} = ($user, $uri, $digest, "MD5");

    if (($auth_param->{qop} || "") =~ m|^auth([,;]auth-int)?$|) {
	@resp{qw(qop cnonce nc)} = ("auth", $cnonce, $nc);
    }

    my(@order) = qw(username realm qop algorithm uri nonce nc cnonce response opaque);
    my @pairs;
    for (@order) {
	next unless defined $resp{$_};

	# RFC2617 says that qop-value and nc-value should be unquoted.
	if ( $_ eq 'qop' || $_ eq 'nc' ) {
		push(@pairs, "$_=" . $resp{$_});
	}
	else {
		push(@pairs, "$_=" . qq("$resp{$_}"));
	}
    }

    my $auth_value  = "Digest " . join(", ", @pairs);
    return $auth_value;
}

1;
PK6N%[��}/"/"perl5/LWP/ConnCache.pmnu��6�$package LWP::ConnCache;

use strict;

our $VERSION = '6.78';
our $DEBUG;

sub new {
    my($class, %cnf) = @_;

    my $total_capacity = 1;
    if (exists $cnf{total_capacity}) {
        $total_capacity = delete $cnf{total_capacity};
    }
    if (%cnf && $^W) {
	require Carp;
	Carp::carp("Unrecognised options: @{[sort keys %cnf]}")
    }
    my $self = bless { cc_conns => [] }, $class;
    $self->total_capacity($total_capacity);
    $self;
}


sub deposit {
    my($self, $type, $key, $conn) = @_;
    push(@{$self->{cc_conns}}, [$conn, $type, $key, time]);
    $self->enforce_limits($type);
    return;
}


sub withdraw {
    my($self, $type, $key) = @_;
    my $conns = $self->{cc_conns};
    for my $i (0 .. @$conns - 1) {
	my $c = $conns->[$i];
	next unless $c->[1] eq $type && $c->[2] eq $key;
	splice(@$conns, $i, 1);  # remove it
	return $c->[0];
    }
    return undef;
}


sub total_capacity {
    my $self = shift;
    my $old = $self->{cc_limit_total};
    if (@_) {
	$self->{cc_limit_total} = shift;
	$self->enforce_limits;
    }
    $old;
}


sub capacity {
    my $self = shift;
    my $type = shift;
    my $old = $self->{cc_limit}{$type};
    if (@_) {
	$self->{cc_limit}{$type} = shift;
	$self->enforce_limits($type);
    }
    $old;
}


sub enforce_limits {
    my($self, $type) = @_;
    my $conns = $self->{cc_conns};

    my @types = $type ? ($type) : ($self->get_types);
    for $type (@types) {
	next unless $self->{cc_limit};
	my $limit = $self->{cc_limit}{$type};
	next unless defined $limit;
	for my $i (reverse 0 .. @$conns - 1) {
	    next unless $conns->[$i][1] eq $type;
	    if (--$limit < 0) {
		$self->dropping(splice(@$conns, $i, 1), "$type capacity exceeded");
	    }
	}
    }

    if (defined(my $total = $self->{cc_limit_total})) {
	while (@$conns > $total) {
	    $self->dropping(shift(@$conns), "Total capacity exceeded");
	}
    }
}


sub dropping {
    my($self, $c, $reason) = @_;
    print "DROPPING @$c [$reason]\n" if $DEBUG;
}


sub drop {
    my($self, $checker, $reason) = @_;
    if (ref($checker) ne "CODE") {
	# make it so
	if (!defined $checker) {
	    $checker = sub { 1 };  # drop all of them
	}
	elsif (_looks_like_number($checker)) {
	    my $age_limit = $checker;
	    my $time_limit = time - $age_limit;
	    $reason ||= "older than $age_limit";
	    $checker = sub { $_[3] < $time_limit };
	}
	else {
	    my $type = $checker;
	    $reason ||= "drop $type";
	    $checker = sub { $_[1] eq $type };  # match on type
	}
    }
    $reason ||= "drop";

    local $SIG{__DIE__};  # don't interfere with eval below
    local $@;
    my @c;
    for (@{$self->{cc_conns}}) {
	my $drop;
	eval {
	    if (&$checker(@$_)) {
		$self->dropping($_, $reason);
		$drop++;
	    }
	};
	push(@c, $_) unless $drop;
    }
    @{$self->{cc_conns}} = @c;
}


sub prune {
    my $self = shift;
    $self->drop(sub { !shift->ping }, "ping");
}


sub get_types {
    my $self = shift;
    my %t;
    $t{$_->[1]}++ for @{$self->{cc_conns}};
    return keys %t;
}


sub get_connections {
    my($self, $type) = @_;
    my @c;
    for (@{$self->{cc_conns}}) {
	push(@c, $_->[0]) if !$type || ($type && $type eq $_->[1]);
    }
    @c;
}


sub _looks_like_number {
    $_[0] =~ /^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/;
}

1;


__END__

=pod

=head1 NAME

LWP::ConnCache - Connection cache manager

=head1 NOTE

This module is experimental.  Details of its interface is likely to
change in the future.

=head1 SYNOPSIS

 use LWP::ConnCache;
 my $cache = LWP::ConnCache->new;
 $cache->deposit($type, $key, $sock);
 $sock = $cache->withdraw($type, $key);

=head1 DESCRIPTION

The C<LWP::ConnCache> class is the standard connection cache manager
for L<LWP::UserAgent>.

=head1 METHODS

The following basic methods are provided:

=head2 new

    my $cache = LWP::ConnCache->new( %options )

This method constructs a new L<LWP::ConnCache> object.  The only
option currently accepted is C<total_capacity>.  If specified it
initializes the L<LWP::ConnCache/total_capacity> option. It defaults to C<1>.

=head2 total_capacity

    my $cap = $cache->total_capacity;
    $cache->total_capacity(0); # drop all immediately
    $cache->total_capacity(undef); # no limit
    $cache->total_capacity($number);

Get/sets the number of connection that will be cached.  Connections
will start to be dropped when this limit is reached.  If set to C<0>,
then all connections are immediately dropped.  If set to C<undef>,
then there is no limit.

=head2 capacity

    my $http_capacity = $cache->capacity('http');
    $cache->capacity('http', 2 );

Get/set a limit for the number of connections of the specified type
that can be cached.  The first parameter is a short string like
C<"http"> or C<"ftp">.

=head2 drop

    $cache->drop(); # Drop ALL connections
    # which is just a synonym for:
    $cache->drop(sub{1}); # Drop ALL connections
    # drop all connections older than 22 seconds and add a reason for it!
    $cache->drop(22, "Older than 22 secs dropped");
    # which is just a synonym for:
    $cache->drop(sub {
        my ($conn, $type, $key, $deposit_time) = @_;
        if ($deposit_time < 22) {
            # true values drop the connection
            return 1;
        }
        # false values don't drop the connection
        return 0;
    }, "Older than 22 secs dropped" );

Drop connections by some criteria.  The $checker argument is a
subroutine that is called for each connection.  If the routine returns
a TRUE value then the connection is dropped.  The routine is called
with C<($conn, $type, $key, $deposit_time)> as arguments.

Shortcuts: If the C<$checker> argument is absent (or C<undef>) all cached
connections are dropped.  If the $checker is a number then all
connections untouched that the given number of seconds or more are
dropped.  If $checker is a string then all connections of the given
type are dropped.

The C<reason> is passed on to the L<LWP::ConnCache/dropped> method.

=head2 prune

    $cache->prune();

Calling this method will drop all connections that are dead.  This is
tested by calling the L<LWP::ConnCache/ping> method on the connections. If
the L<LWP::ConnCache/ping> method exists and returns a false value, then the
connection is dropped.

=head2 get_types

    my @types = $cache->get_types();

This returns all the C<type> fields used for the currently cached
connections.

=head2 get_connections

    my @conns = $cache->get_connections(); # all connections
    my @conns = $cache->get_connections('http'); # connections for http

This returns all connection objects of the specified type.  If no type
is specified then all connections are returned.  In scalar context the
number of cached connections of the specified type is returned.

=head1 PROTOCOL METHODS

The following methods are called by low-level protocol modules to
try to save away connections and to get them back.

=head2 deposit

    $cache->deposit($type, $key, $conn);

This method adds a new connection to the cache.  As a result, other
already cached connections might be dropped.  Multiple connections with
the same type/key might be added.

=head2 withdraw

    my $conn = $cache->withdraw($type, $key);

This method tries to fetch back a connection that was previously
deposited.  If no cached connection with the specified $type/$key is
found, then C<undef> is returned.  There is not guarantee that a
deposited connection can be withdrawn, as the cache manger is free to
drop connections at any time.

=head1 INTERNAL METHODS

The following methods are called internally.  Subclasses might want to
override them.

=head2 enforce_limits

    $conn->enforce_limits([$type])

This method is called with after a new connection is added (deposited)
in the cache or capacity limits are adjusted.  The default
implementation drops connections until the specified capacity limits
are not exceeded.

=head2 dropping

    $conn->dropping($conn_record, $reason)

This method is called when a connection is dropped.  The record
belonging to the dropped connection is passed as the first argument
and a string describing the reason for the drop is passed as the
second argument.  The default implementation makes some noise if the
C<$LWP::ConnCache::DEBUG> variable is set and nothing more.

=head1 SUBCLASSING

For specialized cache policy it makes sense to subclass
C<LWP::ConnCache> and perhaps override the L<LWP::ConnCache/deposit>,
L<LWP::ConnCache/enforce_limits>, and L<LWP::ConnCache/dropping> methods.

The object itself is a hash.  Keys prefixed with C<cc_> are reserved
for the base class.

=head1 SEE ALSO

L<LWP::UserAgent>

=head1 COPYRIGHT

Copyright 2001 Gisle Aas.

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

=cut
PK6N%[��3v�(�(perl5/LWP/UserAgent.pmnu��6�$package LWP::UserAgent;

use strict;

use parent qw(LWP::MemberMixin);

use Carp ();
use File::Copy ();
use HTTP::Request ();
use HTTP::Response ();
use HTTP::Date ();

use LWP ();
use HTTP::Status ();
use LWP::Protocol ();
use Module::Load qw( load );

use Scalar::Util qw(blessed openhandle);
use Try::Tiny qw(try catch);

our $VERSION = '6.78';

sub new
{
    # Check for common user mistake
    Carp::croak("Options to LWP::UserAgent should be key/value pairs, not hash reference")
        if ref($_[1]) eq 'HASH';

    my($class, %cnf) = @_;

    my $agent = delete $cnf{agent};
    my $from  = delete $cnf{from};
    my $def_headers = delete $cnf{default_headers};
    my $timeout = delete $cnf{timeout};
    $timeout = 3*60 unless defined $timeout;
    my $local_address = delete $cnf{local_address};
    my $ssl_opts = delete $cnf{ssl_opts} || {};
    unless (exists $ssl_opts->{verify_hostname}) {
	# The processing of HTTPS_CA_* below is for compatibility with Crypt::SSLeay
	if (exists $ENV{PERL_LWP_SSL_VERIFY_HOSTNAME}) {
	    $ssl_opts->{verify_hostname} = $ENV{PERL_LWP_SSL_VERIFY_HOSTNAME};
	}
	elsif ($ENV{HTTPS_CA_FILE} || $ENV{HTTPS_CA_DIR}) {
	    # Crypt-SSLeay compatibility (verify peer certificate; but not the hostname)
	    $ssl_opts->{verify_hostname} = 0;
	    $ssl_opts->{SSL_verify_mode} = 1;
	}
	else {
	    $ssl_opts->{verify_hostname} = 1;
	}
    }
    unless (exists $ssl_opts->{SSL_ca_file}) {
	if (my $ca_file = $ENV{PERL_LWP_SSL_CA_FILE} || $ENV{HTTPS_CA_FILE}) {
	    $ssl_opts->{SSL_ca_file} = $ca_file;
	}
    }
    unless (exists $ssl_opts->{SSL_ca_path}) {
	if (my $ca_path = $ENV{PERL_LWP_SSL_CA_PATH} || $ENV{HTTPS_CA_DIR}) {
	    $ssl_opts->{SSL_ca_path} = $ca_path;
	}
    }
    my $use_eval = delete $cnf{use_eval};
    $use_eval = 1 unless defined $use_eval;
    my $parse_head = delete $cnf{parse_head};
    $parse_head = 1 unless defined $parse_head;
    my $send_te = delete $cnf{send_te};
    $send_te = 1 unless defined $send_te;
    my $show_progress = delete $cnf{show_progress};
    my $max_size = delete $cnf{max_size};
    my $max_redirect = delete $cnf{max_redirect};
    $max_redirect = 7 unless defined $max_redirect;
    my $env_proxy = exists $cnf{env_proxy} ? delete $cnf{env_proxy} : $ENV{PERL_LWP_ENV_PROXY};
    my $no_proxy = exists $cnf{no_proxy} ? delete $cnf{no_proxy} : [];
    Carp::croak(qq{no_proxy must be an arrayref, not $no_proxy!}) if ref $no_proxy ne 'ARRAY';

    my $proxy = exists $cnf{proxy} ? delete $cnf{proxy} : [];

    my $cookie_jar = delete $cnf{cookie_jar};
    my $conn_cache = delete $cnf{conn_cache};
    my $keep_alive = delete $cnf{keep_alive};

    Carp::croak("Can't mix conn_cache and keep_alive")
	  if $conn_cache && $keep_alive;

    my $protocols_allowed   = delete $cnf{protocols_allowed};
    my $protocols_forbidden = delete $cnf{protocols_forbidden};

    my $requests_redirectable = delete $cnf{requests_redirectable};
    $requests_redirectable = ['GET', 'HEAD']
      unless defined $requests_redirectable;

    my $cookie_jar_class = delete $cnf{cookie_jar_class};
    $cookie_jar_class = 'HTTP::Cookies'
      unless defined $cookie_jar_class;

    # Actually ""s are just as good as 0's, but for concision we'll just say:
    Carp::croak("protocols_allowed has to be an arrayref or 0, not \"$protocols_allowed\"!")
      if $protocols_allowed and ref($protocols_allowed) ne 'ARRAY';
    Carp::croak("protocols_forbidden has to be an arrayref or 0, not \"$protocols_forbidden\"!")
      if $protocols_forbidden and ref($protocols_forbidden) ne 'ARRAY';
    Carp::croak("requests_redirectable has to be an arrayref or 0, not \"$requests_redirectable\"!")
      if $requests_redirectable and ref($requests_redirectable) ne 'ARRAY';

    if (%cnf && $^W) {
	Carp::carp("Unrecognized LWP::UserAgent options: @{[sort keys %cnf]}");
    }

    my $self = bless {
        def_headers           => $def_headers,
        timeout               => $timeout,
        local_address         => $local_address,
        ssl_opts              => $ssl_opts,
        use_eval              => $use_eval,
        show_progress         => $show_progress,
        max_size              => $max_size,
        max_redirect          => $max_redirect,
        # We set proxy later as we do validation on the values
        proxy                 => {},
        no_proxy              => [ @{ $no_proxy } ],
        protocols_allowed     => $protocols_allowed,
        protocols_forbidden   => $protocols_forbidden,
        requests_redirectable => $requests_redirectable,
        send_te               => $send_te,
        cookie_jar_class      => $cookie_jar_class,
    }, $class;

    $self->agent(defined($agent) ? $agent : $class->_agent)
        if defined($agent) || !$def_headers || !$def_headers->header("User-Agent");
    $self->from($from) if $from;
    $self->cookie_jar($cookie_jar) if $cookie_jar;
    $self->parse_head($parse_head);
    $self->env_proxy if $env_proxy;

    if ($proxy) {
        Carp::croak(qq{proxy must be an arrayref, not $cnf{proxy}!})
            if ref $proxy ne 'ARRAY';
        $self->proxy($proxy);
    }

    $self->protocols_allowed(  $protocols_allowed  ) if $protocols_allowed;
    $self->protocols_forbidden($protocols_forbidden) if $protocols_forbidden;

    if ($keep_alive) {
	$conn_cache ||= { total_capacity => $keep_alive };
    }
    $self->conn_cache($conn_cache) if $conn_cache;

    return $self;
}


sub send_request
{
    my($self, $request, $arg, $size) = @_;
    my($method, $url) = ($request->method, $request->uri);
    my $scheme = $url->scheme;

    local($SIG{__DIE__});  # protect against user defined die handlers

    $self->progress("begin", $request);

    my $response = $self->run_handlers("request_send", $request);

    unless ($response) {
        my $protocol;

        {
            # Honor object-specific restrictions by forcing protocol objects
            #  into class LWP::Protocol::nogo.
            my $x;
            if($x = $self->protocols_allowed) {
                if (grep lc($_) eq $scheme, @$x) {
                }
                else {
                    require LWP::Protocol::nogo;
                    $protocol = LWP::Protocol::nogo->new;
                }
            }
            elsif ($x = $self->protocols_forbidden) {
                if(grep lc($_) eq $scheme, @$x) {
                    require LWP::Protocol::nogo;
                    $protocol = LWP::Protocol::nogo->new;
                }
            }
            # else fall thru and create the protocol object normally
        }

        # Locate protocol to use
        my $proxy = $request->{proxy};
        if ($proxy) {
            $scheme = $proxy->scheme;
        }

        unless ($protocol) {
            try {
                $protocol = LWP::Protocol::create($scheme, $self);
            }
            catch {
                my $error = $_;
                $error =~ s/ at .* line \d+.*//s;  # remove file/line number
                $response =  _new_response($request, HTTP::Status::RC_NOT_IMPLEMENTED, $error);
                if ($scheme eq "https") {
                    $response->message($response->message . " (LWP::Protocol::https not installed)");
                    $response->content_type("text/plain");
                    $response->content(<<EOT);
LWP will support https URLs if the LWP::Protocol::https module
is installed.
EOT
                }
            };
        }

        if (!$response && $self->{use_eval}) {
            # we eval, and turn dies into responses below
            try {
                $response = $protocol->request($request, $proxy, $arg, $size, $self->{timeout}) || die "No response returned by $protocol";
            }
            catch {
                my $error = $_;
                if (blessed($error) && $error->isa("HTTP::Response")) {
                    $response = $error;
                    $response->request($request);
                }
                else {
                    my $full = $error;
                    (my $status = $error) =~ s/\n.*//s;
                    $status =~ s/ at .* line \d+.*//s;  # remove file/line number
                    my $code = ($status =~ s/^(\d\d\d)\s+//) ? $1 : HTTP::Status::RC_INTERNAL_SERVER_ERROR;
                    $response = _new_response($request, $code, $status, $full);
                }
            };
        }
        elsif (!$response) {
            $response = $protocol->request($request, $proxy,
                                           $arg, $size, $self->{timeout});
            # XXX: Should we die unless $response->is_success ???
        }
    }

    $response->request($request);  # record request for reference
    $response->header("Client-Date" => HTTP::Date::time2str(time));

    $self->run_handlers("response_done", $response);

    $self->progress("end", $response);
    return $response;
}


sub prepare_request
{
    my($self, $request) = @_;
    die "Method missing" unless $request->method;
    my $url = $request->uri;
    die "URL missing" unless $url;
    die "URL must be absolute" unless $url->scheme;

    $self->run_handlers("request_preprepare", $request);

    if (my $def_headers = $self->{def_headers}) {
	for my $h ($def_headers->header_field_names) {
	    $request->init_header($h => [$def_headers->header($h)]);
	}
    }

    $self->run_handlers("request_prepare", $request);

    return $request;
}


sub simple_request
{
    my($self, $request, $arg, $size) = @_;

    # sanity check the request passed in
    if (defined $request) {
	if (ref $request) {
	    Carp::croak("You need a request object, not a " . ref($request) . " object")
	      if ref($request) eq 'ARRAY' or ref($request) eq 'HASH' or
		 !$request->can('method') or !$request->can('uri');
	}
	else {
	    Carp::croak("You need a request object, not '$request'");
	}
    }
    else {
        Carp::croak("No request object passed in");
    }

    my $error;
    try {
        $request = $self->prepare_request($request);
    }
    catch {
        $error = $_;
        $error =~ s/ at .* line \d+.*//s;  # remove file/line number
    };

    if ($error) {
        return _new_response($request, HTTP::Status::RC_BAD_REQUEST, $error);
    }
    return $self->send_request($request, $arg, $size);
}


sub request {
    my ($self, $request, $arg, $size, $previous) = @_;

    my $response = $self->simple_request($request, $arg, $size);
    $response->previous($previous) if $previous;

    if ($response->redirects >= $self->{max_redirect}) {
        if ($response->header('Location')) {
            $response->header("Client-Warning" =>
                "Redirect loop detected (max_redirect = $self->{max_redirect})"
            );
        }
        return $response;
    }

    if (my $req = $self->run_handlers("response_redirect", $response)) {
        return $self->request($req, $arg, $size, $response);
    }

    my $code = $response->code;

    if (   $code == HTTP::Status::RC_MOVED_PERMANENTLY
        or $code == HTTP::Status::RC_FOUND
        or $code == HTTP::Status::RC_SEE_OTHER
        or $code == HTTP::Status::RC_TEMPORARY_REDIRECT
        or $code == HTTP::Status::RC_PERMANENT_REDIRECT)
    {
        my $referral = $request->clone;

        # These headers should never be forwarded
        $referral->remove_header('Host', 'Cookie');

        if (   $referral->header('Referer')
            && $request->uri->scheme eq 'https'
            && $referral->uri->scheme eq 'http')
        {
            # RFC 2616, section 15.1.3.
            # https -> http redirect, suppressing Referer
            $referral->remove_header('Referer');
        }

        if (   $code == HTTP::Status::RC_SEE_OTHER
            || $code == HTTP::Status::RC_FOUND)
        {
            my $method = uc($referral->method);
            unless ($method eq "GET" || $method eq "HEAD") {
                $referral->method("GET");
                $referral->content("");
                $referral->remove_content_headers;
            }
        }

        # And then we update the URL based on the Location:-header.
        my $referral_uri = $response->header('Location');
        {
            # Some servers erroneously return a relative URL for redirects,
            # so make it absolute if it not already is.
            local $URI::ABS_ALLOW_RELATIVE_SCHEME = 1;
            my $base = $response->base;
            $referral_uri = "" unless defined $referral_uri;
            $referral_uri
                = $HTTP::URI_CLASS->new($referral_uri, $base)->abs($base);
        }
        $referral->uri($referral_uri);

        return $response unless $self->redirect_ok($referral, $response);
        return $self->request($referral, $arg, $size, $response);

    }
    elsif ($code == HTTP::Status::RC_UNAUTHORIZED
        || $code == HTTP::Status::RC_PROXY_AUTHENTICATION_REQUIRED)
    {
        my $proxy = ($code == HTTP::Status::RC_PROXY_AUTHENTICATION_REQUIRED);
        my $ch_header
            = $proxy || $request->method eq 'CONNECT'
            ? "Proxy-Authenticate"
            : "WWW-Authenticate";
        my @challenges = $response->header($ch_header);
        unless (@challenges) {
            $response->header(
                "Client-Warning" => "Missing Authenticate header");
            return $response;
        }

        require HTTP::Headers::Util;
        CHALLENGE: for my $challenge (@challenges) {
            $challenge =~ tr/,/;/;    # "," is used to separate auth-params!!
            ($challenge) = HTTP::Headers::Util::split_header_words($challenge);
            my $scheme = shift(@$challenge);
            shift(@$challenge);       # no value
            $challenge = {@$challenge};    # make rest into a hash

            unless ($scheme =~ /^([a-z]+(?:-[a-z]+)*)$/) {
                $response->header(
                    "Client-Warning" => "Bad authentication scheme '$scheme'");
                return $response;
            }
            $scheme = $1;                  # untainted now
            my $class = "LWP::Authen::\u$scheme";
            $class =~ tr/-/_/;

            no strict 'refs';
            unless (%{"$class\::"}) {
                # try to load it
                my $error;
                try {
                    (my $req = $class) =~ s{::}{/}g;
                    $req .= '.pm' unless $req =~ /\.pm$/;
                    require $req;
                }
                catch {
                    $error = $_;
                };
                if ($error) {
                    if ($error =~ /^Can\'t locate/) {
                        $response->header("Client-Warning" =>
                                "Unsupported authentication scheme '$scheme'");
                    }
                    else {
                        $response->header("Client-Warning" => $error);
                    }
                    next CHALLENGE;
                }
            }
            unless ($class->can("authenticate")) {
                $response->header("Client-Warning" =>
                        "Unsupported authentication scheme '$scheme'");
                next CHALLENGE;
            }
            my $re = $class->authenticate($self, $proxy, $challenge, $response,
                $request, $arg, $size);

            next CHALLENGE if $re->code == HTTP::Status::RC_UNAUTHORIZED;
            return $re;
        }
        return $response;
    }
    return $response;
}

#
# Now the shortcuts...
#
sub get {
    require HTTP::Request::Common;
    my($self, @parameters) = @_;
    my @suff = $self->_process_colonic_headers(\@parameters,1);
    return $self->request( HTTP::Request::Common::GET( @parameters ), @suff );
}

sub _maybe_copy_default_content_type {
    my $self = shift;
    my $req  = shift;

    my $default_ct = $self->default_header('Content-Type');
    return unless defined $default_ct;

    # drop url
    shift;

    # adapted from HTTP::Request::Common::request_type_with_data
    my $content;
    $content = shift if @_ and ref $_[0];

    # We only care about the final value, really
    my $ct;

    my ($k, $v);
    while (($k, $v) = splice(@_, 0, 2)) {
        if (lc($k) eq 'content') {
            $content = $v;
        }
        elsif (lc($k) eq 'content-type') {
            $ct = $v;
        }
    }

    # Content-type provided and truthy? skip
    return if $ct;

    # Content is not just a string? Then it must be x-www-form-urlencoded
    return if defined $content && ref($content);

    # Provide default
    $req->header('Content-Type' => $default_ct);
}

sub post {
    require HTTP::Request::Common;
    my($self, @parameters) = @_;
    my @suff = $self->_process_colonic_headers(\@parameters, (ref($parameters[1]) ? 2 : 1));
    my $req = HTTP::Request::Common::POST(@parameters);
    $self->_maybe_copy_default_content_type($req, @parameters);
    return $self->request($req, @suff);
}


sub head {
    require HTTP::Request::Common;
    my($self, @parameters) = @_;
    my @suff = $self->_process_colonic_headers(\@parameters,1);
    return $self->request( HTTP::Request::Common::HEAD( @parameters ), @suff );
}

sub patch {
    require HTTP::Request::Common;
    my($self, @parameters) = @_;
    my @suff = $self->_process_colonic_headers(\@parameters, (ref($parameters[1]) ? 2 : 1));

    # this work-around is in place as HTTP::Request::Common
    # did not implement a patch convenience method until
    # version 6.12. Once we can bump the prereq to at least
    # that version, we can use ::PATCH instead of this hack
    my $req = HTTP::Request::Common::PUT(@parameters);
    $req->method('PATCH');

    $self->_maybe_copy_default_content_type($req, @parameters);
    return $self->request($req, @suff);
}

sub put {
    require HTTP::Request::Common;
    my($self, @parameters) = @_;
    my @suff = $self->_process_colonic_headers(\@parameters, (ref($parameters[1]) ? 2 : 1));
    my $req = HTTP::Request::Common::PUT(@parameters);
    $self->_maybe_copy_default_content_type($req, @parameters);
    return $self->request($req, @suff);
}


sub delete {
    require HTTP::Request::Common;
    my($self, @parameters) = @_;
    my @suff = $self->_process_colonic_headers(\@parameters,1);
    return $self->request( HTTP::Request::Common::DELETE( @parameters ), @suff );
}


sub _process_colonic_headers {
    # Process :content_cb / :content_file / :read_size_hint headers.
    my($self, $args, $start_index) = @_;

    my($arg, $size);
    for(my $i = $start_index; $i < @$args; $i += 2) {
	next unless defined $args->[$i];

	#printf "Considering %s => %s\n", $args->[$i], $args->[$i + 1];

	if($args->[$i] eq ':content_cb') {
	    # Some sanity-checking...
	    $arg = $args->[$i + 1];
	    Carp::croak("A :content_cb value can't be undef") unless defined $arg;
	    Carp::croak("A :content_cb value must be a coderef")
		unless ref $arg and UNIVERSAL::isa($arg, 'CODE');

	}
	elsif ($args->[$i] eq ':content_file') {
	    $arg = $args->[$i + 1];

	    # Some sanity-checking...
	    Carp::croak("A :content_file value can't be undef")
		unless defined $arg;

	    unless ( defined openhandle($arg) ) {
		    Carp::croak("A :content_file value can't be a reference")
			if ref $arg;
		    Carp::croak("A :content_file value can't be \"\"")
			unless length $arg;
	    }
	}
	elsif ($args->[$i] eq ':read_size_hint') {
	    $size = $args->[$i + 1];
	    # Bother checking it?

	}
	else {
	    next;
	}
	splice @$args, $i, 2;
	$i -= 2;
    }

    # And return a suitable suffix-list for request(REQ,...)

    return             unless defined $arg;
    return $arg, $size if     defined $size;
    return $arg;
}


sub is_online {
    my $self = shift;
    return 1 if $self->get("http://www.msftncsi.com/ncsi.txt")->content eq "Microsoft NCSI";
    return 1 if $self->get("http://www.apple.com")->content =~ m,<title>Apple</title>,;
    return 0;
}


my @ANI = qw(- \ | /);

sub progress {
    my($self, $status, $m) = @_;
    return unless $self->{show_progress};

    local($,, $\);
    if ($status eq "begin") {
        print STDERR "** ", $m->method, " ", $m->uri, " ==> ";
        $self->{progress_start} = time;
        $self->{progress_lastp} = "";
        $self->{progress_ani} = 0;
    }
    elsif ($status eq "end") {
        delete $self->{progress_lastp};
        delete $self->{progress_ani};
        print STDERR $m->status_line;
        my $t = time - delete $self->{progress_start};
        print STDERR " (${t}s)" if $t;
        print STDERR "\n";
    }
    elsif ($status eq "tick") {
        print STDERR "$ANI[$self->{progress_ani}++]\b";
        $self->{progress_ani} %= @ANI;
    }
    else {
        my $p = sprintf "%3.0f%%", $status * 100;
        return if $p eq $self->{progress_lastp};
        print STDERR "$p\b\b\b\b";
        $self->{progress_lastp} = $p;
    }
    STDERR->flush;
}


#
# This whole allow/forbid thing is based on man 1 at's way of doing things.
#
sub is_protocol_supported
{
    my($self, $scheme) = @_;
    if (ref $scheme) {
	# assume we got a reference to a URI object
	$scheme = $scheme->scheme;
    }
    else {
	Carp::croak("Illegal scheme '$scheme' passed to is_protocol_supported")
	    if $scheme =~ /\W/;
	$scheme = lc $scheme;
    }

    my $x;
    if(ref($self) and $x       = $self->protocols_allowed) {
      return 0 unless grep lc($_) eq $scheme, @$x;
    }
    elsif (ref($self) and $x = $self->protocols_forbidden) {
      return 0 if grep lc($_) eq $scheme, @$x;
    }

    local($SIG{__DIE__});  # protect against user defined die handlers
    $x = LWP::Protocol::implementor($scheme);
    return 1 if $x and $x ne 'LWP::Protocol::nogo';
    return 0;
}


sub protocols_allowed      { shift->_elem('protocols_allowed'    , @_) }
sub protocols_forbidden    { shift->_elem('protocols_forbidden'  , @_) }
sub requests_redirectable  { shift->_elem('requests_redirectable', @_) }


sub redirect_ok
{
    # RFC 2616, section 10.3.2 and 10.3.3 say:
    #  If the 30[12] status code is received in response to a request other
    #  than GET or HEAD, the user agent MUST NOT automatically redirect the
    #  request unless it can be confirmed by the user, since this might
    #  change the conditions under which the request was issued.

    # Note that this routine used to be just:
    #  return 0 if $_[1]->method eq "POST";  return 1;

    my($self, $new_request, $response) = @_;
    my $method = $response->request->method;
    return 0 unless grep $_ eq $method,
      @{ $self->requests_redirectable || [] };

    if ($new_request->uri->scheme eq 'file') {
      $response->header("Client-Warning" =>
			"Can't redirect to a file:// URL!");
      return 0;
    }

    # Otherwise it's apparently okay...
    return 1;
}

sub credentials {
    my $self   = shift;
    my $netloc = lc(shift || '');
    my $realm  = shift || "";
    my $old    = $self->{basic_authentication}{$netloc}{$realm};
    if (@_) {
        $self->{basic_authentication}{$netloc}{$realm} = [@_];
    }
    return unless $old;
    return @$old if wantarray;
    return join(":", @$old);
}

sub get_basic_credentials
{
    my($self, $realm, $uri, $proxy) = @_;
    return if $proxy;
    return $self->credentials($uri->host_port, $realm);
}


sub timeout
{
    my $self = shift;
    my $old = $self->{timeout};
    if (@_) {
        $self->{timeout} = shift;
        if (my $conn_cache = $self->conn_cache) {
            for my $conn ($conn_cache->get_connections) {
                $conn->timeout($self->{timeout});
            }
        }
    }
    return $old;
}

sub local_address{ shift->_elem('local_address',@_); }
sub max_size     { shift->_elem('max_size',     @_); }
sub max_redirect { shift->_elem('max_redirect', @_); }
sub show_progress{ shift->_elem('show_progress', @_); }
sub send_te      { shift->_elem('send_te',      @_); }

sub ssl_opts {
    my $self = shift;
    if (@_ == 1) {
	my $k = shift;
	return $self->{ssl_opts}{$k};
    }
    if (@_) {
	my $old;
	while (@_) {
	    my($k, $v) = splice(@_, 0, 2);
	    $old = $self->{ssl_opts}{$k} unless @_;
	    if (defined $v) {
		$self->{ssl_opts}{$k} = $v;
	    }
	    else {
		delete $self->{ssl_opts}{$k};
	    }
	}
	%{$self->{ssl_opts}} = (%{$self->{ssl_opts}}, @_);
	return $old;
    }

    my @opts= sort keys %{$self->{ssl_opts}};
    return @opts;
}

sub parse_head {
    my $self = shift;
    if (@_) {
        my $flag = shift;
        my $parser;
        my $old = $self->set_my_handler("response_header", $flag ? sub {
               my($response, $ua) = @_;
               require HTML::HeadParser;
               $parser = HTML::HeadParser->new;
               $parser->xml_mode(1) if $response->content_is_xhtml;
               $parser->utf8_mode(1) if $HTML::Parser::VERSION >= 3.40;

               push(@{$response->{handlers}{response_data}}, {
		   callback => sub {
		       return unless $parser;
		       unless ($parser->parse($_[3])) {
			   my $h = $parser->header;
			   my $r = $_[0];
			   for my $f ($h->header_field_names) {
			       $r->init_header($f, [$h->header($f)]);
			   }
			   undef($parser);
		       }
		   },
	       });

            } : undef,
            m_media_type => "html",
        );
        return !!$old;
    }
    else {
        return !!$self->get_my_handler("response_header");
    }
}

sub cookie_jar {
    my $self = shift;
    my $old = $self->{cookie_jar};

    return $old unless @_;

    my $jar = shift;
    if (ref($jar) eq "HASH") {
        my $class = $self->{cookie_jar_class};
        try {
            load($class);
            $jar = $class->new(%$jar);
        }
        catch {
            my $error = $_;
            if ($error =~ /Can't locate/) {
                die "cookie_jar_class '$class' not found\n";
            }
            else {
                die "$error\n";
            }
        };
    }
    $self->{cookie_jar} = $jar;
    $self->set_my_handler("request_prepare",
        $jar ? sub {
            return if $_[0]->header("Cookie");
            $jar->add_cookie_header($_[0]);
        } : undef,
    );
    $self->set_my_handler("response_done",
        $jar ? sub { $jar->extract_cookies($_[0]); } : undef,
    );

    return $old;
}

sub default_headers {
    my $self = shift;
    my $old = $self->{def_headers} ||= HTTP::Headers->new;
    if (@_) {
	Carp::croak("default_headers not set to HTTP::Headers compatible object")
	    unless @_ == 1 && $_[0]->can("header_field_names");
	$self->{def_headers} = shift;
    }
    return $old;
}

sub default_header {
    my $self = shift;
    return $self->default_headers->header(@_);
}

sub _agent { "libwww-perl/$VERSION" }

sub agent {
    my $self = shift;
    if (@_) {
	my $agent = shift;
        if ($agent) {
            $agent .= $self->_agent if $agent =~ /\s+$/;
        }
        else {
            undef($agent)
        }
        return $self->default_header("User-Agent", $agent);
    }
    return $self->default_header("User-Agent");
}

sub from {  # legacy
    my $self = shift;
    return $self->default_header("From", @_);
}


sub conn_cache {
    my $self = shift;
    my $old  = $self->{conn_cache};
    if (@_) {
        my $cache = shift;
        if ( ref($cache) eq "HASH" ) {
            require LWP::ConnCache;
            $cache = LWP::ConnCache->new(%$cache);
        }
        elsif ( defined $cache)  {
            for my $conn ( $cache->get_connections ) {
                $conn->timeout( $self->timeout );
            }
        }
        $self->{conn_cache} = $cache;
    }
    return $old;
}


sub add_handler {
    my($self, $phase, $cb, %spec) = @_;
    $spec{line} ||= join(":", (caller)[1,2]);
    my $conf = $self->{handlers}{$phase} ||= do {
        require HTTP::Config;
        HTTP::Config->new;
    };
    $conf->add(%spec, callback => $cb);
}

sub set_my_handler {
    my($self, $phase, $cb, %spec) = @_;
    $spec{owner} = (caller(1))[3] unless exists $spec{owner};
    $self->remove_handler($phase, %spec);
    $spec{line} ||= join(":", (caller)[1,2]);
    $self->add_handler($phase, $cb, %spec) if $cb;
}

sub get_my_handler {
    my $self = shift;
    my $phase = shift;
    my $init = pop if @_ % 2;
    my %spec = @_;
    my $conf = $self->{handlers}{$phase};
    unless ($conf) {
        return unless $init;
        require HTTP::Config;
        $conf = $self->{handlers}{$phase} = HTTP::Config->new;
    }
    $spec{owner} = (caller(1))[3] unless exists $spec{owner};
    my @h = $conf->find(%spec);
    if (!@h && $init) {
        if (ref($init) eq "CODE") {
            $init->(\%spec);
        }
        elsif (ref($init) eq "HASH") {
            $spec{$_}= $init->{$_}
                for keys %$init;
        }
        $spec{callback} ||= sub {};
        $spec{line} ||= join(":", (caller)[1,2]);
        $conf->add(\%spec);
        return \%spec;
    }
    return wantarray ? @h : $h[0];
}

sub remove_handler {
    my($self, $phase, %spec) = @_;
    if ($phase) {
        my $conf = $self->{handlers}{$phase} || return;
        my @h = $conf->remove(%spec);
        delete $self->{handlers}{$phase} if $conf->empty;
        return @h;
    }

    return unless $self->{handlers};
    return map $self->remove_handler($_), sort keys %{$self->{handlers}};
}

sub handlers {
    my($self, $phase, $o) = @_;
    my @h;
    if ($o->{handlers} && $o->{handlers}{$phase}) {
        push(@h, @{$o->{handlers}{$phase}});
    }
    if (my $conf = $self->{handlers}{$phase}) {
        push(@h, $conf->matching($o));
    }
    return @h;
}

sub run_handlers {
    my($self, $phase, $o) = @_;

    # here we pass $_[2] to the callbacks, instead of $o, so that they
    # can assign to it; e.g. request_prepare is documented to allow
    # that
    if (defined(wantarray)) {
        for my $h ($self->handlers($phase, $o)) {
            my $ret = $h->{callback}->($_[2], $self, $h);
            return $ret if $ret;
        }
        return undef;
    }

    for my $h ($self->handlers($phase, $o)) {
        $h->{callback}->($_[2], $self, $h);
    }
}


# deprecated
sub use_eval   { shift->_elem('use_eval',  @_); }
sub use_alarm
{
    Carp::carp("LWP::UserAgent->use_alarm(BOOL) is a no-op")
	if @_ > 1 && $^W;
    "";
}


sub clone
{
    my $self = shift;
    my $copy = bless { %$self }, ref $self;  # copy most fields

    delete $copy->{handlers};
    delete $copy->{conn_cache};

    # copy any plain arrays and hashes; known not to need recursive copy
    for my $k (qw(proxy no_proxy requests_redirectable ssl_opts)) {
        next unless $copy->{$k};
        if (ref($copy->{$k}) eq "ARRAY") {
            $copy->{$k} = [ @{$copy->{$k}} ];
        }
        elsif (ref($copy->{$k}) eq "HASH") {
            $copy->{$k} = { %{$copy->{$k}} };
        }
    }

    if ($self->{def_headers}) {
        $copy->{def_headers} = $self->{def_headers}->clone;
    }

    # re-enable standard handlers
    $copy->parse_head($self->parse_head);

    # no easy way to clone the cookie jar; so let's just remove it for now
    $copy->cookie_jar(undef);

    $copy;
}


sub mirror
{
    my($self, $url, $file) = @_;

    die "Local file name is missing" unless defined $file && length $file;

    my $request = HTTP::Request->new('GET', $url);

    # If the file exists, add a cache-related header
    if ( -e $file ) {
        my ($mtime) = ( stat($file) )[9];
        if ($mtime) {
            $request->header( 'If-Modified-Since' => HTTP::Date::time2str($mtime) );
        }
    }

    require File::Temp;
    my ($tmpfh, $tmpfile) = File::Temp::tempfile("$file-XXXXXX");
    close($tmpfh) or die "Could not close tmpfile '$tmpfile': $!";

    my $response = $self->request($request, $tmpfile);
    if ( $response->header('X-Died') ) {
        unlink($tmpfile);
        die $response->header('X-Died');
    }

    # Only fetching a fresh copy of the file would be considered success.
    # If the file was not modified, "304" would returned, which
    # is considered by HTTP::Status to be a "redirect", /not/ "success"
    if ( $response->is_success ) {
        my @stat        = stat($tmpfile) or die "Could not stat tmpfile '$tmpfile': $!";
        my $file_length = $stat[7];
        my ($content_length) = $response->header('Content-length');

        if ( defined $content_length and $file_length < $content_length ) {
            unlink($tmpfile);
            die "Transfer truncated: only $file_length out of $content_length bytes received\n";
        }
        elsif ( defined $content_length and $file_length > $content_length ) {
            unlink($tmpfile);
            die "Content-length mismatch: expected $content_length bytes, got $file_length\n";
        }
        # The file was the expected length.
        else {
            # Replace the stale file with a fresh copy
            # File::Copy will attempt to do it atomically,
            # and fall back to a delete + copy if that fails.
            File::Copy::move( $tmpfile, $file )
                or die "Cannot rename '$tmpfile' to '$file': $!\n";

            # Set standard file permissions if umask is supported.
            # If not, leave what File::Temp created in effect.
            if ( defined(my $umask = umask()) ) {
                my $mode = 0666 &~ $umask;
                chmod $mode, $file
                    or die sprintf("Cannot chmod %o '%s': %s\n", $mode, $file, $!);
            }

            # make sure the file has the same last modification time
            if ( my $lm = $response->last_modified ) {
                utime $lm, $lm, $file
                    or warn "Cannot update modification time of '$file': $!\n";
            }
        }
    }
    # The local copy is fresh enough, so just delete the temp file
    else {
        unlink($tmpfile);
    }
    return $response;
}


sub _need_proxy {
    my($req, $ua) = @_;
    return if exists $req->{proxy};
    my $proxy = $ua->{proxy}{$req->uri->scheme} || return;
    if ($ua->{no_proxy}) {
        if (my $host = eval { $req->uri->host }) {
            for my $domain (@{$ua->{no_proxy}}) {
                $domain =~ s/^\.//;
                return if $host =~ /(?:^|\.)\Q$domain\E$/;
            }
        }
    }
    $req->{proxy} = $HTTP::URI_CLASS->new($proxy);
}


sub proxy {
    my $self = shift;
    my $key  = shift;
    if (!@_ && ref $key eq 'ARRAY') {
        die 'odd number of items in proxy arrayref!' unless @{$key} % 2 == 0;

        # This map reads the elements of $key 2 at a time
        return
            map { $self->proxy($key->[2 * $_], $key->[2 * $_ + 1]) }
            (0 .. @{$key} / 2 - 1);
    }
    return map { $self->proxy($_, @_) } @$key if ref $key;

    Carp::croak("'$key' is not a valid URI scheme") unless $key =~ /^$URI::scheme_re\z/;
    my $old = $self->{'proxy'}{$key};
    if (@_) {
        my $url = shift;
        if (defined($url) && length($url)) {
            Carp::croak("Proxy must be specified as absolute URI; '$url' is not") unless $url =~ /^$URI::scheme_re:/;
            Carp::croak("Bad http proxy specification '$url'") if $url =~ /^https?:/ && $url !~ m,^https?://[\w[],;
        }
        $self->{proxy}{$key} = $url;
        $self->set_my_handler("request_preprepare", \&_need_proxy)
    }
    return $old;
}


sub env_proxy {
    my ($self) = @_;
    require Encode;
    require Encode::Locale;
    my $env_request_method= $ENV{REQUEST_METHOD};
    my %seen;
    foreach my $k (sort keys %ENV) {
        my $real_key= $k;
        my $v= $ENV{$k}
            or next;
        if ( $env_request_method ) {
            # Need to be careful when called in the CGI environment, as
            # the HTTP_PROXY variable is under control of that other guy.
            next if $k =~ /^HTTP_/;
            $k = "HTTP_PROXY" if $k eq "CGI_HTTP_PROXY";
        }
	$k = lc($k);
        if (my $from_key= $seen{$k}) {
            warn "Environment contains multiple differing definitions for '$k'.\n".
                 "Using value from '$from_key' ($ENV{$from_key}) and ignoring '$real_key' ($v)"
                if $v ne $ENV{$from_key};
            next;
        } else {
            $seen{$k}= $real_key;
        }

	next unless $k =~ /^(.*)_proxy$/;
	$k = $1;
	if ($k eq 'no') {
	    $self->no_proxy(split(/\s*,\s*/, $v));
	}
	else {
            # Ignore random _proxy variables, allow only valid schemes
            next unless $k =~ /^$URI::scheme_re\z/;
            # Ignore xxx_proxy variables if xxx isn't a supported protocol
            next unless LWP::Protocol::implementor($k);
	    $self->proxy($k, Encode::decode(locale => $v));
	}
    }
}


sub no_proxy {
    my($self, @no) = @_;
    if (@no) {
	push(@{ $self->{'no_proxy'} }, @no);
    }
    else {
	$self->{'no_proxy'} = [];
    }
}


sub _new_response {
    my($request, $code, $message, $content) = @_;
    $message ||= HTTP::Status::status_message($code);
    my $response = HTTP::Response->new($code, $message);
    $response->request($request);
    $response->header("Client-Date" => HTTP::Date::time2str(time));
    $response->header("Client-Warning" => "Internal response");
    $response->header("Content-Type" => "text/plain");
    $response->content($content || "$code $message\n");
    return $response;
}


1;

__END__

=pod

=head1 NAME

LWP::UserAgent - Web user agent class

=head1 SYNOPSIS

    use strict;
    use warnings;

    use LWP::UserAgent ();

    my $ua = LWP::UserAgent->new(timeout => 10);
    $ua->env_proxy;

    my $response = $ua->get('http://example.com');

    if ($response->is_success) {
        print $response->decoded_content;
    }
    else {
        die $response->status_line;
    }

Extra layers of security (note the C<cookie_jar> and C<protocols_allowed>):

    use strict;
    use warnings;

    use HTTP::CookieJar::LWP ();
    use LWP::UserAgent       ();

    my $jar = HTTP::CookieJar::LWP->new;
    my $ua  = LWP::UserAgent->new(
        cookie_jar        => $jar,
        protocols_allowed => ['http', 'https'],
        timeout           => 10,
    );

    $ua->env_proxy;

    my $response = $ua->get('http://example.com');

    if ($response->is_success) {
        print $response->decoded_content;
    }
    else {
        die $response->status_line;
    }

=head1 DESCRIPTION

The L<LWP::UserAgent> is a class implementing a web user agent.
L<LWP::UserAgent> objects can be used to dispatch web requests.

In normal use the application creates an L<LWP::UserAgent> object, and
then configures it with values for timeouts, proxies, name, etc. It
then creates an instance of L<HTTP::Request> for the request that
needs to be performed. This request is then passed to one of the
request method the UserAgent, which dispatches it using the relevant
protocol, and returns a L<HTTP::Response> object.  There are
convenience methods for sending the most common request types:
L<LWP::UserAgent/get>, L<LWP::UserAgent/head>, L<LWP::UserAgent/post>,
L<LWP::UserAgent/put> and L<LWP::UserAgent/delete>.  When using these
methods, the creation of the request object is hidden as shown in the
synopsis above.

The basic approach of the library is to use HTTP-style communication
for all protocol schemes.  This means that you will construct
L<HTTP::Request> objects and receive L<HTTP::Response> objects even
for non-HTTP resources like I<gopher> and I<ftp>.  In order to achieve
even more similarity to HTTP-style communications, I<gopher> menus and
file directories are converted to HTML documents.

=head1 CONSTRUCTOR METHODS

The following constructor methods are available:

=head2 clone

    my $ua2 = $ua->clone;

Returns a copy of the L<LWP::UserAgent> object.

B<CAVEAT>: Please be aware that the clone method does not copy or clone your
C<cookie_jar> attribute. Due to the limited restrictions on what can be used
for your cookie jar, there is no way to clone the attribute. The C<cookie_jar>
attribute will be C<undef> in the new object instance.

=head2 new

    my $ua = LWP::UserAgent->new( %options )

This method constructs a new L<LWP::UserAgent> object and returns it.
Key/value pair arguments may be provided to set up the initial state.
The following options correspond to attribute methods described below:

   KEY                     DEFAULT
   -----------             --------------------
   agent                   "libwww-perl/#.###"
   conn_cache              undef
   cookie_jar              undef
   cookie_jar_class        HTTP::Cookies
   default_headers         HTTP::Headers->new
   from                    undef
   local_address           undef
   max_redirect            7
   max_size                undef
   no_proxy                []
   parse_head              1
   protocols_allowed       undef
   protocols_forbidden     undef
   proxy                   {}
   requests_redirectable   ['GET', 'HEAD']
   send_te                 1
   show_progress           undef
   ssl_opts                { verify_hostname => 1 }
   timeout                 180

The following additional options are also accepted: If the C<env_proxy> option
is passed in with a true value, then proxy settings are read from environment
variables (see L<LWP::UserAgent/env_proxy>). If C<env_proxy> isn't provided, the
C<PERL_LWP_ENV_PROXY> environment variable controls if
L<LWP::UserAgent/env_proxy> is called during initialization.  If the
C<keep_alive> option value is defined and non-zero, then an C<LWP::ConnCache> is set up (see
L<LWP::UserAgent/conn_cache>).  The C<keep_alive> value is passed on as the
C<total_capacity> for the connection cache.

C<proxy> must be set as an arrayref of key/value pairs. C<no_proxy> takes an
arrayref of domains.

=head1 ATTRIBUTES

The settings of the configuration attributes modify the behaviour of the
L<LWP::UserAgent> when it dispatches requests.  Most of these can also
be initialized by options passed to the constructor method.

The following attribute methods are provided.  The attribute value is
left unchanged if no argument is given.  The return value from each
method is the old attribute value.

=head2 agent

    my $agent = $ua->agent;
    $ua->agent('Checkbot/0.4 ');    # append the default to the end
    $ua->agent('Mozilla/5.0');
    $ua->agent("");                 # don't identify

Get/set the product token that is used to identify the user agent on
the network. The agent value is sent as the C<User-Agent> header in
the requests.

The default is a string of the form C<libwww-perl/#.###>, where C<#.###> is
substituted with the version number of this library.

If the provided string ends with space, the default C<libwww-perl/#.###>
string is appended to it.

The user agent string should be one or more simple product identifiers
with an optional version number separated by the C</> character.

=head2 conn_cache

    my $cache_obj = $ua->conn_cache;
    $ua->conn_cache( $cache_obj );

Get/set the L<LWP::ConnCache> object to use.  See L<LWP::ConnCache>
for details.

=head2 cookie_jar

    my $jar = $ua->cookie_jar;
    $ua->cookie_jar( $cookie_jar_obj );

Get/set the cookie jar object to use.  The only requirement is that
the cookie jar object must implement the C<extract_cookies($response)> and
C<add_cookie_header($request)> methods.  These methods will then be
invoked by the user agent as requests are sent and responses are
received.  Normally this will be a L<HTTP::Cookies> object or some
subclass.  You are, however, encouraged to use L<HTTP::CookieJar::LWP>
instead.  See L</"BEST PRACTICES"> for more information.

    use HTTP::CookieJar::LWP ();

    my $jar = HTTP::CookieJar::LWP->new;
    my $ua = LWP::UserAgent->new( cookie_jar => $jar );

    # or after object creation
    $ua->cookie_jar( $cookie_jar );

The default is to have no cookie jar, i.e. never automatically add
C<Cookie> headers to the requests.

If C<$jar> contains an unblessed hash reference, a new cookie jar object is
created for you automatically. The object is of the class set with the
C<cookie_jar_class> constructor argument, which defaults to L<HTTP::Cookies>.

  $ua->cookie_jar({ file => "$ENV{HOME}/.cookies.txt" });

is really just a shortcut for:

  require HTTP::Cookies;
  $ua->cookie_jar(HTTP::Cookies->new(file => "$ENV{HOME}/.cookies.txt"));

As described above and in L</"BEST PRACTICES">, you should set
C<cookie_jar_class> to C<"HTTP::CookieJar::LWP"> to get a safer cookie jar.

  my $ua = LWP::UserAgent->new( cookie_jar_class => 'HTTP::CookieJar::LWP' );
  $ua->cookie_jar({}); # HTTP::CookieJar::LWP takes no args

These can also be combined into the constructor, so a jar is created at
instantiation.

  my $ua = LWP::UserAgent->new(
    cookie_jar_class => 'HTTP::CookieJar::LWP',
    cookie_jar       =>  {},
  );

=head2 credentials

    my $creds = $ua->credentials();
    $ua->credentials( $netloc, $realm );
    $ua->credentials( $netloc, $realm, $uname, $pass );
    $ua->credentials("www.example.com:80", "Some Realm", "foo", "secret");

Get/set the user name and password to be used for a realm.

The C<$netloc> is a string of the form C<< <host>:<port> >>.  The username and
password will only be passed to this server.

=head2 default_header

    $ua->default_header( $field );
    $ua->default_header( $field => $value );
    $ua->default_header('Accept-Encoding' => scalar HTTP::Message::decodable());
    $ua->default_header('Accept-Language' => "no, en");

This is just a shortcut for
C<< $ua->default_headers->header( $field => $value ) >>.

=head2 default_headers

    my $headers = $ua->default_headers;
    $ua->default_headers( $headers_obj );

Get/set the headers object that will provide default header values for
any requests sent.  By default this will be an empty L<HTTP::Headers>
object.

=head2 from

    my $from = $ua->from;
    $ua->from('foo@bar.com');

Get/set the email address for the human user who controls
the requesting user agent.  The address should be machine-usable, as
defined in L<RFC2822|https://tools.ietf.org/html/rfc2822>. The C<from> value
is sent as the C<From> header in the requests.

The default is to not send a C<From> header.  See
L<LWP::UserAgent/default_headers> for the more general interface that allow
any header to be defaulted.


=head2 local_address

    my $address = $ua->local_address;
    $ua->local_address( $address );

Get/set the local interface to bind to for network connections.  The interface
can be specified as a hostname or an IP address.  This value is passed as the
C<LocalAddr> argument to L<IO::Socket::INET>.

=head2 max_redirect

    my $max = $ua->max_redirect;
    $ua->max_redirect( $n );

This reads or sets the object's limit of how many times it will obey
redirection responses in a given request cycle.

By default, the value is C<7>. This means that if you call L<LWP::UserAgent/request>
and the response is a redirect elsewhere which is in turn a
redirect, and so on seven times, then LWP gives up after that seventh
request.

=head2 max_size

    my $size = $ua->max_size;
    $ua->max_size( $bytes );

Get/set the size limit for response content.  The default is C<undef>,
which means that there is no limit.  If the returned response content
is only partial, because the size limit was exceeded, then a
C<Client-Aborted> header will be added to the response.  The content
might end up longer than C<max_size> as we abort once appending a
chunk of data makes the length exceed the limit.  The C<Content-Length>
header, if present, will indicate the length of the full content and
will normally not be the same as C<< length($res->content) >>.

=head2 parse_head

    my $bool = $ua->parse_head;
    $ua->parse_head( $boolean );

Get/set a value indicating whether we should initialize response
headers from the E<lt>head> section of HTML documents. The default is
true. I<Do not turn this off> unless you know what you are doing.

=head2 protocols_allowed

    my $aref = $ua->protocols_allowed;      # get allowed protocols
    $ua->protocols_allowed( \@protocols );  # allow ONLY these
    $ua->protocols_allowed(undef);          # delete the list
    $ua->protocols_allowed(['http',]);      # ONLY allow http

By default, an object has neither a C<protocols_allowed> list, nor a
L<LWP::UserAgent/protocols_forbidden> list.

This reads (or sets) this user agent's list of protocols that the
request methods will exclusively allow.  The protocol names are case
insensitive.

For example: C<< $ua->protocols_allowed( [ 'http', 'https'] ); >>
means that this user agent will I<allow only> those protocols,
and attempts to use this user agent to access URLs with any other
schemes (like C<ftp://...>) will result in a 500 error.

Note that having a C<protocols_allowed> list causes any
L<LWP::UserAgent/protocols_forbidden> list to be ignored.

=head2 protocols_forbidden

    my $aref = $ua->protocols_forbidden;    # get the forbidden list
    $ua->protocols_forbidden(\@protocols);  # do not allow these
    $ua->protocols_forbidden(['http',]);    # All http reqs get a 500
    $ua->protocols_forbidden(undef);        # delete the list

This reads (or sets) this user agent's list of protocols that the
request method will I<not> allow. The protocol names are case
insensitive.

For example: C<< $ua->protocols_forbidden( [ 'file', 'mailto'] ); >>
means that this user agent will I<not> allow those protocols, and
attempts to use this user agent to access URLs with those schemes
will result in a 500 error.

=head2 requests_redirectable

    my $aref = $ua->requests_redirectable;
    $ua->requests_redirectable( \@requests );
    $ua->requests_redirectable(['GET', 'HEAD',]); # the default

This reads or sets the object's list of request names that
L<LWP::UserAgent/redirect_ok> will allow redirection for. By default, this
is C<['GET', 'HEAD']>, as per L<RFC 2616|https://tools.ietf.org/html/rfc2616>.
To change to include C<POST>, consider:

   push @{ $ua->requests_redirectable }, 'POST';

=head2 send_te

    my $bool = $ua->send_te;
    $ua->send_te( $boolean );

If true, will send a C<TE> header along with the request. The default is
true. Set it to false to disable the C<TE> header for systems who can't
handle it.

=head2 show_progress

    my $bool = $ua->show_progress;
    $ua->show_progress( $boolean );

Get/set a value indicating whether a progress bar should be displayed
on the terminal as requests are processed. The default is false.

=head2 ssl_opts

    my @keys = $ua->ssl_opts;
    my $val = $ua->ssl_opts( $key );
    $ua->ssl_opts( $key => $value );

Get/set the options for SSL connections.  Without argument return the list
of options keys currently set.  With a single argument return the current
value for the given option.  With 2 arguments set the option value and return
the old.  Setting an option to the value C<undef> removes this option.

The options that LWP relates to are:

=over

=item C<verify_hostname> => $bool

When TRUE LWP will for secure protocol schemes ensure it connects to servers
that have a valid certificate matching the expected hostname.  If FALSE no
checks are made and you can't be sure that you communicate with the expected peer.
The no checks behaviour was the default for libwww-perl-5.837 and earlier releases.

This option is initialized from the C<PERL_LWP_SSL_VERIFY_HOSTNAME> environment
variable.  If this environment variable isn't set; then C<verify_hostname>
defaults to 1.

Please note that recently the overall effect of this option with regards to
SSL handling has changed. As of version 6.11 of L<LWP::Protocol::https>, which is an
external module, SSL certificate verification was harmonized to behave in sync with
L<IO::Socket::SSL>. With this change, setting this option no longer disables all SSL
certificate verification, only the hostname checks. To disable all verification,
use the C<SSL_verify_mode> option in the C<ssl_opts> attribute. For example:
C<$ua->ssl_opts(SSL_verify_mode => IO::Socket::SSL::SSL_VERIFY_NONE);>

=item C<SSL_ca_file> => $path

The path to a file containing Certificate Authority certificates.
A default setting for this option is provided by checking the environment
variables C<PERL_LWP_SSL_CA_FILE> and C<HTTPS_CA_FILE> in order.

=item C<SSL_ca_path> => $path

The path to a directory containing files containing Certificate Authority
certificates.
A default setting for this option is provided by checking the environment
variables C<PERL_LWP_SSL_CA_PATH> and C<HTTPS_CA_DIR> in order.

=back

Other options can be set and are processed directly by the SSL Socket implementation
in use.  See L<IO::Socket::SSL> or L<Net::SSL> for details.

The libwww-perl core no longer bundles protocol plugins for SSL.  You will need
to install L<LWP::Protocol::https> separately to enable support for processing
https-URLs.

=head2 timeout

    my $secs = $ua->timeout;
    $ua->timeout( $secs );

Get/set the timeout value in seconds. The default value is
180 seconds, i.e. 3 minutes.

The request is aborted if no activity on the connection to the server
is observed for C<timeout> seconds.  This means that the time it takes
for the complete transaction and the L<LWP::UserAgent/request> method to
actually return might be longer.

When a request times out, a response object is still returned.  The response
will have a standard HTTP Status Code (500).  This response will have the
"Client-Warning" header set to the value of "Internal response".  See the
L<LWP::UserAgent/get> method description below for further details.

Disabling the timeout is not supported,
but it can be set to an arbitrarily large value.

=head1 PROXY ATTRIBUTES

The following methods set up when requests should be passed via a
proxy server.

=head2 env_proxy

    $ua->env_proxy;

Load proxy settings from C<*_proxy> environment variables.  You might
specify proxies like this (sh-syntax):

  gopher_proxy=http://proxy.my.place/
  wais_proxy=http://proxy.my.place/
  no_proxy="localhost,example.com"
  export gopher_proxy wais_proxy no_proxy

csh or tcsh users should use the C<setenv> command to define these
environment variables.

On systems with case insensitive environment variables there exists a
name clash between the CGI environment variables and the C<HTTP_PROXY>
environment variable normally picked up by C<env_proxy>.  Because of
this C<HTTP_PROXY> is not honored for CGI scripts.  The
C<CGI_HTTP_PROXY> environment variable can be used instead.

=head2 no_proxy

    $ua->no_proxy( @domains );
    $ua->no_proxy('localhost', 'example.com');
    $ua->no_proxy(); # clear the list

Do not proxy requests to the given domains, including subdomains.
Calling C<no_proxy> without any domains clears the list of domains.

=head2 proxy

    $ua->proxy(\@schemes, $proxy_url)
    $ua->proxy(['http', 'ftp'], 'http://proxy.sn.no:8001/');

    # For a single scheme:
    $ua->proxy($scheme, $proxy_url)
    $ua->proxy('gopher', 'http://proxy.sn.no:8001/');

    # To set multiple proxies at once:
    $ua->proxy([
        ftp => 'http://ftp.example.com:8001/',
        [ 'http', 'https' ] => 'http://http.example.com:8001/',
    ]);

Set/retrieve proxy URL for a scheme.

The first form specifies that the URL is to be used as a proxy for
access methods listed in the list in the first method argument,
i.e. C<http> and C<ftp>.

The second form shows a shorthand form for specifying
proxy URL for a single access scheme.

The third form demonstrates setting multiple proxies at once. This is also
the only form accepted by the constructor.

=head1 HANDLERS

Handlers are code that injected at various phases during the
processing of requests.  The following methods are provided to manage
the active handlers:

=head2 add_handler

    $ua->add_handler( $phase => \&cb, %matchspec )

Add handler to be invoked in the given processing phase.  For how to
specify C<%matchspec> see L<HTTP::Config/"Matching">.

The possible values C<$phase> and the corresponding callback signatures are as
follows.  Note that the handlers are documented in the order in which they will
be run, which is:

    request_preprepare
    request_prepare
    request_send
    response_header
    response_data
    response_done
    response_redirect

=over

=item request_preprepare => sub { my($request, $ua, $handler) = @_; ... }

The handler is called before the C<request_prepare> and other standard
initialization of the request.  This can be used to set up headers
and attributes that the C<request_prepare> handler depends on.  Proxy
initialization should take place here; but in general don't register
handlers for this phase.

=item request_prepare => sub { my($request, $ua, $handler) = @_; ... }

The handler is called before the request is sent and can modify the
request any way it see fit.  This can for instance be used to add
certain headers to specific requests.

The method can assign a new request object to C<$_[0]> to replace the
request that is sent fully.

The return value from the callback is ignored.  If an exception is
raised it will abort the request and make the request method return a
"400 Bad request" response.

=item request_send => sub { my($request, $ua, $handler) = @_; ... }

This handler gets a chance of handling requests before they're sent to the
protocol handlers.  It should return an L<HTTP::Response> object if it
wishes to terminate the processing; otherwise it should return nothing.

The C<response_header> and C<response_data> handlers will not be
invoked for this response, but the C<response_done> will be.

=item response_header => sub { my($response, $ua, $handler) = @_; ... }

This handler is called right after the response headers have been
received, but before any content data.  The handler might set up
handlers for data and might croak to abort the request.

The handler might set the C<< $response->{default_add_content} >> value to
control if any received data should be added to the response object
directly.  This will initially be false if the C<< $ua->request() >> method
was called with a C<$content_file> or C<$content_cb argument>; otherwise true.

=item response_data => sub { my($response, $ua, $handler, $data) = @_; ... }

This handler is called for each chunk of data received for the
response.  The handler might croak to abort the request.

This handler needs to return a TRUE value to be called again for
subsequent chunks for the same request.

=item response_done => sub { my($response, $ua, $handler) = @_; ... }

The handler is called after the response has been fully received, but
before any redirect handling is attempted.  The handler can be used to
extract information or modify the response.

=item response_redirect => sub { my($response, $ua, $handler) = @_; ... }

The handler is called in C<< $ua->request >> after C<response_done>.  If the
handler returns an L<HTTP::Request> object we'll start over with processing
this request instead.

=back

For all of these, C<$handler> is a code reference to the handler that
is currently being run.

=head2 get_my_handler

    $ua->get_my_handler( $phase, %matchspec );
    $ua->get_my_handler( $phase, %matchspec, $init );

Will retrieve the matching handler as hash ref.

If C<$init> is passed as a true value, create and add the
handler if it's not found.  If C<$init> is a subroutine reference, then
it's called with the created handler hash as argument.  This sub might
populate the hash with extra fields; especially the callback.  If
C<$init> is a hash reference, merge the hashes.

=head2 handlers

    $ua->handlers( $phase, $request )
    $ua->handlers( $phase, $response )

Returns the handlers that apply to the given request or response at
the given processing phase.

=head2 remove_handler

    $ua->remove_handler( undef, %matchspec );
    $ua->remove_handler( $phase, %matchspec );
    $ua->remove_handler(); # REMOVE ALL HANDLERS IN ALL PHASES

Remove handlers that match the given C<%matchspec>.  If C<$phase> is not
provided, remove handlers from all phases.

Be careful as calling this function with C<%matchspec> that is not
specific enough can remove handlers not owned by you.  It's probably
better to use the L<LWP::UserAgent/set_my_handler> method instead.

The removed handlers are returned.

=head2 set_my_handler

    $ua->set_my_handler( $phase, $cb, %matchspec );
    $ua->set_my_handler($phase, undef); # remove handler for phase

Set handlers private to the executing subroutine.  Works by defaulting
an C<owner> field to the C<%matchspec> that holds the name of the called
subroutine.  You might pass an explicit C<owner> to override this.

If C<$cb> is passed as C<undef>, remove the handler.

=head1 REQUEST METHODS

The methods described in this section are used to dispatch requests
via the user agent.  The following request methods are provided:

=head2 delete

    my $res = $ua->delete( $url );
    my $res = $ua->delete( $url, $field_name => $value, ... );

This method will dispatch a C<DELETE> request on the given URL.  Additional
headers and content options are the same as for the L<LWP::UserAgent/get>
method.

This method will use the C<DELETE()> function from L<HTTP::Request::Common>
to build the request.  See L<HTTP::Request::Common> for a details on
how to pass form content and other advanced features.

=head2 get

    my $res = $ua->get( $url );
    my $res = $ua->get( $url , $field_name => $value, ... );

This method will dispatch a C<GET> request on the given URL.  Further
arguments can be given to initialize the headers of the request. These
are given as separate name/value pairs.  The return value is a
response object.  See L<HTTP::Response> for a description of the
interface it provides.

There will still be a response object returned when LWP can't connect to the
server specified in the URL or when other failures in protocol handlers occur.
These internal responses use the standard HTTP status codes, so the responses
can't be differentiated by testing the response status code alone.  Error
responses that LWP generates internally will have the "Client-Warning" header
set to the value "Internal response".  If you need to differentiate these
internal responses from responses that a remote server actually generates, you
need to test this header value.

Fields names that start with ":" are special.  These will not
initialize headers of the request but will determine how the response
content is treated.  The following special field names are recognized:

    ':content_file'   => $filename # or $filehandle
    ':content_cb'     => \&callback
    ':read_size_hint' => $bytes

If a C<$filename> or C<$filehandle> is provided with the C<:content_file>
option, then the response content will be saved here instead of in
the response object.  The C<$filehandle> may also be an object with
an open file descriptor, such as a L<File::Temp> object.
If a callback is provided with the C<:content_cb> option then
this function will be called for each chunk of the response content as
it is received from the server.  If neither of these options are
given, then the response content will accumulate in the response
object itself.  This might not be suitable for very large response
bodies.  Only one of C<:content_file> or C<:content_cb> can be
specified.  The content of unsuccessful responses will always
accumulate in the response object itself, regardless of the
C<:content_file> or C<:content_cb> options passed in.  Note that errors
writing to the content file (for example due to permission denied
or the filesystem being full) will be reported via the C<Client-Aborted>
or C<X-Died> response headers, and not the C<is_success> method.

The C<:read_size_hint> option is passed to the protocol module which
will try to read data from the server in chunks of this size.  A
smaller value for the C<:read_size_hint> will result in a higher
number of callback invocations.

The callback function is called with 3 arguments: a chunk of data, a
reference to the response object, and a reference to the protocol
object.  The callback can abort the request by invoking C<die()>.  The
exception message will show up as the "X-Died" header field in the
response returned by the C<< $ua->get() >> method.

=head2 head

    my $res = $ua->head( $url );
    my $res = $ua->head( $url , $field_name => $value, ... );

This method will dispatch a C<HEAD> request on the given URL.
Otherwise it works like the L<LWP::UserAgent/get> method described above.

=head2 is_protocol_supported

    my $bool = $ua->is_protocol_supported( $scheme );

You can use this method to test whether this user agent object supports the
specified C<scheme>.  (The C<scheme> might be a string (like C<http> or
C<ftp>) or it might be an L<URI> object reference.)

Whether a scheme is supported is determined by the user agent's
C<protocols_allowed> or C<protocols_forbidden> lists (if any), and by
the capabilities of LWP.  I.e., this will return true only if LWP
supports this protocol I<and> it's permitted for this particular
object.

=head2 is_online

    my $bool = $ua->is_online;

Tries to determine if you have access to the Internet. Returns C<1> (true)
if the built-in heuristics determine that the user agent is
able to access the Internet (over HTTP) or C<0> (false).

See also L<LWP::Online>.

=head2 mirror

    my $res = $ua->mirror( $url, $filename );

This method will get the document identified by URL and store it in
file called C<$filename>.  If the file already exists, then the request
will contain an C<If-Modified-Since> header matching the modification
time of the file.  If the document on the server has not changed since
this time, then nothing happens.  If the document has been updated, it
will be downloaded again.  The modification time of the file will be
forced to match that of the server.

Uses L<File::Copy/move> to attempt to atomically replace the C<$filename>.

The return value is an L<HTTP::Response> object.

=head2 patch

    # Any version of HTTP::Message works with this form:
    my $res = $ua->patch( $url, $field_name => $value, Content => $content );

    # Using hash or array references requires HTTP::Message >= 6.12
    use HTTP::Request 6.12;
    my $res = $ua->patch( $url, \%form );
    my $res = $ua->patch( $url, \@form );
    my $res = $ua->patch( $url, \%form, $field_name => $value, ... );
    my $res = $ua->patch( $url, $field_name => $value, Content => \%form );
    my $res = $ua->patch( $url, $field_name => $value, Content => \@form );

This method will dispatch a C<PATCH> request on the given URL, with
C<%form> or C<@form> providing the key/value pairs for the fill-in form
content. Additional headers and content options are the same as for
the L<LWP::UserAgent/get> method.

CAVEAT:

This method can only accept content that is in key-value pairs when using
L<HTTP::Request::Common> prior to version C<6.12>. Any use of hash or array
references will result in an error prior to version C<6.12>.

This method will use the C<PATCH> function from L<HTTP::Request::Common>
to build the request.  See L<HTTP::Request::Common> for a details on
how to pass form content and other advanced features.

=head2 post

    my $res = $ua->post( $url, \%form );
    my $res = $ua->post( $url, \@form );
    my $res = $ua->post( $url, \%form, $field_name => $value, ... );
    my $res = $ua->post( $url, $field_name => $value, Content => \%form );
    my $res = $ua->post( $url, $field_name => $value, Content => \@form );
    my $res = $ua->post( $url, $field_name => $value, Content => $content );

This method will dispatch a C<POST> request on the given URL, with
C<%form> or C<@form> providing the key/value pairs for the fill-in form
content. Additional headers and content options are the same as for
the L<LWP::UserAgent/get> method.

This method will use the C<POST> function from L<HTTP::Request::Common>
to build the request.  See L<HTTP::Request::Common> for a details on
how to pass form content and other advanced features.

=head2 put

    # Any version of HTTP::Message works with this form:
    my $res = $ua->put( $url, $field_name => $value, Content => $content );

    # Using hash or array references requires HTTP::Message >= 6.07
    use HTTP::Request 6.07;
    my $res = $ua->put( $url, \%form );
    my $res = $ua->put( $url, \@form );
    my $res = $ua->put( $url, \%form, $field_name => $value, ... );
    my $res = $ua->put( $url, $field_name => $value, Content => \%form );
    my $res = $ua->put( $url, $field_name => $value, Content => \@form );

This method will dispatch a C<PUT> request on the given URL, with
C<%form> or C<@form> providing the key/value pairs for the fill-in form
content. Additional headers and content options are the same as for
the L<LWP::UserAgent/get> method.

CAVEAT:

This method can only accept content that is in key-value pairs when using
L<HTTP::Request::Common> prior to version C<6.07>. Any use of hash or array
references will result in an error prior to version C<6.07>.

This method will use the C<PUT> function from L<HTTP::Request::Common>
to build the request.  See L<HTTP::Request::Common> for a details on
how to pass form content and other advanced features.

=head2 request

    my $res = $ua->request( $request );
    my $res = $ua->request( $request, $content_file );
    my $res = $ua->request( $request, $content_cb );
    my $res = $ua->request( $request, $content_cb, $read_size_hint );

This method will dispatch the given C<$request> object. Normally this
will be an instance of the L<HTTP::Request> class, but any object with
a similar interface will do. The return value is an L<HTTP::Response> object.

The C<request> method will process redirects and authentication
responses transparently. This means that it may actually send several
simple requests via the L<LWP::UserAgent/simple_request> method described below.

The request methods described above; L<LWP::UserAgent/get>, L<LWP::UserAgent/head>,
L<LWP::UserAgent/post> and L<LWP::UserAgent/mirror> will all dispatch the request
they build via this method. They are convenience methods that simply hide the
creation of the request object for you.

The C<$content_file>, C<$content_cb> and C<$read_size_hint> all correspond to
options described with the L<LWP::UserAgent/get> method above. Note that errors
writing to the content file (for example due to permission denied
or the filesystem being full) will be reported via the C<Client-Aborted>
or C<X-Died> response headers, and not the C<is_success> method.

You are allowed to use a CODE reference as C<content> in the request
object passed in.  The C<content> function should return the content
when called.  The content can be returned in chunks.  The content
function will be invoked repeatedly until it return an empty string to
signal that there is no more content.

=head2 simple_request

    my $request = HTTP::Request->new( ... );
    my $res = $ua->simple_request( $request );
    my $res = $ua->simple_request( $request, $content_file );
    my $res = $ua->simple_request( $request, $content_cb );
    my $res = $ua->simple_request( $request, $content_cb, $read_size_hint );

This method dispatches a single request and returns the response
received.  Arguments are the same as for the L<LWP::UserAgent/request> described above.

The difference from L<LWP::UserAgent/request> is that C<simple_request> will not try to
handle redirects or authentication responses.  The L<LWP::UserAgent/request> method
will, in fact, invoke this method for each simple request it sends.

=head1 CALLBACK METHODS

The following methods will be invoked as requests are processed. These
methods are documented here because subclasses of L<LWP::UserAgent>
might want to override their behaviour.

=head2 get_basic_credentials

    # This checks wantarray and can either return an array:
    my ($user, $pass) = $ua->get_basic_credentials( $realm, $uri, $isproxy );
    # or a string that looks like "user:pass"
    my $creds = $ua->get_basic_credentials($realm, $uri, $isproxy);

This is called by L<LWP::UserAgent/request> to retrieve credentials for documents
protected by Basic or Digest Authentication.  The arguments passed in
is the C<$realm> provided by the server, the C<$uri> requested and a
C<boolean flag> to indicate if this is authentication against a proxy server.

The method should return a username and password.  It should return an
empty list to abort the authentication resolution attempt.  Subclasses
can override this method to prompt the user for the information. An
example of this can be found in C<lwp-request> program distributed
with this library.

The base implementation simply checks a set of pre-stored member
variables, set up with the L<LWP::UserAgent/credentials> method.

=head2 prepare_request

    $request = $ua->prepare_request( $request );

This method is invoked by L<LWP::UserAgent/simple_request>. Its task is
to modify the given C<$request> object by setting up various headers based
on the attributes of the user agent. The return value should normally be the
C<$request> object passed in.  If a different request object is returned
it will be the one actually processed.

The headers affected by the base implementation are; C<User-Agent>,
C<From>, C<Range> and C<Cookie>.

=head2 progress

    my $prog = $ua->progress( $status, $request_or_response );

This is called frequently as the response is received regardless of
how the content is processed.  The method is called with C<$status>
"begin" at the start of processing the request and with C<$state> "end"
before the request method returns.  In between these C<$status> will be
the fraction of the response currently received or the string "tick"
if the fraction can't be calculated.

When C<$status> is "begin" the second argument is the L<HTTP::Request> object,
otherwise it is the L<HTTP::Response> object.

=head2 redirect_ok

    my $bool = $ua->redirect_ok( $prospective_request, $response );

This method is called by L<LWP::UserAgent/request> before it tries to follow a
redirection to the request in C<$response>.  This should return a true
value if this redirection is permissible.  The C<$prospective_request>
will be the request to be sent if this method returns true.

The base implementation will return false unless the method
is in the object's C<requests_redirectable> list,
false if the proposed redirection is to a C<file://...>
URL, and true otherwise.

=head1 BEST PRACTICES

The default settings can get you up and running quickly, but there are settings
you can change in order to make your life easier.

=head2 Handling Cookies

You are encouraged to install L<Mozilla::PublicSuffix> and use
L<HTTP::CookieJar::LWP> as your cookie jar.  L<HTTP::CookieJar::LWP> provides a
better security model matching that of current Web browsers when
L<Mozilla::PublicSuffix> is installed.

    use HTTP::CookieJar::LWP ();

    my $jar = HTTP::CookieJar::LWP->new;
    my $ua = LWP::UserAgent->new( cookie_jar => $jar );

See L</"cookie_jar"> for more information.

=head2 Managing Protocols

C<protocols_allowed> gives you the ability to allow arbitrary protocols.

    my $ua = LWP::UserAgent->new(
        protocols_allowed => [ 'http', 'https' ]
    );

This will prevent you from inadvertently following URLs like
C<file:///etc/passwd>.  See L</"protocols_allowed">.

C<protocols_forbidden> gives you the ability to deny arbitrary protocols.

    my $ua = LWP::UserAgent->new(
        protocols_forbidden => [ 'file', 'mailto', 'ssh', ]
    );

This can also prevent you from inadvertently following URLs like
C<file:///etc/passwd>.  See L</protocols_forbidden>.

=head1 SEE ALSO

See L<LWP> for a complete overview of libwww-perl5.  See L<lwpcook>
and the scripts F<lwp-request> and F<lwp-download> for examples of
usage.

See L<HTTP::Request> and L<HTTP::Response> for a description of the
message objects dispatched and received.  See L<HTTP::Request::Common>
and L<HTML::Form> for other ways to build request objects.

See L<WWW::Mechanize> and L<WWW::Search> for examples of more
specialized user agents based on L<LWP::UserAgent>.

=head1 COPYRIGHT AND LICENSE

Copyright 1995-2009 Gisle Aas.

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

=cut
PK6N%[�� mmperl5/LWP/MemberMixin.pmnu��6�$package LWP::MemberMixin;

our $VERSION = '6.78';

sub _elem {
    my $self = shift;
    my $elem = shift;
    my $old  = $self->{$elem};
    $self->{$elem} = shift if @_;
    return $old;
}

1;

__END__

=pod

=head1 NAME

LWP::MemberMixin - Member access mixin class

=head1 SYNOPSIS

 package Foo;
 use parent qw(LWP::MemberMixin);

=head1 DESCRIPTION

A mixin class to get methods that provide easy access to member
variables in the C<%$self>.
Ideally there should be better Perl language support for this.

=head1 METHODS

There is only one method provided:

=head2 _elem

    _elem($elem [, $val])

Internal method to get/set the value of member variable
C<$elem>. If C<$val> is present it is used as the new value
for the member variable.  If it is not present the current
value is not touched. In both cases the previous value of
the member variable is returned.

=cut
PK6N%[��v%v%perl5/LWP/Protocol.pmnu��6�$package LWP::Protocol;

use parent 'LWP::MemberMixin';

our $VERSION = '6.78';

use strict;
use Carp ();
use HTTP::Status ();
use HTTP::Response ();
use Scalar::Util qw(openhandle);
use Try::Tiny qw(try catch);

my %ImplementedBy = (); # scheme => classname
my %ImplementorAlreadyTested;

sub new
{
    my($class, $scheme, $ua) = @_;

    my $self = bless {
	scheme => $scheme,
	ua => $ua,

	# historical/redundant
        max_size => $ua->{max_size},
    }, $class;

    $self;
}


sub create
{
    my($scheme, $ua) = @_;
    my $impclass = LWP::Protocol::implementor($scheme) or
	Carp::croak("Protocol scheme '$scheme' is not supported");

    # hand-off to scheme specific implementation sub-class
    my $protocol = $impclass->new($scheme, $ua);

    return $protocol;
}


sub implementor
{
    my($scheme, $impclass) = @_;

    if ($impclass) {
	$ImplementedBy{$scheme} = $impclass;
    }

    my $ic = $ImplementedBy{$scheme};
    # module does not exist
    return $ic if $ic || $ImplementorAlreadyTested{$scheme};

    return '' unless $scheme =~ /^([.+\-\w]+)$/;  # check valid URL schemes
    $scheme = $1; # untaint

    # scheme not yet known, look for a 'use'd implementation
    $ic = $scheme;
    $ic =~ tr/.+-/_/;  # make it a legal module name
    $ic = "LWP::Protocol::$ic";  # default location
    $ic = "LWP::Protocol::nntp" if $scheme eq 'news'; #XXX ugly hack
    no strict 'refs';
    # check we actually have one for the scheme:
    unless (@{"${ic}::ISA"}) {
        # try to autoload it
        try {
            (my $class = $ic) =~ s{::}{/}g;
            $class .= '.pm' unless $class =~ /\.pm$/;
            require $class;
        }
        catch {
            my $error = $_;
            if ($error =~ /Can't locate/) {
                $ic = '';
            }
            else {
                die "$error\n";
            }
        };
    }
    $ImplementedBy{$scheme} = $ic if $ic;
    $ImplementorAlreadyTested{$scheme} = 1;
    $ic;
}


sub request
{
    my($self, $request, $proxy, $arg, $size, $timeout) = @_;
    Carp::croak('LWP::Protocol::request() needs to be overridden in subclasses');
}


# legacy
sub timeout    { shift->_elem('timeout',    @_); }
sub max_size   { shift->_elem('max_size',   @_); }


sub collect
{
    my ($self, $arg, $response, $collector) = @_;
    my $content;
    my($ua, $max_size) = @{$self}{qw(ua max_size)};

    # This can't be moved to Try::Tiny due to the closures within causing
    # leaks on any version of Perl prior to 5.18.
    # https://perl5.git.perl.org/perl.git/commitdiff/a0d2bbd5c
    my $error = do { #catch
        local $@;
        local $\; # protect the print below from surprises
        eval { # try
            if (!defined($arg) || !$response->is_success) {
                $response->{default_add_content} = 1;
            }
            elsif (defined(openhandle($arg)) || !ref($arg) && length($arg)) {
                my $existing_fh = defined(openhandle($arg));
                my $mode = $existing_fh ? '>&=' : '>';
                open(my $fh, $mode, $arg) or die "Can't write to '$arg': $!";
                binmode($fh);
                push(@{$response->{handlers}{response_data}}, {
                    callback => sub {
                        print $fh $_[3] or die "Can't write to '$arg': $!";
                        1;
                    },
                });
                push(@{$response->{handlers}{response_done}}, {
                    callback => sub {
                        unless ($existing_fh) {
                            close($fh) or die "Can't write to '$arg': $!";
                        }
                        undef($fh);
                    },
                });
            }
            elsif (ref($arg) eq 'CODE') {
                push(@{$response->{handlers}{response_data}}, {
                    callback => sub {
                        &$arg($_[3], $_[0], $self);
                        1;
                    },
                });
            }
            else {
                die "Unexpected collect argument '$arg'";
            }

            $ua->run_handlers("response_header", $response);

            if (delete $response->{default_add_content}) {
                push(@{$response->{handlers}{response_data}}, {
                    callback => sub {
                        $_[0]->add_content($_[3]);
                        1;
                    },
                });
            }


            my $content_size = 0;
            my $length = $response->content_length;
            my %skip_h;

            while ($content = &$collector, length $$content) {
                for my $h ($ua->handlers("response_data", $response)) {
                    next if $skip_h{$h};
                    unless ($h->{callback}->($response, $ua, $h, $$content)) {
                        # XXX remove from $response->{handlers}{response_data} if present
                        $skip_h{$h}++;
                    }
                }
                $content_size += length($$content);
                $ua->progress(($length ? ($content_size / $length) : "tick"), $response);
                if (defined($max_size) && $content_size > $max_size) {
                    $response->push_header("Client-Aborted", "max_size");
                    last;
                }
            }
            1;
        };
        $@;
    };

    if ($error) {
        chomp($error);
        $response->push_header('X-Died' => $error);
        $response->push_header("Client-Aborted", "die");
    };
    delete $response->{handlers}{response_data};
    delete $response->{handlers} unless %{$response->{handlers}};
    return $response;
}


sub collect_once
{
    my($self, $arg, $response) = @_;
    my $content = \ $_[3];
    my $first = 1;
    $self->collect($arg, $response, sub {
	return $content if $first--;
	return \ "";
    });
}

1;


__END__

=pod

=head1 NAME

LWP::Protocol - Base class for LWP protocols

=head1 SYNOPSIS

 package LWP::Protocol::foo;
 use parent qw(LWP::Protocol);

=head1 DESCRIPTION

This class is used as the base class for all protocol implementations
supported by the LWP library.

When creating an instance of this class using
C<LWP::Protocol::create($url)>, and you get an initialized subclass
appropriate for that access method. In other words, the
L<LWP::Protocol/create> function calls the constructor for one of its
subclasses.

All derived C<LWP::Protocol> classes need to override the C<request()>
method which is used to service a request. The overridden method can
make use of the C<collect()> method to collect together chunks of data
as it is received.

=head1 METHODS

The following methods and functions are provided:

=head2 new

    my $prot = LWP::Protocol->new();

The LWP::Protocol constructor is inherited by subclasses. As this is a
virtual base class this method should B<not> be called directly.

=head2 create

    my $prot = LWP::Protocol::create($scheme)

Create an object of the class implementing the protocol to handle the
given scheme. This is a function, not a method. It is more an object
factory than a constructor. This is the function user agents should
use to access protocols.

=head2 implementor

    my $class = LWP::Protocol::implementor($scheme, [$class])

Get and/or set implementor class for a scheme.  Returns C<''> if the
specified scheme is not supported.

=head2 request

    $response = $protocol->request($request, $proxy, undef);
    $response = $protocol->request($request, $proxy, '/tmp/sss');
    $response = $protocol->request($request, $proxy, \&callback, 1024);
    $response = $protocol->request($request, $proxy, $fh);

Dispatches a request over the protocol, and returns a response
object. This method needs to be overridden in subclasses.  Refer to
L<LWP::UserAgent> for description of the arguments.

=head2 collect

    my $res = $prot->collect(undef, $response, $collector); # stored in $response
    my $res = $prot->collect($filename, $response, $collector);
    my $res = $prot->collect(sub { ... }, $response, $collector);

Collect the content of a request, and process it appropriately into a scalar,
file, or by calling a callback. If the first parameter is undefined, then the
content is stored within the C<$response>. If it's a simple scalar, then it's
interpreted as a file name and the content is written to this file.  If it's a
code reference, then content is passed to this routine.
If it is a filehandle, or similar, such as a L<File::Temp> object,
content will be written to it.

The collector is a routine that will be called and which is
responsible for returning pieces (as ref to scalar) of the content to
process.  The C<$collector> signals C<EOF> by returning a reference to an
empty string.

The return value is the L<HTTP::Response> object reference.

B<Note:> We will only use the callback or file argument if
C<< $response->is_success() >>.  This avoids sending content data for
redirects and authentication responses to the callback which would be
confusing.

=head2 collect_once

    $prot->collect_once($arg, $response, $content)

Can be called when the whole response content is available as content. This
will invoke L<LWP::Protocol/collect> with a collector callback that
returns a reference to C<$content> the first time and an empty string the
next.

=head1 SEE ALSO

Inspect the F<LWP/Protocol/file.pm> and F<LWP/Protocol/http.pm> files
for examples of usage.

=head1 COPYRIGHT

Copyright 1995-2001 Gisle Aas.

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

=cut
PK6N%[����� perl5/LWP/Protocol/http/hosts.pmnu��6�$package LWP::Protocol::http::hosts;

use strict;
use warnings;
use parent 'LWP::Protocol::http';
use LWP::UserAgent::DNS::Hosts;

sub _extra_sock_opts {
    my ($self, $host, $port) = @_;

    my @opts = $self->SUPER::_extra_sock_opts($host, $port);
    if (my $peer_addr = LWP::UserAgent::DNS::Hosts->_registered_peer_addr($host)) {
        push @opts, (PeerAddr => $peer_addr, Host => $host);
    }

    return @opts;
}

sub socket_class { 'LWP::Protocol::http::Socket' }

1;

__END__
PK6N%[O+�O88perl5/LWP/Protocol/mailto.pmnu��6�$package LWP::Protocol::mailto;

# This module implements the mailto protocol.  It is just a simple
# frontend to the Unix sendmail program except on MacOS, where it uses
# Mail::Internet.

require HTTP::Request;
require HTTP::Response;
require HTTP::Status;

use Carp;
use strict;

our $VERSION = '6.78';

use parent qw(LWP::Protocol);
our $SENDMAIL;

unless ($SENDMAIL = $ENV{SENDMAIL}) {
    for my $sm (qw(/usr/sbin/sendmail
		   /usr/lib/sendmail
		   /usr/ucblib/sendmail
		  ))
    {
	if (-x $sm) {
	    $SENDMAIL = $sm;
	    last;
	}
    }
    die "Can't find the 'sendmail' program" unless $SENDMAIL;
}

sub request
{
    my($self, $request, $proxy, $arg, $size) = @_;

    my ($mail, $addr) if $^O eq "MacOS";
    my @text = () if $^O eq "MacOS";

    # check proxy
    if (defined $proxy)
    {
	return HTTP::Response->new(HTTP::Status::RC_BAD_REQUEST,
				  'You can not proxy with mail');
    }

    # check method
    my $method = $request->method;

    if ($method ne 'POST') {
	return HTTP::Response->new( HTTP::Status::RC_BAD_REQUEST,
				  'Library does not allow method ' .
				  "$method for 'mailto:' URLs");
    }

    # check url
    my $url = $request->uri;

    my $scheme = $url->scheme;
    if ($scheme ne 'mailto') {
	return HTTP::Response->new( HTTP::Status::RC_INTERNAL_SERVER_ERROR,
			 "LWP::Protocol::mailto::request called for '$scheme'");
    }
    if ($^O eq "MacOS") {
	eval {
	    require Mail::Internet;
	};
	if($@) {
	    return HTTP::Response->new( HTTP::Status::RC_INTERNAL_SERVER_ERROR,
	               "You don't have MailTools installed");
	}
	unless ($ENV{SMTPHOSTS}) {
	    return HTTP::Response->new( HTTP::Status::RC_INTERNAL_SERVER_ERROR,
	               "You don't have SMTPHOSTS defined");
	}
    }
    else {
	unless (-x $SENDMAIL) {
	    return HTTP::Response->new( HTTP::Status::RC_INTERNAL_SERVER_ERROR,
	               "You don't have $SENDMAIL");
    }
    }
    if ($^O eq "MacOS") {
	    $mail = Mail::Internet->new or
	    return HTTP::Response->new( HTTP::Status::RC_INTERNAL_SERVER_ERROR,
	    "Can't get a Mail::Internet object");
    }
    else {
	open(SENDMAIL, "| $SENDMAIL -oi -t") or
	    return HTTP::Response->new( HTTP::Status::RC_INTERNAL_SERVER_ERROR,
	               "Can't run $SENDMAIL: $!");
    }
    if ($^O eq "MacOS") {
	$addr = $url->encoded822addr;
    }
    else {
	$request = $request->clone;  # we modify a copy
	my @h = $url->headers;  # URL headers override those in the request
	while (@h) {
	    my $k = shift @h;
	    my $v = shift @h;
	    next unless defined $v;
	    if (lc($k) eq "body") {
		$request->content($v);
	    }
	    else {
		$request->push_header($k => $v);
	    }
	}
    }
    if ($^O eq "MacOS") {
	$mail->add(To => $addr);
	$mail->add(split(/[:\n]/,$request->headers_as_string));
    }
    else {
	print SENDMAIL $request->headers_as_string;
	print SENDMAIL "\n";
    }
    my $content = $request->content;
    if (defined $content) {
	my $contRef = ref($content) ? $content : \$content;
	if (ref($contRef) eq 'SCALAR') {
	    if ($^O eq "MacOS") {
		@text = split("\n",$$contRef);
		foreach (@text) {
		    $_ .= "\n";
		}
	    }
	    else {
	    print SENDMAIL $$contRef;
	    }

	}
	elsif (ref($contRef) eq 'CODE') {
	    # Callback provides data
	    my $d;
	    if ($^O eq "MacOS") {
		my $stuff = "";
		while (length($d = &$contRef)) {
		    $stuff .= $d;
		}
		@text = split("\n",$stuff);
		foreach (@text) {
		    $_ .= "\n";
		}
	    }
	    else {
		print SENDMAIL $d;
	    }
	}
    }
    if ($^O eq "MacOS") {
	$mail->body(\@text);
	unless ($mail->smtpsend) {
	    return HTTP::Response->new(HTTP::Status::RC_INTERNAL_SERVER_ERROR,
				       "Mail::Internet->smtpsend unable to send message to <$addr>");
	}
    }
    else {
	unless (close(SENDMAIL)) {
	    my $err = $! ? "$!" : "Exit status $?";
	    return HTTP::Response->new(HTTP::Status::RC_INTERNAL_SERVER_ERROR,
				       "$SENDMAIL: $err");
	}
    }


    my $response = HTTP::Response->new(HTTP::Status::RC_ACCEPTED,
				       "Mail accepted");
    $response->header('Content-Type', 'text/plain');
    if ($^O eq "MacOS") {
	$response->header('Server' => "Mail::Internet $Mail::Internet::VERSION");
	$response->content("Message sent to <$addr>\n");
    }
    else {
	$response->header('Server' => $SENDMAIL);
	my $to = $request->header("To");
	$response->content("Message sent to <$to>\n");
    }

    return $response;
}

1;
PK6N%[��w�bbperl5/LWP/Protocol/gopher.pmnu��6�$package LWP::Protocol::gopher;

# Implementation of the gopher protocol (RFC 1436)
#
# This code is based on 'wwwgopher.pl,v 0.10 1994/10/17 18:12:34 shelden'
# which in turn is a vastly modified version of Oscar's http'get()
# dated 28/3/94 in <ftp://cui.unige.ch/PUBLIC/oscar/scripts/http.pl>
# including contributions from Marc van Heyningen and Martijn Koster.

use strict;

our $VERSION = '6.78';

require HTTP::Response;
require HTTP::Status;
require IO::Socket;
require IO::Select;

use parent qw(LWP::Protocol);


my %gopher2mimetype = (
    '0' => 'text/plain',                # 0 file
    '1' => 'text/html',                 # 1 menu
					# 2 CSO phone-book server
					# 3 Error
    '4' => 'application/mac-binhex40',  # 4 BinHexed Macintosh file
    '5' => 'application/zip',           # 5 DOS binary archive of some sort
    '6' => 'application/octet-stream',  # 6 UNIX uuencoded file.
    '7' => 'text/html',                 # 7 Index-Search server
					# 8 telnet session
    '9' => 'application/octet-stream',  # 9 binary file
    'h' => 'text/html',                 # html
    'g' => 'image/gif',                 # gif
    'I' => 'image/*',                   # some kind of image
);

my %gopher2encoding = (
    '6' => 'x_uuencode',                # 6 UNIX uuencoded file.
);

sub request
{
    my($self, $request, $proxy, $arg, $size, $timeout) = @_;

    $size = 4096 unless $size;

    # check proxy
    if (defined $proxy) {
	return HTTP::Response->new(HTTP::Status::RC_BAD_REQUEST,
				   'You can not proxy through the gopher');
    }

    my $url = $request->uri;
    die "bad scheme" if $url->scheme ne 'gopher';


    my $method = $request->method;
    unless ($method eq 'GET' || $method eq 'HEAD') {
	return HTTP::Response->new(HTTP::Status::RC_BAD_REQUEST,
				   'Library does not allow method ' .
				   "$method for 'gopher:' URLs");
    }

    my $gophertype = $url->gopher_type;
    unless (exists $gopher2mimetype{$gophertype}) {
	return HTTP::Response->new(HTTP::Status::RC_NOT_IMPLEMENTED,
				   'Library does not support gophertype ' .
				   $gophertype);
    }

    my $response = HTTP::Response->new(HTTP::Status::RC_OK, "OK");
    $response->header('Content-type' => $gopher2mimetype{$gophertype}
					|| 'text/plain');
    $response->header('Content-Encoding' => $gopher2encoding{$gophertype})
	if exists $gopher2encoding{$gophertype};

    if ($method eq 'HEAD') {
	# XXX: don't even try it so we set this header
	$response->header('Client-Warning' => 'Client answer only');
	return $response;
    }

    if ($gophertype eq '7' && ! $url->search) {
      # the url is the prompt for a gopher search; supply boiler-plate
      return $self->collect_once($arg, $response, <<"EOT");
<HEAD>
<TITLE>Gopher Index</TITLE>
<ISINDEX>
</HEAD>
<BODY>
<H1>$url<BR>Gopher Search</H1>
This is a searchable Gopher index.
Use the search function of your browser to enter search terms.
</BODY>
EOT
    }

    my $host = $url->host;
    my $port = $url->port;

    my $requestLine = "";

    my $selector = $url->selector;
    if (defined $selector) {
	$requestLine .= $selector;
	my $search = $url->search;
	if (defined $search) {
	    $requestLine .= "\t$search";
	    my $string = $url->string;
	    if (defined $string) {
		$requestLine .= "\t$string";
	    }
	}
    }
    $requestLine .= "\015\012";

    # potential request headers are just ignored

    # Ok, lets make the request
    my $socket = IO::Socket::INET->new(PeerAddr => $host,
				       PeerPort => $port,
				       LocalAddr => $self->{ua}{local_address},
				       Proto    => 'tcp',
				       Timeout  => $timeout);
    die "Can't connect to $host:$port" unless $socket;
    my $sel = IO::Select->new($socket);

    {
	die "write timeout" if $timeout && !$sel->can_write($timeout);
	my $n = syswrite($socket, $requestLine, length($requestLine));
	die $! unless defined($n);
	die "short write" if $n != length($requestLine);
    }

    my $user_arg = $arg;

    # must handle menus in a special way since they are to be
    # converted to HTML.  Undefing $arg ensures that the user does
    # not see the data before we get a change to convert it.
    $arg = undef if $gophertype eq '1' || $gophertype eq '7';

    # collect response
    my $buf = '';
    $response = $self->collect($arg, $response, sub {
	die "read timeout" if $timeout && !$sel->can_read($timeout);
        my $n = sysread($socket, $buf, $size);
	die $! unless defined($n);
	return \$buf;
      } );

    # Convert menu to HTML and return data to user.
    if ($gophertype eq '1' || $gophertype eq '7') {
	my $content = menu2html($response->content);
	if (defined $user_arg) {
	    $response = $self->collect_once($user_arg, $response, $content);
	}
	else {
	    $response->content($content);
	}
    }

    $response;
}


sub gopher2url
{
    my($gophertype, $path, $host, $port) = @_;

    my $url;

    if ($gophertype eq '8' || $gophertype eq 'T') {
	# telnet session
	$url = $HTTP::URI_CLASS->new($gophertype eq '8' ? 'telnet:':'tn3270:');
	$url->user($path) if defined $path;
    }
    else {
	$path = URI::Escape::uri_escape($path);
	$url = $HTTP::URI_CLASS->new("gopher:/$gophertype$path");
    }
    $url->host($host);
    $url->port($port);
    $url;
}

sub menu2html {
    my($menu) = @_;

    $menu =~ tr/\015//d;  # remove carriage return
    my $tmp = <<"EOT";
<HTML>
<HEAD>
   <TITLE>Gopher menu</TITLE>
</HEAD>
<BODY>
<H1>Gopher menu</H1>
EOT
    for (split("\n", $menu)) {
	last if /^\./;
	my($pretty, $path, $host, $port) = split("\t");

	$pretty =~ s/^(.)//;
	my $type = $1;

	my $url = gopher2url($type, $path, $host, $port)->as_string;
	$tmp .= qq{<A HREF="$url">$pretty</A><BR>\n};
    }
    $tmp .= "</BODY>\n</HTML>\n";
    $tmp;
}

1;
PK6N%[�N�ddperl5/LWP/Protocol/nogo.pmnu��6�$package LWP::Protocol::nogo;
# If you want to disable access to a particular scheme, use this
# class and then call
#   LWP::Protocol::implementor(that_scheme, 'LWP::Protocol::nogo');
# For then on, attempts to access URLs with that scheme will generate
# a 500 error.

use strict;

our $VERSION = '6.78';

require HTTP::Response;
require HTTP::Status;
use parent qw(LWP::Protocol);

sub request {
    my($self, $request) = @_;
    my $scheme = $request->uri->scheme;

    return HTTP::Response->new(
      HTTP::Status::RC_INTERNAL_SERVER_ERROR,
      "Access to \'$scheme\' URIs has been disabled"
    );
}
1;
PK6N%[ɐS�LLperl5/LWP/Protocol/loopback.pmnu��6�$package LWP::Protocol::loopback;

use strict;

our $VERSION = '6.78';

require HTTP::Response;

use parent qw(LWP::Protocol);

sub request {
    my($self, $request, $proxy, $arg, $size, $timeout) = @_;

    my $response = HTTP::Response->new(200, "OK");
    $response->content_type("message/http; msgtype=request");

    $response->header("Via", "loopback/1.0 $proxy")
	if $proxy;

    $response->header("X-Arg", $arg);
    $response->header("X-Read-Size", $size);
    $response->header("X-Timeout", $timeout);

    return $self->collect_once($arg, $response, $request->as_string);
}

1;
PK6N%[-'G�perl5/LWP/Protocol/file.pmnu��6�$package LWP::Protocol::file;

use parent qw(LWP::Protocol);

use strict;

our $VERSION = '6.78';

require LWP::MediaTypes;
require HTTP::Request;
require HTTP::Response;
require HTTP::Status;
require HTTP::Date;


sub request
{
    my($self, $request, $proxy, $arg, $size) = @_;

    $size = 4096 unless defined $size and $size > 0;

    # check proxy
    if (defined $proxy)
    {
	return HTTP::Response->new( HTTP::Status::RC_BAD_REQUEST,
				  'You can not proxy through the filesystem');
    }

    # check method
    my $method = $request->method;
    unless ($method eq 'GET' || $method eq 'HEAD') {
	return HTTP::Response->new( HTTP::Status::RC_BAD_REQUEST,
				  'Library does not allow method ' .
				  "$method for 'file:' URLs");
    }

    # check url
    my $url = $request->uri;

    my $scheme = $url->scheme;
    if ($scheme ne 'file') {
	return HTTP::Response->new( HTTP::Status::RC_INTERNAL_SERVER_ERROR,
			   "LWP::Protocol::file::request called for '$scheme'");
    }

    # URL OK, look at file
    my $path  = $url->file;

    # test file exists and is readable
    unless (-e $path) {
	return HTTP::Response->new( HTTP::Status::RC_NOT_FOUND,
				  "File `$path' does not exist");
    }
    unless (-r _) {
	return HTTP::Response->new( HTTP::Status::RC_FORBIDDEN,
				  'User does not have read permission');
    }

    # looks like file exists
    my($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$filesize,
       $atime,$mtime,$ctime,$blksize,$blocks)
	    = stat(_);

    # XXX should check Accept headers?

    # check if-modified-since
    my $ims = $request->header('If-Modified-Since');
    if (defined $ims) {
	my $time = HTTP::Date::str2time($ims);
	if (defined $time and $time >= $mtime) {
	    return HTTP::Response->new( HTTP::Status::RC_NOT_MODIFIED,
				      "$method $path");
	}
    }

    # Ok, should be an OK response by now...
    my $response = HTTP::Response->new( HTTP::Status::RC_OK );

    # fill in response headers
    $response->header('Last-Modified', HTTP::Date::time2str($mtime));

    if (-d _) {         # If the path is a directory, process it
	# generate the HTML for directory
	opendir(D, $path) or
	   return HTTP::Response->new( HTTP::Status::RC_INTERNAL_SERVER_ERROR,
				     "Cannot read directory '$path': $!");
	my(@files) = sort readdir(D);
	closedir(D);

	# Make directory listing
	require URI::Escape;
	require HTML::Entities;
        my $pathe = $path . ( $^O eq 'MacOS' ? ':' : '/');
	for (@files) {
	    my $furl = URI::Escape::uri_escape($_);
            if ( -d "$pathe$_" ) {
                $furl .= '/';
                $_ .= '/';
            }
	    my $desc = HTML::Entities::encode($_);
	    $_ = qq{<LI><A HREF="$furl">$desc</A>};
	}
	# Ensure that the base URL is "/" terminated
	my $base = $url->clone;
	unless ($base->path =~ m|/$|) {
	    $base->path($base->path . "/");
	}
	my $html = join("\n",
			"<HTML>\n<HEAD>",
			"<TITLE>Directory $path</TITLE>",
			"<BASE HREF=\"$base\">",
			"</HEAD>\n<BODY>",
			"<H1>Directory listing of $path</H1>",
			"<UL>", @files, "</UL>",
			"</BODY>\n</HTML>\n");

	$response->header('Content-Type',   'text/html');
	$response->header('Content-Length', length $html);
	$html = "" if $method eq "HEAD";

	return $self->collect_once($arg, $response, $html);

    }

    # path is a regular file
    $response->header('Content-Length', $filesize);
    LWP::MediaTypes::guess_media_type($path, $response);

    # read the file
    if ($method ne "HEAD") {
	open(my $fh, '<', $path) or return new
	    HTTP::Response(HTTP::Status::RC_INTERNAL_SERVER_ERROR,
			   "Cannot read file '$path': $!");
	binmode($fh);
	$response =  $self->collect($arg, $response, sub {
	    my $content = "";
	    my $bytes = sysread($fh, $content, $size);
	    return \$content if $bytes > 0;
	    return \ "";
	});
	close($fh);
    }

    $response;
}

1;
PK6N%[��Q�ffperl5/LWP/Protocol/nntp.pmnu��6�$package LWP::Protocol::nntp;

# Implementation of the Network News Transfer Protocol (RFC 977)

use parent qw(LWP::Protocol);

our $VERSION = '6.78';

require HTTP::Response;
require HTTP::Status;
require Net::NNTP;

use strict;


sub request {
    my ($self, $request, $proxy, $arg, $size, $timeout) = @_;

    $size = 4096 unless $size;

    # Check for proxy
    if (defined $proxy) {
        return HTTP::Response->new(HTTP::Status::RC_BAD_REQUEST,
            'You can not proxy through NNTP');
    }

    # Check that the scheme is as expected
    my $url    = $request->uri;
    my $scheme = $url->scheme;
    unless ($scheme eq 'news' || $scheme eq 'nntp') {
        return HTTP::Response->new(HTTP::Status::RC_INTERNAL_SERVER_ERROR,
            "LWP::Protocol::nntp::request called for '$scheme'");
    }

    # check for a valid method
    my $method = $request->method;
    unless ($method eq 'GET' || $method eq 'HEAD' || $method eq 'POST') {
        return HTTP::Response->new(HTTP::Status::RC_BAD_REQUEST,
            'Library does not allow method ' . "$method for '$scheme:' URLs");
    }

    # extract the identifier and check against posting to an article
    my $groupart = $url->_group;
    my $is_art   = $groupart =~ /@/;

    if ($is_art && $method eq 'POST') {
        return HTTP::Response->new(HTTP::Status::RC_BAD_REQUEST,
            "Can't post to an article <$groupart>");
    }

    my $nntp = Net::NNTP->new(
        $url->host,

        #Port    => 18574,
        Timeout => $timeout,

        #Debug   => 1,
    );
    die "Can't connect to nntp server" unless $nntp;

    # Check the initial welcome message from the NNTP server
    if ($nntp->status != 2) {
        return HTTP::Response->new(HTTP::Status::RC_SERVICE_UNAVAILABLE,
            $nntp->message);
    }
    my $response = HTTP::Response->new(HTTP::Status::RC_OK, "OK");

    my $mess = $nntp->message;

    # Try to extract server name from greeting message.
    # Don't know if this works well for a large class of servers, but
    # this works for our server.
    $mess =~ s/\s+ready\b.*//;
    $mess =~ s/^\S+\s+//;
    $response->header(Server => $mess);

    # First we handle posting of articles
    if ($method eq 'POST') {
        $nntp->quit;
        $nntp = undef;
        $response->code(HTTP::Status::RC_NOT_IMPLEMENTED);
        $response->message("POST not implemented yet");
        return $response;
    }

    # The method must be "GET" or "HEAD" by now
    if (!$is_art) {
        if (!$nntp->group($groupart)) {
            $response->code(HTTP::Status::RC_NOT_FOUND);
            $response->message($nntp->message);
        }
        $nntp->quit;
        $nntp = undef;

        # HEAD: just check if the group exists
        if ($method eq 'GET' && $response->is_success) {
            $response->code(HTTP::Status::RC_NOT_IMPLEMENTED);
            $response->message("GET newsgroup not implemented yet");
        }
        return $response;
    }

    # Send command to server to retrieve an article (or just the headers)
    my $get = $method eq 'HEAD' ? "head" : "article";
    my $art = $nntp->$get("<$groupart>");
    unless ($art) {
        $nntp->quit;
        $response->code(HTTP::Status::RC_NOT_FOUND);
        $response->message($nntp->message);
        $nntp = undef;
        return $response;
    }

    # Parse headers
    my ($key, $val);
    local $_;
    while ($_ = shift @$art) {
        if (/^\s+$/) {
            last;    # end of headers
        }
        elsif (/^(\S+):\s*(.*)/) {
            $response->push_header($key, $val) if $key;
            ($key, $val) = ($1, $2);
        }
        elsif (/^\s+(.*)/) {
            next unless $key;
            $val .= $1;
        }
        else {
            unshift(@$art, $_);
            last;
        }
    }
    $response->push_header($key, $val) if $key;

    # Ensure that there is a Content-Type header
    $response->header("Content-Type", "text/plain")
        unless $response->header("Content-Type");

    # Collect the body
    $response = $self->collect_once($arg, $response, join("", @$art)) if @$art;

    # Say goodbye to the server
    $nntp->quit;
    $nntp = undef;

    $response;
}

1;
PK6N%[Z����perl5/LWP/Protocol/data.pmnu��6�$package LWP::Protocol::data;

# Implements access to data:-URLs as specified in RFC 2397

use strict;

our $VERSION = '6.78';

require HTTP::Response;
require HTTP::Status;

use parent qw(LWP::Protocol);

use HTTP::Date qw(time2str);
require LWP;  # needs version number

sub request
{
    my($self, $request, $proxy, $arg, $size) = @_;

    # check proxy
    if (defined $proxy)
    {
	return HTTP::Response->new( HTTP::Status::RC_BAD_REQUEST,
				  'You can not proxy with data');
    }

    # check method
    my $method = $request->method;
    unless ($method eq 'GET' || $method eq 'HEAD') {
	return HTTP::Response->new( HTTP::Status::RC_BAD_REQUEST,
				  'Library does not allow method ' .
				  "$method for 'data:' URLs");
    }

    my $url = $request->uri;
    my $response = HTTP::Response->new( HTTP::Status::RC_OK, "Document follows");

    my $media_type = $url->media_type;

    my $data = $url->data;
    $response->header('Content-Type'   => $media_type,
		      'Content-Length' => length($data),
		      'Date'           => time2str(time),
		      'Server'         => "libwww-perl-internal/$LWP::VERSION"
		     );

    $data = "" if $method eq "HEAD";
    return $self->collect_once($arg, $response, $data);
}

1;
PK6N%[���SSperl5/LWP/Protocol/cpan.pmnu��6�$package LWP::Protocol::cpan;

use strict;

use parent qw(LWP::Protocol);

our $VERSION = '6.78';

require URI;
require HTTP::Status;
require HTTP::Response;

our $CPAN;

unless ($CPAN) {
    # Try to find local CPAN mirror via $CPAN::Config
    eval {
	require CPAN::Config;
	if($CPAN::Config) {
	    my $urls = $CPAN::Config->{urllist};
	    if (ref($urls) eq "ARRAY") {
		my $file;
		for (@$urls) {
		    if (/^file:/) {
			$file = $_;
			last;
		    }
		}

		if ($file) {
		    $CPAN = $file;
		}
		else {
		    $CPAN = $urls->[0];
		}
	    }
	}
    };

    $CPAN ||= "http://cpan.org/";  # last resort
}

# ensure that we don't chop of last part
$CPAN .= "/" unless $CPAN =~ m,/$,;


sub request {
    my($self, $request, $proxy, $arg, $size) = @_;
    # check proxy
    if (defined $proxy)
    {
	return HTTP::Response->new(HTTP::Status::RC_BAD_REQUEST,
				   'You can not proxy with cpan');
    }

    # check method
    my $method = $request->method;
    unless ($method eq 'GET' || $method eq 'HEAD') {
	return HTTP::Response->new(HTTP::Status::RC_BAD_REQUEST,
				   'Library does not allow method ' .
				   "$method for 'cpan:' URLs");
    }

    my $path = $request->uri->path;
    $path =~ s,^/,,;

    my $response = HTTP::Response->new(HTTP::Status::RC_FOUND);
    $response->header("Location" => URI->new_abs($path, $CPAN));
    $response;
}

1;
PK6N%[��6��J�Jperl5/LWP/Protocol/ftp.pmnu��6�$package LWP::Protocol::ftp;

# Implementation of the ftp protocol (RFC 959). We let the Net::FTP
# package do all the dirty work.
use parent qw(LWP::Protocol);
use strict;

our $VERSION = '6.78';

use Carp            ();
use HTTP::Status    ();
use HTTP::Negotiate ();
use HTTP::Response  ();
use LWP::MediaTypes ();
use File::Listing   ();


{

    package # hide from PAUSE
        LWP::Protocol::MyFTP;

    use strict;
    use parent qw(Net::FTP);

    sub new {
        my $class = shift;

        my $self = $class->SUPER::new(@_) || return undef;

        my $mess = $self->message;    # welcome message
        $mess =~ s|\n.*||s;           # only first line left
        $mess =~ s|\s*ready\.?$||;

        # Make the version number more HTTP like
        $mess =~ s|\s*\(Version\s*|/| and $mess =~ s|\)$||;
        ${*$self}{myftp_server} = $mess;

        #$response->header("Server", $mess);

        $self;
    }

    sub http_server {
        my $self = shift;
        ${*$self}{myftp_server};
    }

    sub home {
        my $self = shift;
        my $old  = ${*$self}{myftp_home};
        if (@_) {
            ${*$self}{myftp_home} = shift;
        }
        $old;
    }

    sub go_home {
        my $self = shift;
        $self->cwd(${*$self}{myftp_home});
    }

    sub request_count {
        my $self = shift;
        ++${*$self}{myftp_reqcount};
    }

    sub ping {
        my $self = shift;
        return $self->go_home;
    }
}

sub _connect {
    my ($self, $host, $port, $user, $account, $password, $timeout) = @_;

    my $key;
    my $conn_cache = $self->{ua}{conn_cache};
    if ($conn_cache) {
        $key = "$host:$port:$user";
        $key .= ":$account" if defined($account);
        if (my $ftp = $conn_cache->withdraw("ftp", $key)) {
            if ($ftp->ping) {

                # save it again
                $conn_cache->deposit("ftp", $key, $ftp);
                return $ftp;
            }
        }
    }

    # try to make a connection
    my $ftp = LWP::Protocol::MyFTP->new(
        $host,
        Port      => $port,
        Timeout   => $timeout,
        LocalAddr => $self->{ua}{local_address},
    );

    # XXX Should be some what to pass on 'Passive' (header??)
    unless ($ftp) {
        $@ =~ s/^Net::FTP: //;
        return HTTP::Response->new(HTTP::Status::RC_INTERNAL_SERVER_ERROR, $@);
    }

    unless ($ftp->login($user, $password, $account)) {

        # Unauthorized.  Let's fake a RC_UNAUTHORIZED response
        my $mess = scalar($ftp->message);
        $mess =~ s/\n$//;
        my $res = HTTP::Response->new(HTTP::Status::RC_UNAUTHORIZED, $mess);
        $res->header("Server",           $ftp->http_server);
        $res->header("WWW-Authenticate", qq(Basic Realm="FTP login"));
        return $res;
    }

    my $home = $ftp->pwd;
    $ftp->home($home);

    $conn_cache->deposit("ftp", $key, $ftp) if $conn_cache;

    return $ftp;
}


sub request {
    my ($self, $request, $proxy, $arg, $size, $timeout) = @_;

    $size = 4096 unless $size;

    # check proxy
    if (defined $proxy) {
        return HTTP::Response->new(HTTP::Status::RC_BAD_REQUEST,
            'You can not proxy through the ftp');
    }

    my $url = $request->uri;
    if ($url->scheme ne 'ftp') {
        my $scheme = $url->scheme;
        return HTTP::Response->new(HTTP::Status::RC_INTERNAL_SERVER_ERROR,
            "LWP::Protocol::ftp::request called for '$scheme'");
    }

    # check method
    my $method = $request->method;

    unless ($method eq 'GET' || $method eq 'HEAD' || $method eq 'PUT') {
        return HTTP::Response->new(HTTP::Status::RC_BAD_REQUEST,
            'Library does not allow method ' . "$method for 'ftp:' URLs");
    }

    my $host     = $url->host;
    my $port     = $url->port;
    my $user     = $url->user;
    my $password = $url->password;

    # If a basic authorization header is present than we prefer these over
    # the username/password specified in the URL.
    {
        my ($u, $p) = $request->authorization_basic;
        if (defined $u) {
            $user     = $u;
            $password = $p;
        }
    }

    # We allow the account to be specified in the "Account" header
    my $account = $request->header('Account');

    my $ftp
        = $self->_connect($host, $port, $user, $account, $password, $timeout);
    return $ftp if ref($ftp) eq "HTTP::Response";    # ugh!

    # Create an initial response object
    my $response = HTTP::Response->new(HTTP::Status::RC_OK, "OK");
    $response->header(Server               => $ftp->http_server);
    $response->header('Client-Request-Num' => $ftp->request_count);
    $response->request($request);

    # Get & fix the path
    my @path = grep {length} $url->path_segments;
    my $remote_file = pop(@path);
    $remote_file = '' unless defined $remote_file;

    my $type;
    if (ref $remote_file) {
        my @params;
        ($remote_file, @params) = @$remote_file;
        for (@params) {
            $type = $_ if s/^type=//;
        }
    }

    if ($type && $type eq 'a') {
        $ftp->ascii;
    }
    else {
        $ftp->binary;
    }

    for (@path) {
        unless ($ftp->cwd($_)) {
            return HTTP::Response->new(HTTP::Status::RC_NOT_FOUND,
                "Can't chdir to $_");
        }
    }

    if ($method eq 'GET' || $method eq 'HEAD') {
        if (my $mod_time = $ftp->mdtm($remote_file)) {
            $response->last_modified($mod_time);
            if (my $ims = $request->if_modified_since) {
                if ($mod_time <= $ims) {
                    $response->code(HTTP::Status::RC_NOT_MODIFIED);
                    $response->message("Not modified");
                    return $response;
                }
            }
        }

        # We'll use this later to abort the transfer if necessary.
        # if $max_size is defined, we need to abort early. Otherwise, it's
        # a normal transfer
        my $max_size = undef;

        # Set resume location, if the client requested it
        if ($request->header('Range') && $ftp->supported('REST')) {
            my $range_info = $request->header('Range');

            # Change bytes=2772992-6781209 to just 2772992
            my ($start_byte, $end_byte) = $range_info =~ /.*=\s*(\d+)-(\d+)?/;
            if (defined $start_byte && !defined $end_byte) {

                # open range -- only the start is specified

                $ftp->restart($start_byte);

                # don't define $max_size, we don't want to abort early
            }
            elsif (defined $start_byte
                && defined $end_byte
                && $start_byte >= 0
                && $end_byte >= $start_byte)
            {

                $ftp->restart($start_byte);
                $max_size = $end_byte - $start_byte;
            }
            else {

                return HTTP::Response->new(HTTP::Status::RC_BAD_REQUEST,
                    'Incorrect syntax for Range request');
            }
        }
        elsif ($request->header('Range') && !$ftp->supported('REST')) {
            return HTTP::Response->new(HTTP::Status::RC_NOT_IMPLEMENTED,
                "Server does not support resume."
            );
        }

        my $data;    # the data handle
        if (length($remote_file) and $data = $ftp->retr($remote_file)) {
            my ($type, @enc) = LWP::MediaTypes::guess_media_type($remote_file);
            $response->header('Content-Type', $type) if $type;
            for (@enc) {
                $response->push_header('Content-Encoding', $_);
            }
            my $mess = $ftp->message;
            if ($mess =~ /\((\d+)\s+bytes\)/) {
                $response->header('Content-Length', "$1");
            }

            if ($method ne 'HEAD') {

                # Read data from server
                $response = $self->collect(
                    $arg,
                    $response,
                    sub {
                        my $content = '';
                        my $result = $data->read($content, $size);

                        # Stop early if we need to.
                        if (defined $max_size) {

                        # We need an interface to Net::FTP::dataconn for getting
                        # the number of bytes already read
                            my $bytes_received = $data->bytes_read();

                           # We were already over the limit. (Should only happen
                           # once at the end.)
                            if ($bytes_received - length($content) > $max_size)
                            {
                                $content = '';
                            }

                            # We just went over the limit
                            elsif ($bytes_received > $max_size) {

                                # Trim content
                                $content = substr($content, 0,
                                    $max_size
                                        - ($bytes_received - length($content)));
                            }

                            # We're under the limit
                            else {
                            }
                        }

                        return \$content;
                    }
                );
            }

            # abort is needed for HEAD, it's == close if the transfer has
            # already completed.
            unless ($data->abort) {

                # Something did not work too well.  Note that we treat
                # responses to abort() with code 0 in case of HEAD as ok
                # (at least wu-ftpd 2.6.1(1) does that).
                if ($method ne 'HEAD' || $ftp->code != 0) {
                    $response->code(HTTP::Status::RC_INTERNAL_SERVER_ERROR);
                    $response->message("FTP close response: "
                            . $ftp->code . " "
                            . $ftp->message);
                }
            }
        }
        elsif (!length($remote_file) || ($ftp->code >= 400 && $ftp->code < 600))
        {
            # not a plain file, try to list instead
            if (length($remote_file) && !$ftp->cwd($remote_file)) {
                return HTTP::Response->new(HTTP::Status::RC_NOT_FOUND,
                    "File '$remote_file' not found"
                );
            }

            # It should now be safe to try to list the directory
            my @lsl = $ftp->dir;

            # Try to figure out if the user want us to convert the
            # directory listing to HTML.
            my @variants = (
                ['html', 0.60, 'text/html'],
                ['dir',  1.00, 'text/ftp-dir-listing']
            );

            #$HTTP::Negotiate::DEBUG=1;
            my $prefer = HTTP::Negotiate::choose(\@variants, $request);

            my $content = '';

            if (!defined($prefer)) {
                return HTTP::Response->new(HTTP::Status::RC_NOT_ACCEPTABLE,
                    "Neither HTML nor directory listing wanted");
            }
            elsif ($prefer eq 'html') {
                $response->header('Content-Type' => 'text/html');
                $content = "<HEAD><TITLE>File Listing</TITLE>\n";
                my $base = $request->uri->clone;
                my $path = $base->path;
                $base->path("$path/") unless $path =~ m|/$|;
                $content .= qq(<BASE HREF="$base">\n</HEAD>\n);
                $content .= "<BODY>\n<UL>\n";
                for (File::Listing::parse_dir(\@lsl, 'GMT')) {
                    my ($name, $type, $size, $mtime, $mode) = @$_;
                    $content .= qq(  <LI> <a href="$name">$name</a>);
                    $content .= " $size bytes" if $type eq 'f';
                    $content .= "\n";
                }
                $content .= "</UL></body>\n";
            }
            else {
                $response->header('Content-Type', 'text/ftp-dir-listing');
                $content = join("\n", @lsl, '');
            }

            $response->header('Content-Length', length($content));

            if ($method ne 'HEAD') {
                $response = $self->collect_once($arg, $response, $content);
            }
        }
        else {
            my $res = HTTP::Response->new(HTTP::Status::RC_BAD_REQUEST,
                "FTP return code " . $ftp->code);
            $res->content_type("text/plain");
            $res->content($ftp->message);
            return $res;
        }
    }
    elsif ($method eq 'PUT') {

        # method must be PUT
        unless (length($remote_file)) {
            return HTTP::Response->new(HTTP::Status::RC_BAD_REQUEST,
                "Must have a file name to PUT to"
            );
        }
        my $data;
        if ($data = $ftp->stor($remote_file)) {
            my $content = $request->content;
            my $bytes   = 0;
            if (defined $content) {
                if (ref($content) eq 'SCALAR') {
                    $bytes = $data->write($$content, length($$content));
                }
                elsif (ref($content) eq 'CODE') {
                    my ($buf, $n);
                    while (length($buf = &$content)) {
                        $n = $data->write($buf, length($buf));
                        last unless $n;
                        $bytes += $n;
                    }
                }
                elsif (!ref($content)) {
                    if (defined $content && length($content)) {
                        $bytes = $data->write($content, length($content));
                    }
                }
                else {
                    die "Bad content";
                }
            }
            $data->close;

            $response->code(HTTP::Status::RC_CREATED);
            $response->header('Content-Type', 'text/plain');
            $response->content("$bytes bytes stored as $remote_file on $host\n")

        }
        else {
            my $res = HTTP::Response->new(HTTP::Status::RC_BAD_REQUEST,
                "FTP return code " . $ftp->code);
            $res->content_type("text/plain");
            $res->content($ftp->message);
            return $res;
        }
    }
    else {
        return HTTP::Response->new(HTTP::Status::RC_BAD_REQUEST,
            "Illegal method $method");
    }

    $response;
}

1;

__END__

# This is what RFC 1738 has to say about FTP access:
# --------------------------------------------------
#
# 3.2. FTP
#
#    The FTP URL scheme is used to designate files and directories on
#    Internet hosts accessible using the FTP protocol (RFC959).
#
#    A FTP URL follow the syntax described in Section 3.1.  If :<port> is
#    omitted, the port defaults to 21.
#
# 3.2.1. FTP Name and Password
#
#    A user name and password may be supplied; they are used in the ftp
#    "USER" and "PASS" commands after first making the connection to the
#    FTP server.  If no user name or password is supplied and one is
#    requested by the FTP server, the conventions for "anonymous" FTP are
#    to be used, as follows:
#
#         The user name "anonymous" is supplied.
#
#         The password is supplied as the Internet e-mail address
#         of the end user accessing the resource.
#
#    If the URL supplies a user name but no password, and the remote
#    server requests a password, the program interpreting the FTP URL
#    should request one from the user.
#
# 3.2.2. FTP url-path
#
#    The url-path of a FTP URL has the following syntax:
#
#         <cwd1>/<cwd2>/.../<cwdN>/<name>;type=<typecode>
#
#    Where <cwd1> through <cwdN> and <name> are (possibly encoded) strings
#    and <typecode> is one of the characters "a", "i", or "d".  The part
#    ";type=<typecode>" may be omitted. The <cwdx> and <name> parts may be
#    empty. The whole url-path may be omitted, including the "/"
#    delimiting it from the prefix containing user, password, host, and
#    port.
#
#    The url-path is interpreted as a series of FTP commands as follows:
#
#       Each of the <cwd> elements is to be supplied, sequentially, as the
#       argument to a CWD (change working directory) command.
#
#       If the typecode is "d", perform a NLST (name list) command with
#       <name> as the argument, and interpret the results as a file
#       directory listing.
#
#       Otherwise, perform a TYPE command with <typecode> as the argument,
#       and then access the file whose name is <name> (for example, using
#       the RETR command.)
#
#    Within a name or CWD component, the characters "/" and ";" are
#    reserved and must be encoded. The components are decoded prior to
#    their use in the FTP protocol.  In particular, if the appropriate FTP
#    sequence to access a particular file requires supplying a string
#    containing a "/" as an argument to a CWD or RETR command, it is
#    necessary to encode each "/".
#
#    For example, the URL <URL:ftp://myname@host.dom/%2Fetc/motd> is
#    interpreted by FTP-ing to "host.dom", logging in as "myname"
#    (prompting for a password if it is asked for), and then executing
#    "CWD /etc" and then "RETR motd". This has a different meaning from
#    <URL:ftp://myname@host.dom/etc/motd> which would "CWD etc" and then
#    "RETR motd"; the initial "CWD" might be executed relative to the
#    default directory for "myname". On the other hand,
#    <URL:ftp://myname@host.dom//etc/motd>, would "CWD " with a null
#    argument, then "CWD etc", and then "RETR motd".
#
#    FTP URLs may also be used for other operations; for example, it is
#    possible to update a file on a remote file server, or infer
#    information about it from the directory listings. The mechanism for
#    doing so is not spelled out here.
#
# 3.2.3. FTP Typecode is Optional
#
#    The entire ;type=<typecode> part of a FTP URL is optional. If it is
#    omitted, the client program interpreting the URL must guess the
#    appropriate mode to use. In general, the data content type of a file
#    can only be guessed from the name, e.g., from the suffix of the name;
#    the appropriate type code to be used for transfer of the file can
#    then be deduced from the data content of the file.
#
# 3.2.4 Hierarchy
#
#    For some file systems, the "/" used to denote the hierarchical
#    structure of the URL corresponds to the delimiter used to construct a
#    file name hierarchy, and thus, the filename will look similar to the
#    URL path. This does NOT mean that the URL is a Unix filename.
#
# 3.2.5. Optimization
#
#    Clients accessing resources via FTP may employ additional heuristics
#    to optimize the interaction. For some FTP servers, for example, it
#    may be reasonable to keep the control connection open while accessing
#    multiple URLs from the same server. However, there is no common
#    hierarchical model to the FTP protocol, so if a directory change
#    command has been given, it is impossible in general to deduce what
#    sequence should be given to navigate to another directory for a
#    second retrieval, if the paths are different.  The only reliable
#    algorithm is to disconnect and reestablish the control connection.
PK6N%[�e����perl5/LWP/Protocol/https.pmnu��6�$package LWP::Protocol::https;

use strict;
use warnings;

our $VERSION = '6.14';

use parent qw(LWP::Protocol::http);
require Net::HTTPS;

sub socket_type
{
    return "https";
}

sub _extra_sock_opts
{
    my $self = shift;
    my %ssl_opts = %{$self->{ua}{ssl_opts} || {}};
    if (delete $ssl_opts{verify_hostname}) {
	$ssl_opts{SSL_verify_mode} ||= 1;
	$ssl_opts{SSL_verifycn_scheme} = 'www';
    }
    else {
        if ( $Net::HTTPS::SSL_SOCKET_CLASS eq 'Net::SSL' ) {
            $ssl_opts{SSL_verifycn_scheme} = '';
        } else {
            $ssl_opts{SSL_verifycn_scheme} = 'none';
        }
    }
    if ($ssl_opts{SSL_verify_mode}) {
        unless (exists $ssl_opts{SSL_ca_file} || exists $ssl_opts{SSL_ca_path}) {
            if ($Net::HTTPS::SSL_SOCKET_CLASS eq 'IO::Socket::SSL'
                && defined &IO::Socket::SSL::default_ca
                && IO::Socket::SSL::default_ca() ) {
                # IO::Socket::SSL has a usable default CA
            } elsif ( my $cafile = eval {
            require Mozilla::CA;
            Mozilla::CA::SSL_ca_file()
            }) {
            # use Mozilla::CA
            $ssl_opts{SSL_ca_file} = $cafile;
            } else {
                die <<'EOT';
Can't verify SSL peers without knowing which Certificate Authorities to trust.

This problem can be fixed by either setting the PERL_LWP_SSL_CA_FILE
environment variable to the file where your trusted CA are, or by installing
the Mozilla::CA module for set of commonly trusted CAs.

To completely disable the verification that you talk to the correct SSL peer you
can set SSL_verify_mode to 0 within ssl_opts.  But, if you do this you can't be
sure that you communicate with the expected peer.
EOT
            }
        }
    }
    $self->{ssl_opts} = \%ssl_opts;
    return (%ssl_opts, MultiHomed => 1, $self->SUPER::_extra_sock_opts);
}

# This is a subclass of LWP::Protocol::http.
# That parent class calls ->_check_sock() during the
# request method. This allows us to hook in and run checks
# sub _check_sock
# {
#     my($self, $req, $sock) = @_;
# }

sub _get_sock_info
{
    my $self = shift;
    $self->SUPER::_get_sock_info(@_);
    my($res, $sock) = @_;
    if ($sock->can('get_sslversion') and my $sslversion = $sock->get_sslversion) {
        $res->header("Client-SSL-Version" => $sslversion);
    }
    $res->header("Client-SSL-Cipher" => $sock->get_cipher);
    my $cert = $sock->get_peer_certificate;
    if ($cert) {
	$res->header("Client-SSL-Cert-Subject" => $cert->subject_name);
	$res->header("Client-SSL-Cert-Issuer" => $cert->issuer_name);
    }
    if (!$self->{ssl_opts}{SSL_verify_mode}) {
	$res->push_header("Client-SSL-Warning" => "Peer certificate not verified");
    }
    elsif (!$self->{ssl_opts}{SSL_verifycn_scheme}) {
	$res->push_header("Client-SSL-Warning" => "Peer hostname match with certificate not verified");
    }
    $res->header("Client-SSL-Socket-Class" => $Net::HTTPS::SSL_SOCKET_CLASS);
}

# upgrade plain socket to SSL, used for CONNECT tunnel when proxying https
# will only work if the underlying socket class of Net::HTTPS is
# IO::Socket::SSL, but code will only be called in this case
if ( $Net::HTTPS::SSL_SOCKET_CLASS->can('start_SSL')) {
    *_upgrade_sock = sub {
	my ($self,$sock,$url) = @_;
    # SNI should be passed there only if it is not an IP address.
    # Details: https://github.com/libwww-perl/libwww-perl/issues/449#issuecomment-1896175509
	my $host = $url->host() =~ m/:|^[\d.]+$/s ? undef : $url->host();
	$sock = LWP::Protocol::https::Socket->start_SSL( $sock,
	    SSL_verifycn_name => $url->host,
	    SSL_hostname => $host,
	    $self->_extra_sock_opts,
	);
	$@ = LWP::Protocol::https::Socket->errstr if ! $sock;
	return $sock;
    }
}

#-----------------------------------------------------------
package LWP::Protocol::https::Socket;

use parent -norequire, qw(Net::HTTPS LWP::Protocol::http::SocketMethods);

1;

__END__

=head1 NAME

LWP::Protocol::https - Provide https support for LWP::UserAgent

=head1 SYNOPSIS

  use LWP::UserAgent;

  $ua = LWP::UserAgent->new(ssl_opts => { verify_hostname => 1 });
  $res = $ua->get("https://www.example.com");

  # specify a CA path
  $ua = LWP::UserAgent->new(
      ssl_opts => {
          SSL_ca_path     => '/etc/ssl/certs',
          verify_hostname => 1,
      }
  );

=head1 DESCRIPTION

The LWP::Protocol::https module provides support for using https schemed
URLs with LWP.  This module is a plug-in to the LWP protocol handling, so
you don't use it directly.  Once the module is installed LWP is able
to access sites using HTTP over SSL/TLS.

If hostname verification is requested by LWP::UserAgent's C<ssl_opts>, and
neither C<SSL_ca_file> nor C<SSL_ca_path> is set, then C<SSL_ca_file> is
implied to be the one provided by L<Mozilla::CA>.  If the Mozilla::CA module
isn't available SSL requests will fail.  Either install this module, set up an
alternative C<SSL_ca_file> or disable hostname verification.

This module used to be bundled with the libwww-perl, but it was unbundled in
v6.02 in order to be able to declare its dependencies properly for the CPAN
tool-chain.  Applications that need https support can just declare their
dependency on LWP::Protocol::https and will no longer need to know what
underlying modules to install.

=head1 SEE ALSO

L<IO::Socket::SSL>, L<Crypt::SSLeay>, L<Mozilla::CA>

=head1 COPYRIGHT & LICENSE

Copyright (c) 1997-2011 Gisle Aas.

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

=cut
PK6N%[:,}}!perl5/LWP/Protocol/https/hosts.pmnu��6�$package LWP::Protocol::https::hosts;

use strict;
use warnings;
use parent 'LWP::Protocol::https';
use LWP::UserAgent::DNS::Hosts;

sub _extra_sock_opts {
    my ($self, $host, $port) = @_;

    my @opts = $self->SUPER::_extra_sock_opts($host, $port);
    if (my $peer_addr = LWP::UserAgent::DNS::Hosts->_registered_peer_addr($host)) {
        push @opts, (
            PeerAddr          => $peer_addr,
            Host              => $host,
            SSL_verifycn_name => $host,
            SSL_hostname      => $host, # for SNI
        );
    }

    return @opts;
}

sub socket_class { 'LWP::Protocol::https::Socket' }

1;

__END__
PK6N%[��:�:perl5/LWP/Protocol/http.pmnu��6�$package LWP::Protocol::http;

use strict;

our $VERSION = '6.78';

require HTTP::Response;
require HTTP::Status;
require Net::HTTP;
use parent qw(LWP::Protocol);

our @EXTRA_SOCK_OPTS;
my $CRLF = "\015\012";

sub _new_socket
{
    my($self, $host, $port, $timeout) = @_;

    # IPv6 literal IP address should be [bracketed] to remove
    # ambiguity between ip address and port number.
    if ( ($host =~ /:/) && ($host !~ /^\[/) ) {
      $host = "[$host]";
    }

    local($^W) = 0;  # IO::Socket::INET can be noisy
    my $sock = $self->socket_class->new(PeerAddr => $host,
					PeerPort => $port,
					LocalAddr => $self->{ua}{local_address},
					Proto    => 'tcp',
					Timeout  => $timeout,
					KeepAlive => !!$self->{ua}{conn_cache},
					SendTE    => $self->{ua}{send_te},
					$self->_extra_sock_opts($host, $port),
				       );

    unless ($sock) {
	# IO::Socket::INET leaves additional error messages in $@
	my $status = "Can't connect to $host:$port";
	if ($@ =~ /\bconnect: (.*)/ ||
	    $@ =~ /\b(Bad hostname)\b/ ||
	    $@ =~ /\b(nodename nor servname provided, or not known)\b/ ||
	    $@ =~ /\b(certificate verify failed)\b/ ||
	    $@ =~ /\b(Crypt-SSLeay can't verify hostnames)\b/
	) {
	    $status .= " ($1)";
	} elsif ($@) {
	    $status .= " ($@)";
	}
	die "$status\n\n$@";
    }

    $sock->blocking(0);

    $sock;
}

sub socket_type
{
    return "http";
}

sub socket_class
{
    my $self = shift;
    (ref($self) || $self) . "::Socket";
}

sub _extra_sock_opts  # to be overridden by subclass
{
    return @EXTRA_SOCK_OPTS;
}

sub _check_sock
{
    #my($self, $req, $sock) = @_;
}

sub _get_sock_info
{
    my($self, $res, $sock) = @_;
    if (defined(my $peerhost = $sock->peerhost)) {
        $res->header("Client-Peer" => "$peerhost:" . $sock->peerport);
    }
}

sub _fixup_header
{
    my($self, $h, $url, $proxy) = @_;

    # Extract 'Host' header
    my $hhost = $url->authority;
    if ($hhost =~ s/^([^\@]*)\@//) {  # get rid of potential "user:pass@"
	# add authorization header if we need them.  HTTP URLs do
	# not really support specification of user and password, but
	# we allow it.
	if (defined($1) && not $h->header('Authorization')) {
	    require URI::Escape;
	    $h->authorization_basic(map URI::Escape::uri_unescape($_),
				    split(":", $1, 2));
	}
    }
    $h->init_header('Host' => $hhost);

    if ($proxy && $url->scheme ne 'https') {
	# Check the proxy URI's userinfo() for proxy credentials
	# export http_proxy="http://proxyuser:proxypass@proxyhost:port".
	# For https only the initial CONNECT requests needs authorization.
	my $p_auth = $proxy->userinfo();
	if(defined $p_auth) {
	    require URI::Escape;
	    $h->proxy_authorization_basic(map URI::Escape::uri_unescape($_),
					  split(":", $p_auth, 2))
	}
    }
}

sub hlist_remove {
    my($hlist, $k) = @_;
    $k = lc $k;
    for (my $i = @$hlist - 2; $i >= 0; $i -= 2) {
	next unless lc($hlist->[$i]) eq $k;
	splice(@$hlist, $i, 2);
    }
}

sub request
{
    my($self, $request, $proxy, $arg, $size, $timeout) = @_;

    $size ||= 4096;

    # check method
    my $method = $request->method;
    unless ($method =~ /^[A-Za-z0-9_!\#\$%&\'*+\-.^\`|~]+$/) {  # HTTP token
	return HTTP::Response->new( HTTP::Status::RC_BAD_REQUEST,
				  'Library does not allow method ' .
				  "$method for 'http:' URLs");
    }

    my $url = $request->uri;

    # Proxying SSL with a http proxy needs issues a CONNECT request to build a
    # tunnel and then upgrades the tunnel to SSL. But when doing keep-alive the
    # https request does not need to be the first request in the connection, so
    # we need to distinguish between
    # - not yet connected (create socket and ssl upgrade)
    # - connected but not inside ssl tunnel (ssl upgrade)
    # - inside ssl tunnel to the target - once we are in the tunnel to the
    #   target we cannot only reuse the tunnel for more https requests with the
    #   same target

    my $ssl_tunnel = $proxy && $url->scheme eq 'https'
	&& $url->host_port();

    my ($host,$port) = $proxy
	? ($proxy->host,$proxy->port)
	: ($url->host,$url->port);
    my $fullpath =
	$method eq 'CONNECT' ? $url->host_port() :
	$proxy && ! $ssl_tunnel ? $url->as_string :
	do {
	    my $path = $url->path_query;
	    $path = "/$path" if $path !~m{^/};
	    $path
	};

    my $socket;
    my $conn_cache = $self->{ua}{conn_cache};
    my $cache_key;
    if ( $conn_cache ) {
	$cache_key = "$host:$port";
	# For https we reuse the socket immediately only if it has an established
	# tunnel to the target. Otherwise a CONNECT request followed by an SSL
	# upgrade need to be done first. The request itself might reuse an
	# existing non-ssl connection to the proxy
	$cache_key .= "!".$ssl_tunnel if $ssl_tunnel;
	if ( $socket = $conn_cache->withdraw($self->socket_type,$cache_key)) {
	    if ($socket->can_read(0)) {
		# if the socket is readable, then either the peer has closed the
		# connection or there are some garbage bytes on it.  In either
		# case we abandon it.
		$socket->close;
		$socket = undef;
	    } # else use $socket
	    else {
		$socket->timeout($timeout);
	    }
	}
    }

    if ( ! $socket && $ssl_tunnel ) {
	my $proto_https = LWP::Protocol::create('https',$self->{ua})
	    or die "no support for scheme https found";

	# only if ssl socket class is IO::Socket::SSL we can upgrade
	# a plain socket to SSL. In case of Net::SSL we fall back to
	# the old version
	if ( my $upgrade_sub = $proto_https->can('_upgrade_sock')) {
	    my $response = $self->request(
		HTTP::Request->new('CONNECT',"http://$ssl_tunnel"),
		$proxy,
		undef,$size,$timeout
	    );
	    $response->is_success or die
		"establishing SSL tunnel failed: ".$response->status_line;
	    $socket = $upgrade_sub->($proto_https,
		$response->{client_socket},$url)
		or die "SSL upgrade failed: $@";
	} else {
	    $socket = $proto_https->_new_socket($url->host,$url->port,$timeout);
	}
    }

    if ( ! $socket ) {
	# connect to remote site w/o reusing established socket
	$socket = $self->_new_socket($host, $port, $timeout );
    }

    my $http_version = "";
    if (my $proto = $request->protocol) {
	if ($proto =~ /^(?:HTTP\/)?(1.\d+)$/) {
	    $http_version = $1;
	    $socket->http_version($http_version);
	    $socket->send_te(0) if $http_version eq "1.0";
	}
    }

    $self->_check_sock($request, $socket);

    my @h;
    my $request_headers = $request->headers->clone;
    $self->_fixup_header($request_headers, $url, $proxy);

    $request_headers->scan(sub {
			       my($k, $v) = @_;
			       $k =~ s/^://;
			       $v =~ tr/\n/ /;
			       push(@h, $k, $v);
			   });

    my $content_ref = $request->content_ref;
    $content_ref = $$content_ref if ref($$content_ref);
    my $chunked;
    my $has_content;

    if (ref($content_ref) eq 'CODE') {
	my $clen = $request_headers->header('Content-Length');
	$has_content++ if $clen;
	unless (defined $clen) {
	    push(@h, "Transfer-Encoding" => "chunked");
	    $has_content++;
	    $chunked++;
	}
    }
    else {
	# Set (or override) Content-Length header
	my $clen = $request_headers->header('Content-Length');
	if (defined($$content_ref) && length($$content_ref)) {
	    $has_content = length($$content_ref);
	    if (!defined($clen) || $clen ne $has_content) {
		if (defined $clen) {
		    warn "Content-Length header value was wrong, fixed";
		    hlist_remove(\@h, 'Content-Length');
		}
		push(@h, 'Content-Length' => $has_content);
	    }
	}
	elsif ($clen) {
	    warn "Content-Length set when there is no content, fixed";
	    hlist_remove(\@h, 'Content-Length');
	}
    }

    my $write_wait = 0;
    $write_wait = 2
	if ($request_headers->header("Expect") || "") =~ /100-continue/;

    my $req_buf = $socket->format_request($method, $fullpath, @h);
    #print "------\n$req_buf\n------\n";

    if (!$has_content || $write_wait || $has_content > 8*1024) {
      WRITE:
        {
            # Since this just writes out the header block it should almost
            # always succeed to send the whole buffer in a single write call.
            my $n = $socket->syswrite($req_buf, length($req_buf));
            unless (defined $n) {
                redo WRITE if $!{EINTR};
                if ($!{EWOULDBLOCK} || $!{EAGAIN}) {
                    select(undef, undef, undef, 0.1);
                    redo WRITE;
                }
                die "write failed: $!";
            }
            if ($n) {
                substr($req_buf, 0, $n, "");
            }
            else {
                select(undef, undef, undef, 0.5);
            }
            redo WRITE if length $req_buf;
        }
    }

    my($code, $mess, @junk);
    my $drop_connection;

    if ($has_content) {
	my $eof;
	my $wbuf;
	my $woffset = 0;
      INITIAL_READ:
	if ($write_wait) {
	    # skip filling $wbuf when waiting for 100-continue
	    # because if the response is a redirect or auth required
	    # the request will be cloned and there is no way
	    # to reset the input stream
	    # return here via the label after the 100-continue is read
	}
	elsif (ref($content_ref) eq 'CODE') {
	    my $buf = &$content_ref();
	    $buf = "" unless defined($buf);
	    $buf = sprintf "%x%s%s%s", length($buf), $CRLF, $buf, $CRLF
		if $chunked;
	    substr($buf, 0, 0) = $req_buf if $req_buf;
	    $wbuf = \$buf;
	}
	else {
	    if ($req_buf) {
		my $buf = $req_buf . $$content_ref;
		$wbuf = \$buf;
	    }
	    else {
		$wbuf = $content_ref;
	    }
	    $eof = 1;
	}

	my $fbits = '';
	vec($fbits, fileno($socket), 1) = 1;

      WRITE:
	while ($write_wait || $woffset < length($$wbuf)) {

	    my $sel_timeout = $timeout;
	    if ($write_wait) {
		$sel_timeout = $write_wait if $write_wait < $sel_timeout;
	    }
	    my $time_before;
            $time_before = time if $sel_timeout;

	    my $rbits = $fbits;
	    my $wbits = $write_wait ? undef : $fbits;
            my $sel_timeout_before = $sel_timeout;
          SELECT:
            {
                my $nfound = select($rbits, $wbits, undef, $sel_timeout);
                if ($nfound < 0) {
                    if ($!{EINTR} || $!{EWOULDBLOCK} || $!{EAGAIN}) {
                        if ($time_before) {
                            $sel_timeout = $sel_timeout_before - (time - $time_before);
                            $sel_timeout = 0 if $sel_timeout < 0;
                        }
                        redo SELECT;
                    }
                    die "select failed: $!";
                }
	    }

	    if ($write_wait) {
		$write_wait -= time - $time_before;
		$write_wait = 0 if $write_wait < 0;
	    }

	    if (defined($rbits) && $rbits =~ /[^\0]/) {
		# readable
		my $buf = $socket->_rbuf;
		my $n = $socket->sysread($buf, 1024, length($buf));
                unless (defined $n) {
                    die "read failed: $!" unless  $!{EINTR} || $!{EWOULDBLOCK} || $!{EAGAIN};
                    # if we get here the rest of the block will do nothing
                    # and we will retry the read on the next round
                }
		elsif ($n == 0) {
                    # the server closed the connection before we finished
                    # writing all the request content.  No need to write any more.
                    $drop_connection++;
                    last WRITE;
		}
		$socket->_rbuf($buf);
		if (!$code && $buf =~ /\015?\012\015?\012/) {
		    # a whole response header is present, so we can read it without blocking
		    ($code, $mess, @h) = $socket->read_response_headers(laxed => 1,
									junk_out => \@junk,
								       );
		    if ($code eq "100") {
			$write_wait = 0;
			undef($code);
			goto INITIAL_READ;
		    }
		    else {
			$drop_connection++;
			last WRITE;
			# XXX should perhaps try to abort write in a nice way too
		    }
		}
	    }
	    if (defined($wbits) && $wbits =~ /[^\0]/) {
		my $n = $socket->syswrite($$wbuf, length($$wbuf), $woffset);
                unless (defined $n) {
                    die "write failed: $!" unless $!{EINTR} || $!{EWOULDBLOCK} || $!{EAGAIN};
                    $n = 0;  # will retry write on the next round
                }
                elsif ($n == 0) {
		    die "write failed: no bytes written";
		}
		$woffset += $n;

		if (!$eof && $woffset >= length($$wbuf)) {
		    # need to refill buffer from $content_ref code
		    my $buf = &$content_ref();
		    $buf = "" unless defined($buf);
		    $eof++ unless length($buf);
		    $buf = sprintf "%x%s%s%s", length($buf), $CRLF, $buf, $CRLF
			if $chunked;
		    $wbuf = \$buf;
		    $woffset = 0;
		}
	    }
	} # WRITE
    }

    ($code, $mess, @h) = $socket->read_response_headers(laxed => 1, junk_out => \@junk)
	unless $code;
    ($code, $mess, @h) = $socket->read_response_headers(laxed => 1, junk_out => \@junk)
	if $code eq "100";

    my $response = HTTP::Response->new($code, $mess);
    my $peer_http_version = $socket->peer_http_version;
    $response->protocol("HTTP/$peer_http_version");
    {
	local $HTTP::Headers::TRANSLATE_UNDERSCORE;
	$response->push_header(@h);
    }
    $response->push_header("Client-Junk" => \@junk) if @junk;

    $response->request($request);
    $self->_get_sock_info($response, $socket);

    if ($method eq "CONNECT") {
	$response->{client_socket} = $socket;  # so it can be picked up
	return $response;
    }

    if (my @te = $response->remove_header('Transfer-Encoding')) {
	$response->push_header('Client-Transfer-Encoding', \@te);
    }
    $response->push_header('Client-Response-Num', scalar $socket->increment_response_count);

    my $complete;
    $response = $self->collect($arg, $response, sub {
	my $buf = ""; #prevent use of uninitialized value in SSLeay.xs
	my $n;
      READ:
	{
	    $n = $socket->read_entity_body($buf, $size);
            unless (defined $n) {
                redo READ if $!{EINTR} || $!{EWOULDBLOCK} || $!{EAGAIN} || $!{ENOTTY};
                die "read failed: $!";
            }
	    redo READ if $n == -1;
	}
	$complete++ if !$n;
        return \$buf;
    } );
    $drop_connection++ unless $complete;

    @h = $socket->get_trailers;
    if (@h) {
	local $HTTP::Headers::TRANSLATE_UNDERSCORE;
	$response->push_header(@h);
    }

    # keep-alive support
    unless ($drop_connection) {
	if ($cache_key) {
	    my %connection = map { (lc($_) => 1) }
		             split(/\s*,\s*/, ($response->header("Connection") || ""));
	    if (($peer_http_version eq "1.1" && !$connection{close}) ||
		$connection{"keep-alive"})
	    {
		$conn_cache->deposit($self->socket_type, $cache_key, $socket);
	    }
	}
    }

    $response;
}


#-----------------------------------------------------------
package # hide from PAUSE
    LWP::Protocol::http::SocketMethods;

sub ping {
    my $self = shift;
    !$self->can_read(0);
}

sub increment_response_count {
    my $self = shift;
    return ++${*$self}{'myhttp_response_count'};
}

#-----------------------------------------------------------
package # hide from PAUSE
    LWP::Protocol::http::Socket;

use parent -norequire, qw(LWP::Protocol::http::SocketMethods Net::HTTP);

1;
PK6N%[`m@�� perl5/LWP/UserAgent/DNS/Hosts.pmnu��6�$package LWP::UserAgent::DNS::Hosts;

use 5.008001;
use strict;
use warnings;
use Carp;
use LWP::Protocol;
use Scope::Guard qw(guard);

our $VERSION = '0.14';
$VERSION = eval $VERSION;

our @Protocols = qw(http https);
our %Implementors;

our %Hosts;

sub register_host {
    my ($class, $host, $peer_addr) = @_;
    $Hosts{$host} = $peer_addr;
}

sub register_hosts {
    my ($class, %pairs) = @_;
    while (my ($host, $peer_addr) = each %pairs) {
        $class->register_host($host, $peer_addr);
    }
}

sub clear_hosts {
    %Hosts = ();
}

sub read_hosts {
    my ($class, $source) = @_;

    if (ref $source eq 'GLOB') {
        $class->_read_hosts_from_handle($source);
    }
    elsif ($source !~ /[\x0D\x0A]/ && -f $source) {
        $class->_read_hosts_from_file($source);
    }
    else {
        $class->_read_hosts_from_string($source);
    }
}

sub _read_hosts_from_handle {
    my ($class, $handle) = @_;
    while (<$handle>) {
        chomp;
        s/^\s+//g;
        s/\s+$//g;
        next if !$_ || /^#/;

        my ($addr, @hosts) = split /\s+/;
        for my $host (@hosts) {
            $class->register_host($host, $addr);
        }
    }
}

sub _read_hosts_from_file {
    my ($class, $file) = @_;
    open my $fh, '<', $file or croak $!;
    $class->_read_hosts_from_handle($fh);
    close $fh;
}

sub _read_hosts_from_string {
    my ($class, $string) = @_;
    open my $fh, '<', \$string or croak $!;
    $class->_read_hosts_from_handle($fh);
    close $fh;
}

sub _registered_peer_addr {
    my ($class, $host) = @_;
    return $Hosts{$host};
}

sub _implementor {
    my ($class, $proto) = @_;
    return sprintf 'LWP::Protocol::%s::hosts' => $proto;
}

sub enable_override {
    my $class = shift;

    for my $proto (@Protocols) {
        if (my $orig = LWP::Protocol::implementor($proto)) {
            my $impl = $class->_implementor($proto);
            if (eval "require $impl; 1") {
                LWP::Protocol::implementor($proto => $impl);
                $Implementors{$proto} = $orig;
            }
        }
        else {
            carp("LWP::Protocol::$proto is unavailable. Skip overriding it.");
        }
    }

    if (defined wantarray) {
        return guard { $class->disable_override };
    }
}

sub disable_override {
    my $class = shift;
    for my $proto (@Protocols) {
        if (my $impl = $Implementors{$proto}) {
            LWP::Protocol::implementor($proto, $impl);
        }
    }
}

1;

=encoding utf-8

=for stopwords

=head1 NAME

LWP::UserAgent::DNS::Hosts - Override LWP HTTP/HTTPS request's host like /etc/hosts

=head1 SYNOPSIS

  use LWP::UserAgent;
  use LWP::UserAgent::DNS::Hosts;

  # add entry
  LWP::UserAgent::DNS::Hosts->register_host(
      'www.cpan.org' => '127.0.0.1',
  );

  # add entries
  LWP::UserAgent::DNS::Hosts->register_hosts(
      'search.cpan.org' => '192.168.0.100',
      'pause.perl.org'  => '192.168.0.101',
  );

  # read hosts file
  LWP::UserAgent::DNS::Hosts->read_hosts('/path/to/my/hosts');

  LWP::UserAgent::DNS::Hosts->enable_override;

  # override request hosts with peer addr defined above
  my $ua  = LWP::UserAgent->new;
  my $res = $ua->get("http://www.cpan.org/");
  print $res->content; # is same as "http://127.0.0.1/" content

=head1 DESCRIPTION

LWP::UserAgent::DNS::Hosts is a module to override HTTP/HTTPS request
peer addresses that uses LWP::UserAgent.

This module concept was got from L<LWP::Protocol::PSGI>.

=head1 METHODS

=over 4

=item register_host($host, $peer_addr)

  LWP::UserAgent::DNS::Hosts->register_host($host, $peer_addr);

Registers a pair of hostname and peer ip address.

  # /etc/hosts
  127.0.0.1    example.com

equals to:

  LWP::UserAgent::DNS::Hosts->register_hosts('example.com', '127.0.0.1');

=item register_hosts(%host_addr_pairs)

  LWP::UserAgent::DNS::Hosts->register_hosts(
      'example.com' => '192.168.0.1',
      'example.org' => '192.168.0.2',
      ...
  );

Registers pairs of hostname and peer ip address.

=item read_hosts($file_or_string)

  LWP::UserAgent::DNS::Hosts->read_hosts('hosts.my');

  LWP::UserAgent::DNS::Hosts->read_hosts(<<'__HOST__');
      127.0.0.1      example.com
      192.168.0.1    example.net example.org
  __HOST__

Registers "/etc/hosts" syntax entries.

=item clear_hosts

Clears registered pairs.

=item enable_override

  LWP::UserAgent::DNS::Hosts->enable_override;
  my $guard = LWP::UserAgent::DNS::Hosts->enable_override;

Enables to override hook.

If called in a non-void context, returns a L<Guard> object that
automatically resets the override when it goes out of context.

=item disable_override

  LWP::UserAgent::DNS::Hosts->disable_override;

Disables to override hook.

If you use the guard interface described above,
it will be automatically called for you.

=back

=head1 AUTHOR

NAKAGAWA Masaki E<lt>masaki@cpan.orgE<gt>

=head1 LICENSE

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

=head1 SEE ALSO

L<LWP::Protocol>, L<LWP::Protocol::http>, L<LWP::Protocol::https>

=cut
PK6N%[!��CCperl5/LWP/DebugFile.pmnu��6�$package LWP::DebugFile;

our $VERSION = '6.78';

# legacy stub

1;
PK6N%[m���perl5/LWP/Simple.pmnu��6�$package LWP::Simple;

use strict;

our $VERSION = '6.78';

require Exporter;

our @EXPORT = qw(get head getprint getstore mirror);
our @EXPORT_OK = qw($ua);

# I really hate this.  It was a bad idea to do it in the first place.
# Wonder how to get rid of it???  (It even makes LWP::Simple 7% slower
# for trivial tests)
use HTTP::Status;
push(@EXPORT, @HTTP::Status::EXPORT);

sub import
{
    my $pkg = shift;
    my $callpkg = caller;
    Exporter::export($pkg, $callpkg, @_);
}

use LWP::UserAgent ();
use HTTP::Date ();

our $ua = LWP::UserAgent->new;  # we create a global UserAgent object
$ua->agent("LWP::Simple/$VERSION ");
$ua->env_proxy;

sub get ($)
{
    my $response = $ua->get(shift);
    return $response->decoded_content if $response->is_success;
    return undef;
}


sub head ($)
{
    my($url) = @_;
    my $request = HTTP::Request->new(HEAD => $url);
    my $response = $ua->request($request);

    if ($response->is_success) {
	return $response unless wantarray;
	return (scalar $response->header('Content-Type'),
		scalar $response->header('Content-Length'),
		HTTP::Date::str2time($response->header('Last-Modified')),
		HTTP::Date::str2time($response->header('Expires')),
		scalar $response->header('Server'),
	       );
    }
    return;
}


sub getprint ($)
{
    my($url) = @_;
    my $request = HTTP::Request->new(GET => $url);
    local($\) = ""; # ensure standard $OUTPUT_RECORD_SEPARATOR
    my $callback = sub { print $_[0] };
    if ($^O eq "MacOS") {
	$callback = sub { $_[0] =~ s/\015?\012/\n/g; print $_[0] }
    }
    my $response = $ua->request($request, $callback);
    unless ($response->is_success) {
	print STDERR $response->status_line, " <URL:$url>\n";
    }
    $response->code;
}


sub getstore ($$)
{
    my($url, $file) = @_;
    my $request = HTTP::Request->new(GET => $url);
    my $response = $ua->request($request, $file);

    $response->code;
}


sub mirror ($$)
{
    my($url, $file) = @_;
    my $response = $ua->mirror($url, $file);
    $response->code;
}


1;

__END__

=pod

=head1 NAME

LWP::Simple - simple procedural interface to LWP

=head1 SYNOPSIS

 perl -MLWP::Simple -e 'getprint "http://www.sn.no"'

 use LWP::Simple;
 $content = get("http://www.sn.no/");
 die "Couldn't get it!" unless defined $content;

 if (mirror("http://www.sn.no/", "foo") == RC_NOT_MODIFIED) {
     ...
 }

 if (is_success(getprint("http://www.sn.no/"))) {
     ...
 }

=head1 DESCRIPTION

This module is meant for people who want a simplified view of the
libwww-perl library.  It should also be suitable for one-liners.  If
you need more control or access to the header fields in the requests
sent and responses received, then you should use the full object-oriented
interface provided by the L<LWP::UserAgent> module.

The module will also export the L<LWP::UserAgent> object as C<$ua> if you
ask for it explicitly.

The user agent created by this module will identify itself as
C<LWP::Simple/#.##>
and will initialize its proxy defaults from the environment (by
calling C<< $ua->env_proxy >>).

=head1 FUNCTIONS

The following functions are provided (and exported) by this module:

=head2 get

    my $res = get($url);

The get() function will fetch the document identified by the given URL
and return it.  It returns C<undef> if it fails.  The C<$url> argument can
be either a string or a reference to a L<URI> object.

You will not be able to examine the response code or response headers
(like C<Content-Type>) when you are accessing the web using this
function.  If you need that information you should use the full OO
interface (see L<LWP::UserAgent>).

=head2 head

    my $res = head($url);

Get document headers. Returns the following 5 values if successful:
($content_type, $document_length, $modified_time, $expires, $server)

Returns an empty list if it fails.  In scalar context returns TRUE if
successful.

=head2 getprint

    my $code = getprint($url);

Get and print a document identified by a URL. The document is printed
to the selected default filehandle for output (normally STDOUT) as
data is received from the network.  If the request fails, then the
status code and message are printed on STDERR.  The return value is
the HTTP response code.

=head2 getstore

    my $code = getstore($url, $file)
    my $code = getstore($url, $filehandle)

Gets a document identified by a URL and stores it in the file. The
return value is the HTTP response code.
You may also pass a writeable filehandle or similar,
such as a L<File::Temp> object.

=head2 mirror

    my $code = mirror($url, $file);

Get and store a document identified by a URL, using
I<If-modified-since>, and checking the I<Content-Length>.  Returns
the HTTP response code.

=head1 STATUS CONSTANTS

This module also exports the L<HTTP::Status> constants and procedures.
You can use them when you check the response code from L<LWP::Simple/getprint>,
L<LWP::Simple/getstore> or L<LWP::Simple/mirror>.  The constants are:

   RC_CONTINUE
   RC_SWITCHING_PROTOCOLS
   RC_OK
   RC_CREATED
   RC_ACCEPTED
   RC_NON_AUTHORITATIVE_INFORMATION
   RC_NO_CONTENT
   RC_RESET_CONTENT
   RC_PARTIAL_CONTENT
   RC_MULTIPLE_CHOICES
   RC_MOVED_PERMANENTLY
   RC_MOVED_TEMPORARILY
   RC_SEE_OTHER
   RC_NOT_MODIFIED
   RC_USE_PROXY
   RC_BAD_REQUEST
   RC_UNAUTHORIZED
   RC_PAYMENT_REQUIRED
   RC_FORBIDDEN
   RC_NOT_FOUND
   RC_METHOD_NOT_ALLOWED
   RC_NOT_ACCEPTABLE
   RC_PROXY_AUTHENTICATION_REQUIRED
   RC_REQUEST_TIMEOUT
   RC_CONFLICT
   RC_GONE
   RC_LENGTH_REQUIRED
   RC_PRECONDITION_FAILED
   RC_REQUEST_ENTITY_TOO_LARGE
   RC_REQUEST_URI_TOO_LARGE
   RC_UNSUPPORTED_MEDIA_TYPE
   RC_INTERNAL_SERVER_ERROR
   RC_NOT_IMPLEMENTED
   RC_BAD_GATEWAY
   RC_SERVICE_UNAVAILABLE
   RC_GATEWAY_TIMEOUT
   RC_HTTP_VERSION_NOT_SUPPORTED

=head1 CLASSIFICATION FUNCTIONS

The L<HTTP::Status> classification functions are:

=head2 is_success

    my $bool = is_success($rc);

True if response code indicated a successful request.

=head2 is_error

    my $bool = is_error($rc)

True if response code indicated that an error occurred.

=head1 CAVEAT

Note that if you are using both LWP::Simple and the very popular L<CGI>
module, you may be importing a C<head> function from each module,
producing a warning like C<Prototype mismatch: sub main::head ($) vs none>.
Get around this problem by just not importing LWP::Simple's
C<head> function, like so:

        use LWP::Simple qw(!head);
        use CGI qw(:standard);  # then only CGI.pm defines a head()

Then if you do need LWP::Simple's C<head> function, you can just call
it as C<LWP::Simple::head($url)>.

=head1 SEE ALSO

L<LWP>, L<lwpcook>, L<LWP::UserAgent>, L<HTTP::Status>, L<lwp-request>,
L<lwp-mirror>

=cut
PK6N%[��45$5$perl5/XML/SAX.pmnu��6�$# $Id$

package XML::SAX;

use strict;
use vars qw($VERSION @ISA @EXPORT_OK);

$VERSION = '1.02';

use Exporter ();
@ISA = ('Exporter');

@EXPORT_OK = qw(Namespaces Validation);

use File::Basename qw(dirname);
use File::Spec ();
use Symbol qw(gensym);
use XML::SAX::ParserFactory (); # loaded for simplicity

use constant PARSER_DETAILS => "ParserDetails.ini";

use constant Namespaces => "http://xml.org/sax/features/namespaces";
use constant Validation => "http://xml.org/sax/features/validation";

my $known_parsers = undef;

# load_parsers takes the ParserDetails.ini file out of the same directory
# that XML::SAX is in, and looks at it. Format in POD below

=begin EXAMPLE

[XML::SAX::PurePerl]
http://xml.org/sax/features/namespaces = 1
http://xml.org/sax/features/validation = 0
# a comment

# blank lines ignored

[XML::SAX::AnotherParser]
http://xml.org/sax/features/namespaces = 0
http://xml.org/sax/features/validation = 1

=end EXAMPLE

=cut

sub load_parsers {
    my $class = shift;
    my $dir = shift;
    
    # reset parsers
    $known_parsers = [];
    
    # get directory from wherever XML::SAX is installed
    if (!$dir) {
        $dir = $INC{'XML/SAX.pm'};
        $dir = dirname($dir);
    }
    
    my $fh = gensym();
    if (!open($fh, File::Spec->catfile($dir, "SAX", PARSER_DETAILS))) {
        XML::SAX->do_warn("could not find " . PARSER_DETAILS . " in $dir/SAX\n");
        return $class;
    }

    $known_parsers = $class->_parse_ini_file($fh);

    return $class;
}

sub _parse_ini_file {
    my $class = shift;
    my ($fh) = @_;

    my @config;
    
    my $lineno = 0;
    while (defined(my $line = <$fh>)) {
        $lineno++;
        my $original = $line;
        # strip whitespace
        $line =~ s/\s*$//m;
        $line =~ s/^\s*//m;
        # strip comments
        $line =~ s/[#;].*$//m;
        # ignore blanks
        next if $line =~ /^$/m;
        
        # heading
        if ($line =~ /^\[\s*(.*)\s*\]$/m) {
            push @config, { Name => $1 };
            next;
        }
        
        # instruction
        elsif ($line =~ /^(.*?)\s*?=\s*(.*)$/) {
            unless(@config) {
                push @config, { Name => '' };
            }
            $config[-1]{Features}{$1} = $2;
        }

        # not whitespace, comment, or instruction
        else {
            die "Invalid line in ini: $lineno\n>>> $original\n";
        }
    }

    return \@config;
}

sub parsers {
    my $class = shift;
    if (!$known_parsers) {
        $class->load_parsers();
    }
    return $known_parsers;
}

sub remove_parser {
    my $class = shift;
    my ($parser_module) = @_;

    if (!$known_parsers) {
        $class->load_parsers();
    }
    
    @$known_parsers = grep { $_->{Name} ne $parser_module } @$known_parsers;

    return $class;
}
 
sub add_parser {
    my $class = shift;
    my ($parser_module) = @_;

    if (!$known_parsers) {
        $class->load_parsers();
    }
    
    # first load module, then query features, then push onto known_parsers,
    
    my $parser_file = $parser_module;
    $parser_file =~ s/::/\//g;
    $parser_file .= ".pm";

    require $parser_file;

    my @features = $parser_module->supported_features();
    
    my $new = { Name => $parser_module };
    foreach my $feature (@features) {
        $new->{Features}{$feature} = 1;
    }

    # If exists in list already, move to end.
    my $done = 0;
    my $pos = undef;
    for (my $i = 0; $i < @$known_parsers; $i++) {
        my $p = $known_parsers->[$i];
        if ($p->{Name} eq $parser_module) {
            $pos = $i;
        }
    }
    if (defined $pos) {
        splice(@$known_parsers, $pos, 1);
        push @$known_parsers, $new;
        $done++;
    }

    # Otherwise (not in list), add at end of list.
    if (!$done) {
        push @$known_parsers, $new;
    }
    
    return $class;
}

sub save_parsers {
    my $class = shift;
    
    # get directory from wherever XML::SAX is installed
    my $dir = $INC{'XML/SAX.pm'};
    $dir = dirname($dir);
    
    my $file = File::Spec->catfile($dir, "SAX", PARSER_DETAILS);
    chmod 0644, $file;
    unlink($file);
    
    my $fh = gensym();
    open($fh, ">$file") ||
        die "Cannot write to $file: $!";

    foreach my $p (@$known_parsers) {
        print $fh "[$p->{Name}]\n";
        foreach my $key (keys %{$p->{Features}}) {
            print $fh "$key = $p->{Features}{$key}\n";
        }
        print $fh "\n";
    }

    print $fh "\n";

    close $fh;

    return $class;
}

sub do_warn {
    my $class = shift;
    # Don't output warnings if running under Test::Harness
    warn(@_) unless $ENV{HARNESS_ACTIVE};
}

1;
__END__

=head1 NAME

XML::SAX - Simple API for XML

=head1 SYNOPSIS

  use XML::SAX;
  
  # get a list of known parsers
  my $parsers = XML::SAX->parsers();
  
  # add/update a parser
  XML::SAX->add_parser(q(XML::SAX::PurePerl));

  # remove parser
  XML::SAX->remove_parser(q(XML::SAX::Foodelberry));

  # save parsers
  XML::SAX->save_parsers();

=head1 DESCRIPTION

XML::SAX is a SAX parser access API for Perl. It includes classes
and APIs required for implementing SAX drivers, along with a factory
class for returning any SAX parser installed on the user's system.

=head1 USING A SAX2 PARSER

The factory class is XML::SAX::ParserFactory. Please see the
documentation of that module for how to instantiate a SAX parser:
L<XML::SAX::ParserFactory>. However if you don't want to load up
another manual page, here's a short synopsis:

  use XML::SAX::ParserFactory;
  use XML::SAX::XYZHandler;
  my $handler = XML::SAX::XYZHandler->new();
  my $p = XML::SAX::ParserFactory->parser(Handler => $handler);
  $p->parse_uri("foo.xml");
  # or $p->parse_string("<foo/>") or $p->parse_file($fh);

This will automatically load a SAX2 parser (defaulting to
XML::SAX::PurePerl if no others are found) and return it to you.

In order to learn how to use SAX to parse XML, you will need to read
L<XML::SAX::Intro> and for reference, L<XML::SAX::Specification>.

=head1 WRITING A SAX2 PARSER

The first thing to remember in writing a SAX2 parser is to subclass
XML::SAX::Base. This will make your life infinitely easier, by providing
a number of methods automagically for you. See L<XML::SAX::Base> for more
details.

When writing a SAX2 parser that is compatible with XML::SAX, you need
to inform XML::SAX of the presence of that driver when you install it.
In order to do that, XML::SAX contains methods for saving the fact that
the parser exists on your system to a "INI" file, which is then loaded
to determine which parsers are installed.

The best way to do this is to follow these rules:

=over 4

=item * Add XML::SAX as a prerequisite in Makefile.PL:

  WriteMakefile(
      ...
      PREREQ_PM => { 'XML::SAX' => 0 },
      ...
  );

Alternatively you may wish to check for it in other ways that will
cause more than just a warning.

=item * Add the following code snippet to your Makefile.PL:

  sub MY::install {
    package MY;
    my $script = shift->SUPER::install(@_);
    if (ExtUtils::MakeMaker::prompt(
      "Do you want to modify ParserDetails.ini?", 'Y')
      =~ /^y/i) {
      $script =~ s/install :: (.*)$/install :: $1 install_sax_driver/m;
      $script .= <<"INSTALL";
  
  install_sax_driver :
  \t\@\$(PERL) -MXML::SAX -e "XML::SAX->add_parser(q(\$(NAME)))->save_parsers()"
  
  INSTALL
    }
    return $script;
  }

Note that you should check the output of this - \$(NAME) will use the name of
your distribution, which may not be exactly what you want. For example XML::LibXML
has a driver called XML::LibXML::SAX::Generator, which is used in place of
\$(NAME) in the above.

=item * Add an XML::SAX test:

A test file should be added to your t/ directory containing something like the
following:

  use Test;
  BEGIN { plan tests => 3 }
  use XML::SAX;
  use XML::SAX::PurePerl::DebugHandler;
  XML::SAX->add_parser(q(XML::SAX::MyDriver));
  local $XML::SAX::ParserPackage = 'XML::SAX::MyDriver';
  eval {
    my $handler = XML::SAX::PurePerl::DebugHandler->new();
    ok($handler);
    my $parser = XML::SAX::ParserFactory->parser(Handler => $handler);
    ok($parser);
    ok($parser->isa('XML::SAX::MyDriver');
    $parser->parse_string("<tag/>");
    ok($handler->{seen}{start_element});
  };

=back

=head1 EXPORTS

By default, XML::SAX exports nothing into the caller's namespace. However you
can request the symbols C<Namespaces> and C<Validation> which are the
URIs for those features, allowing an easier way to request those features
via ParserFactory:

  use XML::SAX qw(Namespaces Validation);
  my $factory = XML::SAX::ParserFactory->new();
  $factory->require_feature(Namespaces);
  $factory->require_feature(Validation);
  my $parser = $factory->parser();

=head1 AUTHOR

Current maintainer: Grant McLean, grantm@cpan.org

Originally written by:

Matt Sergeant, matt@sergeant.org

Kip Hampton, khampton@totalcinema.com

Robin Berjon, robin@knowscape.com

=head1 LICENSE

This is free software, you may use it and distribute it under
the same terms as Perl itself.

=head1 SEE ALSO

L<XML::SAX::Base> for writing SAX Filters and Parsers

L<XML::SAX::PurePerl> for an XML parser written in 100%
pure perl.

L<XML::SAX::Exception> for details on exception handling

=cut

PK6N%[ʛ��Q�Qperl5/XML/Simple/FAQ.podnu��6�$
=head1 NAME

XML::Simple::FAQ - Frequently Asked Questions about XML::Simple

=head1 Basics


=head2 What should I use XML::Simple for?

Nothing!

It's as simple as that.

Choose a better module. See
L<Perl XML::LibXML by Example|http://grantm.github.io/perl-libxml-by-example/>
for a gentle introduction to L<XML::LibXML> with lots of examples.


=head2 What was XML::Simple designed to be used for?

XML::Simple is a Perl module that was originally developed as a tool for
reading and writing configuration data in XML format.  You could use it for
other purposes that involve storing and retrieving structured data in
XML but it's likely to be a frustrating experience.


=head2 Why store configuration data in XML anyway?

It seemed like a good idea at the time.  Now, I use and recommend
L<Config::General> which uses a format similar to that used by the Apache web
server.  This is easier to read than XML while still allowing advanced concepts
such as nested sections.

At the time XML::Simple was written, the advantages of using XML format for
configuration data were thought to include:

=over 4

=item *

Using existing XML parsing tools requires less development time, is easier
and more robust than developing your own config file parsing code

=item *

XML can represent relationships between pieces of data, such as nesting of
sections to arbitrary levels (not easily done with .INI files for example)

=item *

XML is basically just text, so you can easily edit a config file (easier than
editing a Win32 registry)

=item *

XML provides standard solutions for handling character sets and encoding
beyond basic ASCII (important for internationalization)

=item *

If it becomes necessary to change your configuration file format, there are
many tools available for performing transformations on XML files

=item *

XML is an open standard (the world does not need more proprietary binary
file formats)

=item *

Taking the extra step of developing a DTD allows the format of configuration
files to be validated before your program reads them (not directly supported
by XML::Simple)

=item *

Combining a DTD with a good XML editor can give you a GUI config editor for
minimal coding effort

=back


=head2 What isn't XML::Simple good for?

The main limitation of XML::Simple is that it does not work with 'mixed
content' (see the next question).  If you consider your XML files contain
marked up text rather than structured data, you should probably use another
module.

If your source XML documents change regularly, it's likely that you will
experience intermittent failures.  In particular, failure to properly use the
ForceArray and KeyAttr options will produce code that works when you get a list
of elements with the same name, but fails when there's only one item in the
list.  These types of problems can be avoided by not using XML::Simple in the
first place.

If you are working with very large XML files, XML::Simple's approach of
representing the whole file in memory as a 'tree' data structure may not be
suitable.


=head2 What is mixed content?

Consider this example XML:

  <document>
    <para>This is <em>mixed</em> content.</para>
  </document>

This is said to be mixed content, because the E<lt>paraE<gt> element contains
both character data (text content) and nested elements.

Here's some more XML:

  <person>
    <first_name>Joe</first_name>
    <last_name>Bloggs</last_name>
    <dob>25-April-1969</dob>
  </person>

This second example is not generally considered to be mixed content.  The
E<lt>first_nameE<gt>, E<lt>last_nameE<gt> and E<lt>dobE<gt> elements contain
only character data and the  E<lt>personE<gt> element contains only nested
elements.  (Note: Strictly speaking, the whitespace between the nested
elements is character data, but it is ignored by XML::Simple).


=head2 Why doesn't XML::Simple handle mixed content?

Because if it did, it would no longer be simple :-)

Seriously though, there are plenty of excellent modules that allow you to
work with mixed content in a variety of ways.  Handling mixed content
correctly is not easy and by ignoring these issues, XML::Simple is able to
present an API without a steep learning curve.


=head2 Which Perl modules do handle mixed content?

Every one of them except XML::Simple :-)

If you're looking for a recommendation, I'd suggest you look at the Perl-XML
FAQ at:

  http://perl-xml.sourceforge.net/faq/


=head1 Installation


=head2 How do I install XML::Simple?

If you're running ActiveState Perl, or
L<Strawberry Perl|http://strawberryperl.com/> you've probably already got
XML::Simple and therefore do not need to install it at all.  But you probably
also have L<XML::LibXML>, which is a much better module, so just use that.

If you do need to install XML::Simple, you'll need to install an XML parser
module first.  Install either XML::Parser (which you may have already) or
XML::SAX.  If you install both, XML::SAX will be used by default.

Once you have a parser installed ...

On Unix systems, try:

  perl -MCPAN -e 'install XML::Simple'

If that doesn't work, download the latest distribution from
ftp://ftp.cpan.org/pub/CPAN/authors/id/G/GR/GRANTM , unpack it and run these
commands:

  perl Makefile.PL
  make
  make test
  make install

On Win32, if you have a recent build of ActiveState Perl (618 or better) try
this command:

  ppm install XML::Simple

If that doesn't work, you really only need the Simple.pm file, so extract it
from the .tar.gz file (eg: using WinZIP) and save it in the \site\lib\XML
directory under your Perl installation (typically C:\Perl).


=head2 I'm trying to install XML::Simple and 'make test' fails

Is the directory where you've unpacked XML::Simple mounted from a file server
using NFS, SMB or some other network file sharing?  If so, that may cause
errors in the following test scripts:

  3_Storable.t
  4_MemShare.t
  5_MemCopy.t

The test suite is designed to exercise the boundary conditions of all
XML::Simple's functionality and these three scripts exercise the caching
functions.  If XML::Simple is asked to parse a file for which it has a cached
copy of a previous parse, then it compares the timestamp on the XML file with
the timestamp on the cached copy.  If the cached copy is *newer* then it will
be used.  If the cached copy is older or the same age then the file is
re-parsed.  The test scripts will get confused by networked filesystems if
the workstation and server system clocks are not synchronised (to the
second).

If you get an error in one of these three test scripts but you don't plan to
use the caching options (they're not enabled by default), then go right ahead
and run 'make install'.  If you do plan to use caching, then try unpacking
the distribution on local disk and doing the build/test there.

It's probably not a good idea to use the caching options with networked
filesystems in production.  If the file server's clock is ahead of the local
clock, XML::Simple will re-parse files when it could have used the cached
copy.  However if the local clock is ahead of the file server clock and a
file is changed immediately after it is cached, the old cached copy will be
used.

Is one of the three test scripts (above) failing but you're not running on
a network filesystem?  Are you running Win32?  If so, you may be seeing a bug
in Win32 where writes to a file do not affect its modification timestamp.

If none of these scenarios match your situation, please confirm you're
running the latest version of XML::Simple and then email the output of
'make test' to me at grantm@cpan.org

=head2 Why is XML::Simple so slow?

If you find that XML::Simple is very slow reading XML, the most likely reason
is that you have XML::SAX installed but no additional SAX parser module.  The
XML::SAX distribution includes an XML parser written entirely in Perl.  This is
very portable but not very fast.  For better performance install either
XML::SAX::Expat or XML::LibXML.


=head1 Usage

=head2 How do I use XML::Simple?

If you don't know how to use XML::Simple then the best approach is to
L<learn to use XML::LibXML|http://grantm.github.io/perl-libxml-by-example/>
instead.  Stop reading this document and use that one instead.

If you are determined to use XML::Simple, it come with copious documentation,
so L<read that|XML::Simple>.


=head2 There are so many options, which ones do I really need to know about?

Although you can get by without using any options, you shouldn't even
consider using XML::Simple in production until you know what these two
options do:

=over 4

=item *

forcearray

=item *

keyattr

=back

The reason you really need to read about them is because the default values
for these options will trip you up if you don't.  Although everyone agrees
that these defaults are not ideal, there is not wide agreement on what they
should be changed to.  The answer therefore is to read about them (see below)
and select values which are right for you.


=head2 What is the forcearray option all about?

Consider this XML in a file called ./person.xml:

  <person>
    <first_name>Joe</first_name>
    <last_name>Bloggs</last_name>
    <hobbie>bungy jumping</hobbie>
    <hobbie>sky diving</hobbie>
    <hobbie>knitting</hobbie>
  </person>

You could read it in with this line:

  my $person = XMLin('./person.xml');

Which would give you a data structure like this:

  $person = {
    'first_name' => 'Joe',
    'last_name'  => 'Bloggs',
    'hobbie'     => [ 'bungy jumping', 'sky diving', 'knitting' ]
  };

The E<lt>first_nameE<gt> and E<lt>last_nameE<gt> elements are represented as
simple scalar values which you could refer to like this:

  print "$person->{first_name} $person->{last_name}\n";

The E<lt>hobbieE<gt> elements are represented as an array - since there is
more than one.  You could refer to the first one like this:

  print $person->{hobbie}->[0], "\n";

Or the whole lot like this:

  print join(', ', @{$person->{hobbie}} ), "\n";

The catch is, that these last two lines of code will only work for people
who have more than one hobbie.  If there is only one E<lt>hobbieE<gt>
element, it will be represented as a simple scalar (just like
E<lt>first_nameE<gt> and E<lt>last_nameE<gt>).  Which might lead you to write
code like this:

  if(ref($person->{hobbie})) {
    print join(', ', @{$person->{hobbie}} ), "\n";
  }
  else {
    print $person->{hobbie}, "\n";
  }

Don't do that.

One alternative approach is to set the forcearray option to a true value:

  my $person = XMLin('./person.xml', forcearray => 1);

Which will give you a data structure like this:

  $person = {
    'first_name' => [ 'Joe' ],
    'last_name'  => [ 'Bloggs' ],
    'hobbie'     => [ 'bungy jumping', 'sky diving', 'knitting' ]
  };

Then you can use this line to refer to all the list of hobbies even if there
was only one:

  print join(', ', @{$person->{hobbie}} ), "\n";

The downside of this approach is that the E<lt>first_nameE<gt> and
E<lt>last_nameE<gt> elements will also always be represented as arrays even
though there will never be more than one:

  print "$person->{first_name}->[0] $person->{last_name}->[0]\n";

This might be OK if you change the XML to use attributes for things that
will always be singular and nested elements for things that may be plural:

  <person first_name="Jane" last_name="Bloggs">
    <hobbie>motorcycle maintenance</hobbie>
  </person>

On the other hand, if you prefer not to use attributes, then you could
specify that any E<lt>hobbieE<gt> elements should always be represented as
arrays and all other nested elements should be simple scalar values unless
there is more than one:

  my $person = XMLin('./person.xml', forcearray => [ 'hobbie' ]);

The forcearray option accepts a list of element names which should always
be forced to an array representation:

  forcearray => [ qw(hobbie qualification childs_name) ]

See the XML::Simple manual page for more information.


=head2 What is the keyattr option all about?

Consider this sample XML:

  <catalog>
    <part partnum="1842334" desc="High pressure flange" price="24.50" />
    <part partnum="9344675" desc="Threaded gasket"      price="9.25" />
    <part partnum="5634896" desc="Low voltage washer"   price="12.00" />
  </catalog>

You could slurp it in with this code:

  my $catalog = XMLin('./catalog.xml');

Which would return a data structure like this:

  $catalog = {
      'part' => [
          {
            'partnum' => '1842334',
            'desc'    => 'High pressure flange',
            'price'   => '24.50'
          },
          {
            'partnum' => '9344675',
            'desc'    => 'Threaded gasket',
            'price'   => '9.25'
          },
          {
            'partnum' => '5634896',
            'desc'    => 'Low voltage washer',
            'price'   => '12.00'
          }
      ]
  };

Then you could access the description of the first part in the catalog
with this code:

  print $catalog->{part}->[0]->{desc}, "\n";

However, if you wanted to access the description of the part with the
part number of "9344675" then you'd have to code a loop like this:

  foreach my $part (@{$catalog->{part}}) {
    if($part->{partnum} eq '9344675') {
      print $part->{desc}, "\n";
      last;
    }
  }

The knowledge that each E<lt>partE<gt> element has a unique partnum attribute
allows you to eliminate this search.  You can pass this knowledge on to
XML::Simple like this:

  my $catalog = XMLin($xml, keyattr => ['partnum']);

Which will return a data structure like this:

  $catalog = {
    'part' => {
      '5634896' => { 'desc' => 'Low voltage washer',   'price' => '12.00' },
      '1842334' => { 'desc' => 'High pressure flange', 'price' => '24.50' },
      '9344675' => { 'desc' => 'Threaded gasket',      'price' => '9.25'  }
    }
  };

XML::Simple has been able to transform $catalog->{part} from an arrayref to
a hashref (keyed on partnum).  This transformation is called 'array folding'.

Through the use of array folding, you can now index directly to the
description of the part you want:

  print $catalog->{part}->{9344675}->{desc}, "\n";

The 'keyattr' option also enables array folding when the unique key is in a
nested element rather than an attribute.  eg:

  <catalog>
    <part>
      <partnum>1842334</partnum>
      <desc>High pressure flange</desc>
      <price>24.50</price>
    </part>
    <part>
      <partnum>9344675</partnum>
      <desc>Threaded gasket</desc>
      <price>9.25</price>
    </part>
    <part>
      <partnum>5634896</partnum>
      <desc>Low voltage washer</desc>
      <price>12.00</price>
    </part>
  </catalog>

See the XML::Simple manual page for more information.


=head2 So what's the catch with 'keyattr'?

One thing to watch out for is that you might get array folding even if you
don't supply the keyattr option.  The default value for this option is:

  [ 'name', 'key', 'id']

Which means if your XML elements have a 'name', 'key' or 'id' attribute (or
nested element) then they may get folded on those values.  This means that
you can take advantage of array folding simply through careful choice of
attribute names.  On the hand, if you really don't want array folding at all,
you'll need to set 'key attr to an empty list:

  my $ref = XMLin($xml, keyattr => []);

A second 'gotcha' is that array folding only works on arrays.  That might
seem obvious, but if there's only one record in your XML and you didn't set
the 'forcearray' option then it won't be represented as an array and
consequently won't get folded into a hash.  The moral is that if you're
using array folding, you should always turn on the forcearray option.

You probably want to be as specific as you can be too.  For instance, the
safest way to parse the E<lt>catalogE<gt> example above would be:

  my $catalog = XMLin($xml, keyattr => { part => 'partnum'},
                            forcearray => ['part']);

By using the hashref for keyattr, you can specify that only E<lt>partE<gt>
elements should be folded on the 'partnum' attribute (and that the
E<lt>partE<gt> elements should not be folded on any other attribute).

By supplying a list of element names for forcearray, you're ensuring that
folding will work even if there's only one E<lt>partE<gt>.  You're also
ensuring that if the 'partnum' unique key is supplied in a nested element
then that element won't get forced to an array too.


=head2 How do I know what my data structure should look like?

The rules are fairly straightforward:

=over 4

=item *

each element gets represented as a hash

=item *

unless it contains only text, in which case it'll be a simple scalar value

=item *

or unless there's more than one element with the same name, in which case
they'll be represented as an array

=item *

unless you've got array folding enabled, in which case they'll be folded into
a hash

=item *

empty elements (no text contents B<and> no attributes) will either be
represented as an empty hash, an empty string or undef - depending on the value
of the 'suppressempty' option.

=back

If you're in any doubt, use Data::Dumper, eg:

  use XML::Simple;
  use Data::Dumper;

  my $ref = XMLin($xml);

  print Dumper($ref);


=head2 I'm getting 'Use of uninitialized value' warnings

You're probably trying to index into a non-existant hash key - try
Data::Dumper.


=head2 I'm getting a 'Not an ARRAY reference' error

Something that you expect to be an array is not.  The two most likely causes
are that you forgot to use 'forcearray' or that the array got folded into a
hash - try Data::Dumper.


=head2 I'm getting a 'No such array field' error

Something that you expect to be a hash is actually an array.  Perhaps array
folding failed because one element was missing the key attribute - try
Data::Dumper.


=head2 I'm getting an 'Out of memory' error

Something in the data structure is not as you expect and Perl may be trying
unsuccessfully to autovivify things - try Data::Dumper.

If you're already using Data::Dumper, try calling Dumper() immediately after
XMLin() - ie: before you attempt to access anything in the data structure.


=head2 My element order is getting jumbled up

If you read an XML file with XMLin() and then write it back out with
XMLout(), the order of the elements will likely be different.  (However, if
you read the file back in with XMLin() you'll get the same Perl data
structure).

The reordering happens because XML::Simple uses hashrefs to store your data
and Perl hashes do not really have any order.

It is possible that a future version of XML::Simple will use Tie::IxHash
to store the data in hashrefs which do retain the order.  However this will
not fix all cases of element order being lost.

If your application really is sensitive to element order, don't use
XML::Simple (and don't put order-sensitive values in attributes).


=head2 XML::Simple turns nested elements into attributes

If you read an XML file with XMLin() and then write it back out with
XMLout(), some data which was originally stored in nested elements may end up
in attributes.  (However, if you read the file back in with XMLin() you'll
get the same Perl data structure).

There are a number of ways you might handle this:

=over 4

=item *

use the 'forcearray' option with XMLin()

=item *

use the 'noattr' option with XMLout()

=item *

live with it

=item *

don't use XML::Simple

=back


=head2 Why does XMLout() insert E<lt>nameE<gt> elements (or attributes)?

Try setting keyattr => [].

When you call XMLin() to read XML, the 'keyattr' option controls whether arrays
get 'folded' into hashes.  Similarly, when you call XMLout(), the 'keyattr'
option controls whether hashes get 'unfolded' into arrays.  As described above,
'keyattr' is enabled by default.

=head2 Why are empty elements represented as empty hashes?

An element is always represented as a hash unless it contains only text, in
which case it is represented as a scalar string.

If you would prefer empty elements to be represented as empty strings or the
undefined value, set the 'suppressempty' option to '' or undef respectively.

=head2 Why is ParserOpts deprecated?

The C<ParserOpts> option is a remnant of the time when XML::Simple only worked
with the XML::Parser API.  Its value is completely ignored if you're using a
SAX parser, so writing code which relied on it would bar you from taking
advantage of SAX.

Even if you are using XML::Parser, it is seldom necessary to pass options to
the parser object.  A number of people have written to say they use this option
to set XML::Parser's C<ProtocolEncoding> option.  Don't do that, it's wrong,
Wrong, WRONG!  Fix the XML document so that it's well-formed and you won't have
a problem.

Having said all of that, as long as XML::Simple continues to support the
XML::Parser API, this option will not be removed.  There are currently no plans
to remove support for the XML::Parser API.

=cut


PK6N%[W||perl5/XML/SAX/ParserDetails.ininu�[���[XML::SAX::PurePerl]
http://xml.org/sax/features/namespaces = 1

[XML::SAX::Expat]
http://xml.org/sax/features/namespaces = 1
http://xml.org/sax/features/external-general-entities = 1
http://xml.org/sax/features/external-parameter-entities = 1

[XML::LibXML::SAX::Parser]
http://xml.org/sax/features/namespaces = 1

[XML::LibXML::SAX]
http://xml.org/sax/features/namespaces = 1


PK6N%[����L�Lperl5/XML/SAX/Expat.pmnu�7��m
###
# XML::SAX::Expat - SAX2 Driver for Expat (XML::Parser)
# Originally by Robin Berjon
###

package XML::SAX::Expat;
use strict;
use base qw(XML::SAX::Base);
use XML::NamespaceSupport   qw();
use XML::Parser             qw();

use vars qw($VERSION);
$VERSION = '0.51';


#,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,#
#`,`, Variations on parse `,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,#
#```````````````````````````````````````````````````````````````````#

#-------------------------------------------------------------------#
# CharacterStream
#-------------------------------------------------------------------#
sub _parse_characterstream {
    my $p       = shift;
    my $xml     = shift;
    my $opt     = shift;

    my $expat = $p->_create_parser($opt);
    my $result = $expat->parse($xml);
    $p->_cleanup;
    return $result;
}
#-------------------------------------------------------------------#

#-------------------------------------------------------------------#
# ByteStream
#-------------------------------------------------------------------#
sub _parse_bytestream {
    my $p       = shift;
    my $xml     = shift;
    my $opt     = shift;

    my $expat = $p->_create_parser($opt);
    my $result = $expat->parse($xml);
    $p->_cleanup;
    return $result;
}
#-------------------------------------------------------------------#

#-------------------------------------------------------------------#
# String
#-------------------------------------------------------------------#
sub _parse_string {
    my $p       = shift;
    my $xml     = shift;
    my $opt     = shift;

    my $expat = $p->_create_parser($opt);
    my $result = $expat->parse($xml);
    $p->_cleanup;
    return $result;
}
#-------------------------------------------------------------------#

#-------------------------------------------------------------------#
# SystemId
#-------------------------------------------------------------------#
sub _parse_systemid {
    my $p       = shift;
    my $xml     = shift;
    my $opt     = shift;

    my $expat = $p->_create_parser($opt);
    my $result = $expat->parsefile($xml);
    $p->_cleanup;
    return $result;
}
#-------------------------------------------------------------------#


#-------------------------------------------------------------------#
# $p->_create_parser(\%options)
#-------------------------------------------------------------------#
sub _create_parser {
    my $self = shift;
    my $opt  = shift;

    die "ParserReference: parser instance ($self) already parsing\n"
         if $self->{_InParse};

    my $featUri = 'http://xml.org/sax/features/';
    my $ppe = ($self->get_feature($featUri . 'external-general-entities') or
               $self->get_feature($featUri . 'external-parameter-entities') ) ? 1 : 0;

    my $expat = XML::Parser->new( ParseParamEnt => $ppe );
    $expat->{__XSE} = $self;
    $expat->setHandlers(
                        Init        => \&_handle_init,
                        Final       => \&_handle_final,
                        Start       => \&_handle_start,
                        End         => \&_handle_end,
                        Char        => \&_handle_char,
                        Comment     => \&_handle_comment,
                        Proc        => \&_handle_proc,
                        CdataStart  => \&_handle_start_cdata,
                        CdataEnd    => \&_handle_end_cdata,
                        Unparsed    => \&_handle_unparsed_entity,
                        Notation    => \&_handle_notation_decl,
                        #ExternEnt
                        #ExternEntFin
                        Entity      => \&_handle_entity_decl,
                        Element     => \&_handle_element_decl,
                        Attlist     => \&_handle_attr_decl,
                        Doctype     => \&_handle_start_doctype,
                        DoctypeFin  => \&_handle_end_doctype,
                        XMLDecl     => \&_handle_xml_decl,
                      );

    $self->{_InParse} = 1;
    $self->{_NodeStack} = [];
    $self->{_NSStack} = [];
    $self->{_NSHelper} = XML::NamespaceSupport->new({xmlns => 1});
    $self->{_started} = 0;

    return $expat;
}
#-------------------------------------------------------------------#


#-------------------------------------------------------------------#
# $p->_cleanup
#-------------------------------------------------------------------#
sub _cleanup {
    my $self = shift;

    $self->{_InParse} = 0;
    delete $self->{_NodeStack};
}
#-------------------------------------------------------------------#



#,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,#
#`,`, Expat Handlers ,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,#
#```````````````````````````````````````````````````````````````````#

#-------------------------------------------------------------------#
# _handle_init
#-------------------------------------------------------------------#
sub _handle_init {
    #my $self    = shift()->{__XSE};

    #my $document = {};
    #push @{$self->{_NodeStack}}, $document;
    #$self->SUPER::start_document($document);
}
#-------------------------------------------------------------------#

#-------------------------------------------------------------------#
# _handle_final
#-------------------------------------------------------------------#
sub _handle_final {
    my $self    = shift()->{__XSE};

    #my $document = pop @{$self->{_NodeStack}};
    return $self->SUPER::end_document({});
}
#-------------------------------------------------------------------#

#-------------------------------------------------------------------#
# _handle_start
#-------------------------------------------------------------------#
sub _handle_start {
    my $self    = shift()->{__XSE};
    my $e_name  = shift;
    my %attr    = @_;

    # start_document data
    $self->_handle_start_document({}) unless $self->{_started};

    # take care of namespaces
    my $nsh = $self->{_NSHelper};
    $nsh->push_context;
    my @new_ns;
    for my $k (grep !index($_, 'xmlns'), keys %attr) {
        $k =~ m/^xmlns(:(.*))?$/;
        my $prefix = $2 || '';
        $nsh->declare_prefix($prefix, $attr{$k});
        my $ns = {
                    Prefix       => $prefix,
                    NamespaceURI => $attr{$k},
                 };
        push @new_ns, $ns;
        $self->SUPER::start_prefix_mapping($ns);
    }
    push @{$self->{_NSStack}}, \@new_ns;


    # create the attributes
    my %saxattr;
    map {
        my ($ns,$prefix,$lname) = $nsh->process_attribute_name($_);
        $saxattr{'{' . ($ns || '') . '}' . $lname} = {
                                    Name         => $_,
                                    LocalName    => $lname || '',
                                    Prefix       => $prefix || '',
                                    Value        => $attr{$_},
                                    NamespaceURI => $ns || '',
                                 };
    } keys %attr;


    # now the element
    my ($ns,$prefix,$lname) = $nsh->process_element_name($e_name);
    my $element = {
                    Name         => $e_name,
                    LocalName    => $lname || '',
                    Prefix       => $prefix || '',
                    NamespaceURI => $ns || '',
                    Attributes   => \%saxattr,
                   };

    push @{$self->{_NodeStack}}, $element;
    $self->SUPER::start_element($element);
}
#-------------------------------------------------------------------#

#-------------------------------------------------------------------#
# _handle_end
#-------------------------------------------------------------------#
sub _handle_end {
    my $self    = shift()->{__XSE};

    my %element = %{pop @{$self->{_NodeStack}}};
    delete $element{Attributes};
    $self->SUPER::end_element(\%element);

    my $prev_ns = pop @{$self->{_NSStack}};
    for my $ns (@$prev_ns) {
        $self->SUPER::end_prefix_mapping( { %$ns } );
    }
    $self->{_NSHelper}->pop_context;
}
#-------------------------------------------------------------------#

#-------------------------------------------------------------------#
# _handle_char
#-------------------------------------------------------------------#
sub _handle_char {
    $_[0]->{__XSE}->_handle_start_document({}) unless $_[0]->{__XSE}->{_started};
    $_[0]->{__XSE}->SUPER::characters({ Data => $_[1] });
}
#-------------------------------------------------------------------#

#-------------------------------------------------------------------#
# _handle_comment
#-------------------------------------------------------------------#
sub _handle_comment {
    $_[0]->{__XSE}->_handle_start_document({}) unless $_[0]->{__XSE}->{_started};
    $_[0]->{__XSE}->SUPER::comment({ Data => $_[1] });
}
#-------------------------------------------------------------------#

#-------------------------------------------------------------------#
# _handle_proc
#-------------------------------------------------------------------#
sub _handle_proc {
    $_[0]->{__XSE}->_handle_start_document({}) unless $_[0]->{__XSE}->{_started};
    $_[0]->{__XSE}->SUPER::processing_instruction({ Target => $_[1], Data => $_[2] });
}
#-------------------------------------------------------------------#

#-------------------------------------------------------------------#
# _handle_start_cdata
#-------------------------------------------------------------------#
sub _handle_start_cdata {
    $_[0]->{__XSE}->SUPER::start_cdata( {} );
}
#-------------------------------------------------------------------#

#-------------------------------------------------------------------#
# _handle_end_cdata
#-------------------------------------------------------------------#
sub _handle_end_cdata {
    $_[0]->{__XSE}->SUPER::end_cdata( {} );
}
#-------------------------------------------------------------------#

#-------------------------------------------------------------------#
# _handle_xml_decl
#-------------------------------------------------------------------#
sub _handle_xml_decl {
    my $self    = shift()->{__XSE};
    my $version     = shift;
    my $encoding    = shift;
    my $standalone  = shift;

    if (not defined $standalone) { $standalone = '';    }
    elsif ($standalone)          { $standalone = 'yes'; }
    else                         { $standalone = 'no';  }
    my $xd = {
                Version     => $version,
                Encoding    => $encoding,
                Standalone  => $standalone,
             };
    #$self->SUPER::xml_decl($xd);
    $self->_handle_start_document($xd);
}
#-------------------------------------------------------------------#

#-------------------------------------------------------------------#
# _handle_notation_decl
#-------------------------------------------------------------------#
sub _handle_notation_decl {
    my $self    = shift()->{__XSE};
    my $notation    = shift;
    shift;
    my $system      = shift;
    my $public      = shift;

    my $not = {
                Name        => $notation,
                PublicId    => $public,
                SystemId    => $system,
              };
    $self->SUPER::notation_decl($not);
}
#-------------------------------------------------------------------#

#-------------------------------------------------------------------#
# _handle_unparsed_entity
#-------------------------------------------------------------------#
sub _handle_unparsed_entity {
    my $self    = shift()->{__XSE};
    my $name        = shift;
    my $system      = shift;
    my $public      = shift;
    my $notation    = shift;

    my $ue = {
                Name        => $name,
                PublicId    => $public,
                SystemId    => $system,
                Notation    => $notation,
             };
    $self->SUPER::unparsed_entity_decl($ue);
}
#-------------------------------------------------------------------#

#-------------------------------------------------------------------#
# _handle_element_decl
#-------------------------------------------------------------------#
sub _handle_element_decl {
    $_[0]->{__XSE}->SUPER::element_decl({ Name => $_[1], Model => "$_[2]" });
}
#-------------------------------------------------------------------#


#-------------------------------------------------------------------#
# _handle_attr_decl
#-------------------------------------------------------------------#
sub _handle_attr_decl {
    my $self    = shift()->{__XSE};
    my $ename   = shift;
    my $aname   = shift;
    my $type    = shift;
    my $default = shift;
    my $fixed   = shift;

    my ($vd, $value);
    if ($fixed) {
        $vd = '#FIXED';
        $default =~ s/^(?:"|')//; #"
        $default =~ s/(?:"|')$//; #"
        $value = $default;
    }
    else {
        if ($default =~ m/^#/) {
            $vd = $default;
            $value = '';
        }
        else {
            $vd = ''; # maybe there's a default ?
            $default =~ s/^(?:"|')//; #"
            $default =~ s/(?:"|')$//; #"
            $value = $default;
        }
    }

    my $at = {
                eName           => $ename,
                aName           => $aname,
                Type            => $type,
                ValueDefault    => $vd,
                Value           => $value,
             };
    $self->SUPER::attribute_decl($at);
}
#-------------------------------------------------------------------#

#-------------------------------------------------------------------#
# _handle_entity_decl
#-------------------------------------------------------------------#
sub _handle_entity_decl {
    my $self    = shift()->{__XSE};
    my $name    = shift;
    my $val     = shift;
    my $sys     = shift;
    my $pub     = shift;
    my $ndata   = shift;
    my $isprm   = shift;

    # deal with param ents
    if ($isprm) {
        $name = '%' . $name;
    }

    # int vs ext
    if ($val) {
        my $ent = {
                    Name    => $name,
                    Value   => $val,
                  };
        $self->SUPER::internal_entity_decl($ent);
    }
    else {
        my $ent = {
                    Name        => $name,
                    PublicId    => $pub || '',
                    SystemId    => $sys,
                  };
        $self->SUPER::external_entity_decl($ent);
    }
}
#-------------------------------------------------------------------#


#-------------------------------------------------------------------#
# _handle_start_doctype
#-------------------------------------------------------------------#
sub _handle_start_doctype {
    my $self    = shift()->{__XSE};
    my $name    = shift;
    my $sys     = shift;
    my $pub     = shift;

    $self->_handle_start_document({}) unless $self->{_started};

    my $dtd = {
                Name        => $name,
                SystemId    => $sys,
                PublicId    => $pub,
              };
    $self->SUPER::start_dtd($dtd);
}
#-------------------------------------------------------------------#

#-------------------------------------------------------------------#
# _handle_end_doctype
#-------------------------------------------------------------------#
sub _handle_end_doctype {
    $_[0]->{__XSE}->SUPER::end_dtd( {} );
}
#-------------------------------------------------------------------#


#-------------------------------------------------------------------#
# _handle_start_document
#-------------------------------------------------------------------#
sub _handle_start_document {
    $_[0]->SUPER::start_document($_[1]);
    $_[0]->{_started} = 1;
}
#-------------------------------------------------------------------#


#-------------------------------------------------------------------#
# supported_features
#-------------------------------------------------------------------#
sub supported_features {
    return (
             $_[0]->SUPER::supported_features,
             'http://xml.org/sax/features/external-general-entities',
             'http://xml.org/sax/features/external-parameter-entities',
           );
}
#-------------------------------------------------------------------#





#,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,#
#`,`, Private Helpers `,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,#
#```````````````````````````````````````````````````````````````````#

#-------------------------------------------------------------------#
# _create_node
#-------------------------------------------------------------------#
#sub _create_node {
#    shift;
#    # this may check for a factory later
#    return {@_};
#}
#-------------------------------------------------------------------#


1;
#,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,#
#`,`, Documentation `,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,#
#```````````````````````````````````````````````````````````````````#

=pod

=head1 NAME

XML::SAX::Expat - SAX2 Driver for Expat (XML::Parser)

=head1 SYNOPSIS

  use XML::SAX::Expat;
  use XML::SAX::MyFooHandler;
  my $h = XML::SAX::MyFooHandler->new;
  my $p = XML::SAX::Expat->new(Handler => $h);
  $p->parse_file('/path/to/foo.xml');

=head1 DESCRIPTION

This is an implementation of a SAX2 driver sitting on top of Expat
(XML::Parser) which Ken MacLeod posted to perl-xml and which I have
updated.

It is still incomplete, though most of the basic SAX2 events should be
available. The SAX2 spec is currently available from L<http://perl-xml.sourceforge.net/perl-sax/>.

A more friendly URL as well as a PODification of the spec are in the
works.

=head1 METHODS

The methods defined in this class correspond to those listed in the
PerlSAX2 specification, available above.

=head1 FEATURES AND CAVEATS

=over 2

=item supported_features

Returns:

  * http://xml.org/sax/features/external-general-entities
  * http://xml.org/sax/features/external-parameter-entities
  * [ Features supported by ancestors ]

Turning one of the first two on also turns the other on (this maps
to the XML::Parser ParseParamEnts option). This may be fixed in the
future, so don't rely on this behaviour.

=back

=head1 MISSING PARTS

XML::Parser has no listed callbacks for the following events, which
are therefore not presently generated (ways may be found in the
future):

  * ignorable_whitespace
  * skipped_entity
  * start_entity / end_entity
  * resolve_entity

Ways of signalling them are welcome. In addition to those,
set_document_locator is not yet called.

=head1 TODO

  - reuse Ken's tests and add more

=head1 AUTHOR

Robin Berjon; stolen from Ken Macleod, ken@bitsko.slc.ut.us, and with
suggestions and feedback from perl-xml. Currently maintained by Bjoern
Hoehrmann, L<http://bjoern.hoehrmann.de/>.

=head1 COPYRIGHT AND LICENSE

Copyright (c) 2001-2008 Robin Berjon. All rights reserved. This program is
free software; you can redistribute it and/or modify it under the same
terms as Perl itself.

=head1 SEE ALSO

XML::Parser::PerlSAX

=cut
PK6N%[�IWOkPkPperl5/XML/SAX/PurePerl.pmnu��6�$# $Id$

package XML::SAX::PurePerl;

use strict;
use vars qw/$VERSION/;

$VERSION = '1.02';

use XML::SAX::PurePerl::Productions qw($NameChar $SingleChar);
use XML::SAX::PurePerl::Reader;
use XML::SAX::PurePerl::EncodingDetect ();
use XML::SAX::Exception;
use XML::SAX::PurePerl::DocType ();
use XML::SAX::PurePerl::DTDDecls ();
use XML::SAX::PurePerl::XMLDecl ();
use XML::SAX::DocumentLocator ();
use XML::SAX::Base ();
use XML::SAX qw(Namespaces);
use XML::NamespaceSupport ();
use IO::File;

if ($] < 5.006) {
    require XML::SAX::PurePerl::NoUnicodeExt;
}
else {
    require XML::SAX::PurePerl::UnicodeExt;
}

use vars qw(@ISA);
@ISA = ('XML::SAX::Base');

my %int_ents = (
        amp => '&',
        lt => '<',
        gt => '>',
        quot => '"',
        apos => "'",
        );

my $xmlns_ns = "http://www.w3.org/2000/xmlns/";
my $xml_ns = "http://www.w3.org/XML/1998/namespace";

use Carp;
sub _parse_characterstream {
    my $self = shift;
    my ($fh) = @_;
    confess("CharacterStream is not yet correctly implemented");
    my $reader = XML::SAX::PurePerl::Reader::Stream->new($fh);
    return $self->_parse($reader);
}

sub _parse_bytestream {
    my $self = shift;
    my ($fh) = @_;
    my $reader = XML::SAX::PurePerl::Reader::Stream->new($fh);
    return $self->_parse($reader);
}

sub _parse_string {
    my $self = shift;
    my ($str) = @_;
    my $reader = XML::SAX::PurePerl::Reader::String->new($str);
    return $self->_parse($reader);
}

sub _parse_systemid {
    my $self = shift;
    my ($uri) = @_;
    my $reader = XML::SAX::PurePerl::Reader::URI->new($uri);
    return $self->_parse($reader);
}

sub _parse {
    my ($self, $reader) = @_;
    
    $reader->public_id($self->{ParseOptions}{Source}{PublicId});
    $reader->system_id($self->{ParseOptions}{Source}{SystemId});

    $self->{NSHelper} = XML::NamespaceSupport->new({xmlns => 1});

    $self->set_document_locator(
        XML::SAX::DocumentLocator->new(
            sub { $reader->public_id },
            sub { $reader->system_id },
            sub { $reader->line },
            sub { $reader->column },
            sub { $reader->get_encoding },
            sub { $reader->get_xml_version },
        ),
    );
    
    $self->start_document({});

    if (defined $self->{ParseOptions}{Source}{Encoding}) {
        $reader->set_encoding($self->{ParseOptions}{Source}{Encoding});
    }
    else {
        $self->encoding_detect($reader);
    }
    
    # parse a document
    $self->document($reader);
    
    return $self->end_document({});
}

sub parser_error {
    my $self = shift;
    my ($error, $reader) = @_;
    
# warn("parser error: $error from ", $reader->line, " : ", $reader->column, "\n");
    my $exception = XML::SAX::Exception::Parse->new(
                Message => $error,
                ColumnNumber => $reader->column,
                LineNumber => $reader->line,
                PublicId => $reader->public_id,
                SystemId => $reader->system_id,
            );

    $self->fatal_error($exception);
    $exception->throw;
}

sub document {
    my ($self, $reader) = @_;
    
    # document ::= prolog element Misc*
    
    $self->prolog($reader);
    $self->element($reader) ||
        $self->parser_error("Document requires an element", $reader);
    
    while(length($reader->data)) {
        $self->Misc($reader) || 
                $self->parser_error("Only Comments, PIs and whitespace allowed at end of document", $reader);
    }
}

sub prolog {
    my ($self, $reader) = @_;
    
    $self->XMLDecl($reader);
    
    # consume all misc bits
    1 while($self->Misc($reader));
    
    if ($self->doctypedecl($reader)) {
        while (length($reader->data)) {
            $self->Misc($reader) || last;
        }
    }
}

sub element {
    my ($self, $reader) = @_;
    
    return 0 unless $reader->match('<');
    
    my $name = $self->Name($reader) || $self->parser_error("Invalid element name", $reader);
    
    my %attribs;
    
    while( my ($k, $v) = $self->Attribute($reader) ) {
        $attribs{$k} = $v;
    }
    
    my $have_namespaces = $self->get_feature(Namespaces);
    
    # Namespace processing
    $self->{NSHelper}->push_context;
    my @new_ns;
#        my %attrs = @attribs;
#        while (my ($k,$v) = each %attrs) {
    if ($have_namespaces) {
        while ( my ($k, $v) = each %attribs ) {
            if ($k =~ m/^xmlns(:(.*))?$/) {
                my $prefix = $2 || '';
                $self->{NSHelper}->declare_prefix($prefix, $v);
                my $ns = 
                    {
                        Prefix       => $prefix,
                        NamespaceURI => $v,
                    };
                push @new_ns, $ns;
                $self->SUPER::start_prefix_mapping($ns);
            }
        }
    }

    # Create element object and fire event
    my %attrib_hash;
    while (my ($name, $value) = each %attribs ) {
        # TODO normalise value here
        my ($ns, $prefix, $lname);
        if ($have_namespaces) {
            ($ns, $prefix, $lname) = $self->{NSHelper}->process_attribute_name($name);
        }
        $ns ||= ''; $prefix ||= ''; $lname ||= '';
        $attrib_hash{"{$ns}$lname"} = {
            Name => $name,
            LocalName => $lname,
            Prefix => $prefix,
            NamespaceURI => $ns,
            Value => $value,
        };
    }
    
    %attribs = (); # lose the memory since we recurse deep
    
    my ($ns, $prefix, $lname);
    if ($self->get_feature(Namespaces)) {
        ($ns, $prefix, $lname) = $self->{NSHelper}->process_element_name($name);
    }
    else {
        $lname = $name;
    }
    $ns ||= ''; $prefix ||= ''; $lname ||= '';

    # Process remainder of start_element
    $self->skip_whitespace($reader);
    my $have_content;
    my $data = $reader->data(2);
    if ($data =~ /^\/>/) {
        $reader->move_along(2);
    }
    else {
        $data =~ /^>/ or $self->parser_error("No close element tag", $reader);
        $reader->move_along(1);
        $have_content++;
    }
    
    my $el = 
    {
        Name => $name,
        LocalName => $lname,
        Prefix => $prefix,
        NamespaceURI => $ns,
        Attributes => \%attrib_hash,
    };
    $self->start_element($el);
    
    # warn("($name\n");
    
    if ($have_content) {
        $self->content($reader);
        
        my $data = $reader->data(2);
        $data =~ /^<\// or $self->parser_error("No close tag marker", $reader);
        $reader->move_along(2);
        my $end_name = $self->Name($reader);
        $end_name eq $name || $self->parser_error("End tag mismatch ($end_name != $name)", $reader);
        $self->skip_whitespace($reader);
        $reader->match('>') or $self->parser_error("No close '>' on end tag", $reader);
    }
        
    my %end_el = %$el;
    delete $end_el{Attributes};
    $self->end_element(\%end_el);

    for my $ns (@new_ns) {
        $self->end_prefix_mapping($ns);
    }
    $self->{NSHelper}->pop_context;
    
    return 1;
}

sub content {
    my ($self, $reader) = @_;
    
    while (1) {
        $self->CharData($reader);
        
        my $data = $reader->data(2);
        
        if ($data =~ /^<\//) {
            return 1;
        }
        elsif ($data =~ /^&/) {
            $self->Reference($reader) or $self->parser_error("bare & not allowed in content", $reader);
            next;
        }
        elsif ($data =~ /^<!/) {
            ($self->CDSect($reader)
             or
             $self->Comment($reader))
             and next;
        }
        elsif ($data =~ /^<\?/) {
            $self->PI($reader) and next;
        }
        elsif ($data =~ /^</) {
            $self->element($reader) and next;
        }
        last;
    }
    
    return 1;
}

sub CDSect {
    my ($self, $reader) = @_;
    
    my $data = $reader->data(9);
    return 0 unless $data =~ /^<!\[CDATA\[/;
    $reader->move_along(9);
    
    $self->start_cdata({});
    
    $data = $reader->data;
    while (1) {
        $self->parser_error("EOF looking for CDATA section end", $reader)
            unless length($data);
        
        if ($data =~ /^(.*?)\]\]>/s) {
            my $chars = $1;
            $reader->move_along(length($chars) + 3);
            $self->characters({Data => $chars});
            last;
        }
        else {
            $self->characters({Data => $data});
            $reader->move_along(length($data));
            $data = $reader->data;
        }
    }
    $self->end_cdata({});
    return 1;
}

sub CharData {
    my ($self, $reader) = @_;
    
    my $data = $reader->data;
    
    while (1) {
        return unless length($data);
        
        if ($data =~ /^([^<&]*)[<&]/s) {
            my $chars = $1;
            $self->parser_error("String ']]>' not allowed in character data", $reader)
                if $chars =~ /\]\]>/;
            $reader->move_along(length($chars));
            $self->characters({Data => $chars}) if length($chars);
            last;
        }
        else {
            $self->characters({Data => $data});
            $reader->move_along(length($data));
            $data = $reader->data;
        }
    }
}

sub Misc {
    my ($self, $reader) = @_;
    if ($self->Comment($reader)) {
        return 1;
    }
    elsif ($self->PI($reader)) {
        return 1;
    }
    elsif ($self->skip_whitespace($reader)) {
        return 1;
    }
    
    return 0;
}

sub Reference {
    my ($self, $reader) = @_;
    
    return 0 unless $reader->match('&');
    
    my $data = $reader->data;

    # Fetch more data if we have an incomplete numeric reference
    if ($data =~ /^(#\d*|#x[0-9a-fA-F]*)$/) {
        $data = $reader->data(length($data) + 6);
    }
    
    if ($data =~ /^#x([0-9a-fA-F]+);/) {
        my $ref = $1;
        $reader->move_along(length($ref) + 3);
        my $char = chr_ref(hex($ref));
        $self->parser_error("Character reference &#$ref; refers to an illegal XML character ($char)", $reader)
            unless $char =~ /$SingleChar/o;
        $self->characters({ Data => $char });
        return 1;
    }
    elsif ($data =~ /^#([0-9]+);/) {
        my $ref = $1;
        $reader->move_along(length($ref) + 2);
        my $char = chr_ref($ref);
        $self->parser_error("Character reference &#$ref; refers to an illegal XML character ($char)", $reader)
            unless $char =~ /$SingleChar/o;
        $self->characters({ Data => $char });
        return 1;
    }
    else {
        # EntityRef
        my $name = $self->Name($reader)
            || $self->parser_error("Invalid name in entity", $reader);
        $reader->match(';') or $self->parser_error("No semi-colon found after entity name", $reader);
        
        # warn("got entity: \&$name;\n");
        
        # expand it
        if ($self->_is_entity($name)) {
            
            if ($self->_is_external($name)) {
                my $value = $self->_get_entity($name);
                my $ent_reader = XML::SAX::PurePerl::Reader::URI->new($value);
                $self->encoding_detect($ent_reader);
                $self->extParsedEnt($ent_reader);
            }
            else {
                my $value = $self->_stringify_entity($name);
                my $ent_reader = XML::SAX::PurePerl::Reader::String->new($value);
                $self->content($ent_reader);
            }
            return 1;
        }
        elsif ($name =~ /^(?:amp|gt|lt|quot|apos)$/) {
            $self->characters({ Data => $int_ents{$name} });
            return 1;
        }
        else {
            $self->parser_error("Undeclared entity", $reader);
        }
    }
}

sub AttReference {
    my ($self, $name, $reader) = @_;
    if ($name =~ /^#x([0-9a-fA-F]+)$/) {
        my $chr = chr_ref(hex($1));
        $chr =~ /$SingleChar/o or $self->parser_error("Character reference '&$name;' refers to an illegal XML character", $reader);
        return $chr;
    }
    elsif ($name =~ /^#([0-9]+)$/) {
        my $chr = chr_ref($1);
        $chr =~ /$SingleChar/o or $self->parser_error("Character reference '&$name;' refers to an illegal XML character", $reader);
        return $chr;
    }
    else {
        if ($self->_is_entity($name)) {
            if ($self->_is_external($name)) {
                $self->parser_error("No external entity references allowed in attribute values", $reader);
            }
            else {
                my $value = $self->_stringify_entity($name);
                return $value;
            }
        }
        elsif ($name =~ /^(?:amp|lt|gt|quot|apos)$/) {
            return $int_ents{$name};
        }
        else {
            $self->parser_error("Undeclared entity '$name'", $reader);
        }
    }
}

sub extParsedEnt {
    my ($self, $reader) = @_;
    
    $self->TextDecl($reader);
    $self->content($reader);
}

sub _is_external {
    my ($self, $name) = @_;
# TODO: Fix this to use $reader to store the entities perhaps.
    if ($self->{ParseOptions}{external_entities}{$name}) {
        return 1;
    }
    return ;
}

sub _is_entity {
    my ($self, $name) = @_;
# TODO: ditto above
    if (exists $self->{ParseOptions}{entities}{$name}) {
        return 1;
    }
    return 0;
}

sub _stringify_entity {
    my ($self, $name) = @_;
# TODO: ditto above
    if (exists $self->{ParseOptions}{expanded_entity}{$name}) {
        return $self->{ParseOptions}{expanded_entity}{$name};
    }
    # expand
    my $reader = XML::SAX::PurePerl::Reader::URI->new($self->{ParseOptions}{entities}{$name});
    my $ent = '';
    while(1) {
        my $data = $reader->data;
        $ent .= $data;
        $reader->move_along(length($data)) or last;
    }
    return $self->{ParseOptions}{expanded_entity}{$name} = $ent;
}

sub _get_entity {
    my ($self, $name) = @_;
# TODO: ditto above
    return $self->{ParseOptions}{entities}{$name};
}

sub skip_whitespace {
    my ($self, $reader) = @_;
    
    my $data = $reader->data;
    
    my $found = 0;
    while ($data =~ s/^([\x20\x0A\x0D\x09]*)//) {
        last unless length($1);
        $found++;
        $reader->move_along(length($1));
        $data = $reader->data;
    }
    
    return $found;
}

sub Attribute {
    my ($self, $reader) = @_;
    
    $self->skip_whitespace($reader) || return;
    
    my $data = $reader->data(2);
    return if $data =~ /^\/?>/;
    
    if (my $name = $self->Name($reader)) {
        $self->skip_whitespace($reader);
        $reader->match('=') or $self->parser_error("No '=' in Attribute", $reader);
        $self->skip_whitespace($reader);
        my $value = $self->AttValue($reader);

        if (!$self->cdata_attrib($name)) {
            $value =~ s/^\x20*//; # discard leading spaces
            $value =~ s/\x20*$//; # discard trailing spaces
            $value =~ s/ {1,}/ /g; # all >1 space to single space
        }
        
        return $name, $value;
    }
    
    return;
}

sub cdata_attrib {
    # TODO implement this!
    return 1;
}

sub AttValue {
    my ($self, $reader) = @_;
    
    my $quote = $self->quote($reader);
    
    my $value = '';
    
    while (1) {
        my $data = $reader->data;
        $self->parser_error("EOF found while looking for the end of attribute value", $reader)
            unless length($data);
        if ($data =~ /^([^$quote]*)$quote/) {
            $reader->move_along(length($1) + 1);
            $value .= $1;
            last;
        }
        else {
            $value .= $data;
            $reader->move_along(length($data));
        }
    }
    
    if ($value =~ /</) {
        $self->parser_error("< character not allowed in attribute values", $reader);
    }
    
    $value =~ s/[\x09\x0A\x0D]/\x20/g;
    $value =~ s/&(#(x[0-9a-fA-F]+)|#([0-9]+)|\w+);/$self->AttReference($1, $reader)/geo;
    
    return $value;
}

sub Comment {
    my ($self, $reader) = @_;
    
    my $data = $reader->data(4);
    if ($data =~ /^<!--/) {
        $reader->move_along(4);
        my $comment_str = '';
        while (1) {
            my $data = $reader->data;
            $self->parser_error("End of data seen while looking for close comment marker", $reader)
                unless length($data);
            if ($data =~ /^(.*?)-->/s) {
                $comment_str .= $1;
                $self->parser_error("Invalid comment (dash)", $reader) if $comment_str =~ /-$/;
                $reader->move_along(length($1) + 3);
                last;
            }
            else {
                $comment_str .= $data;
                $reader->move_along(length($data));
            }
        }
        
        $self->comment({ Data => $comment_str });
        
        return 1;
    }
    return 0;
}

sub PI {
    my ($self, $reader) = @_;
    
    my $data = $reader->data(2);
    
    if ($data =~ /^<\?/) {
        $reader->move_along(2);
        my ($target);
        $target = $self->Name($reader) ||
            $self->parser_error("PI has no target", $reader);
	    
        my $pi_data = '';
        if ($self->skip_whitespace($reader)) {
            while (1) {
                my $data = $reader->data;
                $self->parser_error("End of data seen while looking for close PI marker", $reader)
                    unless length($data);
                if ($data =~ /^(.*?)\?>/s) {
                    $pi_data .= $1;
                    $reader->move_along(length($1) + 2);
                    last;
                }
                else {
                    $pi_data .= $data;
                    $reader->move_along(length($data));
                }
            }
        }
        else {
            my $data = $reader->data(2);
            $data =~ /^\?>/ or $self->parser_error("PI closing sequence not found", $reader);
            $reader->move_along(2);
        }
	
        $self->processing_instruction({ Target => $target, Data => $pi_data });
        
        return 1;
    }
    return 0;
}

sub Name {
    my ($self, $reader) = @_;
    
    my $name = '';
    while(1) {
        my $data = $reader->data;
        return unless length($data);
        $data =~ /^([^\s>\/&\?;=<\)\(\[\],\%\#\!\*\|]*)/ or return;
        $name .= $1;
        my $len = length($1);
        $reader->move_along($len);
        last if ($len != length($data));
    }
    
    return unless length($name);
    
    $name =~ /$NameChar/o or $self->parser_error("Name <$name> does not match NameChar production", $reader);

    return $name;
}

sub quote {
    my ($self, $reader) = @_;
    
    my $data = $reader->data;
    
    $data =~ /^(['"])/ or $self->parser_error("Invalid quote token", $reader);
    $reader->move_along(1);
    return $1;
}

1;
__END__

=head1 NAME

XML::SAX::PurePerl - Pure Perl XML Parser with SAX2 interface

=head1 SYNOPSIS

  use XML::Handler::Foo;
  use XML::SAX::PurePerl;
  my $handler = XML::Handler::Foo->new();
  my $parser = XML::SAX::PurePerl->new(Handler => $handler);
  $parser->parse_uri("myfile.xml");

=head1 DESCRIPTION

This module implements an XML parser in pure perl. It is written around the
upcoming perl 5.8's unicode support and support for multiple document 
encodings (using the PerlIO layer), however it has been ported to work with
ASCII/UTF8 documents under lower perl versions.

The SAX2 API is described in detail at http://sourceforge.net/projects/perl-xml/, in
the CVS archive, under libxml-perl/docs. Hopefully those documents will be in a
better location soon.

Please refer to the SAX2 documentation for how to use this module - it is merely a
front end to SAX2, and implements nothing that is not in that spec (or at least tries
not to - please email me if you find errors in this implementation).

=head1 BUGS

XML::SAX::PurePerl is B<slow>. Very slow. I suggest you use something else
in fact. However it is great as a fallback parser for XML::SAX, where the
user might not be able to install an XS based parser or C library.

Currently lots, probably. At the moment the weakest area is parsing DOCTYPE declarations,
though the code is in place to start doing this. Also parsing parameter entity
references is causing me much confusion, since it's not exactly what I would call
trivial, or well documented in the XML grammar. XML documents with internal subsets
are likely to fail.

I am however trying to work towards full conformance using the Oasis test suite.

=head1 AUTHOR

Matt Sergeant, matt@sergeant.org. Copyright 2001.

Please report all bugs to the Perl-XML mailing list at perl-xml@listserv.activestate.com.

=head1 LICENSE

This is free software. You may use it or redistribute it under the same terms as
Perl 5.7.2 itself.

=cut

PK6N%[a�3tt&perl5/XML/SAX/PurePerl/NoUnicodeExt.pmnu��6�$# $Id$

package XML::SAX::PurePerl;
use strict;

sub chr_ref {
    my $n = shift;
    if ($n < 0x80) {
        return chr ($n);
    }
    elsif ($n < 0x800) {
        return pack ("CC", (($n >> 6) | 0xc0), (($n & 0x3f) | 0x80));
    }
    elsif ($n < 0x10000) {
        return pack ("CCC", (($n >> 12) | 0xe0), ((($n >> 6) & 0x3f) | 0x80),
                                    (($n & 0x3f) | 0x80));
    }
    elsif ($n < 0x110000)
    {
        return pack ("CCCC", (($n >> 18) | 0xf0), ((($n >> 12) & 0x3f) | 0x80),
        ((($n >> 6) & 0x3f) | 0x80), (($n & 0x3f) | 0x80));
    }
    else {
        return undef;
    }
}

1;
PK6N%[	G��KK-perl5/XML/SAX/PurePerl/Reader/NoUnicodeExt.pmnu��6�$# $Id$

package XML::SAX::PurePerl::Reader;
use strict;

sub set_raw_stream {
    # no-op
}

sub switch_encoding_stream {
    my ($fh, $encoding) = @_;
    throw XML::SAX::Exception::Parse (
        Message => "Only ASCII encoding allowed without perl 5.7.2 or higher. You tried: $encoding",
    ) if $encoding !~ /(ASCII|UTF\-?8)/i;
}

sub switch_encoding_string {
    my (undef, $encoding) = @_;
    throw XML::SAX::Exception::Parse (
        Message => "Only ASCII encoding allowed without perl 5.7.2 or higher. You tried: $encoding",
    ) if $encoding !~ /(ASCII|UTF\-?8)/i;
}

1;

PK6N%[Lk��FF+perl5/XML/SAX/PurePerl/Reader/UnicodeExt.pmnu��6�$# $Id$

package XML::SAX::PurePerl::Reader;
use strict;

use Encode ();

sub set_raw_stream {
    my ($fh) = @_;
    binmode($fh, ":bytes");
}

sub switch_encoding_stream {
    my ($fh, $encoding) = @_;
    binmode($fh, ":encoding($encoding)");
}

sub switch_encoding_string {
    $_[0] = Encode::decode($_[1], $_[0]);
}

1;

PK6N%[`�$���$perl5/XML/SAX/PurePerl/Reader/URI.pmnu��6�$# $Id$

package XML::SAX::PurePerl::Reader::URI;

use strict;

use XML::SAX::PurePerl::Reader;
use File::Temp qw(tempfile);
use Symbol;

## NOTE: This is *not* a subclass of Reader. It just returns Stream or String
## Reader objects depending on what it's capabilities are.

sub new {
    my $class = shift;
    my $uri = shift;
    # request the URI
    if (-e $uri && -f _) {
        my $fh = gensym;
        open($fh, $uri) || die "Cannot open file $uri : $!";
        return XML::SAX::PurePerl::Reader::Stream->new($fh);
    }
    elsif ($uri =~ /^file:(.*)$/ && -e $1 && -f _) {
        my $file = $1;
        my $fh = gensym;
        open($fh, $file) || die "Cannot open file $file : $!";
        return XML::SAX::PurePerl::Reader::Stream->new($fh);
    }
    else {
        # request URI, return String reader
        require LWP::UserAgent;
        my $ua = LWP::UserAgent->new;
        $ua->agent("Perl/XML/SAX/PurePerl/1.0 " . $ua->agent);
        
        my $req = HTTP::Request->new(GET => $uri);
        
        my $fh = tempfile();
        
        my $callback = sub {
            my ($data, $response, $protocol) = @_;
            print $fh $data;
        };
        
        my $res = $ua->request($req, $callback, 4096);
        
        if ($res->is_success) {
            seek($fh, 0, 0);
            return XML::SAX::PurePerl::Reader::Stream->new($fh);
        }
        else {
            die "LWP Request Failed";
        }
    }
}


1;
PK6N%['8��'perl5/XML/SAX/PurePerl/Reader/String.pmnu��6�$# $Id$

package XML::SAX::PurePerl::Reader::String;

use strict;
use vars qw(@ISA);

use XML::SAX::PurePerl::Reader qw(
    LINE
    COLUMN
    BUFFER
    ENCODING
    EOF
);

@ISA = ('XML::SAX::PurePerl::Reader');

use constant DISCARDED  => 8;
use constant STRING     => 9;
use constant USED       => 10;
use constant CHUNK_SIZE => 2048;

sub new {
    my $class = shift;
    my $string = shift;
    my @parts;
    @parts[BUFFER, EOF, LINE, COLUMN, DISCARDED, STRING, USED] =
        ('',   0,   1,    0,       0, $string, 0);
    return bless \@parts, $class;
}

sub read_more () {
    my $self = shift;
    if ($self->[USED] >= length($self->[STRING])) {
        $self->[EOF]++;
        return 0;
    }
    my $bytes = CHUNK_SIZE;
    if ($bytes > (length($self->[STRING]) - $self->[USED])) {
       $bytes = (length($self->[STRING]) - $self->[USED]);
    }
    $self->[BUFFER] .= substr($self->[STRING], $self->[USED], $bytes);
    $self->[USED] += $bytes;
    return 1;
 }


sub move_along {
    my($self, $bytes) = @_;
    my $discarded = substr($self->[BUFFER], 0, $bytes, '');
    $self->[DISCARDED] += length($discarded);
    
    # Wish I could skip this lot - tells us where we are in the file
    my $lines = $discarded =~ tr/\n//;
    $self->[LINE] += $lines;
    if ($lines) {
        $discarded =~ /\n([^\n]*)$/;
        $self->[COLUMN] = length($1);
    }
    else {
        $self->[COLUMN] += $_[0];
    }
}

sub set_encoding {
    my $self = shift;
    my ($encoding) = @_;

    XML::SAX::PurePerl::Reader::switch_encoding_string($self->[BUFFER], $encoding, "utf-8");
    $self->[ENCODING] = $encoding;
}

sub bytepos {
    my $self = shift;
    $self->[DISCARDED];
}

1;
PK6N%[��'�		'perl5/XML/SAX/PurePerl/Reader/Stream.pmnu��6�$# $Id$

package XML::SAX::PurePerl::Reader::Stream;

use strict;
use vars qw(@ISA);

use XML::SAX::PurePerl::Reader qw(
    EOF
    BUFFER
    LINE
    COLUMN
    ENCODING
    XML_VERSION
);
use XML::SAX::Exception;

@ISA = ('XML::SAX::PurePerl::Reader');

# subclassed by adding 1 to last element
use constant FH => 8;
use constant BUFFER_SIZE => 4096;

sub new {
    my $class = shift;
    my $ioref = shift;
    XML::SAX::PurePerl::Reader::set_raw_stream($ioref);
    my @parts;
    @parts[FH, LINE, COLUMN, BUFFER, EOF, XML_VERSION] =
        ($ioref, 1,   0,      '',     0,   '1.0');
    return bless \@parts, $class;
}

sub read_more {
    my $self = shift;
    my $buf;
    my $bytesread = read($self->[FH], $buf, BUFFER_SIZE);
    if ($bytesread) {
        $self->[BUFFER] .= $buf;
        return 1;
    }
    elsif (defined($bytesread)) {
        $self->[EOF]++;
        return 0;
    }
    else {
        throw XML::SAX::Exception::Parse(
            Message => "Error reading from filehandle: $!",
        );
    }
}

sub move_along {
    my $self = shift;
    my $discarded = substr($self->[BUFFER], 0, $_[0], '');
    
    # Wish I could skip this lot - tells us where we are in the file
    my $lines = $discarded =~ tr/\n//;
    $self->[LINE] += $lines;
    if ($lines) {
        $discarded =~ /\n([^\n]*)$/;
        $self->[COLUMN] = length($1);
    }
    else {
        $self->[COLUMN] += $_[0];
    }
}

sub set_encoding {
    my $self = shift;
    my ($encoding) = @_;
    # warn("set encoding to: $encoding\n");
    XML::SAX::PurePerl::Reader::switch_encoding_stream($self->[FH], $encoding);
    XML::SAX::PurePerl::Reader::switch_encoding_string($self->[BUFFER], $encoding);
    $self->[ENCODING] = $encoding;
}

sub bytepos {
    my $self = shift;
    tell($self->[FH]);
}

1;

PK6N%[�5+�22!perl5/XML/SAX/PurePerl/DocType.pmnu��6�$# $Id$

package XML::SAX::PurePerl;

use strict;
use XML::SAX::PurePerl::Productions qw($PubidChar);

sub doctypedecl {
    my ($self, $reader) = @_;
    
    my $data = $reader->data(9);
    if ($data =~ /^<!DOCTYPE/) {
        $reader->move_along(9);
        $self->skip_whitespace($reader) ||
            $self->parser_error("No whitespace after doctype declaration", $reader);
        
        my $root_name = $self->Name($reader) ||
            $self->parser_error("Doctype declaration has no root element name", $reader);
        
        if ($self->skip_whitespace($reader)) {
            # might be externalid...
            my %dtd = $self->ExternalID($reader);
            # TODO: Call SAX event
        }
        
        $self->skip_whitespace($reader);
        
        $self->InternalSubset($reader);
        
        $reader->match('>') or $self->parser_error("Doctype not closed", $reader);
        
        return 1;
    }
    
    return 0;
}

sub ExternalID {
    my ($self, $reader) = @_;
    
    my $data = $reader->data(6);
    
    if ($data =~ /^SYSTEM/) {
        $reader->move_along(6);
        $self->skip_whitespace($reader) ||
            $self->parser_error("No whitespace after SYSTEM identifier", $reader);
        return (SYSTEM => $self->SystemLiteral($reader));
    }
    elsif ($data =~ /^PUBLIC/) {
        $reader->move_along(6);
        $self->skip_whitespace($reader) ||
            $self->parser_error("No whitespace after PUBLIC identifier", $reader);
        
        my $quote = $self->quote($reader) || 
            $self->parser_error("Not a quote character in PUBLIC identifier", $reader);
        
        my $data = $reader->data;
        my $pubid = '';
        while(1) {
            $self->parser_error("EOF while looking for end of PUBLIC identifiier", $reader)
                unless length($data);
            
            if ($data =~ /^([^$quote]*)$quote/) {
                $pubid .= $1;
                $reader->move_along(length($1) + 1);
                last;
            }
            else {
                $pubid .= $data;
                $reader->move_along(length($data));
                $data = $reader->data;
            }
        }
        
        if ($pubid !~ /^($PubidChar)+$/) {
            $self->parser_error("Invalid characters in PUBLIC identifier", $reader);
        }
        
        $self->skip_whitespace($reader) ||
            $self->parser_error("Not whitespace after PUBLIC ID in DOCTYPE", $reader);
        
        return (PUBLIC => $pubid, 
                SYSTEM => $self->SystemLiteral($reader));
    }
    else {
        return;
    }
    
    return 1;
}

sub SystemLiteral {
    my ($self, $reader) = @_;
    
    my $quote = $self->quote($reader);
    
    my $data = $reader->data;
    my $systemid = '';
    while (1) {
        $self->parser_error("EOF found while looking for end of System Literal", $reader)
            unless length($data);
        if ($data =~ /^([^$quote]*)$quote/) {
            $systemid .= $1;
            $reader->move_along(length($1) + 1);
            return $systemid;
        }
        else {
            $systemid .= $data;
            $reader->move_along(length($data));
            $data = $reader->data;
        }
    }
}

sub InternalSubset {
    my ($self, $reader) = @_;
    
    return 0 unless $reader->match('[');
    
    1 while $self->IntSubsetDecl($reader);
    
    $reader->match(']') or $self->parser_error("No close bracket on internal subset (found: " . $reader->data, $reader);
    $self->skip_whitespace($reader);
    return 1;
}

sub IntSubsetDecl {
    my ($self, $reader) = @_;

    return $self->DeclSep($reader) || $self->markupdecl($reader);
}

sub DeclSep {
    my ($self, $reader) = @_;

    if ($self->skip_whitespace($reader)) {
        return 1;
    }

    if ($self->PEReference($reader)) {
        return 1;
    }
    
#    if ($self->ParsedExtSubset($reader)) {
#        return 1;
#    }
    
    return 0;
}

sub PEReference {
    my ($self, $reader) = @_;
    
    return 0 unless $reader->match('%');
    
    my $peref = $self->Name($reader) ||
        $self->parser_error("PEReference did not find a Name", $reader);
    # TODO - load/parse the peref
    
    $reader->match(';') or $self->parser_error("Invalid token in PEReference", $reader);
    return 1;
}

sub markupdecl {
    my ($self, $reader) = @_;
    
    if ($self->elementdecl($reader) ||
        $self->AttlistDecl($reader) ||
        $self->EntityDecl($reader) ||
        $self->NotationDecl($reader) ||
        $self->PI($reader) ||
        $self->Comment($reader))
    {
        return 1;
    }
    
    return 0;
}

1;
PK6N%[�z]Xqq$perl5/XML/SAX/PurePerl/UnicodeExt.pmnu��6�$# $Id$

package XML::SAX::PurePerl;
use strict;

no warnings 'utf8';

sub chr_ref {
    return chr(shift);
}

if ($] >= 5.007002) {
    require Encode;
    
    Encode::define_alias( "UTF-16" => "UCS-2" );
    Encode::define_alias( "UTF-16BE" => "UCS-2" );
    Encode::define_alias( "UTF-16LE" => "ucs-2le" );
    Encode::define_alias( "UTF16LE" => "ucs-2le" );
}

1;

PK7N%[�6:o`B`B"perl5/XML/SAX/PurePerl/DTDDecls.pmnu��6�$# $Id$

package XML::SAX::PurePerl;

use strict;
use XML::SAX::PurePerl::Productions qw($SingleChar);

sub elementdecl {
    my ($self, $reader) = @_;
    
    my $data = $reader->data(9);
    return 0 unless $data =~ /^<!ELEMENT/;
    $reader->move_along(9);
    
    $self->skip_whitespace($reader) ||
        $self->parser_error("No whitespace after ELEMENT declaration", $reader);
    
    my $name = $self->Name($reader);
    
    $self->skip_whitespace($reader) ||
        $self->parser_error("No whitespace after ELEMENT's name", $reader);
        
    $self->contentspec($reader, $name);
    
    $self->skip_whitespace($reader);
    
    $reader->match('>') or $self->parser_error("Closing angle bracket not found on ELEMENT declaration", $reader);
    
    return 1;
}

sub contentspec {
    my ($self, $reader, $name) = @_;
    
    my $data = $reader->data(5);
    
    my $model;
    if ($data =~ /^EMPTY/) {
        $reader->move_along(5);
        $model = 'EMPTY';
    }
    elsif ($data =~ /^ANY/) {
        $reader->move_along(3);
        $model = 'ANY';
    }
    else {
        $model = $self->Mixed_or_children($reader);
    }

    if ($model) {
        # call SAX callback now.
        $self->element_decl({Name => $name, Model => $model});
        return 1;
    }
    
    $self->parser_error("contentspec not found in ELEMENT declaration", $reader);
}

sub Mixed_or_children {
    my ($self, $reader) = @_;

    my $data = $reader->data(8);
    $data =~ /^\(/ or return; # $self->parser_error("No opening bracket in Mixed or children", $reader);
    
    if ($data =~ /^\(\s*\#PCDATA/) {
        $reader->match('(');
        $self->skip_whitespace($reader);
        $reader->move_along(7);
        my $model = $self->Mixed($reader);
        return $model;
    }

    # not matched - must be Children
    return $self->children($reader);
}

# Mixed ::= ( '(' S* PCDATA ( S* '|' S* QName )* S* ')' '*' )
#               | ( '(' S* PCDATA S* ')' )
sub Mixed {
    my ($self, $reader) = @_;

    # Mixed_or_children already matched '(' S* '#PCDATA'

    my $model = '(#PCDATA';
            
    $self->skip_whitespace($reader);

    my %seen;
    
    while (1) {
        last unless $reader->match('|');
        $self->skip_whitespace($reader);

        my $name = $self->Name($reader) || 
            $self->parser_error("No 'Name' after Mixed content '|'", $reader);

        if ($seen{$name}) {
            $self->parser_error("Element '$name' has already appeared in this group", $reader);
        }
        $seen{$name}++;

        $model .= "|$name";
        
        $self->skip_whitespace($reader);
    }
    
    $reader->match(')') || $self->parser_error("no closing bracket on mixed content", $reader);

    $model .= ")";

    if ($reader->match('*')) {
        $model .= "*";
    }
    
    return $model;
}

# [[47]] Children ::= ChoiceOrSeq Cardinality?
# [[48]] Cp ::= ( QName | ChoiceOrSeq ) Cardinality?
#       ChoiceOrSeq ::= '(' S* Cp ( Choice | Seq )? S* ')'
# [[49]] Choice ::= ( S* '|' S* Cp )+
# [[50]] Seq    ::= ( S* ',' S* Cp )+
#        // Children ::= (Choice | Seq) Cardinality?
#        // Cp ::= ( QName | Choice | Seq) Cardinality?
#        // Choice ::= '(' S* Cp ( S* '|' S* Cp )+ S* ')'
#        // Seq    ::= '(' S* Cp ( S* ',' S* Cp )* S* ')'
# [[51]] Mixed ::= ( '(' S* PCDATA ( S* '|' S* QName )* S* ')' MixedCardinality )
#                | ( '(' S* PCDATA S* ')' )
#        Cardinality ::= '?' | '+' | '*'
#        MixedCardinality ::= '*'
sub children {
    my ($self, $reader) = @_;
    
    return $self->ChoiceOrSeq($reader) . $self->Cardinality($reader);
}

sub ChoiceOrSeq {
    my ($self, $reader) = @_;
    
    $reader->match('(') or $self->parser_error("choice/seq contains no opening bracket", $reader);
    
    my $model = '(';
    
    $self->skip_whitespace($reader);

    $model .= $self->Cp($reader);
    
    if (my $choice = $self->Choice($reader)) {
        $model .= $choice;
    }
    else {
        $model .= $self->Seq($reader);
    }

    $self->skip_whitespace($reader);

    $reader->match(')') or $self->parser_error("choice/seq contains no closing bracket", $reader);

    $model .= ')';
    
    return $model;
}

sub Cardinality {
    my ($self, $reader) = @_;
    # cardinality is always optional
    my $data = $reader->data;
    if ($data =~ /^([\?\+\*])/) {
        $reader->move_along(1);
        return $1;
    }
    return '';
}

sub Cp {
    my ($self, $reader) = @_;

    my $model;
    my $name = eval
    {
	if (my $name = $self->Name($reader)) {
	    return $name . $self->Cardinality($reader);
	}
    };
    return $name if defined $name;
    return $self->ChoiceOrSeq($reader) . $self->Cardinality($reader);
}

sub Choice {
    my ($self, $reader) = @_;
    
    my $model = '';
    $self->skip_whitespace($reader);
    
    while ($reader->match('|')) {
        $self->skip_whitespace($reader);
        $model .= '|';
        $model .= $self->Cp($reader);
        $self->skip_whitespace($reader);
    }

    return $model;
}

sub Seq {
    my ($self, $reader) = @_;
    
    my $model = '';
    $self->skip_whitespace($reader);
    
    while ($reader->match(',')) {
        $self->skip_whitespace($reader);
        my $cp = $self->Cp($reader);
        if ($cp) {
            $model .= ',';
            $model .= $cp;
        }
        $self->skip_whitespace($reader);
    }

    return $model;
}

sub AttlistDecl {
    my ($self, $reader) = @_;
    
    my $data = $reader->data(9);
    if ($data =~ /^<!ATTLIST/) {
        # It's an attlist
        
        $reader->move_along(9);
        
        $self->skip_whitespace($reader) || 
            $self->parser_error("No whitespace after ATTLIST declaration", $reader);
        my $name = $self->Name($reader);

        $self->AttDefList($reader, $name);

        $self->skip_whitespace($reader);
        
        $reader->match('>') or $self->parser_error("Closing angle bracket not found on ATTLIST declaration", $reader);
        
        return 1;
    }
    
    return 0;
}

sub AttDefList {
    my ($self, $reader, $name) = @_;

    1 while $self->AttDef($reader, $name);
}

sub AttDef {
    my ($self, $reader, $el_name) = @_;

    $self->skip_whitespace($reader) || return 0;
    my $att_name = $self->Name($reader) || return 0;
    $self->skip_whitespace($reader) || 
        $self->parser_error("No whitespace after Name in attribute definition", $reader);
    my $att_type = $self->AttType($reader);

    $self->skip_whitespace($reader) ||
        $self->parser_error("No whitespace after AttType in attribute definition", $reader);
    my ($mode, $value) = $self->DefaultDecl($reader);
    
    # fire SAX event here!
    $self->attribute_decl({
            eName => $el_name, 
            aName => $att_name, 
            Type => $att_type, 
            Mode => $mode, 
            Value => $value,
            });
    return 1;
}

sub AttType {
    my ($self, $reader) = @_;

    return $self->StringType($reader) ||
            $self->TokenizedType($reader) ||
            $self->EnumeratedType($reader) ||
            $self->parser_error("Can't match AttType", $reader);
}

sub StringType {
    my ($self, $reader) = @_;
    
    my $data = $reader->data(5);
    return unless $data =~ /^CDATA/;
    $reader->move_along(5);
    return 'CDATA';
}

sub TokenizedType {
    my ($self, $reader) = @_;
    
    my $data = $reader->data(8);
    if ($data =~ /^(IDREFS?|ID|ENTITIES|ENTITY|NMTOKENS?)/) {
        $reader->move_along(length($1));
        return $1;
    }
    return;
}

sub EnumeratedType {
    my ($self, $reader) = @_;
    return $self->NotationType($reader) || $self->Enumeration($reader);
}

sub NotationType {
    my ($self, $reader) = @_;
    
    my $data = $reader->data(8);
    return unless $data =~ /^NOTATION/;
    $reader->move_along(8);
    
    $self->skip_whitespace($reader) ||
        $self->parser_error("No whitespace after NOTATION", $reader);
    $reader->match('(') or $self->parser_error("No opening bracket in notation section", $reader);
    
    $self->skip_whitespace($reader);
    my $model = 'NOTATION (';
    my $name = $self->Name($reader) ||
        $self->parser_error("No name in notation section", $reader);
    $model .= $name;
    $self->skip_whitespace($reader);
    $data = $reader->data;
    while ($data =~ /^\|/) {
        $reader->move_along(1);
        $model .= '|';
        $self->skip_whitespace($reader);
        my $name = $self->Name($reader) ||
            $self->parser_error("No name in notation section", $reader);
        $model .= $name;
        $self->skip_whitespace($reader);
        $data = $reader->data;
    }
    $data =~ /^\)/ or $self->parser_error("No closing bracket in notation section", $reader);
    $reader->move_along(1);
    
    $model .= ')';

    return $model;
}

sub Enumeration {
    my ($self, $reader) = @_;
    
    return unless $reader->match('(');
    
    $self->skip_whitespace($reader);
    my $model = '(';
    my $nmtoken = $self->Nmtoken($reader) ||
        $self->parser_error("No Nmtoken in enumerated declaration", $reader);
    $model .= $nmtoken;
    $self->skip_whitespace($reader);
    my $data = $reader->data;
    while ($data =~ /^\|/) {
        $model .= '|';
        $reader->move_along(1);
        $self->skip_whitespace($reader);
        my $nmtoken = $self->Nmtoken($reader) ||
            $self->parser_error("No Nmtoken in enumerated declaration", $reader);
        $model .= $nmtoken;
        $self->skip_whitespace($reader);
        $data = $reader->data;
    }
    $data =~ /^\)/ or $self->parser_error("No closing bracket in enumerated declaration", $reader);
    $reader->move_along(1);
    
    $model .= ')';

    return $model;
}

sub Nmtoken {
    my ($self, $reader) = @_;
    return $self->Name($reader);
}

sub DefaultDecl {
    my ($self, $reader) = @_;
    
    my $data = $reader->data(9);
    if ($data =~ /^(\#REQUIRED|\#IMPLIED)/) {
        $reader->move_along(length($1));
        return $1;
    }
    my $model = '';
    if ($data =~ /^\#FIXED/) {
        $reader->move_along(6);
        $self->skip_whitespace($reader) || $self->parser_error(
                "no whitespace after FIXED specifier", $reader);
        my $value = $self->AttValue($reader);
        return "#FIXED", $value;
    }
    my $value = $self->AttValue($reader);
    return undef, $value;
}

sub EntityDecl {
    my ($self, $reader) = @_;
    
    my $data = $reader->data(8);
    return 0 unless $data =~ /^<!ENTITY/;
    $reader->move_along(8);
    
    $self->skip_whitespace($reader) || $self->parser_error(
        "No whitespace after ENTITY declaration", $reader);
    
    $self->PEDecl($reader) || $self->GEDecl($reader);
    
    $self->skip_whitespace($reader);
    
    $reader->match('>') or $self->parser_error("No closing '>' in entity definition", $reader);
    
    return 1;
}

sub GEDecl {
    my ($self, $reader) = @_;

    my $name = $self->Name($reader) || $self->parser_error("No entity name given", $reader);
    $self->skip_whitespace($reader) || $self->parser_error("No whitespace after entity name", $reader);

    # TODO: ExternalID calls lexhandler method. Wrong place for it.
    my $value;
    if ($value = $self->ExternalID($reader)) {
        $value .= $self->NDataDecl($reader);
    }
    else {
        $value = $self->EntityValue($reader);
    }

    if ($self->{ParseOptions}{entities}{$name}) {
        warn("entity $name already exists\n");
    } else {
        $self->{ParseOptions}{entities}{$name} = 1;
        $self->{ParseOptions}{expanded_entity}{$name} = $value; # ???
    }
    # do callback?
    return 1;
}

sub PEDecl {
    my ($self, $reader) = @_;
    
    return 0 unless $reader->match('%');

    $self->skip_whitespace($reader) || $self->parser_error("No whitespace after parameter entity marker", $reader);
    my $name = $self->Name($reader) || $self->parser_error("No parameter entity name given", $reader);
    $self->skip_whitespace($reader) || $self->parser_error("No whitespace after parameter entity name", $reader);
    my $value = $self->ExternalID($reader) ||
                $self->EntityValue($reader) ||
                $self->parser_error("PE is not a value or an external resource", $reader);
    # do callback?
    return 1;
}

my $quotre = qr/[^%&\"]/;
my $aposre = qr/[^%&\']/;

sub EntityValue {
    my ($self, $reader) = @_;
    
    my $data = $reader->data;
    my $quote = '"';
    my $re = $quotre;
    if ($data !~ /^"/) {
        $data =~ /^'/ or $self->parser_error("Not a quote character", $reader);
        $quote = "'";
        $re = $aposre;
    }
    $reader->move_along(1);
    
    my $value = '';
    
    while (1) {
        my $data = $reader->data;

        $self->parser_error("EOF found while reading entity value", $reader)
            unless length($data);
        
        if ($data =~ /^($re+)/) {
            my $match = $1;
            $value .= $match;
            $reader->move_along(length($match));
        }
        elsif ($reader->match('&')) {
            # if it's a char ref, expand now:
            if ($reader->match('#')) {
                my $char;
                my $ref = '';
                if ($reader->match('x')) {
                    my $data = $reader->data;
                    while (1) {
                        $self->parser_error("EOF looking for reference end", $reader)
                            unless length($data);
                        if ($data !~ /^([0-9a-fA-F]*)/) {
                            last;
                        }
                        $ref .= $1;
                        $reader->move_along(length($1));
                        if (length($1) == length($data)) {
                            $data = $reader->data;
                        }
                        else {
                            last;
                        }
                    }
                    $char = chr_ref(hex($ref));
                    $ref = "x$ref";
                }
                else {
                    my $data = $reader->data;
                    while (1) {
                        $self->parser_error("EOF looking for reference end", $reader)
                            unless length($data);
                        if ($data !~ /^([0-9]*)/) {
                            last;
                        }
                        $ref .= $1;
                        $reader->move_along(length($1));
                        if (length($1) == length($data)) {
                            $data = $reader->data;
                        }
                        else {
                            last;
                        }
                    }
                    $char = chr($ref);
                }
                $reader->match(';') ||
                    $self->parser_error("No semi-colon found after character reference", $reader);
                if ($char !~ $SingleChar) { # match a single character
                    $self->parser_error("Character reference '&#$ref;' refers to an illegal XML character ($char)", $reader);
                }
                $value .= $char;
            }
            else {
                # entity refs in entities get expanded later, so don't parse now.
                $value .= '&';
            }
        }
        elsif ($reader->match('%')) {
            $value .= $self->PEReference($reader);
        }
        elsif ($reader->match($quote)) {
            # end of attrib
            last;
        }
        else {
            $self->parser_error("Invalid character in attribute value: " . substr($reader->data, 0, 1), $reader);
        }
    }
    
    return $value;
}

sub NDataDecl {
    my ($self, $reader) = @_;
    $self->skip_whitespace($reader) || return '';
    my $data = $reader->data(5);
    return '' unless $data =~ /^NDATA/;
    $reader->move_along(5);
    $self->skip_whitespace($reader) || $self->parser_error("No whitespace after NDATA declaration", $reader);
    my $name = $self->Name($reader) || $self->parser_error("NDATA declaration lacks a proper Name", $reader);
    return " NDATA $name";
}

sub NotationDecl {
    my ($self, $reader) = @_;
    
    my $data = $reader->data(10);
    return 0 unless $data =~ /^<!NOTATION/;
    $reader->move_along(10);
    $self->skip_whitespace($reader) ||
        $self->parser_error("No whitespace after NOTATION declaration", $reader);
    $data = $reader->data;
    my $value = '';
    while(1) {
        $self->parser_error("EOF found while looking for end of NotationDecl", $reader)
            unless length($data);
        
        if ($data =~ /^([^>]*)>/) {
            $value .= $1;
            $reader->move_along(length($1) + 1);
            $self->notation_decl({Name => "FIXME", SystemId => "FIXME", PublicId => "FIXME" });
            last;
        }
        else {
            $value .= $data;
            $reader->move_along(length($data));
            $data = $reader->data;
        }
    }
    return 1;
}

1;
PK7N%[� ���	�	 perl5/XML/SAX/PurePerl/Reader.pmnu��6�$# $Id$

package XML::SAX::PurePerl::Reader;

use strict;
use XML::SAX::PurePerl::Reader::URI;
use Exporter ();

use vars qw(@ISA @EXPORT_OK);
@ISA = qw(Exporter);
@EXPORT_OK = qw(
    EOF
    BUFFER
    LINE
    COLUMN
    ENCODING
    XML_VERSION
);

use constant EOF => 0;
use constant BUFFER => 1;
use constant LINE => 2;
use constant COLUMN => 3;
use constant ENCODING => 4;
use constant SYSTEM_ID => 5;
use constant PUBLIC_ID => 6;
use constant XML_VERSION => 7;

require XML::SAX::PurePerl::Reader::Stream;
require XML::SAX::PurePerl::Reader::String;

if ($] >= 5.007002) {
    require XML::SAX::PurePerl::Reader::UnicodeExt;
}
else {
    require XML::SAX::PurePerl::Reader::NoUnicodeExt;
}

sub new {
    my $class = shift;
    my $thing = shift;
    
    # try to figure if this $thing is a handle of some sort
    if (ref($thing) && UNIVERSAL::isa($thing, 'IO::Handle')) {
        return XML::SAX::PurePerl::Reader::Stream->new($thing)->init;
    }
    my $ioref;
    if (tied($thing)) {
        my $class = ref($thing);
        no strict 'refs';
        $ioref = $thing if defined &{"${class}::TIEHANDLE"};
    }
    else {
        eval {
            $ioref = *{$thing}{IO};
        };
        undef $@;
    }
    if ($ioref) {
        return XML::SAX::PurePerl::Reader::Stream->new($thing)->init;
    }
    
    if ($thing =~ /</) {
        # assume it's a string
        return XML::SAX::PurePerl::Reader::String->new($thing)->init;
    }
    
    # assume it is a    uri
    return XML::SAX::PurePerl::Reader::URI->new($thing)->init;
}

sub init {
    my $self = shift;
    $self->[LINE] = 1;
    $self->[COLUMN] = 1;
    $self->read_more;
    return $self;
}

sub data {
    my ($self, $min_length) = (@_, 1);
    if (length($self->[BUFFER]) < $min_length) {
        $self->read_more;
    }
    return $self->[BUFFER];
}

sub match {
    my ($self, $char) = @_;
    my $data = $self->data;
    if (substr($data, 0, 1) eq $char) {
        $self->move_along(1);
        return 1;
    }
    return 0;
}

sub public_id {
    my $self = shift;
    @_ and $self->[PUBLIC_ID] = shift;
    $self->[PUBLIC_ID];
}

sub system_id {
    my $self = shift;
    @_ and $self->[SYSTEM_ID] = shift;
    $self->[SYSTEM_ID];
}

sub line {
    shift->[LINE];
}

sub column {
    shift->[COLUMN];
}

sub get_encoding {
    my $self = shift;
    return $self->[ENCODING];
}

sub get_xml_version {
    my $self = shift;
    return $self->[XML_VERSION];
}

1;

__END__

=head1 NAME

XML::Parser::PurePerl::Reader - Abstract Reader factory class

=cut
PK7N%[�.��D
D
(perl5/XML/SAX/PurePerl/EncodingDetect.pmnu��6�$# $Id$

package XML::SAX::PurePerl; # NB, not ::EncodingDetect!

use strict;

sub encoding_detect {
    my ($parser, $reader) = @_;
    
    my $error = "Invalid byte sequence at start of file";
    
    my $data = $reader->data;
    if ($data =~ /^\x00\x00\xFE\xFF/) {
        # BO-UCS4-be
        $reader->move_along(4);
        $reader->set_encoding('UCS-4BE');
        return;
    }
    elsif ($data =~ /^\x00\x00\xFF\xFE/) {
        # BO-UCS-4-2143
        $reader->move_along(4);
        $reader->set_encoding('UCS-4-2143');
        return;
    }
    elsif ($data =~ /^\x00\x00\x00\x3C/) {
        $reader->set_encoding('UCS-4BE');
        return;
    }
    elsif ($data =~ /^\x00\x00\x3C\x00/) {
        $reader->set_encoding('UCS-4-2143');
        return;
    }
    elsif ($data =~ /^\x00\x3C\x00\x00/) {
        $reader->set_encoding('UCS-4-3412');
        return;
    }
    elsif ($data =~ /^\x00\x3C\x00\x3F/) {
        $reader->set_encoding('UTF-16BE');
        return;
    }
    elsif ($data =~ /^\xFF\xFE\x00\x00/) {
        # BO-UCS-4LE
        $reader->move_along(4);
        $reader->set_encoding('UCS-4LE');
        return;
    }
    elsif ($data =~ /^\xFF\xFE/) {
        $reader->move_along(2);
        $reader->set_encoding('UTF-16LE');
        return;
    }
    elsif ($data =~ /^\xFE\xFF\x00\x00/) {
        $reader->move_along(4);
        $reader->set_encoding('UCS-4-3412');
        return;
    }
    elsif ($data =~ /^\xFE\xFF/) {
        $reader->move_along(2);
        $reader->set_encoding('UTF-16BE');
        return;
    }
    elsif ($data =~ /^\xEF\xBB\xBF/) { # UTF-8 BOM
        $reader->move_along(3);
        $reader->set_encoding('UTF-8');
        return;
    }
    elsif ($data =~ /^\x3C\x00\x00\x00/) {
        $reader->set_encoding('UCS-4LE');
        return;
    }
    elsif ($data =~ /^\x3C\x00\x3F\x00/) {
        $reader->set_encoding('UTF-16LE');
        return;
    }
    elsif ($data =~ /^\x3C\x3F\x78\x6D/) {
        # $reader->set_encoding('UTF-8');
        return;
    }
    elsif ($data =~ /^\x3C\x3F\x78/) {
        # $reader->set_encoding('UTF-8');
        return;
    }
    elsif ($data =~ /^\x3C\x3F/) {
        # $reader->set_encoding('UTF-8');
        return;
    }
    elsif ($data =~ /^\x3C/) {
        # $reader->set_encoding('UTF-8');
        return;
    }
    elsif ($data =~ /^[\x20\x09\x0A\x0D]+\x3C[^\x3F]/) {
        # $reader->set_encoding('UTF-8');
        return;
    }
    elsif ($data =~ /^\x4C\x6F\xA7\x94/) {
        $reader->set_encoding('EBCDIC');
        return;
    }
    
    warn("Unable to recognise encoding of this document");
    return;
}

1;

PK7N%[�&��#perl5/XML/SAX/PurePerl/Exception.pmnu��6�$# $Id$

package XML::SAX::PurePerl::Exception;

use strict;

use overload '""' => "stringify";

use vars qw/$StackTrace/;

$StackTrace = $ENV{XML_DEBUG} || 0;

sub throw {
    my $class = shift;
    die $class->new(@_);
}

sub new {
    my $class = shift;
    my %opts = @_;
    die "Invalid options" unless exists $opts{Message};
    
    if ($opts{reader}) {
        return bless { Message => $opts{Message},
                        Exception => undef, # not sure what this is for!!!
                        ColumnNumber => $opts{reader}->column,
                        LineNumber => $opts{reader}->line,
                        PublicId => $opts{reader}->public_id,
                        SystemId => $opts{reader}->system_id,
                        $StackTrace ? (StackTrace => stacktrace()) : (),
                    }, $class;
    }
    return bless { Message => $opts{Message},
                    Exception => undef, # not sure what this is for!!!
                  }, $class;
}

sub stringify {
    my $self = shift;
    local $^W;
    return $self->{Message} . " [Ln: " . $self->{LineNumber} . 
                ", Col: " . $self->{ColumnNumber} . "]" .
                ($StackTrace ? stackstring($self->{StackTrace}) : "") . "\n";
}

sub stacktrace {
    my $i = 2;
    my @fulltrace;
    while (my @trace = caller($i++)) {
        my %hash;
        @hash{qw(Package Filename Line)} = @trace[0..2];
        push @fulltrace, \%hash;
    }
    return \@fulltrace;
}

sub stackstring {
    my $stacktrace = shift;
    my $string = "\nFrom:\n";
    foreach my $current (@$stacktrace) {
        $string .= $current->{Filename} . " Line: " . $current->{Line} . "\n";
    }
    return $string;
}

1;

PK7N%[�N��=
=
!perl5/XML/SAX/PurePerl/XMLDecl.pmnu��6�$# $Id$

package XML::SAX::PurePerl;

use strict;
use XML::SAX::PurePerl::Productions qw($S $VersionNum $EncNameStart $EncNameEnd);

sub XMLDecl {
    my ($self, $reader) = @_;
    
    my $data = $reader->data(5);
    # warn("Looking for xmldecl in: $data");
    if ($data =~ /^<\?xml$S/o) {
        $reader->move_along(5);
        $self->skip_whitespace($reader);
        
        # get version attribute
        $self->VersionInfo($reader) || 
            $self->parser_error("XML Declaration lacks required version attribute, or version attribute does not match XML specification", $reader);
        
        if (!$self->skip_whitespace($reader)) {
            my $data = $reader->data(2);
            $data =~ /^\?>/ or $self->parser_error("Syntax error", $reader);
            $reader->move_along(2);
            return;
        }
        
        if ($self->EncodingDecl($reader)) {
            if (!$self->skip_whitespace($reader)) {
                my $data = $reader->data(2);
                $data =~ /^\?>/ or $self->parser_error("Syntax error", $reader);
                $reader->move_along(2);
                return;
            }
        }
        
        $self->SDDecl($reader);
        
        $self->skip_whitespace($reader);
        
        my $data = $reader->data(2);
        $data =~ /^\?>/ or $self->parser_error("Syntax error", $reader);
        $reader->move_along(2);
    }
    else {
        # warn("first 5 bytes: ", join(',', unpack("CCCCC", $data)), "\n");
        # no xml decl
        if (!$reader->get_encoding) {
            $reader->set_encoding("UTF-8");
        }
    }
}

sub VersionInfo {
    my ($self, $reader) = @_;
    
    my $data = $reader->data(11);
    
    # warn("Looking for version in $data");
    
    $data =~ /^(version$S*=$S*(["'])($VersionNum)\2)/o or return 0;
    $reader->move_along(length($1));
    my $vernum = $3;
    
    if ($vernum ne "1.0") {
        $self->parser_error("Only XML version 1.0 supported. Saw: '$vernum'", $reader);
    }

    return 1;
}

sub SDDecl {
    my ($self, $reader) = @_;
    
    my $data = $reader->data(15);
    
    $data =~ /^(standalone$S*=$S*(["'])(yes|no)\2)/o or return 0;
    $reader->move_along(length($1));
    my $yesno = $3;
    
    if ($yesno eq 'yes') {
        $self->{standalone} = 1;
    }
    else {
        $self->{standalone} = 0;
    }
    
    return 1;
}

sub EncodingDecl {
    my ($self, $reader) = @_;
    
    my $data = $reader->data(12);
    
    $data =~ /^(encoding$S*=$S*(["'])($EncNameStart$EncNameEnd*)\2)/o or return 0;
    $reader->move_along(length($1));
    my $encoding = $3;
    
    $reader->set_encoding($encoding);
    
    return 1;
}

sub TextDecl {
    my ($self, $reader) = @_;
    
    my $data = $reader->data(6);
    $data =~ /^<\?xml$S+/ or return;
    $reader->move_along(5);
    $self->skip_whitespace($reader);
    
    if ($self->VersionInfo($reader)) {
        $self->skip_whitespace($reader) ||
                $self->parser_error("Lack of whitespace after version attribute in text declaration", $reader);
    }
    
    $self->EncodingDecl($reader) ||
        $self->parser_error("Encoding declaration missing from external entity text declaration", $reader);
    
    $self->skip_whitespace($reader);
    
    $data = $reader->data(2);
    $data =~ /^\?>/ or $self->parser_error("Syntax error", $reader);
    
    return 1;
}

1;
PK7N%[���k��%perl5/XML/SAX/PurePerl/Productions.pmnu��6�$# $Id$

package XML::SAX::PurePerl::Productions;

use Exporter;
@ISA = ('Exporter');
@EXPORT_OK = qw($S $Char $VersionNum $BaseChar $Ideographic
    $Extender $Digit $CombiningChar $EncNameStart $EncNameEnd $NameChar $CharMinusDash
    $PubidChar $Any $SingleChar);

### WARNING!!! All productions here must *only* match a *single* character!!! ###

BEGIN {
$S = qr/[\x20\x09\x0D\x0A]/;

$CharMinusDash = qr/[^-]/x;

$Any = qr/ . /xms;

$VersionNum = qr/ [a-zA-Z0-9_.:-]+ /x;

$EncNameStart = qr/ [A-Za-z] /x;
$EncNameEnd = qr/ [A-Za-z0-9\._-] /x;

$PubidChar = qr/ [\x20\x0D\x0Aa-zA-Z0-9'()\+,.\/:=\?;!*\#@\$_\%-] /x;

if ($] < 5.006) {
    eval <<'    PERL';
    $Char = qr/^ [\x09\x0A\x0D\x20-\x7F]|([\xC0-\xFD][\x80-\xBF]+) $/x;

    $SingleChar = qr/^$Char$/;

    $BaseChar = qr/ [\x41-\x5A\x61-\x7A]|([\xC0-\xFD][\x80-\xBF]+) /x;
    
    $Extender = qr/ \xB7 /x;
    
    $Digit = qr/ [\x30-\x39] /x;
    
    # can't do this one without unicode
    # $CombiningChar = qr/^$/msx;
    
    $NameChar = qr/^ (?: $BaseChar | $Digit | [._:-] | $Extender )+ $/x;
    PERL
    die $@ if $@;
}
else {
    eval <<'    PERL';
    
    use utf8; # for 5.6
 
    $Char = qr/^ [\x09\x0A\x0D\x{0020}-\x{D7FF}\x{E000}-\x{FFFD}\x{10000}-\x{10FFFF}] $/x;

    $SingleChar = qr/^$Char$/;

    $BaseChar = qr/
[\x{0041}-\x{005A}\x{0061}-\x{007A}\x{00C0}-\x{00D6}\x{00D8}-\x{00F6}] |
[\x{00F8}-\x{00FF}\x{0100}-\x{0131}\x{0134}-\x{013E}\x{0141}-\x{0148}] |
[\x{014A}-\x{017E}\x{0180}-\x{01C3}\x{01CD}-\x{01F0}\x{01F4}-\x{01F5}] |
[\x{01FA}-\x{0217}\x{0250}-\x{02A8}\x{02BB}-\x{02C1}\x{0386}\x{0388}-\x{038A}] |
[\x{038C}\x{038E}-\x{03A1}\x{03A3}-\x{03CE}\x{03D0}-\x{03D6}\x{03DA}] |
[\x{03DC}\x{03DE}\x{03E0}\x{03E2}-\x{03F3}\x{0401}-\x{040C}\x{040E}-\x{044F}] |
[\x{0451}-\x{045C}\x{045E}-\x{0481}\x{0490}-\x{04C4}\x{04C7}-\x{04C8}] |
[\x{04CB}-\x{04CC}\x{04D0}-\x{04EB}\x{04EE}-\x{04F5}\x{04F8}-\x{04F9}] |
[\x{0531}-\x{0556}\x{0559}\x{0561}-\x{0586}\x{05D0}-\x{05EA}\x{05F0}-\x{05F2}] |
[\x{0621}-\x{063A}\x{0641}-\x{064A}\x{0671}-\x{06B7}\x{06BA}-\x{06BE}] |
[\x{06C0}-\x{06CE}\x{06D0}-\x{06D3}\x{06D5}\x{06E5}-\x{06E6}\x{0905}-\x{0939}] |
[\x{093D}\x{0958}-\x{0961}\x{0985}-\x{098C}\x{098F}-\x{0990}] |
[\x{0993}-\x{09A8}\x{09AA}-\x{09B0}\x{09B2}\x{09B6}-\x{09B9}\x{09DC}-\x{09DD}] |
[\x{09DF}-\x{09E1}\x{09F0}-\x{09F1}\x{0A05}-\x{0A0A}\x{0A0F}-\x{0A10}] |
[\x{0A13}-\x{0A28}\x{0A2A}-\x{0A30}\x{0A32}-\x{0A33}\x{0A35}-\x{0A36}] |
[\x{0A38}-\x{0A39}\x{0A59}-\x{0A5C}\x{0A5E}\x{0A72}-\x{0A74}\x{0A85}-\x{0A8B}] |
[\x{0A8D}\x{0A8F}-\x{0A91}\x{0A93}-\x{0AA8}\x{0AAA}-\x{0AB0}] |
[\x{0AB2}-\x{0AB3}\x{0AB5}-\x{0AB9}\x{0ABD}\x{0AE0}\x{0B05}-\x{0B0C}] |
[\x{0B0F}-\x{0B10}\x{0B13}-\x{0B28}\x{0B2A}-\x{0B30}\x{0B32}-\x{0B33}] |
[\x{0B36}-\x{0B39}\x{0B3D}\x{0B5C}-\x{0B5D}\x{0B5F}-\x{0B61}\x{0B85}-\x{0B8A}] |
[\x{0B8E}-\x{0B90}\x{0B92}-\x{0B95}\x{0B99}-\x{0B9A}\x{0B9C}] |
[\x{0B9E}-\x{0B9F}\x{0BA3}-\x{0BA4}\x{0BA8}-\x{0BAA}\x{0BAE}-\x{0BB5}] |
[\x{0BB7}-\x{0BB9}\x{0C05}-\x{0C0C}\x{0C0E}-\x{0C10}\x{0C12}-\x{0C28}] |
[\x{0C2A}-\x{0C33}\x{0C35}-\x{0C39}\x{0C60}-\x{0C61}\x{0C85}-\x{0C8C}] |
[\x{0C8E}-\x{0C90}\x{0C92}-\x{0CA8}\x{0CAA}-\x{0CB3}\x{0CB5}-\x{0CB9}\x{0CDE}] |
[\x{0CE0}-\x{0CE1}\x{0D05}-\x{0D0C}\x{0D0E}-\x{0D10}\x{0D12}-\x{0D28}] |
[\x{0D2A}-\x{0D39}\x{0D60}-\x{0D61}\x{0E01}-\x{0E2E}\x{0E30}\x{0E32}-\x{0E33}] |
[\x{0E40}-\x{0E45}\x{0E81}-\x{0E82}\x{0E84}\x{0E87}-\x{0E88}\x{0E8A}] |
[\x{0E8D}\x{0E94}-\x{0E97}\x{0E99}-\x{0E9F}\x{0EA1}-\x{0EA3}\x{0EA5}\x{0EA7}] |
[\x{0EAA}-\x{0EAB}\x{0EAD}-\x{0EAE}\x{0EB0}\x{0EB2}-\x{0EB3}\x{0EBD}] |
[\x{0EC0}-\x{0EC4}\x{0F40}-\x{0F47}\x{0F49}-\x{0F69}\x{10A0}-\x{10C5}] |
[\x{10D0}-\x{10F6}\x{1100}\x{1102}-\x{1103}\x{1105}-\x{1107}\x{1109}] |
[\x{110B}-\x{110C}\x{110E}-\x{1112}\x{113C}\x{113E}\x{1140}\x{114C}\x{114E}] |
[\x{1150}\x{1154}-\x{1155}\x{1159}\x{115F}-\x{1161}\x{1163}\x{1165}] |
[\x{1167}\x{1169}\x{116D}-\x{116E}\x{1172}-\x{1173}\x{1175}\x{119E}\x{11A8}] |
[\x{11AB}\x{11AE}-\x{11AF}\x{11B7}-\x{11B8}\x{11BA}\x{11BC}-\x{11C2}] |
[\x{11EB}\x{11F0}\x{11F9}\x{1E00}-\x{1E9B}\x{1EA0}-\x{1EF9}\x{1F00}-\x{1F15}] |
[\x{1F18}-\x{1F1D}\x{1F20}-\x{1F45}\x{1F48}-\x{1F4D}\x{1F50}-\x{1F57}] |
[\x{1F59}\x{1F5B}\x{1F5D}\x{1F5F}-\x{1F7D}\x{1F80}-\x{1FB4}\x{1FB6}-\x{1FBC}] |
[\x{1FBE}\x{1FC2}-\x{1FC4}\x{1FC6}-\x{1FCC}\x{1FD0}-\x{1FD3}] |
[\x{1FD6}-\x{1FDB}\x{1FE0}-\x{1FEC}\x{1FF2}-\x{1FF4}\x{1FF6}-\x{1FFC}] |
[\x{2126}\x{212A}-\x{212B}\x{212E}\x{2180}-\x{2182}\x{3041}-\x{3094}] |
[\x{30A1}-\x{30FA}\x{3105}-\x{312C}\x{AC00}-\x{D7A3}]
    /x;

    $Extender = qr/
[\x{00B7}\x{02D0}\x{02D1}\x{0387}\x{0640}\x{0E46}\x{0EC6}\x{3005}\x{3031}-\x{3035}\x{309D}-\x{309E}\x{30FC}-\x{30FE}]
/x;

    $Digit = qr/
[\x{0030}-\x{0039}\x{0660}-\x{0669}\x{06F0}-\x{06F9}\x{0966}-\x{096F}] |
[\x{09E6}-\x{09EF}\x{0A66}-\x{0A6F}\x{0AE6}-\x{0AEF}\x{0B66}-\x{0B6F}] |
[\x{0BE7}-\x{0BEF}\x{0C66}-\x{0C6F}\x{0CE6}-\x{0CEF}\x{0D66}-\x{0D6F}] |
[\x{0E50}-\x{0E59}\x{0ED0}-\x{0ED9}\x{0F20}-\x{0F29}]
/x;

    $CombiningChar = qr/
[\x{0300}-\x{0345}\x{0360}-\x{0361}\x{0483}-\x{0486}\x{0591}-\x{05A1}] |
[\x{05A3}-\x{05B9}\x{05BB}-\x{05BD}\x{05BF}\x{05C1}-\x{05C2}\x{05C4}] |
[\x{064B}-\x{0652}\x{0670}\x{06D6}-\x{06DC}\x{06DD}-\x{06DF}\x{06E0}-\x{06E4}] |
[\x{06E7}-\x{06E8}\x{06EA}-\x{06ED}\x{0901}-\x{0903}\x{093C}] |
[\x{093E}-\x{094C}\x{094D}\x{0951}-\x{0954}\x{0962}-\x{0963}\x{0981}-\x{0983}] |
[\x{09BC}\x{09BE}\x{09BF}\x{09C0}-\x{09C4}\x{09C7}-\x{09C8}] |
[\x{09CB}-\x{09CD}\x{09D7}\x{09E2}-\x{09E3}\x{0A02}\x{0A3C}\x{0A3E}\x{0A3F}] |
[\x{0A40}-\x{0A42}\x{0A47}-\x{0A48}\x{0A4B}-\x{0A4D}\x{0A70}-\x{0A71}] |
[\x{0A81}-\x{0A83}\x{0ABC}\x{0ABE}-\x{0AC5}\x{0AC7}-\x{0AC9}\x{0ACB}-\x{0ACD}] |
[\x{0B01}-\x{0B03}\x{0B3C}\x{0B3E}-\x{0B43}\x{0B47}-\x{0B48}] |
[\x{0B4B}-\x{0B4D}\x{0B56}-\x{0B57}\x{0B82}-\x{0B83}\x{0BBE}-\x{0BC2}] |
[\x{0BC6}-\x{0BC8}\x{0BCA}-\x{0BCD}\x{0BD7}\x{0C01}-\x{0C03}\x{0C3E}-\x{0C44}] |
[\x{0C46}-\x{0C48}\x{0C4A}-\x{0C4D}\x{0C55}-\x{0C56}\x{0C82}-\x{0C83}] |
[\x{0CBE}-\x{0CC4}\x{0CC6}-\x{0CC8}\x{0CCA}-\x{0CCD}\x{0CD5}-\x{0CD6}] |
[\x{0D02}-\x{0D03}\x{0D3E}-\x{0D43}\x{0D46}-\x{0D48}\x{0D4A}-\x{0D4D}\x{0D57}] |
[\x{0E31}\x{0E34}-\x{0E3A}\x{0E47}-\x{0E4E}\x{0EB1}\x{0EB4}-\x{0EB9}] |
[\x{0EBB}-\x{0EBC}\x{0EC8}-\x{0ECD}\x{0F18}-\x{0F19}\x{0F35}\x{0F37}\x{0F39}] |
[\x{0F3E}\x{0F3F}\x{0F71}-\x{0F84}\x{0F86}-\x{0F8B}\x{0F90}-\x{0F95}] |
[\x{0F97}\x{0F99}-\x{0FAD}\x{0FB1}-\x{0FB7}\x{0FB9}\x{20D0}-\x{20DC}\x{20E1}] |
[\x{302A}-\x{302F}\x{3099}\x{309A}]
/x;

    $Ideographic = qr/
[\x{4E00}-\x{9FA5}\x{3007}\x{3021}-\x{3029}]
/x;

    $NameChar = qr/^ (?: $BaseChar | $Ideographic | $Digit | [._:-] | $CombiningChar | $Extender )+ $/x;
    PERL

    die $@ if $@;
}

}

1;
PK7N%[��*�WW&perl5/XML/SAX/PurePerl/DebugHandler.pmnu��6�$# $Id$

package XML::SAX::PurePerl::DebugHandler;

use strict;

sub new {
    my $class = shift;
    my %opts = @_;
    return bless \%opts, $class;
}

# DocumentHandler

sub set_document_locator {
    my $self = shift;
    print "set_document_locator\n" if $ENV{DEBUG_XML};
    $self->{seen}{set_document_locator}++;
}

sub start_document {
    my $self = shift;
    print "start_document\n" if $ENV{DEBUG_XML};
    $self->{seen}{start_document}++;    
}

sub end_document {
    my $self = shift;
    print "end_document\n" if $ENV{DEBUG_XML};
    $self->{seen}{end_document}++;
}

sub start_element {
    my $self = shift;
    print "start_element\n" if $ENV{DEBUG_XML};
    $self->{seen}{start_element}++;
}

sub end_element {
    my $self = shift;
    print "end_element\n" if $ENV{DEBUG_XML};
    $self->{seen}{end_element}++;
}

sub characters {
    my $self = shift;
    print "characters\n" if $ENV{DEBUG_XML};
#    warn "Char: ", $_[0]->{Data}, "\n";
    $self->{seen}{characters}++;
}

sub processing_instruction {
    my $self = shift;
    print "processing_instruction\n" if $ENV{DEBUG_XML};
    $self->{seen}{processing_instruction}++;
}

sub ignorable_whitespace {
    my $self = shift;
    print "ignorable_whitespace\n" if $ENV{DEBUG_XML};
    $self->{seen}{ignorable_whitespace}++;
}

# LexHandler

sub comment {
    my $self = shift;
    print "comment\n" if $ENV{DEBUG_XML};
    $self->{seen}{comment}++;
}

# DTDHandler

sub notation_decl {
    my $self = shift;
    print "notation_decl\n" if $ENV{DEBUG_XML};
    $self->{seen}{notation_decl}++;
}

sub unparsed_entity_decl {
    my $self = shift;
    print "unparsed_entity_decl\n" if $ENV{DEBUG_XML};
    $self->{seen}{entity_decl}++;
}

# EntityResolver

sub resolve_entity {
    my $self = shift;
    print "resolve_entity\n" if $ENV{DEBUG_XML};
    $self->{seen}{resolve_entity}++;
    return '';
}

1;
PK7N%[h=�
��perl5/XML/SAX/ParserFactory.pmnu��6�$# $Id$

package XML::SAX::ParserFactory;

use strict;
use vars qw($VERSION);

$VERSION = '1.02';

use Symbol qw(gensym);
use XML::SAX;
use XML::SAX::Exception;

sub new {
    my $class = shift;
    my %params = @_; # TODO : Fix this in spec.
    my $self = bless \%params, $class;
    $self->{KnownParsers} = XML::SAX->parsers();
    return $self;
}

sub parser {
    my $self = shift;
    my @parser_params = @_;
    if (!ref($self)) {
        $self = $self->new();
    }
    
    my $parser_class = $self->_parser_class();

    my $version = '';
    if ($parser_class =~ s/\s*\(([\d\.]+)\)\s*$//) {
        $version = " $1";
    }

    if (!$parser_class->can('new')) {
        eval "require $parser_class $version;";
        die $@ if $@;
    }

    return $parser_class->new(@parser_params);
}

sub require_feature {
    my $self = shift;
    my ($feature) = @_;
    $self->{RequiredFeatures}{$feature}++;
    return $self;
}

sub _parser_class {
    my $self = shift;

    # First try ParserPackage
    if ($XML::SAX::ParserPackage) {
        return $XML::SAX::ParserPackage;
    }

    # Now check if required/preferred is there
    if ($self->{RequiredFeatures}) {
        my %required = %{$self->{RequiredFeatures}};
        # note - we never go onto the next try (ParserDetails.ini),
        # because if we can't provide the requested feature
        # we need to throw an exception.
        PARSER:
        foreach my $parser (reverse @{$self->{KnownParsers}}) {
            foreach my $feature (keys %required) {
                if (!exists $parser->{Features}{$feature}) {
                    next PARSER;
                }
            }
            # got here - all features must exist!
            return $parser->{Name};
        }
        # TODO : should this be NotSupported() ?
        throw XML::SAX::Exception (
                Message => "Unable to provide required features",
            );
    }

    # Next try SAX.ini
    for my $dir (@INC) {
        my $fh = gensym();
        if (open($fh, "$dir/SAX.ini")) {
            my $param_list = XML::SAX->_parse_ini_file($fh);
            my $params = $param_list->[0]->{Features};
            if ($params->{ParserPackage}) {
                return $params->{ParserPackage};
            }
            else {
                # we have required features (or nothing?)
                PARSER:
                foreach my $parser (reverse @{$self->{KnownParsers}}) {
                    foreach my $feature (keys %$params) {
                        if (!exists $parser->{Features}{$feature}) {
                            next PARSER;
                        }
                    }
                    return $parser->{Name};
                }
                XML::SAX->do_warn("Unable to provide SAX.ini required features. Using fallback\n");
            } 
            last; # stop after first INI found
        }
    }

    if (@{$self->{KnownParsers}}) {
        return $self->{KnownParsers}[-1]{Name};
    }
    else {
        return "XML::SAX::PurePerl"; # backup plan!
    }
}

1;
__END__

=head1 NAME

XML::SAX::ParserFactory - Obtain a SAX parser

=head1 SYNOPSIS

  use XML::SAX::ParserFactory;
  use XML::SAX::XYZHandler;
  my $handler = XML::SAX::XYZHandler->new();
  my $p = XML::SAX::ParserFactory->parser(Handler => $handler);
  $p->parse_uri("foo.xml");
  # or $p->parse_string("<foo/>") or $p->parse_file($fh);

=head1 DESCRIPTION

XML::SAX::ParserFactory is a factory class for providing an application
with a Perl SAX2 XML parser. It is akin to DBI - a front end for other
parser classes. Each new SAX2 parser installed will register itself
with XML::SAX, and then it will become available to all applications
that use XML::SAX::ParserFactory to obtain a SAX parser.

Unlike DBI however, XML/SAX parsers almost all work alike (especially
if they subclass XML::SAX::Base, as they should), so rather than
specifying the parser you want in the call to C<parser()>, XML::SAX
has several ways to automatically choose which parser to use:

=over 4

=item * $XML::SAX::ParserPackage

If this package variable is set, then this package is C<require()>d
and an instance of this package is returned by calling the C<new()>
class method in that package. If it cannot be loaded or there is
an error, an exception will be thrown. The variable can also contain
a version number:

  $XML::SAX::ParserPackage = "XML::SAX::Expat (0.72)";

And the number will be treated as a minimum version number.

=item * Required features

It is possible to require features from the parsers. For example, you
may wish for a parser that supports validation via a DTD. To do that,
use the following code:

  use XML::SAX::ParserFactory;
  my $factory = XML::SAX::ParserFactory->new();
  $factory->require_feature('http://xml.org/sax/features/validation');
  my $parser = $factory->parser(...);

Alternatively, specify the required features in the call to the
ParserFactory constructor:

  my $factory = XML::SAX::ParserFactory->new(
          RequiredFeatures => {
               'http://xml.org/sax/features/validation' => 1,
               }
          );

If the features you have asked for are unavailable (for example the
user might not have a validating parser installed), then an
exception will be thrown.

The list of known parsers is searched in reverse order, so it will
always return the last installed parser that supports all of your
requested features (Note: this is subject to change if someone
comes up with a better way of making this work).

=item * SAX.ini

ParserFactory will search @INC for a file called SAX.ini, which
is in a simple format:

  # a comment looks like this,
  ; or like this, and are stripped anywhere in the file
  key = value # SAX.in contains key/value pairs.

All whitespace is non-significant.

This file can contain either a line:

  ParserPackage = MyParserModule (1.02)

Where MyParserModule is the module to load and use for the parser,
and the number in brackets is a minimum version to load.

Or you can list required features:

  http://xml.org/sax/features/validation = 1

And each feature with a true value will be required.

=item * Fallback

If none of the above works, the last parser installed on the user's
system will be used. The XML::SAX package ships with a pure perl
XML parser, XML::SAX::PurePerl, so that there will always be a
fallback parser.

=back

=head1 AUTHOR

Matt Sergeant, matt@sergeant.org

=head1 LICENSE

This is free software, you may use it and distribute it under the same
terms as Perl itself.

=cut

PK7N%[�9ms��perl5/XML/SAX/Exception.pmnu��6�$package XML::SAX::Exception;
$XML::SAX::Exception::VERSION = '1.09';
use strict;

use overload '""' => "stringify",
    'fallback' => 1;

use vars qw($StackTrace);

use Carp;

$StackTrace = $ENV{XML_DEBUG} || 0;

# Other exception classes:

@XML::SAX::Exception::NotRecognized::ISA = ('XML::SAX::Exception');
@XML::SAX::Exception::NotSupported::ISA = ('XML::SAX::Exception');
@XML::SAX::Exception::Parse::ISA = ('XML::SAX::Exception');


sub throw {
    my $class = shift;
    if (ref($class)) {
        die $class;
    }
    die $class->new(@_);
}

sub new {
    my $class = shift;
    my %opts = @_;
    confess "Invalid options: " . join(', ', keys %opts) unless exists $opts{Message};
    
    bless { ($StackTrace ? (StackTrace => stacktrace()) : ()), %opts },
        $class;
}

sub stringify {
    my $self = shift;
    local $^W;
    my $error;
    if (exists $self->{LineNumber}) {
        $error = $self->{Message} . " [Ln: " . $self->{LineNumber} . 
                ", Col: " . $self->{ColumnNumber} . "]";
    }
    else {
        $error = $self->{Message};
    }
    if ($StackTrace) {
        $error .= stackstring($self->{StackTrace});
    }
    $error .= "\n";
    return $error;
}

sub stacktrace {
    my $i = 2;
    my @fulltrace;
    while (my @trace = caller($i++)) {
        my %hash;
        @hash{qw(Package Filename Line)} = @trace[0..2];
        push @fulltrace, \%hash;
    }
    return \@fulltrace;
}

sub stackstring {
    my $stacktrace = shift;
    my $string = "\nFrom:\n";
    foreach my $current (@$stacktrace) {
        $string .= $current->{Filename} . " Line: " . $current->{Line} . "\n";
    }
    return $string;
}

1;

__END__

=head1 NAME

XML::SAX::Exception - Exception classes for XML::SAX

=head1 SYNOPSIS

  throw XML::SAX::Exception::NotSupported(
          Message => "The foo feature is not supported",
          );

=head1 DESCRIPTION

This module is the base class for all SAX Exceptions, those defined in
the spec as well as those that one may create for one's own SAX errors.

There are three subclasses included, corresponding to those of the SAX
spec:

  XML::SAX::Exception::NotSupported
  XML::SAX::Exception::NotRecognized
  XML::SAX::Exception::Parse

Use them wherever you want, and as much as possible when you encounter
such errors. SAX is meant to use exceptions as much as possible to 
flag problems.

=head1 CREATING NEW EXCEPTION CLASSES

All you need to do to create a new exception class is:

  @XML::SAX::Exception::MyException::ISA = ('XML::SAX::Exception')

The given package doesn't need to exist, it'll behave correctly this 
way. If your exception refines an existing exception class, then you
may also inherit from that instead of from the base class.

=head1 THROWING EXCEPTIONS

This is as simple as exemplified in the SYNOPSIS. In fact, there's 
nothing more to know. All you have to do is:

  throw XML::SAX::Exception::MyException( Message => 'Something went wrong' );

and voila, you've thrown an exception which can be caught in an eval block.

=cut

PK7N%[u��=�9�9perl5/XML/SAX/Intro.podnu��6�$=head1 NAME

XML::SAX::Intro - An Introduction to SAX Parsing with Perl

=head1 Introduction

XML::SAX is a new way to work with XML Parsers in Perl. In this article
we'll discuss why you should be using SAX, why you should be using
XML::SAX, and we'll see some of the finer implementation details. The
text below assumes some familiarity with callback, or push based
parsing, but if you are unfamiliar with these techniques then a good
place to start is Kip Hampton's excellent series of articles on XML.com.

=head1 Replacing XML::Parser

The de-facto way of parsing XML under perl is to use Larry Wall and
Clark Cooper's XML::Parser. This module is a Perl and XS wrapper around
the expat XML parser library by James Clark. It has been a hugely
successful project, but suffers from a couple of rather major flaws.
Firstly it is a proprietary API, designed before the SAX API was
conceived, which means that it is not easily replaceable by other
streaming parsers. Secondly it's callbacks are subrefs. This doesn't
sound like much of an issue, but unfortunately leads to code like:

  sub handle_start {
    my ($e, $el, %attrs) = @_;
    if ($el eq 'foo') {
      $e->{inside_foo}++; # BAD! $e is an XML::Parser::Expat object.
    }
  }

As you can see, we're using the $e object to hold our state
information, which is a bad idea because we don't own that object - we
didn't create it. It's an internal object of XML::Parser, that happens
to be a hashref. We could all too easily overwrite XML::Parser internal
state variables by using this, or Clark could change it to an array ref
(not that he would, because it would break so much code, but he could).

The only way currently with XML::Parser to safely maintain state is to
use a closure:

  my $state = MyState->new();
  $parser->setHandlers(Start => sub { handle_start($state, @_) });

This closure traps the $state variable, which now gets passed as the
first parameter to your callback. Unfortunately very few people use
this technique, as it is not documented in the XML::Parser POD files.

Another reason you might not want to use XML::Parser is because you
need some feature that it doesn't provide (such as validation), or you
might need to use a library that doesn't use expat, due to it not being
installed on your system, or due to having a restrictive ISP. Using SAX
allows you to work around these restrictions.

=head1 Introducing SAX

SAX stands for the Simple API for XML. And simple it really is.
Constructing a SAX parser and passing events to handlers is done as
simply as:

  use XML::SAX;
  use MySAXHandler;
  
  my $parser = XML::SAX::ParserFactory->parser(
  	Handler => MySAXHandler->new
  );
  
  $parser->parse_uri("foo.xml");

The important concept to grasp here is that SAX uses a factory class
called XML::SAX::ParserFactory to create a new parser instance. The
reason for this is so that you can support other underlying
parser implementations for different feature sets. This is one thing
that XML::Parser has always sorely lacked.

In the code above we see the parse_uri method used, but we could
have equally well
called parse_file, parse_string, or parse(). Please see XML::SAX::Base
for what these methods take as parameters, but don't be fooled into
believing parse_file takes a filename. No, it takes a file handle, a
glob, or a subclass of IO::Handle. Beware.

SAX works very similarly to XML::Parser's default callback method,
except it has one major difference: rather than setting individual
callbacks, you create a new class in which to receive the callbacks.
Each callback is called as a method call on an instance of that handler
class. An example will best demonstrate this:

  package MySAXHandler;
  use base qw(XML::SAX::Base);
  
  sub start_document {
    my ($self, $doc) = @_;
    # process document start event
  }
  
  sub start_element {
    my ($self, $el) = @_;
    # process element start event
  }

Now, when we instantiate this as above, and parse some XML with this as
the handler, the methods start_document and start_element will be
called as method calls, so this would be the equivalent of directly
calling:

  $object->start_element($el);

Notice how this is different to XML::Parser's calling style, which
calls:

  start_element($e, $name, %attribs);

It's the difference between function calling and method calling which
allows you to subclass SAX handlers which contributes to SAX being a
powerful solution.

As you can see, unlike XML::Parser, we have to define a new package in
which to do our processing (there are hacks you can do to make this
uneccessary, but I'll leave figuring those out to the experts). The
biggest benefit of this is that you maintain your own state variable
($self in the above example) thus freeing you of the concerns listed
above. It is also an improvement in maintainability - you can place the
code in a separate file if you wish to, and your callback methods are
always called the same thing, rather than having to choose a suitable
name for them as you had to with XML::Parser. This is an obvious win.

SAX parsers are also very flexible in how you pass a handler to them.
You can use a constructor parameter as we saw above, or we can pass the
handler directly in the call to one of the parse methods:

  $parser->parse(Handler => $handler, 
                 Source => { SystemId => "foo.xml" });
  # or...
  $parser->parse_file($fh, Handler => $handler);

This flexibility allows for one parser to be used in many different
scenarios throughout your script (though one shouldn't feel pressure to
use this method, as parser construction is generally not a time
consuming process).

=head1 Callback Parameters

The only other thing you need to know to understand basic SAX is the
structure of the parameters passed to each of the callbacks. In
XML::Parser, all parameters are passed as multiple options to the
callbacks, so for example the Start callback would be called as
my_start($e, $name, %attributes), and the PI callback would be called
as my_processing_instruction($e, $target, $data). In SAX, every
callback is passed a hash reference, containing entries that define our
"node". The key callbacks and the structures they receive are:

=head2 start_element

The start_element handler is called whenever a parser sees an opening
tag. It is passed an element structure consisting of:

=over 4

=item LocalName

The name of the element minus any namespace prefix it may
have come with in the document.

=item NamespaceURI

The URI of the namespace associated with this element,
or the empty string for none.

=item Attributes

A set of attributes as described below.

=item Name

The name of the element as it was seen in the document (i.e.
including any prefix associated with it)

=item Prefix

The prefix used to qualify this element's namespace, or the 
empty string if none.

=back

The B<Attributes> are a hash reference, keyed by what we have called
"James Clark" notation. This means that the attribute name has been
expanded to include any associated namespace URI, and put together as
{ns}name, where "ns" is the expanded namespace URI of the attribute if
and only if the attribute had a prefix, and "name" is the LocalName of
the attribute.

The value of each entry in the attributes hash is another hash
structure consisting of:

=over 4

=item LocalName

The name of the attribute minus any namespace prefix it may have
come with in the document.

=item NamespaceURI

The URI of the namespace associated with this attribute. If the 
attribute had no prefix, then this consists of just the empty string.

=item Name

The attribute's name as it appeared in the document, including any 
namespace prefix.

=item Prefix

The prefix used to qualify this attribute's namepace, or the 
empty string if none.

=item Value

The value of the attribute.

=back

So a full example, as output by Data::Dumper might be:

  ....

=head2 end_element

The end_element handler is called either when a parser sees a closing
tag, or after start_element has been called for an empty element (do
note however that a parser may if it is so inclined call characters
with an empty string when it sees an empty element. There is no simple
way in SAX to determine if the parser in fact saw an empty element, a
start and end element with no content..

The end_element handler receives exactly the same structure as
start_element, minus the Attributes entry. One must note though that it
should not be a reference to the same data as start_element receives,
so you may change the values in start_element but this will not affect
the values later seen by end_element.

=head2 characters

The characters callback may be called in serveral circumstances. The
most obvious one is when seeing ordinary character data in the markup.
But it is also called for text in a CDATA section, and is also called
in other situations. A SAX parser has to make no guarantees whatsoever
about how many times it may call characters for a stretch of text in an
XML document - it may call once, or it may call once for every
character in the text. In order to work around this it is often
important for the SAX developer to use a bundling technique, where text
is gathered up and processed in one of the other callbacks. This is not
always necessary, but it is a worthwhile technique to learn, which we
will cover in XML::SAX::Advanced (when I get around to writing it).

The characters handler is called with a very simple structure - a hash
reference consisting of just one entry:

=over 4

=item Data

The text data that was received.

=back

=head2 comment

The comment callback is called for comment text. Unlike with
C<characters()>, the comment callback *must* be invoked just once for an
entire comment string. It receives a single simple structure - a hash
reference containing just one entry:

=over 4

=item Data

The text of the comment.

=back

=head2 processing_instruction

The processing instruction handler is called for all processing
instructions in the document. Note that these processing instructions
may appear before the document root element, or after it, or anywhere
where text and elements would normally appear within the document,
according to the XML specification.

The handler is passed a structure containing just two entries:

=over 4

=item Target

The target of the processing instrcution

=item Data

The text data in the processing instruction. Can be an empty
string for a processing instruction that has no data element. 
For example E<lt>?wiggle?E<gt> is a perfectly valid processing instruction.

=back

=head1 Tip of the iceberg

What we have discussed above is really the tip of the SAX iceberg. And
so far it looks like there's not much of interest to SAX beyond what we
have seen with XML::Parser. But it does go much further than that, I
promise.

People who hate Object Oriented code for the sake of it may be thinking
here that creating a new package just to parse something is a waste
when they've been parsing things just fine up to now using procedural
code. But there's reason to all this madness. And that reason is SAX
Filters.

As you saw right at the very start, to let the parser know about our
class, we pass it an instance of our class as the Handler to the
parser. But now imagine what would happen if our class could also take
a Handler option, and simply do some processing and pass on our data
further down the line? That in a nutshell is how SAX filters work. It's
Unix pipes for the 21st century!

There are two downsides to this. Number 1 - writing SAX filters can be
tricky. If you look into the future and read the advanced tutorial I'm
writing, you'll see that Handler can come in several shapes and sizes.
So making sure your filter does the right thing can be tricky.
Secondly, constructing complex filter chains can be difficult, and
simple thinking tells us that we only get one pass at our document,
when often we'll need more than that.

Luckily though, those downsides have been fixed by the release of two
very cool modules. What's even better is that I didn't write either of
them!

The first module is XML::SAX::Base. This is a VITAL SAX module that
acts as a base class for all SAX parsers and filters. It provides an
abstraction away from calling the handler methods, that makes sure your
filter or parser does the right thing, and it does it FAST. So, if you
ever need to write a SAX filter, which if you're processing XML -> XML,
or XML -> HTML, then you probably do, then you need to be writing it as
a subclass of XML::SAX::Base. Really - this is advice not to ignore
lightly. I will not go into the details of writing a SAX filter here.
Kip Hampton, the author of XML::SAX::Base has covered this nicely in
his article on XML.com here <URI>.

To construct SAX pipelines, Barrie Slaymaker, a long time Perl hacker
whose modules you will probably have heard of or used, wrote a very
clever module called XML::SAX::Machines. This combines some really
clever SAX filter-type modules, with a construction toolkit for filters
that makes building pipelines easy. But before we see how it makes
things easy, first lets see how tricky it looks to build complex SAX
filter pipelines.

  use XML::SAX::ParserFactory;
  use XML::Filter::Filter1;
  use XML::Filter::Filter2;
  use XML::SAX::Writer;
  
  my $output_string;
  my $writer = XML::SAX::Writer->new(Output => \$output_string);
  my $filter2 = XML::SAX::Filter2->new(Handler => $writer);
  my $filter1 = XML::SAX::Filter1->new(Handler => $filter2);
  my $parser = XML::SAX::ParserFactory->parser(Handler => $filter1);
  
  $parser->parse_uri("foo.xml");

This is a lot easier with XML::SAX::Machines:

  use XML::SAX::Machines qw(Pipeline);
  
  my $output_string;
  my $parser = Pipeline(
  	XML::SAX::Filter1 => XML::SAX::Filter2 => \$output_string
  	);
  
  $parser->parse_uri("foo.xml");

One of the main benefits of XML::SAX::Machines is that the pipelines
are constructed in natural order, rather than the reverse order we saw
with manual pipeline construction. XML::SAX::Machines takes care of all
the internals of pipe construction, providing you at the end with just
a parser you can use (and you can re-use the same parser as many times
as you need to).

Just a final tip. If you ever get stuck and are confused about what is
being passed from one SAX filter or parser to the next, then
Devel::TraceSAX will come to your rescue. This perl debugger plugin
will allow you to dump the SAX stream of events as it goes by. Usage is
really very simple just call your perl script that uses SAX as follows:

  $ perl -d:TraceSAX <scriptname>

And preferably pipe the output to a pager of some sort, such as more or
less. The output is extremely verbose, but should help clear some
issues up.

=head1 AUTHOR

Matt Sergeant, matt@sergeant.org

$Id$

=cut
PK7N%[Q��BB perl5/XML/SAX/DocumentLocator.pmnu��6�$# $Id$

package XML::SAX::DocumentLocator;
use strict;

sub new {
    my $class = shift;
    my %object;
    tie %object, $class, @_;

    return bless \%object, $class;
}

sub TIEHASH {
    my $class = shift;
    my ($pubmeth, $sysmeth, $linemeth, $colmeth, $encmeth, $xmlvmeth) = @_;
    return bless { 
        pubmeth => $pubmeth,
        sysmeth => $sysmeth,
        linemeth => $linemeth,
        colmeth => $colmeth,
        encmeth => $encmeth,
        xmlvmeth => $xmlvmeth,
    }, $class;
}

sub FETCH {
    my ($self, $key) = @_;
    my $method;
    if ($key eq 'PublicId') {
        $method = $self->{pubmeth};
    }
    elsif ($key eq 'SystemId') {
        $method = $self->{sysmeth};
    }
    elsif ($key eq 'LineNumber') {
        $method = $self->{linemeth};
    }
    elsif ($key eq 'ColumnNumber') {
        $method = $self->{colmeth};
    }
    elsif ($key eq 'Encoding') {
        $method = $self->{encmeth};
    }
    elsif ($key eq 'XMLVersion') {
        $method = $self->{xmlvmeth};
    }
    if ($method) {
        my $value = $method->($key);
        return $value;
    }
    return undef;
}

sub EXISTS {
    my ($self, $key) = @_;
    if ($key =~ /^(PublicId|SystemId|LineNumber|ColumnNumber|Encoding|XMLVersion)$/) {
        return 1;
    }
    return 0;
}

sub STORE {
    my ($self, $key, $value) = @_;
}

sub DELETE {
    my ($self, $key) = @_;
}

sub CLEAR {
    my ($self) = @_;
}

sub FIRSTKEY {
    my ($self) = @_;
    # assignment resets.
    $self->{keys} = {
        PublicId => 1,
        SystemId => 1,
        LineNumber => 1,
        ColumnNumber => 1,
        Encoding => 1,
        XMLVersion => 1,
    };
    return each %{$self->{keys}};
}

sub NEXTKEY {
    my ($self, $lastkey) = @_;
    return each %{$self->{keys}};
}

1;
__END__

=head1 NAME

XML::SAX::DocumentLocator - Helper class for document locators

=head1 SYNOPSIS

  my $locator = XML::SAX::DocumentLocator->new(
      sub { $object->get_public_id },
      sub { $object->get_system_id },
      sub { $reader->current_line },
      sub { $reader->current_column },
      sub { $reader->get_encoding },
      sub { $reader->get_xml_version },
  );

=head1 DESCRIPTION

This module gives you a tied hash reference that calls the
specified closures when asked for PublicId, SystemId,
LineNumber and ColumnNumber.

It is useful for writing SAX Parsers so that you don't have
to constantly update the line numbers in a hash reference on
the object you pass to set_document_locator(). See the source
code for XML::SAX::PurePerl for a usage example.

=head1 API

There is only 1 method: C<new>. Simply pass it a list of
closures that when called will return the PublicId, the
SystemId, the LineNumber, the ColumnNumber, the Encoding 
and the XMLVersion respectively.

The closures are passed a single parameter, the key being
requested. But you're free to ignore that.

=cut

PK7N%[G�����perl5/XML/SAX/Base.pmnu��6�$package XML::SAX::Base;
$XML::SAX::Base::VERSION = '1.09';
# version 0.10 - Kip Hampton <khampton@totalcinema.com>
# version 0.13 - Robin Berjon <robin@knowscape.com>
# version 0.15 - Kip Hampton <khampton@totalcinema.com>
# version 0.17 - Kip Hampton <khampton@totalcinema.com>
# version 0.19 - Kip Hampton <khampton@totalcinema.com>
# version 0.21 - Kip Hampton <khampton@totalcinema.com>
# version 0.22 - Robin Berjon <robin@knowscape.com>
# version 0.23 - Matt Sergeant <matt@sergeant.org>
# version 0.24 - Robin Berjon <robin@knowscape.com>
# version 0.25 - Kip Hampton <khampton@totalcinema.com>
# version 1.00 - Kip Hampton <khampton@totalcinema.com>
# version 1.01 - Kip Hampton <khampton@totalcinema.com>
# version 1.02 - Robin Berjon <robin@knowscape.com>
# version 1.03 - Matt Sergeant <matt@sergeant.org>
# version 1.04 - Kip Hampton <khampton@totalcinema.com>
# version 1.05 - Grant McLean <grantm@cpan.org>
# version 1.06 - Grant McLean <grantm@cpan.org>
# version 1.07 - Grant McLean <grantm@cpan.org>
# version 1.08 - Grant McLean <grantm@cpan.org>

#-----------------------------------------------------#
# STOP!!!!!
#
# This file is generated by the 'BuildSAXBase.pl' file
# that ships with the XML::SAX::Base distribution.
# If you need to make changes, patch that file NOT
# XML/SAX/Base.pm  Better yet, fork the git repository
# commit your changes and send a pull request:
#   https://github.com/grantm/XML-SAX-Base
#-----------------------------------------------------#

use strict;

use XML::SAX::Exception qw();

sub end_entity {
    my $self = shift;
    if (defined $self->{Methods}->{'end_entity'}) {
        $self->{Methods}->{'end_entity'}->(@_);
    }
    else {
        my $method;
        my $callbacks;
        if (exists $self->{ParseOptions}) {
            $callbacks = $self->{ParseOptions};
        }
        else {
            $callbacks = $self;
        }
        if (0) { # dummy to make elsif's below compile
        }
        elsif (defined $callbacks->{'LexicalHandler'} and $method = $callbacks->{'LexicalHandler'}->can('end_entity') ) {
            my $handler = $callbacks->{'LexicalHandler'};
            $self->{Methods}->{'end_entity'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('end_entity') ) {
            my $handler = $callbacks->{'Handler'};
            $self->{Methods}->{'end_entity'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'LexicalHandler'} 
        	and $callbacks->{'LexicalHandler'}->can('AUTOLOAD')
        	and $callbacks->{'LexicalHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'LexicalHandler'}->end_entity(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'LexicalHandler'};
                $self->{Methods}->{'end_entity'} = sub { $handler->end_entity(@_) };
            }
            return $res;
        }
        elsif (defined $callbacks->{'Handler'} 
        	and $callbacks->{'Handler'}->can('AUTOLOAD')
        	and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'Handler'}->end_entity(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'Handler'};
                $self->{Methods}->{'end_entity'} = sub { $handler->end_entity(@_) };
            }
            return $res;
        }
        else {
            $self->{Methods}->{'end_entity'} = sub { };
        }
    }

}

sub set_document_locator {
    my $self = shift;
    if (defined $self->{Methods}->{'set_document_locator'}) {
        $self->{Methods}->{'set_document_locator'}->(@_);
    }
    else {
        my $method;
        my $callbacks;
        if (exists $self->{ParseOptions}) {
            $callbacks = $self->{ParseOptions};
        }
        else {
            $callbacks = $self;
        }
        if (0) { # dummy to make elsif's below compile
        }
        elsif (defined $callbacks->{'ContentHandler'} and $method = $callbacks->{'ContentHandler'}->can('set_document_locator') ) {
            my $handler = $callbacks->{'ContentHandler'};
            $self->{Methods}->{'set_document_locator'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'DocumentHandler'} and $method = $callbacks->{'DocumentHandler'}->can('set_document_locator') ) {
            my $handler = $callbacks->{'DocumentHandler'};
            $self->{Methods}->{'set_document_locator'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('set_document_locator') ) {
            my $handler = $callbacks->{'Handler'};
            $self->{Methods}->{'set_document_locator'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'ContentHandler'} 
        	and $callbacks->{'ContentHandler'}->can('AUTOLOAD')
        	and $callbacks->{'ContentHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'ContentHandler'}->set_document_locator(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'ContentHandler'};
                $self->{Methods}->{'set_document_locator'} = sub { $handler->set_document_locator(@_) };
            }
            return $res;
        }
        elsif (defined $callbacks->{'DocumentHandler'} 
        	and $callbacks->{'DocumentHandler'}->can('AUTOLOAD')
        	and $callbacks->{'DocumentHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'DocumentHandler'}->set_document_locator(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'DocumentHandler'};
                $self->{Methods}->{'set_document_locator'} = sub { $handler->set_document_locator(@_) };
            }
            return $res;
        }
        elsif (defined $callbacks->{'Handler'} 
        	and $callbacks->{'Handler'}->can('AUTOLOAD')
        	and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'Handler'}->set_document_locator(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'Handler'};
                $self->{Methods}->{'set_document_locator'} = sub { $handler->set_document_locator(@_) };
            }
            return $res;
        }
        else {
            $self->{Methods}->{'set_document_locator'} = sub { };
        }
    }

}

sub notation_decl {
    my $self = shift;
    if (defined $self->{Methods}->{'notation_decl'}) {
        $self->{Methods}->{'notation_decl'}->(@_);
    }
    else {
        my $method;
        my $callbacks;
        if (exists $self->{ParseOptions}) {
            $callbacks = $self->{ParseOptions};
        }
        else {
            $callbacks = $self;
        }
        if (0) { # dummy to make elsif's below compile
        }
        elsif (defined $callbacks->{'DTDHandler'} and $method = $callbacks->{'DTDHandler'}->can('notation_decl') ) {
            my $handler = $callbacks->{'DTDHandler'};
            $self->{Methods}->{'notation_decl'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('notation_decl') ) {
            my $handler = $callbacks->{'Handler'};
            $self->{Methods}->{'notation_decl'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'DTDHandler'} 
        	and $callbacks->{'DTDHandler'}->can('AUTOLOAD')
        	and $callbacks->{'DTDHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'DTDHandler'}->notation_decl(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'DTDHandler'};
                $self->{Methods}->{'notation_decl'} = sub { $handler->notation_decl(@_) };
            }
            return $res;
        }
        elsif (defined $callbacks->{'Handler'} 
        	and $callbacks->{'Handler'}->can('AUTOLOAD')
        	and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'Handler'}->notation_decl(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'Handler'};
                $self->{Methods}->{'notation_decl'} = sub { $handler->notation_decl(@_) };
            }
            return $res;
        }
        else {
            $self->{Methods}->{'notation_decl'} = sub { };
        }
    }

}

sub attlist_decl {
    my $self = shift;
    if (defined $self->{Methods}->{'attlist_decl'}) {
        $self->{Methods}->{'attlist_decl'}->(@_);
    }
    else {
        my $method;
        my $callbacks;
        if (exists $self->{ParseOptions}) {
            $callbacks = $self->{ParseOptions};
        }
        else {
            $callbacks = $self;
        }
        if (0) { # dummy to make elsif's below compile
        }
        elsif (defined $callbacks->{'DTDHandler'} and $method = $callbacks->{'DTDHandler'}->can('attlist_decl') ) {
            my $handler = $callbacks->{'DTDHandler'};
            $self->{Methods}->{'attlist_decl'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('attlist_decl') ) {
            my $handler = $callbacks->{'Handler'};
            $self->{Methods}->{'attlist_decl'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'DTDHandler'} 
        	and $callbacks->{'DTDHandler'}->can('AUTOLOAD')
        	and $callbacks->{'DTDHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'DTDHandler'}->attlist_decl(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'DTDHandler'};
                $self->{Methods}->{'attlist_decl'} = sub { $handler->attlist_decl(@_) };
            }
            return $res;
        }
        elsif (defined $callbacks->{'Handler'} 
        	and $callbacks->{'Handler'}->can('AUTOLOAD')
        	and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'Handler'}->attlist_decl(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'Handler'};
                $self->{Methods}->{'attlist_decl'} = sub { $handler->attlist_decl(@_) };
            }
            return $res;
        }
        else {
            $self->{Methods}->{'attlist_decl'} = sub { };
        }
    }

}

sub fatal_error {
    my $self = shift;
    if (defined $self->{Methods}->{'fatal_error'}) {
        $self->{Methods}->{'fatal_error'}->(@_);
    }
    else {
        my $method;
        my $callbacks;
        if (exists $self->{ParseOptions}) {
            $callbacks = $self->{ParseOptions};
        }
        else {
            $callbacks = $self;
        }
        if (0) { # dummy to make elsif's below compile
        }
        elsif (defined $callbacks->{'ErrorHandler'} and $method = $callbacks->{'ErrorHandler'}->can('fatal_error') ) {
            my $handler = $callbacks->{'ErrorHandler'};
            $self->{Methods}->{'fatal_error'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('fatal_error') ) {
            my $handler = $callbacks->{'Handler'};
            $self->{Methods}->{'fatal_error'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'ErrorHandler'} 
        	and $callbacks->{'ErrorHandler'}->can('AUTOLOAD')
        	and $callbacks->{'ErrorHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'ErrorHandler'}->fatal_error(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'ErrorHandler'};
                $self->{Methods}->{'fatal_error'} = sub { $handler->fatal_error(@_) };
            }
            return $res;
        }
        elsif (defined $callbacks->{'Handler'} 
        	and $callbacks->{'Handler'}->can('AUTOLOAD')
        	and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'Handler'}->fatal_error(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'Handler'};
                $self->{Methods}->{'fatal_error'} = sub { $handler->fatal_error(@_) };
            }
            return $res;
        }
        else {
            $self->{Methods}->{'fatal_error'} = sub { };
        }
    }

}

sub start_document {
    my $self = shift;
    if (defined $self->{Methods}->{'start_document'}) {
        $self->{Methods}->{'start_document'}->(@_);
    }
    else {
        my $method;
        my $callbacks;
        if (exists $self->{ParseOptions}) {
            $callbacks = $self->{ParseOptions};
        }
        else {
            $callbacks = $self;
        }
        if (0) { # dummy to make elsif's below compile
        }
        elsif (defined $callbacks->{'ContentHandler'} and $method = $callbacks->{'ContentHandler'}->can('start_document') ) {
            my $handler = $callbacks->{'ContentHandler'};
            $self->{Methods}->{'start_document'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'DocumentHandler'} and $method = $callbacks->{'DocumentHandler'}->can('start_document') ) {
            my $handler = $callbacks->{'DocumentHandler'};
            $self->{Methods}->{'start_document'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('start_document') ) {
            my $handler = $callbacks->{'Handler'};
            $self->{Methods}->{'start_document'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'ContentHandler'} 
        	and $callbacks->{'ContentHandler'}->can('AUTOLOAD')
        	and $callbacks->{'ContentHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'ContentHandler'}->start_document(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'ContentHandler'};
                $self->{Methods}->{'start_document'} = sub { $handler->start_document(@_) };
            }
            return $res;
        }
        elsif (defined $callbacks->{'DocumentHandler'} 
        	and $callbacks->{'DocumentHandler'}->can('AUTOLOAD')
        	and $callbacks->{'DocumentHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'DocumentHandler'}->start_document(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'DocumentHandler'};
                $self->{Methods}->{'start_document'} = sub { $handler->start_document(@_) };
            }
            return $res;
        }
        elsif (defined $callbacks->{'Handler'} 
        	and $callbacks->{'Handler'}->can('AUTOLOAD')
        	and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'Handler'}->start_document(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'Handler'};
                $self->{Methods}->{'start_document'} = sub { $handler->start_document(@_) };
            }
            return $res;
        }
        else {
            $self->{Methods}->{'start_document'} = sub { };
        }
    }

}

sub warning {
    my $self = shift;
    if (defined $self->{Methods}->{'warning'}) {
        $self->{Methods}->{'warning'}->(@_);
    }
    else {
        my $method;
        my $callbacks;
        if (exists $self->{ParseOptions}) {
            $callbacks = $self->{ParseOptions};
        }
        else {
            $callbacks = $self;
        }
        if (0) { # dummy to make elsif's below compile
        }
        elsif (defined $callbacks->{'ErrorHandler'} and $method = $callbacks->{'ErrorHandler'}->can('warning') ) {
            my $handler = $callbacks->{'ErrorHandler'};
            $self->{Methods}->{'warning'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('warning') ) {
            my $handler = $callbacks->{'Handler'};
            $self->{Methods}->{'warning'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'ErrorHandler'} 
        	and $callbacks->{'ErrorHandler'}->can('AUTOLOAD')
        	and $callbacks->{'ErrorHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'ErrorHandler'}->warning(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'ErrorHandler'};
                $self->{Methods}->{'warning'} = sub { $handler->warning(@_) };
            }
            return $res;
        }
        elsif (defined $callbacks->{'Handler'} 
        	and $callbacks->{'Handler'}->can('AUTOLOAD')
        	and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'Handler'}->warning(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'Handler'};
                $self->{Methods}->{'warning'} = sub { $handler->warning(@_) };
            }
            return $res;
        }
        else {
            $self->{Methods}->{'warning'} = sub { };
        }
    }

}

sub ignorable_whitespace {
    my $self = shift;
    if (defined $self->{Methods}->{'ignorable_whitespace'}) {
        $self->{Methods}->{'ignorable_whitespace'}->(@_);
    }
    else {
        my $method;
        my $callbacks;
        if (exists $self->{ParseOptions}) {
            $callbacks = $self->{ParseOptions};
        }
        else {
            $callbacks = $self;
        }
        if (0) { # dummy to make elsif's below compile
        }
        elsif (defined $callbacks->{'ContentHandler'} and $method = $callbacks->{'ContentHandler'}->can('ignorable_whitespace') ) {
            my $handler = $callbacks->{'ContentHandler'};
            $self->{Methods}->{'ignorable_whitespace'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'DocumentHandler'} and $method = $callbacks->{'DocumentHandler'}->can('ignorable_whitespace') ) {
            my $handler = $callbacks->{'DocumentHandler'};
            $self->{Methods}->{'ignorable_whitespace'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('ignorable_whitespace') ) {
            my $handler = $callbacks->{'Handler'};
            $self->{Methods}->{'ignorable_whitespace'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'ContentHandler'} 
        	and $callbacks->{'ContentHandler'}->can('AUTOLOAD')
        	and $callbacks->{'ContentHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'ContentHandler'}->ignorable_whitespace(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'ContentHandler'};
                $self->{Methods}->{'ignorable_whitespace'} = sub { $handler->ignorable_whitespace(@_) };
            }
            return $res;
        }
        elsif (defined $callbacks->{'DocumentHandler'} 
        	and $callbacks->{'DocumentHandler'}->can('AUTOLOAD')
        	and $callbacks->{'DocumentHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'DocumentHandler'}->ignorable_whitespace(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'DocumentHandler'};
                $self->{Methods}->{'ignorable_whitespace'} = sub { $handler->ignorable_whitespace(@_) };
            }
            return $res;
        }
        elsif (defined $callbacks->{'Handler'} 
        	and $callbacks->{'Handler'}->can('AUTOLOAD')
        	and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'Handler'}->ignorable_whitespace(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'Handler'};
                $self->{Methods}->{'ignorable_whitespace'} = sub { $handler->ignorable_whitespace(@_) };
            }
            return $res;
        }
        else {
            $self->{Methods}->{'ignorable_whitespace'} = sub { };
        }
    }

}

sub resolve_entity {
    my $self = shift;
    if (defined $self->{Methods}->{'resolve_entity'}) {
        $self->{Methods}->{'resolve_entity'}->(@_);
    }
    else {
        my $method;
        my $callbacks;
        if (exists $self->{ParseOptions}) {
            $callbacks = $self->{ParseOptions};
        }
        else {
            $callbacks = $self;
        }
        if (0) { # dummy to make elsif's below compile
        }
        elsif (defined $callbacks->{'EntityResolver'} and $method = $callbacks->{'EntityResolver'}->can('resolve_entity') ) {
            my $handler = $callbacks->{'EntityResolver'};
            $self->{Methods}->{'resolve_entity'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('resolve_entity') ) {
            my $handler = $callbacks->{'Handler'};
            $self->{Methods}->{'resolve_entity'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'EntityResolver'} 
        	and $callbacks->{'EntityResolver'}->can('AUTOLOAD')
        	and $callbacks->{'EntityResolver'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'EntityResolver'}->resolve_entity(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'EntityResolver'};
                $self->{Methods}->{'resolve_entity'} = sub { $handler->resolve_entity(@_) };
            }
            return $res;
        }
        elsif (defined $callbacks->{'Handler'} 
        	and $callbacks->{'Handler'}->can('AUTOLOAD')
        	and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'Handler'}->resolve_entity(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'Handler'};
                $self->{Methods}->{'resolve_entity'} = sub { $handler->resolve_entity(@_) };
            }
            return $res;
        }
        else {
            $self->{Methods}->{'resolve_entity'} = sub { };
        }
    }

}

sub external_entity_decl {
    my $self = shift;
    if (defined $self->{Methods}->{'external_entity_decl'}) {
        $self->{Methods}->{'external_entity_decl'}->(@_);
    }
    else {
        my $method;
        my $callbacks;
        if (exists $self->{ParseOptions}) {
            $callbacks = $self->{ParseOptions};
        }
        else {
            $callbacks = $self;
        }
        if (0) { # dummy to make elsif's below compile
        }
        elsif (defined $callbacks->{'DeclHandler'} and $method = $callbacks->{'DeclHandler'}->can('external_entity_decl') ) {
            my $handler = $callbacks->{'DeclHandler'};
            $self->{Methods}->{'external_entity_decl'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('external_entity_decl') ) {
            my $handler = $callbacks->{'Handler'};
            $self->{Methods}->{'external_entity_decl'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'DeclHandler'} 
        	and $callbacks->{'DeclHandler'}->can('AUTOLOAD')
        	and $callbacks->{'DeclHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'DeclHandler'}->external_entity_decl(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'DeclHandler'};
                $self->{Methods}->{'external_entity_decl'} = sub { $handler->external_entity_decl(@_) };
            }
            return $res;
        }
        elsif (defined $callbacks->{'Handler'} 
        	and $callbacks->{'Handler'}->can('AUTOLOAD')
        	and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'Handler'}->external_entity_decl(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'Handler'};
                $self->{Methods}->{'external_entity_decl'} = sub { $handler->external_entity_decl(@_) };
            }
            return $res;
        }
        else {
            $self->{Methods}->{'external_entity_decl'} = sub { };
        }
    }

}

sub entity_reference {
    my $self = shift;
    if (defined $self->{Methods}->{'entity_reference'}) {
        $self->{Methods}->{'entity_reference'}->(@_);
    }
    else {
        my $method;
        my $callbacks;
        if (exists $self->{ParseOptions}) {
            $callbacks = $self->{ParseOptions};
        }
        else {
            $callbacks = $self;
        }
        if (0) { # dummy to make elsif's below compile
        }
        elsif (defined $callbacks->{'DocumentHandler'} and $method = $callbacks->{'DocumentHandler'}->can('entity_reference') ) {
            my $handler = $callbacks->{'DocumentHandler'};
            $self->{Methods}->{'entity_reference'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('entity_reference') ) {
            my $handler = $callbacks->{'Handler'};
            $self->{Methods}->{'entity_reference'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'DocumentHandler'} 
        	and $callbacks->{'DocumentHandler'}->can('AUTOLOAD')
        	and $callbacks->{'DocumentHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'DocumentHandler'}->entity_reference(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'DocumentHandler'};
                $self->{Methods}->{'entity_reference'} = sub { $handler->entity_reference(@_) };
            }
            return $res;
        }
        elsif (defined $callbacks->{'Handler'} 
        	and $callbacks->{'Handler'}->can('AUTOLOAD')
        	and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'Handler'}->entity_reference(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'Handler'};
                $self->{Methods}->{'entity_reference'} = sub { $handler->entity_reference(@_) };
            }
            return $res;
        }
        else {
            $self->{Methods}->{'entity_reference'} = sub { };
        }
    }

}

sub start_entity {
    my $self = shift;
    if (defined $self->{Methods}->{'start_entity'}) {
        $self->{Methods}->{'start_entity'}->(@_);
    }
    else {
        my $method;
        my $callbacks;
        if (exists $self->{ParseOptions}) {
            $callbacks = $self->{ParseOptions};
        }
        else {
            $callbacks = $self;
        }
        if (0) { # dummy to make elsif's below compile
        }
        elsif (defined $callbacks->{'LexicalHandler'} and $method = $callbacks->{'LexicalHandler'}->can('start_entity') ) {
            my $handler = $callbacks->{'LexicalHandler'};
            $self->{Methods}->{'start_entity'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('start_entity') ) {
            my $handler = $callbacks->{'Handler'};
            $self->{Methods}->{'start_entity'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'LexicalHandler'} 
        	and $callbacks->{'LexicalHandler'}->can('AUTOLOAD')
        	and $callbacks->{'LexicalHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'LexicalHandler'}->start_entity(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'LexicalHandler'};
                $self->{Methods}->{'start_entity'} = sub { $handler->start_entity(@_) };
            }
            return $res;
        }
        elsif (defined $callbacks->{'Handler'} 
        	and $callbacks->{'Handler'}->can('AUTOLOAD')
        	and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'Handler'}->start_entity(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'Handler'};
                $self->{Methods}->{'start_entity'} = sub { $handler->start_entity(@_) };
            }
            return $res;
        }
        else {
            $self->{Methods}->{'start_entity'} = sub { };
        }
    }

}

sub end_dtd {
    my $self = shift;
    if (defined $self->{Methods}->{'end_dtd'}) {
        $self->{Methods}->{'end_dtd'}->(@_);
    }
    else {
        my $method;
        my $callbacks;
        if (exists $self->{ParseOptions}) {
            $callbacks = $self->{ParseOptions};
        }
        else {
            $callbacks = $self;
        }
        if (0) { # dummy to make elsif's below compile
        }
        elsif (defined $callbacks->{'LexicalHandler'} and $method = $callbacks->{'LexicalHandler'}->can('end_dtd') ) {
            my $handler = $callbacks->{'LexicalHandler'};
            $self->{Methods}->{'end_dtd'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('end_dtd') ) {
            my $handler = $callbacks->{'Handler'};
            $self->{Methods}->{'end_dtd'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'LexicalHandler'} 
        	and $callbacks->{'LexicalHandler'}->can('AUTOLOAD')
        	and $callbacks->{'LexicalHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'LexicalHandler'}->end_dtd(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'LexicalHandler'};
                $self->{Methods}->{'end_dtd'} = sub { $handler->end_dtd(@_) };
            }
            return $res;
        }
        elsif (defined $callbacks->{'Handler'} 
        	and $callbacks->{'Handler'}->can('AUTOLOAD')
        	and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'Handler'}->end_dtd(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'Handler'};
                $self->{Methods}->{'end_dtd'} = sub { $handler->end_dtd(@_) };
            }
            return $res;
        }
        else {
            $self->{Methods}->{'end_dtd'} = sub { };
        }
    }

}

sub element_decl {
    my $self = shift;
    if (defined $self->{Methods}->{'element_decl'}) {
        $self->{Methods}->{'element_decl'}->(@_);
    }
    else {
        my $method;
        my $callbacks;
        if (exists $self->{ParseOptions}) {
            $callbacks = $self->{ParseOptions};
        }
        else {
            $callbacks = $self;
        }
        if (0) { # dummy to make elsif's below compile
        }
        elsif (defined $callbacks->{'DeclHandler'} and $method = $callbacks->{'DeclHandler'}->can('element_decl') ) {
            my $handler = $callbacks->{'DeclHandler'};
            $self->{Methods}->{'element_decl'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('element_decl') ) {
            my $handler = $callbacks->{'Handler'};
            $self->{Methods}->{'element_decl'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'DeclHandler'} 
        	and $callbacks->{'DeclHandler'}->can('AUTOLOAD')
        	and $callbacks->{'DeclHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'DeclHandler'}->element_decl(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'DeclHandler'};
                $self->{Methods}->{'element_decl'} = sub { $handler->element_decl(@_) };
            }
            return $res;
        }
        elsif (defined $callbacks->{'Handler'} 
        	and $callbacks->{'Handler'}->can('AUTOLOAD')
        	and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'Handler'}->element_decl(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'Handler'};
                $self->{Methods}->{'element_decl'} = sub { $handler->element_decl(@_) };
            }
            return $res;
        }
        else {
            $self->{Methods}->{'element_decl'} = sub { };
        }
    }

}

sub start_element {
    my $self = shift;
    if (defined $self->{Methods}->{'start_element'}) {
        $self->{Methods}->{'start_element'}->(@_);
    }
    else {
        my $method;
        my $callbacks;
        if (exists $self->{ParseOptions}) {
            $callbacks = $self->{ParseOptions};
        }
        else {
            $callbacks = $self;
        }
        if (0) { # dummy to make elsif's below compile
        }
        elsif (defined $callbacks->{'ContentHandler'} and $method = $callbacks->{'ContentHandler'}->can('start_element') ) {
            my $handler = $callbacks->{'ContentHandler'};
            $self->{Methods}->{'start_element'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'DocumentHandler'} and $method = $callbacks->{'DocumentHandler'}->can('start_element') ) {
            my $handler = $callbacks->{'DocumentHandler'};
            $self->{Methods}->{'start_element'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('start_element') ) {
            my $handler = $callbacks->{'Handler'};
            $self->{Methods}->{'start_element'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'ContentHandler'} 
        	and $callbacks->{'ContentHandler'}->can('AUTOLOAD')
        	and $callbacks->{'ContentHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'ContentHandler'}->start_element(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'ContentHandler'};
                $self->{Methods}->{'start_element'} = sub { $handler->start_element(@_) };
            }
            return $res;
        }
        elsif (defined $callbacks->{'DocumentHandler'} 
        	and $callbacks->{'DocumentHandler'}->can('AUTOLOAD')
        	and $callbacks->{'DocumentHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'DocumentHandler'}->start_element(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'DocumentHandler'};
                $self->{Methods}->{'start_element'} = sub { $handler->start_element(@_) };
            }
            return $res;
        }
        elsif (defined $callbacks->{'Handler'} 
        	and $callbacks->{'Handler'}->can('AUTOLOAD')
        	and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'Handler'}->start_element(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'Handler'};
                $self->{Methods}->{'start_element'} = sub { $handler->start_element(@_) };
            }
            return $res;
        }
        else {
            $self->{Methods}->{'start_element'} = sub { };
        }
    }

}

sub error {
    my $self = shift;
    if (defined $self->{Methods}->{'error'}) {
        $self->{Methods}->{'error'}->(@_);
    }
    else {
        my $method;
        my $callbacks;
        if (exists $self->{ParseOptions}) {
            $callbacks = $self->{ParseOptions};
        }
        else {
            $callbacks = $self;
        }
        if (0) { # dummy to make elsif's below compile
        }
        elsif (defined $callbacks->{'ErrorHandler'} and $method = $callbacks->{'ErrorHandler'}->can('error') ) {
            my $handler = $callbacks->{'ErrorHandler'};
            $self->{Methods}->{'error'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('error') ) {
            my $handler = $callbacks->{'Handler'};
            $self->{Methods}->{'error'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'ErrorHandler'} 
        	and $callbacks->{'ErrorHandler'}->can('AUTOLOAD')
        	and $callbacks->{'ErrorHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'ErrorHandler'}->error(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'ErrorHandler'};
                $self->{Methods}->{'error'} = sub { $handler->error(@_) };
            }
            return $res;
        }
        elsif (defined $callbacks->{'Handler'} 
        	and $callbacks->{'Handler'}->can('AUTOLOAD')
        	and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'Handler'}->error(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'Handler'};
                $self->{Methods}->{'error'} = sub { $handler->error(@_) };
            }
            return $res;
        }
        else {
            $self->{Methods}->{'error'} = sub { };
        }
    }

}

sub xml_decl {
    my $self = shift;
    if (defined $self->{Methods}->{'xml_decl'}) {
        $self->{Methods}->{'xml_decl'}->(@_);
    }
    else {
        my $method;
        my $callbacks;
        if (exists $self->{ParseOptions}) {
            $callbacks = $self->{ParseOptions};
        }
        else {
            $callbacks = $self;
        }
        if (0) { # dummy to make elsif's below compile
        }
        elsif (defined $callbacks->{'DTDHandler'} and $method = $callbacks->{'DTDHandler'}->can('xml_decl') ) {
            my $handler = $callbacks->{'DTDHandler'};
            $self->{Methods}->{'xml_decl'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('xml_decl') ) {
            my $handler = $callbacks->{'Handler'};
            $self->{Methods}->{'xml_decl'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'DTDHandler'} 
        	and $callbacks->{'DTDHandler'}->can('AUTOLOAD')
        	and $callbacks->{'DTDHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'DTDHandler'}->xml_decl(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'DTDHandler'};
                $self->{Methods}->{'xml_decl'} = sub { $handler->xml_decl(@_) };
            }
            return $res;
        }
        elsif (defined $callbacks->{'Handler'} 
        	and $callbacks->{'Handler'}->can('AUTOLOAD')
        	and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'Handler'}->xml_decl(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'Handler'};
                $self->{Methods}->{'xml_decl'} = sub { $handler->xml_decl(@_) };
            }
            return $res;
        }
        else {
            $self->{Methods}->{'xml_decl'} = sub { };
        }
    }

}

sub end_document {
    my $self = shift;
    if (defined $self->{Methods}->{'end_document'}) {
        $self->{Methods}->{'end_document'}->(@_);
    }
    else {
        my $method;
        my $callbacks;
        if (exists $self->{ParseOptions}) {
            $callbacks = $self->{ParseOptions};
        }
        else {
            $callbacks = $self;
        }
        if (0) { # dummy to make elsif's below compile
        }
        elsif (defined $callbacks->{'ContentHandler'} and $method = $callbacks->{'ContentHandler'}->can('end_document') ) {
            my $handler = $callbacks->{'ContentHandler'};
            $self->{Methods}->{'end_document'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'DocumentHandler'} and $method = $callbacks->{'DocumentHandler'}->can('end_document') ) {
            my $handler = $callbacks->{'DocumentHandler'};
            $self->{Methods}->{'end_document'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('end_document') ) {
            my $handler = $callbacks->{'Handler'};
            $self->{Methods}->{'end_document'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'ContentHandler'} 
        	and $callbacks->{'ContentHandler'}->can('AUTOLOAD')
        	and $callbacks->{'ContentHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'ContentHandler'}->end_document(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'ContentHandler'};
                $self->{Methods}->{'end_document'} = sub { $handler->end_document(@_) };
            }
            return $res;
        }
        elsif (defined $callbacks->{'DocumentHandler'} 
        	and $callbacks->{'DocumentHandler'}->can('AUTOLOAD')
        	and $callbacks->{'DocumentHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'DocumentHandler'}->end_document(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'DocumentHandler'};
                $self->{Methods}->{'end_document'} = sub { $handler->end_document(@_) };
            }
            return $res;
        }
        elsif (defined $callbacks->{'Handler'} 
        	and $callbacks->{'Handler'}->can('AUTOLOAD')
        	and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'Handler'}->end_document(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'Handler'};
                $self->{Methods}->{'end_document'} = sub { $handler->end_document(@_) };
            }
            return $res;
        }
        else {
            $self->{Methods}->{'end_document'} = sub { };
        }
    }

}

sub attribute_decl {
    my $self = shift;
    if (defined $self->{Methods}->{'attribute_decl'}) {
        $self->{Methods}->{'attribute_decl'}->(@_);
    }
    else {
        my $method;
        my $callbacks;
        if (exists $self->{ParseOptions}) {
            $callbacks = $self->{ParseOptions};
        }
        else {
            $callbacks = $self;
        }
        if (0) { # dummy to make elsif's below compile
        }
        elsif (defined $callbacks->{'DeclHandler'} and $method = $callbacks->{'DeclHandler'}->can('attribute_decl') ) {
            my $handler = $callbacks->{'DeclHandler'};
            $self->{Methods}->{'attribute_decl'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('attribute_decl') ) {
            my $handler = $callbacks->{'Handler'};
            $self->{Methods}->{'attribute_decl'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'DeclHandler'} 
        	and $callbacks->{'DeclHandler'}->can('AUTOLOAD')
        	and $callbacks->{'DeclHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'DeclHandler'}->attribute_decl(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'DeclHandler'};
                $self->{Methods}->{'attribute_decl'} = sub { $handler->attribute_decl(@_) };
            }
            return $res;
        }
        elsif (defined $callbacks->{'Handler'} 
        	and $callbacks->{'Handler'}->can('AUTOLOAD')
        	and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'Handler'}->attribute_decl(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'Handler'};
                $self->{Methods}->{'attribute_decl'} = sub { $handler->attribute_decl(@_) };
            }
            return $res;
        }
        else {
            $self->{Methods}->{'attribute_decl'} = sub { };
        }
    }

}

sub internal_entity_decl {
    my $self = shift;
    if (defined $self->{Methods}->{'internal_entity_decl'}) {
        $self->{Methods}->{'internal_entity_decl'}->(@_);
    }
    else {
        my $method;
        my $callbacks;
        if (exists $self->{ParseOptions}) {
            $callbacks = $self->{ParseOptions};
        }
        else {
            $callbacks = $self;
        }
        if (0) { # dummy to make elsif's below compile
        }
        elsif (defined $callbacks->{'DeclHandler'} and $method = $callbacks->{'DeclHandler'}->can('internal_entity_decl') ) {
            my $handler = $callbacks->{'DeclHandler'};
            $self->{Methods}->{'internal_entity_decl'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('internal_entity_decl') ) {
            my $handler = $callbacks->{'Handler'};
            $self->{Methods}->{'internal_entity_decl'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'DeclHandler'} 
        	and $callbacks->{'DeclHandler'}->can('AUTOLOAD')
        	and $callbacks->{'DeclHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'DeclHandler'}->internal_entity_decl(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'DeclHandler'};
                $self->{Methods}->{'internal_entity_decl'} = sub { $handler->internal_entity_decl(@_) };
            }
            return $res;
        }
        elsif (defined $callbacks->{'Handler'} 
        	and $callbacks->{'Handler'}->can('AUTOLOAD')
        	and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'Handler'}->internal_entity_decl(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'Handler'};
                $self->{Methods}->{'internal_entity_decl'} = sub { $handler->internal_entity_decl(@_) };
            }
            return $res;
        }
        else {
            $self->{Methods}->{'internal_entity_decl'} = sub { };
        }
    }

}

sub doctype_decl {
    my $self = shift;
    if (defined $self->{Methods}->{'doctype_decl'}) {
        $self->{Methods}->{'doctype_decl'}->(@_);
    }
    else {
        my $method;
        my $callbacks;
        if (exists $self->{ParseOptions}) {
            $callbacks = $self->{ParseOptions};
        }
        else {
            $callbacks = $self;
        }
        if (0) { # dummy to make elsif's below compile
        }
        elsif (defined $callbacks->{'DTDHandler'} and $method = $callbacks->{'DTDHandler'}->can('doctype_decl') ) {
            my $handler = $callbacks->{'DTDHandler'};
            $self->{Methods}->{'doctype_decl'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('doctype_decl') ) {
            my $handler = $callbacks->{'Handler'};
            $self->{Methods}->{'doctype_decl'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'DTDHandler'} 
        	and $callbacks->{'DTDHandler'}->can('AUTOLOAD')
        	and $callbacks->{'DTDHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'DTDHandler'}->doctype_decl(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'DTDHandler'};
                $self->{Methods}->{'doctype_decl'} = sub { $handler->doctype_decl(@_) };
            }
            return $res;
        }
        elsif (defined $callbacks->{'Handler'} 
        	and $callbacks->{'Handler'}->can('AUTOLOAD')
        	and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'Handler'}->doctype_decl(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'Handler'};
                $self->{Methods}->{'doctype_decl'} = sub { $handler->doctype_decl(@_) };
            }
            return $res;
        }
        else {
            $self->{Methods}->{'doctype_decl'} = sub { };
        }
    }

}

sub unparsed_entity_decl {
    my $self = shift;
    if (defined $self->{Methods}->{'unparsed_entity_decl'}) {
        $self->{Methods}->{'unparsed_entity_decl'}->(@_);
    }
    else {
        my $method;
        my $callbacks;
        if (exists $self->{ParseOptions}) {
            $callbacks = $self->{ParseOptions};
        }
        else {
            $callbacks = $self;
        }
        if (0) { # dummy to make elsif's below compile
        }
        elsif (defined $callbacks->{'DTDHandler'} and $method = $callbacks->{'DTDHandler'}->can('unparsed_entity_decl') ) {
            my $handler = $callbacks->{'DTDHandler'};
            $self->{Methods}->{'unparsed_entity_decl'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('unparsed_entity_decl') ) {
            my $handler = $callbacks->{'Handler'};
            $self->{Methods}->{'unparsed_entity_decl'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'DTDHandler'} 
        	and $callbacks->{'DTDHandler'}->can('AUTOLOAD')
        	and $callbacks->{'DTDHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'DTDHandler'}->unparsed_entity_decl(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'DTDHandler'};
                $self->{Methods}->{'unparsed_entity_decl'} = sub { $handler->unparsed_entity_decl(@_) };
            }
            return $res;
        }
        elsif (defined $callbacks->{'Handler'} 
        	and $callbacks->{'Handler'}->can('AUTOLOAD')
        	and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'Handler'}->unparsed_entity_decl(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'Handler'};
                $self->{Methods}->{'unparsed_entity_decl'} = sub { $handler->unparsed_entity_decl(@_) };
            }
            return $res;
        }
        else {
            $self->{Methods}->{'unparsed_entity_decl'} = sub { };
        }
    }

}

sub skipped_entity {
    my $self = shift;
    if (defined $self->{Methods}->{'skipped_entity'}) {
        $self->{Methods}->{'skipped_entity'}->(@_);
    }
    else {
        my $method;
        my $callbacks;
        if (exists $self->{ParseOptions}) {
            $callbacks = $self->{ParseOptions};
        }
        else {
            $callbacks = $self;
        }
        if (0) { # dummy to make elsif's below compile
        }
        elsif (defined $callbacks->{'ContentHandler'} and $method = $callbacks->{'ContentHandler'}->can('skipped_entity') ) {
            my $handler = $callbacks->{'ContentHandler'};
            $self->{Methods}->{'skipped_entity'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('skipped_entity') ) {
            my $handler = $callbacks->{'Handler'};
            $self->{Methods}->{'skipped_entity'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'ContentHandler'} 
        	and $callbacks->{'ContentHandler'}->can('AUTOLOAD')
        	and $callbacks->{'ContentHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'ContentHandler'}->skipped_entity(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'ContentHandler'};
                $self->{Methods}->{'skipped_entity'} = sub { $handler->skipped_entity(@_) };
            }
            return $res;
        }
        elsif (defined $callbacks->{'Handler'} 
        	and $callbacks->{'Handler'}->can('AUTOLOAD')
        	and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'Handler'}->skipped_entity(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'Handler'};
                $self->{Methods}->{'skipped_entity'} = sub { $handler->skipped_entity(@_) };
            }
            return $res;
        }
        else {
            $self->{Methods}->{'skipped_entity'} = sub { };
        }
    }

}

sub end_prefix_mapping {
    my $self = shift;
    if (defined $self->{Methods}->{'end_prefix_mapping'}) {
        $self->{Methods}->{'end_prefix_mapping'}->(@_);
    }
    else {
        my $method;
        my $callbacks;
        if (exists $self->{ParseOptions}) {
            $callbacks = $self->{ParseOptions};
        }
        else {
            $callbacks = $self;
        }
        if (0) { # dummy to make elsif's below compile
        }
        elsif (defined $callbacks->{'ContentHandler'} and $method = $callbacks->{'ContentHandler'}->can('end_prefix_mapping') ) {
            my $handler = $callbacks->{'ContentHandler'};
            $self->{Methods}->{'end_prefix_mapping'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('end_prefix_mapping') ) {
            my $handler = $callbacks->{'Handler'};
            $self->{Methods}->{'end_prefix_mapping'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'ContentHandler'} 
        	and $callbacks->{'ContentHandler'}->can('AUTOLOAD')
        	and $callbacks->{'ContentHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'ContentHandler'}->end_prefix_mapping(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'ContentHandler'};
                $self->{Methods}->{'end_prefix_mapping'} = sub { $handler->end_prefix_mapping(@_) };
            }
            return $res;
        }
        elsif (defined $callbacks->{'Handler'} 
        	and $callbacks->{'Handler'}->can('AUTOLOAD')
        	and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'Handler'}->end_prefix_mapping(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'Handler'};
                $self->{Methods}->{'end_prefix_mapping'} = sub { $handler->end_prefix_mapping(@_) };
            }
            return $res;
        }
        else {
            $self->{Methods}->{'end_prefix_mapping'} = sub { };
        }
    }

}

sub characters {
    my $self = shift;
    if (defined $self->{Methods}->{'characters'}) {
        $self->{Methods}->{'characters'}->(@_);
    }
    else {
        my $method;
        my $callbacks;
        if (exists $self->{ParseOptions}) {
            $callbacks = $self->{ParseOptions};
        }
        else {
            $callbacks = $self;
        }
        if (0) { # dummy to make elsif's below compile
        }
        elsif (defined $callbacks->{'ContentHandler'} and $method = $callbacks->{'ContentHandler'}->can('characters') ) {
            my $handler = $callbacks->{'ContentHandler'};
            $self->{Methods}->{'characters'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'DocumentHandler'} and $method = $callbacks->{'DocumentHandler'}->can('characters') ) {
            my $handler = $callbacks->{'DocumentHandler'};
            $self->{Methods}->{'characters'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('characters') ) {
            my $handler = $callbacks->{'Handler'};
            $self->{Methods}->{'characters'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'ContentHandler'} 
        	and $callbacks->{'ContentHandler'}->can('AUTOLOAD')
        	and $callbacks->{'ContentHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'ContentHandler'}->characters(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'ContentHandler'};
                $self->{Methods}->{'characters'} = sub { $handler->characters(@_) };
            }
            return $res;
        }
        elsif (defined $callbacks->{'DocumentHandler'} 
        	and $callbacks->{'DocumentHandler'}->can('AUTOLOAD')
        	and $callbacks->{'DocumentHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'DocumentHandler'}->characters(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'DocumentHandler'};
                $self->{Methods}->{'characters'} = sub { $handler->characters(@_) };
            }
            return $res;
        }
        elsif (defined $callbacks->{'Handler'} 
        	and $callbacks->{'Handler'}->can('AUTOLOAD')
        	and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'Handler'}->characters(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'Handler'};
                $self->{Methods}->{'characters'} = sub { $handler->characters(@_) };
            }
            return $res;
        }
        else {
            $self->{Methods}->{'characters'} = sub { };
        }
    }

}

sub comment {
    my $self = shift;
    if (defined $self->{Methods}->{'comment'}) {
        $self->{Methods}->{'comment'}->(@_);
    }
    else {
        my $method;
        my $callbacks;
        if (exists $self->{ParseOptions}) {
            $callbacks = $self->{ParseOptions};
        }
        else {
            $callbacks = $self;
        }
        if (0) { # dummy to make elsif's below compile
        }
        elsif (defined $callbacks->{'DocumentHandler'} and $method = $callbacks->{'DocumentHandler'}->can('comment') ) {
            my $handler = $callbacks->{'DocumentHandler'};
            $self->{Methods}->{'comment'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'LexicalHandler'} and $method = $callbacks->{'LexicalHandler'}->can('comment') ) {
            my $handler = $callbacks->{'LexicalHandler'};
            $self->{Methods}->{'comment'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('comment') ) {
            my $handler = $callbacks->{'Handler'};
            $self->{Methods}->{'comment'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'DocumentHandler'} 
        	and $callbacks->{'DocumentHandler'}->can('AUTOLOAD')
        	and $callbacks->{'DocumentHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'DocumentHandler'}->comment(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'DocumentHandler'};
                $self->{Methods}->{'comment'} = sub { $handler->comment(@_) };
            }
            return $res;
        }
        elsif (defined $callbacks->{'LexicalHandler'} 
        	and $callbacks->{'LexicalHandler'}->can('AUTOLOAD')
        	and $callbacks->{'LexicalHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'LexicalHandler'}->comment(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'LexicalHandler'};
                $self->{Methods}->{'comment'} = sub { $handler->comment(@_) };
            }
            return $res;
        }
        elsif (defined $callbacks->{'Handler'} 
        	and $callbacks->{'Handler'}->can('AUTOLOAD')
        	and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'Handler'}->comment(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'Handler'};
                $self->{Methods}->{'comment'} = sub { $handler->comment(@_) };
            }
            return $res;
        }
        else {
            $self->{Methods}->{'comment'} = sub { };
        }
    }

}

sub start_dtd {
    my $self = shift;
    if (defined $self->{Methods}->{'start_dtd'}) {
        $self->{Methods}->{'start_dtd'}->(@_);
    }
    else {
        my $method;
        my $callbacks;
        if (exists $self->{ParseOptions}) {
            $callbacks = $self->{ParseOptions};
        }
        else {
            $callbacks = $self;
        }
        if (0) { # dummy to make elsif's below compile
        }
        elsif (defined $callbacks->{'LexicalHandler'} and $method = $callbacks->{'LexicalHandler'}->can('start_dtd') ) {
            my $handler = $callbacks->{'LexicalHandler'};
            $self->{Methods}->{'start_dtd'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('start_dtd') ) {
            my $handler = $callbacks->{'Handler'};
            $self->{Methods}->{'start_dtd'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'LexicalHandler'} 
        	and $callbacks->{'LexicalHandler'}->can('AUTOLOAD')
        	and $callbacks->{'LexicalHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'LexicalHandler'}->start_dtd(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'LexicalHandler'};
                $self->{Methods}->{'start_dtd'} = sub { $handler->start_dtd(@_) };
            }
            return $res;
        }
        elsif (defined $callbacks->{'Handler'} 
        	and $callbacks->{'Handler'}->can('AUTOLOAD')
        	and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'Handler'}->start_dtd(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'Handler'};
                $self->{Methods}->{'start_dtd'} = sub { $handler->start_dtd(@_) };
            }
            return $res;
        }
        else {
            $self->{Methods}->{'start_dtd'} = sub { };
        }
    }

}

sub entity_decl {
    my $self = shift;
    if (defined $self->{Methods}->{'entity_decl'}) {
        $self->{Methods}->{'entity_decl'}->(@_);
    }
    else {
        my $method;
        my $callbacks;
        if (exists $self->{ParseOptions}) {
            $callbacks = $self->{ParseOptions};
        }
        else {
            $callbacks = $self;
        }
        if (0) { # dummy to make elsif's below compile
        }
        elsif (defined $callbacks->{'DTDHandler'} and $method = $callbacks->{'DTDHandler'}->can('entity_decl') ) {
            my $handler = $callbacks->{'DTDHandler'};
            $self->{Methods}->{'entity_decl'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('entity_decl') ) {
            my $handler = $callbacks->{'Handler'};
            $self->{Methods}->{'entity_decl'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'DTDHandler'} 
        	and $callbacks->{'DTDHandler'}->can('AUTOLOAD')
        	and $callbacks->{'DTDHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'DTDHandler'}->entity_decl(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'DTDHandler'};
                $self->{Methods}->{'entity_decl'} = sub { $handler->entity_decl(@_) };
            }
            return $res;
        }
        elsif (defined $callbacks->{'Handler'} 
        	and $callbacks->{'Handler'}->can('AUTOLOAD')
        	and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'Handler'}->entity_decl(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'Handler'};
                $self->{Methods}->{'entity_decl'} = sub { $handler->entity_decl(@_) };
            }
            return $res;
        }
        else {
            $self->{Methods}->{'entity_decl'} = sub { };
        }
    }

}

sub start_prefix_mapping {
    my $self = shift;
    if (defined $self->{Methods}->{'start_prefix_mapping'}) {
        $self->{Methods}->{'start_prefix_mapping'}->(@_);
    }
    else {
        my $method;
        my $callbacks;
        if (exists $self->{ParseOptions}) {
            $callbacks = $self->{ParseOptions};
        }
        else {
            $callbacks = $self;
        }
        if (0) { # dummy to make elsif's below compile
        }
        elsif (defined $callbacks->{'ContentHandler'} and $method = $callbacks->{'ContentHandler'}->can('start_prefix_mapping') ) {
            my $handler = $callbacks->{'ContentHandler'};
            $self->{Methods}->{'start_prefix_mapping'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('start_prefix_mapping') ) {
            my $handler = $callbacks->{'Handler'};
            $self->{Methods}->{'start_prefix_mapping'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'ContentHandler'} 
        	and $callbacks->{'ContentHandler'}->can('AUTOLOAD')
        	and $callbacks->{'ContentHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'ContentHandler'}->start_prefix_mapping(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'ContentHandler'};
                $self->{Methods}->{'start_prefix_mapping'} = sub { $handler->start_prefix_mapping(@_) };
            }
            return $res;
        }
        elsif (defined $callbacks->{'Handler'} 
        	and $callbacks->{'Handler'}->can('AUTOLOAD')
        	and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'Handler'}->start_prefix_mapping(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'Handler'};
                $self->{Methods}->{'start_prefix_mapping'} = sub { $handler->start_prefix_mapping(@_) };
            }
            return $res;
        }
        else {
            $self->{Methods}->{'start_prefix_mapping'} = sub { };
        }
    }

}

sub end_cdata {
    my $self = shift;
    if (defined $self->{Methods}->{'end_cdata'}) {
        $self->{Methods}->{'end_cdata'}->(@_);
    }
    else {
        my $method;
        my $callbacks;
        if (exists $self->{ParseOptions}) {
            $callbacks = $self->{ParseOptions};
        }
        else {
            $callbacks = $self;
        }
        if (0) { # dummy to make elsif's below compile
        }
        elsif (defined $callbacks->{'DocumentHandler'} and $method = $callbacks->{'DocumentHandler'}->can('end_cdata') ) {
            my $handler = $callbacks->{'DocumentHandler'};
            $self->{Methods}->{'end_cdata'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'LexicalHandler'} and $method = $callbacks->{'LexicalHandler'}->can('end_cdata') ) {
            my $handler = $callbacks->{'LexicalHandler'};
            $self->{Methods}->{'end_cdata'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('end_cdata') ) {
            my $handler = $callbacks->{'Handler'};
            $self->{Methods}->{'end_cdata'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'DocumentHandler'} 
        	and $callbacks->{'DocumentHandler'}->can('AUTOLOAD')
        	and $callbacks->{'DocumentHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'DocumentHandler'}->end_cdata(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'DocumentHandler'};
                $self->{Methods}->{'end_cdata'} = sub { $handler->end_cdata(@_) };
            }
            return $res;
        }
        elsif (defined $callbacks->{'LexicalHandler'} 
        	and $callbacks->{'LexicalHandler'}->can('AUTOLOAD')
        	and $callbacks->{'LexicalHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'LexicalHandler'}->end_cdata(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'LexicalHandler'};
                $self->{Methods}->{'end_cdata'} = sub { $handler->end_cdata(@_) };
            }
            return $res;
        }
        elsif (defined $callbacks->{'Handler'} 
        	and $callbacks->{'Handler'}->can('AUTOLOAD')
        	and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'Handler'}->end_cdata(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'Handler'};
                $self->{Methods}->{'end_cdata'} = sub { $handler->end_cdata(@_) };
            }
            return $res;
        }
        else {
            $self->{Methods}->{'end_cdata'} = sub { };
        }
    }

}

sub processing_instruction {
    my $self = shift;
    if (defined $self->{Methods}->{'processing_instruction'}) {
        $self->{Methods}->{'processing_instruction'}->(@_);
    }
    else {
        my $method;
        my $callbacks;
        if (exists $self->{ParseOptions}) {
            $callbacks = $self->{ParseOptions};
        }
        else {
            $callbacks = $self;
        }
        if (0) { # dummy to make elsif's below compile
        }
        elsif (defined $callbacks->{'ContentHandler'} and $method = $callbacks->{'ContentHandler'}->can('processing_instruction') ) {
            my $handler = $callbacks->{'ContentHandler'};
            $self->{Methods}->{'processing_instruction'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'DocumentHandler'} and $method = $callbacks->{'DocumentHandler'}->can('processing_instruction') ) {
            my $handler = $callbacks->{'DocumentHandler'};
            $self->{Methods}->{'processing_instruction'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('processing_instruction') ) {
            my $handler = $callbacks->{'Handler'};
            $self->{Methods}->{'processing_instruction'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'ContentHandler'} 
        	and $callbacks->{'ContentHandler'}->can('AUTOLOAD')
        	and $callbacks->{'ContentHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'ContentHandler'}->processing_instruction(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'ContentHandler'};
                $self->{Methods}->{'processing_instruction'} = sub { $handler->processing_instruction(@_) };
            }
            return $res;
        }
        elsif (defined $callbacks->{'DocumentHandler'} 
        	and $callbacks->{'DocumentHandler'}->can('AUTOLOAD')
        	and $callbacks->{'DocumentHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'DocumentHandler'}->processing_instruction(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'DocumentHandler'};
                $self->{Methods}->{'processing_instruction'} = sub { $handler->processing_instruction(@_) };
            }
            return $res;
        }
        elsif (defined $callbacks->{'Handler'} 
        	and $callbacks->{'Handler'}->can('AUTOLOAD')
        	and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'Handler'}->processing_instruction(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'Handler'};
                $self->{Methods}->{'processing_instruction'} = sub { $handler->processing_instruction(@_) };
            }
            return $res;
        }
        else {
            $self->{Methods}->{'processing_instruction'} = sub { };
        }
    }

}

sub end_element {
    my $self = shift;
    if (defined $self->{Methods}->{'end_element'}) {
        $self->{Methods}->{'end_element'}->(@_);
    }
    else {
        my $method;
        my $callbacks;
        if (exists $self->{ParseOptions}) {
            $callbacks = $self->{ParseOptions};
        }
        else {
            $callbacks = $self;
        }
        if (0) { # dummy to make elsif's below compile
        }
        elsif (defined $callbacks->{'ContentHandler'} and $method = $callbacks->{'ContentHandler'}->can('end_element') ) {
            my $handler = $callbacks->{'ContentHandler'};
            $self->{Methods}->{'end_element'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'DocumentHandler'} and $method = $callbacks->{'DocumentHandler'}->can('end_element') ) {
            my $handler = $callbacks->{'DocumentHandler'};
            $self->{Methods}->{'end_element'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('end_element') ) {
            my $handler = $callbacks->{'Handler'};
            $self->{Methods}->{'end_element'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'ContentHandler'} 
        	and $callbacks->{'ContentHandler'}->can('AUTOLOAD')
        	and $callbacks->{'ContentHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'ContentHandler'}->end_element(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'ContentHandler'};
                $self->{Methods}->{'end_element'} = sub { $handler->end_element(@_) };
            }
            return $res;
        }
        elsif (defined $callbacks->{'DocumentHandler'} 
        	and $callbacks->{'DocumentHandler'}->can('AUTOLOAD')
        	and $callbacks->{'DocumentHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'DocumentHandler'}->end_element(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'DocumentHandler'};
                $self->{Methods}->{'end_element'} = sub { $handler->end_element(@_) };
            }
            return $res;
        }
        elsif (defined $callbacks->{'Handler'} 
        	and $callbacks->{'Handler'}->can('AUTOLOAD')
        	and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'Handler'}->end_element(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'Handler'};
                $self->{Methods}->{'end_element'} = sub { $handler->end_element(@_) };
            }
            return $res;
        }
        else {
            $self->{Methods}->{'end_element'} = sub { };
        }
    }

}

sub start_cdata {
    my $self = shift;
    if (defined $self->{Methods}->{'start_cdata'}) {
        $self->{Methods}->{'start_cdata'}->(@_);
    }
    else {
        my $method;
        my $callbacks;
        if (exists $self->{ParseOptions}) {
            $callbacks = $self->{ParseOptions};
        }
        else {
            $callbacks = $self;
        }
        if (0) { # dummy to make elsif's below compile
        }
        elsif (defined $callbacks->{'DocumentHandler'} and $method = $callbacks->{'DocumentHandler'}->can('start_cdata') ) {
            my $handler = $callbacks->{'DocumentHandler'};
            $self->{Methods}->{'start_cdata'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'LexicalHandler'} and $method = $callbacks->{'LexicalHandler'}->can('start_cdata') ) {
            my $handler = $callbacks->{'LexicalHandler'};
            $self->{Methods}->{'start_cdata'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('start_cdata') ) {
            my $handler = $callbacks->{'Handler'};
            $self->{Methods}->{'start_cdata'} = sub { $method->($handler, @_) };
            return $method->($handler, @_);
        }
        elsif (defined $callbacks->{'DocumentHandler'} 
        	and $callbacks->{'DocumentHandler'}->can('AUTOLOAD')
        	and $callbacks->{'DocumentHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'DocumentHandler'}->start_cdata(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'DocumentHandler'};
                $self->{Methods}->{'start_cdata'} = sub { $handler->start_cdata(@_) };
            }
            return $res;
        }
        elsif (defined $callbacks->{'LexicalHandler'} 
        	and $callbacks->{'LexicalHandler'}->can('AUTOLOAD')
        	and $callbacks->{'LexicalHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'LexicalHandler'}->start_cdata(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'LexicalHandler'};
                $self->{Methods}->{'start_cdata'} = sub { $handler->start_cdata(@_) };
            }
            return $res;
        }
        elsif (defined $callbacks->{'Handler'} 
        	and $callbacks->{'Handler'}->can('AUTOLOAD')
        	and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my $res = eval { $callbacks->{'Handler'}->start_cdata(@_) };
            if ($@) {
                die $@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my $handler = $callbacks->{'Handler'};
                $self->{Methods}->{'start_cdata'} = sub { $handler->start_cdata(@_) };
            }
            return $res;
        }
        else {
            $self->{Methods}->{'start_cdata'} = sub { };
        }
    }

}

#-------------------------------------------------------------------#
# Class->new(%options)
#-------------------------------------------------------------------#
sub new {
    my $proto = shift;
    my $class = ref($proto) || $proto;
    my $options = ($#_ == 0) ? shift : { @_ };

    unless ( defined( $options->{Handler} )         or
             defined( $options->{ContentHandler} )  or
             defined( $options->{DTDHandler} )      or
             defined( $options->{DocumentHandler} ) or
             defined( $options->{LexicalHandler} )  or
             defined( $options->{ErrorHandler} )    or
             defined( $options->{DeclHandler} ) ) {
            
             $options->{Handler} = XML::SAX::Base::NoHandler->new;
    }

    my $self = bless $options, $class;
    # turn NS processing on by default
    $self->set_feature('http://xml.org/sax/features/namespaces', 1);
    return $self;
}
#-------------------------------------------------------------------#

#-------------------------------------------------------------------#
# $p->parse(%options)
#-------------------------------------------------------------------#
sub parse {
    my $self = shift;
    my $parse_options = $self->get_options(@_);
    local $self->{ParseOptions} = $parse_options;
    if ($self->{Parent}) { # calling parse on a filter for some reason
        return $self->{Parent}->parse($parse_options);
    }
    else {
        my $method;
        if (defined $parse_options->{Source}{CharacterStream} and $method = $self->can('_parse_characterstream')) {
            warn("parse charstream???\n");
            return $method->($self, $parse_options->{Source}{CharacterStream});
        }
        elsif (defined $parse_options->{Source}{ByteStream} and $method = $self->can('_parse_bytestream')) {
            return $method->($self, $parse_options->{Source}{ByteStream});
        }
        elsif (defined $parse_options->{Source}{String} and $method = $self->can('_parse_string')) {
            return $method->($self, $parse_options->{Source}{String});
        }
        elsif (defined $parse_options->{Source}{SystemId} and $method = $self->can('_parse_systemid')) {
            return $method->($self, $parse_options->{Source}{SystemId});
        }
        else {
            die "No _parse_* routine defined on this driver (If it is a filter, remember to set the Parent property. If you call the parse() method, make sure to set a Source. You may want to call parse_uri, parse_string or parse_file instead.) [$self]";
        }
    }
}
#-------------------------------------------------------------------#

#-------------------------------------------------------------------#
# $p->parse_file(%options)
#-------------------------------------------------------------------#
sub parse_file {
    my $self = shift;
    my $file = shift;
    return $self->parse_uri($file, @_) if ref(\$file) eq 'SCALAR';
    my $parse_options = $self->get_options(@_);
    $parse_options->{Source}{ByteStream} = $file;
    return $self->parse($parse_options);
}
#-------------------------------------------------------------------#

#-------------------------------------------------------------------#
# $p->parse_uri(%options)
#-------------------------------------------------------------------#
sub parse_uri {
    my $self = shift;
    my $file = shift;
    my $parse_options = $self->get_options(@_);
    $parse_options->{Source}{SystemId} = $file;
    return $self->parse($parse_options);
}
#-------------------------------------------------------------------#

#-------------------------------------------------------------------#
# $p->parse_string(%options)
#-------------------------------------------------------------------#
sub parse_string {
    my $self = shift;
    my $string = shift;
    my $parse_options = $self->get_options(@_);
    $parse_options->{Source}{String} = $string;
    return $self->parse($parse_options);
}
#-------------------------------------------------------------------#

#-------------------------------------------------------------------#
# get_options
#-------------------------------------------------------------------#
sub get_options {
    my $self = shift;

    if (@_ == 1) {
        return { %$self, %{$_[0]} };
    } else {
        return { %$self, @_ };
    }
}
#-------------------------------------------------------------------#

#-------------------------------------------------------------------#
# get_features
#-------------------------------------------------------------------#
sub get_features {
   return (
    'http://xml.org/sax/features/external-general-entities'     => undef,
    'http://xml.org/sax/features/external-parameter-entities'   => undef,
    'http://xml.org/sax/features/is-standalone'                 => undef,
    'http://xml.org/sax/features/lexical-handler'               => undef,
    'http://xml.org/sax/features/parameter-entities'            => undef,
    'http://xml.org/sax/features/namespaces'                    => 1,
    'http://xml.org/sax/features/namespace-prefixes'            => 0,
    'http://xml.org/sax/features/string-interning'              => undef,
    'http://xml.org/sax/features/use-attributes2'               => undef,
    'http://xml.org/sax/features/use-locator2'                  => undef,
    'http://xml.org/sax/features/validation'                    => undef,

    'http://xml.org/sax/properties/dom-node'                    => undef,
    'http://xml.org/sax/properties/xml-string'                  => undef,
               );
}
#-------------------------------------------------------------------#

#-------------------------------------------------------------------#
# get_feature
#-------------------------------------------------------------------#
sub get_feature {
    my $self = shift;
    my $feat = shift;

    # check %FEATURES to see if it's there, and return it if so
    # throw XML::SAX::Exception::NotRecognized if it's not there
    # throw XML::SAX::Exception::NotSupported if it's there but we
    # don't support it
    
    my %features = $self->get_features();
    if (exists $features{$feat}) {
        my %supported = map { $_ => 1 } $self->supported_features();
        if ($supported{$feat}) {
            return $self->{__PACKAGE__ . "::Features"}{$feat};
        }
        throw XML::SAX::Exception::NotSupported(
            Message => "The feature '$feat' is not supported by " . ref($self),
            Exception => undef,
            );
    }
    throw XML::SAX::Exception::NotRecognized(
        Message => "The feature '$feat' is not recognized by " . ref($self),
        Exception => undef,
        );
}
#-------------------------------------------------------------------#

#-------------------------------------------------------------------#
# set_feature
#-------------------------------------------------------------------#
sub set_feature {
    my $self = shift;
    my $feat = shift;
    my $value = shift;
    # check %FEATURES to see if it's there, and set it if so
    # throw XML::SAX::Exception::NotRecognized if it's not there
    # throw XML::SAX::Exception::NotSupported if it's there but we
    # don't support it
    
    my %features = $self->get_features();
    if (exists $features{$feat}) {
        my %supported = map { $_ => 1 } $self->supported_features();
        if ($supported{$feat}) {
            return $self->{__PACKAGE__ . "::Features"}{$feat} = $value;
        }
        throw XML::SAX::Exception::NotSupported(
            Message => "The feature '$feat' is not supported by " . ref($self),
            Exception => undef,
            );
    }
    throw XML::SAX::Exception::NotRecognized(
        Message => "The feature '$feat' is not recognized by " . ref($self),
        Exception => undef,
        );
}
#-------------------------------------------------------------------#

#-------------------------------------------------------------------#
# get_handler and friends
#-------------------------------------------------------------------#
sub get_handler {
    my $self = shift;
    my $handler_type = shift;
    $handler_type ||= 'Handler';
    return  defined( $self->{$handler_type} ) ? $self->{$handler_type} : undef;
}

sub get_document_handler {
    my $self = shift;
    return $self->get_handler('DocumentHandler', @_);
}

sub get_content_handler {
    my $self = shift;
    return $self->get_handler('ContentHandler', @_);
}

sub get_dtd_handler {
    my $self = shift;
    return $self->get_handler('DTDHandler', @_);
}

sub get_lexical_handler {
    my $self = shift;
    return $self->get_handler('LexicalHandler', @_);
}

sub get_decl_handler {
    my $self = shift;
    return $self->get_handler('DeclHandler', @_);
}

sub get_error_handler {
    my $self = shift;
    return $self->get_handler('ErrorHandler', @_);
}

sub get_entity_resolver {
    my $self = shift;
    return $self->get_handler('EntityResolver', @_);
}
#-------------------------------------------------------------------#

#-------------------------------------------------------------------#
# set_handler and friends
#-------------------------------------------------------------------#
sub set_handler {
    my $self = shift;
    my ($new_handler, $handler_type) = reverse @_;
    $handler_type ||= 'Handler';
    $self->{Methods} = {} if $self->{Methods};
    $self->{$handler_type} = $new_handler;
    $self->{ParseOptions}->{$handler_type} = $new_handler;
    return 1;
}

sub set_document_handler {
    my $self = shift;
    return $self->set_handler('DocumentHandler', @_);
}

sub set_content_handler {
    my $self = shift;
    return $self->set_handler('ContentHandler', @_);
}
sub set_dtd_handler {
    my $self = shift;
    return $self->set_handler('DTDHandler', @_);
}
sub set_lexical_handler {
    my $self = shift;
    return $self->set_handler('LexicalHandler', @_);
}
sub set_decl_handler {
    my $self = shift;
    return $self->set_handler('DeclHandler', @_);
}
sub set_error_handler {
    my $self = shift;
    return $self->set_handler('ErrorHandler', @_);
}
sub set_entity_resolver {
    my $self = shift;
    return $self->set_handler('EntityResolver', @_);
}

#-------------------------------------------------------------------#

#-------------------------------------------------------------------#
# supported_features
#-------------------------------------------------------------------#
sub supported_features {
    my $self = shift;
    # Only namespaces are required by all parsers
    return (
        'http://xml.org/sax/features/namespaces',
    );
}
#-------------------------------------------------------------------#

sub no_op {
    # this space intentionally blank
}


package XML::SAX::Base::NoHandler;
$XML::SAX::Base::NoHandler::VERSION = '1.09';
# we need a fake handler that doesn't implement anything, this
# simplifies the code a lot (though given the recent changes,
# it may be better to do without)
sub new {
    #warn "no handler called\n";
    return bless {};
}

1;

__END__

=head1 NAME

XML::SAX::Base - Base class SAX Drivers and Filters

=head1 SYNOPSIS

  package MyFilter;
  use XML::SAX::Base;
  @ISA = ('XML::SAX::Base');

=head1 DESCRIPTION

This module has a very simple task - to be a base class for PerlSAX
drivers and filters. It's default behaviour is to pass the input directly
to the output unchanged. It can be useful to use this module as a base class
so you don't have to, for example, implement the characters() callback.

The main advantages that it provides are easy dispatching of events the right
way (ie it takes care for you of checking that the handler has implemented
that method, or has defined an AUTOLOAD), and the guarantee that filters
will pass along events that they aren't implementing to handlers downstream
that might nevertheless be interested in them.

=head1 WRITING SAX DRIVERS AND FILTERS

The Perl Sax API Reference is at L<http://perl-xml.sourceforge.net/perl-sax/>.

Writing SAX Filters is tremendously easy: all you need to do is
inherit from this module, and define the events you want to handle. A
more detailed explanation can be found at
http://www.xml.com/pub/a/2001/10/10/sax-filters.html.

Writing Drivers is equally simple. The one thing you need to pay
attention to is B<NOT> to call events yourself (this applies to Filters
as well). For instance:

  package MyFilter;
  use base qw(XML::SAX::Base);

  sub start_element {
    my $self = shift;
    my $data = shift;
    # do something
    $self->{Handler}->start_element($data); # BAD
  }

The above example works well as precisely that: an example. But it has
several faults: 1) it doesn't test to see whether the handler defines
start_element. Perhaps it doesn't want to see that event, in which
case you shouldn't throw it (otherwise it'll die). 2) it doesn't check
ContentHandler and then Handler (ie it doesn't look to see that the
user hasn't requested events on a specific handler, and if not on the
default one), 3) if it did check all that, not only would the code be
cumbersome (see this module's source to get an idea) but it would also
probably have to check for a DocumentHandler (in case this were SAX1)
and for AUTOLOADs potentially defined in all these packages. As you can
tell, that would be fairly painful. Instead of going through that,
simply remember to use code similar to the following instead:

  package MyFilter;
  use base qw(XML::SAX::Base);

  sub start_element {
    my $self = shift;
    my $data = shift;
    # do something to filter
    $self->SUPER::start_element($data); # GOOD (and easy) !
  }

This way, once you've done your job you hand the ball back to
XML::SAX::Base and it takes care of all those problems for you!

Note that the above example doesn't apply to filters only, drivers
will benefit from the exact same feature.

=head1 METHODS

A number of methods are defined within this class for the purpose of
inheritance. Some probably don't need to be overridden (eg parse_file)
but some clearly should be (eg parse). Options for these methods are
described in the PerlSAX2 specification available from
http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/~checkout~/perl-xml/libxml-perl/doc/sax-2.0.html?rev=HEAD&content-type=text/html.

=over 4

=item * parse

The parse method is the main entry point to parsing documents. Internally
the parse method will detect what type of "thing" you are parsing, and
call the appropriate method in your implementation class. Here is the
mapping table of what is in the Source options (see the Perl SAX 2.0
specification for the meaning of these values):

  Source Contains           parse() calls
  ===============           =============
  CharacterStream (*)       _parse_characterstream($stream, $options)
  ByteStream                _parse_bytestream($stream, $options)
  String                    _parse_string($string, $options)
  SystemId                  _parse_systemid($string, $options)

However note that these methods may not be sensible if your driver class 
is not for parsing XML. An example might be a DBI driver that generates
XML/SAX from a database table. If that is the case, you likely want to
write your own parse() method.

Also note that the Source may contain both a PublicId entry, and an
Encoding entry. To get at these, examine $options->{Source} as passed
to your method.

(*) A CharacterStream is a filehandle that does not need any encoding
translation done on it. This is implemented as a regular filehandle
and only works under Perl 5.7.2 or higher using PerlIO. To get a single
character, or number of characters from it, use the perl core read()
function. To get a single byte from it (or number of bytes), you can 
use sysread(). The encoding of the stream should be in the Encoding
entry for the Source.

=item * parse_file, parse_uri, parse_string

These are all convenience variations on parse(), and in fact simply
set up the options before calling it. You probably don't need to
override these.

=item * get_options

This is a convenience method to get options in SAX2 style, or more
generically either as hashes or as hashrefs (it returns a hashref).
You will probably want to use this method in your own implementations
of parse() and of new().

=item * get_feature, set_feature

These simply get and set features, and throw the
appropriate exceptions defined in the specification if need be.

If your subclass defines features not defined in this one,
then you should override these methods in such a way that they check for
your features first, and then call the base class's methods
for features not defined by your class. An example would be:

  sub get_feature {
      my $self = shift;
      my $feat = shift;
      if (exists $MY_FEATURES{$feat}) {
          # handle the feature in various ways
      }
      else {
          return $self->SUPER::get_feature($feat);
      }
  }

Currently this part is unimplemented.


=item * set_handler

This method takes a handler type (Handler, ContentHandler, etc.) and a
handler object as arguments, and changes the current handler for that
handler type, while taking care of resetting the internal state that 
needs to be reset. This allows one to change a handler during parse
without running into problems (changing it on the parser object 
directly will most likely cause trouble).

=item * set_document_handler, set_content_handler, set_dtd_handler, set_lexical_handler, set_decl_handler, set_error_handler, set_entity_resolver

These are just simple wrappers around the former method, and take a
handler object as their argument. Internally they simply call
set_handler with the correct arguments.

=item * get_handler

The inverse of set_handler, this method takes a an optional string containing a handler type (DTDHandler, 
ContentHandler, etc. 'Handler' is used if no type is passed). It returns a reference to the object that implements
that class, or undef if that handler type is not set for the current driver/filter. 

=item * get_document_handler, get_content_handler, get_dtd_handler, get_lexical_handler, get_decl_handler, 
get_error_handler, get_entity_resolver

These are just simple wrappers around the get_handler() method, and take no arguments. Internally 
they simply call get_handler with the correct handler type name.

=back

It would be rather useless to describe all the methods that this
module implements here. They are all the methods supported in SAX1 and
SAX2. In case your memory is a little short, here is a list. The
apparent duplicates are there so that both versions of SAX can be
supported.

=over 4

=item * start_document

=item * end_document

=item * start_element

=item * start_document

=item * end_document

=item * start_element

=item * end_element

=item * characters

=item * processing_instruction

=item * ignorable_whitespace

=item * set_document_locator

=item * start_prefix_mapping

=item * end_prefix_mapping

=item * skipped_entity

=item * start_cdata

=item * end_cdata

=item * comment

=item * entity_reference

=item * notation_decl

=item * unparsed_entity_decl

=item * element_decl

=item * attlist_decl

=item * doctype_decl

=item * xml_decl

=item * entity_decl

=item * attribute_decl

=item * internal_entity_decl

=item * external_entity_decl

=item * resolve_entity

=item * start_dtd

=item * end_dtd

=item * start_entity

=item * end_entity

=item * warning

=item * error

=item * fatal_error

=back

=head1 TODO

  - more tests
  - conform to the "SAX Filters" and "Java and DOM compatibility"
    sections of the SAX2 document.

=head1 AUTHOR

Kip Hampton (khampton@totalcinema.com) did most of the work, after porting
it from XML::Filter::Base.

Robin Berjon (robin@knowscape.com) pitched in with patches to make it 
usable as a base for drivers as well as filters, along with other patches.

Matt Sergeant (matt@sergeant.org) wrote the original XML::Filter::Base,
and patched a few things here and there, and imported it into
the XML::SAX distribution.

=head1 SEE ALSO

L<XML::SAX>

=cut

PK7N%[�~@ppperl5/XML/SAX/BuildSAXBase.plnu��6�$#!/usr/bin/perl
#
# This file is used to generate lib/XML/SAX/Base.pm.  There is a pre-generated
# Base.pm file included in the distribution so you don't need to run this
# script unless you are attempting to modify the code.
#
# The code in this file was adapted from the Makefile.PL when XML::SAX::Base
# was split back out into its own distribution.
#
# You can manually run this file:
#
#   perl ./BuildSAXBase.pl
#
# or better yet it will be invoked by automatically Dist::Zilla when building
# a release from the git repository.
#
#   dzil build
#

package SAX::Base::Builder;

use strict;
use warnings;

use File::Spec;

write_xml_sax_base() unless caller();

sub build_xml_sax_base {
    my $code = <<'EOHEADER';
package XML::SAX::Base;

# version 0.10 - Kip Hampton <khampton@totalcinema.com>
# version 0.13 - Robin Berjon <robin@knowscape.com>
# version 0.15 - Kip Hampton <khampton@totalcinema.com>
# version 0.17 - Kip Hampton <khampton@totalcinema.com>
# version 0.19 - Kip Hampton <khampton@totalcinema.com>
# version 0.21 - Kip Hampton <khampton@totalcinema.com>
# version 0.22 - Robin Berjon <robin@knowscape.com>
# version 0.23 - Matt Sergeant <matt@sergeant.org>
# version 0.24 - Robin Berjon <robin@knowscape.com>
# version 0.25 - Kip Hampton <khampton@totalcinema.com>
# version 1.00 - Kip Hampton <khampton@totalcinema.com>
# version 1.01 - Kip Hampton <khampton@totalcinema.com>
# version 1.02 - Robin Berjon <robin@knowscape.com>
# version 1.03 - Matt Sergeant <matt@sergeant.org>
# version 1.04 - Kip Hampton <khampton@totalcinema.com>
# version 1.05 - Grant McLean <grantm@cpan.org>
# version 1.06 - Grant McLean <grantm@cpan.org>
# version 1.07 - Grant McLean <grantm@cpan.org>
# version 1.08 - Grant McLean <grantm@cpan.org>

#-----------------------------------------------------#
# STOP!!!!!
#
# This file is generated by the 'BuildSAXBase.pl' file
# that ships with the XML::SAX::Base distribution.
# If you need to make changes, patch that file NOT
# XML/SAX/Base.pm  Better yet, fork the git repository
# commit your changes and send a pull request:
#   https://github.com/grantm/XML-SAX-Base
#-----------------------------------------------------#

use strict;

use XML::SAX::Exception qw();

EOHEADER

    my %EVENT_SPEC = (
                        start_document          => [qw(ContentHandler DocumentHandler Handler)],
                        end_document            => [qw(ContentHandler DocumentHandler Handler)],
                        start_element           => [qw(ContentHandler DocumentHandler Handler)],
                        end_element             => [qw(ContentHandler DocumentHandler Handler)],
                        characters              => [qw(ContentHandler DocumentHandler Handler)],
                        processing_instruction  => [qw(ContentHandler DocumentHandler Handler)],
                        ignorable_whitespace    => [qw(ContentHandler DocumentHandler Handler)],
                        set_document_locator    => [qw(ContentHandler DocumentHandler Handler)],
                        start_prefix_mapping    => [qw(ContentHandler Handler)],
                        end_prefix_mapping      => [qw(ContentHandler Handler)],
                        skipped_entity          => [qw(ContentHandler Handler)],
                        start_cdata             => [qw(DocumentHandler LexicalHandler Handler)],
                        end_cdata               => [qw(DocumentHandler LexicalHandler Handler)],
                        comment                 => [qw(DocumentHandler LexicalHandler Handler)],
                        entity_reference        => [qw(DocumentHandler Handler)],
                        notation_decl           => [qw(DTDHandler Handler)],
                        unparsed_entity_decl    => [qw(DTDHandler Handler)],
                        element_decl            => [qw(DeclHandler Handler)],
                        attlist_decl            => [qw(DTDHandler Handler)],
                        doctype_decl            => [qw(DTDHandler Handler)],
                        xml_decl                => [qw(DTDHandler Handler)],
                        entity_decl             => [qw(DTDHandler Handler)],
                        attribute_decl          => [qw(DeclHandler Handler)],
                        internal_entity_decl    => [qw(DeclHandler Handler)],
                        external_entity_decl    => [qw(DeclHandler Handler)],
                        resolve_entity          => [qw(EntityResolver Handler)],
                        start_dtd               => [qw(LexicalHandler Handler)],
                        end_dtd                 => [qw(LexicalHandler Handler)],
                        start_entity            => [qw(LexicalHandler Handler)],
                        end_entity              => [qw(LexicalHandler Handler)],
                        warning                 => [qw(ErrorHandler Handler)],
                        error                   => [qw(ErrorHandler Handler)],
                        fatal_error             => [qw(ErrorHandler Handler)],
                     );

    for my $ev (keys %EVENT_SPEC) {
        $code .= <<"        EOTOPCODE";
sub $ev {
    my \$self = shift;
    if (defined \$self->{Methods}->{'$ev'}) {
        \$self->{Methods}->{'$ev'}->(\@_);
    }
    else {
        my \$method;
        my \$callbacks;
        if (exists \$self->{ParseOptions}) {
            \$callbacks = \$self->{ParseOptions};
        }
        else {
            \$callbacks = \$self;
        }
        if (0) { # dummy to make elsif's below compile
        }
        EOTOPCODE

       my ($can_string, $aload_string);
       for my $h (@{$EVENT_SPEC{$ev}}) {
            $can_string .= <<"            EOCANBLOCK";
        elsif (defined \$callbacks->{'$h'} and \$method = \$callbacks->{'$h'}->can('$ev') ) {
            my \$handler = \$callbacks->{'$h'};
            \$self->{Methods}->{'$ev'} = sub { \$method->(\$handler, \@_) };
            return \$method->(\$handler, \@_);
        }
            EOCANBLOCK
            $aload_string .= <<"            EOALOADBLOCK";
        elsif (defined \$callbacks->{'$h'} 
        	and \$callbacks->{'$h'}->can('AUTOLOAD')
        	and \$callbacks->{'$h'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '')
        	)
        {
            my \$res = eval { \$callbacks->{'$h'}->$ev(\@_) };
            if (\$@) {
                die \$@;
            }
            else {
                # I think there's a buggette here...
                # if the first call throws an exception, we don't set it up right.
                # Not fatal, but we might want to address it.
                my \$handler = \$callbacks->{'$h'};
                \$self->{Methods}->{'$ev'} = sub { \$handler->$ev(\@_) };
            }
            return \$res;
        }
            EOALOADBLOCK
        }

        $code .= $can_string . $aload_string;

            $code .= <<"            EOFALLTHROUGH";
        else {
            \$self->{Methods}->{'$ev'} = sub { };
        }
    }
            EOFALLTHROUGH

        $code .= "\n}\n\n";
    }

    $code .= <<'BODY';
#-------------------------------------------------------------------#
# Class->new(%options)
#-------------------------------------------------------------------#
sub new {
    my $proto = shift;
    my $class = ref($proto) || $proto;
    my $options = ($#_ == 0) ? shift : { @_ };

    unless ( defined( $options->{Handler} )         or
             defined( $options->{ContentHandler} )  or
             defined( $options->{DTDHandler} )      or
             defined( $options->{DocumentHandler} ) or
             defined( $options->{LexicalHandler} )  or
             defined( $options->{ErrorHandler} )    or
             defined( $options->{DeclHandler} ) ) {
            
             $options->{Handler} = XML::SAX::Base::NoHandler->new;
    }

    my $self = bless $options, $class;
    # turn NS processing on by default
    $self->set_feature('http://xml.org/sax/features/namespaces', 1);
    return $self;
}
#-------------------------------------------------------------------#

#-------------------------------------------------------------------#
# $p->parse(%options)
#-------------------------------------------------------------------#
sub parse {
    my $self = shift;
    my $parse_options = $self->get_options(@_);
    local $self->{ParseOptions} = $parse_options;
    if ($self->{Parent}) { # calling parse on a filter for some reason
        return $self->{Parent}->parse($parse_options);
    }
    else {
        my $method;
        if (defined $parse_options->{Source}{CharacterStream} and $method = $self->can('_parse_characterstream')) {
            warn("parse charstream???\n");
            return $method->($self, $parse_options->{Source}{CharacterStream});
        }
        elsif (defined $parse_options->{Source}{ByteStream} and $method = $self->can('_parse_bytestream')) {
            return $method->($self, $parse_options->{Source}{ByteStream});
        }
        elsif (defined $parse_options->{Source}{String} and $method = $self->can('_parse_string')) {
            return $method->($self, $parse_options->{Source}{String});
        }
        elsif (defined $parse_options->{Source}{SystemId} and $method = $self->can('_parse_systemid')) {
            return $method->($self, $parse_options->{Source}{SystemId});
        }
        else {
            die "No _parse_* routine defined on this driver (If it is a filter, remember to set the Parent property. If you call the parse() method, make sure to set a Source. You may want to call parse_uri, parse_string or parse_file instead.) [$self]";
        }
    }
}
#-------------------------------------------------------------------#

#-------------------------------------------------------------------#
# $p->parse_file(%options)
#-------------------------------------------------------------------#
sub parse_file {
    my $self = shift;
    my $file = shift;
    return $self->parse_uri($file, @_) if ref(\$file) eq 'SCALAR';
    my $parse_options = $self->get_options(@_);
    $parse_options->{Source}{ByteStream} = $file;
    return $self->parse($parse_options);
}
#-------------------------------------------------------------------#

#-------------------------------------------------------------------#
# $p->parse_uri(%options)
#-------------------------------------------------------------------#
sub parse_uri {
    my $self = shift;
    my $file = shift;
    my $parse_options = $self->get_options(@_);
    $parse_options->{Source}{SystemId} = $file;
    return $self->parse($parse_options);
}
#-------------------------------------------------------------------#

#-------------------------------------------------------------------#
# $p->parse_string(%options)
#-------------------------------------------------------------------#
sub parse_string {
    my $self = shift;
    my $string = shift;
    my $parse_options = $self->get_options(@_);
    $parse_options->{Source}{String} = $string;
    return $self->parse($parse_options);
}
#-------------------------------------------------------------------#

#-------------------------------------------------------------------#
# get_options
#-------------------------------------------------------------------#
sub get_options {
    my $self = shift;

    if (@_ == 1) {
        return { %$self, %{$_[0]} };
    } else {
        return { %$self, @_ };
    }
}
#-------------------------------------------------------------------#

#-------------------------------------------------------------------#
# get_features
#-------------------------------------------------------------------#
sub get_features {
   return (
    'http://xml.org/sax/features/external-general-entities'     => undef,
    'http://xml.org/sax/features/external-parameter-entities'   => undef,
    'http://xml.org/sax/features/is-standalone'                 => undef,
    'http://xml.org/sax/features/lexical-handler'               => undef,
    'http://xml.org/sax/features/parameter-entities'            => undef,
    'http://xml.org/sax/features/namespaces'                    => 1,
    'http://xml.org/sax/features/namespace-prefixes'            => 0,
    'http://xml.org/sax/features/string-interning'              => undef,
    'http://xml.org/sax/features/use-attributes2'               => undef,
    'http://xml.org/sax/features/use-locator2'                  => undef,
    'http://xml.org/sax/features/validation'                    => undef,

    'http://xml.org/sax/properties/dom-node'                    => undef,
    'http://xml.org/sax/properties/xml-string'                  => undef,
               );
}
#-------------------------------------------------------------------#

#-------------------------------------------------------------------#
# get_feature
#-------------------------------------------------------------------#
sub get_feature {
    my $self = shift;
    my $feat = shift;

    # check %FEATURES to see if it's there, and return it if so
    # throw XML::SAX::Exception::NotRecognized if it's not there
    # throw XML::SAX::Exception::NotSupported if it's there but we
    # don't support it
    
    my %features = $self->get_features();
    if (exists $features{$feat}) {
        my %supported = map { $_ => 1 } $self->supported_features();
        if ($supported{$feat}) {
            return $self->{__PACKAGE__ . "::Features"}{$feat};
        }
        throw XML::SAX::Exception::NotSupported(
            Message => "The feature '$feat' is not supported by " . ref($self),
            Exception => undef,
            );
    }
    throw XML::SAX::Exception::NotRecognized(
        Message => "The feature '$feat' is not recognized by " . ref($self),
        Exception => undef,
        );
}
#-------------------------------------------------------------------#

#-------------------------------------------------------------------#
# set_feature
#-------------------------------------------------------------------#
sub set_feature {
    my $self = shift;
    my $feat = shift;
    my $value = shift;
    # check %FEATURES to see if it's there, and set it if so
    # throw XML::SAX::Exception::NotRecognized if it's not there
    # throw XML::SAX::Exception::NotSupported if it's there but we
    # don't support it
    
    my %features = $self->get_features();
    if (exists $features{$feat}) {
        my %supported = map { $_ => 1 } $self->supported_features();
        if ($supported{$feat}) {
            return $self->{__PACKAGE__ . "::Features"}{$feat} = $value;
        }
        throw XML::SAX::Exception::NotSupported(
            Message => "The feature '$feat' is not supported by " . ref($self),
            Exception => undef,
            );
    }
    throw XML::SAX::Exception::NotRecognized(
        Message => "The feature '$feat' is not recognized by " . ref($self),
        Exception => undef,
        );
}
#-------------------------------------------------------------------#

#-------------------------------------------------------------------#
# get_handler and friends
#-------------------------------------------------------------------#
sub get_handler {
    my $self = shift;
    my $handler_type = shift;
    $handler_type ||= 'Handler';
    return  defined( $self->{$handler_type} ) ? $self->{$handler_type} : undef;
}

sub get_document_handler {
    my $self = shift;
    return $self->get_handler('DocumentHandler', @_);
}

sub get_content_handler {
    my $self = shift;
    return $self->get_handler('ContentHandler', @_);
}

sub get_dtd_handler {
    my $self = shift;
    return $self->get_handler('DTDHandler', @_);
}

sub get_lexical_handler {
    my $self = shift;
    return $self->get_handler('LexicalHandler', @_);
}

sub get_decl_handler {
    my $self = shift;
    return $self->get_handler('DeclHandler', @_);
}

sub get_error_handler {
    my $self = shift;
    return $self->get_handler('ErrorHandler', @_);
}

sub get_entity_resolver {
    my $self = shift;
    return $self->get_handler('EntityResolver', @_);
}
#-------------------------------------------------------------------#

#-------------------------------------------------------------------#
# set_handler and friends
#-------------------------------------------------------------------#
sub set_handler {
    my $self = shift;
    my ($new_handler, $handler_type) = reverse @_;
    $handler_type ||= 'Handler';
    $self->{Methods} = {} if $self->{Methods};
    $self->{$handler_type} = $new_handler;
    $self->{ParseOptions}->{$handler_type} = $new_handler;
    return 1;
}

sub set_document_handler {
    my $self = shift;
    return $self->set_handler('DocumentHandler', @_);
}

sub set_content_handler {
    my $self = shift;
    return $self->set_handler('ContentHandler', @_);
}
sub set_dtd_handler {
    my $self = shift;
    return $self->set_handler('DTDHandler', @_);
}
sub set_lexical_handler {
    my $self = shift;
    return $self->set_handler('LexicalHandler', @_);
}
sub set_decl_handler {
    my $self = shift;
    return $self->set_handler('DeclHandler', @_);
}
sub set_error_handler {
    my $self = shift;
    return $self->set_handler('ErrorHandler', @_);
}
sub set_entity_resolver {
    my $self = shift;
    return $self->set_handler('EntityResolver', @_);
}

#-------------------------------------------------------------------#

#-------------------------------------------------------------------#
# supported_features
#-------------------------------------------------------------------#
sub supported_features {
    my $self = shift;
    # Only namespaces are required by all parsers
    return (
        'http://xml.org/sax/features/namespaces',
    );
}
#-------------------------------------------------------------------#

sub no_op {
    # this space intentionally blank
}


package XML::SAX::Base::NoHandler;

# we need a fake handler that doesn't implement anything, this
# simplifies the code a lot (though given the recent changes,
# it may be better to do without)
sub new {
    #warn "no handler called\n";
    return bless {};
}

1;

BODY

    $code .= "__END__\n";

    $code .= <<'FOOTER';

=head1 NAME

XML::SAX::Base - Base class SAX Drivers and Filters

=head1 SYNOPSIS

  package MyFilter;
  use XML::SAX::Base;
  @ISA = ('XML::SAX::Base');

=head1 DESCRIPTION

This module has a very simple task - to be a base class for PerlSAX
drivers and filters. It's default behaviour is to pass the input directly
to the output unchanged. It can be useful to use this module as a base class
so you don't have to, for example, implement the characters() callback.

The main advantages that it provides are easy dispatching of events the right
way (ie it takes care for you of checking that the handler has implemented
that method, or has defined an AUTOLOAD), and the guarantee that filters
will pass along events that they aren't implementing to handlers downstream
that might nevertheless be interested in them.

=head1 WRITING SAX DRIVERS AND FILTERS

The Perl Sax API Reference is at L<http://perl-xml.sourceforge.net/perl-sax/>.

Writing SAX Filters is tremendously easy: all you need to do is
inherit from this module, and define the events you want to handle. A
more detailed explanation can be found at
http://www.xml.com/pub/a/2001/10/10/sax-filters.html.

Writing Drivers is equally simple. The one thing you need to pay
attention to is B<NOT> to call events yourself (this applies to Filters
as well). For instance:

  package MyFilter;
  use base qw(XML::SAX::Base);

  sub start_element {
    my $self = shift;
    my $data = shift;
    # do something
    $self->{Handler}->start_element($data); # BAD
  }

The above example works well as precisely that: an example. But it has
several faults: 1) it doesn't test to see whether the handler defines
start_element. Perhaps it doesn't want to see that event, in which
case you shouldn't throw it (otherwise it'll die). 2) it doesn't check
ContentHandler and then Handler (ie it doesn't look to see that the
user hasn't requested events on a specific handler, and if not on the
default one), 3) if it did check all that, not only would the code be
cumbersome (see this module's source to get an idea) but it would also
probably have to check for a DocumentHandler (in case this were SAX1)
and for AUTOLOADs potentially defined in all these packages. As you can
tell, that would be fairly painful. Instead of going through that,
simply remember to use code similar to the following instead:

  package MyFilter;
  use base qw(XML::SAX::Base);

  sub start_element {
    my $self = shift;
    my $data = shift;
    # do something to filter
    $self->SUPER::start_element($data); # GOOD (and easy) !
  }

This way, once you've done your job you hand the ball back to
XML::SAX::Base and it takes care of all those problems for you!

Note that the above example doesn't apply to filters only, drivers
will benefit from the exact same feature.

=head1 METHODS

A number of methods are defined within this class for the purpose of
inheritance. Some probably don't need to be overridden (eg parse_file)
but some clearly should be (eg parse). Options for these methods are
described in the PerlSAX2 specification available from
http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/~checkout~/perl-xml/libxml-perl/doc/sax-2.0.html?rev=HEAD&content-type=text/html.

=over 4

=item * parse

The parse method is the main entry point to parsing documents. Internally
the parse method will detect what type of "thing" you are parsing, and
call the appropriate method in your implementation class. Here is the
mapping table of what is in the Source options (see the Perl SAX 2.0
specification for the meaning of these values):

  Source Contains           parse() calls
  ===============           =============
  CharacterStream (*)       _parse_characterstream($stream, $options)
  ByteStream                _parse_bytestream($stream, $options)
  String                    _parse_string($string, $options)
  SystemId                  _parse_systemid($string, $options)

However note that these methods may not be sensible if your driver class 
is not for parsing XML. An example might be a DBI driver that generates
XML/SAX from a database table. If that is the case, you likely want to
write your own parse() method.

Also note that the Source may contain both a PublicId entry, and an
Encoding entry. To get at these, examine $options->{Source} as passed
to your method.

(*) A CharacterStream is a filehandle that does not need any encoding
translation done on it. This is implemented as a regular filehandle
and only works under Perl 5.7.2 or higher using PerlIO. To get a single
character, or number of characters from it, use the perl core read()
function. To get a single byte from it (or number of bytes), you can 
use sysread(). The encoding of the stream should be in the Encoding
entry for the Source.

=item * parse_file, parse_uri, parse_string

These are all convenience variations on parse(), and in fact simply
set up the options before calling it. You probably don't need to
override these.

=item * get_options

This is a convenience method to get options in SAX2 style, or more
generically either as hashes or as hashrefs (it returns a hashref).
You will probably want to use this method in your own implementations
of parse() and of new().

=item * get_feature, set_feature

These simply get and set features, and throw the
appropriate exceptions defined in the specification if need be.

If your subclass defines features not defined in this one,
then you should override these methods in such a way that they check for
your features first, and then call the base class's methods
for features not defined by your class. An example would be:

  sub get_feature {
      my $self = shift;
      my $feat = shift;
      if (exists $MY_FEATURES{$feat}) {
          # handle the feature in various ways
      }
      else {
          return $self->SUPER::get_feature($feat);
      }
  }

Currently this part is unimplemented.


=item * set_handler

This method takes a handler type (Handler, ContentHandler, etc.) and a
handler object as arguments, and changes the current handler for that
handler type, while taking care of resetting the internal state that 
needs to be reset. This allows one to change a handler during parse
without running into problems (changing it on the parser object 
directly will most likely cause trouble).

=item * set_document_handler, set_content_handler, set_dtd_handler, set_lexical_handler, set_decl_handler, set_error_handler, set_entity_resolver

These are just simple wrappers around the former method, and take a
handler object as their argument. Internally they simply call
set_handler with the correct arguments.

=item * get_handler

The inverse of set_handler, this method takes a an optional string containing a handler type (DTDHandler, 
ContentHandler, etc. 'Handler' is used if no type is passed). It returns a reference to the object that implements
that class, or undef if that handler type is not set for the current driver/filter. 

=item * get_document_handler, get_content_handler, get_dtd_handler, get_lexical_handler, get_decl_handler, 
get_error_handler, get_entity_resolver

These are just simple wrappers around the get_handler() method, and take no arguments. Internally 
they simply call get_handler with the correct handler type name.

=back

It would be rather useless to describe all the methods that this
module implements here. They are all the methods supported in SAX1 and
SAX2. In case your memory is a little short, here is a list. The
apparent duplicates are there so that both versions of SAX can be
supported.

=over 4

=item * start_document

=item * end_document

=item * start_element

=item * start_document

=item * end_document

=item * start_element

=item * end_element

=item * characters

=item * processing_instruction

=item * ignorable_whitespace

=item * set_document_locator

=item * start_prefix_mapping

=item * end_prefix_mapping

=item * skipped_entity

=item * start_cdata

=item * end_cdata

=item * comment

=item * entity_reference

=item * notation_decl

=item * unparsed_entity_decl

=item * element_decl

=item * attlist_decl

=item * doctype_decl

=item * xml_decl

=item * entity_decl

=item * attribute_decl

=item * internal_entity_decl

=item * external_entity_decl

=item * resolve_entity

=item * start_dtd

=item * end_dtd

=item * start_entity

=item * end_entity

=item * warning

=item * error

=item * fatal_error

=back

=head1 TODO

  - more tests
  - conform to the "SAX Filters" and "Java and DOM compatibility"
    sections of the SAX2 document.

=head1 AUTHOR

Kip Hampton (khampton@totalcinema.com) did most of the work, after porting
it from XML::Filter::Base.

Robin Berjon (robin@knowscape.com) pitched in with patches to make it 
usable as a base for drivers as well as filters, along with other patches.

Matt Sergeant (matt@sergeant.org) wrote the original XML::Filter::Base,
and patched a few things here and there, and imported it into
the XML::SAX distribution.

=head1 SEE ALSO

L<XML::SAX>

=cut

FOOTER


    return $code;
}


sub write_xml_sax_base {
    confirm_forced_update();

    my $path = File::Spec->catfile("lib", "XML", "SAX", "Base.pm");
    save_original_xml_sax_base($path);

    my $code = build_xml_sax_base();
    $code = add_version_stanzas($code);

    open my $fh, ">", $path or die "Cannot write $path: $!";
    print $fh $code;
    close $fh or die "Error writing $path: $!";
    print "Wrote $path\n";
}


sub confirm_forced_update {
    return if grep { $_ eq '--force' } @ARGV;

    print <<'EOF';
*** WARNING ***

The BuildSAXBase.pl script is used to generate the lib/XML/SAX/Base.pm file.
However a pre-generated version of Base.pm is included in the distribution
so you do not need to run this script unless you intend to modify the code.

You must use the --force option to deliberately overwrite the distributed
version of lib/XML/SAX/Base.pm

EOF

    exit;
}


sub save_original_xml_sax_base {
    my($path) = @_;

    return unless -e $path;
    (my $save_path = $path) =~ s{Base}{Base-orig};
    return if -e $save_path;
    print "Saving $path to $save_path\n";
    rename($path, $save_path);
}


sub add_version_stanzas {
    my($code) = @_;

    my $version = get_xml_sax_base_version();
    $code =~ s<^(package\s+(\w[:\w]+).*?\n)>
              <${1}BEGIN {\n  \$${2}::VERSION = '$version';\n}\n>mg;
    return $code;
}


sub get_xml_sax_base_version {
    open my $fh, '<', 'dist.ini' or die "open(<dist.ini): $!";
    while(<$fh>) {
        m{^\s*version\s*=\s*(\S+)} && return $1;
    }
    die "Failed to find version in dist.ini";
}

PK7N%[F��|�M�Mperl5/XML/NamespaceSupport.pmnu��6�$package XML::NamespaceSupport;
use strict;

our $VERSION = '1.12'; # VERSION

# ABSTRACT: A simple generic namespace processor

use constant FATALS         => 0; # root object
use constant NSMAP          => 1;
use constant UNKNOWN_PREF   => 2;
use constant AUTO_PREFIX    => 3;
use constant XMLNS_11       => 4;
use constant DEFAULT        => 0; # maps
use constant PREFIX_MAP     => 1;
use constant DECLARATIONS   => 2;

use vars qw($NS_XMLNS $NS_XML);
$NS_XMLNS   = 'http://www.w3.org/2000/xmlns/';
$NS_XML     = 'http://www.w3.org/XML/1998/namespace';


# add the ns stuff that baud wants based on Java's xml-writer

#-------------------------------------------------------------------#
# constructor
#-------------------------------------------------------------------#
sub new {
    my $class   = ref($_[0]) ? ref(shift) : shift;
    my $options = shift;
    my $self = [
                1, # FATALS
                [[ # NSMAP
                  undef,              # DEFAULT
                  { xml => $NS_XML }, # PREFIX_MAP
                  undef,              # DECLARATIONS
                ]],
                'aaa', # UNKNOWN_PREF
                0,     # AUTO_PREFIX
                1,     # XML_11
               ];
    $self->[NSMAP]->[0]->[PREFIX_MAP]->{xmlns} = $NS_XMLNS if $options->{xmlns};
    $self->[FATALS] = $options->{fatal_errors} if defined $options->{fatal_errors};
    $self->[AUTO_PREFIX] = $options->{auto_prefix} if defined $options->{auto_prefix};
    $self->[XMLNS_11] = $options->{xmlns_11} if defined $options->{xmlns_11};
    return bless $self, $class;
}

#-------------------------------------------------------------------#
# reset() - return to the original state (for reuse)
#-------------------------------------------------------------------#
sub reset {
    my $self = shift;
    $#{$self->[NSMAP]} = 0;
}

#-------------------------------------------------------------------#
# push_context() - add a new empty context to the stack
#-------------------------------------------------------------------#
sub push_context {
    my $self = shift;
    push @{$self->[NSMAP]}, [
                             $self->[NSMAP]->[-1]->[DEFAULT],
                             { %{$self->[NSMAP]->[-1]->[PREFIX_MAP]} },
                             [],
                            ];
}

#-------------------------------------------------------------------#
# pop_context() - remove the topmost context from the stack
#-------------------------------------------------------------------#
sub pop_context {
    my $self = shift;
    die 'Trying to pop context without push context' unless @{$self->[NSMAP]} > 1;
    pop @{$self->[NSMAP]};
}

#-------------------------------------------------------------------#
# declare_prefix() - declare a prefix in the current scope
#-------------------------------------------------------------------#
sub declare_prefix {
    my $self    = shift;
    my $prefix  = shift;
    my $value   = shift;

    warn <<'    EOWARN' unless defined $prefix or $self->[AUTO_PREFIX];
    Prefix was undefined.
    If you wish to set the default namespace, use the empty string ''.
    If you wish to autogenerate prefixes, set the auto_prefix option
    to a true value.
    EOWARN

    no warnings 'uninitialized';
    if ($prefix eq 'xml' and $value ne $NS_XML) {
        die "The xml prefix can only be bound to the $NS_XML namespace."
    }
    elsif ($value eq $NS_XML and $prefix ne 'xml') {
        die "the $NS_XML namespace can only be bound to the xml prefix.";
    }
    elsif ($value eq $NS_XML and $prefix eq 'xml') {
        return 1;
    }
    return 0 if index(lc($prefix), 'xml') == 0;
    use warnings 'uninitialized';

    if (defined $prefix and $prefix eq '') {
        $self->[NSMAP]->[-1]->[DEFAULT] = $value;
    }
    else {
        die "Cannot declare prefix $prefix" if $value eq '' and not $self->[XMLNS_11];
        if (not defined $prefix and $self->[AUTO_PREFIX]) {
            while (1) {
                $prefix = $self->[UNKNOWN_PREF]++;
                last if not exists $self->[NSMAP]->[-1]->[PREFIX_MAP]->{$prefix};
            }
        }
        elsif (not defined $prefix and not $self->[AUTO_PREFIX]) {
            return 0;
        }
        $self->[NSMAP]->[-1]->[PREFIX_MAP]->{$prefix} = $value;
    }
    push @{$self->[NSMAP]->[-1]->[DECLARATIONS]}, $prefix;
    return 1;
}

#-------------------------------------------------------------------#
# declare_prefixes() - declare several prefixes in the current scope
#-------------------------------------------------------------------#
sub declare_prefixes {
    my $self     = shift;
    my %prefixes = @_;
    while (my ($k,$v) = each %prefixes) {
        $self->declare_prefix($k,$v);
    }
}

#-------------------------------------------------------------------#
# undeclare_prefix
#-------------------------------------------------------------------#
sub undeclare_prefix {
    my $self   = shift;
    my $prefix = shift;
    return if not defined($prefix);
    return unless exists $self->[NSMAP]->[-1]->[PREFIX_MAP]->{$prefix};

    my ( $tfix ) = grep { $_ eq $prefix } @{$self->[NSMAP]->[-1]->[DECLARATIONS]};
    if ( not defined $tfix ) {
        die "prefix $prefix not declared in this context\n";
    }

    @{$self->[NSMAP]->[-1]->[DECLARATIONS]} = grep { $_ ne $prefix } @{$self->[NSMAP]->[-1]->[DECLARATIONS]};
    delete $self->[NSMAP]->[-1]->[PREFIX_MAP]->{$prefix};
}

#-------------------------------------------------------------------#
# get_prefix() - get a (random) prefix for a given URI
#-------------------------------------------------------------------#
sub get_prefix {
    my $self    = shift;
    my $uri     = shift;

    # we have to iterate over the whole hash here because if we don't
    # the iterator isn't reset and the next pass will fail
    my $pref;
    while (my ($k, $v) = each %{$self->[NSMAP]->[-1]->[PREFIX_MAP]}) {
        $pref = $k if $v eq $uri;
    }
    return $pref;
}

#-------------------------------------------------------------------#
# get_prefixes() - get all the prefixes for a given URI
#-------------------------------------------------------------------#
sub get_prefixes {
    my $self    = shift;
    my $uri     = shift;

    return keys %{$self->[NSMAP]->[-1]->[PREFIX_MAP]} unless defined $uri;
    return grep { $self->[NSMAP]->[-1]->[PREFIX_MAP]->{$_} eq $uri } keys %{$self->[NSMAP]->[-1]->[PREFIX_MAP]};
}

#-------------------------------------------------------------------#
# get_declared_prefixes() - get all prefixes declared in the last context
#-------------------------------------------------------------------#
sub get_declared_prefixes {
    my $declarations = $_[0]->[NSMAP]->[-1]->[DECLARATIONS];
    die "At least one context must be pushed onto stack with push_context()\n",
	"before calling get_declared_prefixes()"
	if not defined $declarations;
    return @{$_[0]->[NSMAP]->[-1]->[DECLARATIONS]};
}

#-------------------------------------------------------------------#
# get_uri() - get a URI given a prefix
#-------------------------------------------------------------------#
sub get_uri {
    my $self    = shift;
    my $prefix  = shift;

    warn "Prefix must not be undef in get_uri(). The emtpy prefix must be ''" unless defined $prefix;

    return $self->[NSMAP]->[-1]->[DEFAULT] if $prefix eq '';
    return $self->[NSMAP]->[-1]->[PREFIX_MAP]->{$prefix} if exists $self->[NSMAP]->[-1]->[PREFIX_MAP]->{$prefix};
    return undef;
}

#-------------------------------------------------------------------#
# process_name() - provide details on a name
#-------------------------------------------------------------------#
sub process_name {
    my $self    = shift;
    my $qname   = shift;
    my $aflag   = shift;

    if ($self->[FATALS]) {
        return( ($self->_get_ns_details($qname, $aflag))[0,2], $qname );
    }
    else {
        eval { return( ($self->_get_ns_details($qname, $aflag))[0,2], $qname ); }
    }
}

#-------------------------------------------------------------------#
# process_element_name() - provide details on a element's name
#-------------------------------------------------------------------#
sub process_element_name {
    my $self    = shift;
    my $qname   = shift;

    if ($self->[FATALS]) {
        return $self->_get_ns_details($qname, 0);
    }
    else {
        eval { return $self->_get_ns_details($qname, 0); }
    }
}


#-------------------------------------------------------------------#
# process_attribute_name() - provide details on a attribute's name
#-------------------------------------------------------------------#
sub process_attribute_name {
    my $self    = shift;
    my $qname   = shift;

    if ($self->[FATALS]) {
        return $self->_get_ns_details($qname, 1);
    }
    else {
        eval { return $self->_get_ns_details($qname, 1); }
    }
}


#-------------------------------------------------------------------#
# ($ns, $prefix, $lname) = $self->_get_ns_details($qname, $f_attr)
# returns ns, prefix, and lname for a given attribute name
# >> the $f_attr flag, if set to one, will work for an attribute
#-------------------------------------------------------------------#
sub _get_ns_details {
    my $self    = shift;
    my $qname   = shift;
    my $aflag   = shift;

    my ($ns, $prefix, $lname);
    (my ($tmp_prefix, $tmp_lname) = split /:/, $qname, 3)
                                    < 3 or die "Invalid QName: $qname";

    # no prefix
    my $cur_map = $self->[NSMAP]->[-1];
    if (not defined($tmp_lname)) {
        $prefix = undef;
        $lname = $qname;
        # attr don't have a default namespace
        $ns = ($aflag) ? undef : $cur_map->[DEFAULT];
    }

    # prefix
    else {
        if (exists $cur_map->[PREFIX_MAP]->{$tmp_prefix}) {
            $prefix = $tmp_prefix;
            $lname  = $tmp_lname;
            $ns     = $cur_map->[PREFIX_MAP]->{$prefix}
        }
        else { # no ns -> lname == name, all rest undef
            die "Undeclared prefix: $tmp_prefix";
        }
    }

    return ($ns, $prefix, $lname);
}

#-------------------------------------------------------------------#
# parse_jclark_notation() - parse the Clarkian notation
#-------------------------------------------------------------------#
sub parse_jclark_notation {
    shift;
    my $jc = shift;
    $jc =~ m/^\{(.*)\}([^}]+)$/;
    return $1, $2;
}


#-------------------------------------------------------------------#
# Java names mapping
#-------------------------------------------------------------------#
*XML::NamespaceSupport::pushContext          = \&push_context;
*XML::NamespaceSupport::popContext           = \&pop_context;
*XML::NamespaceSupport::declarePrefix        = \&declare_prefix;
*XML::NamespaceSupport::declarePrefixes      = \&declare_prefixes;
*XML::NamespaceSupport::getPrefix            = \&get_prefix;
*XML::NamespaceSupport::getPrefixes          = \&get_prefixes;
*XML::NamespaceSupport::getDeclaredPrefixes  = \&get_declared_prefixes;
*XML::NamespaceSupport::getURI               = \&get_uri;
*XML::NamespaceSupport::processName          = \&process_name;
*XML::NamespaceSupport::processElementName   = \&process_element_name;
*XML::NamespaceSupport::processAttributeName = \&process_attribute_name;
*XML::NamespaceSupport::parseJClarkNotation  = \&parse_jclark_notation;
*XML::NamespaceSupport::undeclarePrefix      = \&undeclare_prefix;


1;

__END__

=pod

=encoding UTF-8

=head1 NAME

XML::NamespaceSupport - A simple generic namespace processor

=head1 VERSION

version 1.12

=head1 SYNOPSIS

  use XML::NamespaceSupport;
  my $nsup = XML::NamespaceSupport->new;

  # add a new empty context
  $nsup->push_context;
  # declare a few prefixes
  $nsup->declare_prefix($prefix1, $uri1);
  $nsup->declare_prefix($prefix2, $uri2);
  # the same shorter
  $nsup->declare_prefixes($prefix1 => $uri1, $prefix2 => $uri2);

  # get a single prefix for a URI (randomly)
  $prefix = $nsup->get_prefix($uri);
  # get all prefixes for a URI (probably better)
  @prefixes = $nsup->get_prefixes($uri);
  # get all prefixes in scope
  @prefixes = $nsup->get_prefixes();
  # get all prefixes that were declared for the current scope
  @prefixes = $nsup->get_declared_prefixes;
  # get a URI for a given prefix
  $uri = $nsup->get_uri($prefix);

  # get info on a qname (java-ish way, it's a bit weird)
  ($ns_uri, $local_name, $qname) = $nsup->process_name($qname, $is_attr);
  # the same, more perlish
  ($ns_uri, $prefix, $local_name) = $nsup->process_element_name($qname);
  ($ns_uri, $prefix, $local_name) = $nsup->process_attribute_name($qname);

  # remove the current context
  $nsup->pop_context;

  # reset the object for reuse in another document
  $nsup->reset;

  # a simple helper to process Clarkian Notation
  my ($ns, $lname) = $nsup->parse_jclark_notation('{http://foo}bar');
  # or (given that it doesn't care about the object
  my ($ns, $lname) = XML::NamespaceSupport->parse_jclark_notation('{http://foo}bar');

=head1 DESCRIPTION

This module offers a simple to process namespaced XML names (unames)
from within any application that may need them. It also helps maintain
a prefix to namespace URI map, and provides a number of basic checks.

The model for this module is SAX2's NamespaceSupport class, readable at
http://www.saxproject.org/namespaces.html
It adds a few perlisations where we thought it appropriate.

=head1 NAME

XML::NamespaceSupport - a simple generic namespace support class

=head1 METHODS

=over 4

=item * XML::NamespaceSupport->new(\%options)

A simple constructor.

The options are C<xmlns>, C<fatal_errors>, and C<auto_prefix>

If C<xmlns> is turned on (it is off by default) the mapping from the
xmlns prefix to the URI defined for it in DOM level 2 is added to the
list of predefined mappings (which normally only contains the xml
prefix mapping).

If C<fatal_errors> is turned off (it is on by default) a number of
validity errors will simply be flagged as failures, instead of
die()ing.

If C<auto_prefix> is turned on (it is off by default) when one
provides a prefix of C<undef> to C<declare_prefix> it will generate a
random prefix mapped to that namespace. Otherwise an undef prefix will
trigger a warning (you should probably know what you're doing if you
turn this option on).

If C<xmlns_11> us turned off, it becomes illegal to undeclare namespace
prefixes. It is on by default. This behaviour is compliant with Namespaces
in XML 1.1, turning it off reverts you to version 1.0.

=item * $nsup->push_context

Adds a new empty context to the stack. You can then populate it with
new prefixes defined at this level.

=item * $nsup->pop_context

Removes the topmost context in the stack and reverts to the previous
one. It will die() if you try to pop more than you have pushed.

=item * $nsup->declare_prefix($prefix, $uri)

Declares a mapping of $prefix to $uri, at the current level.

Note that with C<auto_prefix> turned on, if you declare a prefix
mapping in which $prefix is undef(), you will get an automatic prefix
selected for you. If it is off you will get a warning.

This is useful when you deal with code that hasn't kept prefixes around
and need to reserialize the nodes. It also means that if you want to
set the default namespace (i.e. with an empty prefix) you must use the
empty string instead of undef. This behaviour is consistent with the
SAX 2.0 specification.

=item * $nsup->declare_prefixes(%prefixes2uris)

Declares a mapping of several prefixes to URIs, at the current level.

=item * $nsup->get_prefix($uri)

Returns a prefix given a URI. Note that as several prefixes may be
mapped to the same URI, it returns an arbitrary one. It'll return
undef on failure.

=item * $nsup->get_prefixes($uri)

Returns an array of prefixes given a URI. It'll return all the
prefixes if the uri is undef.

=item * $nsup->get_declared_prefixes

Returns an array of all the prefixes that have been declared within
this context, ie those that were declared on the last element, not
those that were declared above and are simply in scope.

Note that at least one context must be added to the stack via
C<push_context> before this method can be called.

=item * $nsup->get_uri($prefix)

Returns a URI for a given prefix. Returns undef on failure.

=item * $nsup->process_name($qname, $is_attr)

Given a qualified name and a boolean indicating whether this is an
attribute or another type of name (those are differently affected by
default namespaces), it returns a namespace URI, local name, qualified
name tuple. I know that that is a rather abnormal list to return, but
it is so for compatibility with the Java spec. See below for more
Perlish alternatives.

If the prefix is not declared, or if the name is not valid, it'll
either die or return undef depending on the current setting of
C<fatal_errors>.

=item * $nsup->undeclare_prefix($prefix);

Removes a namespace prefix from the current context. This function may
be used in SAX's end_prefix_mapping when there is fear that a namespace
declaration might be available outside their scope (which shouldn't
normally happen, but you never know ;) ). This may be needed in order
to properly support Namespace 1.1.

=item * $nsup->process_element_name($qname)

Given a qualified name, it returns a namespace URI, prefix, and local
name tuple. This method applies to element names.

If the prefix is not declared, or if the name is not valid, it'll
either die or return undef depending on the current setting of
C<fatal_errors>.

=item * $nsup->process_attribute_name($qname)

Given a qualified name, it returns a namespace URI, prefix, and local
name tuple. This method applies to attribute names.

If the prefix is not declared, or if the name is not valid, it'll
either die or return undef depending on the current setting of
C<fatal_errors>.

=item * $nsup->reset

Resets the object so that it can be reused on another document.

=back

All methods of the interface have an alias that is the name used in
the original Java specification. You can use either name
interchangeably. Here is the mapping:

  Java name                 Perl name
  ---------------------------------------------------
  pushContext               push_context
  popContext                pop_context
  declarePrefix             declare_prefix
  declarePrefixes           declare_prefixes
  getPrefix                 get_prefix
  getPrefixes               get_prefixes
  getDeclaredPrefixes       get_declared_prefixes
  getURI                    get_uri
  processName               process_name
  processElementName        process_element_name
  processAttributeName      process_attribute_name
  parseJClarkNotation       parse_jclark_notation
  undeclarePrefix           undeclare_prefix

=head1 VARIABLES

Two global variables are made available to you. They used to be constants but
simple scalars are easier to use in a number of contexts. They are not
exported but can easily be accessed from any package, or copied into it.

=over 4

=item * C<$NS_XMLNS>

The namespace for xmlns prefixes, http://www.w3.org/2000/xmlns/.

=item * C<$NS_XML>

The namespace for xml prefixes, http://www.w3.org/XML/1998/namespace.

=back

=head1 TODO

 - add more tests
 - optimise here and there

=head1 SEE ALSO

XML::Parser::PerlSAX

=head1 AUTHORS

=over 4

=item *

Robin Berjon <robin@knowscape.com>

=item *

Chris Prather <chris@prather.org>

=back

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2015 by Robin Berjon.

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

=head1 CONTRIBUTORS

=for stopwords Chris Prather David Steinbrunner Paul Cochrane Paulo Custodio

=over 4

=item *

Chris Prather <cprather@hdpublishing.com>

=item *

David Steinbrunner <dsteinbrunner@pobox.com>

=item *

Paul Cochrane <paul@liekut.de>

=item *

Paulo Custodio <pauloscustodio@gmail.com>

=back

=cut
PK7N%[�q�i��perl5/XML/Simple.pmnu��6�$package XML::Simple;
$XML::Simple::VERSION = '2.25';
=head1 NAME

XML::Simple - An API for simple XML files

=head1 SYNOPSIS

PLEASE DO NOT USE THIS MODULE IN NEW CODE.  If you ignore this
warning and use it anyway, the C<qw(:strict)> mode will save you a little pain.

    use XML::Simple qw(:strict);

    my $ref = XMLin([<xml file or string>] [, <options>]);

    my $xml = XMLout($hashref [, <options>]);

Or the object oriented way:

    require XML::Simple qw(:strict);

    my $xs = XML::Simple->new([<options>]);

    my $ref = $xs->XMLin([<xml file or string>] [, <options>]);

    my $xml = $xs->XMLout($hashref [, <options>]);

(or see L<"SAX SUPPORT"> for 'the SAX way').

Note, in these examples, the square brackets are used to denote optional items
not to imply items should be supplied in arrayrefs.

=cut

# See after __END__ for more POD documentation


# Load essentials here, other modules loaded on demand later

use strict;
use warnings;
use warnings::register;
use Carp;
use Scalar::Util qw();
require Exporter;


##############################################################################
# Define some constants
#

use vars qw($VERSION @ISA @EXPORT @EXPORT_OK $PREFERRED_PARSER);

@ISA               = qw(Exporter);
@EXPORT            = qw(XMLin XMLout);
@EXPORT_OK         = qw(xml_in xml_out);

my %StrictMode     = ();

my @KnownOptIn     = qw(keyattr keeproot forcecontent contentkey noattr
                        searchpath forcearray cache suppressempty parseropts
                        grouptags nsexpand datahandler varattr variables
                        normalisespace normalizespace valueattr strictmode);

my @KnownOptOut    = qw(keyattr keeproot contentkey noattr
                        rootname xmldecl outputfile noescape suppressempty
                        grouptags nsexpand handler noindent attrindent nosort
                        valueattr numericescape strictmode);

my @DefKeyAttr     = qw(name key id);
my $DefRootName    = qq(opt);
my $DefContentKey  = qq(content);
my $DefXmlDecl     = qq(<?xml version='1.0' standalone='yes'?>);

my $xmlns_ns       = 'http://www.w3.org/2000/xmlns/';
my $bad_def_ns_jcn = '{' . $xmlns_ns . '}';     # LibXML::SAX workaround


##############################################################################
# Globals for use by caching routines
#

my %MemShareCache  = ();
my %MemCopyCache   = ();


##############################################################################
# Wrapper for Exporter - handles ':strict'
#

sub import {
  # Handle the :strict tag

  my($calling_package) = caller();
  _strict_mode_for_caller(1) if grep(/^:strict$/, @_);

  # Pass everything else to Exporter.pm

  @_ = grep(!/^:strict$/, @_);
  goto &Exporter::import;
}


##############################################################################
# Constructor for optional object interface.
#

sub new {
  my $class = shift;

  if(@_ % 2) {
    croak "Default options must be name=>value pairs (odd number supplied)";
  }

  my %known_opt;
  @known_opt{@KnownOptIn, @KnownOptOut} = ();

  my %raw_opt = @_;
  $raw_opt{strictmode} = _strict_mode_for_caller()
    unless exists $raw_opt{strictmode};
  my %def_opt;
  while(my($key, $val) = each %raw_opt) {
    my $lkey = lc($key);
    $lkey =~ s/_//g;
    croak "Unrecognised option: $key" unless(exists($known_opt{$lkey}));
    $def_opt{$lkey} = $val;
  }
  my $self = { def_opt => \%def_opt };

  return(bless($self, $class));
}


##############################################################################
# Sub: _strict_mode_for_caller()
#
# Gets or sets the XML::Simple :strict mode flag for the calling namespace.
# Walks back through call stack to find the calling namespace and sets the
# :strict mode flag for that namespace if an argument was supplied and returns
# the flag value if not.
#

sub _strict_mode_for_caller {
  my $set_mode = @_;
  my $frame = 1;
  while(my($package) = caller($frame++)) {
    next if $package eq 'XML::Simple';
    $StrictMode{$package} = 1 if $set_mode;
    return $StrictMode{$package};
  }
  return(0);
}


##############################################################################
# Sub: _get_object()
#
# Helper routine called from XMLin() and XMLout() to create an object if none
# was provided.  Note, this routine does mess with the caller's @_ array.
#

sub _get_object {
  my $self;
  if($_[0]  and  UNIVERSAL::isa($_[0], 'XML::Simple')) {
    $self = shift;
  }
  else {
    $self = XML::Simple->new();
  }

  return $self;
}


##############################################################################
# Sub/Method: XMLin()
#
# Exported routine for slurping XML into a hashref - see pod for info.
#
# May be called as object method or as a plain function.
#
# Expects one arg for the source XML, optionally followed by a number of
# name => value option pairs.
#

sub XMLin {
  my $self = &_get_object;      # note, @_ is passed implicitly

  my $target = shift;


  # Work out whether to parse a string, a file or a filehandle

  if(not defined $target) {
    return $self->parse_file(undef, @_);
  }

  elsif($target eq '-') {
    local($/) = undef;
    $target = <STDIN>;
    return $self->parse_string(\$target, @_);
  }

  elsif(my $type = ref($target)) {
    if($type eq 'SCALAR') {
      return $self->parse_string($target, @_);
    }
    else {
      return $self->parse_fh($target, @_);
    }
  }

  elsif($target =~ m{<.*?>}s) {
    return $self->parse_string(\$target, @_);
  }

  else {
    return $self->parse_file($target, @_);
  }
}


##############################################################################
# Sub/Method: parse_file()
#
# Same as XMLin, but only parses from a named file.
#

sub parse_file {
  my $self = &_get_object;      # note, @_ is passed implicitly

  my $filename = shift;

  $self->handle_options('in', @_);

  $filename = $self->default_config_file if not defined $filename;

  $filename = $self->find_xml_file($filename, @{$self->{opt}->{searchpath}});

  # Check cache for previous parse

  if($self->{opt}->{cache}) {
    foreach my $scheme (@{$self->{opt}->{cache}}) {
      my $method = 'cache_read_' . $scheme;
      my $opt = $self->$method($filename);
      return($opt) if($opt);
    }
  }

  my $ref = $self->build_simple_tree($filename, undef);

  if($self->{opt}->{cache}) {
    my $method = 'cache_write_' . $self->{opt}->{cache}->[0];
    $self->$method($ref, $filename);
  }

  return $ref;
}


##############################################################################
# Sub/Method: parse_fh()
#
# Same as XMLin, but only parses from a filehandle.
#

sub parse_fh {
  my $self = &_get_object;      # note, @_ is passed implicitly

  my $fh = shift;
  croak "Can't use " . (defined $fh ? qq{string ("$fh")} : 'undef') .
        " as a filehandle" unless ref $fh;

  $self->handle_options('in', @_);

  return $self->build_simple_tree(undef, $fh);
}


##############################################################################
# Sub/Method: parse_string()
#
# Same as XMLin, but only parses from a string or a reference to a string.
#

sub parse_string {
  my $self = &_get_object;      # note, @_ is passed implicitly

  my $string = shift;

  $self->handle_options('in', @_);

  return $self->build_simple_tree(undef, ref $string ? $string : \$string);
}


##############################################################################
# Method: default_config_file()
#
# Returns the name of the XML file to parse if no filename (or XML string)
# was provided.
#

sub default_config_file {
  my $self = shift;

  require File::Basename;

  my($basename, $script_dir, $ext) = File::Basename::fileparse($0, '\.[^\.]+');

  # Add script directory to searchpath

  if($script_dir) {
    unshift(@{$self->{opt}->{searchpath}}, $script_dir);
  }

  return $basename . '.xml';
}


##############################################################################
# Method: build_simple_tree()
#
# Builds a 'tree' data structure as provided by XML::Parser and then
# 'simplifies' it as specified by the various options in effect.
#

sub build_simple_tree {
  my $self = shift;

  my $tree = eval {
    $self->build_tree(@_);
  };
  Carp::croak("$@XML::Simple called") if $@;

  return $self->{opt}->{keeproot}
         ? $self->collapse({}, @$tree)
         : $self->collapse(@{$tree->[1]});
}


##############################################################################
# Method: build_tree()
#
# This routine will be called if there is no suitable pre-parsed tree in a
# cache.  It parses the XML and returns an XML::Parser 'Tree' style data
# structure (summarised in the comments for the collapse() routine below).
#
# XML::Simple requires the services of another module that knows how to parse
# XML.  If XML::SAX is installed, the default SAX parser will be used,
# otherwise XML::Parser will be used.
#
# This routine expects to be passed a filename as argument 1 or a 'string' as
# argument 2.  The 'string' might be a string of XML (passed by reference to
# save memory) or it might be a reference to an IO::Handle.  (This
# non-intuitive mess results in part from the way XML::Parser works but that's
# really no excuse).
#

sub build_tree {
  my $self     = shift;
  my $filename = shift;
  my $string   = shift;


  my $preferred_parser = $PREFERRED_PARSER;
  unless(defined($preferred_parser)) {
    $preferred_parser = $ENV{XML_SIMPLE_PREFERRED_PARSER} || '';
  }
  if($preferred_parser eq 'XML::Parser') {
    return($self->build_tree_xml_parser($filename, $string));
  }

  eval { require XML::SAX; };      # We didn't need it until now
  if($@) {                         # No XML::SAX - fall back to XML::Parser
    if($preferred_parser) {        # unless a SAX parser was expressly requested
      croak "XMLin() could not load XML::SAX";
    }
    return($self->build_tree_xml_parser($filename, $string));
  }

  $XML::SAX::ParserPackage = $preferred_parser if($preferred_parser);

  my $sp = XML::SAX::ParserFactory->parser(Handler => $self);

  $self->{nocollapse} = 1;
  my($tree);
  if($filename) {
    $tree = $sp->parse_uri($filename);
  }
  else {
    if(ref($string) && ref($string) ne 'SCALAR') {
      $tree = $sp->parse_file($string);
    }
    else {
      $tree = $sp->parse_string($$string);
    }
  }

  return($tree);
}


##############################################################################
# Method: build_tree_xml_parser()
#
# This routine will be called if XML::SAX is not installed, or if XML::Parser
# was specifically requested.  It takes the same arguments as build_tree() and
# returns the same data structure (XML::Parser 'Tree' style).
#

sub build_tree_xml_parser {
  my $self     = shift;
  my $filename = shift;
  my $string   = shift;


  eval {
    local($^W) = 0;      # Suppress warning from Expat.pm re File::Spec::load()
    require XML::Parser; # We didn't need it until now
  };
  if($@) {
    croak "XMLin() requires either XML::SAX or XML::Parser";
  }

  if($self->{opt}->{nsexpand}) {
    carp "'nsexpand' option requires XML::SAX";
  }

  my $xp = $self->new_xml_parser();

  my($tree);
  if($filename) {
    # $tree = $xp->parsefile($filename);  # Changed due to prob w/mod_perl
    open(my $xfh, '<', $filename) || croak qq($filename - $!);
    $tree = $xp->parse($xfh);
  }
  else {
    $tree = $xp->parse($$string);
  }

  return($tree);
}


##############################################################################
# Method: new_xml_parser()
#
# Simply calls the XML::Parser constructor.  Override this method to customise
# the behaviour of the parser.
#

sub new_xml_parser {
  my($self) = @_;

  my $xp = XML::Parser->new(Style => 'Tree', @{$self->{opt}->{parseropts}});
  $xp->setHandlers(ExternEnt => sub {return $_[2]});

  return $xp;
}


##############################################################################
# Method: cache_write_storable()
#
# Wrapper routine for invoking Storable::nstore() to cache a parsed data
# structure.
#

sub cache_write_storable {
  my($self, $data, $filename) = @_;

  my $cachefile = $self->storable_filename($filename);

  require Storable;           # We didn't need it until now

  if ('VMS' eq $^O) {
    Storable::nstore($data, $cachefile);
  }
  else {
    # If the following line fails for you, your Storable.pm is old - upgrade
    Storable::lock_nstore($data, $cachefile);
  }

}


##############################################################################
# Method: cache_read_storable()
#
# Wrapper routine for invoking Storable::retrieve() to read a cached parsed
# data structure.  Only returns cached data if the cache file exists and is
# newer than the source XML file.
#

sub cache_read_storable {
  my($self, $filename) = @_;

  my $cachefile = $self->storable_filename($filename);

  return unless(-r $cachefile);
  return unless((stat($cachefile))[9] > (stat($filename))[9]);

  require Storable;           # We didn't need it until now

  if ('VMS' eq $^O) {
    return(Storable::retrieve($cachefile));
  }
  else {
    return(Storable::lock_retrieve($cachefile));
  }

}


##############################################################################
# Method: storable_filename()
#
# Translates the supplied source XML filename into a filename for the storable
# cached data.  A '.stor' suffix is added after stripping an optional '.xml'
# suffix.
#

sub storable_filename {
  my($self, $cachefile) = @_;

  $cachefile =~ s{(\.xml)?$}{.stor};
  return $cachefile;
}


##############################################################################
# Method: cache_write_memshare()
#
# Takes the supplied data structure reference and stores it away in a global
# hash structure.
#

sub cache_write_memshare {
  my($self, $data, $filename) = @_;

  $MemShareCache{$filename} = [time(), $data];
}


##############################################################################
# Method: cache_read_memshare()
#
# Takes a filename and looks in a global hash for a cached parsed version.
#

sub cache_read_memshare {
  my($self, $filename) = @_;

  return unless($MemShareCache{$filename});
  return unless($MemShareCache{$filename}->[0] > (stat($filename))[9]);

  return($MemShareCache{$filename}->[1]);

}


##############################################################################
# Method: cache_write_memcopy()
#
# Takes the supplied data structure and stores a copy of it in a global hash
# structure.
#

sub cache_write_memcopy {
  my($self, $data, $filename) = @_;

  require Storable;           # We didn't need it until now

  $MemCopyCache{$filename} = [time(), Storable::dclone($data)];
}


##############################################################################
# Method: cache_read_memcopy()
#
# Takes a filename and looks in a global hash for a cached parsed version.
# Returns a reference to a copy of that data structure.
#

sub cache_read_memcopy {
  my($self, $filename) = @_;

  return unless($MemCopyCache{$filename});
  return unless($MemCopyCache{$filename}->[0] > (stat($filename))[9]);

  return(Storable::dclone($MemCopyCache{$filename}->[1]));

}


##############################################################################
# Sub/Method: XMLout()
#
# Exported routine for 'unslurping' a data structure out to XML.
#
# Expects a reference to a data structure and an optional list of option
# name => value pairs.
#

sub XMLout {
  my $self = &_get_object;      # note, @_ is passed implicitly

  croak "XMLout() requires at least one argument" unless(@_);
  my $ref = shift;

  $self->handle_options('out', @_);


  # If namespace expansion is set, XML::NamespaceSupport is required

  if($self->{opt}->{nsexpand}) {
    require XML::NamespaceSupport;
    $self->{nsup} = XML::NamespaceSupport->new();
    $self->{ns_prefix} = 'aaa';
  }


  # Wrap top level arrayref in a hash

  if(UNIVERSAL::isa($ref, 'ARRAY')) {
    $ref = { anon => $ref };
  }


  # Extract rootname from top level hash if keeproot enabled

  if($self->{opt}->{keeproot}) {
    my(@keys) = keys(%$ref);
    if(@keys == 1) {
      $ref = $ref->{$keys[0]};
      $self->{opt}->{rootname} = $keys[0];
    }
  }

  # Ensure there are no top level attributes if we're not adding root elements

  elsif($self->{opt}->{rootname} eq '') {
    if(UNIVERSAL::isa($ref, 'HASH')) {
      my $refsave = $ref;
      $ref = {};
      foreach (keys(%$refsave)) {
        if(ref($refsave->{$_})) {
          $ref->{$_} = $refsave->{$_};
        }
        else {
          $ref->{$_} = [ $refsave->{$_} ];
        }
      }
    }
  }


  # Encode the hashref and write to file if necessary

  $self->{_ancestors} = {};
  my $xml = $self->value_to_xml($ref, $self->{opt}->{rootname}, '');
  delete $self->{_ancestors};

  if($self->{opt}->{xmldecl}) {
    $xml = $self->{opt}->{xmldecl} . "\n" . $xml;
  }

  if($self->{opt}->{outputfile}) {
    if(ref($self->{opt}->{outputfile})) {
      my $fh = $self->{opt}->{outputfile};
      if(UNIVERSAL::isa($fh, 'GLOB') and !UNIVERSAL::can($fh, 'print')) {
        eval { require IO::Handle; };
        croak $@ if $@;
      }
      return($fh->print($xml));
    }
    else {
      open(my $out, '>', "$self->{opt}->{outputfile}") ||
        croak "open($self->{opt}->{outputfile}): $!";
      binmode($out, ':utf8') if($] >= 5.008);
      print $out $xml or croak "print: $!";
      close $out or croak "close: $!";
    }
  }
  elsif($self->{opt}->{handler}) {
    require XML::SAX;
    my $sp = XML::SAX::ParserFactory->parser(
               Handler => $self->{opt}->{handler}
             );
    return($sp->parse_string($xml));
  }
  else {
    return($xml);
  }
}


##############################################################################
# Method: handle_options()
#
# Helper routine for both XMLin() and XMLout().  Both routines handle their
# first argument and assume all other args are options handled by this routine.
# Saves a hash of options in $self->{opt}.
#
# If default options were passed to the constructor, they will be retrieved
# here and merged with options supplied to the method call.
#
# First argument should be the string 'in' or the string 'out'.
#
# Remaining arguments should be name=>value pairs.  Sets up default values
# for options not supplied.  Unrecognised options are a fatal error.
#

sub handle_options  {
  my $self = shift;
  my $dirn = shift;


  # Determine valid options based on context

  my %known_opt;
  if($dirn eq 'in') {
    @known_opt{@KnownOptIn} = @KnownOptIn;
  }
  else {
    @known_opt{@KnownOptOut} = @KnownOptOut;
  }


  # Store supplied options in hashref and weed out invalid ones

  if(@_ % 2) {
    croak "Options must be name=>value pairs (odd number supplied)";
  }
  my %raw_opt  = @_;
  my $opt      = {};
  $self->{opt} = $opt;

  while(my($key, $val) = each %raw_opt) {
    my $lkey = lc($key);
    $lkey =~ s/_//g;
    croak "Unrecognised option: $key" unless($known_opt{$lkey});
    $opt->{$lkey} = $val;
  }


  # Merge in options passed to constructor

  foreach (keys(%known_opt)) {
    unless(exists($opt->{$_})) {
      if(exists($self->{def_opt}->{$_})) {
        $opt->{$_} = $self->{def_opt}->{$_};
      }
    }
  }


  # Set sensible defaults if not supplied

  if(exists($opt->{rootname})) {
    unless(defined($opt->{rootname})) {
      $opt->{rootname} = '';
    }
  }
  else {
    $opt->{rootname} = $DefRootName;
  }

  if($opt->{xmldecl}  and  $opt->{xmldecl} eq '1') {
    $opt->{xmldecl} = $DefXmlDecl;
  }

  if(exists($opt->{contentkey})) {
    if($opt->{contentkey} =~ m{^-(.*)$}) {
      $opt->{contentkey} = $1;
      $opt->{collapseagain} = 1;
    }
  }
  else {
    $opt->{contentkey} = $DefContentKey;
  }

  unless(exists($opt->{normalisespace})) {
    $opt->{normalisespace} = $opt->{normalizespace};
  }
  $opt->{normalisespace} = 0 unless(defined($opt->{normalisespace}));

  # Cleanups for values assumed to be arrays later

  if($opt->{searchpath}) {
    unless(ref($opt->{searchpath})) {
      $opt->{searchpath} = [ $opt->{searchpath} ];
    }
  }
  else  {
    $opt->{searchpath} = [ ];
  }

  if($opt->{cache}  and !ref($opt->{cache})) {
    $opt->{cache} = [ $opt->{cache} ];
  }
  if($opt->{cache}) {
    $_ = lc($_) foreach (@{$opt->{cache}});
    foreach my $scheme (@{$opt->{cache}}) {
      my $method = 'cache_read_' . $scheme;
      croak "Unsupported caching scheme: $scheme"
        unless($self->can($method));
    }
  }

  if(exists($opt->{parseropts})) {
    if(warnings::enabled()) {
      carp "Warning: " .
           "'ParserOpts' is deprecated, contact the author if you need it";
    }
  }
  else {
    $opt->{parseropts} = [ ];
  }


  # Special cleanup for {forcearray} which could be regex, arrayref or boolean
  # or left to default to 0

  if(exists($opt->{forcearray})) {
    if(ref($opt->{forcearray}) eq 'Regexp') {
      $opt->{forcearray} = [ $opt->{forcearray} ];
    }

    if(ref($opt->{forcearray}) eq 'ARRAY') {
      my @force_list = @{$opt->{forcearray}};
      if(@force_list) {
        $opt->{forcearray} = {};
        foreach my $tag (@force_list) {
          if(ref($tag) eq 'Regexp') {
            push @{$opt->{forcearray}->{_regex}}, $tag;
          }
          else {
            $opt->{forcearray}->{$tag} = 1;
          }
        }
      }
      else {
        $opt->{forcearray} = 0;
      }
    }
    else {
      $opt->{forcearray} = ( $opt->{forcearray} ? 1 : 0 );
    }
  }
  else {
    if($opt->{strictmode}  and  $dirn eq 'in') {
      croak "No value specified for 'ForceArray' option in call to XML$dirn()";
    }
    $opt->{forcearray} = 0;
  }


  # Special cleanup for {keyattr} which could be arrayref or hashref or left
  # to default to arrayref

  if(exists($opt->{keyattr}))  {
    if(ref($opt->{keyattr})) {
      if(ref($opt->{keyattr}) eq 'HASH') {

        # Make a copy so we can mess with it

        $opt->{keyattr} = { %{$opt->{keyattr}} };


        # Convert keyattr => { elem => '+attr' }
        # to keyattr => { elem => [ 'attr', '+' ] }

        foreach my $el (keys(%{$opt->{keyattr}})) {
          if($opt->{keyattr}->{$el} =~ /^(\+|-)?(.*)$/) {
            $opt->{keyattr}->{$el} = [ $2, ($1 ? $1 : '') ];
            if($opt->{strictmode}  and  $dirn eq 'in') {
              next if($opt->{forcearray} == 1);
              next if(ref($opt->{forcearray}) eq 'HASH'
                      and $opt->{forcearray}->{$el});
              croak "<$el> set in KeyAttr but not in ForceArray";
            }
          }
          else {
            delete($opt->{keyattr}->{$el}); # Never reached (famous last words?)
          }
        }
      }
      else {
        if(@{$opt->{keyattr}} == 0) {
          delete($opt->{keyattr});
        }
      }
    }
    else {
      $opt->{keyattr} = [ $opt->{keyattr} ];
    }
  }
  else  {
    if($opt->{strictmode}) {
      croak "No value specified for 'KeyAttr' option in call to XML$dirn()";
    }
    $opt->{keyattr} = [ @DefKeyAttr ];
  }


  # Special cleanup for {valueattr} which could be arrayref or hashref

  if(exists($opt->{valueattr})) {
    if(ref($opt->{valueattr}) eq 'ARRAY') {
      $opt->{valueattrlist} = {};
      $opt->{valueattrlist}->{$_} = 1 foreach(@{ delete $opt->{valueattr} });
    }
  }

  # make sure there's nothing weird in {grouptags}

  if($opt->{grouptags}) {
    croak "Illegal value for 'GroupTags' option - expected a hashref"
      unless UNIVERSAL::isa($opt->{grouptags}, 'HASH');

    while(my($key, $val) = each %{$opt->{grouptags}}) {
      next if $key ne $val;
      croak "Bad value in GroupTags: '$key' => '$val'";
    }
  }


  # Check the {variables} option is valid and initialise variables hash

  if($opt->{variables} and !UNIVERSAL::isa($opt->{variables}, 'HASH')) {
    croak "Illegal value for 'Variables' option - expected a hashref";
  }

  if($opt->{variables}) {
    $self->{_var_values} = { %{$opt->{variables}} };
  }
  elsif($opt->{varattr}) {
    $self->{_var_values} = {};
  }

}


##############################################################################
# Method: find_xml_file()
#
# Helper routine for XMLin().
# Takes a filename, and a list of directories, attempts to locate the file in
# the directories listed.
# Returns a full pathname on success; croaks on failure.
#

sub find_xml_file  {
  my $self = shift;
  my $file = shift;
  my @search_path = @_;


  require File::Basename;
  require File::Spec;

  my($filename, $filedir) = File::Basename::fileparse($file);

  if($filename ne $file) {        # Ignore searchpath if dir component
    return($file) if(-e $file);
  }
  else {
    my($path);
    foreach $path (@search_path)  {
      my $fullpath = File::Spec->catfile($path, $file);
      return($fullpath) if(-e $fullpath);
    }
  }

  # If user did not supply a search path, default to current directory

  if(!@search_path) {
    return($file) if(-e $file);
    croak "File does not exist: $file";
  }

  croak "Could not find $file in ", join(':', @search_path);
}


##############################################################################
# Method: collapse()
#
# Helper routine for XMLin().  This routine really comprises the 'smarts' (or
# value add) of this module.
#
# Takes the parse tree that XML::Parser produced from the supplied XML and
# recurses through it 'collapsing' unnecessary levels of indirection (nested
# arrays etc) to produce a data structure that is easier to work with.
#
# Elements in the original parser tree are represented as an element name
# followed by an arrayref.  The first element of the array is a hashref
# containing the attributes.  The rest of the array contains a list of any
# nested elements as name+arrayref pairs:
#
#  <element name>, [ { <attribute hashref> }, <element name>, [ ... ], ... ]
#
# The special element name '0' (zero) flags text content.
#
# This routine cuts down the noise by discarding any text content consisting of
# only whitespace and then moves the nested elements into the attribute hash
# using the name of the nested element as the hash key and the collapsed
# version of the nested element as the value.  Multiple nested elements with
# the same name will initially be represented as an arrayref, but this may be
# 'folded' into a hashref depending on the value of the keyattr option.
#

sub collapse {
  my $self = shift;


  # Start with the hash of attributes

  my $attr  = shift;
  if($self->{opt}->{noattr}) {                    # Discard if 'noattr' set
    $attr = $self->new_hashref;
  }
  elsif($self->{opt}->{normalisespace} == 2) {
    while(my($key, $value) = each %$attr) {
      $attr->{$key} = $self->normalise_space($value)
    }
  }


  # Do variable substitutions

  if(my $var = $self->{_var_values}) {
    while(my($key, $val) = each(%$attr)) {
      $val =~ s^\$\{([\w.]+)\}^ $self->get_var($1) ^ge;
      $attr->{$key} = $val;
    }
  }


  # Roll up 'value' attributes (but only if no nested elements)

  if(!@_  and  keys %$attr == 1) {
    my($k) = keys %$attr;
    if($self->{opt}->{valueattrlist}  and $self->{opt}->{valueattrlist}->{$k}) {
      return $attr->{$k};
    }
  }


  # Add any nested elements

  my($key, $val);
  while(@_) {
    $key = shift;
    $val = shift;
    $val = '' if not defined $val;

    if(ref($val)) {
      $val = $self->collapse(@$val);
      next if(!defined($val)  and  $self->{opt}->{suppressempty});
    }
    elsif($key eq '0') {
      next if($val =~ m{^\s*$}s);  # Skip all whitespace content

      $val = $self->normalise_space($val)
        if($self->{opt}->{normalisespace} == 2);

      # do variable substitutions

      if(my $var = $self->{_var_values}) {
        $val =~ s^\$\{(\w+)\}^ $self->get_var($1) ^ge;
      }


      # look for variable definitions

      if(my $var = $self->{opt}->{varattr}) {
        if(exists $attr->{$var}) {
          $self->set_var($attr->{$var}, $val);
        }
      }


      # Collapse text content in element with no attributes to a string

      if(!%$attr  and  !@_) {
        return($self->{opt}->{forcecontent} ?
          { $self->{opt}->{contentkey} => $val } : $val
        );
      }
      $key = $self->{opt}->{contentkey};
    }


    # Combine duplicate attributes into arrayref if required

    if(exists($attr->{$key})) {
      if(UNIVERSAL::isa($attr->{$key}, 'ARRAY')) {
        push(@{$attr->{$key}}, $val);
      }
      else {
        $attr->{$key} = [ $attr->{$key}, $val ];
      }
    }
    elsif(defined($val)  and  UNIVERSAL::isa($val, 'ARRAY')) {
      $attr->{$key} = [ $val ];
    }
    else {
      if( $key ne $self->{opt}->{contentkey}
          and (
            ($self->{opt}->{forcearray} == 1)
            or (
              (ref($self->{opt}->{forcearray}) eq 'HASH')
              and (
                $self->{opt}->{forcearray}->{$key}
                or (grep $key =~ $_, @{$self->{opt}->{forcearray}->{_regex}})
              )
            )
          )
        ) {
        $attr->{$key} = [ $val ];
      }
      else {
        $attr->{$key} = $val;
      }
    }

  }


  # Turn arrayrefs into hashrefs if key fields present

  if($self->{opt}->{keyattr}) {
    while(($key,$val) = each %$attr) {
      if(defined($val)  and  UNIVERSAL::isa($val, 'ARRAY')) {
        $attr->{$key} = $self->array_to_hash($key, $val);
      }
    }
  }


  # disintermediate grouped tags

  if($self->{opt}->{grouptags}) {
    while(my($key, $val) = each(%$attr)) {
      next unless(UNIVERSAL::isa($val, 'HASH') and (keys %$val == 1));
      next unless(exists($self->{opt}->{grouptags}->{$key}));

      my($child_key, $child_val) =  %$val;

      if($self->{opt}->{grouptags}->{$key} eq $child_key) {
        $attr->{$key}= $child_val;
      }
    }
  }


  # Fold hashes containing a single anonymous array up into just the array

  my $count = scalar keys %$attr;
  if($count == 1
     and  exists $attr->{anon}
     and  UNIVERSAL::isa($attr->{anon}, 'ARRAY')
  ) {
    return($attr->{anon});
  }


  # Do the right thing if hash is empty, otherwise just return it

  if(!%$attr  and  exists($self->{opt}->{suppressempty})) {
    if(defined($self->{opt}->{suppressempty})  and
       $self->{opt}->{suppressempty} eq '') {
      return('');
    }
    return(undef);
  }


  # Roll up named elements with named nested 'value' attributes

  if($self->{opt}->{valueattr}) {
    while(my($key, $val) = each(%$attr)) {
      next unless($self->{opt}->{valueattr}->{$key});
      next unless(UNIVERSAL::isa($val, 'HASH') and (keys %$val == 1));
      my($k) = keys %$val;
      next unless($k eq $self->{opt}->{valueattr}->{$key});
      $attr->{$key} = $val->{$k};
    }
  }

  return($attr)

}


##############################################################################
# Method: set_var()
#
# Called when a variable definition is encountered in the XML.  (A variable
# definition looks like <element attrname="name">value</element> where attrname
# matches the varattr setting).
#

sub set_var {
  my($self, $name, $value) = @_;

  $self->{_var_values}->{$name} = $value;
}


##############################################################################
# Method: get_var()
#
# Called during variable substitution to get the value for the named variable.
#

sub get_var {
  my($self, $name) = @_;

  my $value = $self->{_var_values}->{$name};
  return $value if(defined($value));

  return '${' . $name . '}';
}


##############################################################################
# Method: normalise_space()
#
# Strips leading and trailing whitespace and collapses sequences of whitespace
# characters to a single space.
#

sub normalise_space {
  my($self, $text) = @_;

  $text =~ s/^\s+//s;
  $text =~ s/\s+$//s;
  $text =~ s/\s\s+/ /sg;

  return $text;
}


##############################################################################
# Method: array_to_hash()
#
# Helper routine for collapse().
# Attempts to 'fold' an array of hashes into an hash of hashes.  Returns a
# reference to the hash on success or the original array if folding is
# not possible.  Behaviour is controlled by 'keyattr' option.
#

sub array_to_hash {
  my $self     = shift;
  my $name     = shift;
  my $arrayref = shift;

  my $hashref  = $self->new_hashref;

  my($i, $key, $val, $flag);


  # Handle keyattr => { .... }

  if(ref($self->{opt}->{keyattr}) eq 'HASH') {
    return($arrayref) unless(exists($self->{opt}->{keyattr}->{$name}));
    ($key, $flag) = @{$self->{opt}->{keyattr}->{$name}};
    for($i = 0; $i < @$arrayref; $i++)  {
      if(UNIVERSAL::isa($arrayref->[$i], 'HASH') and
         exists($arrayref->[$i]->{$key})
      ) {
        $val = $arrayref->[$i]->{$key};
        if(ref($val)) {
          $self->die_or_warn("<$name> element has non-scalar '$key' key attribute");
          return($arrayref);
        }
        $val = $self->normalise_space($val)
          if($self->{opt}->{normalisespace} == 1);
        $self->die_or_warn("<$name> element has non-unique value in '$key' key attribute: $val")
          if(exists($hashref->{$val}));
        $hashref->{$val} = $self->new_hashref( %{$arrayref->[$i]} );
        $hashref->{$val}->{"-$key"} = $hashref->{$val}->{$key} if($flag eq '-');
        delete $hashref->{$val}->{$key} unless($flag eq '+');
      }
      else {
        $self->die_or_warn("<$name> element has no '$key' key attribute");
        return($arrayref);
      }
    }
  }


  # Or assume keyattr => [ .... ]

  else {
    my $default_keys =
      join(',', @DefKeyAttr) eq join(',', @{$self->{opt}->{keyattr}});

    ELEMENT: for($i = 0; $i < @$arrayref; $i++)  {
      return($arrayref) unless(UNIVERSAL::isa($arrayref->[$i], 'HASH'));

      foreach $key (@{$self->{opt}->{keyattr}}) {
        if(defined($arrayref->[$i]->{$key}))  {
          $val = $arrayref->[$i]->{$key};
          if(ref($val)) {
            $self->die_or_warn("<$name> element has non-scalar '$key' key attribute")
              if not $default_keys;
            return($arrayref);
          }
          $val = $self->normalise_space($val)
            if($self->{opt}->{normalisespace} == 1);
          $self->die_or_warn("<$name> element has non-unique value in '$key' key attribute: $val")
            if(exists($hashref->{$val}));
          $hashref->{$val} = $self->new_hashref( %{$arrayref->[$i]} );
          delete $hashref->{$val}->{$key};
          next ELEMENT;
        }
      }

      return($arrayref);    # No keyfield matched
    }
  }

  # collapse any hashes which now only have a 'content' key

  if($self->{opt}->{collapseagain}) {
    $hashref = $self->collapse_content($hashref);
  }

  return($hashref);
}


##############################################################################
# Method: die_or_warn()
#
# Takes a diagnostic message and does one of three things:
# 1. dies if strict mode is enabled
# 2. warns if warnings are enabled but strict mode is not
# 3. ignores message and returns silently if neither strict mode nor warnings
#    are enabled
#

sub die_or_warn {
  my $self = shift;
  my $msg  = shift;

  croak $msg if($self->{opt}->{strictmode});
  if(warnings::enabled()) {
    carp "Warning: $msg";
  }
}


##############################################################################
# Method: new_hashref()
#
# This is a hook routine for overriding in a sub-class.  Some people believe
# that using Tie::IxHash here will solve order-loss problems.
#

sub new_hashref {
  my $self = shift;

  return { @_ };
}


##############################################################################
# Method: collapse_content()
#
# Helper routine for array_to_hash
#
# Arguments expected are:
# - an XML::Simple object
# - a hashref
# the hashref is a former array, turned into a hash by array_to_hash because
# of the presence of key attributes
# at this point collapse_content avoids over-complicated structures like
# dir => { libexecdir    => { content => '$exec_prefix/libexec' },
#          localstatedir => { content => '$prefix' },
#        }
# into
# dir => { libexecdir    => '$exec_prefix/libexec',
#          localstatedir => '$prefix',
#        }

sub collapse_content {
  my $self       = shift;
  my $hashref    = shift;

  my $contentkey = $self->{opt}->{contentkey};

  # first go through the values,checking that they are fit to collapse
  foreach my $val (values %$hashref) {
    return $hashref unless (     (ref($val) eq 'HASH')
                             and (keys %$val == 1)
                             and (exists $val->{$contentkey})
                           );
  }

  # now collapse them
  foreach my $key (keys %$hashref) {
    $hashref->{$key}=  $hashref->{$key}->{$contentkey};
  }

  return $hashref;
}


##############################################################################
# Method: value_to_xml()
#
# Helper routine for XMLout() - recurses through a data structure building up
# and returning an XML representation of that structure as a string.
#
# Arguments expected are:
# - the data structure to be encoded (usually a reference)
# - the XML tag name to use for this item
# - a string of spaces for use as the current indent level
#

sub value_to_xml {
  my $self = shift;;


  # Grab the other arguments

  my($ref, $name, $indent) = @_;

  my $named = (defined($name) and $name ne '' ? 1 : 0);

  my $nl = "\n";

  my $is_root = $indent eq '' ? 1 : 0;   # Warning, dirty hack!
  if($self->{opt}->{noindent}) {
    $indent = '';
    $nl     = '';
  }


  # Convert to XML

  my $refaddr = Scalar::Util::refaddr($ref);
  if($refaddr) {
    croak "circular data structures not supported"
      if $self->{_ancestors}->{$refaddr};
    $self->{_ancestors}->{$refaddr} = $ref;  # keep ref alive until we delete it
  }
  else {
    if($named) {
      return(join('',
              $indent, '<', $name, '>',
              ($self->{opt}->{noescape} ? $ref : $self->escape_value($ref)),
              '</', $name, ">", $nl
            ));
    }
    else {
      return("$ref$nl");
    }
  }


  # Unfold hash to array if possible

  if(UNIVERSAL::isa($ref, 'HASH')      # It is a hash
     and keys %$ref                    # and it's not empty
     and $self->{opt}->{keyattr}       # and folding is enabled
     and !$is_root                     # and its not the root element
  ) {
    $ref = $self->hash_to_array($name, $ref);
  }


  my @result = ();
  my($key, $value);


  # Handle hashrefs

  if(UNIVERSAL::isa($ref, 'HASH')) {

    # Reintermediate grouped values if applicable

    if($self->{opt}->{grouptags}) {
      $ref = $self->copy_hash($ref);
      while(my($key, $val) = each %$ref) {
        if($self->{opt}->{grouptags}->{$key}) {
          $ref->{$key} = $self->new_hashref(
            $self->{opt}->{grouptags}->{$key} => $val
          );
        }
      }
    }


    # Scan for namespace declaration attributes

    my $nsdecls = '';
    my $default_ns_uri;
    if($self->{nsup}) {
      $ref = $self->copy_hash($ref);
      $self->{nsup}->push_context();

      # Look for default namespace declaration first

      if(exists($ref->{xmlns})) {
        $self->{nsup}->declare_prefix('', $ref->{xmlns});
        $nsdecls .= qq( xmlns="$ref->{xmlns}");
        delete($ref->{xmlns});
      }
      $default_ns_uri = $self->{nsup}->get_uri('');


      # Then check all the other keys

      foreach my $qname (keys(%$ref)) {
        my($uri, $lname) = $self->{nsup}->parse_jclark_notation($qname);
        if($uri) {
          if($uri eq $xmlns_ns) {
            $self->{nsup}->declare_prefix($lname, $ref->{$qname});
            $nsdecls .= qq( xmlns:$lname="$ref->{$qname}");
            delete($ref->{$qname});
          }
        }
      }

      # Translate any remaining Clarkian names

      foreach my $qname (keys(%$ref)) {
        my($uri, $lname) = $self->{nsup}->parse_jclark_notation($qname);
        if($uri) {
          if($default_ns_uri  and  $uri eq $default_ns_uri) {
            $ref->{$lname} = $ref->{$qname};
            delete($ref->{$qname});
          }
          else {
            my $prefix = $self->{nsup}->get_prefix($uri);
            unless($prefix) {
              # $self->{nsup}->declare_prefix(undef, $uri);
              # $prefix = $self->{nsup}->get_prefix($uri);
              $prefix = $self->{ns_prefix}++;
              $self->{nsup}->declare_prefix($prefix, $uri);
              $nsdecls .= qq( xmlns:$prefix="$uri");
            }
            $ref->{"$prefix:$lname"} = $ref->{$qname};
            delete($ref->{$qname});
          }
        }
      }
    }


    my @nested = ();
    my $text_content = undef;
    if($named) {
      push @result, $indent, '<', $name, $nsdecls;
    }

    if(keys %$ref) {
      my $first_arg = 1;
      foreach my $key ($self->sorted_keys($name, $ref)) {
        my $value = $ref->{$key};
        next if(substr($key, 0, 1) eq '-');
        if(!defined($value)) {
          next if $self->{opt}->{suppressempty};
          unless(exists($self->{opt}->{suppressempty})
             and !defined($self->{opt}->{suppressempty})
          ) {
            carp 'Use of uninitialized value' if warnings::enabled();
          }
          if($key eq $self->{opt}->{contentkey}) {
            $text_content = '';
          }
          else {
            $value = exists($self->{opt}->{suppressempty}) ? {} : '';
          }
        }

        if(!ref($value)
           and $self->{opt}->{valueattr}
           and $self->{opt}->{valueattr}->{$key}
        ) {
          $value = $self->new_hashref(
            $self->{opt}->{valueattr}->{$key} => $value
          );
        }

        if(ref($value)  or  $self->{opt}->{noattr}) {
          push @nested,
            $self->value_to_xml($value, $key, "$indent  ");
        }
        else {
          if($key eq $self->{opt}->{contentkey}) {
            $value = $self->escape_value($value) unless($self->{opt}->{noescape});
            $text_content = $value;
          }
          else {
            $value = $self->escape_attr($value) unless($self->{opt}->{noescape});
            push @result, "\n$indent " . ' ' x length($name)
              if($self->{opt}->{attrindent}  and  !$first_arg);
            push @result, ' ', $key, '="', $value , '"';
            $first_arg = 0;
          }
        }
      }
    }
    else {
      $text_content = '';
    }

    if(@nested  or  defined($text_content)) {
      if($named) {
        push @result, ">";
        if(defined($text_content)) {
          push @result, $text_content;
          $nested[0] =~ s/^\s+// if(@nested);
        }
        else {
          push @result, $nl;
        }
        if(@nested) {
          push @result, @nested, $indent;
        }
        push @result, '</', $name, ">", $nl;
      }
      else {
        push @result, @nested;             # Special case if no root elements
      }
    }
    else {
      push @result, " />", $nl;
    }
    $self->{nsup}->pop_context() if($self->{nsup});
  }


  # Handle arrayrefs

  elsif(UNIVERSAL::isa($ref, 'ARRAY')) {
    foreach $value (@$ref) {
      next if !defined($value) and $self->{opt}->{suppressempty};
      if(!ref($value)) {
        push @result,
             $indent, '<', $name, '>',
             ($self->{opt}->{noescape} ? $value : $self->escape_value($value)),
             '</', $name, ">$nl";
      }
      elsif(UNIVERSAL::isa($value, 'HASH')) {
        push @result, $self->value_to_xml($value, $name, $indent);
      }
      else {
        push @result,
               $indent, '<', $name, ">$nl",
               $self->value_to_xml($value, 'anon', "$indent  "),
               $indent, '</', $name, ">$nl";
      }
    }
  }

  else {
    croak "Can't encode a value of type: " . ref($ref);
  }


  delete $self->{_ancestors}->{$refaddr};

  return(join('', @result));
}


##############################################################################
# Method: sorted_keys()
#
# Returns the keys of the referenced hash sorted into alphabetical order, but
# with the 'key' key (as in KeyAttr) first, if there is one.
#

sub sorted_keys {
  my($self, $name, $ref) = @_;

  return keys %$ref if $self->{opt}->{nosort};

  my %hash = %$ref;
  my $keyattr = $self->{opt}->{keyattr};

  my @key;

  if(ref $keyattr eq 'HASH') {
    if(exists $keyattr->{$name} and exists $hash{$keyattr->{$name}->[0]}) {
      push @key, $keyattr->{$name}->[0];
      delete $hash{$keyattr->{$name}->[0]};
    }
  }
  elsif(ref $keyattr eq 'ARRAY') {
    foreach (@{$keyattr}) {
      if(exists $hash{$_}) {
        push @key, $_;
        delete $hash{$_};
        last;
      }
    }
  }

  return(@key, sort keys %hash);
}

##############################################################################
# Method: escape_value()
#
# Helper routine for automatically escaping values for XMLout().
# Expects a scalar data value.  Returns escaped version.
#

sub escape_value {
  my($self, $data) = @_;

  return '' unless(defined($data));

  $data =~ s/&/&amp;/sg;
  $data =~ s/</&lt;/sg;
  $data =~ s/>/&gt;/sg;
  $data =~ s/"/&quot;/sg;

  my $level = $self->{opt}->{numericescape} or return $data;

  return $self->numeric_escape($data, $level);
}

sub numeric_escape {
  my($self, $data, $level) = @_;

  if($self->{opt}->{numericescape} eq '2') {
    $data =~ s/([^\x00-\x7F])/'&#' . ord($1) . ';'/gse;
  }
  else {
    $data =~ s/([^\x00-\xFF])/'&#' . ord($1) . ';'/gse;
  }

  return $data;
}

##############################################################################
# Method: escape_attr()
#
# Helper routine for escaping attribute values.  Defaults to escape_value(),
# but may be overridden by a subclass to customise behaviour.
#

sub escape_attr {
  my $self = shift;

  return $self->escape_value(@_);
}


##############################################################################
# Method: hash_to_array()
#
# Helper routine for value_to_xml().
# Attempts to 'unfold' a hash of hashes into an array of hashes.  Returns a
# reference to the array on success or the original hash if unfolding is
# not possible.
#

sub hash_to_array {
  my $self    = shift;
  my $parent  = shift;
  my $hashref = shift;

  my $arrayref = [];

  my($key, $value);

  my @keys = $self->{opt}->{nosort} ? keys %$hashref : sort keys %$hashref;
  foreach $key (@keys) {
    $value = $hashref->{$key};
    return($hashref) unless(UNIVERSAL::isa($value, 'HASH'));

    if(ref($self->{opt}->{keyattr}) eq 'HASH') {
      return($hashref) unless(defined($self->{opt}->{keyattr}->{$parent}));
      push @$arrayref, $self->copy_hash(
        $value, $self->{opt}->{keyattr}->{$parent}->[0] => $key
      );
    }
    else {
      push(@$arrayref, { $self->{opt}->{keyattr}->[0] => $key, %$value });
    }
  }

  return($arrayref);
}


##############################################################################
# Method: copy_hash()
#
# Helper routine for hash_to_array().  When unfolding a hash of hashes into
# an array of hashes, we need to copy the key from the outer hash into the
# inner hash.  This routine makes a copy of the original hash so we don't
# destroy the original data structure.  You might wish to override this
# method if you're using tied hashes and don't want them to get untied.
#

sub copy_hash {
  my($self, $orig, @extra) = @_;

  return { @extra, %$orig };
}

##############################################################################
# Methods required for building trees from SAX events
##############################################################################

sub start_document {
  my $self = shift;

  $self->handle_options('in') unless($self->{opt});

  $self->{lists} = [];
  $self->{curlist} = $self->{tree} = [];
}


sub start_element {
  my $self    = shift;
  my $element = shift;

  my $name = $element->{Name};
  if($self->{opt}->{nsexpand}) {
    $name = $element->{LocalName} || '';
    if($element->{NamespaceURI}) {
      $name = '{' . $element->{NamespaceURI} . '}' . $name;
    }
  }
  my $attributes = {};
  if($element->{Attributes}) {  # Might be undef
    foreach my $attr (values %{$element->{Attributes}}) {
      if($self->{opt}->{nsexpand}) {
        my $name = $attr->{LocalName} || '';
        if($attr->{NamespaceURI}) {
          $name = '{' . $attr->{NamespaceURI} . '}' . $name
        }
        $name = 'xmlns' if($name eq $bad_def_ns_jcn);
        $attributes->{$name} = $attr->{Value};
      }
      else {
        $attributes->{$attr->{Name}} = $attr->{Value};
      }
    }
  }
  my $newlist = [ $attributes ];
  push @{ $self->{lists} }, $self->{curlist};
  push @{ $self->{curlist} }, $name => $newlist;
  $self->{curlist} = $newlist;
}


sub characters {
  my $self  = shift;
  my $chars = shift;

  my $text  = $chars->{Data};
  my $clist = $self->{curlist};
  my $pos = $#$clist;

  if ($pos > 0 and $clist->[$pos - 1] eq '0') {
    $clist->[$pos] .= $text;
  }
  else {
    push @$clist, 0 => $text;
  }
}


sub end_element {
  my $self    = shift;

  $self->{curlist} = pop @{ $self->{lists} };
}


sub end_document {
  my $self = shift;

  delete($self->{curlist});
  delete($self->{lists});

  my $tree = $self->{tree};
  delete($self->{tree});


  # Return tree as-is to XMLin()

  return($tree) if($self->{nocollapse});


  # Or collapse it before returning it to SAX parser class

  if($self->{opt}->{keeproot}) {
    $tree = $self->collapse({}, @$tree);
  }
  else {
    $tree = $self->collapse(@{$tree->[1]});
  }

  if($self->{opt}->{datahandler}) {
    return($self->{opt}->{datahandler}->($self, $tree));
  }

  return($tree);
}

*xml_in  = \&XMLin;
*xml_out = \&XMLout;

1;

__END__

=head1 STATUS OF THIS MODULE

The use of this module in new code is B<strongly discouraged>.  Other modules
are available which provide more straightforward and consistent interfaces.  In
particular, L<XML::LibXML> is highly recommended and you can refer to
L<Perl XML::LibXML by Example|http://grantm.github.io/perl-libxml-by-example/>
for a tutorial introduction.

L<XML::Twig> is another excellent alternative.

The major problems with this module are the large number of options (some of
which have unfortunate defaults) and the arbitrary ways in which these options
interact - often producing unexpected results.

Patches with bug fixes and documentation fixes are welcome, but new features
are unlikely to be added.

=head1 QUICK START

Say you have a script called B<foo> and a file of configuration options
called B<foo.xml> containing the following:

  <config logdir="/var/log/foo/" debugfile="/tmp/foo.debug">
    <server name="sahara" osname="solaris" osversion="2.6">
      <address>10.0.0.101</address>
      <address>10.0.1.101</address>
    </server>
    <server name="gobi" osname="irix" osversion="6.5">
      <address>10.0.0.102</address>
    </server>
    <server name="kalahari" osname="linux" osversion="2.0.34">
      <address>10.0.0.103</address>
      <address>10.0.1.103</address>
    </server>
  </config>

The following lines of code in B<foo>:

  use XML::Simple qw(:strict);

  my $config = XMLin(undef, KeyAttr => { server => 'name' }, ForceArray => [ 'server', 'address' ]);

will 'slurp' the configuration options into the hashref $config (because no
filename or XML string was passed as the first argument to C<XMLin()> the name
and location of the XML file will be inferred from name and location of the
script).  You can dump out the contents of the hashref using Data::Dumper:

  use Data::Dumper;

  print Dumper($config);

which will produce something like this (formatting has been adjusted for
brevity):

  {
      'logdir'        => '/var/log/foo/',
      'debugfile'     => '/tmp/foo.debug',
      'server'        => {
          'sahara'        => {
              'osversion'     => '2.6',
              'osname'        => 'solaris',
              'address'       => [ '10.0.0.101', '10.0.1.101' ]
          },
          'gobi'          => {
              'osversion'     => '6.5',
              'osname'        => 'irix',
              'address'       => [ '10.0.0.102' ]
          },
          'kalahari'      => {
              'osversion'     => '2.0.34',
              'osname'        => 'linux',
              'address'       => [ '10.0.0.103', '10.0.1.103' ]
          }
      }
  }

Your script could then access the name of the log directory like this:

  print $config->{logdir};

similarly, the second address on the server 'kalahari' could be referenced as:

  print $config->{server}->{kalahari}->{address}->[1];

Note: If the mapping between the output of Data::Dumper and the print
statements above is not obvious to you, then please refer to the 'references'
tutorial (AKA: "Mark's very short tutorial about references") at L<perlreftut>.

In this example, the C<< ForceArray >> option was used to list elements that
might occur multiple times and should therefore be represented as arrayrefs
(even when only one element is present).

The C<< KeyAttr >> option was used to indicate that each C<< <server> >>
element has a unique identifier in the C<< name >> attribute.  This allows you
to index directly to a particular server record using the name as a hash key
(as shown above).

For simple requirements, that's really all there is to it.  If you want to
store your XML in a different directory or file, or pass it in as a string or
even pass it in via some derivative of an IO::Handle, you'll need to check out
L<"OPTIONS">.  If you want to turn off or tweak the array folding feature (that
neat little transformation that produced $config->{server}) you'll find options
for that as well.

If you want to generate XML (for example to write a modified version of
$config back out as XML), check out C<XMLout()>.

If your needs are not so simple, this may not be the module for you.  In that
case, you might want to read L<"WHERE TO FROM HERE?">.

=head1 DESCRIPTION

The XML::Simple module provides a simple API layer on top of an underlying XML
parsing module (either XML::Parser or one of the SAX2 parser modules).  Two
functions are exported: C<XMLin()> and C<XMLout()>.  Note: you can explicitly
request the lower case versions of the function names: C<xml_in()> and
C<xml_out()>.

The simplest approach is to call these two functions directly, but an
optional object oriented interface (see L<"OPTIONAL OO INTERFACE"> below)
allows them to be called as methods of an B<XML::Simple> object.  The object
interface can also be used at either end of a SAX pipeline.

=head2 XMLin()

Parses XML formatted data and returns a reference to a data structure which
contains the same information in a more readily accessible form.  (Skip
down to L<"EXAMPLES"> below, for more sample code).

C<XMLin()> accepts an optional XML specifier followed by zero or more 'name =>
value' option pairs.  The XML specifier can be one of the following:

=over 4

=item A filename

If the filename contains no directory components C<XMLin()> will look for the
file in each directory in the SearchPath (see L<"OPTIONS"> below) or in the
current directory if the SearchPath option is not defined.  eg:

  $ref = XMLin('/etc/params.xml');

Note, the filename '-' can be used to parse from STDIN.

=item undef

If there is no XML specifier, C<XMLin()> will check the script directory and
each of the SearchPath directories for a file with the same name as the script
but with the extension '.xml'.  Note: if you wish to specify options, you
must specify the value 'undef'.  eg:

  $ref = XMLin(undef, ForceArray => 1);

=item A string of XML

A string containing XML (recognised by the presence of '<' and '>' characters)
will be parsed directly.  eg:

  $ref = XMLin('<opt username="bob" password="flurp" />');

=item An IO::Handle object

An IO::Handle object will be read to EOF and its contents parsed. eg:

  $fh = IO::File->new('/etc/params.xml');
  $ref = XMLin($fh);

=back

=head2 XMLout()

Takes a data structure (generally a hashref) and returns an XML encoding of
that structure.  If the resulting XML is parsed using C<XMLin()>, it should
return a data structure equivalent to the original (see caveats below).

The C<XMLout()> function can also be used to output the XML as SAX events
see the C<Handler> option and L<"SAX SUPPORT"> for more details).

When translating hashes to XML, hash keys which have a leading '-' will be
silently skipped.  This is the approved method for marking elements of a
data structure which should be ignored by C<XMLout>.  (Note: If these items
were not skipped the key names would be emitted as element or attribute names
with a leading '-' which would not be valid XML).

=head2 Caveats

Some care is required in creating data structures which will be passed to
C<XMLout()>.  Hash keys from the data structure will be encoded as either XML
element names or attribute names.  Therefore, you should use hash key names
which conform to the relatively strict XML naming rules:

Names in XML must begin with a letter.  The remaining characters may be
letters, digits, hyphens (-), underscores (_) or full stops (.).  It is also
allowable to include one colon (:) in an element name but this should only be
used when working with namespaces (B<XML::Simple> can only usefully work with
namespaces when teamed with a SAX Parser).

You can use other punctuation characters in hash values (just not in hash
keys) however B<XML::Simple> does not support dumping binary data.

If you break these rules, the current implementation of C<XMLout()> will
simply emit non-compliant XML which will be rejected if you try to read it
back in.  (A later version of B<XML::Simple> might take a more proactive
approach).

Note also that although you can nest hashes and arrays to arbitrary levels,
circular data structures are not supported and will cause C<XMLout()> to die.

If you wish to 'round-trip' arbitrary data structures from Perl to XML and back
to Perl, then you should probably disable array folding (using the KeyAttr
option) both with C<XMLout()> and with C<XMLin()>.  If you still don't get the
expected results, you may prefer to use L<XML::Dumper> which is designed for
exactly that purpose.

Refer to L<"WHERE TO FROM HERE?"> if C<XMLout()> is too simple for your needs.


=head1 OPTIONS

B<XML::Simple> supports a number of options (in fact as each release of
B<XML::Simple> adds more options, the module's claim to the name 'Simple'
becomes increasingly tenuous).  If you find yourself repeatedly having to
specify the same options, you might like to investigate L<"OPTIONAL OO
INTERFACE"> below.

If you can't be bothered reading the documentation, refer to
L<"STRICT MODE"> to automatically catch common mistakes.

Because there are so many options, it's hard for new users to know which ones
are important, so here are the two you really need to know about:

=over 4

=item *

check out C<ForceArray> because you'll almost certainly want to turn it on

=item *

make sure you know what the C<KeyAttr> option does and what its default value is
because it may surprise you otherwise (note in particular that 'KeyAttr'
affects both C<XMLin> and C<XMLout>)

=back

The option name headings below have a trailing 'comment' - a hash followed by
two pieces of metadata:

=over 4

=item *

Options are marked with 'I<in>' if they are recognised by C<XMLin()> and
'I<out>' if they are recognised by C<XMLout()>.

=item *

Each option is also flagged to indicate whether it is:

 'important'   - don't use the module until you understand this one
 'handy'       - you can skip this on the first time through
 'advanced'    - you can skip this on the second time through
 'SAX only'    - don't worry about this unless you're using SAX (or
                 alternatively if you need this, you also need SAX)
 'seldom used' - you'll probably never use this unless you were the
                 person that requested the feature

=back

The options are listed alphabetically:

Note: option names are no longer case sensitive so you can use the mixed case
versions shown here; all lower case as required by versions 2.03 and earlier;
or you can add underscores between the words (eg: key_attr).


=head2 AttrIndent => 1 I<# out - handy>

When you are using C<XMLout()>, enable this option to have attributes printed
one-per-line with sensible indentation rather than all on one line.

=head2 Cache => [ cache schemes ] I<# in - advanced>

Because loading the B<XML::Parser> module and parsing an XML file can consume a
significant number of CPU cycles, it is often desirable to cache the output of
C<XMLin()> for later reuse.

When parsing from a named file, B<XML::Simple> supports a number of caching
schemes.  The 'Cache' option may be used to specify one or more schemes (using
an anonymous array).  Each scheme will be tried in turn in the hope of finding
a cached pre-parsed representation of the XML file.  If no cached copy is
found, the file will be parsed and the first cache scheme in the list will be
used to save a copy of the results.  The following cache schemes have been
implemented:

=over 4

=item storable

Utilises B<Storable.pm> to read/write a cache file with the same name as the
XML file but with the extension .stor

=item memshare

When a file is first parsed, a copy of the resulting data structure is retained
in memory in the B<XML::Simple> module's namespace.  Subsequent calls to parse
the same file will return a reference to this structure.  This cached version
will persist only for the life of the Perl interpreter (which in the case of
mod_perl for example, may be some significant time).

Because each caller receives a reference to the same data structure, a change
made by one caller will be visible to all.  For this reason, the reference
returned should be treated as read-only.

=item memcopy

This scheme works identically to 'memshare' (above) except that each caller
receives a reference to a new data structure which is a copy of the cached
version.  Copying the data structure will add a little processing overhead,
therefore this scheme should only be used where the caller intends to modify
the data structure (or wishes to protect itself from others who might).  This
scheme uses B<Storable.pm> to perform the copy.

=back

Warning! The memory-based caching schemes compare the timestamp on the file to
the time when it was last parsed.  If the file is stored on an NFS filesystem
(or other network share) and the clock on the file server is not exactly
synchronised with the clock where your script is run, updates to the source XML
file may appear to be ignored.

=head2 ContentKey => 'keyname' I<# in+out - seldom used>

When text content is parsed to a hash value, this option lets you specify a
name for the hash key to override the default 'content'.  So for example:

  XMLin('<opt one="1">Text</opt>', ContentKey => 'text')

will parse to:

  { 'one' => 1, 'text' => 'Text' }

instead of:

  { 'one' => 1, 'content' => 'Text' }

C<XMLout()> will also honour the value of this option when converting a hashref
to XML.

You can also prefix your selected key name with a '-' character to have
C<XMLin()> try a little harder to eliminate unnecessary 'content' keys after
array folding.  For example:

  XMLin(
    '<opt><item name="one">First</item><item name="two">Second</item></opt>',
    KeyAttr => {item => 'name'},
    ForceArray => [ 'item' ],
    ContentKey => '-content'
  )

will parse to:

  {
    'item' => {
      'one' =>  'First'
      'two' =>  'Second'
    }
  }

rather than this (without the '-'):

  {
    'item' => {
      'one' => { 'content' => 'First' }
      'two' => { 'content' => 'Second' }
    }
  }

=head2 DataHandler => code_ref I<# in - SAX only>

When you use an B<XML::Simple> object as a SAX handler, it will return a
'simple tree' data structure in the same format as C<XMLin()> would return.  If
this option is set (to a subroutine reference), then when the tree is built the
subroutine will be called and passed two arguments: a reference to the
B<XML::Simple> object and a reference to the data tree.  The return value from
the subroutine will be returned to the SAX driver.  (See L<"SAX SUPPORT"> for
more details).

=head2 ForceArray => 1 I<# in - important>

This option should be set to '1' to force nested elements to be represented
as arrays even when there is only one.  Eg, with ForceArray enabled, this
XML:

    <opt>
      <name>value</name>
    </opt>

would parse to this:

    {
      'name' => [
                  'value'
                ]
    }

instead of this (the default):

    {
      'name' => 'value'
    }

This option is especially useful if the data structure is likely to be written
back out as XML and the default behaviour of rolling single nested elements up
into attributes is not desirable.

If you are using the array folding feature, you should almost certainly enable
this option.  If you do not, single nested elements will not be parsed to
arrays and therefore will not be candidates for folding to a hash.  (Given that
the default value of 'KeyAttr' enables array folding, the default value of this
option should probably also have been enabled too - sorry).

=head2 ForceArray => [ names ] I<# in - important>

This alternative (and preferred) form of the 'ForceArray' option allows you to
specify a list of element names which should always be forced into an array
representation, rather than the 'all or nothing' approach above.

It is also possible (since version 2.05) to include compiled regular
expressions in the list - any element names which match the pattern will be
forced to arrays.  If the list contains only a single regex, then it is not
necessary to enclose it in an arrayref.  Eg:

  ForceArray => qr/_list$/

=head2 ForceContent => 1 I<# in - seldom used>

When C<XMLin()> parses elements which have text content as well as attributes,
the text content must be represented as a hash value rather than a simple
scalar.  This option allows you to force text content to always parse to
a hash value even when there are no attributes.  So for example:

  XMLin('<opt><x>text1</x><y a="2">text2</y></opt>', ForceContent => 1)

will parse to:

  {
    'x' => {           'content' => 'text1' },
    'y' => { 'a' => 2, 'content' => 'text2' }
  }

instead of:

  {
    'x' => 'text1',
    'y' => { 'a' => 2, 'content' => 'text2' }
  }

=head2 GroupTags => { grouping tag => grouped tag } I<# in+out - handy>

You can use this option to eliminate extra levels of indirection in your Perl
data structure.  For example this XML:

  <opt>
   <searchpath>
     <dir>/usr/bin</dir>
     <dir>/usr/local/bin</dir>
     <dir>/usr/X11/bin</dir>
   </searchpath>
 </opt>

Would normally be read into a structure like this:

  {
    searchpath => {
                    dir => [ '/usr/bin', '/usr/local/bin', '/usr/X11/bin' ]
                  }
  }

But when read in with the appropriate value for 'GroupTags':

  my $opt = XMLin($xml, GroupTags => { searchpath => 'dir' });

It will return this simpler structure:

  {
    searchpath => [ '/usr/bin', '/usr/local/bin', '/usr/X11/bin' ]
  }

The grouping element (C<< <searchpath> >> in the example) must not contain any
attributes or elements other than the grouped element.

You can specify multiple 'grouping element' to 'grouped element' mappings in
the same hashref.  If this option is combined with C<KeyAttr>, the array
folding will occur first and then the grouped element names will be eliminated.

C<XMLout> will also use the grouptag mappings to re-introduce the tags around
the grouped elements.  Beware though that this will occur in all places that
the 'grouping tag' name occurs - you probably don't want to use the same name
for elements as well as attributes.

=head2 Handler => object_ref I<# out - SAX only>

Use the 'Handler' option to have C<XMLout()> generate SAX events rather than
returning a string of XML.  For more details see L<"SAX SUPPORT"> below.

Note: the current implementation of this option generates a string of XML
and uses a SAX parser to translate it into SAX events.  The normal encoding
rules apply here - your data must be UTF8 encoded unless you specify an
alternative encoding via the 'XMLDecl' option; and by the time the data reaches
the handler object, it will be in UTF8 form regardless of the encoding you
supply.  A future implementation of this option may generate the events
directly.

=head2 KeepRoot => 1 I<# in+out - handy>

In its attempt to return a data structure free of superfluous detail and
unnecessary levels of indirection, C<XMLin()> normally discards the root
element name.  Setting the 'KeepRoot' option to '1' will cause the root element
name to be retained.  So after executing this code:

  $config = XMLin('<config tempdir="/tmp" />', KeepRoot => 1)

You'll be able to reference the tempdir as
C<$config-E<gt>{config}-E<gt>{tempdir}> instead of the default
C<$config-E<gt>{tempdir}>.

Similarly, setting the 'KeepRoot' option to '1' will tell C<XMLout()> that the
data structure already contains a root element name and it is not necessary to
add another.

=head2 KeyAttr => [ list ] I<# in+out - important>

This option controls the 'array folding' feature which translates nested
elements from an array to a hash.  It also controls the 'unfolding' of hashes
to arrays.

For example, this XML:

    <opt>
      <user login="grep" fullname="Gary R Epstein" />
      <user login="stty" fullname="Simon T Tyson" />
    </opt>

would, by default, parse to this:

    {
      'user' => [
                  {
                    'login' => 'grep',
                    'fullname' => 'Gary R Epstein'
                  },
                  {
                    'login' => 'stty',
                    'fullname' => 'Simon T Tyson'
                  }
                ]
    }

If the option 'KeyAttr => "login"' were used to specify that the 'login'
attribute is a key, the same XML would parse to:

    {
      'user' => {
                  'stty' => {
                              'fullname' => 'Simon T Tyson'
                            },
                  'grep' => {
                              'fullname' => 'Gary R Epstein'
                            }
                }
    }

The key attribute names should be supplied in an arrayref if there is more
than one.  C<XMLin()> will attempt to match attribute names in the order
supplied.  C<XMLout()> will use the first attribute name supplied when
'unfolding' a hash into an array.

Note 1: The default value for 'KeyAttr' is ['name', 'key', 'id'].  If you do
not want folding on input or unfolding on output you must set this option
to an empty list to disable the feature.

Note 2: If you wish to use this option, you should also enable the
C<ForceArray> option.  Without 'ForceArray', a single nested element will be
rolled up into a scalar rather than an array and therefore will not be folded
(since only arrays get folded).

=head2 KeyAttr => { list } I<# in+out - important>

This alternative (and preferred) method of specifying the key attributes
allows more fine grained control over which elements are folded and on which
attributes.  For example the option 'KeyAttr => { package => 'id' } will cause
any package elements to be folded on the 'id' attribute.  No other elements
which have an 'id' attribute will be folded at all.

Note: C<XMLin()> will generate a warning (or a fatal error in L<"STRICT MODE">)
if this syntax is used and an element which does not have the specified key
attribute is encountered (eg: a 'package' element without an 'id' attribute, to
use the example above).  Warnings can be suppressed with the lexical
C<no warnings;> pragma or C<no warnings 'XML::Simple';>.

Two further variations are made possible by prefixing a '+' or a '-' character
to the attribute name:

The option 'KeyAttr => { user => "+login" }' will cause this XML:

    <opt>
      <user login="grep" fullname="Gary R Epstein" />
      <user login="stty" fullname="Simon T Tyson" />
    </opt>

to parse to this data structure:

    {
      'user' => {
                  'stty' => {
                              'fullname' => 'Simon T Tyson',
                              'login'    => 'stty'
                            },
                  'grep' => {
                              'fullname' => 'Gary R Epstein',
                              'login'    => 'grep'
                            }
                }
    }

The '+' indicates that the value of the key attribute should be copied rather
than moved to the folded hash key.

A '-' prefix would produce this result:

    {
      'user' => {
                  'stty' => {
                              'fullname' => 'Simon T Tyson',
                              '-login'    => 'stty'
                            },
                  'grep' => {
                              'fullname' => 'Gary R Epstein',
                              '-login'    => 'grep'
                            }
                }
    }

As described earlier, C<XMLout> will ignore hash keys starting with a '-'.

=head2 NoAttr => 1 I<# in+out - handy>

When used with C<XMLout()>, the generated XML will contain no attributes.
All hash key/values will be represented as nested elements instead.

When used with C<XMLin()>, any attributes in the XML will be ignored.

=head2 NoEscape => 1 I<# out - seldom used>

By default, C<XMLout()> will translate the characters 'E<lt>', 'E<gt>', '&' and
'"' to '&lt;', '&gt;', '&amp;' and '&quot' respectively.  Use this option to
suppress escaping (presumably because you've already escaped the data in some
more sophisticated manner).

=head2 NoIndent => 1 I<# out - seldom used>

Set this option to 1 to disable C<XMLout()>'s default 'pretty printing' mode.
With this option enabled, the XML output will all be on one line (unless there
are newlines in the data) - this may be easier for downstream processing.

=head2 NoSort => 1 I<# out - seldom used>

Newer versions of XML::Simple sort elements and attributes alphabetically (*),
by default.  Enable this option to suppress the sorting - possibly for
backwards compatibility.

* Actually, sorting is alphabetical but 'key' attribute or element names (as in
'KeyAttr') sort first.  Also, when a hash of hashes is 'unfolded', the elements
are sorted alphabetically by the value of the key field.

=head2 NormaliseSpace => 0 | 1 | 2 I<# in - handy>

This option controls how whitespace in text content is handled.  Recognised
values for the option are:

=over 4

=item *

0 = (default) whitespace is passed through unaltered (except of course for the
normalisation of whitespace in attribute values which is mandated by the XML
recommendation)

=item *

1 = whitespace is normalised in any value used as a hash key (normalising means
removing leading and trailing whitespace and collapsing sequences of whitespace
characters to a single space)

=item *

2 = whitespace is normalised in all text content

=back

Note: you can spell this option with a 'z' if that is more natural for you.

=head2 NSExpand => 1 I<# in+out handy - SAX only>

This option controls namespace expansion - the translation of element and
attribute names of the form 'prefix:name' to '{uri}name'.  For example the
element name 'xsl:template' might be expanded to:
'{http://www.w3.org/1999/XSL/Transform}template'.

By default, C<XMLin()> will return element names and attribute names exactly as
they appear in the XML.  Setting this option to 1 will cause all element and
attribute names to be expanded to include their namespace prefix.

I<Note: You must be using a SAX parser for this option to work (ie: it does not
work with XML::Parser)>.

This option also controls whether C<XMLout()> performs the reverse translation
from '{uri}name' back to 'prefix:name'.  The default is no translation.  If
your data contains expanded names, you should set this option to 1 otherwise
C<XMLout> will emit XML which is not well formed.

I<Note: You must have the XML::NamespaceSupport module installed if you want
C<XMLout()> to translate URIs back to prefixes>.

=head2 NumericEscape => 0 | 1 | 2 I<# out - handy>

Use this option to have 'high' (non-ASCII) characters in your Perl data
structure converted to numeric entities (eg: &#8364;) in the XML output.  Three
levels are possible:

0 - default: no numeric escaping (OK if you're writing out UTF8)

1 - only characters above 0xFF are escaped (ie: characters in the 0x80-FF range are not escaped), possibly useful with ISO8859-1 output

2 - all characters above 0x7F are escaped (good for plain ASCII output)

=head2 OutputFile => <file specifier> I<# out - handy>

The default behaviour of C<XMLout()> is to return the XML as a string.  If you
wish to write the XML to a file, simply supply the filename using the
'OutputFile' option.

This option also accepts an IO handle object - especially useful in Perl 5.8.0
and later for output using an encoding other than UTF-8, eg:

  open my $fh, '>:encoding(iso-8859-1)', $path or die "open($path): $!";
  XMLout($ref, OutputFile => $fh);

Note, XML::Simple does not require that the object you pass in to the
OutputFile option inherits from L<IO::Handle> - it simply assumes the object
supports a C<print> method.

=head2 ParserOpts => [ XML::Parser Options ] I<# in - don't use this>

I<Note: This option is now officially deprecated.  If you find it useful, email
the author with an example of what you use it for.  Do not use this option to
set the ProtocolEncoding, that's just plain wrong - fix the XML>.

This option allows you to pass parameters to the constructor of the underlying
XML::Parser object (which of course assumes you're not using SAX).

=head2 RootName => 'string' I<# out - handy>

By default, when C<XMLout()> generates XML, the root element will be named
'opt'.  This option allows you to specify an alternative name.

Specifying either undef or the empty string for the RootName option will
produce XML with no root elements.  In most cases the resulting XML fragment
will not be 'well formed' and therefore could not be read back in by C<XMLin()>.
Nevertheless, the option has been found to be useful in certain circumstances.

=head2 SearchPath => [ list ] I<# in - handy>

If you pass C<XMLin()> a filename, but the filename include no directory
component, you can use this option to specify which directories should be
searched to locate the file.  You might use this option to search first in the
user's home directory, then in a global directory such as /etc.

If a filename is provided to C<XMLin()> but SearchPath is not defined, the
file is assumed to be in the current directory.

If the first parameter to C<XMLin()> is undefined, the default SearchPath
will contain only the directory in which the script itself is located.
Otherwise the default SearchPath will be empty.

=head2 StrictMode => 1 | 0  I<# in+out seldom used>

This option allows you to turn L<STRICT MODE> on or off for a particular call,
regardless of whether it was enabled at the time XML::Simple was loaded.

=head2 SuppressEmpty => 1 | '' | undef I<# in+out - handy>

This option controls what C<XMLin()> should do with empty elements (no
attributes and no content).  The default behaviour is to represent them as
empty hashes.  Setting this option to a true value (eg: 1) will cause empty
elements to be skipped altogether.  Setting the option to 'undef' or the empty
string will cause empty elements to be represented as the undefined value or
the empty string respectively.  The latter two alternatives are a little
easier to test for in your code than a hash with no keys.

The option also controls what C<XMLout()> does with undefined values.  Setting
the option to undef causes undefined values to be output as empty elements
(rather than empty attributes), it also suppresses the generation of warnings
about undefined values.  Setting the option to a true value (eg: 1) causes
undefined values to be skipped altogether on output.

=head2 ValueAttr => [ names ] I<# in - handy>

Use this option to deal elements which always have a single attribute and no
content.  Eg:

  <opt>
    <colour value="red" />
    <size   value="XXL" />
  </opt>

Setting C<< ValueAttr => [ 'value' ] >> will cause the above XML to parse to:

  {
    colour => 'red',
    size   => 'XXL'
  }

instead of this (the default):

  {
    colour => { value => 'red' },
    size   => { value => 'XXL' }
  }

Note: This form of the ValueAttr option is not compatible with C<XMLout()> -
since the attribute name is discarded at parse time, the original XML cannot be
reconstructed.

=head2 ValueAttr => { element => attribute, ... } I<# in+out - handy>

This (preferred) form of the ValueAttr option requires you to specify both
the element and the attribute names.  This is not only safer, it also allows
the original XML to be reconstructed by C<XMLout()>.

Note: You probably don't want to use this option and the NoAttr option at the
same time.

=head2 Variables => { name => value } I<# in - handy>

This option allows variables in the XML to be expanded when the file is read.
(there is no facility for putting the variable names back if you regenerate
XML using C<XMLout>).

A 'variable' is any text of the form C<${name}> which occurs in an attribute
value or in the text content of an element.  If 'name' matches a key in the
supplied hashref, C<${name}> will be replaced with the corresponding value from
the hashref.  If no matching key is found, the variable will not be replaced.
Names must match the regex: C<[\w.]+> (ie: only 'word' characters and dots are
allowed).

=head2 VarAttr => 'attr_name' I<# in - handy>

In addition to the variables defined using C<Variables>, this option allows
variables to be defined in the XML.  A variable definition consists of an
element with an attribute called 'attr_name' (the value of the C<VarAttr>
option).  The value of the attribute will be used as the variable name and the
text content of the element will be used as the value.  A variable defined in
this way will override a variable defined using the C<Variables> option.  For
example:

  XMLin( '<opt>
            <dir name="prefix">/usr/local/apache</dir>
            <dir name="exec_prefix">${prefix}</dir>
            <dir name="bindir">${exec_prefix}/bin</dir>
          </opt>',
         VarAttr => 'name', ContentKey => '-content'
        );

produces the following data structure:

  {
    dir => {
             prefix      => '/usr/local/apache',
             exec_prefix => '/usr/local/apache',
             bindir      => '/usr/local/apache/bin',
           }
  }

=head2 XMLDecl => 1  or  XMLDecl => 'string'  I<# out - handy>

If you want the output from C<XMLout()> to start with the optional XML
declaration, simply set the option to '1'.  The default XML declaration is:

        <?xml version='1.0' standalone='yes'?>

If you want some other string (for example to declare an encoding value), set
the value of this option to the complete string you require.


=head1 OPTIONAL OO INTERFACE

The procedural interface is both simple and convenient however there are a
couple of reasons why you might prefer to use the object oriented (OO)
interface:

=over 4

=item *

to define a set of default values which should be used on all subsequent calls
to C<XMLin()> or C<XMLout()>

=item *

to override methods in B<XML::Simple> to provide customised behaviour

=back

The default values for the options described above are unlikely to suit
everyone.  The OO interface allows you to effectively override B<XML::Simple>'s
defaults with your preferred values.  It works like this:

First create an XML::Simple parser object with your preferred defaults:

  my $xs = XML::Simple->new(ForceArray => 1, KeepRoot => 1);

then call C<XMLin()> or C<XMLout()> as a method of that object:

  my $ref = $xs->XMLin($xml);
  my $xml = $xs->XMLout($ref);

You can also specify options when you make the method calls and these values
will be merged with the values specified when the object was created.  Values
specified in a method call take precedence.

Note: when called as methods, the C<XMLin()> and C<XMLout()> routines may be
called as C<xml_in()> or C<xml_out()>.  The method names are aliased so the
only difference is the aesthetics.

=head2 Parsing Methods

You can explicitly call one of the following methods rather than rely on the
C<xml_in()> method automatically determining whether the target to be parsed is
a string, a file or a filehandle:

=over 4

=item parse_string(text)

Works exactly like the C<xml_in()> method but assumes the first argument is
a string of XML (or a reference to a scalar containing a string of XML).

=item parse_file(filename)

Works exactly like the C<xml_in()> method but assumes the first argument is
the name of a file containing XML.

=item parse_fh(file_handle)

Works exactly like the C<xml_in()> method but assumes the first argument is
a filehandle which can be read to get XML.

=back

=head2 Hook Methods

You can make your own class which inherits from XML::Simple and overrides
certain behaviours.  The following methods may provide useful 'hooks' upon
which to hang your modified behaviour.  You may find other undocumented methods
by examining the source, but those may be subject to change in future releases.

=over 4

=item new_xml_parser()

This method will be called when a new XML::Parser object must be constructed
(either because XML::SAX is not installed or XML::Parser is preferred).

=item handle_options(direction, name => value ...)

This method will be called when one of the parsing methods or the C<XMLout()>
method is called.  The initial argument will be a string (either 'in' or 'out')
and the remaining arguments will be name value pairs.

=item default_config_file()

Calculates and returns the name of the file which should be parsed if no
filename is passed to C<XMLin()> (default: C<$0.xml>).

=item build_simple_tree(filename, string)

Called from C<XMLin()> or any of the parsing methods.  Takes either a file name
as the first argument or C<undef> followed by a 'string' as the second
argument.  Returns a simple tree data structure.  You could override this
method to apply your own transformations before the data structure is returned
to the caller.

=item new_hashref()

When the 'simple tree' data structure is being built, this method will be
called to create any required anonymous hashrefs.

=item sorted_keys(name, hashref)

Called when C<XMLout()> is translating a hashref to XML.  This routine returns
a list of hash keys in the order that the corresponding attributes/elements
should appear in the output.

=item escape_value(string)

Called from C<XMLout()>, takes a string and returns a copy of the string with
XML character escaping rules applied.

=item escape_attr(string)

Called from C<XMLout()>, to handle attribute values.  By default, just calls
C<escape_value()>, but you can override this method if you want attributes
escaped differently than text content.

=item numeric_escape(string)

Called from C<escape_value()>, to handle non-ASCII characters (depending on the
value of the NumericEscape option).

=item copy_hash(hashref, extra_key => value, ...)

Called from C<XMLout()>, when 'unfolding' a hash of hashes into an array of
hashes.  You might wish to override this method if you're using tied hashes and
don't want them to get untied.

=back

=head2 Cache Methods

XML::Simple implements three caching schemes ('storable', 'memshare' and
'memcopy').  You can implement a custom caching scheme by implementing
two methods - one for reading from the cache and one for writing to it.

For example, you might implement a new 'dbm' scheme that stores cached data
structures using the L<MLDBM> module.  First, you would add a
C<cache_read_dbm()> method which accepted a filename for use as a lookup key
and returned a data structure on success, or undef on failure.  Then, you would
implement a C<cache_read_dbm()> method which accepted a data structure and a
filename.

You would use this caching scheme by specifying the option:

  Cache => [ 'dbm' ]

=head1 STRICT MODE

If you import the B<XML::Simple> routines like this:

  use XML::Simple qw(:strict);

the following common mistakes will be detected and treated as fatal errors

=over 4

=item *

Failing to explicitly set the C<KeyAttr> option - if you can't be bothered
reading about this option, turn it off with: KeyAttr => [ ]

=item *

Failing to explicitly set the C<ForceArray> option - if you can't be bothered
reading about this option, set it to the safest mode with: ForceArray => 1

=item *

Setting ForceArray to an array, but failing to list all the elements from the
KeyAttr hash.

=item *

Data error - KeyAttr is set to say { part => 'partnum' } but the XML contains
one or more E<lt>partE<gt> elements without a 'partnum' attribute (or nested
element).  Note: if strict mode is not set but C<use warnings;> is in force,
this condition triggers a warning.

=item *

Data error - as above, but non-unique values are present in the key attribute
(eg: more than one E<lt>partE<gt> element with the same partnum).  This will
also trigger a warning if strict mode is not enabled.

=item *

Data error - as above, but value of key attribute (eg: partnum) is not a
scalar string (due to nested elements etc).  This will also trigger a warning
if strict mode is not enabled.

=back

=head1 SAX SUPPORT

From version 1.08_01, B<XML::Simple> includes support for SAX (the Simple API
for XML) - specifically SAX2.

In a typical SAX application, an XML parser (or SAX 'driver') module generates
SAX events (start of element, character data, end of element, etc) as it parses
an XML document and a 'handler' module processes the events to extract the
required data.  This simple model allows for some interesting and powerful
possibilities:

=over 4

=item *

Applications written to the SAX API can extract data from huge XML documents
without the memory overheads of a DOM or tree API.

=item *

The SAX API allows for plug and play interchange of parser modules without
having to change your code to fit a new module's API.  A number of SAX parsers
are available with capabilities ranging from extreme portability to blazing
performance.

=item *

A SAX 'filter' module can implement both a handler interface for receiving
data and a generator interface for passing modified data on to a downstream
handler.  Filters can be chained together in 'pipelines'.

=item *

One filter module might split a data stream to direct data to two or more
downstream handlers.

=item *

Generating SAX events is not the exclusive preserve of XML parsing modules.
For example, a module might extract data from a relational database using DBI
and pass it on to a SAX pipeline for filtering and formatting.

=back

B<XML::Simple> can operate at either end of a SAX pipeline.  For example,
you can take a data structure in the form of a hashref and pass it into a
SAX pipeline using the 'Handler' option on C<XMLout()>:

  use XML::Simple;
  use Some::SAX::Filter;
  use XML::SAX::Writer;

  my $ref = {
               ....   # your data here
            };

  my $writer = XML::SAX::Writer->new();
  my $filter = Some::SAX::Filter->new(Handler => $writer);
  my $simple = XML::Simple->new(Handler => $filter);
  $simple->XMLout($ref);

You can also put B<XML::Simple> at the opposite end of the pipeline to take
advantage of the simple 'tree' data structure once the relevant data has been
isolated through filtering:

  use XML::SAX;
  use Some::SAX::Filter;
  use XML::Simple;

  my $simple = XML::Simple->new(ForceArray => 1, KeyAttr => ['partnum']);
  my $filter = Some::SAX::Filter->new(Handler => $simple);
  my $parser = XML::SAX::ParserFactory->parser(Handler => $filter);

  my $ref = $parser->parse_uri('some_huge_file.xml');

  print $ref->{part}->{'555-1234'};

You can build a filter by using an XML::Simple object as a handler and setting
its DataHandler option to point to a routine which takes the resulting tree,
modifies it and sends it off as SAX events to a downstream handler:

  my $writer = XML::SAX::Writer->new();
  my $filter = XML::Simple->new(
                 DataHandler => sub {
                                  my $simple = shift;
                                  my $data = shift;

                                  # Modify $data here

                                  $simple->XMLout($data, Handler => $writer);
                                }
               );
  my $parser = XML::SAX::ParserFactory->parser(Handler => $filter);

  $parser->parse_uri($filename);

I<Note: In this last example, the 'Handler' option was specified in the call to
C<XMLout()> but it could also have been specified in the constructor>.

=head1 ENVIRONMENT

If you don't care which parser module B<XML::Simple> uses then skip this
section entirely (it looks more complicated than it really is).

B<XML::Simple> will default to using a B<SAX> parser if one is available or
B<XML::Parser> if SAX is not available.

You can dictate which parser module is used by setting either the environment
variable 'XML_SIMPLE_PREFERRED_PARSER' or the package variable
$XML::Simple::PREFERRED_PARSER to contain the module name.  The following rules
are used:

=over 4

=item *

The package variable takes precedence over the environment variable if both are defined.  To force B<XML::Simple> to ignore the environment settings and use
its default rules, you can set the package variable to an empty string.

=item *

If the 'preferred parser' is set to the string 'XML::Parser', then
L<XML::Parser> will be used (or C<XMLin()> will die if L<XML::Parser> is not
installed).

=item *

If the 'preferred parser' is set to some other value, then it is assumed to be
the name of a SAX parser module and is passed to L<XML::SAX::ParserFactory>.
If L<XML::SAX> is not installed, or the requested parser module is not
installed, then C<XMLin()> will die.

=item *

If the 'preferred parser' is not defined at all (the normal default
state), an attempt will be made to load L<XML::SAX>.  If L<XML::SAX> is
installed, then a parser module will be selected according to
L<XML::SAX::ParserFactory>'s normal rules (which typically means the last SAX
parser installed).

=item *

if the 'preferred parser' is not defined and B<XML::SAX> is not
installed, then B<XML::Parser> will be used.  C<XMLin()> will die if
L<XML::Parser> is not installed.

=back

Note: The B<XML::SAX> distribution includes an XML parser written entirely in
Perl.  It is very portable but it is not very fast.  You should consider
installing L<XML::LibXML> or L<XML::SAX::Expat> if they are available for your
platform.

=head1 ERROR HANDLING

The XML standard is very clear on the issue of non-compliant documents.  An
error in parsing any single element (for example a missing end tag) must cause
the whole document to be rejected.  B<XML::Simple> will die with an appropriate
message if it encounters a parsing error.

If dying is not appropriate for your application, you should arrange to call
C<XMLin()> in an eval block and look for errors in $@.  eg:

    my $config = eval { XMLin() };
    PopUpMessage($@) if($@);

Note, there is a common misconception that use of B<eval> will significantly
slow down a script.  While that may be true when the code being eval'd is in a
string, it is not true of code like the sample above.

=head1 EXAMPLES

When C<XMLin()> reads the following very simple piece of XML:

    <opt username="testuser" password="frodo"></opt>

it returns the following data structure:

    {
      'username' => 'testuser',
      'password' => 'frodo'
    }

The identical result could have been produced with this alternative XML:

    <opt username="testuser" password="frodo" />

Or this (although see 'ForceArray' option for variations):

    <opt>
      <username>testuser</username>
      <password>frodo</password>
    </opt>

Repeated nested elements are represented as anonymous arrays:

    <opt>
      <person firstname="Joe" lastname="Smith">
        <email>joe@smith.com</email>
        <email>jsmith@yahoo.com</email>
      </person>
      <person firstname="Bob" lastname="Smith">
        <email>bob@smith.com</email>
      </person>
    </opt>

    {
      'person' => [
                    {
                      'email' => [
                                   'joe@smith.com',
                                   'jsmith@yahoo.com'
                                 ],
                      'firstname' => 'Joe',
                      'lastname' => 'Smith'
                    },
                    {
                      'email' => 'bob@smith.com',
                      'firstname' => 'Bob',
                      'lastname' => 'Smith'
                    }
                  ]
    }

Nested elements with a recognised key attribute are transformed (folded) from
an array into a hash keyed on the value of that attribute (see the C<KeyAttr>
option):

    <opt>
      <person key="jsmith" firstname="Joe" lastname="Smith" />
      <person key="tsmith" firstname="Tom" lastname="Smith" />
      <person key="jbloggs" firstname="Joe" lastname="Bloggs" />
    </opt>

    {
      'person' => {
                    'jbloggs' => {
                                   'firstname' => 'Joe',
                                   'lastname' => 'Bloggs'
                                 },
                    'tsmith' => {
                                  'firstname' => 'Tom',
                                  'lastname' => 'Smith'
                                },
                    'jsmith' => {
                                  'firstname' => 'Joe',
                                  'lastname' => 'Smith'
                                }
                  }
    }


The <anon> tag can be used to form anonymous arrays:

    <opt>
      <head><anon>Col 1</anon><anon>Col 2</anon><anon>Col 3</anon></head>
      <data><anon>R1C1</anon><anon>R1C2</anon><anon>R1C3</anon></data>
      <data><anon>R2C1</anon><anon>R2C2</anon><anon>R2C3</anon></data>
      <data><anon>R3C1</anon><anon>R3C2</anon><anon>R3C3</anon></data>
    </opt>

    {
      'head' => [
                  [ 'Col 1', 'Col 2', 'Col 3' ]
                ],
      'data' => [
                  [ 'R1C1', 'R1C2', 'R1C3' ],
                  [ 'R2C1', 'R2C2', 'R2C3' ],
                  [ 'R3C1', 'R3C2', 'R3C3' ]
                ]
    }

Anonymous arrays can be nested to arbitrary levels and as a special case, if
the surrounding tags for an XML document contain only an anonymous array the
arrayref will be returned directly rather than the usual hashref:

    <opt>
      <anon><anon>Col 1</anon><anon>Col 2</anon></anon>
      <anon><anon>R1C1</anon><anon>R1C2</anon></anon>
      <anon><anon>R2C1</anon><anon>R2C2</anon></anon>
    </opt>

    [
      [ 'Col 1', 'Col 2' ],
      [ 'R1C1', 'R1C2' ],
      [ 'R2C1', 'R2C2' ]
    ]

Elements which only contain text content will simply be represented as a
scalar.  Where an element has both attributes and text content, the element
will be represented as a hashref with the text content in the 'content' key
(see the C<ContentKey> option):

  <opt>
    <one>first</one>
    <two attr="value">second</two>
  </opt>

  {
    'one' => 'first',
    'two' => { 'attr' => 'value', 'content' => 'second' }
  }

Mixed content (elements which contain both text content and nested elements)
will be not be represented in a useful way - element order and significant
whitespace will be lost.  If you need to work with mixed content, then
XML::Simple is not the right tool for your job - check out the next section.

=head1 WHERE TO FROM HERE?

B<XML::Simple> is able to present a simple API because it makes some
assumptions on your behalf.  These include:

=over 4

=item *

You're not interested in text content consisting only of whitespace

=item *

You don't mind that when things get slurped into a hash the order is lost

=item *

You don't want fine-grained control of the formatting of generated XML

=item *

You would never use a hash key that was not a legal XML element name

=item *

You don't need help converting between different encodings

=back

In a serious XML project, you'll probably outgrow these assumptions fairly
quickly.  This section of the document used to offer some advice on choosing a
more powerful option.  That advice has now grown into the 'Perl-XML FAQ'
document which you can find at: L<http://perl-xml.sourceforge.net/faq/>

The advice in the FAQ boils down to a quick explanation of tree versus
event based parsers and then recommends:

For event based parsing, use SAX (do not set out to write any new code for
XML::Parser's handler API - it is obsolete).

For tree-based parsing, you could choose between the 'Perlish' approach of
L<XML::Twig> and more standards based DOM implementations - preferably one with
XPath support such as L<XML::LibXML>.


=head1 SEE ALSO

B<XML::Simple> requires either L<XML::Parser> or L<XML::SAX>.

To generate documents with namespaces, L<XML::NamespaceSupport> is required.

The optional caching functions require L<Storable>.

Answers to Frequently Asked Questions about XML::Simple are bundled with this
distribution as: L<XML::Simple::FAQ>

=head1 COPYRIGHT

Copyright 1999-2004 Grant McLean E<lt>grantm@cpan.orgE<gt>

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

=cut


PK7N%[�]�/77perl5/File/Listing.pmnu��6�$package File::Listing;

use strict;
use warnings;
use Carp ();
use HTTP::Date qw(str2time);
use Exporter 5.57 qw( import );

# ABSTRACT: Parse directory listing
our $VERSION = '6.16'; # VERSION

sub Version { $File::Listing::VERSION; }

our @EXPORT = qw(parse_dir);

sub parse_dir ($;$$$)
{
   my($dir, $tz, $fstype, $error) = @_;

   $fstype ||= 'unix';
   $fstype = "File::Listing::" . lc $fstype;

   my @args = $_[0];
   push(@args, $tz) if(@_ >= 2);
   push(@args, $error) if(@_ >= 4);

   $fstype->parse(@args);
}


sub line { Carp::croak("Not implemented yet"); }
sub init { } # Dummy sub


sub file_mode ($)
{
    Carp::croak("Input to file_mode() must be a 10 character string.")
        unless length($_[0]) == 10;

    # This routine was originally borrowed from Graham Barr's
    # Net::FTP package.

    local $_ = shift;
    my $mode = 0;
    my($type);

    s/^(.)// and $type = $1;

    # When the set-group-ID bit (file mode bit 02000) is set, and the group
    # execution bit (file mode bit 00020) is unset, and it is a regular file,
    # some implementations of `ls' use the letter `S', others use `l' or `L'.
    # Convert this `S'.

    s/[Ll](...)$/S$1/;

    while (/(.)/g) {
        $mode <<= 1;
        $mode |= 1 if $1 ne "-" &&
                      $1 ne "*" &&
                      $1 ne 'S' &&
                      $1 ne 'T';
    }

    $mode |= 0004000 if /^..s....../i;
    $mode |= 0002000 if /^.....s.../i;
    $mode |= 0001000 if /^........t/i;

    # De facto standard definitions. From 'stat.h' on Solaris 9.

    $type eq "p" and $mode |= 0010000 or        # fifo
    $type eq "c" and $mode |= 0020000 or        # character special
    $type eq "d" and $mode |= 0040000 or        # directory
    $type eq "b" and $mode |= 0060000 or        # block special
    $type eq "-" and $mode |= 0100000 or        # regular
    $type eq "l" and $mode |= 0120000 or        # symbolic link
    $type eq "s" and $mode |= 0140000 or        # socket
    $type eq "D" and $mode |= 0150000 or        # door
      Carp::croak("Unknown file type: $type");

    $mode;
}


sub parse
{
   my($pkg, $dir, $tz, $error) = @_;

   # First let's try to determine what kind of dir parameter we have
   # received.  We allow both listings, reference to arrays and
   # file handles to read from.

   if (ref($dir) eq 'ARRAY') {
       # Already split up
   }
   elsif (ref($dir) eq 'GLOB') {
       # A file handle
   }
   elsif (ref($dir)) {
      Carp::croak("Illegal argument to parse_dir()");
   }
   elsif ($dir =~ /^\*\w+(::\w+)+$/) {
      # This scalar looks like a file handle, so we assume it is
   }
   else {
      # A normal scalar listing
      $dir = [ split(/\n/, $dir) ];
   }

   $pkg->init();

   my @files = ();
   if (ref($dir) eq 'ARRAY') {
       for (@$dir) {
           push(@files, $pkg->line($_, $tz, $error));
       }
   }
   else {
       local($_);
       while (my $line = <$dir>) {
           chomp $line;
           push(@files, $pkg->line($line, $tz, $error));
       }
   }
   wantarray ? @files : \@files;  ## no critic (Community::Wantarray)
}



package File::Listing::unix;

use HTTP::Date qw(str2time);

our @ISA = qw(File::Listing);

# A place to remember current directory from last line parsed.
our $curdir;

sub init
{
    $curdir = '';
}


sub line
{
    shift; # package name
    local($_) = shift;
    my($tz, $error) = @_;

    s/\015//g;
    #study;

    my ($kind, $size, $date, $name);
    if (($kind, $size, $date, $name) =
        /^([\-\*FlrwxsStTdD]{10})                 # Type and permission bits
         .*                                       # Graps
         \D(\d+)                                  # File size
         \s+                                      # Some space
         (\w{3}\s+\d+\s+(?:\d{1,2}:\d{2}|\d{4})|\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2})  # Date
         \s+                                      # Some more space
         (.*)$                                    # File name
        /x )

    {
        return if $name eq '.' || $name eq '..';
        $name = "$curdir/$name" if length $curdir;
        my $type = '?';
        if ($kind =~ /^l/ && $name =~ /(.*) -> (.*)/ ) {
            $name = $1;
            $type = "l $2";
        }
        elsif ($kind =~ /^[\-F]/) { # (hopefully) a regular file
            $type = 'f';
        }
        elsif ($kind =~ /^[dD]/) {
            $type = 'd';
            $size = undef;  # Don't believe the reported size
        }
        return [$name, $type, $size, str2time($date, $tz),
              File::Listing::file_mode($kind)];

    }
    elsif (/^(.+):$/ && !/^[dcbsp].*\s.*\s.*:$/ ) {
        my $dir = $1;
        return () if $dir eq '.';
        $curdir = $dir;
        return ();
    }
    elsif (/^[Tt]otal\s+(\d+)$/ || /^\s*$/) {
        return ();
    }
    elsif (/not found/    || # OSF1, HPUX, and SunOS return
             # "$file not found"
             /No such file/ || # IRIX returns
             # "UX:ls: ERROR: Cannot access $file: No such file or directory"
                               # Solaris returns
             # "$file: No such file or directory"
             /cannot find/     # Windows NT returns
             # "The system cannot find the path specified."
             ) {
        return () unless defined $error;
        &$error($_) if ref($error) eq 'CODE';
        warn "Error: $_\n" if $error eq 'warn';
        return ();
    }
    elsif ($_ eq '') {       # AIX, and Linux return nothing
        return () unless defined $error;
        &$error("No such file or directory") if ref($error) eq 'CODE';
        warn "Warning: No such file or directory\n" if $error eq 'warn';
        return ();
    }
    else {
        # parse failed, check if the dosftp parse understands it
        File::Listing::dosftp->init();
        return(File::Listing::dosftp->line($_,$tz,$error));
    }

}



package File::Listing::dosftp;

use HTTP::Date qw(str2time);

our @ISA = qw(File::Listing);

# A place to remember current directory from last line parsed.
our $curdir;



sub init
{
    $curdir = '';
}


sub line
{
    shift; # package name
    local($_) = shift;
    my($tz, $error) = @_;

    s/\015//g;

    my ($date, $size_or_dir, $name, $size);

    # usual format:
    # 02-05-96  10:48AM                 1415 src.slf
    # 09-10-96  09:18AM       <DIR>          sl_util
    # alternative dos format with four-digit year:
    # 02-05-2022  10:48AM                 1415 src.slf
    # 09-10-2022  09:18AM       <DIR>          sl_util
    if (($date, $size_or_dir, $name) =
        /^(\d\d-\d\d-\d{2,4}\s+\d\d:\d\d\wM)      # Date and time info
         \s+                                      # Some space
         (<\w{3}>|\d+)                            # Dir or Size
         \s+                                      # Some more space
         (.+)$                                    # File name
        /x )
    {
        return if $name eq '.' || $name eq '..';
        $name = "$curdir/$name" if length $curdir;
        my $type = '?';
        if ($size_or_dir eq '<DIR>') {
            $type = "d";
            $size = ""; # directories have no size in the pc listing
        }
        else {
            $type = 'f';
            $size = $size_or_dir;
        }
        return [$name, $type, $size, str2time($date, $tz), undef];
    }
    else {
        return () unless defined $error;
        &$error($_) if ref($error) eq 'CODE';
        warn "Can't parse: $_\n" if $error eq 'warn';
        return ();
    }

}



package File::Listing::vms;
our @ISA = qw(File::Listing);

package File::Listing::netware;
our @ISA = qw(File::Listing);



package File::Listing::apache;

our @ISA = qw(File::Listing);


sub init { }


sub line {
    shift; # package name
    local($_) = shift;
    my($tz, $error) = @_; # ignored for now...

    s!</?t[rd][^>]*>! !g;  # clean away various table stuff
    if (m!<A\s+HREF=\"([^?\"]+)\">.*</A>.*?(\d+)-([a-zA-Z]+|\d+)-(\d+)\s+(\d+):(\d+)\s+(?:([\d\.]+[kMG]?|-))!i) {
        my($filename, $filesize) = ($1, $7);
        my($d,$m,$y, $H,$M) = ($2,$3,$4,$5,$6);
        if ($m =~ /^\d+$/) {
            ($d,$y) = ($y,$d) # iso date
        }
        else {
            $m = _monthabbrev_number($m);
        }

        $filesize = 0 if $filesize eq '-';
        if ($filesize =~ s/k$//i) {
            $filesize *= 1024;
        }
        elsif ($filesize =~ s/M$//) {
            $filesize *= 1024*1024;
        }
        elsif ($filesize =~ s/G$//) {
            $filesize *= 1024*1024*1024;
        }
        $filesize = int $filesize;

        require Time::Local;
        my $filetime = Time::Local::timelocal(0,$M,$H,$d,$m-1,_guess_year($y));
        my $filetype = ($filename =~ s|/$|| ? "d" : "f");
        return [$filename, $filetype, $filesize, $filetime, undef];
    }

    # the default listing doesn't include timestamps or file sizes
    # but we don't want to grab navigation links, so we ignore links
    # that have a non-trailing slash / character or ?
    elsif(m!<A\s+HREF=\"([^?/\"]+/?)\">.*</A>!i) {
        my $filename = $1;
        my $filetype = ($filename =~ s|/$|| ? "d" : "f");
        return [$filename, $filetype, undef, undef, undef];
    }

    return ();
}


sub _guess_year {
    my $y = shift;

    # if the year is already four digit then we shouldn't do
    # anything to modify it.
    if ($y >= 1900) {
        # do nothing

    # TODO: for hysterical er historical reasons we assume 9x is in the
    # 1990s we should probably not do that, but I don't have any examples
    # where apache provides two digit dates so I am leaving this as-is
    # for now.  Possibly the right thing is to not handle two digit years.
    } elsif ($y >= 90) {
        $y = 1900+$y;
    }

    # TODO: likewise assuming 00-89 are 20xx is long term probably wrong.
    elsif ($y < 100) {
        $y = 2000+$y;
    }
    $y;
}


sub _monthabbrev_number {
    my $mon = shift;
    +{'Jan' => 1,
      'Feb' => 2,
      'Mar' => 3,
      'Apr' => 4,
      'May' => 5,
      'Jun' => 6,
      'Jul' => 7,
      'Aug' => 8,
      'Sep' => 9,
      'Oct' => 10,
      'Nov' => 11,
      'Dec' => 12,
     }->{$mon};
}


1;

__END__

=pod

=encoding UTF-8

=head1 NAME

File::Listing - Parse directory listing

=head1 VERSION

version 6.16

=head1 SYNOPSIS

 use File::Listing qw(parse_dir);
 $ENV{LANG} = "C";  # dates in non-English locales not supported
 foreach my $file (parse_dir(`ls -l`)) {
     my ($name, $type, $size, $mtime, $mode) = @$file;
     next if $type ne 'f'; # plain file
     #...
 }
 
 # directory listing can also be read from a file
 open my $listing, "zcat ls-lR.gz|";
 $dir = parse_dir($listing, '+0000');

=head1 DESCRIPTION

This module exports a single function called C<parse_dir>, which can be
used to parse directory listings.

=head1 FUNCTIONS

=head2 parse_dir

 my $dir = parse_dir( $listing );
 my $dir = parse_dir( $listing, $time_zone );
 my $dir = parse_dir( $listing, $time_zone, $type );
 my $dir = parse_dir( $listing, $time_zone, $type, $error );
 my @files = parse_dir( $listing );
 my @files = parse_dir( $listing, $time_zone );
 my @files = parse_dir( $listing, $time_zone, $type );
 my @files = parse_dir( $listing, $time_zone, $type, $error );

The first parameter (C<$listing>) is the directory listing to parse.
It can be a scalar, a reference to an array of directory lines or a
glob representing a filehandle to read the directory listing from.

The second parameter (C<$time_zone>) is the time zone to use when
parsing time stamps in the listing. If this value is undefined,
then the local time zone is assumed.

The third parameter (C<$type>) is the type of listing to assume.
Currently supported formats are C<'unix'>, C<'apache'> and
C<'dosftp'>. The default value is C<'unix'>. Ideally, the listing
type should be determined automatically.

The fourth parameter (C<$error>) specifies how unparseable lines
should be treated. Values can be C<'ignore'>, C<'warn'> or a code reference.
Warn means that the perl warn() function will be called.  If a code
reference is passed, then this routine will be called and the return
value from it will be incorporated in the listing.  The default is
C<'ignore'>.

Only the first parameter is mandatory.

 # list context
 foreach my $file (parse_dir($listing)) {
     my($name, $type, $size, $mtime, $mode) = @$file;
 }
 
 # scalar context
 my $dir = parse_dir($listing);
 foreach my $file (@$dir) {
     my($name, $type, $size, $mtime, $mode) = @$file;
 }

The return value from parse_dir() is a list of directory entries.
In a scalar context the return value is a reference to the list.
The directory entries are represented by an array consisting of:

=over 4

=item name

The name of the file.

=item type

One of: C<f> file, C<d> directory, C<l> symlink, C<?> unknown.

=item size

The size of the file.

=item time

The number of seconds since January 1, 1970.

=item mode

Bitmask a la the mode returned by C<stat>.

=back

=head1 SEE ALSO

=over 4

=item L<File::Listing::Ftpcopy>

Provides the same interface but uses XS and the parser implementation from C<ftpcopy>.

=back

=head1 AUTHOR

Original author: Gisle Aas

Current maintainer: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Adam Kennedy

Adam Sjogren

Alex Kapranoff

Alexey Tourbin

Andreas J. Koenig

Bill Mann

Bron Gondwana

DAVIDRW

Daniel Hedlund

David E. Wheeler

David Steinbrunner

Erik Esterer

FWILES

Father Chrysostomos

Gavin Peters

Graeme Thompson

Grant Street Group

Hans-H. Froehlich

Ian Kilgore

Jacob J

Mark Stosberg

Mike Schilli

Ondrej Hanak

Peter John Acklam

Peter Rabbitson

Robert Stone

Rolf Grossmann

Sean M. Burke

Simon Legner

Slaven Rezic

Spiros Denaxas

Steve Hay

Todd Lipcon

Tom Hukins

Tony Finch

Toru Yamaguchi

Ville Skyttä

Yuri Karaban

Zefram

amire80

jefflee

john9art

mschilli

murphy

phrstbrn

ruff

sasao

uid39246

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 1996-2022 by Gisle Aas.

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

=cut
PK7N%[dE
�*�*perl5/File/chdir.pmnu��6�$package File::chdir;
use 5.004;
use strict;
use vars qw($VERSION @ISA @EXPORT $CWD @CWD);
# ABSTRACT: a more sensible way to change directories

our $VERSION = '0.1011';

require Exporter;
@ISA = qw(Exporter);
@EXPORT = qw(*CWD);

use Carp;
use Cwd 3.16;
use File::Spec::Functions 3.27 qw/canonpath splitpath catpath splitdir catdir/;

tie $CWD, 'File::chdir::SCALAR' or die "Can't tie \$CWD";
tie @CWD, 'File::chdir::ARRAY'  or die "Can't tie \@CWD";

sub _abs_path {
    # Otherwise we'll never work under taint mode.
    my($cwd) = Cwd::getcwd =~ /(.*)/s;
    # Run through File::Spec, since everything else uses it
    return canonpath($cwd);
}

# splitpath but also split directory
sub _split_cwd {
    my ($vol, $dir) = splitpath(_abs_path, 1);
    my @dirs = splitdir( $dir );
    shift @dirs; # get rid of leading empty "root" directory
    return ($vol, @dirs);
}

# catpath, but take list of directories
# restore the empty root dir and provide an empty file to avoid warnings
sub _catpath {
    my ($vol, @dirs) = @_;
    return catpath($vol, catdir(q{}, @dirs), q{});
}

sub _chdir {
    # Untaint target directory
    my ($new_dir) = $_[0] =~ /(.*)/s;

    local $Carp::CarpLevel = $Carp::CarpLevel + 1;
    if ( ! CORE::chdir($new_dir) ) {
        croak "Failed to change directory to '$new_dir': $!";
    };
    return 1;
}

{
    package File::chdir::SCALAR;
    use Carp;

    BEGIN {
        *_abs_path = \&File::chdir::_abs_path;
        *_chdir = \&File::chdir::_chdir;
        *_split_cwd = \&File::chdir::_split_cwd;
        *_catpath = \&File::chdir::_catpath;
    }

    sub TIESCALAR {
        bless [], $_[0];
    }

    # To be safe, in case someone chdir'd out from under us, we always
    # check the Cwd explicitly.
    sub FETCH {
        return _abs_path;
    }

    sub STORE {
        return unless defined $_[1];
        _chdir($_[1]);
    }
}


{
    package File::chdir::ARRAY;
    use Carp;

    BEGIN {
        *_abs_path = \&File::chdir::_abs_path;
        *_chdir = \&File::chdir::_chdir;
        *_split_cwd = \&File::chdir::_split_cwd;
        *_catpath = \&File::chdir::_catpath;
    }

    sub TIEARRAY {
        bless {}, $_[0];
    }

    sub FETCH {
        my($self, $idx) = @_;
        my ($vol, @cwd) = _split_cwd;
        return $cwd[$idx];
    }

    sub STORE {
        my($self, $idx, $val) = @_;

        my ($vol, @cwd) = _split_cwd;
        if( $self->{Cleared} ) {
            @cwd = ();
            $self->{Cleared} = 0;
        }

        $cwd[$idx] = $val;
        my $dir = _catpath($vol,@cwd);

        _chdir($dir);
        return $cwd[$idx];
    }

    sub FETCHSIZE {
        my ($vol, @cwd) = _split_cwd;
        return scalar @cwd;
    }
    sub STORESIZE {}

    sub PUSH {
        my($self) = shift;

        my $dir = _catpath(_split_cwd, @_);
        _chdir($dir);
        return $self->FETCHSIZE;
    }

    sub POP {
        my($self) = shift;

        my ($vol, @cwd) = _split_cwd;
        my $popped = pop @cwd;
        my $dir = _catpath($vol,@cwd);
        _chdir($dir);
        return $popped;
    }

    sub SHIFT {
        my($self) = shift;

        my ($vol, @cwd) = _split_cwd;
        my $shifted = shift @cwd;
        my $dir = _catpath($vol,@cwd);
        _chdir($dir);
        return $shifted;
    }

    sub UNSHIFT {
        my($self) = shift;

        my ($vol, @cwd) = _split_cwd;
        my $dir = _catpath($vol, @_, @cwd);
        _chdir($dir);
        return $self->FETCHSIZE;
    }

    sub CLEAR  {
        my($self) = shift;
        $self->{Cleared} = 1;
    }

    sub SPLICE {
        my $self = shift;
        my $offset = shift || 0;
        my $len = shift || $self->FETCHSIZE - $offset;
        my @new_dirs = @_;

        my ($vol, @cwd) = _split_cwd;
        my @orig_dirs = splice @cwd, $offset, $len, @new_dirs;
        my $dir = _catpath($vol, @cwd);
        _chdir($dir);
        return @orig_dirs;
    }

    sub EXTEND { }
    sub EXISTS {
        my($self, $idx) = @_;
        return $self->FETCHSIZE >= $idx ? 1 : 0;
    }

    sub DELETE {
        my($self, $idx) = @_;
        croak "Can't delete except at the end of \@CWD"
            if $idx < $self->FETCHSIZE - 1;
        local $Carp::CarpLevel = $Carp::CarpLevel + 1;
        $self->POP;
    }
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

File::chdir - a more sensible way to change directories

=head1 VERSION

version 0.1011

=head1 SYNOPSIS

  use File::chdir;

  $CWD = "/foo/bar";     # now in /foo/bar
  {
      local $CWD = "/moo/baz";  # now in /moo/baz
      ...
  }

  # still in /foo/bar!

=head1 DESCRIPTION

Perl's C<chdir()> has the unfortunate problem of being very, very, very
global.  If any part of your program calls C<chdir()> or if any library
you use calls C<chdir()>, it changes the current working directory for
the *whole* program.

This sucks.

File::chdir gives you an alternative, C<$CWD> and C<@CWD>.  These two
variables combine all the power of C<chdir()>, L<File::Spec> and L<Cwd>.

=head1 $CWD

Use the C<$CWD> variable instead of C<chdir()> and Cwd.

    use File::chdir;
    $CWD = $dir;  # just like chdir($dir)!
    print $CWD;   # prints the current working directory

It can be localized, and it does the right thing.

    $CWD = "/foo";      # it's /foo out here.
    {
        local $CWD = "/bar";  # /bar in here
    }
    # still /foo out here!

C<$CWD> always returns the absolute path in the native form for the
operating system.

C<$CWD> and normal C<chdir()> work together just fine.

=head1 @CWD

C<@CWD> represents the current working directory as an array, each
directory in the path is an element of the array.  This can often make
the directory easier to manipulate, and you don't have to fumble with
C<< File::Spec->splitpath >> and C<< File::Spec->catdir >> to make portable code.

  # Similar to chdir("/usr/local/src/perl")
  @CWD = qw(usr local src perl);

pop, push, shift, unshift and splice all work.  pop and push are
probably the most useful.

  pop @CWD;                 # same as chdir(File::Spec->updir)
  push @CWD, 'some_dir'     # same as chdir('some_dir')

C<@CWD> and C<$CWD> both work fine together.

*NOTE* Due to a perl bug you can't localize C<@CWD>.  See L</CAVEATS> for a work around.

=head1 EXAMPLES

(We omit the C<use File::chdir> from these examples for terseness)

Here's C<$CWD> instead of C<chdir()>:

    $CWD = 'foo';           # chdir('foo')

and now instead of Cwd.

    print $CWD;             # use Cwd;  print Cwd::abs_path

you can even do zsh style C<cd foo bar>

    $CWD = '/usr/local/foo';
    $CWD =~ s/usr/var/;

if you want to localize that, make sure you get the parens right

    {
        (local $CWD) =~ s/usr/var/;
        ...
    }

It's most useful for writing polite subroutines which don't leave the
program in some strange directory:

    sub foo {
        local $CWD = 'some/other/dir';
        ...do your work...
    }

which is much simpler than the equivalent:

    sub foo {
        use Cwd;
        my $orig_dir = Cwd::getcwd;
        chdir('some/other/dir');

        ...do your work...

        chdir($orig_dir);
    }

C<@CWD> comes in handy when you want to start moving up and down the
directory hierarchy in a cross-platform manner without having to use
File::Spec.

    pop @CWD;                   # chdir(File::Spec->updir);
    push @CWD, 'some', 'dir'    # chdir(File::Spec->catdir(qw(some dir)));

You can easily change your parent directory:

    # chdir from /some/dir/bar/moo to /some/dir/foo/moo
    $CWD[-2] = 'foo';

=head1 CAVEATS

=head2 C<local @CWD> does not work.

C<local @CWD> will not localize C<@CWD>.  This is a bug in Perl, you
can't localize tied arrays.  As a work around localizing $CWD will
effectively localize @CWD.

    {
        local $CWD;
        pop @CWD;
        ...
    }

=head2 Assigning to C<@CWD> calls C<chdir()> for each element

    @CWD = qw/a b c d/;

Internally, Perl clears C<@CWD> and assigns each element in turn.  Thus, this
code above will do this:

    chdir 'a';
    chdir 'a/b';
    chdir 'a/b/c';
    chdir 'a/b/c/d';

Generally, avoid assigning to C<@CWD> and just use push and pop instead.

=head2 Volumes not handled

There is currently no way to change the current volume via File::chdir.

=head1 NOTES

C<$CWD> returns the current directory using native path separators, i.e. C<\>
on Win32.  This ensures that C<$CWD> will compare correctly with directories
created using File::Spec.  For example:

    my $working_dir = File::Spec->catdir( $CWD, "foo" );
    $CWD = $working_dir;
    doing_stuff_might_chdir();
    is( $CWD, $working_dir, "back to original working_dir?" );

Deleting the last item of C<@CWD> will act like a pop.  Deleting from the
middle will throw an exception.

    delete @CWD[-1]; # OK
    delete @CWD[-2]; # Dies

What should %CWD do?  Something with volumes?

    # chdir to C:\Program Files\Sierra\Half Life ?
    $CWD{C} = '\\Program Files\\Sierra\\Half Life';

=head1 DIAGNOSTICS

If an error is encountered when changing C<$CWD> or C<@CWD>, one of
the following exceptions will be thrown:

* ~Can't delete except at the end of @CWD~
* ~Failed to change directory to '$dir'~

=head1 HISTORY

Michael wanted C<local chdir> to work.  p5p didn't.  But it wasn't over!
Was it over when the Germans bombed Pearl Harbor?  Hell, no!

Abigail and/or Bryan Warnock suggested the C<$CWD> thing (Michael forgets
which).  They were right.

The C<chdir()> override was eliminated in 0.04.

David became co-maintainer with 0.06_01 to fix some chronic
Win32 path bugs.

As of 0.08, if changing C<$CWD> or C<@CWD> fails to change the directory, an
error will be thrown.

=head1 SEE ALSO

L<File::pushd>, L<File::Spec>, L<Cwd>, L<perlfunc/chdir>,
"Animal House" L<http://www.imdb.com/title/tt0077975/quotes>

=for :stopwords cpan testmatrix url annocpan anno bugtracker rt cpants kwalitee diff irc mailto metadata placeholders metacpan

=head1 SUPPORT

=head2 Bugs / Feature Requests

Please report any bugs or feature requests through the issue tracker
at L<https://github.com/dagolden/File-chdir/issues>.
You will be notified automatically of any progress on your issue.

=head2 Source Code

This is open source software.  The code repository is available for
public review and contribution under the terms of the license.

L<https://github.com/dagolden/File-chdir>

  git clone https://github.com/dagolden/File-chdir.git

=head1 AUTHORS

=over 4

=item *

David Golden <dagolden@cpan.org>

=item *

Michael G. Schwern <schwern@pobox.com>

=back

=head1 CONTRIBUTORS

=for stopwords David Golden Joel Berger Philippe Bruhat (BooK)

=over 4

=item *

David Golden <xdg@xdg.me>

=item *

Joel Berger <joel.a.berger@gmail.com>

=item *

Philippe Bruhat (BooK) <book@cpan.org>

=back

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2016 by Michael G. Schwern and David Golden.

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

=cut
PK7N%[�Y3�AAperl5/CPAN/Tarzip.pmnu��6�$# -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*-
package CPAN::Tarzip;
use strict;
use vars qw($VERSION @ISA $BUGHUNTING);
use CPAN::Debug;
use File::Basename qw(basename);
$VERSION = "5.5013";
# module is internal to CPAN.pm

@ISA = qw(CPAN::Debug); ## no critic
$BUGHUNTING ||= 0; # released code must have turned off

# it's ok if file doesn't exist, it just matters if it is .gz or .bz2
sub new {
    my($class,$file) = @_;
    $CPAN::Frontend->mydie("CPAN::Tarzip->new called without arg") unless defined $file;
    my $me = { FILE => $file };
    if ($file =~ /\.(bz2|gz|zip|tbz|tgz)$/i) {
        $me->{ISCOMPRESSED} = 1;
    } else {
        $me->{ISCOMPRESSED} = 0;
    }
    if (0) {
    } elsif ($file =~ /\.(?:bz2|tbz)$/i) {
        unless ($me->{UNGZIPPRG} = $CPAN::Config->{bzip2}) {
            my $bzip2 = _my_which("bzip2");
            if ($bzip2) {
                $me->{UNGZIPPRG} = $bzip2;
            } else {
                $CPAN::Frontend->mydie(qq{
CPAN.pm needs the external program bzip2 in order to handle '$file'.
Please install it now and run 'o conf init bzip2' from the
CPAN shell prompt to register it as external program.
});
            }
        }
    } else {
        $me->{UNGZIPPRG} = _my_which("gzip");
    }
    $me->{TARPRG} = _my_which("tar") || _my_which("gtar");
    bless $me, $class;
}

sub _zlib_ok () {
    $CPAN::META->has_inst("Compress::Zlib") or return;
    Compress::Zlib->can('gzopen');
}

sub _my_which {
    my($what) = @_;
    if ($CPAN::Config->{$what}) {
        return $CPAN::Config->{$what};
    }
    if ($CPAN::META->has_inst("File::Which")) {
        return File::Which::which($what);
    }
    my @cand = MM->maybe_command($what);
    return $cand[0] if @cand;
    require File::Spec;
    my $component;
  PATH_COMPONENT: foreach $component (File::Spec->path()) {
        next unless defined($component) && $component;
        my($abs) = File::Spec->catfile($component,$what);
        if (MM->maybe_command($abs)) {
            return $abs;
        }
    }
    return;
}

sub gzip {
    my($self,$read) = @_;
    my $write = $self->{FILE};
    if (_zlib_ok) {
        my($buffer,$fhw);
        $fhw = FileHandle->new($read)
            or $CPAN::Frontend->mydie("Could not open $read: $!");
        my $cwd = `pwd`;
        my $gz = Compress::Zlib::gzopen($write, "wb")
            or $CPAN::Frontend->mydie("Cannot gzopen $write: $! (pwd is $cwd)\n");
        binmode($fhw);
        $gz->gzwrite($buffer)
            while read($fhw,$buffer,4096) > 0 ;
        $gz->gzclose() ;
        $fhw->close;
        return 1;
    } else {
        my $command = CPAN::HandleConfig->safe_quote($self->{UNGZIPPRG});
        system(qq{$command -c "$read" > "$write"})==0;
    }
}


sub gunzip {
    my($self,$write) = @_;
    my $read = $self->{FILE};
    if (_zlib_ok) {
        my($buffer,$fhw);
        $fhw = FileHandle->new(">$write")
            or $CPAN::Frontend->mydie("Could not open >$write: $!");
        my $gz = Compress::Zlib::gzopen($read, "rb")
            or $CPAN::Frontend->mydie("Cannot gzopen $read: $!\n");
        binmode($fhw);
        $fhw->print($buffer)
            while $gz->gzread($buffer) > 0 ;
        $CPAN::Frontend->mydie("Error reading from $read: $!\n")
            if $gz->gzerror != Compress::Zlib::Z_STREAM_END();
        $gz->gzclose() ;
        $fhw->close;
        return 1;
    } else {
        my $command = CPAN::HandleConfig->safe_quote($self->{UNGZIPPRG});
        system(qq{$command -d -c "$read" > "$write"})==0;
    }
}


sub gtest {
    my($self) = @_;
    return $self->{GTEST} if exists $self->{GTEST};
    defined $self->{FILE} or $CPAN::Frontend->mydie("gtest called but no FILE specified");
    my $read = $self->{FILE};
    my $success;
    if ($read=~/\.(?:bz2|tbz)$/ && $CPAN::META->has_inst("Compress::Bzip2")) {
        my($buffer,$len);
        $len = 0;
        my $gz = Compress::Bzip2::bzopen($read, "rb")
            or $CPAN::Frontend->mydie(sprintf("Cannot bzopen %s: %s\n",
                                              $read,
                                              $Compress::Bzip2::bzerrno));
        while ($gz->bzread($buffer) > 0 ) {
            $len += length($buffer);
            $buffer = "";
        }
        my $err = $gz->bzerror;
        $success = ! $err || $err == Compress::Bzip2::BZ_STREAM_END();
        if ($len == -s $read) {
            $success = 0;
            CPAN->debug("hit an uncompressed file") if $CPAN::DEBUG;
        }
        $gz->gzclose();
        CPAN->debug("err[$err]success[$success]") if $CPAN::DEBUG;
    } elsif ( $read=~/\.(?:gz|tgz)$/ && _zlib_ok ) {
        # After I had reread the documentation in zlib.h, I discovered that
        # uncompressed files do not lead to an gzerror (anymore?).
        my($buffer,$len);
        $len = 0;
        my $gz = Compress::Zlib::gzopen($read, "rb")
            or $CPAN::Frontend->mydie(sprintf("Cannot gzopen %s: %s\n",
                                              $read,
                                              $Compress::Zlib::gzerrno));
        while ($gz->gzread($buffer) > 0 ) {
            $len += length($buffer);
            $buffer = "";
        }
        my $err = $gz->gzerror;
        $success = ! $err || $err == Compress::Zlib::Z_STREAM_END();
        if ($len == -s $read) {
            $success = 0;
            CPAN->debug("hit an uncompressed file") if $CPAN::DEBUG;
        }
        $gz->gzclose();
        CPAN->debug("err[$err]success[$success]") if $CPAN::DEBUG;
    } elsif (!$self->{ISCOMPRESSED}) {
        $success = 0;
    } else {
        my $command = CPAN::HandleConfig->safe_quote($self->{UNGZIPPRG});
        $success = 0==system(qq{$command -qdt "$read"});
    }
    return $self->{GTEST} = $success;
}


sub TIEHANDLE {
    my($class,$file) = @_;
    my $ret;
    $class->debug("file[$file]");
    my $self = $class->new($file);
    if (0) {
    } elsif (!$self->gtest) {
        my $fh = FileHandle->new($file)
            or $CPAN::Frontend->mydie("Could not open file[$file]: $!");
        binmode $fh;
        $self->{FH} = $fh;
        $class->debug("via uncompressed FH");
    } elsif ($file =~ /\.(?:bz2|tbz)$/ && $CPAN::META->has_inst("Compress::Bzip2")) {
        my $gz = Compress::Bzip2::bzopen($file,"rb") or
            $CPAN::Frontend->mydie("Could not bzopen $file");
        $self->{GZ} = $gz;
        $class->debug("via Compress::Bzip2");
    } elsif ($file =~/\.(?:gz|tgz)$/ && _zlib_ok) {
        my $gz = Compress::Zlib::gzopen($file,"rb") or
            $CPAN::Frontend->mydie("Could not gzopen $file");
        $self->{GZ} = $gz;
        $class->debug("via Compress::Zlib");
    } else {
        my $gzip = CPAN::HandleConfig->safe_quote($self->{UNGZIPPRG});
        my $pipe = "$gzip -d -c $file |";
        my $fh = FileHandle->new($pipe) or $CPAN::Frontend->mydie("Could not pipe[$pipe]: $!");
        binmode $fh;
        $self->{FH} = $fh;
        $class->debug("via external $gzip");
    }
    $self;
}


sub READLINE {
    my($self) = @_;
    if (exists $self->{GZ}) {
        my $gz = $self->{GZ};
        my($line,$bytesread);
        $bytesread = $gz->gzreadline($line);
        return undef if $bytesread <= 0;
        return $line;
    } else {
        my $fh = $self->{FH};
        return scalar <$fh>;
    }
}


sub READ {
    my($self,$ref,$length,$offset) = @_;
    $CPAN::Frontend->mydie("read with offset not implemented") if defined $offset;
    if (exists $self->{GZ}) {
        my $gz = $self->{GZ};
        my $byteread = $gz->gzread($$ref,$length);# 30eaf79e8b446ef52464b5422da328a8
        return $byteread;
    } else {
        my $fh = $self->{FH};
        return read($fh,$$ref,$length);
    }
}


sub DESTROY {
    my($self) = @_;
    if (exists $self->{GZ}) {
        my $gz = $self->{GZ};
        $gz->gzclose() if defined $gz; # hard to say if it is allowed
                                       # to be undef ever. AK, 2000-09
    } else {
        my $fh = $self->{FH};
        $fh->close if defined $fh;
    }
    undef $self;
}

sub untar {
    my($self) = @_;
    my $file = $self->{FILE};
    my($prefer) = 0;

    my $exttar = $self->{TARPRG} || "";
    $exttar = "" if $exttar =~ /^\s+$/; # user refuses to use it
    my $extgzip = $self->{UNGZIPPRG} || "";
    $extgzip = "" if $extgzip =~ /^\s+$/; # user refuses to use it

    if (0) { # makes changing order easier
    } elsif ($BUGHUNTING) {
        $prefer=2;
    } elsif ($CPAN::Config->{prefer_external_tar}) {
        $prefer = 1;
    } elsif (
             $CPAN::META->has_usable("Archive::Tar")
             &&
             _zlib_ok ) {
        my $prefer_external_tar = $CPAN::Config->{prefer_external_tar};
        unless (defined $prefer_external_tar) {
            if ($^O =~ /(MSWin32|solaris)/) {
                $prefer_external_tar = 0;
            } else {
                $prefer_external_tar = 1;
            }
        }
        $prefer = $prefer_external_tar ? 1 : 2;
    } elsif ($exttar && $extgzip) {
        # no modules and not bz2
        $prefer = 1;
        # but solaris binary tar is a problem
        if ($^O eq 'solaris' && qx($exttar --version 2>/dev/null) !~ /gnu/i) {
            $CPAN::Frontend->mywarn(<< 'END_WARN');

WARNING: Many CPAN distributions were archived with GNU tar and some of
them may be incompatible with Solaris tar.  We respectfully suggest you
configure CPAN to use a GNU tar instead ("o conf init tar") or install
a recent Archive::Tar instead;

END_WARN
        }
    } else {
        my $foundtar = $exttar ? "'$exttar'" : "nothing";
        my $foundzip = $extgzip ? "'$extgzip'" : $foundtar ? "nothing" : "also nothing";
        my $foundAT;
        if ($CPAN::META->has_usable("Archive::Tar")) {
            $foundAT = sprintf "'%s'", "Archive::Tar::"->VERSION;
        } else {
            $foundAT = "nothing";
        }
        my $foundCZ;
        if (_zlib_ok) {
            $foundCZ = sprintf "'%s'", "Compress::Zlib::"->VERSION;
        } elsif ($foundAT) {
            $foundCZ = "nothing";
        } else {
            $foundCZ = "also nothing";
        }
        $CPAN::Frontend->mydie(qq{

CPAN.pm needs either the external programs tar and gzip -or- both
modules Archive::Tar and Compress::Zlib installed.

For tar I found $foundtar, for gzip $foundzip.

For Archive::Tar I found $foundAT, for Compress::Zlib $foundCZ;

Can't continue cutting file '$file'.
});
    }
    my $tar_verb = "v";
    if (defined $CPAN::Config->{tar_verbosity}) {
        $tar_verb = $CPAN::Config->{tar_verbosity} eq "none" ? "" :
            $CPAN::Config->{tar_verbosity};
    }
    if ($prefer==1) { # 1 => external gzip+tar
        my($system);
        my $is_compressed = $self->gtest();
        my $tarcommand = CPAN::HandleConfig->safe_quote($exttar);
        if ($is_compressed) {
            my $command = CPAN::HandleConfig->safe_quote($extgzip);
            $system = qq{$command -d -c }.
                qq{< "$file" | $tarcommand x${tar_verb}f -};
        } else {
            $system = qq{$tarcommand x${tar_verb}f "$file"};
        }
        if (system($system) != 0) {
            # people find the most curious tar binaries that cannot handle
            # pipes
            if ($is_compressed) {
                (my $ungzf = $file) =~ s/\.gz(?!\n)\Z//;
                $ungzf = basename $ungzf;
                my $ct = CPAN::Tarzip->new($file);
                if ($ct->gunzip($ungzf)) {
                    $CPAN::Frontend->myprint(qq{Uncompressed $file successfully\n});
                } else {
                    $CPAN::Frontend->mydie(qq{Couldn\'t uncompress $file\n});
                }
                $file = $ungzf;
            }
            $system = qq{$tarcommand x${tar_verb}f "$file"};
            $CPAN::Frontend->myprint(qq{Using Tar:$system:\n});
            my $ret = system($system);
            if ($ret==0) {
                $CPAN::Frontend->myprint(qq{Untarred $file successfully\n});
            } else {
                if ($? == -1) {
                    $CPAN::Frontend->mydie(sprintf qq{Couldn\'t untar %s: '%s'\n},
                                           $file, $!);
                } elsif ($? & 127) {
                    $CPAN::Frontend->mydie(sprintf qq{Couldn\'t untar %s: child died with signal %d, %s coredump\n},
                                           $file, ($? & 127),  ($? & 128) ? 'with' : 'without');
                } else {
                    $CPAN::Frontend->mydie(sprintf qq{Couldn\'t untar %s: child exited with value %d\n},
                                           $file, $? >> 8);
                }
            }
            return 1;
        } else {
            return 1;
        }
    } elsif ($prefer==2) { # 2 => modules
        unless ($CPAN::META->has_usable("Archive::Tar")) {
            $CPAN::Frontend->mydie("Archive::Tar not installed, please install it to continue");
        }
        # Make sure AT does not use uid/gid/permissions in the archive
        # This leaves it to the user's umask instead
        local $Archive::Tar::CHMOD = 1;
        local $Archive::Tar::SAME_PERMISSIONS = 0;
        # Make sure AT leaves current user as owner
        local $Archive::Tar::CHOWN = 0;
        my $tar = Archive::Tar->new($file,1);
        my $af; # archive file
        my @af;
        if ($BUGHUNTING) {
            # RCS 1.337 had this code, it turned out unacceptable slow but
            # it revealed a bug in Archive::Tar. Code is only here to hunt
            # the bug again. It should never be enabled in published code.
            # GDGraph3d-0.53 was an interesting case according to Larry
            # Virden.
            warn(">>>Bughunting code enabled<<< " x 20);
            for $af ($tar->list_files) {
                if ($af =~ m!^(/|\.\./)!) {
                    $CPAN::Frontend->mydie("ALERT: Archive contains ".
                                           "illegal member [$af]");
                }
                $CPAN::Frontend->myprint("$af\n");
                $tar->extract($af); # slow but effective for finding the bug
                return if $CPAN::Signal;
            }
        } else {
            for $af ($tar->list_files) {
                if ($af =~ m!^(/|\.\./)!) {
                    $CPAN::Frontend->mydie("ALERT: Archive contains ".
                                           "illegal member [$af]");
                }
                if ($tar_verb eq "v" || $tar_verb eq "vv") {
                    $CPAN::Frontend->myprint("$af\n");
                }
                push @af, $af;
                return if $CPAN::Signal;
            }
            $tar->extract(@af) or
                $CPAN::Frontend->mydie("Could not untar with Archive::Tar.");
        }

        Mac::BuildTools::convert_files([$tar->list_files], 1)
            if ($^O eq 'MacOS');

        return 1;
    }
}

sub unzip {
    my($self) = @_;
    my $file = $self->{FILE};
    if ($CPAN::META->has_inst("Archive::Zip")) {
        # blueprint of the code from Archive::Zip::Tree::extractTree();
        my $zip = Archive::Zip->new();
        my $status;
        $status = $zip->read($file);
        $CPAN::Frontend->mydie("Read of file[$file] failed\n")
            if $status != Archive::Zip::AZ_OK();
        $CPAN::META->debug("Successfully read file[$file]") if $CPAN::DEBUG;
        my @members = $zip->members();
        for my $member ( @members ) {
            my $af = $member->fileName();
            if ($af =~ m!^(/|\.\./)!) {
                $CPAN::Frontend->mydie("ALERT: Archive contains ".
                                       "illegal member [$af]");
            }
            $status = $member->extractToFileNamed( $af );
            $CPAN::META->debug("af[$af]status[$status]") if $CPAN::DEBUG;
            $CPAN::Frontend->mydie("Extracting of file[$af] from zipfile[$file] failed\n") if
                $status != Archive::Zip::AZ_OK();
            return if $CPAN::Signal;
        }
        return 1;
    } elsif ( my $unzip = $CPAN::Config->{unzip}  ) {
        my @system = ($unzip, $file);
        return system(@system) == 0;
    }
    else {
            $CPAN::Frontend->mydie(<<"END");

Can't unzip '$file':

You have not configured an 'unzip' program and do not have Archive::Zip
installed.  Please either install Archive::Zip or else configure 'unzip'
by running the command 'o conf init unzip' from the CPAN shell prompt.

END
    }
}

1;

__END__

=head1 NAME

CPAN::Tarzip - internal handling of tar archives for CPAN.pm

=head1 LICENSE

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

=cut
PK7N%[B��3��perl5/CPAN/Queue.pmnu��6�$# -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*-
use strict;
package CPAN::Queue::Item;

# CPAN::Queue::Item::new ;
sub new {
    my($class,@attr) = @_;
    my $self = bless { @attr }, $class;
    return $self;
}

sub as_string {
    my($self) = @_;
    $self->{qmod};
}

# r => requires, b => build_requires, c => commandline
sub reqtype {
    my($self) = @_;
    $self->{reqtype};
}

sub optional {
    my($self) = @_;
    $self->{optional};
}

package CPAN::Queue;

# One use of the queue is to determine if we should or shouldn't
# announce the availability of a new CPAN module

# Now we try to use it for dependency tracking. For that to happen
# we need to draw a dependency tree and do the leaves first. This can
# easily be reached by running CPAN.pm recursively, but we don't want
# to waste memory and run into deep recursion. So what we can do is
# this:

# CPAN::Queue is the package where the queue is maintained. Dependencies
# often have high priority and must be brought to the head of the queue,
# possibly by jumping the queue if they are already there. My first code
# attempt tried to be extremely correct. Whenever a module needed
# immediate treatment, I either unshifted it to the front of the queue,
# or, if it was already in the queue, I spliced and let it bypass the
# others. This became a too correct model that made it impossible to put
# an item more than once into the queue. Why would you need that? Well,
# you need temporary duplicates as the manager of the queue is a loop
# that
#
#  (1) looks at the first item in the queue without shifting it off
#
#  (2) cares for the item
#
#  (3) removes the item from the queue, *even if its agenda failed and
#      even if the item isn't the first in the queue anymore* (that way
#      protecting against never ending queues)
#
# So if an item has prerequisites, the installation fails now, but we
# want to retry later. That's easy if we have it twice in the queue.
#
# I also expect insane dependency situations where an item gets more
# than two lives in the queue. Simplest example is triggered by 'install
# Foo Foo Foo'. People make this kind of mistakes and I don't want to
# get in the way. I wanted the queue manager to be a dumb servant, not
# one that knows everything.
#
# Who would I tell in this model that the user wants to be asked before
# processing? I can't attach that information to the module object,
# because not modules are installed but distributions. So I'd have to
# tell the distribution object that it should ask the user before
# processing. Where would the question be triggered then? Most probably
# in CPAN::Distribution::rematein.

use vars qw{ @All $VERSION };
$VERSION = "5.5003";

# CPAN::Queue::queue_item ;
sub queue_item {
    my($class,@attr) = @_;
    my $item = "$class\::Item"->new(@attr);
    $class->qpush($item);
    return 1;
}

# CPAN::Queue::qpush ;
sub qpush {
    my($class,$obj) = @_;
    push @All, $obj;
    CPAN->debug(sprintf("in new All[%s]",
                        join("",map {sprintf " %s\[%s][%s]\n",$_->{qmod},$_->{reqtype},$_->{optional}} @All),
                       )) if $CPAN::DEBUG;
}

# CPAN::Queue::first ;
sub first {
    my $obj = $All[0];
    $obj;
}

# CPAN::Queue::delete_first ;
sub delete_first {
    my($class,$what) = @_;
    my $i;
    for my $i (0..$#All) {
        if (  $All[$i]->{qmod} eq $what ) {
            splice @All, $i, 1;
            last;
        }
    }
    CPAN->debug(sprintf("after delete_first mod[%s] All[%s]",
                        $what,
                        join("",map {sprintf " %s\[%s][%s]\n",$_->{qmod},$_->{reqtype},$_->{optional}} @All)
                       )) if $CPAN::DEBUG;
}

# CPAN::Queue::jumpqueue ;
sub jumpqueue {
    my $class = shift;
    my @what = @_;
    CPAN->debug(sprintf("before jumpqueue All[%s] what[%s]",
                        join("",map {sprintf " %s\[%s][%s]\n",$_->{qmod},$_->{reqtype},$_->{optional}} @All),
                        join("",map {sprintf " %s\[%s][%s]\n",$_->{qmod},$_->{reqtype},$_->{optional}} @what),
                       )) if $CPAN::DEBUG;
    unless (defined $what[0]{reqtype}) {
        # apparently it was not the Shell that sent us this enquiry,
        # treat it as commandline
        $what[0]{reqtype} = "c";
    }
    my $inherit_reqtype = $what[0]{reqtype} =~ /^(c|r)$/ ? "r" : "b";
  WHAT: for my $what_tuple (@what) {
        my($qmod,$reqtype,$optional) = @$what_tuple{qw(qmod reqtype optional)};
        if ($reqtype eq "r"
            &&
            $inherit_reqtype eq "b"
           ) {
            $reqtype = "b";
        }
        my $jumped = 0;
        for (my $i=0; $i<$#All;$i++) { #prevent deep recursion
            if ($All[$i]{qmod} eq $qmod) {
                $jumped++;
            }
        }
        # high jumped values are normal for popular modules when
        # dealing with large bundles: XML::Simple,
        # namespace::autoclean, UNIVERSAL::require
        CPAN->debug("qmod[$qmod]jumped[$jumped]") if $CPAN::DEBUG;
        my $obj = "$class\::Item"->new(
                                       qmod => $qmod,
                                       reqtype => $reqtype,
                                       optional => !! $optional,
                                      );
        unshift @All, $obj;
    }
    CPAN->debug(sprintf("after jumpqueue All[%s]",
                        join("",map {sprintf " %s\[%s][%s]\n",$_->{qmod},$_->{reqtype},$_->{optional}} @All)
                       )) if $CPAN::DEBUG;
}

# CPAN::Queue::exists ;
sub exists {
    my($self,$what) = @_;
    my @all = map { $_->{qmod} } @All;
    my $exists = grep { $_->{qmod} eq $what } @All;
    # warn "in exists what[$what] all[@all] exists[$exists]";
    $exists;
}

# CPAN::Queue::delete ;
sub delete {
    my($self,$mod) = @_;
    @All = grep { $_->{qmod} ne $mod } @All;
    CPAN->debug(sprintf("after delete mod[%s] All[%s]",
                        $mod,
                        join("",map {sprintf " %s\[%s][%s]\n",$_->{qmod},$_->{reqtype},$_->{optional}} @All)
                       )) if $CPAN::DEBUG;
}

# CPAN::Queue::nullify_queue ;
sub nullify_queue {
    @All = ();
}

# CPAN::Queue::size ;
sub size {
    return scalar @All;
}

sub reqtype_of {
    my($self,$mod) = @_;
    my $best = "";
    for my $item (grep { $_->{qmod} eq $mod } @All) {
        my $c = $item->{reqtype};
        if ($c eq "c") {
            $best = $c;
            last;
        } elsif ($c eq "r") {
            $best = $c;
        } elsif ($c eq "b") {
            if ($best eq "") {
                $best = $c;
            }
        } else {
            die "Panic: in reqtype_of: reqtype[$c] seen, should never happen";
        }
    }
    return $best;
}

sub iterator {
    my $i = 0;
    return sub {
        until ($All[$i] || $i > $#All) {
            $i++;
        }
        return if $i > $#All;
        return $All[$i++]
    };
}

1;

__END__

=head1 NAME

CPAN::Queue - internal queue support for CPAN.pm

=head1 LICENSE

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

=cut
PK7N%[�!+���perl5/CPAN/Shell.pmnu��6�$package CPAN::Shell;
use strict;

# -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*-
# vim: ts=4 sts=4 sw=4:

use vars qw(
            $ADVANCED_QUERY
            $AUTOLOAD
            $COLOR_REGISTERED
            $Help
            $autoload_recursion
            $reload
            @ISA
            @relo
            $VERSION
           );
@relo =     (
             "CPAN.pm",
             "CPAN/Author.pm",
             "CPAN/CacheMgr.pm",
             "CPAN/Complete.pm",
             "CPAN/Debug.pm",
             "CPAN/DeferredCode.pm",
             "CPAN/Distribution.pm",
             "CPAN/Distroprefs.pm",
             "CPAN/Distrostatus.pm",
             "CPAN/Exception/RecursiveDependency.pm",
             "CPAN/Exception/yaml_not_installed.pm",
             "CPAN/FirstTime.pm",
             "CPAN/FTP.pm",
             "CPAN/FTP/netrc.pm",
             "CPAN/HandleConfig.pm",
             "CPAN/Index.pm",
             "CPAN/InfoObj.pm",
             "CPAN/Kwalify.pm",
             "CPAN/LWP/UserAgent.pm",
             "CPAN/Module.pm",
             "CPAN/Prompt.pm",
             "CPAN/Queue.pm",
             "CPAN/Reporter/Config.pm",
             "CPAN/Reporter/History.pm",
             "CPAN/Reporter/PrereqCheck.pm",
             "CPAN/Reporter.pm",
             "CPAN/Shell.pm",
             "CPAN/SQLite.pm",
             "CPAN/Tarzip.pm",
             "CPAN/Version.pm",
            );
$VERSION = "5.5009";
# record the initial timestamp for reload.
$reload = { map {$INC{$_} ? ($_,(stat $INC{$_})[9]) : ()} @relo };
@CPAN::Shell::ISA = qw(CPAN::Debug);
use Cwd qw(chdir);
use Carp ();
$COLOR_REGISTERED ||= 0;
$Help = {
         '?' => \"help",
         '!' => "eval the rest of the line as perl",
         a => "whois author",
         autobundle => "write inventory into a bundle file",
         b => "info about bundle",
         bye => \"quit",
         clean => "clean up a distribution's build directory",
         # cvs_import
         d => "info about a distribution",
         # dump
         exit => \"quit",
         failed => "list all failed actions within current session",
         fforce => "redo a command from scratch",
         force => "redo a command",
         get => "download a distribution",
         h => \"help",
         help => "overview over commands; 'help ...' explains specific commands",
         hosts => "statistics about recently used hosts",
         i => "info about authors/bundles/distributions/modules",
         install => "install a distribution",
         install_tested => "install all distributions tested OK",
         is_tested => "list all distributions tested OK",
         look => "open a subshell in a distribution's directory",
         ls => "list distributions matching a fileglob",
         m => "info about a module",
         make => "make/build a distribution",
         mkmyconfig => "write current config into a CPAN/MyConfig.pm file",
         notest => "run a (usually install) command but leave out the test phase",
         o => "'o conf ...' for config stuff; 'o debug ...' for debugging",
         perldoc => "try to get a manpage for a module",
         q => \"quit",
         quit => "leave the cpan shell",
         r => "review upgradable modules",
         readme => "display the README of a distro with a pager",
         recent => "show recent uploads to the CPAN",
         # recompile
         reload => "'reload cpan' or 'reload index'",
         report => "test a distribution and send a test report to cpantesters",
         reports => "info about reported tests from cpantesters",
         # scripts
         # smoke
         test => "test a distribution",
         u => "display uninstalled modules",
         upgrade => "combine 'r' command with immediate installation",
        };
{
    $autoload_recursion   ||= 0;

    #-> sub CPAN::Shell::AUTOLOAD ;
    sub AUTOLOAD { ## no critic
        $autoload_recursion++;
        my($l) = $AUTOLOAD;
        my $class = shift(@_);
        # warn "autoload[$l] class[$class]";
        $l =~ s/.*:://;
        if ($CPAN::Signal) {
            warn "Refusing to autoload '$l' while signal pending";
            $autoload_recursion--;
            return;
        }
        if ($autoload_recursion > 1) {
            my $fullcommand = join " ", map { "'$_'" } $l, @_;
            warn "Refusing to autoload $fullcommand in recursion\n";
            $autoload_recursion--;
            return;
        }
        if ($l =~ /^w/) {
            # XXX needs to be reconsidered
            if ($CPAN::META->has_inst('CPAN::WAIT')) {
                CPAN::WAIT->$l(@_);
            } else {
                $CPAN::Frontend->mywarn(qq{
Commands starting with "w" require CPAN::WAIT to be installed.
Please consider installing CPAN::WAIT to use the fulltext index.
For this you just need to type
    install CPAN::WAIT
});
            }
        } else {
            $CPAN::Frontend->mywarn(qq{Unknown shell command '$l'. }.
                                    qq{Type ? for help.
});
        }
        $autoload_recursion--;
    }
}


#-> sub CPAN::Shell::h ;
sub h {
    my($class,$about) = @_;
    if (defined $about) {
        my $help;
        if (exists $Help->{$about}) {
            if (ref $Help->{$about}) { # aliases
                $about = ${$Help->{$about}};
            }
            $help = $Help->{$about};
        } else {
            $help = "No help available";
        }
        $CPAN::Frontend->myprint("$about\: $help\n");
    } else {
        my $filler = " " x (80 - 28 - length($CPAN::VERSION));
        $CPAN::Frontend->myprint(qq{
Display Information $filler (ver $CPAN::VERSION)
 command  argument          description
 a,b,d,m  WORD or /REGEXP/  about authors, bundles, distributions, modules
 i        WORD or /REGEXP/  about any of the above
 ls       AUTHOR or GLOB    about files in the author's directory
    (with WORD being a module, bundle or author name or a distribution
    name of the form AUTHOR/DISTRIBUTION)

Download, Test, Make, Install...
 get      download                     clean    make clean
 make     make (implies get)           look     open subshell in dist directory
 test     make test (implies make)     readme   display these README files
 install  make install (implies test)  perldoc  display POD documentation

Upgrade installed modules
 r        WORDs or /REGEXP/ or NONE    report updates for some/matching/all
 upgrade  WORDs or /REGEXP/ or NONE    upgrade some/matching/all modules

Pragmas
 force  CMD    try hard to do command  fforce CMD    try harder
 notest CMD    skip testing

Other
 h,?           display this menu       ! perl-code   eval a perl command
 o conf [opt]  set and query options   q             quit the cpan shell
 reload cpan   load CPAN.pm again      reload index  load newer indices
 autobundle    Snapshot                recent        latest CPAN uploads});
}
}

*help = \&h;

#-> sub CPAN::Shell::a ;
sub a {
  my($self,@arg) = @_;
  # authors are always UPPERCASE
  for (@arg) {
    $_ = uc $_ unless /=/;
  }
  $CPAN::Frontend->myprint($self->format_result('Author',@arg));
}

#-> sub CPAN::Shell::globls ;
sub globls {
    my($self,$s,$pragmas) = @_;
    # ls is really very different, but we had it once as an ordinary
    # command in the Shell (up to rev. 321) and we could not handle
    # force well then
    my(@accept,@preexpand);
    if ($s =~ /[\*\?\/]/) {
        if ($CPAN::META->has_inst("Text::Glob")) {
            if (my($au,$pathglob) = $s =~ m|(.*?)/(.*)|) {
                my $rau = Text::Glob::glob_to_regex(uc $au);
                CPAN::Shell->debug("au[$au]pathglob[$pathglob]rau[$rau]")
                      if $CPAN::DEBUG;
                push @preexpand, map { $_->id . "/" . $pathglob }
                    CPAN::Shell->expand_by_method('CPAN::Author',['id'],"/$rau/");
            } else {
                my $rau = Text::Glob::glob_to_regex(uc $s);
                push @preexpand, map { $_->id }
                    CPAN::Shell->expand_by_method('CPAN::Author',
                                                  ['id'],
                                                  "/$rau/");
            }
        } else {
            $CPAN::Frontend->mydie("Text::Glob not installed, cannot proceed");
        }
    } else {
        push @preexpand, uc $s;
    }
    for (@preexpand) {
        unless (/^[A-Z0-9\-]+(\/|$)/i) {
            $CPAN::Frontend->mywarn("ls command rejects argument $_: not an author\n");
            next;
        }
        push @accept, $_;
    }
    my $silent = @accept>1;
    my $last_alpha = "";
    my @results;
    for my $a (@accept) {
        my($author,$pathglob);
        if ($a =~ m|(.*?)/(.*)|) {
            my $a2 = $1;
            $pathglob = $2;
            $author = CPAN::Shell->expand_by_method('CPAN::Author',
                                                    ['id'],
                                                    $a2)
                or $CPAN::Frontend->mydie("No author found for $a2\n");
        } else {
            $author = CPAN::Shell->expand_by_method('CPAN::Author',
                                                    ['id'],
                                                    $a)
                or $CPAN::Frontend->mydie("No author found for $a\n");
        }
        if ($silent) {
            my $alpha = substr $author->id, 0, 1;
            my $ad;
            if ($alpha eq $last_alpha) {
                $ad = "";
            } else {
                $ad = "[$alpha]";
                $last_alpha = $alpha;
            }
            $CPAN::Frontend->myprint($ad);
        }
        for my $pragma (@$pragmas) {
            if ($author->can($pragma)) {
                $author->$pragma();
            }
        }
        CPAN->debug("author[$author]pathglob[$pathglob]silent[$silent]") if $CPAN::DEBUG;
        push @results, $author->ls($pathglob,$silent); # silent if
                                                       # more than one
                                                       # author
        for my $pragma (@$pragmas) {
            my $unpragma = "un$pragma";
            if ($author->can($unpragma)) {
                $author->$unpragma();
            }
        }
    }
    @results;
}

#-> sub CPAN::Shell::local_bundles ;
sub local_bundles {
    my($self,@which) = @_;
    my($incdir,$bdir,$dh);
    foreach $incdir ($CPAN::Config->{'cpan_home'},@INC) {
        my @bbase = "Bundle";
        while (my $bbase = shift @bbase) {
            $bdir = File::Spec->catdir($incdir,split /::/, $bbase);
            CPAN->debug("bdir[$bdir]\@bbase[@bbase]") if $CPAN::DEBUG;
            if ($dh = DirHandle->new($bdir)) { # may fail
                my($entry);
                for $entry ($dh->read) {
                    next if $entry =~ /^\./;
                    next unless $entry =~ /^\w+(\.pm)?(?!\n)\Z/;
                    if (-d File::Spec->catdir($bdir,$entry)) {
                        push @bbase, "$bbase\::$entry";
                    } else {
                        next unless $entry =~ s/\.pm(?!\n)\Z//;
                        $CPAN::META->instance('CPAN::Bundle',"$bbase\::$entry");
                    }
                }
            }
        }
    }
}

#-> sub CPAN::Shell::b ;
sub b {
    my($self,@which) = @_;
    CPAN->debug("which[@which]") if $CPAN::DEBUG;
    $self->local_bundles;
    $CPAN::Frontend->myprint($self->format_result('Bundle',@which));
}

#-> sub CPAN::Shell::d ;
sub d { $CPAN::Frontend->myprint(shift->format_result('Distribution',@_));}

#-> sub CPAN::Shell::m ;
sub m { # emacs confused here }; sub mimimimimi { # emacs in sync here
    my $self = shift;
    my @m = @_;
    for (@m) {
        if (m|(?:\w+/)*\w+\.pm$|) { # same regexp in expandany
            s/.pm$//;
            s|/|::|g;
        }
    }
    $CPAN::Frontend->myprint($self->format_result('Module',@m));
}

#-> sub CPAN::Shell::i ;
sub i {
    my($self) = shift;
    my(@args) = @_;
    @args = '/./' unless @args;
    my(@result);
    for my $type (qw/Bundle Distribution Module/) {
        push @result, $self->expand($type,@args);
    }
    # Authors are always uppercase.
    push @result, $self->expand("Author", map { uc $_ } @args);

    my $result = @result == 1 ?
        $result[0]->as_string :
            @result == 0 ?
                "No objects found of any type for argument @args\n" :
                    join("",
                         (map {$_->as_glimpse} @result),
                         scalar @result, " items found\n",
                        );
    $CPAN::Frontend->myprint($result);
}

#-> sub CPAN::Shell::o ;

# CPAN::Shell::o and CPAN::HandleConfig::edit are closely related. 'o
# conf' calls through to CPAN::HandleConfig::edit. 'o conf' should
# probably have been called 'set' and 'o debug' maybe 'set debug' or
# 'debug'; 'o conf ARGS' calls ->edit in CPAN/HandleConfig.pm
sub o {
    my($self,$o_type,@o_what) = @_;
    $o_type ||= "";
    CPAN->debug("o_type[$o_type] o_what[".join(" | ",@o_what)."]\n");
    if ($o_type eq 'conf') {
        my($cfilter);
        ($cfilter) = $o_what[0] =~ m|^/(.*)/$| if @o_what;
        if (!@o_what or $cfilter) { # print all things, "o conf"
            $cfilter ||= "";
            my $qrfilter = eval 'qr/$cfilter/';
            if ($@) {
                $CPAN::Frontend->mydie("Cannot parse commandline: $@");
            }
            my($k,$v);
            my $configpm = CPAN::HandleConfig->require_myconfig_or_config;
            $CPAN::Frontend->myprint("\$CPAN::Config options from $configpm\:\n");
            for $k (sort keys %CPAN::HandleConfig::can) {
                next unless $k =~ /$qrfilter/;
                $v = $CPAN::HandleConfig::can{$k};
                $CPAN::Frontend->myprint(sprintf "    %-18s [%s]\n", $k, $v);
            }
            $CPAN::Frontend->myprint("\n");
            for $k (sort keys %CPAN::HandleConfig::keys) {
                next unless $k =~ /$qrfilter/;
                CPAN::HandleConfig->prettyprint($k);
            }
            $CPAN::Frontend->myprint("\n");
        } else {
            if (CPAN::HandleConfig->edit(@o_what)) {
            } else {
                $CPAN::Frontend->myprint(qq{Type 'o conf' to view all configuration }.
                                         qq{items\n\n});
            }
        }
    } elsif ($o_type eq 'debug') {
        my(%valid);
        @o_what = () if defined $o_what[0] && $o_what[0] =~ /help/i;
        if (@o_what) {
            while (@o_what) {
                my($what) = shift @o_what;
                if ($what =~ s/^-// && exists $CPAN::DEBUG{$what}) {
                    $CPAN::DEBUG &= $CPAN::DEBUG ^ $CPAN::DEBUG{$what};
                    next;
                }
                if ( exists $CPAN::DEBUG{$what} ) {
                    $CPAN::DEBUG |= $CPAN::DEBUG{$what};
                } elsif ($what =~ /^\d/) {
                    $CPAN::DEBUG = $what;
                } elsif (lc $what eq 'all') {
                    my($max) = 0;
                    for (values %CPAN::DEBUG) {
                        $max += $_;
                    }
                    $CPAN::DEBUG = $max;
                } else {
                    my($known) = 0;
                    for (keys %CPAN::DEBUG) {
                        next unless lc($_) eq lc($what);
                        $CPAN::DEBUG |= $CPAN::DEBUG{$_};
                        $known = 1;
                    }
                    $CPAN::Frontend->myprint("unknown argument [$what]\n")
                        unless $known;
                }
            }
        } else {
            my $raw = "Valid options for debug are ".
                join(", ",sort(keys %CPAN::DEBUG), 'all').
                     qq{ or a number. Completion works on the options. }.
                     qq{Case is ignored.};
            require Text::Wrap;
            $CPAN::Frontend->myprint(Text::Wrap::fill("","",$raw));
            $CPAN::Frontend->myprint("\n\n");
        }
        if ($CPAN::DEBUG) {
            $CPAN::Frontend->myprint("Options set for debugging ($CPAN::DEBUG):\n");
            my($k,$v);
            for $k (sort {$CPAN::DEBUG{$a} <=> $CPAN::DEBUG{$b}} keys %CPAN::DEBUG) {
                $v = $CPAN::DEBUG{$k};
                $CPAN::Frontend->myprint(sprintf "    %-14s(%s)\n", $k, $v)
                    if $v & $CPAN::DEBUG;
            }
        } else {
            $CPAN::Frontend->myprint("Debugging turned off completely.\n");
        }
    } else {
        $CPAN::Frontend->myprint(qq{
Known options:
  conf    set or get configuration variables
  debug   set or get debugging options
});
    }
}

# CPAN::Shell::paintdots_onreload
sub paintdots_onreload {
    my($ref) = shift;
    sub {
        if ( $_[0] =~ /[Ss]ubroutine ([\w:]+) redefined/ ) {
            my($subr) = $1;
            ++$$ref;
            local($|) = 1;
            # $CPAN::Frontend->myprint(".($subr)");
            $CPAN::Frontend->myprint(".");
            if ($subr =~ /\bshell\b/i) {
                # warn "debug[$_[0]]";

                # It would be nice if we could detect that a
                # subroutine has actually changed, but for now we
                # practically always set the GOTOSHELL global

                $CPAN::GOTOSHELL=1;
            }
            return;
        }
        warn @_;
    };
}

#-> sub CPAN::Shell::hosts ;
sub hosts {
    my($self) = @_;
    my $fullstats = CPAN::FTP->_ftp_statistics();
    my $history = $fullstats->{history} || [];
    my %S; # statistics
    while (my $last = pop @$history) {
        my $attempts = $last->{attempts} or next;
        my $start;
        if (@$attempts) {
            $start = $attempts->[-1]{start};
            if ($#$attempts > 0) {
                for my $i (0..$#$attempts-1) {
                    my $url = $attempts->[$i]{url} or next;
                    $S{no}{$url}++;
                }
            }
        } else {
            $start = $last->{start};
        }
        next unless $last->{thesiteurl}; # C-C? bad filenames?
        $S{start} = $start;
        $S{end} ||= $last->{end};
        my $dltime = $last->{end} - $start;
        my $dlsize = $last->{filesize} || 0;
        my $url = ref $last->{thesiteurl} ? $last->{thesiteurl}->text : $last->{thesiteurl};
        my $s = $S{ok}{$url} ||= {};
        $s->{n}++;
        $s->{dlsize} ||= 0;
        $s->{dlsize} += $dlsize/1024;
        $s->{dltime} ||= 0;
        $s->{dltime} += $dltime;
    }
    my $res;
    for my $url (sort keys %{$S{ok}}) {
        next if $S{ok}{$url}{dltime} == 0; # div by zero
        push @{$res->{ok}}, [@{$S{ok}{$url}}{qw(n dlsize dltime)},
                             $S{ok}{$url}{dlsize}/$S{ok}{$url}{dltime},
                             $url,
                            ];
    }
    for my $url (sort keys %{$S{no}}) {
        push @{$res->{no}}, [$S{no}{$url},
                             $url,
                            ];
    }
    my $R = ""; # report
    if ($S{start} && $S{end}) {
        $R .= sprintf "Log starts: %s\n", $S{start} ? scalar(localtime $S{start}) : "unknown";
        $R .= sprintf "Log ends  : %s\n", $S{end}   ? scalar(localtime $S{end})   : "unknown";
    }
    if ($res->{ok} && @{$res->{ok}}) {
        $R .= sprintf "\nSuccessful downloads:
   N       kB  secs      kB/s url\n";
        my $i = 20;
        for (sort { $b->[3] <=> $a->[3] } @{$res->{ok}}) {
            $R .= sprintf "%4d %8d %5d %9.1f %s\n", @$_;
            last if --$i<=0;
        }
    }
    if ($res->{no} && @{$res->{no}}) {
        $R .= sprintf "\nUnsuccessful downloads:\n";
        my $i = 20;
        for (sort { $b->[0] <=> $a->[0] } @{$res->{no}}) {
            $R .= sprintf "%4d %s\n", @$_;
            last if --$i<=0;
        }
    }
    $CPAN::Frontend->myprint($R);
}

# here is where 'reload cpan' is done
#-> sub CPAN::Shell::reload ;
sub reload {
    my($self,$command,@arg) = @_;
    $command ||= "";
    $self->debug("self[$self]command[$command]arg[@arg]") if $CPAN::DEBUG;
    if ($command =~ /^cpan$/i) {
        my $redef = 0;
        chdir "$CPAN::iCwd" if $CPAN::iCwd; # may fail
        my $failed;
      MFILE: for my $f (@relo) {
            next unless exists $INC{$f};
            my $p = $f;
            $p =~ s/\.pm$//;
            $p =~ s|/|::|g;
            $CPAN::Frontend->myprint("($p");
            local($SIG{__WARN__}) = paintdots_onreload(\$redef);
            $self->_reload_this($f) or $failed++;
            my $v = eval "$p\::->VERSION";
            $CPAN::Frontend->myprint("v$v)");
        }
        $CPAN::Frontend->myprint("\n$redef subroutines redefined\n");
        if ($failed) {
            my $errors = $failed == 1 ? "error" : "errors";
            $CPAN::Frontend->mywarn("\n$failed $errors during reload. You better quit ".
                                    "this session.\n");
        }
    } elsif ($command =~ /^index$/i) {
      CPAN::Index->force_reload;
    } else {
      $CPAN::Frontend->myprint(qq{cpan     re-evals the CPAN modules
index    re-reads the index files\n});
    }
}

# reload means only load again what we have loaded before
#-> sub CPAN::Shell::_reload_this ;
sub _reload_this {
    my($self,$f,$args) = @_;
    CPAN->debug("f[$f]") if $CPAN::DEBUG;
    return 1 unless $INC{$f}; # we never loaded this, so we do not
                              # reload but say OK
    my $pwd = CPAN::anycwd();
    CPAN->debug("pwd[$pwd]") if $CPAN::DEBUG;
    my($file);
    for my $inc (@INC) {
        $file = File::Spec->catfile($inc,split /\//, $f);
        last if -f $file;
        $file = "";
    }
    CPAN->debug("file[$file]") if $CPAN::DEBUG;
    my @inc = @INC;
    unless ($file && -f $file) {
        # this thingy is not in the INC path, maybe CPAN/MyConfig.pm?
        $file = $INC{$f};
        unless (CPAN->has_inst("File::Basename")) {
            @inc = File::Basename::dirname($file);
        } else {
            # do we ever need this?
            @inc = substr($file,0,-length($f)-1); # bring in back to me!
        }
    }
    CPAN->debug("file[$file]inc[@inc]") if $CPAN::DEBUG;
    unless (-f $file) {
        $CPAN::Frontend->mywarn("Found no file to reload for '$f'\n");
        return;
    }
    my $mtime = (stat $file)[9];
    $reload->{$f} ||= -1;
    my $must_reload = $mtime != $reload->{$f};
    $args ||= {};
    $must_reload ||= $args->{reloforce}; # o conf defaults needs this
    if ($must_reload) {
        my $fh = FileHandle->new($file) or
            $CPAN::Frontend->mydie("Could not open $file: $!");
        my $content;
        {
            local($/);
            local $^W = 1;
            $content = <$fh>;
        }
        CPAN->debug(sprintf("reload file[%s] content[%s...]",$file,substr($content,0,128)))
            if $CPAN::DEBUG;
        my $includefile;
        if ($includefile = $INC{$f} and -e $includefile) {
            $f = $includefile;
        }
        delete $INC{$f};
        local @INC = @inc;
        eval "require '$f'";
        if ($@) {
            warn $@;
            return;
        }
        $reload->{$f} = $mtime;
    } else {
        $CPAN::Frontend->myprint("__unchanged__");
    }
    return 1;
}

#-> sub CPAN::Shell::mkmyconfig ;
sub mkmyconfig {
    my($self) = @_;
    if ( my $configpm = $INC{'CPAN/MyConfig.pm'} ) {
        $CPAN::Frontend->myprint(
            "CPAN::MyConfig already exists as $configpm.\n" .
            "Running configuration again...\n"
        );
        require CPAN::FirstTime;
        CPAN::FirstTime::init($configpm);
    }
    else {
        # force some missing values to be filled in with defaults
        delete $CPAN::Config->{$_}
            for qw/build_dir cpan_home keep_source_where histfile/;
        CPAN::HandleConfig->load( make_myconfig => 1 );
    }
}

#-> sub CPAN::Shell::_binary_extensions ;
sub _binary_extensions {
    my($self) = shift @_;
    my(@result,$module,%seen,%need,$headerdone);
    for $module ($self->expand('Module','/./')) {
        my $file  = $module->cpan_file;
        next if $file eq "N/A";
        next if $file =~ /^Contact Author/;
        my $dist = $CPAN::META->instance('CPAN::Distribution',$file);
        next if $dist->isa_perl;
        next unless $module->xs_file;
        local($|) = 1;
        $CPAN::Frontend->myprint(".");
        push @result, $module;
    }
#    print join " | ", @result;
    $CPAN::Frontend->myprint("\n");
    return @result;
}

#-> sub CPAN::Shell::recompile ;
sub recompile {
    my($self) = shift @_;
    my($module,@module,$cpan_file,%dist);
    @module = $self->_binary_extensions();
    for $module (@module) { # we force now and compile later, so we
                            # don't do it twice
        $cpan_file = $module->cpan_file;
        my $pack = $CPAN::META->instance('CPAN::Distribution',$cpan_file);
        $pack->force;
        $dist{$cpan_file}++;
    }
    for $cpan_file (sort keys %dist) {
        $CPAN::Frontend->myprint("  CPAN: Recompiling $cpan_file\n\n");
        my $pack = $CPAN::META->instance('CPAN::Distribution',$cpan_file);
        $pack->install;
        $CPAN::Signal = 0; # it's tempting to reset Signal, so we can
                           # stop a package from recompiling,
                           # e.g. IO-1.12 when we have perl5.003_10
    }
}

#-> sub CPAN::Shell::scripts ;
sub scripts {
    my($self, $arg) = @_;
    $CPAN::Frontend->mywarn(">>>> experimental command, currently unsupported <<<<\n\n");

    for my $req (qw( HTML::LinkExtor Sort::Versions List::Util )) {
        unless ($CPAN::META->has_inst($req)) {
            $CPAN::Frontend->mywarn("  $req not available\n");
        }
    }
    my $p = HTML::LinkExtor->new();
    my $indexfile = "/home/ftp/pub/PAUSE/scripts/new/index.html";
    unless (-f $indexfile) {
        $CPAN::Frontend->mydie("found no indexfile[$indexfile]\n");
    }
    $p->parse_file($indexfile);
    my @hrefs;
    my $qrarg;
    if ($arg =~ s|^/(.+)/$|$1|) {
        $qrarg = eval 'qr/$arg/'; # hide construct from 5.004
    }
    for my $l ($p->links) {
        my $tag = shift @$l;
        next unless $tag eq "a";
        my %att = @$l;
        my $href = $att{href};
        next unless $href =~ s|^\.\./authors/id/./../||;
        if ($arg) {
            if ($qrarg) {
                if ($href =~ $qrarg) {
                    push @hrefs, $href;
                }
            } else {
                if ($href =~ /\Q$arg\E/) {
                    push @hrefs, $href;
                }
            }
        } else {
            push @hrefs, $href;
        }
    }
    # now filter for the latest version if there is more than one of a name
    my %stems;
    for (sort @hrefs) {
        my $href = $_;
        s/-v?\d.*//;
        my $stem = $_;
        $stems{$stem} ||= [];
        push @{$stems{$stem}}, $href;
    }
    for (sort keys %stems) {
        my $highest;
        if (@{$stems{$_}} > 1) {
            $highest = List::Util::reduce {
                Sort::Versions::versioncmp($a,$b) > 0 ? $a : $b
              } @{$stems{$_}};
        } else {
            $highest = $stems{$_}[0];
        }
        $CPAN::Frontend->myprint("$highest\n");
    }
}

sub _guess_manpage {
    my($self,$d,$contains,$dist) = @_;
    $dist =~ s/-/::/g;
    my $module;
    if (exists $contains->{$dist}) {
        $module = $dist;
    } elsif (1 == keys %$contains) {
        ($module) = keys %$contains;
    }
    my $manpage;
    if ($module) {
        my $m = $self->expand("Module",$module);
        $m->as_string; # called for side-effects, shame
        $manpage = $m->{MANPAGE};
    } else {
        $manpage = "unknown";
    }
    return $manpage;
}

#-> sub CPAN::Shell::_specfile ;
sub _specfile {
    die "CPAN::Shell::_specfile() has been moved to CPAN::Plugin::Specfile::post_test()";
}

#-> sub CPAN::Shell::report ;
sub report {
    my($self,@args) = @_;
    unless ($CPAN::META->has_inst("CPAN::Reporter")) {
        $CPAN::Frontend->mydie("CPAN::Reporter not installed; cannot continue");
    }
    local $CPAN::Config->{test_report} = 1;
    $self->force("test",@args); # force is there so that the test be
                                # re-run (as documented)
}

# compare with is_tested
#-> sub CPAN::Shell::install_tested
sub install_tested {
    my($self,@some) = @_;
    $CPAN::Frontend->mywarn("install_tested() must not be called with arguments.\n"),
        return if @some;
    CPAN::Index->reload;

    for my $b (reverse $CPAN::META->_list_sorted_descending_is_tested) {
        my $yaml = "$b.yml";
        unless (-f $yaml) {
            $CPAN::Frontend->mywarn("No YAML file for $b available, skipping\n");
            next;
        }
        my $yaml_content = CPAN->_yaml_loadfile($yaml);
        my $id = $yaml_content->[0]{distribution}{ID};
        unless ($id) {
            $CPAN::Frontend->mywarn("No ID found in '$yaml', skipping\n");
            next;
        }
        my $do = CPAN::Shell->expandany($id);
        unless ($do) {
            $CPAN::Frontend->mywarn("Could not expand ID '$id', skipping\n");
            next;
        }
        unless ($do->{build_dir}) {
            $CPAN::Frontend->mywarn("Distro '$id' has no build_dir, skipping\n");
            next;
        }
        unless ($do->{build_dir} eq $b) {
            $CPAN::Frontend->mywarn("Distro '$id' has build_dir '$do->{build_dir}' but expected '$b', skipping\n");
            next;
        }
        push @some, $do;
    }

    $CPAN::Frontend->mywarn("No tested distributions found.\n"),
        return unless @some;

    @some = grep { $_->{make_test} && ! $_->{make_test}->failed } @some;
    $CPAN::Frontend->mywarn("No distributions tested with this build of perl found.\n"),
        return unless @some;

    # @some = grep { not $_->uptodate } @some;
    # $CPAN::Frontend->mywarn("No non-uptodate distributions tested with this build of perl found.\n"),
    #     return unless @some;

    CPAN->debug("some[@some]");
    for my $d (@some) {
        my $id = $d->can("pretty_id") ? $d->pretty_id : $d->id;
        $CPAN::Frontend->myprint("install_tested: Running for $id\n");
        $CPAN::Frontend->mysleep(1);
        $self->install($d);
    }
}

#-> sub CPAN::Shell::upgrade ;
sub upgrade {
    my($self,@args) = @_;
    $self->install($self->r(@args));
}

#-> sub CPAN::Shell::_u_r_common ;
sub _u_r_common {
    my($self) = shift @_;
    my($what) = shift @_;
    CPAN->debug("self[$self] what[$what] args[@_]") if $CPAN::DEBUG;
    Carp::croak "Usage: \$obj->_u_r_common(a|r|u)" unless
          $what && $what =~ /^[aru]$/;
    my(@args) = @_;
    @args = '/./' unless @args;
    my(@result,$module,%seen,%need,$headerdone,
       $version_undefs,$version_zeroes,
       @version_undefs,@version_zeroes);
    $version_undefs = $version_zeroes = 0;
    my $sprintf = "%s%-25s%s %9s %9s  %s\n";
    my @expand = $self->expand('Module',@args);
    if ($CPAN::DEBUG) { # Looks like noise to me, was very useful for debugging
             # for metadata cache
        my $expand = scalar @expand;
        $CPAN::Frontend->myprint(sprintf "%d matches in the database, time[%d]\n", $expand, time);
    }
    my @sexpand;
    if ($] < 5.008) {
        # hard to believe that the more complex sorting can lead to
        # stack curruptions on older perl
        @sexpand = sort {$a->id cmp $b->id} @expand;
    } else {
        @sexpand = map {
            $_->[1]
        } sort {
            $b->[0] <=> $a->[0]
            ||
            $a->[1]{ID} cmp $b->[1]{ID},
        } map {
            [$_->_is_representative_module,
             $_
            ]
        } @expand;
    }
    if ($CPAN::DEBUG) {
        $CPAN::Frontend->myprint(sprintf "sorted at time[%d]\n", time);
        sleep 1;
    }
  MODULE: for $module (@sexpand) {
        my $file  = $module->cpan_file;
        next MODULE unless defined $file; # ??
        $file =~ s!^./../!!;
        my($latest) = $module->cpan_version;
        my($inst_file) = $module->inst_file;
        CPAN->debug("file[$file]latest[$latest]") if $CPAN::DEBUG;
        my($have);
        return if $CPAN::Signal;
        my($next_MODULE);
        eval { # version.pm involved!
            if ($inst_file) {
                if ($what eq "a") {
                    $have = $module->inst_version;
                } elsif ($what eq "r") {
                    $have = $module->inst_version;
                    local($^W) = 0;
                    if ($have eq "undef") {
                        $version_undefs++;
                        push @version_undefs, $module->as_glimpse;
                    } elsif (CPAN::Version->vcmp($have,0)==0) {
                        $version_zeroes++;
                        push @version_zeroes, $module->as_glimpse;
                    }
                    ++$next_MODULE unless CPAN::Version->vgt($latest, $have);
                    # to be pedantic we should probably say:
                    #    && !($have eq "undef" && $latest ne "undef" && $latest gt "");
                    # to catch the case where CPAN has a version 0 and we have a version undef
                } elsif ($what eq "u") {
                    ++$next_MODULE;
                }
            } else {
                if ($what eq "a") {
                    ++$next_MODULE;
                } elsif ($what eq "r") {
                    ++$next_MODULE;
                } elsif ($what eq "u") {
                    $have = "-";
                }
            }
        };
        next MODULE if $next_MODULE;
        if ($@) {
            $CPAN::Frontend->mywarn
                (sprintf("Error while comparing cpan/installed versions of '%s':
INST_FILE: %s
INST_VERSION: %s %s
CPAN_VERSION: %s %s
",
                         $module->id,
                         $inst_file || "",
                         (defined $have ? $have : "[UNDEFINED]"),
                         (ref $have ? ref $have : ""),
                         $latest,
                         (ref $latest ? ref $latest : ""),
                        ));
            next MODULE;
        }
        return if $CPAN::Signal; # this is sometimes lengthy
        $seen{$file} ||= 0;
        if ($what eq "a") {
            push @result, sprintf "%s %s\n", $module->id, $have;
        } elsif ($what eq "r") {
            push @result, $module->id;
            next MODULE if $seen{$file}++;
        } elsif ($what eq "u") {
            push @result, $module->id;
            next MODULE if $seen{$file}++;
            next MODULE if $file =~ /^Contact/;
        }
        unless ($headerdone++) {
            $CPAN::Frontend->myprint("\n");
            $CPAN::Frontend->myprint(sprintf(
                                             $sprintf,
                                             "",
                                             "Package namespace",
                                             "",
                                             "installed",
                                             "latest",
                                             "in CPAN file"
                                            ));
        }
        my $color_on = "";
        my $color_off = "";
        if (
            $COLOR_REGISTERED
            &&
            $CPAN::META->has_inst("Term::ANSIColor")
            &&
            $module->description
           ) {
            $color_on = Term::ANSIColor::color("green");
            $color_off = Term::ANSIColor::color("reset");
        }
        $CPAN::Frontend->myprint(sprintf $sprintf,
                                 $color_on,
                                 $module->id,
                                 $color_off,
                                 $have,
                                 $latest,
                                 $file);
        $need{$module->id}++;
    }
    unless (%need) {
        if (!@expand || $what eq "u") {
            $CPAN::Frontend->myprint("No modules found for @args\n");
        } elsif ($what eq "r") {
            $CPAN::Frontend->myprint("All modules are up to date for @args\n");
        }
    }
    if ($what eq "r") {
        if ($version_zeroes) {
            my $s_has = $version_zeroes > 1 ? "s have" : " has";
            $CPAN::Frontend->myprint(qq{$version_zeroes installed module$s_has }.
                                     qq{a version number of 0\n});
            if ($CPAN::Config->{show_zero_versions}) {
                local $" = "\t";
                $CPAN::Frontend->myprint(qq{  they are\n\t@version_zeroes\n});
                $CPAN::Frontend->myprint(qq{(use 'o conf show_zero_versions 0' }.
                                         qq{to hide them)\n});
            } else {
                $CPAN::Frontend->myprint(qq{(use 'o conf show_zero_versions 1' }.
                                         qq{to show them)\n});
            }
        }
        if ($version_undefs) {
            my $s_has = $version_undefs > 1 ? "s have" : " has";
            $CPAN::Frontend->myprint(qq{$version_undefs installed module$s_has no }.
                                     qq{parsable version number\n});
            if ($CPAN::Config->{show_unparsable_versions}) {
                local $" = "\t";
                $CPAN::Frontend->myprint(qq{  they are\n\t@version_undefs\n});
                $CPAN::Frontend->myprint(qq{(use 'o conf show_unparsable_versions 0' }.
                                         qq{to hide them)\n});
            } else {
                $CPAN::Frontend->myprint(qq{(use 'o conf show_unparsable_versions 1' }.
                                         qq{to show them)\n});
            }
        }
    }
    @result;
}

#-> sub CPAN::Shell::r ;
sub r {
    shift->_u_r_common("r",@_);
}

#-> sub CPAN::Shell::u ;
sub u {
    shift->_u_r_common("u",@_);
}

#-> sub CPAN::Shell::failed ;
sub failed {
    my($self,$only_id,$silent) = @_;
    my @failed = $self->find_failed($only_id);
    my $scope;
    if ($only_id) {
        $scope = "this command";
    } elsif ($CPAN::Index::HAVE_REANIMATED) {
        $scope = "this or a previous session";
        # it might be nice to have a section for previous session and
        # a second for this
    } else {
        $scope = "this session";
    }
    if (@failed) {
        my $print;
        my $debug = 0;
        if ($debug) {
            $print = join "",
                map { sprintf "%5d %-45s: %s %s\n", @$_ }
                    sort { $a->[0] <=> $b->[0] } @failed;
        } else {
            $print = join "",
                map { sprintf " %-45s: %s %s\n", @$_[1..3] }
                    sort {
                        $a->[0] <=> $b->[0]
                            ||
                                $a->[4] <=> $b->[4]
                       } @failed;
        }
        $CPAN::Frontend->myprint("Failed during $scope:\n$print");
    } elsif (!$only_id || !$silent) {
        $CPAN::Frontend->myprint("Nothing failed in $scope\n");
    }
}

sub find_failed {
    my($self,$only_id) = @_;
    my @failed;
  DIST: for my $d (sort { $a->id cmp $b->id } $CPAN::META->all_objects("CPAN::Distribution")) {
        my $failed = "";
      NAY: for my $nosayer ( # order matters!
                            "unwrapped",
                            "writemakefile",
                            "signature_verify",
                            "make",
                            "make_test",
                            "install",
                            "make_clean",
                           ) {
            next unless exists $d->{$nosayer};
            next unless defined $d->{$nosayer};
            next unless (
                         UNIVERSAL::can($d->{$nosayer},"failed") ?
                         $d->{$nosayer}->failed :
                         $d->{$nosayer} =~ /^NO/
                        );
            next NAY if $only_id && $only_id != (
                                                 UNIVERSAL::can($d->{$nosayer},"commandid")
                                                 ?
                                                 $d->{$nosayer}->commandid
                                                 :
                                                 $CPAN::CurrentCommandId
                                                );
            $failed = $nosayer;
            last;
        }
        next DIST unless $failed;
        my $id = $d->id;
        $id =~ s|^./../||;
        ### XXX need to flag optional modules as '(optional)' if they are
        # from recommends/suggests -- i.e. *show* failure, but make it clear
        # it was failure of optional module -- xdg, 2012-04-01
        $id = "(optional) $id" if ! $d->{mandatory};
        #$print .= sprintf(
        #                  "  %-45s: %s %s\n",
        push @failed,
            (
             UNIVERSAL::can($d->{$failed},"failed") ?
             [
              $d->{$failed}->commandid,
              $id,
              $failed,
              $d->{$failed}->text,
              $d->{$failed}{TIME}||0,
              !! $d->{mandatory},
             ] :
             [
              1,
              $id,
              $failed,
              $d->{$failed},
              0,
              !! $d->{mandatory},
             ]
            );
    }
    return @failed;
}

sub mandatory_dist_failed {
    my ($self) = @_;
    return grep { $_->[5] } $self->find_failed($CPAN::CurrentCommandID);
}

# XXX intentionally undocumented because completely bogus, unportable,
# useless, etc.

#-> sub CPAN::Shell::status ;
sub status {
    my($self) = @_;
    require Devel::Size;
    my $ps = FileHandle->new;
    open $ps, "/proc/$$/status";
    my $vm = 0;
    while (<$ps>) {
        next unless /VmSize:\s+(\d+)/;
        $vm = $1;
        last;
    }
    $CPAN::Frontend->mywarn(sprintf(
                                    "%-27s %6d\n%-27s %6d\n",
                                    "vm",
                                    $vm,
                                    "CPAN::META",
                                    Devel::Size::total_size($CPAN::META)/1024,
                                   ));
    for my $k (sort keys %$CPAN::META) {
        next unless substr($k,0,4) eq "read";
        warn sprintf " %-26s %6d\n", $k, Devel::Size::total_size($CPAN::META->{$k})/1024;
        for my $k2 (sort keys %{$CPAN::META->{$k}}) {
            warn sprintf "  %-25s %6d (keys: %6d)\n",
                $k2,
                    Devel::Size::total_size($CPAN::META->{$k}{$k2})/1024,
                          scalar keys %{$CPAN::META->{$k}{$k2}};
        }
    }
}

# compare with install_tested
#-> sub CPAN::Shell::is_tested
sub is_tested {
    my($self) = @_;
    CPAN::Index->reload;
    for my $b (reverse $CPAN::META->_list_sorted_descending_is_tested) {
        my $time;
        if ($CPAN::META->{is_tested}{$b}) {
            $time = scalar(localtime $CPAN::META->{is_tested}{$b});
        } else {
            $time = scalar localtime;
            $time =~ s/\S/?/g;
        }
        $CPAN::Frontend->myprint(sprintf "%s %s\n", $time, $b);
    }
}

#-> sub CPAN::Shell::autobundle ;
sub autobundle {
    my($self) = shift;
    CPAN::HandleConfig->load unless $CPAN::Config_loaded++;
    my(@bundle) = $self->_u_r_common("a",@_);
    my($todir) = File::Spec->catdir($CPAN::Config->{'cpan_home'},"Bundle");
    File::Path::mkpath($todir);
    unless (-d $todir) {
        $CPAN::Frontend->myprint("Couldn't mkdir $todir for some reason\n");
        return;
    }
    my($y,$m,$d) =  (localtime)[5,4,3];
    $y+=1900;
    $m++;
    my($c) = 0;
    my($me) = sprintf "Snapshot_%04d_%02d_%02d_%02d", $y, $m, $d, $c;
    my($to) = File::Spec->catfile($todir,"$me.pm");
    while (-f $to) {
        $me = sprintf "Snapshot_%04d_%02d_%02d_%02d", $y, $m, $d, ++$c;
        $to = File::Spec->catfile($todir,"$me.pm");
    }
    my($fh) = FileHandle->new(">$to") or Carp::croak "Can't open >$to: $!";
    $fh->print(
               "package Bundle::$me;\n\n",
               "\$","VERSION = '0.01';\n\n", # hide from perl-reversion
               "1;\n\n",
               "__END__\n\n",
               "=head1 NAME\n\n",
               "Bundle::$me - Snapshot of installation on ",
               $Config::Config{'myhostname'},
               " on ",
               scalar(localtime),
               "\n\n=head1 SYNOPSIS\n\n",
               "perl -MCPAN -e 'install Bundle::$me'\n\n",
               "=head1 CONTENTS\n\n",
               join("\n", @bundle),
               "\n\n=head1 CONFIGURATION\n\n",
               Config->myconfig,
               "\n\n=head1 AUTHOR\n\n",
               "This Bundle has been generated automatically ",
               "by the autobundle routine in CPAN.pm.\n",
              );
    $fh->close;
    $CPAN::Frontend->myprint("\nWrote bundle file
    $to\n\n");
    return $to;
}

#-> sub CPAN::Shell::expandany ;
sub expandany {
    my($self,$s) = @_;
    CPAN->debug("s[$s]") if $CPAN::DEBUG;
    my $module_as_path = "";
    if ($s =~ m|(?:\w+/)*\w+\.pm$|) { # same regexp in sub m
        $module_as_path = $s;
        $module_as_path =~ s/.pm$//;
        $module_as_path =~ s|/|::|g;
    }
    if ($module_as_path) {
        if ($module_as_path =~ m|^Bundle::|) {
            $self->local_bundles;
            return $self->expand('Bundle',$module_as_path);
        } else {
            return $self->expand('Module',$module_as_path)
                if $CPAN::META->exists('CPAN::Module',$module_as_path);
        }
    } elsif ($s =~ m|/| or substr($s,-1,1) eq ".") { # looks like a file or a directory
        $s = CPAN::Distribution->normalize($s);
        return $CPAN::META->instance('CPAN::Distribution',$s);
        # Distributions spring into existence, not expand
    } elsif ($s =~ m|^Bundle::|) {
        $self->local_bundles; # scanning so late for bundles seems
                              # both attractive and crumpy: always
                              # current state but easy to forget
                              # somewhere
        return $self->expand('Bundle',$s);
    } else {
        return $self->expand('Module',$s)
            if $CPAN::META->exists('CPAN::Module',$s);
    }
    return;
}

#-> sub CPAN::Shell::expand ;
sub expand {
    my $self = shift;
    my($type,@args) = @_;
    CPAN->debug("type[$type]args[@args]") if $CPAN::DEBUG;
    my $class = "CPAN::$type";
    my $methods = ['id'];
    for my $meth (qw(name)) {
        next unless $class->can($meth);
        push @$methods, $meth;
    }
    $self->expand_by_method($class,$methods,@args);
}

#-> sub CPAN::Shell::expand_by_method ;
sub expand_by_method {
    my $self = shift;
    my($class,$methods,@args) = @_;
    my($arg,@m);
    for $arg (@args) {
        my($regex,$command);
        if ($arg =~ m|^/(.*)/$|) {
            $regex = $1;
# FIXME:  there seem to be some ='s in the author data, which trigger
#         a failure here.  This needs to be contemplated.
#            } elsif ($arg =~ m/=/) {
#                $command = 1;
        }
        my $obj;
        CPAN->debug(sprintf "class[%s]regex[%s]command[%s]",
                    $class,
                    defined $regex ? $regex : "UNDEFINED",
                    defined $command ? $command : "UNDEFINED",
                   ) if $CPAN::DEBUG;
        if (defined $regex) {
            if (CPAN::_sqlite_running()) {
                CPAN::Index->reload;
                $CPAN::SQLite->search($class, $regex);
            }
            for $obj (
                      $CPAN::META->all_objects($class)
                     ) {
                unless ($obj && UNIVERSAL::can($obj,"id") && $obj->id) {
                    # BUG, we got an empty object somewhere
                    require Data::Dumper;
                    CPAN->debug(sprintf(
                                        "Bug in CPAN: Empty id on obj[%s][%s]",
                                        $obj,
                                        Data::Dumper::Dumper($obj)
                                       )) if $CPAN::DEBUG;
                    next;
                }
                for my $method (@$methods) {
                    my $match = eval {$obj->$method() =~ /$regex/i};
                    if ($@) {
                        my($err) = $@ =~ /^(.+) at .+? line \d+\.$/;
                        $err ||= $@; # if we were too restrictive above
                        $CPAN::Frontend->mydie("$err\n");
                    } elsif ($match) {
                        push @m, $obj;
                        last;
                    }
                }
            }
        } elsif ($command) {
            die "equal sign in command disabled (immature interface), ".
                "you can set
 ! \$CPAN::Shell::ADVANCED_QUERY=1
to enable it. But please note, this is HIGHLY EXPERIMENTAL code
that may go away anytime.\n"
                    unless $ADVANCED_QUERY;
            my($method,$criterion) = $arg =~ /(.+?)=(.+)/;
            my($matchcrit) = $criterion =~ m/^~(.+)/;
            for my $self (
                          sort
                          {$a->id cmp $b->id}
                          $CPAN::META->all_objects($class)
                         ) {
                my $lhs = $self->$method() or next; # () for 5.00503
                if ($matchcrit) {
                    push @m, $self if $lhs =~ m/$matchcrit/;
                } else {
                    push @m, $self if $lhs eq $criterion;
                }
            }
        } else {
            my($xarg) = $arg;
            if ( $class eq 'CPAN::Bundle' ) {
                $xarg =~ s/^(Bundle::)?(.*)/Bundle::$2/;
            } elsif ($class eq "CPAN::Distribution") {
                $xarg = CPAN::Distribution->normalize($arg);
            } else {
                $xarg =~ s/:+/::/g;
            }
            if ($CPAN::META->exists($class,$xarg)) {
                $obj = $CPAN::META->instance($class,$xarg);
            } elsif ($CPAN::META->exists($class,$arg)) {
                $obj = $CPAN::META->instance($class,$arg);
            } else {
                next;
            }
            push @m, $obj;
        }
    }
    @m = sort {$a->id cmp $b->id} @m;
    if ( $CPAN::DEBUG ) {
        my $wantarray = wantarray;
        my $join_m = join ",", map {$_->id} @m;
        # $self->debug("wantarray[$wantarray]join_m[$join_m]");
        my $count = scalar @m;
        $self->debug("class[$class]wantarray[$wantarray]count m[$count]");
    }
    return wantarray ? @m : $m[0];
}

#-> sub CPAN::Shell::format_result ;
sub format_result {
    my($self) = shift;
    my($type,@args) = @_;
    @args = '/./' unless @args;
    my(@result) = $self->expand($type,@args);
    my $result = @result == 1 ?
        $result[0]->as_string :
            @result == 0 ?
                "No objects of type $type found for argument @args\n" :
                    join("",
                         (map {$_->as_glimpse} @result),
                         scalar @result, " items found\n",
                        );
    $result;
}

#-> sub CPAN::Shell::report_fh ;
{
    my $installation_report_fh;
    my $previously_noticed = 0;

    sub report_fh {
        return $installation_report_fh if $installation_report_fh;
        if ($CPAN::META->has_usable("File::Temp")) {
            $installation_report_fh
                = File::Temp->new(
                                  dir      => File::Spec->tmpdir,
                                  template => 'cpan_install_XXXX',
                                  suffix   => '.txt',
                                  unlink   => 0,
                                 );
        }
        unless ( $installation_report_fh ) {
            warn("Couldn't open installation report file; " .
                 "no report file will be generated."
                ) unless $previously_noticed++;
        }
    }
}


# The only reason for this method is currently to have a reliable
# debugging utility that reveals which output is going through which
# channel. No, I don't like the colors ;-)

# to turn colordebugging on, write
# cpan> o conf colorize_output 1

#-> sub CPAN::Shell::colorize_output ;
{
    my $print_ornamented_have_warned = 0;
    sub colorize_output {
        my $colorize_output = $CPAN::Config->{colorize_output};
        if ($colorize_output && $^O eq 'MSWin32' && !$CPAN::META->has_inst("Win32::Console::ANSI")) {
            unless ($print_ornamented_have_warned++) {
                # no myprint/mywarn within myprint/mywarn!
                warn "Colorize_output is set to true but Win32::Console::ANSI is not
installed. To activate colorized output, please install Win32::Console::ANSI.\n\n";
            }
            $colorize_output = 0;
        }
        if ($colorize_output && !$CPAN::META->has_inst("Term::ANSIColor")) {
            unless ($print_ornamented_have_warned++) {
                # no myprint/mywarn within myprint/mywarn!
                warn "Colorize_output is set to true but Term::ANSIColor is not
installed. To activate colorized output, please install Term::ANSIColor.\n\n";
            }
            $colorize_output = 0;
        }
        return $colorize_output;
    }
}


#-> sub CPAN::Shell::print_ornamented ;
sub print_ornamented {
    my($self,$what,$ornament) = @_;
    return unless defined $what;

    local $| = 1; # Flush immediately
    if ( $CPAN::Be_Silent ) {
        # WARNING: variable Be_Silent is poisoned and must be eliminated.
        print {report_fh()} $what;
        return;
    }
    my $swhat = "$what"; # stringify if it is an object
    if ($CPAN::Config->{term_is_latin}) {
        # note: deprecated, need to switch to $LANG and $LC_*
        # courtesy jhi:
        $swhat
            =~ s{([\xC0-\xDF])([\x80-\xBF])}{chr(ord($1)<<6&0xC0|ord($2)&0x3F)}eg; #};
    }
    if ($self->colorize_output) {
        if ( $CPAN::DEBUG && $swhat =~ /^Debug\(/ ) {
            # if you want to have this configurable, please file a bug report
            $ornament = $CPAN::Config->{colorize_debug} || "black on_cyan";
        }
        my $color_on = eval { Term::ANSIColor::color($ornament) } || "";
        if ($@) {
            print "Term::ANSIColor rejects color[$ornament]: $@\n
Please choose a different color (Hint: try 'o conf init /color/')\n";
        }
        # GGOLDBACH/Test-GreaterVersion-0.008 broke without this
        # $trailer construct. We want the newline be the last thing if
        # there is a newline at the end ensuring that the next line is
        # empty for other players
        my $trailer = "";
        $trailer = $1 if $swhat =~ s/([\r\n]+)\z//;
        print $color_on,
            $swhat,
                Term::ANSIColor::color("reset"),
                      $trailer;
    } else {
        print $swhat;
    }
}

#-> sub CPAN::Shell::myprint ;

# where is myprint/mywarn/Frontend/etc. documented? Where to use what?
# I think, we send everything to STDOUT and use print for normal/good
# news and warn for news that need more attention. Yes, this is our
# working contract for now.
sub myprint {
    my($self,$what) = @_;
    $self->print_ornamented($what,
                            $CPAN::Config->{colorize_print}||'bold blue on_white',
                           );
}

my %already_printed;
#-> sub CPAN::Shell::mywarnonce ;
sub myprintonce {
    my($self,$what) = @_;
    $self->myprint($what) unless $already_printed{$what}++;
}

sub optprint {
    my($self,$category,$what) = @_;
    my $vname = $category . "_verbosity";
    CPAN::HandleConfig->load unless $CPAN::Config_loaded++;
    if (!$CPAN::Config->{$vname}
        || $CPAN::Config->{$vname} =~ /^v/
       ) {
        $CPAN::Frontend->myprint($what);
    }
}

#-> sub CPAN::Shell::myexit ;
sub myexit {
    my($self,$what) = @_;
    $self->myprint($what);
    exit;
}

#-> sub CPAN::Shell::mywarn ;
sub mywarn {
    my($self,$what) = @_;
    $self->print_ornamented($what, $CPAN::Config->{colorize_warn}||'bold red on_white');
}

my %already_warned;
#-> sub CPAN::Shell::mywarnonce ;
sub mywarnonce {
    my($self,$what) = @_;
    $self->mywarn($what) unless $already_warned{$what}++;
}

# only to be used for shell commands
#-> sub CPAN::Shell::mydie ;
sub mydie {
    my($self,$what) = @_;
    $self->mywarn($what);

    # If it is the shell, we want the following die to be silent,
    # but if it is not the shell, we would need a 'die $what'. We need
    # to take care that only shell commands use mydie. Is this
    # possible?

    die "\n";
}

# sub CPAN::Shell::colorable_makemaker_prompt ;
sub colorable_makemaker_prompt {
    my($foo,$bar,$ornament) = @_;
    $ornament ||= "colorize_print";
    if (CPAN::Shell->colorize_output) {
        my $ornament = $CPAN::Config->{$ornament}||'bold blue on_white';
        my $color_on = eval { Term::ANSIColor::color($ornament); } || "";
        print $color_on;
    }
    my $ans = ExtUtils::MakeMaker::prompt($foo,$bar);
    if (CPAN::Shell->colorize_output) {
        print Term::ANSIColor::color('reset');
    }
    return $ans;
}

# use this only for unrecoverable errors!
#-> sub CPAN::Shell::unrecoverable_error ;
sub unrecoverable_error {
    my($self,$what) = @_;
    my @lines = split /\n/, $what;
    my $longest = 0;
    for my $l (@lines) {
        $longest = length $l if length $l > $longest;
    }
    $longest = 62 if $longest > 62;
    for my $l (@lines) {
        if ($l =~ /^\s*$/) {
            $l = "\n";
            next;
        }
        $l = "==> $l";
        if (length $l < 66) {
            $l = pack "A66 A*", $l, "<==";
        }
        $l .= "\n";
    }
    unshift @lines, "\n";
    $self->mydie(join "", @lines);
}

#-> sub CPAN::Shell::mysleep ;
sub mysleep {
    return if $ENV{AUTOMATED_TESTING} || ! -t STDOUT;
    my($self, $sleep) = @_;
    if (CPAN->has_inst("Time::HiRes")) {
        Time::HiRes::sleep($sleep);
    } else {
        sleep($sleep < 1 ? 1 : int($sleep + 0.5));
    }
}

#-> sub CPAN::Shell::setup_output ;
sub setup_output {
    return if -t STDOUT;
    my $odef = select STDERR;
    $| = 1;
    select STDOUT;
    $| = 1;
    select $odef;
}

#-> sub CPAN::Shell::rematein ;
# RE-adme||MA-ke||TE-st||IN-stall : nearly everything runs through here
sub rematein {
    my $self = shift;
    # this variable was global and disturbed programmers, so localize:
    local $CPAN::Distrostatus::something_has_failed_at;
    my($meth,@some) = @_;
    my @pragma;
    while($meth =~ /^(ff?orce|notest)$/) {
        push @pragma, $meth;
        $meth = shift @some or
            $CPAN::Frontend->mydie("Pragma $pragma[-1] used without method: ".
                                   "cannot continue");
    }
    setup_output();
    CPAN->debug("pragma[@pragma]meth[$meth]some[@some]") if $CPAN::DEBUG;

    # Here is the place to set "test_count" on all involved parties to
    # 0. We then can pass this counter on to the involved
    # distributions and those can refuse to test if test_count > X. In
    # the first stab at it we could use a 1 for "X".

    # But when do I reset the distributions to start with 0 again?
    # Jost suggested to have a random or cycling interaction ID that
    # we pass through. But the ID is something that is just left lying
    # around in addition to the counter, so I'd prefer to set the
    # counter to 0 now, and repeat at the end of the loop. But what
    # about dependencies? They appear later and are not reset, they
    # enter the queue but not its copy. How do they get a sensible
    # test_count?

    # With configure_requires, "get" is vulnerable in recursion.

    my $needs_recursion_protection = "get|make|test|install";

    # construct the queue
    my($s,@s,@qcopy);
  STHING: foreach $s (@some) {
        my $obj;
        if (ref $s) {
            CPAN->debug("s is an object[$s]") if $CPAN::DEBUG;
            $obj = $s;
        } elsif ($s =~ m|[\$\@\%]|) { # looks like a perl variable
        } elsif ($s =~ m|^/|) { # looks like a regexp
            if (substr($s,-1,1) eq ".") {
                $obj = CPAN::Shell->expandany($s);
            } else {
                my @obj;
            CLASS: for my $class (qw(Distribution Bundle Module)) {
                    if (@obj = $self->expand($class,$s)) {
                        last CLASS;
                    }
                }
                if (@obj) {
                    if (1==@obj) {
                        $obj = $obj[0];
                    } else {
                        $CPAN::Frontend->mywarn("Sorry, $meth with a regular expression is ".
                                                "only supported when unambiguous.\nRejecting argument '$s'\n");
                        $CPAN::Frontend->mysleep(2);
                        next STHING;
                    }
                }
            }
        } elsif ($meth eq "ls") {
            $self->globls($s,\@pragma);
            next STHING;
        } else {
            CPAN->debug("calling expandany [$s]") if $CPAN::DEBUG;
            $obj = CPAN::Shell->expandany($s);
        }
        if (0) {
        } elsif (ref $obj) {
            if ($meth =~ /^($needs_recursion_protection)$/) {
                # it would be silly to check for recursion for look or dump
                # (we are in CPAN::Shell::rematein)
                CPAN->debug("Testing against recursion") if $CPAN::DEBUG;
                eval {  $obj->color_cmd_tmps(0,1); };
                if ($@) {
                    if (ref $@
                        and $@->isa("CPAN::Exception::RecursiveDependency")) {
                        $CPAN::Frontend->mywarn($@);
                    } else {
                        if (0) {
                            require Carp;
                            Carp::confess(sprintf "DEBUG: \$\@[%s]ref[%s]", $@, ref $@);
                        }
                        die;
                    }
                }
            }
            CPAN::Queue->queue_item(qmod => $obj->id, reqtype => "c", optional => '');
            push @qcopy, $obj;
        } elsif ($CPAN::META->exists('CPAN::Author',uc($s))) {
            $obj = $CPAN::META->instance('CPAN::Author',uc($s));
            if ($meth =~ /^(dump|ls|reports)$/) {
                $obj->$meth();
            } else {
                $CPAN::Frontend->mywarn(
                                        join "",
                                        "Don't be silly, you can't $meth ",
                                        $obj->fullname,
                                        " ;-)\n"
                                       );
                $CPAN::Frontend->mysleep(2);
            }
        } elsif ($s =~ m|[\$\@\%]| && $meth eq "dump") {
            CPAN::InfoObj->dump($s);
        } else {
            $CPAN::Frontend
                ->mywarn(qq{Warning: Cannot $meth $s, }.
                         qq{don't know what it is.
Try the command

    i /$s/

to find objects with matching identifiers.
});
            $CPAN::Frontend->mysleep(2);
        }
    }

    # queuerunner (please be warned: when I started to change the
    # queue to hold objects instead of names, I made one or two
    # mistakes and never found which. I reverted back instead)
  QITEM: while (my $q = CPAN::Queue->first) {
        my $obj;
        my $s = $q->as_string;
        my $reqtype = $q->reqtype || "";
        my $optional = $q->optional || "";
        $obj = CPAN::Shell->expandany($s);
        unless ($obj) {
            # don't know how this can happen, maybe we should panic,
            # but maybe we get a solution from the first user who hits
            # this unfortunate exception?
            $CPAN::Frontend->mywarn("Warning: Could not expand string '$s' ".
                                    "to an object. Skipping.\n");
            $CPAN::Frontend->mysleep(5);
            CPAN::Queue->delete_first($s);
            next QITEM;
        }
        $obj->{reqtype} ||= "";
        my $type = ref $obj;
        if ( $type eq 'CPAN::Distribution' || $type eq 'CPAN::Bundle' ) {
            $obj->{mandatory} ||= ! $optional; # once mandatory, always mandatory
        }
        elsif ( $type eq 'CPAN::Module' ) {
            $obj->{mandatory} ||= ! $optional; # once mandatory, always mandatory
            if (my $d = $obj->distribution) {
                $d->{mandatory} ||= ! $optional; # once mandatory, always mandatory
            } elsif ($optional) {
                # the queue object does not know who was recommending/suggesting us:(
                # So we only vaguely write "optional".
                $CPAN::Frontend->mywarn("Warning: optional module '$s' ".
                                        "not known. Skipping.\n");
                CPAN::Queue->delete_first($s);
                next QITEM;
            }
        }
        {
            # force debugging because CPAN::SQLite somehow delivers us
            # an empty object;

            # local $CPAN::DEBUG = 1024; # Shell; probably fixed now

            CPAN->debug("s[$s]obj-reqtype[$obj->{reqtype}]".
                        "q-reqtype[$reqtype]") if $CPAN::DEBUG;
        }
        if ($obj->{reqtype}) {
            if ($obj->{reqtype} eq "b" && $reqtype =~ /^[rc]$/) {
                $obj->{reqtype} = $reqtype;
                if (
                    exists $obj->{install}
                    &&
                    (
                     UNIVERSAL::can($obj->{install},"failed") ?
                     $obj->{install}->failed :
                     $obj->{install} =~ /^NO/
                    )
                   ) {
                    delete $obj->{install};
                    $CPAN::Frontend->mywarn
                        ("Promoting $obj->{ID} from 'build_requires' to 'requires'");
                }
            }
        } else {
            $obj->{reqtype} = $reqtype;
        }

        for my $pragma (@pragma) {
            if ($pragma
                &&
                $obj->can($pragma)) {
                $obj->$pragma($meth);
            }
        }
        if (UNIVERSAL::can($obj, 'called_for')) {
            $obj->called_for($s) unless $obj->called_for;
        }
        CPAN->debug(qq{pragma[@pragma]meth[$meth]}.
                    qq{ID[$obj->{ID}]}) if $CPAN::DEBUG;

        push @qcopy, $obj;
        if ($meth =~ /^(report)$/) { # they came here with a pragma?
            $self->$meth($obj);
        } elsif (! UNIVERSAL::can($obj,$meth)) {
            # Must never happen
            my $serialized = "";
            if (0) {
            } elsif ($CPAN::META->has_inst("YAML::Syck")) {
                $serialized = YAML::Syck::Dump($obj);
            } elsif ($CPAN::META->has_inst("YAML")) {
                $serialized = YAML::Dump($obj);
            } elsif ($CPAN::META->has_inst("Data::Dumper")) {
                $serialized = Data::Dumper::Dumper($obj);
            } else {
                require overload;
                $serialized = overload::StrVal($obj);
            }
            CPAN->debug("Going to panic. meth[$meth]s[$s]") if $CPAN::DEBUG;
            $CPAN::Frontend->mydie("Panic: obj[$serialized] cannot meth[$meth]");
        } else {
            my $upgraded_meth = $meth;
            if ( $meth eq "make" and $obj->{reqtype} eq "b" ) {
                # rt 86915
                $upgraded_meth = "test";
            }
            if ($obj->$upgraded_meth()) {
                CPAN::Queue->delete($s);
                CPAN->debug("Succeeded and deleted from queue. pragma[@pragma]meth[$meth][s][$s]") if $CPAN::DEBUG;
            } else {
                CPAN->debug("Failed. pragma[@pragma]meth[$meth]s[$s]") if $CPAN::DEBUG;
            }
        }

        $obj->undelay;
        for my $pragma (@pragma) {
            my $unpragma = "un$pragma";
            if ($obj->can($unpragma)) {
                $obj->$unpragma();
            }
        }
        # if any failures occurred and the current object is mandatory, we
        # still don't know if *it* failed or if it was another (optional)
        # module, so we have to check that explicitly (and expensively)
        if (    $CPAN::Config->{halt_on_failure}
            && $obj->{mandatory}
            && CPAN::Distrostatus::something_has_just_failed()
            && $self->mandatory_dist_failed()
        ) {
            $CPAN::Frontend->mywarn("Stopping: '$meth' failed for '$s'.\n");
            CPAN::Queue->nullify_queue;
            last QITEM;
        }
        CPAN::Queue->delete_first($s);
    }
    if ($meth =~ /^($needs_recursion_protection)$/) {
        for my $obj (@qcopy) {
            $obj->color_cmd_tmps(0,0);
        }
    }
}

#-> sub CPAN::Shell::recent ;
sub recent {
  my($self) = @_;
  if ($CPAN::META->has_inst("XML::LibXML")) {
      my $url = $CPAN::Defaultrecent;
      $CPAN::Frontend->myprint("Fetching '$url'\n");
      unless ($CPAN::META->has_usable("LWP")) {
          $CPAN::Frontend->mydie("LWP not installed; cannot continue");
      }
      CPAN::LWP::UserAgent->config;
      my $Ua;
      eval { $Ua = CPAN::LWP::UserAgent->new; };
      if ($@) {
          $CPAN::Frontend->mydie("CPAN::LWP::UserAgent->new dies with $@\n");
      }
      my $resp = $Ua->get($url);
      unless ($resp->is_success) {
          $CPAN::Frontend->mydie(sprintf "Could not download '%s': %s\n", $url, $resp->code);
      }
      $CPAN::Frontend->myprint("DONE\n\n");
      my $xml = XML::LibXML->new->parse_string($resp->content);
      if (0) {
          my $s = $xml->serialize(2);
          $s =~ s/\n\s*\n/\n/g;
          $CPAN::Frontend->myprint($s);
          return;
      }
      my @distros;
      if ($url =~ /winnipeg/) {
          my $pubdate = $xml->findvalue("/rss/channel/pubDate");
          $CPAN::Frontend->myprint("    pubDate: $pubdate\n\n");
          for my $eitem ($xml->findnodes("/rss/channel/item")) {
              my $distro = $eitem->findvalue("enclosure/\@url");
              $distro =~ s|.*?/authors/id/./../||;
              my $size   = $eitem->findvalue("enclosure/\@length");
              my $desc   = $eitem->findvalue("description");
              $desc =~ s/.+? - //;
              $CPAN::Frontend->myprint("$distro [$size b]\n    $desc\n");
              push @distros, $distro;
          }
      } elsif ($url =~ /search.*uploads.rdf/) {
          # xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
          # xmlns="http://purl.org/rss/1.0/"
          # xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/"
          # xmlns:dc="http://purl.org/dc/elements/1.1/"
          # xmlns:syn="http://purl.org/rss/1.0/modules/syndication/"
          # xmlns:admin="http://webns.net/mvcb/"


          my $dc_date = $xml->findvalue("//*[local-name(.) = 'RDF']/*[local-name(.) = 'channel']/*[local-name(.) = 'date']");
          $CPAN::Frontend->myprint("    dc:date: $dc_date\n\n");
          my $finish_eitem = 0;
          local $SIG{INT} = sub { $finish_eitem = 1 };
        EITEM: for my $eitem ($xml->findnodes("//*[local-name(.) = 'RDF']/*[local-name(.) = 'item']")) {
              my $distro = $eitem->findvalue("\@rdf:about");
              $distro =~ s|.*~||; # remove up to the tilde before the name
              $distro =~ s|/$||; # remove trailing slash
              $distro =~ s|([^/]+)|\U$1\E|; # upcase the name
              my $author = uc $1 or die "distro[$distro] without author, cannot continue";
              my $desc   = $eitem->findvalue("*[local-name(.) = 'description']");
              my $i = 0;
            SUBDIRTEST: while () {
                  last SUBDIRTEST if ++$i >= 6; # half a dozen must do!
                  if (my @ret = $self->globls("$distro*")) {
                      @ret = grep {$_->[2] !~ /meta/} @ret;
                      @ret = grep {length $_->[2]} @ret;
                      if (@ret) {
                          $distro = "$author/$ret[0][2]";
                          last SUBDIRTEST;
                      }
                  }
                  $distro =~ s|/|/*/|; # allow it to reside in a subdirectory
              }

              next EITEM if $distro =~ m|\*|; # did not find the thing
              $CPAN::Frontend->myprint("____$desc\n");
              push @distros, $distro;
              last EITEM if $finish_eitem;
          }
      }
      return \@distros;
  } else {
      # deprecated old version
      $CPAN::Frontend->mydie("no XML::LibXML installed, cannot continue\n");
  }
}

#-> sub CPAN::Shell::smoke ;
sub smoke {
    my($self) = @_;
    my $distros = $self->recent;
  DISTRO: for my $distro (@$distros) {
        next if $distro =~ m|/Bundle-|; # XXX crude heuristic to skip bundles
        $CPAN::Frontend->myprint(sprintf "Downloading and testing '$distro'\n");
        {
            my $skip = 0;
            local $SIG{INT} = sub { $skip = 1 };
            for (0..9) {
                $CPAN::Frontend->myprint(sprintf "\r%2d (Hit ^C to skip)", 10-$_);
                sleep 1;
                if ($skip) {
                    $CPAN::Frontend->myprint(" skipped\n");
                    next DISTRO;
                }
            }
        }
        $CPAN::Frontend->myprint("\r  \n"); # leave the dirty line with a newline
        $self->test($distro);
    }
}

{
    # set up the dispatching methods
    no strict "refs";
    for my $command (qw(
                        clean
                        cvs_import
                        dump
                        force
                        fforce
                        get
                        install
                        look
                        ls
                        make
                        notest
                        perldoc
                        readme
                        reports
                        test
                       )) {
        *$command = sub { shift->rematein($command, @_); };
    }
}

1;
PK7N%[naX677perl5/CPAN/Prompt.pmnu��6�$# -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*-
# vim: ts=4 sts=4 sw=4:
package CPAN::Prompt;
use overload '""' => "as_string";
use vars qw($prompt);
use vars qw(
            $VERSION
);
$VERSION = "5.5";


$prompt = "cpan> ";
$CPAN::CurrentCommandId ||= 0;
sub new {
    bless {}, shift;
}
sub as_string {
    my $word = "cpan";
    unless ($CPAN::META->{LOCK}) {
        $word = "nolock_cpan";
    }
    if ($CPAN::Config->{commandnumber_in_prompt}) {
        sprintf "$word\[%d]> ", $CPAN::CurrentCommandId;
    } else {
        "$word> ";
    }
}

1;
PK7N%[iۨD��perl5/CPAN/Distrostatus.pmnu��6�$# -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*-
# vim: ts=4 sts=4 sw=4:
package CPAN::Distrostatus;
use overload '""' => "as_string",
    fallback => 1;
use vars qw($something_has_failed_at);
use vars qw(
            $VERSION
);
$VERSION = "5.5";


sub new {
    my($class,$arg) = @_;
    my $failed = substr($arg,0,2) eq "NO";
    if ($failed) {
        $something_has_failed_at = $CPAN::CurrentCommandId;
    }
    bless {
           TEXT => $arg,
           FAILED => $failed,
           COMMANDID => $CPAN::CurrentCommandId,
           TIME => time,
          }, $class;
}
sub something_has_just_failed () {
    defined $something_has_failed_at &&
        $something_has_failed_at == $CPAN::CurrentCommandId;
}
sub commandid { shift->{COMMANDID} }
sub failed { shift->{FAILED} }
sub text {
    my($self,$set) = @_;
    if (defined $set) {
        $self->{TEXT} = $set;
    }
    $self->{TEXT};
}
sub as_string {
    my($self) = @_;
    $self->text;
}


1;
PK7N%[}l�++perl5/CPAN/API/HOWTO.podnu��6�$=head1 NAME

CPAN::API::HOWTO - a recipe book for programming with CPAN.pm

=head1 RECIPES

All of these recipes assume that you have put "use CPAN" at the top of
your program.

=head2 What distribution contains a particular module?

    my $distribution = CPAN::Shell->expand(
        "Module", "Data::UUID"
    )->distribution()->pretty_id();

This returns a string of the form "AUTHORID/TARBALL".  If you want the
full path and filename to this distribution on a CPAN mirror, then it is
C<.../authors/id/A/AU/AUTHORID/TARBALL>.

=head2 What modules does a particular distribution contain?

    CPAN::Index->reload();
    my @modules = CPAN::Shell->expand(
        "Distribution", "JHI/Graph-0.83.tar.gz"
    )->containsmods();

You may also refer to a distribution in the form A/AU/AUTHORID/TARBALL.

=head1 SEE ALSO

the main CPAN.pm documentation

=head1 LICENSE

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

See L<http://www.perl.com/perl/misc/Artistic.html>

=head1 AUTHOR

David Cantrell

=cut
PK7N%[hz.��perl5/CPAN/FTP.pmnu��6�$# -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*-
# vim: ts=4 sts=4 sw=4:
package CPAN::FTP;
use strict;

use Errno ();
use Fcntl qw(:flock);
use File::Basename qw(dirname);
use File::Path qw(mkpath);
use CPAN::FTP::netrc;
use vars qw($connect_to_internet_ok $Ua $Thesite $ThesiteURL $Themethod);

@CPAN::FTP::ISA = qw(CPAN::Debug);

use vars qw(
            $VERSION
);
$VERSION = "5.5016";

sub _plus_append_open {
    my($fh, $file) = @_;
    my $parent_dir = dirname $file;
    mkpath $parent_dir;
    my($cnt);
    until (open $fh, "+>>$file") {
        next if exists &Errno::EAGAIN && $! == &Errno::EAGAIN; # don't increment on EAGAIN
        $CPAN::Frontend->mydie("Could not open '$file' after 10000 tries: $!") if ++$cnt > 100000;
        sleep 0.0001;
        mkpath $parent_dir;
    }
}

#-> sub CPAN::FTP::ftp_statistics
# if they want to rewrite, they need to pass in a filehandle
sub _ftp_statistics {
    my($self,$fh) = @_;
    my $ftpstats_size = $CPAN::Config->{ftpstats_size};
    return if defined $ftpstats_size && $ftpstats_size <= 0;
    my $locktype = $fh ? LOCK_EX : LOCK_SH;
    # XXX On Windows flock() implements mandatory locking, so we can
    # XXX only use shared locking to still allow _yaml_loadfile() to
    # XXX read from the file using a different filehandle.
    $locktype = LOCK_SH if $^O eq "MSWin32";

    $fh ||= FileHandle->new;
    my $file = File::Spec->catfile($CPAN::Config->{cpan_home},"FTPstats.yml");
    _plus_append_open($fh,$file);
    my $sleep = 1;
    my $waitstart;
    while (!CPAN::_flock($fh, $locktype|LOCK_NB)) {
        $waitstart ||= localtime();
        if ($sleep>3) {
            my $now = localtime();
            $CPAN::Frontend->mywarn("$now: waiting for read lock on '$file' (since $waitstart)\n");
        }
        sleep($sleep); # this sleep must not be overridden;
                       # Frontend->mysleep with AUTOMATED_TESTING has
                       # provoked complete lock contention on my NFS
        if ($sleep <= 6) {
            $sleep+=0.5;
        } else {
            # retry to get a fresh handle. If it is NFS and the handle is stale, we will never get an flock
            _plus_append_open($fh, $file);
        }
    }
    my $stats = eval { CPAN->_yaml_loadfile($file, {loadblessed => 1}); };
    if ($@) {
        if (ref $@) {
            if (ref $@ eq "CPAN::Exception::yaml_not_installed") {
                chomp $@;
                $CPAN::Frontend->myprintonce("Warning (usually harmless): $@\n");
                return;
            } elsif (ref $@ eq "CPAN::Exception::yaml_process_error") {
                my $time = time;
                my $to = "$file.$time";
                $CPAN::Frontend->mywarn("Error reading '$file': $@
  Trying to stash it away as '$to' to prevent further interruptions.
  You may want to remove that file later.\n");
                # may fail because somebody else has moved it away in the meantime:
                rename $file, $to or $CPAN::Frontend->mywarn("Could not rename '$file' to '$to': $!\n");
                return;
            }
        } else {
            $CPAN::Frontend->mydie($@);
        }
    }
    CPAN::_flock($fh, LOCK_UN);
    return $stats->[0];
}

#-> sub CPAN::FTP::_mytime
sub _mytime () {
    if (CPAN->has_inst("Time::HiRes")) {
        return Time::HiRes::time();
    } else {
        return time;
    }
}

#-> sub CPAN::FTP::_new_stats
sub _new_stats {
    my($self,$file) = @_;
    my $ret = {
               file => $file,
               attempts => [],
               start => _mytime,
              };
    $ret;
}

#-> sub CPAN::FTP::_add_to_statistics
sub _add_to_statistics {
    my($self,$stats) = @_;
    my $yaml_module = CPAN::_yaml_module();
    $self->debug("yaml_module[$yaml_module]") if $CPAN::DEBUG;
    if ($CPAN::META->has_inst($yaml_module)) {
        $stats->{thesiteurl} = $ThesiteURL;
        $stats->{end} = CPAN::FTP::_mytime();
        my $fh = FileHandle->new;
        my $time = time;
        my $sdebug = 0;
        my @debug;
        @debug = $time if $sdebug;
        my $fullstats = $self->_ftp_statistics($fh);
        close $fh if $fh && defined(fileno($fh));
        $fullstats->{history} ||= [];
        push @debug, scalar @{$fullstats->{history}} if $sdebug;
        push @debug, time if $sdebug;
        push @{$fullstats->{history}}, $stats;
        # YAML.pm 0.62 is unacceptably slow with 999;
        # YAML::Syck 0.82 has no noticable performance problem with 999;
        my $ftpstats_size = $CPAN::Config->{ftpstats_size};
        $ftpstats_size = 99 unless defined $ftpstats_size;
        my $ftpstats_period = $CPAN::Config->{ftpstats_period} || 14;
        while (
               @{$fullstats->{history} || []}
               &&
               (
                @{$fullstats->{history}} > $ftpstats_size
                || $time - $fullstats->{history}[0]{start} > 86400*$ftpstats_period
               )
              ) {
            shift @{$fullstats->{history}}
        }
        push @debug, scalar @{$fullstats->{history}} if $sdebug;
        push @debug, time if $sdebug;
        push @debug, scalar localtime($fullstats->{history}[0]{start}) if $sdebug;
        # need no eval because if this fails, it is serious
        my $sfile = File::Spec->catfile($CPAN::Config->{cpan_home},"FTPstats.yml");
        CPAN->_yaml_dumpfile("$sfile.$$",$fullstats);
        if ( $sdebug ) {
            local $CPAN::DEBUG = 512; # FTP
            push @debug, time;
            CPAN->debug(sprintf("DEBUG history: before_read[%d]before[%d]at[%d]".
                                "after[%d]at[%d]oldest[%s]dumped backat[%d]",
                                @debug,
                               ));
        }
        # Win32 cannot rename a file to an existing filename
        unlink($sfile) if ($^O eq 'MSWin32' or $^O eq 'os2');
	_copy_stat($sfile, "$sfile.$$") if -e $sfile;
        rename "$sfile.$$", $sfile
            or $CPAN::Frontend->mywarn("Could not rename '$sfile.$$' to '$sfile': $!\nGiving up\n");
    }
}

# Copy some stat information (owner, group, mode and) from one file to
# another.
# This is a utility function which might be moved to a utility repository.
#-> sub CPAN::FTP::_copy_stat
sub _copy_stat {
    my($src, $dest) = @_;
    my @stat = stat($src);
    if (!@stat) {
	$CPAN::Frontend->mywarn("Can't stat '$src': $!\n");
	return;
    }

    eval {
	chmod $stat[2], $dest
	    or $CPAN::Frontend->mywarn("Can't chmod '$dest' to " . sprintf("0%o", $stat[2]) . ": $!\n");
    };
    warn $@ if $@;
    eval {
	chown $stat[4], $stat[5], $dest
	    or do {
		my $save_err = $!; # otherwise it's lost in the get... calls
		$CPAN::Frontend->mywarn("Can't chown '$dest' to " .
					(getpwuid($stat[4]))[0] . "/" .
					(getgrgid($stat[5]))[0] . ": $save_err\n"
				       );
	    };
    };
    warn $@ if $@;
}

# if file is CHECKSUMS, suggest the place where we got the file to be
# checked from, maybe only for young files?
#-> sub CPAN::FTP::_recommend_url_for
sub _recommend_url_for {
    my($self, $file, $urllist) = @_;
    if ($file =~ s|/CHECKSUMS(.gz)?$||) {
        my $fullstats = $self->_ftp_statistics();
        my $history = $fullstats->{history} || [];
        while (my $last = pop @$history) {
            last if $last->{end} - time > 3600; # only young results are interesting
            next unless $last->{file}; # dirname of nothing dies!
            next unless $file eq dirname($last->{file});
            return $last->{thesiteurl};
        }
    }
    if ($CPAN::Config->{randomize_urllist}
        &&
        rand(1) < $CPAN::Config->{randomize_urllist}
       ) {
        $urllist->[int rand scalar @$urllist];
    } else {
        return ();
    }
}

#-> sub CPAN::FTP::_get_urllist
sub _get_urllist {
    my($self, $with_defaults) = @_;
    $with_defaults ||= 0;
    CPAN->debug("with_defaults[$with_defaults]") if $CPAN::DEBUG;

    $CPAN::Config->{urllist} ||= [];
    unless (ref $CPAN::Config->{urllist} eq 'ARRAY') {
        $CPAN::Frontend->mywarn("Malformed urllist; ignoring.  Configuration file corrupt?\n");
        $CPAN::Config->{urllist} = [];
    }
    my @urllist = grep { defined $_ and length $_ } @{$CPAN::Config->{urllist}};
    push @urllist, @CPAN::Defaultsites if $with_defaults;
    for my $u (@urllist) {
        CPAN->debug("u[$u]") if $CPAN::DEBUG;
        if (UNIVERSAL::can($u,"text")) {
            $u->{TEXT} .= "/" unless substr($u->{TEXT},-1) eq "/";
        } else {
            $u .= "/" unless substr($u,-1) eq "/";
            $u = CPAN::URL->new(TEXT => $u, FROM => "USER");
        }
    }
    \@urllist;
}

#-> sub CPAN::FTP::ftp_get ;
sub ftp_get {
    my($class,$host,$dir,$file,$target) = @_;
    $class->debug(
                  qq[Going to fetch file [$file] from dir [$dir]
        on host [$host] as local [$target]\n]
                 ) if $CPAN::DEBUG;
    my $ftp = Net::FTP->new($host);
    unless ($ftp) {
        $CPAN::Frontend->mywarn("  Could not connect to host '$host' with Net::FTP\n");
        return;
    }
    return 0 unless defined $ftp;
    $ftp->debug(1) if $CPAN::DEBUG{'FTP'} & $CPAN::DEBUG;
    $class->debug(qq[Going to login("anonymous","$Config::Config{cf_email}")]);
    unless ( $ftp->login("anonymous",$Config::Config{'cf_email'}) ) {
        my $msg = $ftp->message;
        $CPAN::Frontend->mywarn("  Couldn't login on $host: $msg\n");
        return;
    }
    unless ( $ftp->cwd($dir) ) {
        my $msg = $ftp->message;
        $CPAN::Frontend->mywarn("  Couldn't cwd $dir: $msg\n");
        return;
    }
    $ftp->binary;
    $class->debug(qq[Going to ->get("$file","$target")\n]) if $CPAN::DEBUG;
    unless ( $ftp->get($file,$target) ) {
        my $msg = $ftp->message;
        $CPAN::Frontend->mywarn("  Couldn't fetch $file from $host: $msg\n");
        return;
    }
    $ftp->quit; # it's ok if this fails
    return 1;
}

# If more accuracy is wanted/needed, Chris Leach sent me this patch...

 # > *** /install/perl/live/lib/CPAN.pm- Wed Sep 24 13:08:48 1997
 # > --- /tmp/cp Wed Sep 24 13:26:40 1997
 # > ***************
 # > *** 1562,1567 ****
 # > --- 1562,1580 ----
 # >       return 1 if substr($url,0,4) eq "file";
 # >       return 1 unless $url =~ m|://([^/]+)|;
 # >       my $host = $1;
 # > +     my $proxy = $CPAN::Config->{'http_proxy'} || $ENV{'http_proxy'};
 # > +     if ($proxy) {
 # > +         $proxy =~ m|://([^/:]+)|;
 # > +         $proxy = $1;
 # > +         my $noproxy = $CPAN::Config->{'no_proxy'} || $ENV{'no_proxy'};
 # > +         if ($noproxy) {
 # > +             if ($host !~ /$noproxy$/) {
 # > +                 $host = $proxy;
 # > +             }
 # > +         } else {
 # > +             $host = $proxy;
 # > +         }
 # > +     }
 # >       require Net::Ping;
 # >       return 1 unless $Net::Ping::VERSION >= 2;
 # >       my $p;


#-> sub CPAN::FTP::localize ;
sub localize {
    my($self,$file,$aslocal,$force,$with_defaults) = @_;
    $force ||= 0;
    Carp::croak( "Usage: ->localize(cpan_file,as_local_file[,\$force])" )
        unless defined $aslocal;
    if ($CPAN::DEBUG){
        require Carp;
        my $longmess = Carp::longmess();
        $self->debug("file[$file] aslocal[$aslocal] force[$force] carplongmess[$longmess]");
    }
    for ($CPAN::Config->{connect_to_internet_ok}) {
        $connect_to_internet_ok = $_ if not defined $connect_to_internet_ok and defined $_;
    }
    my $ph = $CPAN::Config->{pushy_https};
    if (!defined $ph || $ph) {
        return $self->localize_2021($file,$aslocal,$force,$with_defaults);
    } else {
        return $self->localize_1995ff($file,$aslocal,$force,$with_defaults);
    }
}

sub have_promising_aslocal {
    my($self, $aslocal, $force) = @_;
    if (-f $aslocal && -r _ && !($force & 1)) {
        my $size;
        if ($size = -s $aslocal) {
            $self->debug("aslocal[$aslocal]size[$size]") if $CPAN::DEBUG;
            return 1;
        } else {
            # empty file from a previous unsuccessful attempt to download it
            unlink $aslocal or
                $CPAN::Frontend->mydie("Found a zero-length '$aslocal' that I ".
                                       "could not remove.");
        }
    }
    return;
}

#-> sub CPAN::FTP::localize ;
sub localize_2021 {
    my($self,$file,$aslocal,$force,$with_defaults) = @_;
    return $aslocal if $self->have_promising_aslocal($aslocal, $force);
    my($aslocal_dir) = dirname($aslocal);
    my $ret;
    $self->mymkpath($aslocal_dir);
    my $aslocal_tempfile = $aslocal . ".tmp" . $$;
    my $base;
    if (
           ($CPAN::META->has_usable('HTTP::Tiny')
            && $CPAN::META->has_usable('Net::SSLeay')
            && $CPAN::META->has_usable('IO::Socket::SSL')
           )
        || $CPAN::Config->{curl}
        || $CPAN::Config->{wget}
       ) {
        for my $prx (qw(https_proxy no_proxy)) {
            $ENV{$prx} = $CPAN::Config->{$prx} if $CPAN::Config->{$prx};
        }
        $base = "https://cpan.org/";
    } else {
        my @missing_modules = grep { ! $CPAN::META->has_usable($_) } qw(HTTP::Tiny Net::SSLeay IO::Socket::SSL);
        my $miss = join ", ", map { "'$_'" } @missing_modules;
        my $modules = @missing_modules == 1 ? "module" : "modules";
        $CPAN::Frontend->mywarn("Missing or unusable $modules $miss, and found neither curl nor wget installed.\n");
        if ($CPAN::META->has_usable('HTTP::Tiny')) {
            $CPAN::Frontend->mywarn("Need to fall back to http.\n")
        }
        for my $prx (qw(http_proxy no_proxy)) {
            $ENV{$prx} = $CPAN::Config->{$prx} if $CPAN::Config->{$prx};
        }
        $base = "http://www.cpan.org/";
    }
    $ret = $self->hostdl_2021($base,$file,$aslocal_tempfile);
    if ($ret) { # c&p from below
        CPAN->debug("ret[$ret]aslocal[$aslocal]") if $CPAN::DEBUG;
        if ($ret eq $aslocal_tempfile) {
            # if we got it exactly as we asked for, only then we
            # want to rename
            rename $aslocal_tempfile, $aslocal
                or $CPAN::Frontend->mydie("Error while trying to rename ".
                                          "'$ret' to '$aslocal': $!");
            $ret = $aslocal;
        }
    } else {
        unlink $aslocal_tempfile;
        return;
    }
    return $ret;
}

sub hostdl_2021 {
    my($self, $base, $file, $aslocal) = @_; # the $aslocal is $aslocal_tempfile in the caller (old convention)
    my $proxy_vars = $self->_proxy_vars($base);
    my($proto) = $base =~ /^(https?)/;
    my $url = "$base$file";
    # hostdl_2021 may be called with either http or https urls
    if (
        $CPAN::META->has_usable('HTTP::Tiny')
        &&
        (
         $proto eq "http"
         ||
         (    $CPAN::META->has_usable('Net::SSLeay')
              && $CPAN::META->has_usable('IO::Socket::SSL')   )
        )
       ){
        # mostly c&p from below
        require CPAN::HTTP::Client;
        my $chc = CPAN::HTTP::Client->new(
            proxy => $CPAN::Config->{http_proxy} || $ENV{http_proxy},
            no_proxy => $CPAN::Config->{no_proxy} || $ENV{no_proxy},
        );
        for my $try ( $url, ( $url !~ /\.gz(?!\n)\Z/ ? "$url.gz" : () ) ) {
            $CPAN::Frontend->myprint("Fetching with HTTP::Tiny:\n$try\n");
            my $res = eval { $chc->mirror($try, $aslocal) };
            if ( $res && $res->{success} ) {
                my $now = time;
                utime $now, $now, $aslocal; # download time is more
                                            # important than upload
                                            # time
                return $aslocal;
            }
            elsif ( $res && $res->{status} ne '599') {
                $CPAN::Frontend->myprint(sprintf(
                        "HTTP::Tiny failed with code[%s] message[%s]\n",
                        $res->{status},
                        $res->{reason},
                    )
                );
            }
            elsif ( $res && $res->{status} eq '599') {
                $CPAN::Frontend->myprint(sprintf(
                        "HTTP::Tiny failed with an internal error: %s\n",
                        $res->{content},
                    )
                );
            }
            else {
                my $err = $@ || 'Unknown error';
                $CPAN::Frontend->myprint(sprintf(
                        "Error downloading with HTTP::Tiny: %s\n", $err
                    )
                );
            }
        }
    } elsif ($CPAN::Config->{curl} || $CPAN::Config->{wget}){
        # c&p from further down
        my($src_switch, $stdout_redir);
        my($devnull) = $CPAN::Config->{devnull} || "";
      DLPRG: for my $dlprg (qw(curl wget)) {
            my $dlprg_configured = $CPAN::Config->{$dlprg};
            next unless defined $dlprg_configured && length $dlprg_configured;
            my $funkyftp = CPAN::HandleConfig->safe_quote($dlprg_configured);
            if ($dlprg eq "wget") {
                $src_switch = " -O \"$aslocal\"";
                $stdout_redir = "";
            } elsif ($dlprg eq 'curl') {
                $src_switch   = ' -L -f -s -S --netrc-optional';
                $stdout_redir = " > \"$aslocal\"";
                if ($proxy_vars->{http_proxy}) {
                    $src_switch .= qq{ -U "$proxy_vars->{proxy_user}:$proxy_vars->{proxy_pass}" -x "$proxy_vars->{http_proxy}"};
                }
            }
            $CPAN::Frontend->myprint(
                                     qq[
Trying with
    $funkyftp$src_switch
to get
    $url
]);
            my($system) =
                "$funkyftp$src_switch \"$url\" $devnull$stdout_redir";
            $self->debug("system[$system]") if $CPAN::DEBUG;
            my($wstatus) = system($system);
            if ($wstatus == 0) {
                return $aslocal;
            } else {
                my $estatus = $wstatus >> 8;
                my $size = -f $aslocal ?
                    ", left\n$aslocal with size ".-s _ :
                    "\nWarning: expected file [$aslocal] doesn't exist";
                $CPAN::Frontend->myprint(qq{
    Function system("$system")
    returned status $estatus (wstat $wstatus)$size
    });
            }
        } # DLPRG
    } # curl, wget
    return;
}

#-> sub CPAN::FTP::localize ;
sub localize_1995ff {
    my($self,$file,$aslocal,$force,$with_defaults) = @_;
    if ($^O eq 'MacOS') {
        # Comment by AK on 2000-09-03: Uniq short filenames would be
        # available in CHECKSUMS file
        my($name, $path) = File::Basename::fileparse($aslocal, '');
        if (length($name) > 31) {
            $name =~ s/(
                        \.(
                           readme(\.(gz|Z))? |
                           (tar\.)?(gz|Z) |
                           tgz |
                           zip |
                           pm\.(gz|Z)
                          )
                       )$//x;
            my $suf = $1;
            my $size = 31 - length($suf);
            while (length($name) > $size) {
                chop $name;
            }
            $name .= $suf;
            $aslocal = File::Spec->catfile($path, $name);
        }
    }

    return $aslocal if $self->have_promising_aslocal($aslocal, $force);
    my($maybe_restore) = 0;
    if (-f $aslocal) {
        rename $aslocal, "$aslocal.bak$$";
        $maybe_restore++;
    }

    my($aslocal_dir) = dirname($aslocal);
    # Inheritance is not easier to manage than a few if/else branches
    if ($CPAN::META->has_usable('LWP::UserAgent')) {
        unless ($Ua) {
            CPAN::LWP::UserAgent->config;
            eval {$Ua = CPAN::LWP::UserAgent->new;}; # Why is has_usable still not fit enough?
            if ($@) {
                $CPAN::Frontend->mywarn("CPAN::LWP::UserAgent->new dies with $@\n")
                    if $CPAN::DEBUG;
            } else {
                my($var);
                $Ua->proxy('ftp',  $var)
                    if $var = $CPAN::Config->{ftp_proxy} || $ENV{ftp_proxy};
                $Ua->proxy('http', $var)
                    if $var = $CPAN::Config->{http_proxy} || $ENV{http_proxy};
                $Ua->no_proxy($var)
                    if $var = $CPAN::Config->{no_proxy} || $ENV{no_proxy};
            }
        }
    }
    for my $prx (qw(ftp_proxy http_proxy no_proxy)) {
        $ENV{$prx} = $CPAN::Config->{$prx} if $CPAN::Config->{$prx};
    }

    # Try the list of urls for each single object. We keep a record
    # where we did get a file from
    my(@reordered,$last);
    my $ccurllist = $self->_get_urllist($with_defaults);
    $last = $#$ccurllist;
    if ($force & 2) { # local cpans probably out of date, don't reorder
        @reordered = (0..$last);
    } else {
        @reordered =
            sort {
                (substr($ccurllist->[$b],0,4) eq "file")
                    <=>
                (substr($ccurllist->[$a],0,4) eq "file")
                    or
                defined($ThesiteURL)
                    and
                ($ccurllist->[$b] eq $ThesiteURL)
                    <=>
                ($ccurllist->[$a] eq $ThesiteURL)
            } 0..$last;
    }
    my(@levels);
    $Themethod ||= "";
    $self->debug("Themethod[$Themethod]reordered[@reordered]") if $CPAN::DEBUG;
    my @all_levels = (
                      ["dleasy",   "file"],
                      ["dleasy"],
                      ["dlhard"],
                      ["dlhardest"],
                      ["dleasy",   "http","defaultsites"],
                      ["dlhard",   "http","defaultsites"],
                      ["dleasy",   "ftp", "defaultsites"],
                      ["dlhard",   "ftp", "defaultsites"],
                      ["dlhardest","",    "defaultsites"],
                     );
    if ($Themethod) {
        @levels = grep {$_->[0] eq $Themethod} @all_levels;
        push @levels, grep {$_->[0] ne $Themethod} @all_levels;
    } else {
        @levels = @all_levels;
    }
    @levels = qw/dleasy/ if $^O eq 'MacOS';
    my($levelno);
    local $ENV{FTP_PASSIVE} =
        exists $CPAN::Config->{ftp_passive} ?
        $CPAN::Config->{ftp_passive} : 1;
    my $ret;
    my $stats = $self->_new_stats($file);
  LEVEL: for $levelno (0..$#levels) {
        my $level_tuple = $levels[$levelno];
        my($level,$scheme,$sitetag) = @$level_tuple;
        $self->mymkpath($aslocal_dir) unless $scheme && "file" eq $scheme;
        my $defaultsites = $sitetag && $sitetag eq "defaultsites" && !@$ccurllist;
        my @urllist;
        if ($defaultsites) {
            unless (defined $connect_to_internet_ok) {
                $CPAN::Frontend->myprint(sprintf qq{
I would like to connect to one of the following sites to get '%s':

%s
},
                                         $file,
                                         join("",map { " ".$_->text."\n" } @CPAN::Defaultsites),
                                        );
                my $answer = CPAN::Shell::colorable_makemaker_prompt("Is it OK to try to connect to the Internet?", "yes");
                if ($answer =~ /^y/i) {
                    $connect_to_internet_ok = 1;
                } else {
                    $connect_to_internet_ok = 0;
                }
            }
            if ($connect_to_internet_ok) {
                @urllist = @CPAN::Defaultsites;
            } else {
                my $sleep = 2;
                # the tricky thing about dying here is that everybody
                # believes that calls to exists() or all_objects() are
                # safe.
                require CPAN::Exception::blocked_urllist;
                die CPAN::Exception::blocked_urllist->new;
            }
        } else { # ! $defaultsites
            my @host_seq = $level =~ /dleasy/ ?
                @reordered : 0..$last;  # reordered has file and $Thesiteurl first
            @urllist = map { $ccurllist->[$_] } @host_seq;
        }
        $self->debug("synth. urllist[@urllist]") if $CPAN::DEBUG;
        my $aslocal_tempfile = $aslocal . ".tmp" . $$;
        if (my $recommend = $self->_recommend_url_for($file,\@urllist)) {
            @urllist = grep { $_ ne $recommend } @urllist;
            unshift @urllist, $recommend;
        }
        $self->debug("synth. urllist[@urllist]") if $CPAN::DEBUG;
        $ret = $self->hostdlxxx($level,$scheme,\@urllist,$file,$aslocal_tempfile,$stats);
        if ($ret) {
            CPAN->debug("ret[$ret]aslocal[$aslocal]") if $CPAN::DEBUG;
            if ($ret eq $aslocal_tempfile) {
                # if we got it exactly as we asked for, only then we
                # want to rename
                rename $aslocal_tempfile, $aslocal
                    or $CPAN::Frontend->mydie("Error while trying to rename ".
                                              "'$ret' to '$aslocal': $!");
                $ret = $aslocal;
            }
            elsif (-f $ret && $scheme eq 'file' ) {
                # it's a local file, so there's nothing left to do, we
                # let them read from where it is
            }
            $Themethod = $level;
            my $now = time;
            # utime $now, $now, $aslocal; # too bad, if we do that, we
                                          # might alter a local mirror
            $self->debug("level[$level]") if $CPAN::DEBUG;
            last LEVEL;
        } else {
            unlink $aslocal_tempfile;
            last if $CPAN::Signal; # need to cleanup
        }
    }
    if ($ret) {
        $stats->{filesize} = -s $ret;
    }
    $self->debug("before _add_to_statistics") if $CPAN::DEBUG;
    $self->_add_to_statistics($stats);
    $self->debug("after _add_to_statistics") if $CPAN::DEBUG;
    if ($ret) {
        unlink "$aslocal.bak$$";
        return $ret;
    }
    unless ($CPAN::Signal) {
        my(@mess);
        local $" = " ";
        if (@{$CPAN::Config->{urllist}}) {
            push @mess,
                qq{Please check, if the URLs I found in your configuration file \(}.
                    join(", ", @{$CPAN::Config->{urllist}}).
                        qq{\) are valid.};
        } else {
            push @mess, qq{Your urllist is empty!};
        }
        push @mess, qq{The urllist can be edited.},
            qq{E.g. with 'o conf urllist push ftp://myurl/'};
        $CPAN::Frontend->mywarn(Text::Wrap::wrap("","","@mess"). "\n\n");
        $CPAN::Frontend->mydie("Could not fetch $file\n");
    }
    if ($maybe_restore) {
        rename "$aslocal.bak$$", $aslocal;
        $CPAN::Frontend->myprint("Trying to get away with old file:\n" .
                                 $self->ls($aslocal) . "\n");
        return $aslocal;
    }
    return;
}

sub mymkpath {
    my($self, $aslocal_dir) = @_;
    mkpath($aslocal_dir);
    $CPAN::Frontend->mywarn(qq{Warning: You are not allowed to write into }.
                            qq{directory "$aslocal_dir".
    I\'ll continue, but if you encounter problems, they may be due
    to insufficient permissions.\n}) unless -w $aslocal_dir;
}

sub hostdlxxx {
    my $self = shift;
    my $level = shift;
    my $scheme = shift;
    my $h = shift;
    $h = [ grep /^\Q$scheme\E:/, @$h ] if $scheme;
    my $method = "host$level";
    $self->$method($h, @_);
}

sub _set_attempt {
    my($self,$stats,$method,$url) = @_;
    push @{$stats->{attempts}}, {
                                 method => $method,
                                 start => _mytime,
                                 url => $url,
                                };
}

# package CPAN::FTP;
sub hostdleasy { #called from hostdlxxx
    my($self,$host_seq,$file,$aslocal,$stats) = @_;
    my($ro_url);
  HOSTEASY: for $ro_url (@$host_seq) {
        $self->_set_attempt($stats,"dleasy",$ro_url);
        my $url = "$ro_url$file";
        $self->debug("localizing perlish[$url]") if $CPAN::DEBUG;
        if ($url =~ /^file:/) {
            my $l;
            if ($CPAN::META->has_inst('URI::URL')) {
                my $u =  URI::URL->new($url);
                $l = $u->file;
            } else { # works only on Unix, is poorly constructed, but
                # hopefully better than nothing.
                # RFC 1738 says fileurl BNF is
                # fileurl = "file://" [ host | "localhost" ] "/" fpath
                # Thanks to "Mark D. Baushke" <mdb@cisco.com> for
                # the code
                ($l = $url) =~ s|^file://[^/]*/|/|; # discard the host part
                $l =~ s|^file:||;                   # assume they
                                                    # meant
                                                    # file://localhost
                $l =~ s|^/||s
                    if ! -f $l && $l =~ m|^/\w:|;   # e.g. /P:
            }
            $self->debug("local file[$l]") if $CPAN::DEBUG;
            if ( -f $l && -r _) {
                $ThesiteURL = $ro_url;
                return $l;
            }
            # If request is for a compressed file and we can find the
            # uncompressed file also, return the path of the uncompressed file
            # otherwise, decompress it and return the resulting path
            if ($l =~ /(.+)\.gz$/) {
                my $ungz = $1;
                if ( -f $ungz && -r _) {
                    $ThesiteURL = $ro_url;
                    return $ungz;
                }
                elsif (-f $l && -r _) {
                    eval { CPAN::Tarzip->new($l)->gunzip($aslocal) };
                    if ( -f $aslocal && -s _) {
                        $ThesiteURL = $ro_url;
                        return $aslocal;
                    }
                    elsif (! -s $aslocal) {
                        unlink $aslocal;
                    }
                    elsif (-f $l) {
                        $CPAN::Frontend->mywarn("Error decompressing '$l': $@\n")
                            if $@;
                        return;
                    }
                }
            }
            # Otherwise, return the local file path if it exists
            elsif ( -f $l && -r _) {
                $ThesiteURL = $ro_url;
                return $l;
            }
            # If we can't find it, but there is a compressed version
            # of it, then decompress it
            elsif (-f "$l.gz") {
                $self->debug("found compressed $l.gz") if $CPAN::DEBUG;
                eval { CPAN::Tarzip->new("$l.gz")->gunzip($aslocal) };
                if ( -f $aslocal) {
                    $ThesiteURL = $ro_url;
                    return $aslocal;
                }
                else {
                    $CPAN::Frontend->mywarn("Error decompressing '$l': $@\n")
                        if $@;
                    return;
                }
            }
            $CPAN::Frontend->mywarn("Could not find '$l'\n");
        }
        $self->debug("it was not a file URL") if $CPAN::DEBUG;
        if ($CPAN::META->has_usable('LWP')) {
            $CPAN::Frontend->myprint("Fetching with LWP:\n$url\n");
            unless ($Ua) {
                CPAN::LWP::UserAgent->config;
                eval { $Ua = CPAN::LWP::UserAgent->new; };
                if ($@) {
                    $CPAN::Frontend->mywarn("CPAN::LWP::UserAgent->new dies with $@\n");
                }
            }
            my $res = $Ua->mirror($url, $aslocal);
            if ($res->is_success) {
                $ThesiteURL = $ro_url;
                my $now = time;
                utime $now, $now, $aslocal; # download time is more
                                            # important than upload
                                            # time
                return $aslocal;
            } elsif ($url !~ /\.gz(?!\n)\Z/) {
                my $gzurl = "$url.gz";
                $CPAN::Frontend->myprint("Fetching with LWP:\n$gzurl\n");
                $res = $Ua->mirror($gzurl, "$aslocal.gz");
                if ($res->is_success) {
                    if (eval {CPAN::Tarzip->new("$aslocal.gz")->gunzip($aslocal)}) {
                        $ThesiteURL = $ro_url;
                        return $aslocal;
                    }
                }
            } else {
                $CPAN::Frontend->myprint(sprintf(
                                                 "LWP failed with code[%s] message[%s]\n",
                                                 $res->code,
                                                 $res->message,
                                                ));
                # Alan Burlison informed me that in firewall environments
                # Net::FTP can still succeed where LWP fails. So we do not
                # skip Net::FTP anymore when LWP is available.
            }
        } elsif ($url =~ /^http:/i && $CPAN::META->has_usable('HTTP::Tiny')) {
            require CPAN::HTTP::Client;
            my $chc = CPAN::HTTP::Client->new(
                proxy => $CPAN::Config->{http_proxy} || $ENV{http_proxy},
                no_proxy => $CPAN::Config->{no_proxy} || $ENV{no_proxy},
            );
            for my $try ( $url, ( $url !~ /\.gz(?!\n)\Z/ ? "$url.gz" : () ) ) {
                $CPAN::Frontend->myprint("Fetching with HTTP::Tiny:\n$try\n");
                my $res = eval { $chc->mirror($try, $aslocal) };
                if ( $res && $res->{success} ) {
                    $ThesiteURL = $ro_url;
                    my $now = time;
                    utime $now, $now, $aslocal; # download time is more
                                                # important than upload
                                                # time
                    return $aslocal;
                }
                elsif ( $res && $res->{status} ne '599') {
                    $CPAN::Frontend->myprint(sprintf(
                            "HTTP::Tiny failed with code[%s] message[%s]\n",
                            $res->{status},
                            $res->{reason},
                        )
                    );
                }
                elsif ( $res && $res->{status} eq '599') {
                    $CPAN::Frontend->myprint(sprintf(
                            "HTTP::Tiny failed with an internal error: %s\n",
                            $res->{content},
                        )
                    );
                }
                else {
                    my $err = $@ || 'Unknown error';
                    $CPAN::Frontend->myprint(sprintf(
                            "Error downloading with HTTP::Tiny: %s\n", $err
                        )
                    );
                }
            }
        }
        return if $CPAN::Signal;
        if ($url =~ m|^ftp://(.*?)/(.*)/(.*)|) {
            # that's the nice and easy way thanks to Graham
            $self->debug("recognized ftp") if $CPAN::DEBUG;
            my($host,$dir,$getfile) = ($1,$2,$3);
            if ($CPAN::META->has_usable('Net::FTP')) {
                $dir =~ s|/+|/|g;
                $CPAN::Frontend->myprint("Fetching with Net::FTP:\n$url\n");
                $self->debug("getfile[$getfile]dir[$dir]host[$host]" .
                             "aslocal[$aslocal]") if $CPAN::DEBUG;
                if (CPAN::FTP->ftp_get($host,$dir,$getfile,$aslocal)) {
                    $ThesiteURL = $ro_url;
                    return $aslocal;
                }
                if ($aslocal !~ /\.gz(?!\n)\Z/) {
                    my $gz = "$aslocal.gz";
                    $CPAN::Frontend->myprint("Fetching with Net::FTP\n$url.gz\n");
                    if (CPAN::FTP->ftp_get($host,
                                           $dir,
                                           "$getfile.gz",
                                           $gz) &&
                        eval{CPAN::Tarzip->new($gz)->gunzip($aslocal)}
                    ) {
                        $ThesiteURL = $ro_url;
                        return $aslocal;
                    }
                }
                # next HOSTEASY;
            } else {
                CPAN->debug("Net::FTP does not count as usable atm") if $CPAN::DEBUG;
            }
        }
        if (
            UNIVERSAL::can($ro_url,"text")
            and
            $ro_url->{FROM} eq "USER"
           ) {
            ##address #17973: default URLs should not try to override
            ##user-defined URLs just because LWP is not available
            my $ret = $self->hostdlhard([$ro_url],$file,$aslocal,$stats);
            return $ret if $ret;
        }
        return if $CPAN::Signal;
    }
}

# package CPAN::FTP;
sub hostdlhard {
    my($self,$host_seq,$file,$aslocal,$stats) = @_;

    # Came back if Net::FTP couldn't establish connection (or
    # failed otherwise) Maybe they are behind a firewall, but they
    # gave us a socksified (or other) ftp program...

    my($ro_url);
    my($devnull) = $CPAN::Config->{devnull} || "";
    # < /dev/null ";
    my($aslocal_dir) = dirname($aslocal);
    mkpath($aslocal_dir);
    my $some_dl_success = 0;
    my $any_attempt = 0;
 HOSTHARD: for $ro_url (@$host_seq) {
        $self->_set_attempt($stats,"dlhard",$ro_url);
        my $url = "$ro_url$file";
        my($proto,$host,$dir,$getfile);

        # Courtesy Mark Conty mark_conty@cargill.com change from
        # if ($url =~ m|^ftp://(.*?)/(.*)/(.*)|) {
        # to
        if ($url =~ m|^([^:]+)://(.*?)/(.*)/(.*)|) {
            # proto not yet used
            ($proto,$host,$dir,$getfile) = ($1,$2,$3,$4);
        } else {
            next HOSTHARD; # who said, we could ftp anything except ftp?
        }
        next HOSTHARD if $proto eq "file"; # file URLs would have had
                                           # success above. Likely a bogus URL

        # making at least one attempt against a host
        $any_attempt++;

        $self->debug("localizing funkyftpwise[$url]") if $CPAN::DEBUG;

        # Try the most capable first and leave ncftp* for last as it only
        # does FTP.
        my $proxy_vars = $self->_proxy_vars($ro_url);
      DLPRG: for my $f (qw(curl wget lynx ncftpget ncftp)) {
            my $funkyftp = CPAN::HandleConfig->safe_quote($CPAN::Config->{$f});
            next DLPRG unless defined $funkyftp;
            next DLPRG if $funkyftp =~ /^\s*$/;

            my($src_switch) = "";
            my($chdir) = "";
            my($stdout_redir) = " > \"$aslocal\"";
            if ($f eq "lynx") {
                $src_switch = " -source";
            } elsif ($f eq "ncftp") {
                next DLPRG unless $url =~ m{\Aftp://};
                $src_switch = " -c";
            } elsif ($f eq "wget") {
                $src_switch = " -O \"$aslocal\"";
                $stdout_redir = "";
            } elsif ($f eq 'curl') {
                $src_switch = ' -L -f -s -S --netrc-optional';
                if ($proxy_vars->{http_proxy}) {
                    $src_switch .= qq{ -U "$proxy_vars->{proxy_user}:$proxy_vars->{proxy_pass}" -x "$proxy_vars->{http_proxy}"};
                }
            } elsif ($f eq "ncftpget") {
                next DLPRG unless $url =~ m{\Aftp://};
                $chdir = "cd $aslocal_dir && ";
                $stdout_redir = "";
            }
            $CPAN::Frontend->myprint(
                                     qq[
Trying with
    $funkyftp$src_switch
to get
    $url
]);
            my($system) =
                "$chdir$funkyftp$src_switch \"$url\" $devnull$stdout_redir";
            $self->debug("system[$system]") if $CPAN::DEBUG;
            my($wstatus) = system($system);
            if ($f eq "lynx") {
                # lynx returns 0 when it fails somewhere
                if (-s $aslocal) {
                    my $content = do { local *FH;
                                       open FH, $aslocal or die;
                                       local $/;
                                       <FH> };
                    if ($content =~ /^<.*(<title>[45]|Error [45])/si) {
                        $CPAN::Frontend->mywarn(qq{
No success, the file that lynx has downloaded looks like an error message:
$content
});
                        $CPAN::Frontend->mysleep(1);
                        next DLPRG;
                    }
                    $some_dl_success++;
                } else {
                    $CPAN::Frontend->myprint(qq{
No success, the file that lynx has downloaded is an empty file.
});
                    next DLPRG;
                }
            }
            if ($wstatus == 0) {
                if (-s $aslocal) {
                    # Looks good
                    $some_dl_success++;
                }
                $ThesiteURL = $ro_url;
                return $aslocal;
            } else {
                my $estatus = $wstatus >> 8;
                my $size = -f $aslocal ?
                    ", left\n$aslocal with size ".-s _ :
                    "\nWarning: expected file [$aslocal] doesn't exist";
                $CPAN::Frontend->myprint(qq{
    Function system("$system")
    returned status $estatus (wstat $wstatus)$size
    });
            }
            return if $CPAN::Signal;
        } # download/transfer programs (DLPRG)
    } # host
    return unless $any_attempt;
    if ($some_dl_success) {
        $CPAN::Frontend->mywarn("Warning: doesn't seem we had substantial success downloading '$aslocal'. Don't know how to proceed.\n");
    } else {
        $CPAN::Frontend->mywarn("Warning: no success downloading '$aslocal'. Giving up on it.\n");
    }
    return;
}

#-> CPAN::FTP::_proxy_vars
sub _proxy_vars {
    my($self,$url) = @_;
    my $ret = +{};
    my $http_proxy = $CPAN::Config->{'http_proxy'} || $ENV{'http_proxy'};
    if ($http_proxy) {
        my($host) = $url =~ m|://([^/:]+)|;
        my $want_proxy = 1;
        my $noproxy = $CPAN::Config->{'no_proxy'} || $ENV{'no_proxy'} || "";
        my @noproxy = split /\s*,\s*/, $noproxy;
        if ($host) {
          DOMAIN: for my $domain (@noproxy) {
                if ($host =~ /\Q$domain\E$/) { # cf. LWP::UserAgent
                    $want_proxy = 0;
                    last DOMAIN;
                }
            }
        } else {
            $CPAN::Frontend->mywarn("  Could not determine host from http_proxy '$http_proxy'\n");
        }
        if ($want_proxy) {
            my($user, $pass) =
                CPAN::HTTP::Credentials->get_proxy_credentials();
            $ret = {
                    proxy_user => $user,
                    proxy_pass => $pass,
                    http_proxy => $http_proxy
                  };
        }
    }
    return $ret;
}

# package CPAN::FTP;
sub hostdlhardest {
    my($self,$host_seq,$file,$aslocal,$stats) = @_;

    return unless @$host_seq;
    my($ro_url);
    my($aslocal_dir) = dirname($aslocal);
    mkpath($aslocal_dir);
    my $ftpbin = $CPAN::Config->{ftp};
    unless ($ftpbin && length $ftpbin && MM->maybe_command($ftpbin)) {
        $CPAN::Frontend->myprint("No external ftp command available\n\n");
        return;
    }
    $CPAN::Frontend->mywarn(qq{
As a last resort we now switch to the external ftp command '$ftpbin'
to get '$aslocal'.

Doing so often leads to problems that are hard to diagnose.

If you're the victim of such problems, please consider unsetting the
ftp config variable with

    o conf ftp ""
    o conf commit

});
    $CPAN::Frontend->mysleep(2);
  HOSTHARDEST: for $ro_url (@$host_seq) {
        $self->_set_attempt($stats,"dlhardest",$ro_url);
        my $url = "$ro_url$file";
        $self->debug("localizing ftpwise[$url]") if $CPAN::DEBUG;
        unless ($url =~ m|^ftp://(.*?)/(.*)/(.*)|) {
            next;
        }
        my($host,$dir,$getfile) = ($1,$2,$3);
        my $timestamp = 0;
        my($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,
            $ctime,$blksize,$blocks) = stat($aslocal);
        $timestamp = $mtime ||= 0;
        my($netrc) = CPAN::FTP::netrc->new;
        my($netrcfile) = $netrc->netrc;
        my($verbose) = $CPAN::DEBUG{'FTP'} & $CPAN::DEBUG ? " -v" : "";
        my $targetfile = File::Basename::basename($aslocal);
        my(@dialog);
        push(
             @dialog,
             "lcd $aslocal_dir",
             "cd /",
             map("cd $_", split /\//, $dir), # RFC 1738
             "bin",
             "passive",
             "get $getfile $targetfile",
             "quit"
        );
        if (! $netrcfile) {
            CPAN->debug("No ~/.netrc file found") if $CPAN::DEBUG;
        } elsif ($netrc->hasdefault || $netrc->contains($host)) {
            CPAN->debug(sprintf("hasdef[%d]cont($host)[%d]",
                                $netrc->hasdefault,
                                $netrc->contains($host))) if $CPAN::DEBUG;
            if ($netrc->protected) {
                my $dialog = join "", map { "    $_\n" } @dialog;
                my $netrc_explain;
                if ($netrc->contains($host)) {
                    $netrc_explain = "Relying that your .netrc entry for '$host' ".
                        "manages the login";
                } else {
                    $netrc_explain = "Relying that your default .netrc entry ".
                        "manages the login";
                }
                $CPAN::Frontend->myprint(qq{
  Trying with external ftp to get
    '$url'
  $netrc_explain
  Sending the dialog
$dialog
}
                );
                $self->talk_ftp("$ftpbin$verbose $host",
                                @dialog);
                ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
                    $atime,$mtime,$ctime,$blksize,$blocks) = stat($aslocal);
                $mtime ||= 0;
                if ($mtime > $timestamp) {
                    $CPAN::Frontend->myprint("GOT $aslocal\n");
                    $ThesiteURL = $ro_url;
                    return $aslocal;
                } else {
                    $CPAN::Frontend->myprint("Hmm... Still failed!\n");
                }
                    return if $CPAN::Signal;
            } else {
                $CPAN::Frontend->mywarn(qq{Your $netrcfile is not }.
                                        qq{correctly protected.\n});
            }
        } else {
            $CPAN::Frontend->mywarn("Your ~/.netrc neither contains $host
  nor does it have a default entry\n");
        }

        # OK, they don't have a valid ~/.netrc. Use 'ftp -n'
        # then and login manually to host, using e-mail as
        # password.
        $CPAN::Frontend->myprint(qq{Issuing "$ftpbin$verbose -n"\n});
        unshift(
                @dialog,
                "open $host",
                "user anonymous $Config::Config{'cf_email'}"
        );
        my $dialog = join "", map { "    $_\n" } @dialog;
        $CPAN::Frontend->myprint(qq{
  Trying with external ftp to get
    $url
  Sending the dialog
$dialog
}
        );
        $self->talk_ftp("$ftpbin$verbose -n", @dialog);
        ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
            $atime,$mtime,$ctime,$blksize,$blocks) = stat($aslocal);
        $mtime ||= 0;
        if ($mtime > $timestamp) {
            $CPAN::Frontend->myprint("GOT $aslocal\n");
            $ThesiteURL = $ro_url;
            return $aslocal;
        } else {
            $CPAN::Frontend->myprint("Bad luck... Still failed!\n");
        }
        return if $CPAN::Signal;
        $CPAN::Frontend->mywarn("Can't access URL $url.\n\n");
        $CPAN::Frontend->mysleep(2);
    } # host
}

# package CPAN::FTP;
sub talk_ftp {
    my($self,$command,@dialog) = @_;
    my $fh = FileHandle->new;
    $fh->open("|$command") or die "Couldn't open ftp: $!";
    foreach (@dialog) { $fh->print("$_\n") }
    $fh->close; # Wait for process to complete
    my $wstatus = $?;
    my $estatus = $wstatus >> 8;
    $CPAN::Frontend->myprint(qq{
Subprocess "|$command"
  returned status $estatus (wstat $wstatus)
}) if $wstatus;
}

# find2perl needs modularization, too, all the following is stolen
# from there
# CPAN::FTP::ls
sub ls {
    my($self,$name) = @_;
    my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$sizemm,
     $atime,$mtime,$ctime,$blksize,$blocks) = lstat($name);

    my($perms,%user,%group);
    my $pname = $name;

    if ($blocks) {
        $blocks = int(($blocks + 1) / 2);
    }
    else {
        $blocks = int(($sizemm + 1023) / 1024);
    }

    if    (-f _) { $perms = '-'; }
    elsif (-d _) { $perms = 'd'; }
    elsif (-c _) { $perms = 'c'; $sizemm = &sizemm; }
    elsif (-b _) { $perms = 'b'; $sizemm = &sizemm; }
    elsif (-p _) { $perms = 'p'; }
    elsif (-S _) { $perms = 's'; }
    else         { $perms = 'l'; $pname .= ' -> ' . readlink($_); }

    my(@rwx) = ('---','--x','-w-','-wx','r--','r-x','rw-','rwx');
    my(@moname) = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
    my $tmpmode = $mode;
    my $tmp = $rwx[$tmpmode & 7];
    $tmpmode >>= 3;
    $tmp = $rwx[$tmpmode & 7] . $tmp;
    $tmpmode >>= 3;
    $tmp = $rwx[$tmpmode & 7] . $tmp;
    substr($tmp,2,1) =~ tr/-x/Ss/ if -u _;
    substr($tmp,5,1) =~ tr/-x/Ss/ if -g _;
    substr($tmp,8,1) =~ tr/-x/Tt/ if -k _;
    $perms .= $tmp;

    my $user = $user{$uid} || $uid;   # too lazy to implement lookup
    my $group = $group{$gid} || $gid;

    my($sec,$min,$hour,$mday,$mon,$year) = localtime($mtime);
    my($timeyear);
    my($moname) = $moname[$mon];
    if (-M _ > 365.25 / 2) {
        $timeyear = $year + 1900;
    }
    else {
        $timeyear = sprintf("%02d:%02d", $hour, $min);
    }

    sprintf "%5lu %4ld %-10s %2d %-8s %-8s %8s %s %2d %5s %s\n",
             $ino,
                  $blocks,
                       $perms,
                             $nlink,
                                 $user,
                                      $group,
                                           $sizemm,
                                               $moname,
                                                  $mday,
                                                      $timeyear,
                                                          $pname;
}

1;
PK7N%[�U�V�Vperl5/CPAN/Index.pmnu��6�$package CPAN::Index;
use strict;
use vars qw($LAST_TIME $DATE_OF_02 $DATE_OF_03 $HAVE_REANIMATED $VERSION);
$VERSION = "2.29";
@CPAN::Index::ISA = qw(CPAN::Debug);
$LAST_TIME ||= 0;
$DATE_OF_03 ||= 0;
# use constant PROTOCOL => "2.0"; # commented out to avoid warning on upgrade from 1.57
sub PROTOCOL { 2.0 }

#-> sub CPAN::Index::force_reload ;
sub force_reload {
    my($class) = @_;
    $CPAN::Index::LAST_TIME = 0;
    $class->reload(1);
}

my @indexbundle =
    (
     {
      reader => "rd_authindex",
      dir => "authors",
      remotefile => '01mailrc.txt.gz',
      shortlocalfile => '01mailrc.gz',
     },
     {
      reader => "rd_modpacks",
      dir => "modules",
      remotefile => '02packages.details.txt.gz',
      shortlocalfile => '02packag.gz',
     },
     {
      reader => "rd_modlist",
      dir => "modules",
      remotefile => '03modlist.data.gz',
      shortlocalfile => '03mlist.gz',
     },
    );

#-> sub CPAN::Index::reload ;
sub reload {
    my($self,$force) = @_;
    my $time = time;

    # XXX check if a newer one is available. (We currently read it
    # from time to time)
    for ($CPAN::Config->{index_expire}) {
        $_ = 0.001 unless $_ && $_ > 0.001;
    }
    unless (1 || $CPAN::Have_warned->{readmetadatacache}++) {
        # debug here when CPAN doesn't seem to read the Metadata
        require Carp;
        Carp::cluck("META-PROTOCOL[$CPAN::META->{PROTOCOL}]");
    }
    unless ($CPAN::META->{PROTOCOL}) {
        $self->read_metadata_cache;
        $CPAN::META->{PROTOCOL} ||= "1.0";
    }
    if ( $CPAN::META->{PROTOCOL} < PROTOCOL  ) {
        # warn "Setting last_time to 0";
        $LAST_TIME = 0; # No warning necessary
    }
    if ($LAST_TIME + $CPAN::Config->{index_expire}*86400 > $time
        and ! $force) {
        # called too often
        # CPAN->debug("LAST_TIME[$LAST_TIME]index_expire[$CPAN::Config->{index_expire}]time[$time]");
    } elsif (0) {
        # IFF we are developing, it helps to wipe out the memory
        # between reloads, otherwise it is not what a user expects.
        undef $CPAN::META; # Neue Gruendlichkeit since v1.52(r1.274)
        $CPAN::META = CPAN->new;
    } else {
        my($debug,$t2);
        local $LAST_TIME = $time;
        local $CPAN::META->{PROTOCOL} = PROTOCOL;

        my $needshort = $^O eq "dos";

    INX: for my $indexbundle (@indexbundle) {
            my $reader = $indexbundle->{reader};
            my $localfile = $needshort ? $indexbundle->{shortlocalfile} : $indexbundle->{remotefile};
            my $localpath = File::Spec->catfile($indexbundle->{dir}, $localfile);
            my $remote = join "/", $indexbundle->{dir}, $indexbundle->{remotefile};
            my $localized = $self->reload_x($remote, $localpath, $force);
            $self->$reader($localized); # may die but we let the shell catch it
            if ($CPAN::DEBUG){
                $t2 = time;
                $debug = "timing reading 01[".($t2 - $time)."]";
                $time = $t2;
            }
            return if $CPAN::Signal; # this is sometimes lengthy
        }
        $self->write_metadata_cache;
        if ($CPAN::DEBUG){
            $t2 = time;
            $debug .= "03[".($t2 - $time)."]";
            $time = $t2;
        }
        CPAN->debug($debug) if $CPAN::DEBUG;
    }
    if ($CPAN::Config->{build_dir_reuse}) {
        $self->reanimate_build_dir;
    }
    if (CPAN::_sqlite_running()) {
        $CPAN::SQLite->reload(time => $time, force => $force)
            if not $LAST_TIME;
    }
    $LAST_TIME = $time;
    $CPAN::META->{PROTOCOL} = PROTOCOL;
}

#-> sub CPAN::Index::reanimate_build_dir ;
sub reanimate_build_dir {
    my($self) = @_;
    unless ($CPAN::META->has_inst($CPAN::Config->{yaml_module}||"YAML")) {
        return;
    }
    return if $HAVE_REANIMATED++;
    my $d = $CPAN::Config->{build_dir};
    my $dh = DirHandle->new;
    opendir $dh, $d or return; # does not exist
    my $dirent;
    my $i = 0;
    my $painted = 0;
    my $restored = 0;
    my $start = CPAN::FTP::_mytime();
    my @candidates = map { $_->[0] }
        sort { $b->[1] <=> $a->[1] }
            map { [ $_, -M File::Spec->catfile($d,$_) ] }
                grep {/(.+)\.yml$/ && -d File::Spec->catfile($d,$1)} readdir $dh;
    if ( @candidates ) {
        $CPAN::Frontend->myprint
            (sprintf("Reading %d yaml file%s from %s/\n",
                    scalar @candidates,
                    @candidates==1 ? "" : "s",
                    $CPAN::Config->{build_dir}
                    ));
      DISTRO: for $i (0..$#candidates) {
            my $dirent = $candidates[$i];
            my $y = eval {CPAN->_yaml_loadfile(File::Spec->catfile($d,$dirent), {loadblessed => 1})};
            if ($@) {
                warn "Error while parsing file '$dirent'; error: '$@'";
                next DISTRO;
            }
            my $c = $y->[0];
            if ($c && $c->{perl} && $c->{distribution} && CPAN->_perl_fingerprint($c->{perl})) {
                my $key = $c->{distribution}{ID};
                for my $k (keys %{$c->{distribution}}) {
                    if ($c->{distribution}{$k}
                        && ref $c->{distribution}{$k}
                        && UNIVERSAL::isa($c->{distribution}{$k},"CPAN::Distrostatus")) {
                        $c->{distribution}{$k}{COMMANDID} = $i - @candidates;
                    }
                }

                #we tried to restore only if element already
                #exists; but then we do not work with metadata
                #turned off.
                my $do
                    = $CPAN::META->{readwrite}{'CPAN::Distribution'}{$key}
                        = $c->{distribution};
                for my $skipper (qw(
                                    badtestcnt
                                    configure_requires_later
                                    configure_requires_later_for
                                    force_update
                                    later
                                    later_for
                                    notest
                                    should_report
                                    sponsored_mods
                                    prefs
                                    negative_prefs_cache
                                  )) {
                    delete $do->{$skipper};
                }
                if ($do->can("tested_ok_but_not_installed")) {
                    if ($do->tested_ok_but_not_installed) {
                        $CPAN::META->is_tested($do->{build_dir},$do->{make_test}{TIME});
                    } else {
                        next DISTRO;
                    }
                }
                $restored++;
            }
            $i++;
            while (($painted/76) < ($i/@candidates)) {
                $CPAN::Frontend->myprint(".");
                $painted++;
            }
        }
    }
    else {
        $CPAN::Frontend->myprint("Build_dir empty, nothing to restore\n");
    }
    my $took = CPAN::FTP::_mytime() - $start;
    $CPAN::Frontend->myprint(sprintf(
                                     "DONE\nRestored the state of %s (in %.4f secs)\n",
                                     $restored || "none",
                                     $took,
                                    ));
}


#-> sub CPAN::Index::reload_x ;
sub reload_x {
    my($cl,$wanted,$localname,$force) = @_;
    $force |= 2; # means we're dealing with an index here
    CPAN::HandleConfig->load; # we should guarantee loading wherever
                              # we rely on Config XXX
    $localname ||= $wanted;
    my $abs_wanted = File::Spec->catfile($CPAN::Config->{'keep_source_where'},
                                         $localname);
    if (
        -f $abs_wanted &&
        -M $abs_wanted < $CPAN::Config->{'index_expire'} &&
        !($force & 1)
       ) {
        my $s = $CPAN::Config->{'index_expire'} == 1 ? "" : "s";
        $cl->debug(qq{$abs_wanted younger than $CPAN::Config->{'index_expire'} }.
                   qq{day$s. I\'ll use that.});
        return $abs_wanted;
    } else {
        $force |= 1; # means we're quite serious about it.
    }
    return CPAN::FTP->localize($wanted,$abs_wanted,$force);
}

#-> sub CPAN::Index::rd_authindex ;
sub rd_authindex {
    my($cl, $index_target) = @_;
    return unless defined $index_target;
    return if CPAN::_sqlite_running();
    my @lines;
    $CPAN::Frontend->myprint("Reading '$index_target'\n");
    local(*FH);
    tie *FH, 'CPAN::Tarzip', $index_target;
    local($/) = "\n";
    local($_);
    push @lines, split /\012/ while <FH>;
    my $i = 0;
    my $painted = 0;
    foreach (@lines) {
        my($userid,$fullname,$email) =
            m/alias\s+(\S+)\s+\"([^\"\<]*)\s+\<(.*)\>\"/;
        $fullname ||= $email;
        if ($userid && $fullname && $email) {
            my $userobj = $CPAN::META->instance('CPAN::Author',$userid);
            $userobj->set('FULLNAME' => $fullname, 'EMAIL' => $email);
        } else {
            CPAN->debug(sprintf "line[%s]", $_) if $CPAN::DEBUG;
        }
        $i++;
        while (($painted/76) < ($i/@lines)) {
            $CPAN::Frontend->myprint(".");
            $painted++;
        }
        return if $CPAN::Signal;
    }
    $CPAN::Frontend->myprint("DONE\n");
}

sub userid {
  my($self,$dist) = @_;
  $dist = $self->{'id'} unless defined $dist;
  my($ret) = $dist =~ m|(?:\w/\w\w/)?([^/]+)/|;
  $ret;
}

#-> sub CPAN::Index::rd_modpacks ;
sub rd_modpacks {
    my($self, $index_target) = @_;
    return unless defined $index_target;
    return if CPAN::_sqlite_running();
    $CPAN::Frontend->myprint("Reading '$index_target'\n");
    my $fh = CPAN::Tarzip->TIEHANDLE($index_target);
    local $_;
    CPAN->debug(sprintf "start[%d]", time) if $CPAN::DEBUG;
    my $slurp = "";
    my $chunk;
    while (my $bytes = $fh->READ(\$chunk,8192)) {
        $slurp.=$chunk;
    }
    my @lines = split /\012/, $slurp;
    CPAN->debug(sprintf "end[%d]", time) if $CPAN::DEBUG;
    undef $fh;
    # read header
    my($line_count,$last_updated);
    while (@lines) {
        my $shift = shift(@lines);
        last if $shift =~ /^\s*$/;
        $shift =~ /^Line-Count:\s+(\d+)/ and $line_count = $1;
        $shift =~ /^Last-Updated:\s+(.+)/ and $last_updated = $1;
    }
    CPAN->debug("line_count[$line_count]last_updated[$last_updated]") if $CPAN::DEBUG;
    my $errors = 0;
    if (not defined $line_count) {

        $CPAN::Frontend->mywarn(qq{Warning: Your $index_target does not contain a Line-Count header.
Please check the validity of the index file by comparing it to more
than one CPAN mirror. I'll continue but problems seem likely to
happen.\a
});
        $errors++;
        $CPAN::Frontend->mysleep(5);
    } elsif ($line_count != scalar @lines) {

        $CPAN::Frontend->mywarn(sprintf qq{Warning: Your %s
contains a Line-Count header of %d but I see %d lines there. Please
check the validity of the index file by comparing it to more than one
CPAN mirror. I'll continue but problems seem likely to happen.\a\n},
$index_target, $line_count, scalar(@lines));

    }
    if (not defined $last_updated) {

        $CPAN::Frontend->mywarn(qq{Warning: Your $index_target does not contain a Last-Updated header.
Please check the validity of the index file by comparing it to more
than one CPAN mirror. I'll continue but problems seem likely to
happen.\a
});
        $errors++;
        $CPAN::Frontend->mysleep(5);
    } else {

        $CPAN::Frontend
            ->myprint(sprintf qq{  Database was generated on %s\n},
                      $last_updated);
        $DATE_OF_02 = $last_updated;

        my $age = time;
        if ($CPAN::META->has_inst('HTTP::Date')) {
            require HTTP::Date;
            $age -= HTTP::Date::str2time($last_updated);
        } else {
            $CPAN::Frontend->mywarn("  HTTP::Date not available\n");
            require Time::Local;
            my(@d) = $last_updated =~ / (\d+) (\w+) (\d+) (\d+):(\d+):(\d+) /;
            $d[1] = index("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec", $d[1])/4;
            $age -= $d[1]>=0 ? Time::Local::timegm(@d[5,4,3,0,1,2]) : 0;
        }
        $age /= 3600*24;
        if ($age > 30) {

            $CPAN::Frontend
                ->mywarn(sprintf
                         qq{Warning: This index file is %d days old.
  Please check the host you chose as your CPAN mirror for staleness.
  I'll continue but problems seem likely to happen.\a\n},
                         $age);

        } elsif ($age < -1) {

            $CPAN::Frontend
                ->mywarn(sprintf
                         qq{Warning: Your system date is %d days behind this index file!
  System time:          %s
  Timestamp index file: %s
  Please fix your system time, problems with the make command expected.\n},
                         -$age,
                         scalar gmtime,
                         $DATE_OF_02,
                        );

        }
    }


    # A necessity since we have metadata_cache: delete what isn't
    # there anymore
    my $secondtime = $CPAN::META->exists("CPAN::Module","CPAN");
    CPAN->debug("secondtime[$secondtime]") if $CPAN::DEBUG;
    my(%exists);
    my $i = 0;
    my $painted = 0;
 LINE: foreach (@lines) {
        # before 1.56 we split into 3 and discarded the rest. From
        # 1.57 we assign remaining text to $comment thus allowing to
        # influence isa_perl
        my($mod,$version,$dist,$comment) = split " ", $_, 4;
        unless ($mod && defined $version && $dist) {
            require Dumpvalue;
            my $dv = Dumpvalue->new(tick => '"');
            $CPAN::Frontend->mywarn(sprintf "Could not split line[%s]\n", $dv->stringify($_));
            if ($errors++ >= 5){
                $CPAN::Frontend->mydie("Giving up parsing your $index_target, too many errors");
            }
            next LINE;
        }
        my($bundle,$id,$userid);

        if ($mod eq 'CPAN' &&
            ! (
            CPAN::Queue->exists('Bundle::CPAN') ||
            CPAN::Queue->exists('CPAN')
            )
        ) {
            local($^W)= 0;
            if ($version > $CPAN::VERSION) {
                $CPAN::Frontend->mywarn(qq{
  New CPAN.pm version (v$version) available.
  [Currently running version is v$CPAN::VERSION]
  You might want to try
    install CPAN
    reload cpan
  to both upgrade CPAN.pm and run the new version without leaving
  the current session.

}); #});
                $CPAN::Frontend->mysleep(2);
                $CPAN::Frontend->myprint(qq{\n});
            }
            last if $CPAN::Signal;
        } elsif ($mod =~ /^Bundle::(.*)/) {
            $bundle = $1;
        }

        if ($bundle) {
            $id =  $CPAN::META->instance('CPAN::Bundle',$mod);
            # Let's make it a module too, because bundles have so much
            # in common with modules.

            # Changed in 1.57_63: seems like memory bloat now without
            # any value, so commented out

            # $CPAN::META->instance('CPAN::Module',$mod);

        } else {

            # instantiate a module object
            $id = $CPAN::META->instance('CPAN::Module',$mod);

        }

        # Although CPAN prohibits same name with different version the
        # indexer may have changed the version for the same distro
        # since the last time ("Force Reindexing" feature)
        if ($id->cpan_file ne $dist
            ||
            $id->cpan_version ne $version
           ) {
            $userid = $id->userid || $self->userid($dist);
            $id->set(
                     'CPAN_USERID' => $userid,
                     'CPAN_VERSION' => $version,
                     'CPAN_FILE' => $dist,
                    );
        }

        # instantiate a distribution object
        if ($CPAN::META->exists('CPAN::Distribution',$dist)) {
        # we do not need CONTAINSMODS unless we do something with
        # this dist, so we better produce it on demand.

        ## my $obj = $CPAN::META->instance(
        ##                                 'CPAN::Distribution' => $dist
        ##                                );
        ## $obj->{CONTAINSMODS}{$mod} = undef; # experimental
        } else {
            $CPAN::META->instance(
                                  'CPAN::Distribution' => $dist
                                 )->set(
                                        'CPAN_USERID' => $userid,
                                        'CPAN_COMMENT' => $comment,
                                       );
        }
        if ($secondtime) {
            for my $name ($mod,$dist) {
                # $self->debug("exists name[$name]") if $CPAN::DEBUG;
                $exists{$name} = undef;
            }
        }
        $i++;
        while (($painted/76) < ($i/@lines)) {
            $CPAN::Frontend->myprint(".");
            $painted++;
        }
        return if $CPAN::Signal;
    }
    $CPAN::Frontend->myprint("DONE\n");
    if ($secondtime) {
        for my $class (qw(CPAN::Module CPAN::Bundle CPAN::Distribution)) {
            for my $o ($CPAN::META->all_objects($class)) {
                next if exists $exists{$o->{ID}};
                $CPAN::META->delete($class,$o->{ID});
                # CPAN->debug("deleting ID[$o->{ID}] in class[$class]")
                #     if $CPAN::DEBUG;
            }
        }
    }
}

#-> sub CPAN::Index::rd_modlist ;
sub rd_modlist {
    my($cl,$index_target) = @_;
    return unless defined $index_target;
    return if CPAN::_sqlite_running();
    $CPAN::Frontend->myprint("Reading '$index_target'\n");
    my $fh = CPAN::Tarzip->TIEHANDLE($index_target);
    local $_;
    my $slurp = "";
    my $chunk;
    while (my $bytes = $fh->READ(\$chunk,8192)) {
        $slurp.=$chunk;
    }
    my @eval2 = split /\012/, $slurp;

    while (@eval2) {
        my $shift = shift(@eval2);
        if ($shift =~ /^Date:\s+(.*)/) {
            if ($DATE_OF_03 eq $1) {
                $CPAN::Frontend->myprint("Unchanged.\n");
                return;
            }
            ($DATE_OF_03) = $1;
        }
        last if $shift =~ /^\s*$/;
    }
    push @eval2, q{CPAN::Modulelist->data;};
    local($^W) = 0;
    my($compmt) = Safe->new("CPAN::Safe1");
    my($eval2) = join("\n", @eval2);
    CPAN->debug(sprintf "length of eval2[%d]", length $eval2) if $CPAN::DEBUG;
    my $ret = $compmt->reval($eval2);
    Carp::confess($@) if $@;
    return if $CPAN::Signal;
    my $i = 0;
    my $until = keys(%$ret);
    my $painted = 0;
    CPAN->debug(sprintf "until[%d]", $until) if $CPAN::DEBUG;
    for (sort keys %$ret) {
        my $obj = $CPAN::META->instance("CPAN::Module",$_);
        delete $ret->{$_}{modid}; # not needed here, maybe elsewhere
        $obj->set(%{$ret->{$_}});
        $i++;
        while (($painted/76) < ($i/$until)) {
            $CPAN::Frontend->myprint(".");
            $painted++;
        }
        return if $CPAN::Signal;
    }
    $CPAN::Frontend->myprint("DONE\n");
}

#-> sub CPAN::Index::write_metadata_cache ;
sub write_metadata_cache {
    my($self) = @_;
    return unless $CPAN::Config->{'cache_metadata'};
    return if CPAN::_sqlite_running();
    return unless $CPAN::META->has_usable("Storable");
    my $cache;
    foreach my $k (qw(CPAN::Bundle CPAN::Author CPAN::Module
                      CPAN::Distribution)) {
        $cache->{$k} = $CPAN::META->{readonly}{$k}; # unsafe meta access, ok
    }
    my $metadata_file = File::Spec->catfile($CPAN::Config->{cpan_home},"Metadata");
    $cache->{last_time} = $LAST_TIME;
    $cache->{DATE_OF_02} = $DATE_OF_02;
    $cache->{PROTOCOL} = PROTOCOL;
    $CPAN::Frontend->myprint("Writing $metadata_file\n");
    eval { Storable::nstore($cache, $metadata_file) };
    $CPAN::Frontend->mywarn($@) if $@; # ?? missing "\n" after $@ in mywarn ??
}

#-> sub CPAN::Index::read_metadata_cache ;
sub read_metadata_cache {
    my($self) = @_;
    return unless $CPAN::Config->{'cache_metadata'};
    return if CPAN::_sqlite_running();
    return unless $CPAN::META->has_usable("Storable");
    my $metadata_file = File::Spec->catfile($CPAN::Config->{cpan_home},"Metadata");
    return unless -r $metadata_file and -f $metadata_file;
    $CPAN::Frontend->myprint("Reading '$metadata_file'\n");
    my $cache;
    eval { $cache = Storable::retrieve($metadata_file) };
    $CPAN::Frontend->mywarn($@) if $@; # ?? missing "\n" after $@ in mywarn ??
    if (!$cache || !UNIVERSAL::isa($cache, 'HASH')) {
        $LAST_TIME = 0;
        return;
    }
    if (exists $cache->{PROTOCOL}) {
        if (PROTOCOL > $cache->{PROTOCOL}) {
            $CPAN::Frontend->mywarn(sprintf("Ignoring Metadata cache written ".
                                            "with protocol v%s, requiring v%s\n",
                                            $cache->{PROTOCOL},
                                            PROTOCOL)
                                   );
            return;
        }
    } else {
        $CPAN::Frontend->mywarn("Ignoring Metadata cache written ".
                                "with protocol v1.0\n");
        return;
    }
    my $clcnt = 0;
    my $idcnt = 0;
    while(my($class,$v) = each %$cache) {
        next unless $class =~ /^CPAN::/;
        $CPAN::META->{readonly}{$class} = $v; # unsafe meta access, ok
        while (my($id,$ro) = each %$v) {
            $CPAN::META->{readwrite}{$class}{$id} ||=
                $class->new(ID=>$id, RO=>$ro);
            $idcnt++;
        }
        $clcnt++;
    }
    unless ($clcnt) { # sanity check
        $CPAN::Frontend->myprint("Warning: Found no data in $metadata_file\n");
        return;
    }
    if ($idcnt < 1000) {
        $CPAN::Frontend->myprint("Warning: Found only $idcnt objects ".
                                 "in $metadata_file\n");
        return;
    }
    $CPAN::META->{PROTOCOL} ||=
        $cache->{PROTOCOL}; # reading does not up or downgrade, but it
                            # does initialize to some protocol
    $LAST_TIME = $cache->{last_time};
    $DATE_OF_02 = $cache->{DATE_OF_02};
    $CPAN::Frontend->myprint("  Database was generated on $DATE_OF_02\n")
        if defined $DATE_OF_02; # An old cache may not contain DATE_OF_02
    return;
}

1;
PK7N%[�7=$$perl5/CPAN/FirstTime.pmnu��6�$# -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*-
# vim: ts=4 sts=4 sw=4:
package CPAN::FirstTime;
use strict;

use ExtUtils::MakeMaker ();
use FileHandle ();
use File::Basename ();
use File::Path ();
use File::Spec ();
use CPAN::Mirrors ();
use CPAN::Version ();
use vars qw($VERSION $auto_config);
$VERSION = "5.5317";

=head1 NAME

CPAN::FirstTime - Utility for CPAN::Config file Initialization

=head1 SYNOPSIS

CPAN::FirstTime::init()

=head1 DESCRIPTION

The init routine asks a few questions and writes a CPAN/Config.pm or
CPAN/MyConfig.pm file (depending on what it is currently using).

In the following all questions and explanations regarding config
variables are collected.

=cut

# down until the next =back the manpage must be parsed by the program
# because the text is used in the init dialogues.

my @podpara = split /\n\n/, <<'=back';

=over 2

=item allow_installing_module_downgrades

The CPAN shell can watch the C<blib/> directories that are built up
before running C<make test> to determine whether the current
distribution will end up with modules being overwritten with decreasing module version numbers. It
can then let the build of this distro fail when it discovers a
downgrade.

Do you want to allow installing distros with decreasing module
versions compared to what you have installed (yes, no, ask/yes,
ask/no)?

=item allow_installing_outdated_dists

The CPAN shell can watch the C<blib/> directories that are built up
before running C<make test> to determine whether the current
distribution contains modules that are indexed with a distro with a
higher distro-version number than the current one. It can
then let the build of this distro fail when it would not represent the
most up-to-date version of the distro.

Note: choosing anything but 'yes' for this option will need
CPAN::DistnameInfo being installed for taking effect.

Do you want to allow installing distros that are not indexed as the
highest distro-version for all contained modules (yes, no, ask/yes,
ask/no)?

=item auto_commit

Normally CPAN.pm keeps config variables in memory and changes need to
be saved in a separate 'o conf commit' command to make them permanent
between sessions. If you set the 'auto_commit' option to true, changes
to a config variable are always automatically committed to disk.

Always commit changes to config variables to disk?

=item build_cache

CPAN.pm can limit the size of the disk area for keeping the build
directories with all the intermediate files.

Cache size for build directory (in MB)?

=item build_dir

Directory where the build process takes place?

=item build_dir_reuse

Until version 1.88 CPAN.pm never trusted the contents of the build_dir
directory between sessions. Since 1.88_58 CPAN.pm has a YAML-based
mechanism that makes it possible to share the contents of the
build_dir/ directory between different sessions with the same version
of perl. People who prefer to test things several days before
installing will like this feature because it saves a lot of time.

If you say yes to the following question, CPAN will try to store
enough information about the build process so that it can pick up in
future sessions at the same state of affairs as it left a previous
session.

Store and re-use state information about distributions between
CPAN.pm sessions?

=item build_requires_install_policy

When a module declares another one as a 'build_requires' prerequisite
this means that the other module is only needed for building or
testing the module but need not be installed permanently. In this case
you may wish to install that other module nonetheless or just keep it
in the 'build_dir' directory to have it available only temporarily.
Installing saves time on future installations but makes the perl
installation bigger.

You can choose if you want to always install (yes), never install (no)
or be always asked. In the latter case you can set the default answer
for the question to yes (ask/yes) or no (ask/no).

Policy on installing 'build_requires' modules (yes, no, ask/yes,
ask/no)?

=item cache_metadata

To considerably speed up the initial CPAN shell startup, it is
possible to use Storable to create a cache of metadata. If Storable is
not available, the normal index mechanism will be used.

Note: this mechanism is not used when use_sqlite is on and SQLite is
running.

Cache metadata (yes/no)?

=item check_sigs

CPAN packages can be digitally signed by authors and thus verified
with the security provided by strong cryptography. The exact mechanism
is defined in the Module::Signature module. While this is generally
considered a good thing, it is not always convenient to the end user
to install modules that are signed incorrectly or where the key of the
author is not available or where some prerequisite for
Module::Signature has a bug and so on.

With the check_sigs parameter you can turn signature checking on and
off. The default is off for now because the whole tool chain for the
functionality is not yet considered mature by some. The author of
CPAN.pm would recommend setting it to true most of the time and
turning it off only if it turns out to be annoying.

Note that if you do not have Module::Signature installed, no signature
checks will be performed at all.

Always try to check and verify signatures if a SIGNATURE file is in
the package and Module::Signature is installed (yes/no)?

=item cleanup_after_install

Users who install modules and do not intend to look back, can free
occupied disk space quickly by letting CPAN.pm cleanup each build
directory immediately after a successful install.

Remove build directory after a successful install? (yes/no)?

=item colorize_output

When you have Term::ANSIColor installed, you can turn on colorized
output to have some visual differences between normal CPAN.pm output,
warnings, debugging output, and the output of the modules being
installed. Set your favorite colors after some experimenting with the
Term::ANSIColor module.

Please note that on Windows platforms colorized output also requires
the Win32::Console::ANSI module.

Do you want to turn on colored output?

=item colorize_print

Color for normal output?

=item colorize_warn

Color for warnings?

=item colorize_debug

Color for debugging messages?

=item commandnumber_in_prompt

The prompt of the cpan shell can contain the current command number
for easier tracking of the session or be a plain string.

Do you want the command number in the prompt (yes/no)?

=item connect_to_internet_ok

If you have never defined your own C<urllist> in your configuration
then C<CPAN.pm> will be hesitant to use the built in default sites for
downloading. It will ask you once per session if a connection to the
internet is OK and only if you say yes, it will try to connect. But to
avoid this question, you can choose your favorite download sites once
and get away with it. Or, if you have no favorite download sites
answer yes to the following question.

If no urllist has been chosen yet, would you prefer CPAN.pm to connect
to the built-in default sites without asking? (yes/no)?

=item ftp_passive

Shall we always set the FTP_PASSIVE environment variable when dealing
with ftp download (yes/no)?

=item ftpstats_period

Statistics about downloads are truncated by size and period
simultaneously.

How many days shall we keep statistics about downloads?

=item ftpstats_size

Statistics about downloads are truncated by size and period
simultaneously. Setting this to zero or negative disables download
statistics.

How many items shall we keep in the statistics about downloads?

=item getcwd

CPAN.pm changes the current working directory often and needs to
determine its own current working directory. Per default it uses
Cwd::cwd but if this doesn't work on your system for some reason,
alternatives can be configured according to the following table:

    cwd         Cwd::cwd
    getcwd      Cwd::getcwd
    fastcwd     Cwd::fastcwd
    getdcwd     Cwd::getdcwd
    backtickcwd external command cwd

Preferred method for determining the current working directory?

=item halt_on_failure

Normally, CPAN.pm continues processing the full list of targets and
dependencies, even if one of them fails.  However, you can specify
that CPAN should halt after the first failure.  (Note that optional
recommended or suggested modules that fail will not cause a halt.)

Do you want to halt on failure (yes/no)?

=item histfile

If you have one of the readline packages (Term::ReadLine::Perl,
Term::ReadLine::Gnu, possibly others) installed, the interactive CPAN
shell will have history support. The next two questions deal with the
filename of the history file and with its size. If you do not want to
set this variable, please hit SPACE ENTER to the following question.

File to save your history?

=item histsize

Number of lines to save?

=item inactivity_timeout

Sometimes you may wish to leave the processes run by CPAN alone
without caring about them. Because the Makefile.PL or the Build.PL
sometimes contains question you're expected to answer, you can set a
timer that will kill a 'perl Makefile.PL' process after the specified
time in seconds.

If you set this value to 0, these processes will wait forever. This is
the default and recommended setting.

Timeout for inactivity during {Makefile,Build}.PL?

=item index_expire

The CPAN indexes are usually rebuilt once or twice per hour, but the
typical CPAN mirror mirrors only once or twice per day. Depending on
the quality of your mirror and your desire to be on the bleeding edge,
you may want to set the following value to more or less than one day
(which is the default). It determines after how many days CPAN.pm
downloads new indexes.

Let the index expire after how many days?

=item inhibit_startup_message

When the CPAN shell is started it normally displays a greeting message
that contains the running version and the status of readline support.

Do you want to turn this message off?

=item keep_source_where

Unless you are accessing the CPAN on your filesystem via a file: URL,
CPAN.pm needs to keep the source files it downloads somewhere. Please
supply a directory where the downloaded files are to be kept.

Download target directory?

=item load_module_verbosity

When CPAN.pm loads a module it needs for some optional feature, it
usually reports about module name and version. Choose 'v' to get this
message, 'none' to suppress it.

Verbosity level for loading modules (none or v)?

=item makepl_arg

Every Makefile.PL is run by perl in a separate process. Likewise we
run 'make' and 'make install' in separate processes. If you have
any parameters (e.g. PREFIX, UNINST or the like) you want to
pass to the calls, please specify them here.

If you don't understand this question, just press ENTER.

Typical frequently used settings:

    PREFIX=~/perl    # non-root users (please see manual for more hints)

Parameters for the 'perl Makefile.PL' command?

=item make_arg

Parameters for the 'make' command? Typical frequently used setting:

    -j3              # dual processor system (on GNU make)

Your choice:

=item make_install_arg

Parameters for the 'make install' command?
Typical frequently used setting:

    UNINST=1         # to always uninstall potentially conflicting files
                     # (but do NOT use with local::lib or INSTALL_BASE)

Your choice:

=item make_install_make_command

Do you want to use a different make command for 'make install'?
Cautious people will probably prefer:

    su root -c make
 or
    sudo make
 or
    /path1/to/sudo -u admin_account /path2/to/make

or some such. Your choice:

=item mbuildpl_arg

A Build.PL is run by perl in a separate process. Likewise we run
'./Build' and './Build install' in separate processes. If you have any
parameters you want to pass to the calls, please specify them here.

Typical frequently used settings:

    --install_base /home/xxx             # different installation directory

Parameters for the 'perl Build.PL' command?

=item mbuild_arg

Parameters for the './Build' command? Setting might be:

    --extra_linker_flags -L/usr/foo/lib  # non-standard library location

Your choice:

=item mbuild_install_arg

Parameters for the './Build install' command? Typical frequently used
setting:

    --uninst 1       # uninstall conflicting files
                     # (but do NOT use with local::lib or INSTALL_BASE)

Your choice:

=item mbuild_install_build_command

Do you want to use a different command for './Build install'? Sudo
users will probably prefer:

    su root -c ./Build
 or
    sudo ./Build
 or
    /path1/to/sudo -u admin_account ./Build

or some such. Your choice:

=item pager

What is your favorite pager program?

=item prefer_installer

When you have Module::Build installed and a module comes with both a
Makefile.PL and a Build.PL, which shall have precedence?

The main two standard installer modules are the old and well
established ExtUtils::MakeMaker (for short: EUMM) which uses the
Makefile.PL. And the next generation installer Module::Build (MB)
which works with the Build.PL (and often comes with a Makefile.PL
too). If a module comes only with one of the two we will use that one
but if both are supplied then a decision must be made between EUMM and
MB. See also http://rt.cpan.org/Ticket/Display.html?id=29235 for a
discussion about the right default.

Or, as a third option you can choose RAND which will make a random
decision (something regular CPAN testers will enjoy).

In case you can choose between running a Makefile.PL or a Build.PL,
which installer would you prefer (EUMM or MB or RAND)?

=item prefs_dir

CPAN.pm can store customized build environments based on regular
expressions for distribution names. These are YAML files where the
default options for CPAN.pm and the environment can be overridden and
dialog sequences can be stored that can later be executed by an
Expect.pm object. The CPAN.pm distribution comes with some prefab YAML
files that cover sample distributions that can be used as blueprints
to store your own prefs. Please check out the distroprefs/ directory of
the CPAN.pm distribution to get a quick start into the prefs system.

Directory where to store default options/environment/dialogs for
building modules that need some customization?

=item prerequisites_policy

The CPAN module can detect when a module which you are trying to build
depends on prerequisites. If this happens, it can build the
prerequisites for you automatically ('follow'), ask you for
confirmation ('ask'), or just ignore them ('ignore').  Choosing
'follow' also sets PERL_AUTOINSTALL and PERL_EXTUTILS_AUTOINSTALL for
"--defaultdeps" if not already set.

Please set your policy to one of the three values.

Policy on building prerequisites (follow, ask or ignore)?

=item pushy_https

Boolean. Defaults to true. If this option is true, the cpan shell will
use https://cpan.org/ to download stuff from the CPAN. It will fall
back to http://cpan.org/ if it can't handle https for some reason
(missing modules, missing programs). Whenever it falls back to the
http protocol, it will issue a warning.

If this option is true, the option C<urllist> will be ignored.
Consequently, if you want to work with local mirrors via your own
configured list of URLs, you will have to choose no below.

Do you want to turn the pushy_https behaviour on?

=item randomize_urllist

CPAN.pm can introduce some randomness when using hosts for download
that are configured in the urllist parameter. Enter a numeric value
between 0 and 1 to indicate how often you want to let CPAN.pm try a
random host from the urllist. A value of one specifies to always use a
random host as the first try. A value of zero means no randomness at
all. Anything in between specifies how often, on average, a random
host should be tried first.

Randomize parameter

=item recommends_policy

(Experimental feature!) Some CPAN modules recommend additional, optional dependencies.  These should
generally be installed except in resource constrained environments.  When this
policy is true, recommended modules will be included with required modules.

Include recommended modules?

=item scan_cache

By default, each time the CPAN module is started, cache scanning is
performed to keep the cache size in sync ('atstart'). Alternatively,
scanning and cleanup can happen when CPAN exits ('atexit'). To prevent
any cache cleanup, answer 'never'.

Perform cache scanning ('atstart', 'atexit' or 'never')?

=item shell

What is your favorite shell?

=item show_unparsable_versions

During the 'r' command CPAN.pm finds modules without version number.
When the command finishes, it prints a report about this. If you
want this report to be very verbose, say yes to the following
variable.

Show all individual modules that have no $VERSION?

=item show_upload_date

The 'd' and the 'm' command normally only show you information they
have in their in-memory database and thus will never connect to the
internet. If you set the 'show_upload_date' variable to true, 'm' and
'd' will additionally show you the upload date of the module or
distribution. Per default this feature is off because it may require a
net connection to get at the upload date.

Always try to show upload date with 'd' and 'm' command (yes/no)?

=item show_zero_versions

During the 'r' command CPAN.pm finds modules with a version number of
zero. When the command finishes, it prints a report about this. If you
want this report to be very verbose, say yes to the following
variable.

Show all individual modules that have a $VERSION of zero?

=item suggests_policy

(Experimental feature!) Some CPAN modules suggest additional, optional dependencies.  These 'suggest'
dependencies provide enhanced operation.  When this policy is true, suggested
modules will be included with required modules.

Include suggested modules?

=item tar_verbosity

When CPAN.pm uses the tar command, which switch for the verbosity
shall be used? Choose 'none' for quiet operation, 'v' for file
name listing, 'vv' for full listing.

Tar command verbosity level (none or v or vv)?

=item term_is_latin

The next option deals with the charset (a.k.a. character set) your
terminal supports. In general, CPAN is English speaking territory, so
the charset does not matter much but some CPAN have names that are
outside the ASCII range. If your terminal supports UTF-8, you should
say no to the next question. If it expects ISO-8859-1 (also known as
LATIN1) then you should say yes. If it supports neither, your answer
does not matter because you will not be able to read the names of some
authors anyway. If you answer no, names will be output in UTF-8.

Your terminal expects ISO-8859-1 (yes/no)?

=item term_ornaments

When using Term::ReadLine, you can turn ornaments on so that your
input stands out against the output from CPAN.pm.

Do you want to turn ornaments on?

=item test_report

The goal of the CPAN Testers project (http://testers.cpan.org/) is to
test as many CPAN packages as possible on as many platforms as
possible.  This provides valuable feedback to module authors and
potential users to identify bugs or platform compatibility issues and
improves the overall quality and value of CPAN.

One way you can contribute is to send test results for each module
that you install.  If you install the CPAN::Reporter module, you have
the option to automatically generate and deliver test reports to CPAN
Testers whenever you run tests on a CPAN package.

See the CPAN::Reporter documentation for additional details and
configuration settings.  If your firewall blocks outgoing traffic,
you may need to configure CPAN::Reporter before sending reports.

Generate test reports if CPAN::Reporter is installed (yes/no)?

=item perl5lib_verbosity

When CPAN.pm extends @INC via PERL5LIB, it prints a list of
directories added (or a summary of how many directories are
added).  Choose 'v' to get this message, 'none' to suppress it.

Verbosity level for PERL5LIB changes (none or v)?

=item prefer_external_tar

Per default all untar operations are done with the perl module
Archive::Tar; by setting this variable to true the external tar
command is used if available; on Unix this is usually preferred
because they have a reliable and fast gnutar implementation.

Use the external tar program instead of Archive::Tar?

=item trust_test_report_history

When a distribution has already been tested by CPAN::Reporter on
this machine, CPAN can skip the test phase and just rely on the
test report history instead.

Note that this will not apply to distributions that failed tests
because of missing dependencies.  Also, tests can be run
regardless of the history using "force".

Do you want to rely on the test report history (yes/no)?

=item urllist_ping_external

When automatic selection of the nearest cpan mirrors is performed,
turn on the use of the external ping via Net::Ping::External. This is
recommended in the case the local network has a transparent proxy.

Do you want to use the external ping command when autoselecting
mirrors?

=item urllist_ping_verbose

When automatic selection of the nearest cpan mirrors is performed,
this option can be used to turn on verbosity during the selection
process.

Do you want to see verbosity turned on when autoselecting mirrors?

=item use_prompt_default

When this is true, CPAN will set PERL_MM_USE_DEFAULT to a true
value.  This causes ExtUtils::MakeMaker (and compatible) prompts
to use default values instead of stopping to prompt you to answer
questions. It also sets NONINTERACTIVE_TESTING to a true value to
signal more generally that distributions should not try to
interact with you.

Do you want to use prompt defaults (yes/no)?

=item use_sqlite

CPAN::SQLite is a layer between the index files that are downloaded
from the CPAN and CPAN.pm that speeds up metadata queries and reduces
memory consumption of CPAN.pm considerably.

Use CPAN::SQLite if available? (yes/no)?

=item version_timeout

This timeout prevents CPAN from hanging when trying to parse a
pathologically coded $VERSION from a module.

The default is 15 seconds.  If you set this value to 0, no timeout
will occur, but this is not recommended.

Timeout for parsing module versions?

=item yaml_load_code

Both YAML.pm and YAML::Syck are capable of deserialising code. As this
requires a string eval, which might be a security risk, you can use
this option to enable or disable the deserialisation of code via
CPAN::DeferredCode. (Note: This does not work under perl 5.6)

Do you want to enable code deserialisation (yes/no)?

=item yaml_module

At the time of this writing (2009-03) there are three YAML
implementations working: YAML, YAML::Syck, and YAML::XS. The latter
two are faster but need a C compiler installed on your system. There
may be more alternative YAML conforming modules. When I tried two
other players, YAML::Tiny and YAML::Perl, they seemed not powerful
enough to work with CPAN.pm. This may have changed in the meantime.

Which YAML implementation would you prefer?

=back

=head1 LICENSE

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

=cut

use vars qw( %prompts );

{

    my @prompts = (

auto_config => qq{
CPAN.pm requires configuration, but most of it can be done automatically.
If you answer 'no' below, you will enter an interactive dialog for each
configuration option instead.

Would you like to configure as much as possible automatically?},

auto_pick => qq{
Would you like me to automatically choose some CPAN mirror
sites for you? (This means connecting to the Internet)},

config_intro => qq{

The following questions are intended to help you with the
configuration. The CPAN module needs a directory of its own to cache
important index files and maybe keep a temporary mirror of CPAN files.
This may be a site-wide or a personal directory.

},

# cpan_home => qq{ },

cpan_home_where => qq{

First of all, I'd like to create this directory. Where?

},

external_progs => qq{

The CPAN module will need a few external programs to work properly.
Please correct me, if I guess the wrong path for a program. Don't
panic if you do not have some of them, just press ENTER for those. To
disable the use of a program, you can type a space followed by ENTER.

},

proxy_intro => qq{

If you're accessing the net via proxies, you can specify them in the
CPAN configuration or via environment variables. The variable in
the \$CPAN::Config takes precedence.

},

proxy_user => qq{

If your proxy is an authenticating proxy, you can store your username
permanently. If you do not want that, just press ENTER. You will then
be asked for your username in every future session.

},

proxy_pass => qq{

Your password for the authenticating proxy can also be stored
permanently on disk. If this violates your security policy, just press
ENTER. You will then be asked for the password in every future
session.

},

urls_intro => qq{
Now you need to choose your CPAN mirror sites.  You can let me
pick mirrors for you, you can select them from a list or you
can enter them by hand.
},

urls_picker_intro => qq{First, pick a nearby continent and country by typing in the number(s)
in front of the item(s) you want to select. You can pick several of
each, separated by spaces. Then, you will be presented with a list of
URLs of CPAN mirrors in the countries you selected, along with
previously selected URLs. Select some of those URLs, or just keep the
old list. Finally, you will be prompted for any extra URLs -- file:,
ftp:, or http: -- that host a CPAN mirror.

You should select more than one (just in case the first isn't available).

},

password_warn => qq{

Warning: Term::ReadKey seems not to be available, your password will
be echoed to the terminal!

},

install_help => qq{
Warning: You do not have write permission for Perl library directories.

To install modules, you need to configure a local Perl library directory or
escalate your privileges.  CPAN can help you by bootstrapping the local::lib
module or by configuring itself to use 'sudo' (if available).  You may also
resolve this problem manually if you need to customize your setup.

What approach do you want?  (Choose 'local::lib', 'sudo' or 'manual')
},

local_lib_installed => qq{
local::lib is installed. You must now add the following environment variables
to your shell configuration files (or registry, if you are on Windows) and
then restart your command line shell and CPAN before installing modules:

},

              );

    die "Coding error in \@prompts declaration.  Odd number of elements, above"
        if (@prompts % 2);

    %prompts = @prompts;

    if (scalar(keys %prompts) != scalar(@prompts)/2) {
        my %already;
        for my $item (0..$#prompts) {
            next if $item % 2;
            die "$prompts[$item] is duplicated\n" if $already{$prompts[$item]}++;
        }
    }

    shift @podpara;
    while (@podpara) {
        warn "Alert: cannot parse my own manpage for init dialog" unless $podpara[0] =~ s/^=item\s+//;
        my $name = shift @podpara;
        my @para;
        while (@podpara && $podpara[0] !~ /^=item/) {
            push @para, shift @podpara;
        }
        $prompts{$name} = pop @para;
        if (@para) {
            $prompts{$name . "_intro"} = join "", map { "$_\n\n" } @para;
        }
    }

}

sub init {
    my($configpm, %args) = @_;
    use Config;
    # extra args after 'o conf init'
    my $matcher = $args{args} && @{$args{args}} ? $args{args}[0] : '';
    if ($matcher =~ /^\/(.*)\/$/) {
        # case /regex/ => take the first, ignore the rest
        $matcher = $1;
        shift @{$args{args}};
        if (@{$args{args}}) {
            local $" = " ";
            $CPAN::Frontend->mywarn("Ignoring excessive arguments '@{$args{args}}'");
            $CPAN::Frontend->mysleep(2);
        }
    } elsif (0 == length $matcher) {
    } elsif (0 && $matcher eq "~") { # extremely buggy, but a nice idea
        my @unconfigured = sort grep { not exists $CPAN::Config->{$_}
                                      or not defined $CPAN::Config->{$_}
                                          or not length $CPAN::Config->{$_}
                                  } keys %$CPAN::Config;
        $matcher = "\\b(".join("|", @unconfigured).")\\b";
        $CPAN::Frontend->mywarn("matcher[$matcher]");
    } else {
        # case WORD... => all arguments must be valid
        for my $arg (@{$args{args}}) {
            unless (exists $CPAN::HandleConfig::keys{$arg}) {
                $CPAN::Frontend->mywarn("'$arg' is not a valid configuration variable\n");
                return;
            }
        }
        $matcher = "\\b(".join("|",@{$args{args}}).")\\b";
    }
    CPAN->debug("matcher[$matcher]") if $CPAN::DEBUG;

    unless ($CPAN::VERSION) {
        require CPAN::Nox;
    }
    require CPAN::HandleConfig;
    CPAN::HandleConfig::require_myconfig_or_config();
    $CPAN::Config ||= {};
    local($/) = "\n";
    local($\) = "";
    local($|) = 1;

    my($ans,$default); # why so half global?

    #
    #= Files, directories
    #

    local *_real_prompt;
    if ( $args{autoconfig} ) {
        $auto_config = 1;
    } elsif ($matcher) {
        $auto_config = 0;
    } else {
        my $_conf = prompt($prompts{auto_config}, "yes");
        $auto_config = ($_conf and $_conf =~ /^y/i) ? 1 : 0;
    }
    CPAN->debug("auto_config[$auto_config]") if $CPAN::DEBUG;
    if ( $auto_config ) {
            local $^W = 0;
            # prototype should match that of &MakeMaker::prompt
            my $current_second = time;
            my $current_second_count = 0;
            my $i_am_mad = 0;
            # silent prompting -- just quietly use default
            *_real_prompt = sub { return $_[1] };
    }

    #
    # bootstrap local::lib or sudo
    #
    unless ( $matcher
        || _can_write_to_libdirs() || _using_installbase() || _using_sudo()
    ) {
        local $auto_config = 0; # We *must* ask, even under autoconfig
        local *_real_prompt;    # We *must* show prompt
        my_prompt_loop(install_help => 'local::lib', $matcher,
                   'local::lib|sudo|manual');
    }
    $CPAN::Config->{install_help} ||= ''; # Temporary to suppress warnings

    if (!$matcher or q{
                       build_dir
                       build_dir_reuse
                       cpan_home
                       keep_source_where
                       prefs_dir
                      } =~ /$matcher/) {
        $CPAN::Frontend->myprint($prompts{config_intro}) unless $auto_config;

        init_cpan_home($matcher);

        my_dflt_prompt("keep_source_where",
                       File::Spec->catdir($CPAN::Config->{cpan_home},"sources"),
                       $matcher,
                      );
        my_dflt_prompt("build_dir",
                       File::Spec->catdir($CPAN::Config->{cpan_home},"build"),
                       $matcher
                      );
        my_yn_prompt(build_dir_reuse => 0, $matcher);
        my_dflt_prompt("prefs_dir",
                       File::Spec->catdir($CPAN::Config->{cpan_home},"prefs"),
                       $matcher
                      );
    }

    #
    #= Config: auto_commit
    #

    my_yn_prompt(auto_commit => 0, $matcher);

    #
    #= Cache size, Index expire
    #
    my_dflt_prompt(build_cache => 100, $matcher);

    my_dflt_prompt(index_expire => 1, $matcher);
    my_prompt_loop(scan_cache => 'atstart', $matcher, 'atstart|atexit|never');
    my_yn_prompt(cleanup_after_install => 0, $matcher);

    #
    #= cache_metadata
    #

    my_yn_prompt(cache_metadata => 1, $matcher);
    my_yn_prompt(use_sqlite => 0, $matcher);

    #
    #= Do we follow PREREQ_PM?
    #

    my_prompt_loop(prerequisites_policy => 'follow', $matcher,
                   'follow|ask|ignore');
    my_prompt_loop(build_requires_install_policy => 'yes', $matcher,
                   'yes|no|ask/yes|ask/no');
    my_yn_prompt(recommends_policy => 1, $matcher);
    my_yn_prompt(suggests_policy => 0, $matcher);

    #
    #= Module::Signature
    #
    my_yn_prompt(check_sigs => 0, $matcher);

    #
    #= CPAN::Reporter
    #
    if (!$matcher or 'test_report' =~ /$matcher/) {
        my_yn_prompt(test_report => 0, $matcher);
        if (
            $matcher &&
            $CPAN::Config->{test_report} &&
            $CPAN::META->has_inst("CPAN::Reporter") &&
            CPAN::Reporter->can('configure')
           ) {
            my $_conf = prompt("Would you like me configure CPAN::Reporter now?", "yes");
            if ($_conf =~ /^y/i) {
              $CPAN::Frontend->myprint("\nProceeding to configure CPAN::Reporter.\n");
              CPAN::Reporter::configure();
              $CPAN::Frontend->myprint("\nReturning to CPAN configuration.\n");
            }
        }
    }

    my_yn_prompt(trust_test_report_history => 0, $matcher);

    #
    #= YAML vs. YAML::Syck
    #
    if (!$matcher or "yaml_module" =~ /$matcher/) {
        my_dflt_prompt(yaml_module => "YAML", $matcher);
        my $old_v = $CPAN::Config->{load_module_verbosity};
        $CPAN::Config->{load_module_verbosity} = q[none];
        if (!$auto_config && !$CPAN::META->has_inst($CPAN::Config->{yaml_module})) {
            $CPAN::Frontend->mywarn
                ("Warning (maybe harmless): '$CPAN::Config->{yaml_module}' not installed.\n");
            $CPAN::Frontend->mysleep(3);
        }
        $CPAN::Config->{load_module_verbosity} = $old_v;
    }

    #
    #= YAML code deserialisation
    #
    my_yn_prompt(yaml_load_code => 0, $matcher);

    #
    #= External programs
    #
    my(@path) = split /$Config{'path_sep'}/, $ENV{'PATH'};
    $CPAN::Frontend->myprint($prompts{external_progs})
        if !$matcher && !$auto_config;
    _init_external_progs($matcher, {
        path => \@path,
        progs => [ qw/make bzip2 gzip tar unzip gpg patch applypatch/ ],
        shortcut => 0
      });
    _init_external_progs($matcher, {
        path => \@path,
        progs => [ qw/wget curl lynx ncftpget ncftp ftp/ ],
        shortcut => 1
      });

    {
        my $path = $CPAN::Config->{'pager'} ||
            $ENV{PAGER} || find_exe("less",\@path) ||
                find_exe("more",\@path) || ($^O eq 'MacOS' ? $ENV{EDITOR} : 0 )
                    || "more";
        my_dflt_prompt(pager => $path, $matcher);
    }

    {
        my $path = $CPAN::Config->{'shell'};
        if ($path && File::Spec->file_name_is_absolute($path)) {
            $CPAN::Frontend->mywarn("Warning: configured $path does not exist\n")
                unless -e $path;
            $path = "";
        }
        $path ||= $ENV{SHELL};
        $path ||= $ENV{COMSPEC} if $^O eq "MSWin32";
        if ($^O eq 'MacOS') {
            $CPAN::Config->{'shell'} = 'not_here';
        } else {
            $path ||= 'sh', $path =~ s,\\,/,g if $^O eq 'os2'; # Cosmetic only
            my_dflt_prompt(shell => $path, $matcher);
        }
    }

    {
        my $tar = $CPAN::Config->{tar};
        my $prefer_external_tar = $CPAN::Config->{prefer_external_tar}; # XXX not yet supported
        unless (defined $prefer_external_tar) {
            if ($^O =~ /(MSWin32|solaris)/) {
                # both have a record of broken tars
                $prefer_external_tar = 0;
            } elsif ($tar) {
                $prefer_external_tar = 1;
            } else {
                $prefer_external_tar = 0;
            }
        }
        my_yn_prompt(prefer_external_tar => $prefer_external_tar, $matcher);
    }

    #
    # verbosity
    #

    my_prompt_loop(tar_verbosity => 'none', $matcher,
                   'none|v|vv');
    my_prompt_loop(load_module_verbosity => 'none', $matcher,
                   'none|v');
    my_prompt_loop(perl5lib_verbosity => 'none', $matcher,
                   'none|v');
    my_yn_prompt(inhibit_startup_message => 0, $matcher);

    #
    #= Installer, arguments to make etc.
    #

    my_prompt_loop(prefer_installer => 'MB', $matcher, 'MB|EUMM|RAND');

    if (!$matcher or 'makepl_arg make_arg' =~ /$matcher/) {
        my_dflt_prompt(makepl_arg => "", $matcher);
        my_dflt_prompt(make_arg => "", $matcher);
        if ( $CPAN::Config->{makepl_arg} =~ /LIBS=|INC=/ ) {
            $CPAN::Frontend->mywarn(
                "Warning: Using LIBS or INC in makepl_arg will likely break distributions\n" .
                "that specify their own LIBS or INC options in Makefile.PL.\n"
            );
        }

    }

    require CPAN::HandleConfig;
    if (exists $CPAN::HandleConfig::keys{make_install_make_command}) {
        # as long as Windows needs $self->_build_command, we cannot
        # support sudo on windows :-)
        my $default = $CPAN::Config->{make} || "";
        if ( $default && $CPAN::Config->{install_help} eq 'sudo' ) {
            if ( find_exe('sudo') ) {
                $default = "sudo $default";
                delete $CPAN::Config->{make_install_make_command}
                    unless $CPAN::Config->{make_install_make_command} =~ /sudo/;
            }
            else {
                $CPAN::Frontend->mywarnonce("Could not find 'sudo' in PATH\n");
            }
        }
        my_dflt_prompt(make_install_make_command => $default, $matcher);
    }

    my_dflt_prompt(make_install_arg => $CPAN::Config->{make_arg} || "",
                   $matcher);

    my_dflt_prompt(mbuildpl_arg => "", $matcher);
    my_dflt_prompt(mbuild_arg => "", $matcher);

    if (exists $CPAN::HandleConfig::keys{mbuild_install_build_command}
        and $^O ne "MSWin32") {
        # as long as Windows needs $self->_build_command, we cannot
        # support sudo on windows :-)
        my $default = $^O eq 'VMS' ? '@Build.com' : "./Build";
        if ( $CPAN::Config->{install_help} eq 'sudo' ) {
            if ( find_exe('sudo') ) {
                $default = "sudo $default";
                delete $CPAN::Config->{mbuild_install_build_command}
                    unless $CPAN::Config->{mbuild_install_build_command} =~ /sudo/;
            }
            else {
                $CPAN::Frontend->mywarnonce("Could not find 'sudo' in PATH\n");
            }
        }
        my_dflt_prompt(mbuild_install_build_command => $default, $matcher);
    }

    my_dflt_prompt(mbuild_install_arg => "", $matcher);

    for my $o (qw(
        allow_installing_outdated_dists
        allow_installing_module_downgrades
        )) {
        my_prompt_loop($o => 'ask/no', $matcher,
                       'yes|no|ask/yes|ask/no');
    }

    #
    #== use_prompt_default
    #
    my_yn_prompt(use_prompt_default => 0, $matcher);

    #
    #= Alarm period
    #

    my_dflt_prompt(inactivity_timeout => 0, $matcher);
    my_dflt_prompt(version_timeout => 15, $matcher);

    #
    #== halt_on_failure
    #
    my_yn_prompt(halt_on_failure => 0, $matcher);

    #
    #= Proxies
    #

    my @proxy_vars = qw/ftp_proxy http_proxy no_proxy/;
    my @proxy_user_vars = qw/proxy_user proxy_pass/;
    if (!$matcher or "@proxy_vars @proxy_user_vars" =~ /$matcher/) {
        $CPAN::Frontend->myprint($prompts{proxy_intro}) unless $auto_config;

        for (@proxy_vars) {
            $prompts{$_} = "Your $_?";
            my_dflt_prompt($_ => $ENV{$_}||"", $matcher);
        }

        if ($CPAN::Config->{ftp_proxy} ||
            $CPAN::Config->{http_proxy}) {

            $default = $CPAN::Config->{proxy_user} || $CPAN::LWP::UserAgent::USER || "";

            $CPAN::Frontend->myprint($prompts{proxy_user}) unless $auto_config;

            if ($CPAN::Config->{proxy_user} = prompt("Your proxy user id?",$default)) {
                $CPAN::Frontend->myprint($prompts{proxy_pass}) unless $auto_config;

                if ($CPAN::META->has_inst("Term::ReadKey")) {
                    Term::ReadKey::ReadMode("noecho");
                } else {
                    $CPAN::Frontend->myprint($prompts{password_warn}) unless $auto_config;
                }
                $CPAN::Config->{proxy_pass} = prompt_no_strip("Your proxy password?");
                if ($CPAN::META->has_inst("Term::ReadKey")) {
                    Term::ReadKey::ReadMode("restore");
                }
                $CPAN::Frontend->myprint("\n\n") unless $auto_config;
            }
        }
    }

    #
    #= how plugins work
    #

    # XXX MISSING: my_array_prompt to be used with plugins. We did something like this near
    #     git log -p fd68f8f5e33f4cecea4fdb7abc5ee19c12f138f0..test-notest-test-dependency
    # Need to do similar steps for plugin_list. As long as we do not support it here, people
    # must use the cpan shell prompt to write something like
    #     o conf plugin_list push CPAN::Plugin::Specfile=dir,/tmp/foo-20141013,...
    #     o conf commit

    #
    #= how FTP works
    #

    my_yn_prompt(ftp_passive => 1, $matcher);

    #
    #= how cwd works
    #

    my_prompt_loop(getcwd => 'cwd', $matcher,
                   'cwd|getcwd|fastcwd|getdcwd|backtickcwd');

    #
    #= the CPAN shell itself (prompt, color)
    #

    my_yn_prompt(commandnumber_in_prompt => 1, $matcher);
    my_yn_prompt(term_ornaments => 1, $matcher);
    if ("colorize_output colorize_print colorize_warn colorize_debug" =~ $matcher) {
        my_yn_prompt(colorize_output => 0, $matcher);
        if ($CPAN::Config->{colorize_output}) {
            if ($CPAN::META->has_inst("Term::ANSIColor")) {
                my $T="gYw";
                $CPAN::Frontend->myprint( "                                      on_  on_y ".
                    "        on_ma           on_\n") unless $auto_config;
                $CPAN::Frontend->myprint( "                   on_black on_red  green ellow ".
                    "on_blue genta on_cyan white\n") unless $auto_config;

                for my $FG ("", "bold",
                            map {$_,"bold $_"} "black","red","green",
                            "yellow","blue",
                            "magenta",
                            "cyan","white") {
                    $CPAN::Frontend->myprint(sprintf( "%12s ", $FG)) unless $auto_config;
                    for my $BG ("",map {"on_$_"} qw(black red green yellow
                                                    blue magenta cyan white)) {
                            $CPAN::Frontend->myprint( $FG||$BG ?
                            Term::ANSIColor::colored("  $T  ","$FG $BG") : "  $T  ") unless $auto_config;
                    }
                    $CPAN::Frontend->myprint( "\n" ) unless $auto_config;
                }
                $CPAN::Frontend->myprint( "\n" ) unless $auto_config;
            }
            for my $tuple (
                           ["colorize_print", "bold blue on_white"],
                           ["colorize_warn", "bold red on_white"],
                           ["colorize_debug", "black on_cyan"],
                          ) {
                my_dflt_prompt($tuple->[0] => $tuple->[1], $matcher);
                if ($CPAN::META->has_inst("Term::ANSIColor")) {
                    eval { Term::ANSIColor::color($CPAN::Config->{$tuple->[0]})};
                    if ($@) {
                        $CPAN::Config->{$tuple->[0]} = $tuple->[1];
                        $CPAN::Frontend->mywarn($@."setting to default '$tuple->[1]'\n");
                    }
                }
            }
        }
    }

    #
    #== term_is_latin
    #

    my_yn_prompt(term_is_latin => 1, $matcher);

    #
    #== save history in file 'histfile'
    #

    if (!$matcher or 'histfile histsize' =~ /$matcher/) {
        $CPAN::Frontend->myprint($prompts{histfile_intro}) unless $auto_config;
        defined($default = $CPAN::Config->{histfile}) or
            $default = File::Spec->catfile($CPAN::Config->{cpan_home},"histfile");
        my_dflt_prompt(histfile => $default, $matcher);

        if ($CPAN::Config->{histfile}) {
            defined($default = $CPAN::Config->{histsize}) or $default = 100;
            my_dflt_prompt(histsize => $default, $matcher);
        }
    }

    #
    #== do an ls on the m or the d command
    #
    my_yn_prompt(show_upload_date => 0, $matcher);

    #
    #== verbosity at the end of the r command
    #
    if (!$matcher
        or 'show_unparsable_versions' =~ /$matcher/
        or 'show_zero_versions' =~ /$matcher/
       ) {
        my_yn_prompt(show_unparsable_versions => 0, $matcher);
        my_yn_prompt(show_zero_versions => 0, $matcher);
    }

    #
    #= MIRRORED.BY and conf_sites()
    #

    # Let's assume they want to use the internet and make them turn it
    # off if they really don't.
    my_yn_prompt("connect_to_internet_ok" => 1, $matcher);
    my_yn_prompt("pushy_https" => 1, $matcher);

    # Allow matching but don't show during manual config
    if ($matcher) {
        if ("urllist_ping_external" =~ $matcher) {
            my_yn_prompt(urllist_ping_external => 0, $matcher);
        }
        if ("urllist_ping_verbose" =~ $matcher) {
            my_yn_prompt(urllist_ping_verbose => 0, $matcher);
        }
        if ("randomize_urllist" =~ $matcher) {
            my_dflt_prompt(randomize_urllist => 0, $matcher);
        }
        if ("ftpstats_size" =~ $matcher) {
            my_dflt_prompt(ftpstats_size => 99, $matcher);
        }
        if ("ftpstats_period" =~ $matcher) {
            my_dflt_prompt(ftpstats_period => 14, $matcher);
        }
    }

    $CPAN::Config->{urllist} ||= [];

    if ($auto_config) {
        if(@{ $CPAN::Config->{urllist} }) {
            $CPAN::Frontend->myprint(
                "Your 'urllist' is already configured. Type 'o conf init urllist' to change it.\n"
            );
        }
        else {
            # Hint: as of 2021-11: to get http, use http://www.cpan.org/
            $CPAN::Config->{urllist} = [ 'https://cpan.org/' ];
            $CPAN::Frontend->myprint(
                "We initialized your 'urllist' to @{$CPAN::Config->{urllist}}. Type 'o conf init urllist' to change it.\n"
            );
        }
    }
    elsif (!$matcher || "urllist" =~ $matcher) {
        _do_pick_mirrors();
    }

    if ($auto_config) {
        $CPAN::Frontend->myprint(
            "\nAutoconfiguration complete.\n"
        );
        $auto_config = 0; # reset
    }

    # bootstrap local::lib now if requested
    if ( $CPAN::Config->{install_help} eq 'local::lib' ) {
        if ( ! @{ $CPAN::Config->{urllist} } ) {
            $CPAN::Frontend->myprint(
                "\nALERT: Skipping local::lib bootstrap because 'urllist' is not configured.\n"
            );
        }
        elsif (! $CPAN::Config->{make} ) {
            $CPAN::Frontend->mywarn(
                "\nALERT: Skipping local::lib bootstrap because 'make' is not configured.\n"
            );
            _beg_for_make(); # repetitive, but we don't want users to miss it
        }
        else {
            $CPAN::Frontend->myprint("\nAttempting to bootstrap local::lib...\n");
            $CPAN::Frontend->myprint("\nWriting $configpm for bootstrap...\n");
            delete $CPAN::Config->{install_help}; # temporary only
            CPAN::HandleConfig->commit;
            my($dist, $locallib);
            $locallib = CPAN::Shell->expand('Module', 'local::lib');
            if ( $locallib and $dist = $locallib->distribution ) {
                # this is a hack to force bootstrapping
                $dist->{prefs}{pl}{commandline} = "$^X Makefile.PL --bootstrap";
                # Set @INC for this process so we find things as they bootstrap
                require lib;
                lib->import(_local_lib_inc_path());
                eval { $dist->install };
            }
            if ( ! $dist || (my $err = $@) ) {
                $err ||= 'Could not locate local::lib in the CPAN index';
                $CPAN::Frontend->mywarn("Error bootstrapping local::lib: $@\n");
                $CPAN::Frontend->myprint("From the CPAN Shell, you might try 'look local::lib' and \n"
                    . "run 'perl Makefile --bootstrap' and see if that is successful.  Then\n"
                    . "restart your CPAN client\n"
                );
            }
            else {
                _local_lib_config();
            }
        }
    }

    # install_help is temporary for configuration and not saved
    delete $CPAN::Config->{install_help};

    $CPAN::Frontend->myprint("\n");
    if ($matcher && !$CPAN::Config->{auto_commit}) {
        $CPAN::Frontend->myprint("Please remember to call 'o conf commit' to ".
                                 "make the config permanent!\n");
    } else {
        CPAN::HandleConfig->commit;
    }

    if (! $matcher) {
        $CPAN::Frontend->myprint(
            "\nYou can re-run configuration any time with 'o conf init' in the CPAN shell\n"
        );
    }

}

sub _local_lib_config {
    # Set environment stuff for this process
    require local::lib;

    # Tell user about environment vars to set
    $CPAN::Frontend->myprint($prompts{local_lib_installed});
    local $ENV{SHELL} = $CPAN::Config->{shell} || $ENV{SHELL};
    my $shellvars = local::lib->environment_vars_string_for(_local_lib_path());
    $CPAN::Frontend->myprint($shellvars);

    # Set %ENV after getting string above
    my %env = local::lib->build_environment_vars_for(_local_lib_path(), 1);
    while ( my ($k, $v) = each %env ) {
        $ENV{$k} = $v;
    }

    # Offer to mangle the shell config
    my $munged_rc;
    if ( my $rc = _find_shell_config() ) {
        local $auto_config = 0; # We *must* ask, even under autoconfig
        local *_real_prompt;    # We *must* show prompt
        my $_conf = prompt(
            "\nWould you like me to append that to $rc now?", "yes"
        );
        if ($_conf =~ /^y/i) {
            open my $fh, ">>", $rc;
            print {$fh} "\n$shellvars";
            close $fh;
            $munged_rc++;
        }
    }

    # Warn at exit time
    if ($munged_rc) {
        push @{$CPAN::META->_exit_messages}, << "HERE";

*** Remember to restart your shell before running cpan again ***
HERE
    }
    else {
        push @{$CPAN::META->_exit_messages}, << "HERE";

*** Remember to add these environment variables to your shell config
    and restart your shell before running cpan again ***

$shellvars
HERE
    }
}

{
    my %shell_rc_map = (
        map { $_ => ".${_}rc" } qw/ bash tcsh csh /,
        map { $_ => ".profile" } qw/dash ash sh/,
        zsh  => ".zshenv",
    );

    sub _find_shell_config {
        my $shell = File::Basename::basename($CPAN::Config->{shell});
        if ( my $rc = $shell_rc_map{$shell} ) {
            my $path = File::Spec->catfile($ENV{HOME}, $rc);
            return $path if -w $path;
        }
    }
}


sub _local_lib_inc_path {
    return File::Spec->catdir(_local_lib_path(), qw/lib perl5/);
}

sub _local_lib_path {
    return File::Spec->catdir(_local_lib_home(), 'perl5');
}

# Adapted from resolve_home_path() in local::lib -- this is where
# local::lib thinks the user's home is
{
    my $local_lib_home;
    sub _local_lib_home {
        $local_lib_home ||= File::Spec->rel2abs( do {
            if ($CPAN::META->has_usable("File::HomeDir") && File::HomeDir->VERSION >= 0.65) {
                File::HomeDir->my_home;
            } elsif (defined $ENV{HOME}) {
                $ENV{HOME};
            } else {
                (getpwuid $<)[7] || "~";
            }
        });
    }
}

sub _do_pick_mirrors {
    local *_real_prompt;
    *_real_prompt = \&CPAN::Shell::colorable_makemaker_prompt;
    $CPAN::Frontend->myprint($prompts{urls_intro});
    # Only prompt for auto-pick if Net::Ping is new enough to do timings
    my $_conf = 'n';
    if ( $CPAN::META->has_usable("Net::Ping") && CPAN::Version->vgt(Net::Ping->VERSION, '2.13')) {
        $_conf = prompt($prompts{auto_pick}, "yes");
    } else {
        prompt("Autoselection disabled due to Net::Ping missing or insufficient. Please press ENTER");
    }
    my @old_list = @{ $CPAN::Config->{urllist} };
    if ( $_conf =~ /^y/i ) {
        conf_sites( auto_pick => 1 ) or bring_your_own();
    }
    else {
        _print_urllist('Current') if @old_list;
        my $msg = scalar @old_list
            ? "\nWould you like to edit the urllist or pick new mirrors from a list?"
            : "\nWould you like to pick from the CPAN mirror list?" ;
        my $_conf = prompt($msg, "yes");
        if ( $_conf =~ /^y/i ) {
            conf_sites();
        }
        bring_your_own();
    }
    _print_urllist('New');
}

sub _init_external_progs {
    my($matcher,$args) = @_;
    my $PATH = $args->{path};
    my @external_progs = @{ $args->{progs} };
    my $shortcut = $args->{shortcut};
    my $showed_make_warning;

    if (!$matcher or "@external_progs" =~ /$matcher/) {
        my $old_warn = $^W;
        local $^W if $^O eq 'MacOS';
        local $^W = $old_warn;
        my $progname;
        for $progname (@external_progs) {
            next if $matcher && $progname !~ /$matcher/;
            if ($^O eq 'MacOS') {
                $CPAN::Config->{$progname} = 'not_here';
                next;
            }

            my $progcall = $progname;
            unless ($matcher) {
                # we really don't need ncftp if we have ncftpget, but
                # if they chose this dialog via matcher, they shall have it
                next if $progname eq "ncftp" && $CPAN::Config->{ncftpget} gt " ";
            }
            my $path = $CPAN::Config->{$progname}
                || $Config::Config{$progname}
                    || "";
            if (File::Spec->file_name_is_absolute($path)) {
                # testing existence is not good enough, some have these exe
                # extensions

                # warn "Warning: configured $path does not exist\n" unless -e $path;
                # $path = "";
            } elsif ($path =~ /^\s+$/) {
                # preserve disabled programs
            } else {
                $path = '';
            }
            unless ($path) {
                # e.g. make -> nmake
                $progcall = $Config::Config{$progname} if $Config::Config{$progname};
            }

            $path ||= find_exe($progcall,$PATH);
            unless ($path) { # not -e $path, because find_exe already checked that
                local $"=";";
                $CPAN::Frontend->mywarn("Warning: $progcall not found in PATH[@$PATH]\n") unless $auto_config;
                _beg_for_make(), $showed_make_warning++ if $progname eq "make";
            }
            $prompts{$progname} = "Where is your $progname program?";
            $path = my_dflt_prompt($progname,$path,$matcher,1); # 1 => no strip spaces
            my $disabling = $path =~ m/^\s*$/;

            # don't let them disable or misconfigure make without warning
            if ( $progname eq "make" && ( $disabling || ! _check_found($path) ) ) {
              if ( $disabling && $showed_make_warning ) {
                next;
              }
              else {
                _beg_for_make() unless $showed_make_warning++;
                undef $CPAN::Config->{$progname};
                $CPAN::Frontend->mywarn("Press SPACE and ENTER to disable make (NOT RECOMMENDED)\n");
                redo;
              }
            }
            elsif ( $disabling ) {
              next;
            }
            elsif ( _check_found( $CPAN::Config->{$progname} ) ) {
              last if $shortcut && !$matcher;
            }
            else {
              undef $CPAN::Config->{$progname};
              $CPAN::Frontend->mywarn("Press SPACE and ENTER to disable $progname\n");
              redo;
            }
        }
    }
}

sub _check_found {
  my ($prog) = @_;
  if ( ! -f $prog ) {
    $CPAN::Frontend->mywarn("Warning: '$prog' does not exist\n")
      unless $auto_config;
    return;
  }
  elsif ( ! -x $prog ) {
    $CPAN::Frontend->mywarn("Warning: '$prog' is not executable\n")
      unless $auto_config;
    return;
  }
  return 1;
}

sub _beg_for_make {
  $CPAN::Frontend->mywarn(<<"HERE");

ALERT: 'make' is an essential tool for building perl Modules.
Please make sure you have 'make' (or some equivalent) working.

HERE
  if ($^O eq "MSWin32") {
    $CPAN::Frontend->mywarn(<<"HERE");
Windows users may want to follow this procedure when back in the CPAN shell:

    look YVES/scripts/alien_nmake.pl
    perl alien_nmake.pl

This will install nmake on your system which can be used as a 'make'
substitute.

HERE
  }

  $CPAN::Frontend->mywarn(<<"HERE");
You can then retry the 'make' configuration step with

    o conf init make

HERE
}

sub init_cpan_home {
    my($matcher) = @_;
    if (!$matcher or 'cpan_home' =~ /$matcher/) {
        my $cpan_home =
            $CPAN::Config->{cpan_home} || CPAN::HandleConfig::cpan_home();
        if (-d $cpan_home) {
            $CPAN::Frontend->myprint(
                "\nI see you already have a directory\n" .
                "\n$cpan_home\n" .
                "Shall we use it as the general CPAN build and cache directory?\n\n"
            ) unless $auto_config;
        } else {
            # no cpan-home, must prompt and get one
            $CPAN::Frontend->myprint($prompts{cpan_home_where}) unless $auto_config;
        }

        my $default = $cpan_home;
        my $loop = 0;
        my($last_ans,$ans);
        $CPAN::Frontend->myprint(" <cpan_home>\n") unless $auto_config;
    PROMPT: while ($ans = prompt("CPAN build and cache directory?",$default)) {
            if (File::Spec->file_name_is_absolute($ans)) {
                my @cpan_home = split /[\/\\]/, $ans;
            DIR: for my $dir (@cpan_home) {
                    if ($dir =~ /^~/ and (!$last_ans or $ans ne $last_ans)) {
                        $CPAN::Frontend
                            ->mywarn("Warning: a tilde in the path will be ".
                                     "taken as a literal tilde. Please ".
                                     "confirm again if you want to keep it\n");
                        $last_ans = $default = $ans;
                        next PROMPT;
                    }
                }
            } else {
                require Cwd;
                my $cwd = Cwd::cwd();
                my $absans = File::Spec->catdir($cwd,$ans);
                $CPAN::Frontend->mywarn("The path '$ans' is not an ".
                                        "absolute path. Please specify ".
                                        "an absolute path\n");
                $default = $absans;
                next PROMPT;
            }
            eval { File::Path::mkpath($ans); }; # dies if it can't
            if ($@) {
                $CPAN::Frontend->mywarn("Couldn't create directory $ans.\n".
                                        "Please retry.\n");
                next PROMPT;
            }
            if (-d $ans && -w _) {
                last PROMPT;
            } else {
                $CPAN::Frontend->mywarn("Couldn't find directory $ans\n".
                                        "or directory is not writable. Please retry.\n");
                if (++$loop > 5) {
                    $CPAN::Frontend->mydie("Giving up");
                }
            }
        }
        $CPAN::Config->{cpan_home} = $ans;
    }
}

sub my_dflt_prompt {
    my ($item, $dflt, $m, $no_strip) = @_;
    my $default = $CPAN::Config->{$item} || $dflt;

    if (!$auto_config && (!$m || $item =~ /$m/)) {
        if (my $intro = $prompts{$item . "_intro"}) {
            $CPAN::Frontend->myprint($intro);
        }
        $CPAN::Frontend->myprint(" <$item>\n");
        $CPAN::Config->{$item} =
          $no_strip ? prompt_no_strip($prompts{$item}, $default)
                    : prompt(         $prompts{$item}, $default);
    } else {
        $CPAN::Config->{$item} = $default;
    }
    return $CPAN::Config->{$item};
}

sub my_yn_prompt {
    my ($item, $dflt, $m) = @_;
    my $default;
    defined($default = $CPAN::Config->{$item}) or $default = $dflt;

    if (!$auto_config && (!$m || $item =~ /$m/)) {
        if (my $intro = $prompts{$item . "_intro"}) {
            $CPAN::Frontend->myprint($intro);
        }
        $CPAN::Frontend->myprint(" <$item>\n");
        my $ans = prompt($prompts{$item}, $default ? 'yes' : 'no');
        $CPAN::Config->{$item} = ($ans =~ /^[y1]/i ? 1 : 0);
    } else {
        $CPAN::Config->{$item} = $default;
    }
}

sub my_prompt_loop {
    my ($item, $dflt, $m, $ok) = @_;
    my $default = $CPAN::Config->{$item} || $dflt;
    my $ans;

    if (!$auto_config && (!$m || $item =~ /$m/)) {
        my $intro = $prompts{$item . "_intro"};
        $CPAN::Frontend->myprint($intro) if defined $intro;
        $CPAN::Frontend->myprint(" <$item>\n");
        do { $ans = prompt($prompts{$item}, $default);
        } until $ans =~ /$ok/;
        $CPAN::Config->{$item} = $ans;
    } else {
        $CPAN::Config->{$item} = $default;
    }
}


# Here's the logic about the MIRRORED.BY file.  There are a number of scenarios:
# (1) We have a cached MIRRORED.BY file
#   (1a) We're auto-picking
#       - Refresh it automatically if it's old
#   (1b) Otherwise, ask if using cached is ok.  If old, default to no.
#       - If cached is not ok, get it from the Internet. If it succeeds we use
#         the new file.  Otherwise, we use the old file.
# (2) We don't have a copy at all
#   (2a) If we are allowed to connect, we try to get a new copy.  If it succeeds,
#        we use it, otherwise, we warn about failure
#   (2b) If we aren't allowed to connect,

sub conf_sites {
    my %args = @_;
    # auto pick implies using the internet
    $CPAN::Config->{connect_to_internet_ok} = 1 if $args{auto_pick};

    my $m = 'MIRRORED.BY';
    my $mby = File::Spec->catfile($CPAN::Config->{keep_source_where},$m);
    File::Path::mkpath(File::Basename::dirname($mby));
    # Why are we using MIRRORED.BY from the current directory?
    # Is this for testing? -- dagolden, 2009-11-05
    if (-f $mby && -f $m && -M $m < -M $mby) {
        require File::Copy;
        File::Copy::copy($m,$mby) or die "Could not update $mby: $!";
    }
    local $^T = time;
    # if we have a cached copy is not older than 60 days, we either
    # use it or refresh it or fall back to it if the refresh failed.
    if ($mby && -f $mby && -s _ > 0 ) {
      my $very_old = (-M $mby > 60);
      my $mtime = localtime((stat _)[9]);
      # if auto_pick, refresh anything old automatically
      if ( $args{auto_pick} ) {
        if ( $very_old ) {
          $CPAN::Frontend->myprint(qq{Trying to refresh your mirror list\n});
          eval { CPAN::FTP->localize($m,$mby,3,1) }
            or $CPAN::Frontend->myprint(qq{Refresh failed.  Using the old cached copy instead.\n});
          $CPAN::Frontend->myprint("\n");
        }
      }
      else {
        my $prompt = qq{Found a cached mirror list as of $mtime

If you'd like to just use the cached copy, answer 'yes', below.
If you'd like an updated copy of the mirror list, answer 'no' and
I'll get a fresh one from the Internet.

Shall I use the cached mirror list?};
        my $ans = prompt($prompt, $very_old ? "no" : "yes");
        if ($ans =~ /^n/i) {
          $CPAN::Frontend->myprint(qq{Trying to refresh your mirror list\n});
          # you asked for it from the Internet
          $CPAN::Config->{connect_to_internet_ok} = 1;
          eval { CPAN::FTP->localize($m,$mby,3,1) }
            or $CPAN::Frontend->myprint(qq{Refresh failed.  Using the old cached copy instead.\n});
          $CPAN::Frontend->myprint("\n");
        }
      }
    }
    # else there is no cached copy and we must fetch or fail
    else {
      # If they haven't agree to connect to the internet, ask again
      if ( ! $CPAN::Config->{connect_to_internet_ok} ) {
        my $prompt = q{You are missing a copy of the CPAN mirror list.

May I connect to the Internet to get it?};
        my $ans = prompt($prompt, "yes");
        if ($ans =~ /^y/i) {
          $CPAN::Config->{connect_to_internet_ok} = 1;
        }
      }

      # Now get it from the Internet or complain
      if ( $CPAN::Config->{connect_to_internet_ok} ) {
        $CPAN::Frontend->myprint(qq{Trying to fetch a mirror list from the Internet\n});
        eval { CPAN::FTP->localize($m,$mby,3,1) }
          or $CPAN::Frontend->mywarn(<<'HERE');
We failed to get a copy of the mirror list from the Internet.
You will need to provide CPAN mirror URLs yourself.
HERE
        $CPAN::Frontend->myprint("\n");
      }
      else {
        $CPAN::Frontend->mywarn(<<'HERE');
You will need to provide CPAN mirror URLs yourself or set
'o conf connect_to_internet_ok 1' and try again.
HERE
      }
    }

    # if we finally have a good local MIRRORED.BY, get on with picking
    if (-f $mby && -s _ > 0){
        $CPAN::Config->{urllist} =
          $args{auto_pick} ? auto_mirrored_by($mby) : choose_mirrored_by($mby);
        return 1;
    }

    return;
}

sub find_exe {
    my($exe,$path) = @_;
    $path ||= [split /$Config{'path_sep'}/, $ENV{'PATH'}];
    my($dir);
    #warn "in find_exe exe[$exe] path[@$path]";
    for $dir (@$path) {
        my $abs = File::Spec->catfile($dir,$exe);
        if (($abs = MM->maybe_command($abs))) {
            return $abs;
        }
    }
}

sub picklist {
    my($items,$prompt,$default,$require_nonempty,$empty_warning)=@_;
    CPAN->debug("picklist('$items','$prompt','$default','$require_nonempty',".
                "'$empty_warning')") if $CPAN::DEBUG;
    $default ||= '';

    my $pos = 0;

    my @nums;
  SELECTION: while (1) {

        # display, at most, 15 items at a time
        my $limit = $#{ $items } - $pos;
        $limit = 15 if $limit > 15;

        # show the next $limit items, get the new position
        $pos = display_some($items, $limit, $pos, $default);
        $pos = 0 if $pos >= @$items;

        my $num = prompt($prompt,$default);

        @nums = split (' ', $num);
        {
            my %seen;
            @nums = grep { !$seen{$_}++ } @nums;
        }
        my $i = scalar @$items;
        unrangify(\@nums);
        if (0 == @nums) {
            # cannot allow nothing because nothing means paging!
            # return;
        } elsif (grep (/\D/ || $_ < 1 || $_ > $i, @nums)) {
            $CPAN::Frontend->mywarn("invalid items entered, try again\n");
            if ("@nums" =~ /\D/) {
                $CPAN::Frontend->mywarn("(we are expecting only numbers between 1 and $i)\n");
            }
            next SELECTION;
        }
        if ($require_nonempty && !@nums) {
            $CPAN::Frontend->mywarn("$empty_warning\n");
        }

        # a blank line continues...
        unless (@nums){
            $CPAN::Frontend->mysleep(0.1); # prevent hot spinning process on the next bug
            next SELECTION;
        }
        last;
    }
    for (@nums) { $_-- }
    @{$items}[@nums];
}

sub unrangify ($) {
    my($nums) = $_[0];
    my @nums2 = ();
    while (@{$nums||[]}) {
        my $n = shift @$nums;
        if ($n =~ /^(\d+)-(\d+)$/) {
            my @range = $1 .. $2;
            # warn "range[@range]";
            push @nums2, @range;
        } else {
            push @nums2, $n;
        }
    }
    push @$nums, @nums2;
}

sub display_some {
    my ($items, $limit, $pos, $default) = @_;
    $pos ||= 0;

    my @displayable = @$items[$pos .. ($pos + $limit)];
    for my $item (@displayable) {
        $CPAN::Frontend->myprint(sprintf "(%d) %s\n", ++$pos, $item);
    }
    my $hit_what = $default ? "SPACE ENTER" : "ENTER";
    $CPAN::Frontend->myprint(sprintf("%d more items, hit %s to show them\n",
                                     (@$items - $pos),
                                     $hit_what,
                                    ))
        if $pos < @$items;
    return $pos;
}

sub auto_mirrored_by {
    my $local = shift or return;
    local $|=1;
    $CPAN::Frontend->myprint("Looking for CPAN mirrors near you (please be patient)\n");
    my $mirrors = CPAN::Mirrors->new($local);

    my $cnt = 0;
    my $callback_was_active = 0;
    my @best = $mirrors->best_mirrors(
      how_many => 3,
      callback => sub {
          $callback_was_active++;
          $CPAN::Frontend->myprint(".");
          if ($cnt++>60) { $cnt=0; $CPAN::Frontend->myprint("\n"); }
      },
      $CPAN::Config->{urllist_ping_external} ? (external_ping => 1) : (),
      $CPAN::Config->{urllist_ping_verbose} ? (verbose => 1) : (),
    );

    my $urllist = [
        map { $_->http }
        grep { $_ && ref $_ && $_->can('http') }
        @best
    ];
    push @$urllist, grep { /^file:/ } @{$CPAN::Config->{urllist}};
    $CPAN::Frontend->myprint(" done!\n\n") if $callback_was_active;

    return $urllist
}

sub choose_mirrored_by {
    my $local = shift or return;
    my ($default);
    my $mirrors = CPAN::Mirrors->new($local);
    my @previous_urls = @{$CPAN::Config->{urllist}};

    $CPAN::Frontend->myprint($prompts{urls_picker_intro});

    my (@cont, $cont, %cont, @countries, @urls, %seen);
    my $no_previous_warn =
        "Sorry! since you don't have any existing picks, you must make a\n" .
            "geographic selection.";
    my $offer_cont = [sort $mirrors->continents];
    if (@previous_urls) {
        push @$offer_cont, "(edit previous picks)";
        $default = @$offer_cont;
    } else {
        # cannot allow nothing because nothing means paging!
        # push @$offer_cont, "(none of the above)";
    }
    @cont = picklist($offer_cont,
                     "Select your continent (or several nearby continents)",
                     $default,
                     ! @previous_urls,
                     $no_previous_warn);
    # cannot allow nothing because nothing means paging!
    # return unless @cont;

    foreach $cont (@cont) {
        my @c = sort $mirrors->countries($cont);
        @cont{@c} = map ($cont, 0..$#c);
        @c = map ("$_ ($cont)", @c) if @cont > 1;
        push (@countries, @c);
    }
    if (@previous_urls && @countries) {
        push @countries, "(edit previous picks)";
        $default = @countries;
    }

    if (@countries) {
        @countries = picklist (\@countries,
                               "Select your country (or several nearby countries)",
                               $default,
                               ! @previous_urls,
                               $no_previous_warn);
        %seen = map (($_ => 1), @previous_urls);
        # hmmm, should take list of defaults from CPAN::Config->{'urllist'}...
        foreach my $country (@countries) {
            next if $country =~ /edit previous picks/;
            (my $bare_country = $country) =~ s/ \(.*\)//;
            my @u;
            for my $m ( $mirrors->mirrors($bare_country) ) {
              push @u, $m->ftp if $m->ftp;
              push @u, $m->http if $m->http;
            }
            @u = grep (! $seen{$_}, @u);
            @u = map ("$_ ($bare_country)", @u)
                if @countries > 1;
            push (@urls, sort @u);
        }
    }
    push (@urls, map ("$_ (previous pick)", @previous_urls));
    my $prompt = "Select as many URLs as you like (by number),
put them on one line, separated by blanks, hyphenated ranges allowed
 e.g. '1 4 5' or '7 1-4 8'";
    if (@previous_urls) {
        $default = join (' ', ((scalar @urls) - (scalar @previous_urls) + 1) ..
                         (scalar @urls));
        $prompt .= "\n(or just hit ENTER to keep your previous picks)";
    }

    @urls = picklist (\@urls, $prompt, $default);
    foreach (@urls) { s/ \(.*\)//; }
    return [ @urls ];
}

sub bring_your_own {
    my $urllist = [ @{$CPAN::Config->{urllist}} ];
    my %seen = map (($_ => 1), @$urllist);
    my($ans,@urls);
    my $eacnt = 0; # empty answers
    $CPAN::Frontend->myprint(<<'HERE');
Now you can enter your own CPAN URLs by hand. A local CPAN mirror can be
listed using a 'file:' URL like 'file:///path/to/cpan/'

HERE
    do {
        my $prompt = "Enter another URL or ENTER to quit:";
        unless (%seen) {
            $prompt = qq{CPAN.pm needs at least one URL where it can fetch CPAN files from.

Please enter your CPAN site:};
        }
        $ans = prompt ($prompt, "");

        if ($ans) {
            $ans =~ s|/?\z|/|; # has to end with one slash
            # XXX This manipulation is odd.  Shouldn't we check that $ans is
            # a directory before converting to file:///?  And we need /// below,
            # too, don't we?  -- dagolden, 2009-11-05
            $ans = "file:$ans" unless $ans =~ /:/; # without a scheme is a file:
            if ($ans =~ /^\w+:\/./) {
                push @urls, $ans unless $seen{$ans}++;
            } else {
                $CPAN::Frontend->
                    myprint(sprintf(qq{"%s" doesn\'t look like an URL at first sight.
I\'ll ignore it for now.
You can add it to your %s
later if you\'re sure it\'s right.\n},
                                   $ans,
                                   $INC{'CPAN/MyConfig.pm'}
                                   || $INC{'CPAN/Config.pm'}
                                   || "configuration file",
                                  ));
            }
        } else {
            if (++$eacnt >= 5) {
                $CPAN::Frontend->
                    mywarn("Giving up.\n");
                $CPAN::Frontend->mysleep(5);
                return;
            }
        }
    } while $ans || !%seen;

    @$urllist = CPAN::_uniq(@$urllist, @urls);
    $CPAN::Config->{urllist} = $urllist;
}

sub _print_urllist {
    my ($which) = @_;
    $CPAN::Frontend->myprint("$which urllist\n");
    for ( @{$CPAN::Config->{urllist} || []} ) {
      $CPAN::Frontend->myprint("  $_\n")
    };
}

sub _can_write_to_libdirs {
    return -w $Config{installprivlib}
        && -w $Config{installarchlib}
        && -w $Config{installsitelib}
        && -w $Config{installsitearch}
}

sub _using_installbase {
    return 1 if $ENV{PERL_MM_OPT} && $ENV{PERL_MM_OPT} =~ /install_base/i;
    return 1 if grep { ($CPAN::Config->{$_}||q{}) =~ /install_base/i }
        qw(makepl_arg make_install_arg mbuildpl_arg mbuild_install_arg);
    return;
}

sub _using_sudo {
    return 1 if grep { ($CPAN::Config->{$_}||q{}) =~ /sudo/ }
        qw(make_install_make_command mbuild_install_build_command);
    return;
}

sub _strip_spaces {
    $_[0] =~ s/^\s+//;  # no leading spaces
    $_[0] =~ s/\s+\z//; # no trailing spaces
}

sub prompt ($;$) {
    unless (defined &_real_prompt) {
        *_real_prompt = \&CPAN::Shell::colorable_makemaker_prompt;
    }
    my $ans = _real_prompt(@_);

    _strip_spaces($ans);
    $CPAN::Frontend->myprint("\n") unless $auto_config;

    return $ans;
}


sub prompt_no_strip ($;$) {
    unless (defined &_real_prompt) {
        *_real_prompt = \&CPAN::Shell::colorable_makemaker_prompt;
    }
    return _real_prompt(@_);
}



1;
PK7N%[�2]��perl5/CPAN/Nox.pmnu��6�$package CPAN::Nox;
use strict;
use vars qw($VERSION @EXPORT);

BEGIN{
  $CPAN::Suppress_readline=1 unless defined $CPAN::term;
}

use Exporter ();
@CPAN::ISA = ('Exporter');
use CPAN;

$VERSION = "5.5001";
$CPAN::META->has_inst('Digest::MD5','no');
$CPAN::META->has_inst('LWP','no');
$CPAN::META->has_inst('Compress::Zlib','no');
@EXPORT = @CPAN::EXPORT;

*AUTOLOAD = \&CPAN::AUTOLOAD;

1;

__END__

=head1 NAME

CPAN::Nox - Wrapper around CPAN.pm without using any XS module

=head1 SYNOPSIS

Interactive mode:

  perl -MCPAN::Nox -e shell;

=head1 DESCRIPTION

This package has the same functionality as CPAN.pm, but tries to
prevent the usage of compiled extensions during its own
execution. Its primary purpose is a rescue in case you upgraded perl
and broke binary compatibility somehow.

=head1 LICENSE

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

=head1  SEE ALSO

L<CPAN>

=cut

PK7N%[��L����perl5/CPAN/Distribution.pmnu��6�$# -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*-
# vim: ts=4 sts=4 sw=4:
package CPAN::Distribution;
use strict;
use Cwd qw(chdir);
use CPAN::Distroprefs;
use CPAN::InfoObj;
use File::Path ();
use POSIX ":sys_wait_h"; 
@CPAN::Distribution::ISA = qw(CPAN::InfoObj);
use vars qw($VERSION);
$VERSION = "2.34";

my $run_allow_installing_within_test = 1; # boolean; either in test or in install, there is no third option

# no prepare, because prepare is not a command on the shell command line
# TODO: clear instance cache on reload
my %instance;
for my $method (qw(get make test install)) {
    no strict 'refs';
    for my $prefix (qw(pre post)) {
        my $hookname = sprintf "%s_%s", $prefix, $method;
        *$hookname = sub {
            my($self) = @_;
            for my $plugin (@{$CPAN::Config->{plugin_list}}) {
                my($plugin_proper,$args) = split /=/, $plugin, 2;
                $args = "" unless defined $args;
                if ($CPAN::META->has_inst($plugin_proper)){
                    my @args = split /,/, $args;
                    $instance{$plugin} ||= $plugin_proper->new(@args);
                    if ($instance{$plugin}->can($hookname)) {
                        $instance{$plugin}->$hookname($self);
                    }
                } else {
                    $CPAN::Frontend->mydie("Plugin '$plugin_proper' not found for hook '$hookname'");
                }
            }
        };
    }
}

# Accessors
sub cpan_comment {
    my $self = shift;
    my $ro = $self->ro or return;
    $ro->{CPAN_COMMENT}
}

#-> CPAN::Distribution::undelay
sub undelay {
    my $self = shift;
    for my $delayer (
                     "configure_requires_later",
                     "configure_requires_later_for",
                     "later",
                     "later_for",
                    ) {
        delete $self->{$delayer};
    }
}

#-> CPAN::Distribution::is_dot_dist
sub is_dot_dist {
    my($self) = @_;
    return substr($self->id,-1,1) eq ".";
}

# add the A/AN/ stuff
#-> CPAN::Distribution::normalize
sub normalize {
    my($self,$s) = @_;
    $s = $self->id unless defined $s;
    if (substr($s,-1,1) eq ".") {
        # using a global because we are sometimes called as static method
        if (!$CPAN::META->{LOCK}
            && !$CPAN::Have_warned->{"$s is unlocked"}++
           ) {
            $CPAN::Frontend->mywarn("You are visiting the local directory
  '$s'
  without lock, take care that concurrent processes do not do likewise.\n");
            $CPAN::Frontend->mysleep(1);
        }
        if ($s eq ".") {
            $s = "$CPAN::iCwd/.";
        } elsif (File::Spec->file_name_is_absolute($s)) {
        } elsif (File::Spec->can("rel2abs")) {
            $s = File::Spec->rel2abs($s);
        } else {
            $CPAN::Frontend->mydie("Your File::Spec is too old, please upgrade File::Spec");
        }
        CPAN->debug("s[$s]") if $CPAN::DEBUG;
        unless ($CPAN::META->exists("CPAN::Distribution", $s)) {
            for ($CPAN::META->instance("CPAN::Distribution", $s)) {
                $_->{build_dir} = $s;
                $_->{archived} = "local_directory";
                $_->{unwrapped} = CPAN::Distrostatus->new("YES -- local_directory");
            }
        }
    } elsif (
        $s =~ tr|/|| == 1
        or
        $s !~ m|[A-Z]/[A-Z-0-9]{2}/[A-Z-0-9]{2,}/|
       ) {
        return $s if $s =~ m:^N/A|^Contact Author: ;
        $s =~ s|^(.)(.)([^/]*/)(.+)$|$1/$1$2/$1$2$3$4|;
        CPAN->debug("s[$s]") if $CPAN::DEBUG;
    }
    $s;
}

#-> sub CPAN::Distribution::author ;
sub author {
    my($self) = @_;
    my($authorid);
    if (substr($self->id,-1,1) eq ".") {
        $authorid = "LOCAL";
    } else {
        ($authorid) = $self->pretty_id =~ /^([\w\-]+)/;
    }
    CPAN::Shell->expand("Author",$authorid);
}

# tries to get the yaml from CPAN instead of the distro itself:
# EXPERIMENTAL, UNDOCUMENTED AND UNTESTED, for Tels
sub fast_yaml {
    my($self) = @_;
    my $meta = $self->pretty_id;
    $meta =~ s/\.(tar.gz|tgz|zip|tar.bz2)/.meta/;
    my(@ls) = CPAN::Shell->globls($meta);
    my $norm = $self->normalize($meta);

    my($local_file);
    my($local_wanted) =
        File::Spec->catfile(
                            $CPAN::Config->{keep_source_where},
                            "authors",
                            "id",
                            split(/\//,$norm)
                           );
    $self->debug("Doing localize") if $CPAN::DEBUG;
    unless ($local_file =
            CPAN::FTP->localize("authors/id/$norm",
                                $local_wanted)) {
        $CPAN::Frontend->mydie("Giving up on downloading yaml file '$local_wanted'\n");
    }
    my $yaml = CPAN->_yaml_loadfile($local_file)->[0];
}

#-> sub CPAN::Distribution::cpan_userid
sub cpan_userid {
    my $self = shift;
    if ($self->{ID} =~ m{[A-Z]/[A-Z\-]{2}/([A-Z\-]+)/}) {
        return $1;
    }
    return $self->SUPER::cpan_userid;
}

#-> sub CPAN::Distribution::pretty_id
sub pretty_id {
    my $self = shift;
    my $id = $self->id;
    return $id unless $id =~ m|^./../|;
    substr($id,5);
}

#-> sub CPAN::Distribution::base_id
sub base_id {
    my $self = shift;
    my $id = $self->pretty_id();
    my $base_id = File::Basename::basename($id);
    $base_id =~ s{\.(?:tar\.(bz2|gz|Z)|t(?:gz|bz)|zip)$}{}i;
    return $base_id;
}

#-> sub CPAN::Distribution::tested_ok_but_not_installed
sub tested_ok_but_not_installed {
    my $self = shift;
    return (
           $self->{make_test}
        && $self->{build_dir}
        && (UNIVERSAL::can($self->{make_test},"failed") ?
             ! $self->{make_test}->failed :
             $self->{make_test} =~ /^YES/
            )
        && (
            !$self->{install}
            ||
            $self->{install}->failed
           )
    );
}


# mark as dirty/clean for the sake of recursion detection. $color=1
# means "in use", $color=0 means "not in use anymore". $color=2 means
# we have determined prereqs now and thus insist on passing this
# through (at least) once again.

#-> sub CPAN::Distribution::color_cmd_tmps ;
sub color_cmd_tmps {
    my($self) = shift;
    my($depth) = shift || 0;
    my($color) = shift || 0;
    my($ancestors) = shift || [];
    # a distribution needs to recurse into its prereq_pms
    $self->debug("color_cmd_tmps[$depth,$color,@$ancestors]") if $CPAN::DEBUG;

    return if exists $self->{incommandcolor}
        && $color==1
        && $self->{incommandcolor}==$color;
    $CPAN::MAX_RECURSION||=0; # silence 'once' warnings
    if ($depth>=$CPAN::MAX_RECURSION) {
        my $e = CPAN::Exception::RecursiveDependency->new($ancestors);
        if ($e->is_resolvable) {
            return $self->{incommandcolor}=2;
        } else {
            die $e;
        }
    }
    # warn "color_cmd_tmps $depth $color " . $self->id; # sleep 1;
    my $prereq_pm = $self->prereq_pm;
    if (defined $prereq_pm) {
        # XXX also optional_req & optional_breq? -- xdg, 2012-04-01
        # A: no, optional deps may recurse -- ak, 2014-05-07
      PREREQ: for my $pre (sort(
                keys %{$prereq_pm->{requires}||{}},
                keys %{$prereq_pm->{build_requires}||{}},
            )) {
            next PREREQ if $pre eq "perl";
            my $premo;
            unless ($premo = CPAN::Shell->expand("Module",$pre)) {
                $CPAN::Frontend->mywarn("prerequisite module[$pre] not known\n");
                $CPAN::Frontend->mysleep(0.2);
                next PREREQ;
            }
            $premo->color_cmd_tmps($depth+1,$color,[@$ancestors, $self->id]);
        }
    }
    if ($color==0) {
        delete $self->{sponsored_mods};

        # as we are at the end of a command, we'll give up this
        # reminder of a broken test. Other commands may test this guy
        # again. Maybe 'badtestcnt' should be renamed to
        # 'make_test_failed_within_command'?
        delete $self->{badtestcnt};
    }
    $self->{incommandcolor} = $color;
}

#-> sub CPAN::Distribution::as_string ;
sub as_string {
    my $self = shift;
    $self->containsmods;
    $self->upload_date;
    $self->SUPER::as_string(@_);
}

#-> sub CPAN::Distribution::containsmods ;
sub containsmods {
    my $self = shift;
    return sort keys %{$self->{CONTAINSMODS}} if exists $self->{CONTAINSMODS};
    my $dist_id = $self->{ID};
    for my $mod ($CPAN::META->all_objects("CPAN::Module")) {
        my $mod_file = $mod->cpan_file or next;
        my $mod_id = $mod->{ID} or next;
        # warn "mod_file[$mod_file] dist_id[$dist_id] mod_id[$mod_id]";
        # sleep 1;
        if ($CPAN::Signal) {
            delete $self->{CONTAINSMODS};
            return;
        }
        $self->{CONTAINSMODS}{$mod_id} = undef if $mod_file eq $dist_id;
    }
    sort keys %{$self->{CONTAINSMODS}||={}};
}

#-> sub CPAN::Distribution::upload_date ;
sub upload_date {
    my $self = shift;
    return $self->{UPLOAD_DATE} if exists $self->{UPLOAD_DATE};
    my(@local_wanted) = split(/\//,$self->id);
    my $filename = pop @local_wanted;
    push @local_wanted, "CHECKSUMS";
    my $author = CPAN::Shell->expand("Author",$self->cpan_userid);
    return unless $author;
    my @dl = $author->dir_listing(\@local_wanted,0,$CPAN::Config->{show_upload_date});
    return unless @dl;
    my($dirent) = grep { $_->[2] eq $filename } @dl;
    # warn sprintf "dirent[%s]id[%s]", $dirent, $self->id;
    return unless $dirent->[1];
    return $self->{UPLOAD_DATE} = $dirent->[1];
}

#-> sub CPAN::Distribution::uptodate ;
sub uptodate {
    my($self) = @_;
    my $c;
    foreach $c ($self->containsmods) {
        my $obj = CPAN::Shell->expandany($c);
        unless ($obj->uptodate) {
            my $id = $self->pretty_id;
            $self->debug("$id not uptodate due to $c") if $CPAN::DEBUG;
            return 0;
        }
    }
    return 1;
}

#-> sub CPAN::Distribution::called_for ;
sub called_for {
    my($self,$id) = @_;
    $self->{CALLED_FOR} = $id if defined $id;
    return $self->{CALLED_FOR};
}

#-> sub CPAN::Distribution::shortcut_get ;
# return values: undef means don't shortcut; 0 means shortcut as fail;
# and 1 means shortcut as success
sub shortcut_get {
    my ($self) = @_;

    if (exists $self->{cleanup_after_install_done}) {
        if ($self->{force_update}) {
            delete $self->{cleanup_after_install_done};
        } else {
            my $id = $self->{CALLED_FOR} || $self->pretty_id;
            return $self->success(
                "Has already been *installed and cleaned up in the staging area* within this session, will not work on it again; if you really want to start over, try something like `force get $id`"
            );
        }
    }

    if (my $why = $self->check_disabled) {
        $self->{unwrapped} = CPAN::Distrostatus->new("NO $why");
        # XXX why is this goodbye() instead of just print/warn?
        # Alternatively, should other print/warns here be goodbye()?
        # -- xdg, 2012-04-05
        return $self->goodbye("[disabled] -- NA $why");
    }

    $self->debug("checking already unwrapped[$self->{ID}]") if $CPAN::DEBUG;
    if (exists $self->{build_dir} && -d $self->{build_dir}) {
        # this deserves print, not warn:
        return $self->success("Has already been unwrapped into directory ".
            "$self->{build_dir}"
        );
    }

    # XXX I'm not sure this should be here because it's not really
    # a test for whether get should continue or return; this is
    # a side effect -- xdg, 2012-04-05
    $self->debug("checking missing build_dir[$self->{ID}]") if $CPAN::DEBUG;
    if (exists $self->{build_dir} && ! -d $self->{build_dir}){
        # we have lost it.
        $self->fforce(""); # no method to reset all phases but not set force (dodge)
        return undef; # no shortcut
    }

    # although we talk about 'force' we shall not test on
    # force directly. New model of force tries to refrain from
    # direct checking of force.
    $self->debug("checking unwrapping error[$self->{ID}]") if $CPAN::DEBUG;
    if ( exists $self->{unwrapped} and (
            UNIVERSAL::can($self->{unwrapped},"failed") ?
            $self->{unwrapped}->failed :
            $self->{unwrapped} =~ /^NO/ )
    ) {
        return $self->goodbye("Unwrapping had some problem, won't try again without force");
    }

    return undef; # no shortcut
}

#-> sub CPAN::Distribution::get ;
sub get {
    my($self) = @_;

    $self->pre_get();

    $self->debug("checking goto id[$self->{ID}]") if $CPAN::DEBUG;
    if (my $goto = $self->prefs->{goto}) {
        $self->post_get();
        return $self->goto($goto);
    }

    if ( defined( my $sc = $self->shortcut_get) ) {
        $self->post_get();
        return $sc;
    }

    local $ENV{PERL5LIB} = defined($ENV{PERL5LIB})
                           ? $ENV{PERL5LIB}
                           : ($ENV{PERLLIB} || "");
    local $ENV{PERL5OPT} = defined $ENV{PERL5OPT} ? $ENV{PERL5OPT} : "";
    # local $ENV{PERL_USE_UNSAFE_INC} = exists $ENV{PERL_USE_UNSAFE_INC} ? $ENV{PERL_USE_UNSAFE_INC} : 1; # get
    $CPAN::META->set_perl5lib;
    local $ENV{MAKEFLAGS}; # protect us from outer make calls

    my $sub_wd = CPAN::anycwd(); # for cleaning up as good as possible

    my($local_file);
    # XXX I don't think this check needs to be here, as it
    # is already checked in shortcut_get() -- xdg, 2012-04-05
    unless ($self->{build_dir} && -d $self->{build_dir}) {
        $self->get_file_onto_local_disk;
        if ($CPAN::Signal){
            $self->post_get();
            return;
        }
        $self->check_integrity;
        if ($CPAN::Signal){
            $self->post_get();
            return;
        }
        (my $packagedir,$local_file) = $self->run_preps_on_packagedir;
        # XXX why is this check here? -- xdg, 2012-04-08
        if (exists $self->{writemakefile} && ref $self->{writemakefile}
           && $self->{writemakefile}->can("failed") &&
           $self->{writemakefile}->failed) {
           #
            $self->post_get();
            return;
        }
        $packagedir ||= $self->{build_dir};
        $self->{build_dir} = $packagedir;
    }

    # XXX should this move up to after run_preps_on_packagedir?
    # Otherwise, failing writemakefile can return without
    # a $CPAN::Signal check -- xdg, 2012-04-05
    if ($CPAN::Signal) {
        $self->safe_chdir($sub_wd);
        $self->post_get();
        return;
    }
    unless ($self->patch){
        $self->post_get();
        return;
    }
    $self->store_persistent_state;

    $self->post_get();

    return 1; # success
}

#-> CPAN::Distribution::get_file_onto_local_disk
sub get_file_onto_local_disk {
    my($self) = @_;

    return if $self->is_dot_dist;
    my($local_file);
    my($local_wanted) =
        File::Spec->catfile(
                            $CPAN::Config->{keep_source_where},
                            "authors",
                            "id",
                            split(/\//,$self->id)
                           );

    $self->debug("Doing localize") if $CPAN::DEBUG;
    unless ($local_file =
            CPAN::FTP->localize("authors/id/$self->{ID}",
                                $local_wanted)) {
        my $note = "";
        if ($CPAN::Index::DATE_OF_02) {
            $note = "Note: Current database in memory was generated ".
                "on $CPAN::Index::DATE_OF_02\n";
        }
        $CPAN::Frontend->mydie("Giving up on '$local_wanted'\n$note");
    }

    $self->debug("local_wanted[$local_wanted]local_file[$local_file]") if $CPAN::DEBUG;
    $self->{localfile} = $local_file;
}


#-> CPAN::Distribution::check_integrity
sub check_integrity {
    my($self) = @_;

    return if $self->is_dot_dist;
    if ($CPAN::META->has_inst("Digest::SHA")) {
        $self->debug("Digest::SHA is installed, verifying");
        $self->verifyCHECKSUM;
    } else {
        $self->debug("Digest::SHA is NOT installed");
    }
}

#-> CPAN::Distribution::run_preps_on_packagedir
sub run_preps_on_packagedir {
    my($self) = @_;
    return if $self->is_dot_dist;

    $CPAN::META->{cachemgr} ||= CPAN::CacheMgr->new(); # unsafe meta access, ok
    my $builddir = $CPAN::META->{cachemgr}->dir; # unsafe meta access, ok
    $self->safe_chdir($builddir);
    $self->debug("Removing tmp-$$") if $CPAN::DEBUG;
    File::Path::rmtree("tmp-$$");
    unless (mkdir "tmp-$$", 0755) {
        $CPAN::Frontend->unrecoverable_error(<<EOF);
Couldn't mkdir '$builddir/tmp-$$': $!

Cannot continue: Please find the reason why I cannot make the
directory
$builddir/tmp-$$
and fix the problem, then retry.

EOF
    }
    if ($CPAN::Signal) {
        return;
    }
    $self->safe_chdir("tmp-$$");

    #
    # Unpack the goods
    #
    my $local_file = $self->{localfile};
    my $ct = eval{CPAN::Tarzip->new($local_file)};
    unless ($ct) {
        $self->{unwrapped} = CPAN::Distrostatus->new("NO");
        delete $self->{build_dir};
        return;
    }
    if ($local_file =~ /(\.tar\.(bz2|gz|Z)|\.tgz)(?!\n)\Z/i) {
        $self->{was_uncompressed}++ unless eval{$ct->gtest()};
        $self->untar_me($ct);
    } elsif ( $local_file =~ /\.zip(?!\n)\Z/i ) {
        $self->unzip_me($ct);
    } else {
        $self->{was_uncompressed}++ unless $ct->gtest();
        $local_file = $self->handle_singlefile($local_file);
    }

    # we are still in the tmp directory!
    # Let's check if the package has its own directory.
    my $dh = DirHandle->new(File::Spec->curdir)
        or Carp::croak("Couldn't opendir .: $!");
    my @readdir = grep $_ !~ /^\.\.?(?!\n)\Z/s, $dh->read; ### MAC??
    if (grep { $_ eq "pax_global_header" } @readdir) {
        $CPAN::Frontend->mywarn("Your (un)tar seems to have extracted a file named 'pax_global_header'
from the tarball '$local_file'.
This is almost certainly an error. Please upgrade your tar.
I'll ignore this file for now.
See also http://rt.cpan.org/Ticket/Display.html?id=38932\n");
        $CPAN::Frontend->mysleep(5);
        @readdir = grep { $_ ne "pax_global_header" } @readdir;
    }
    $dh->close;
    my $tdir_base;
    my $from_dir;
    my @dirents;
    if (@readdir == 1 && -d $readdir[0]) {
        $tdir_base = $readdir[0];
        $from_dir = File::Spec->catdir(File::Spec->curdir,$readdir[0]);
        my($mode) = (stat $from_dir)[2];
        chmod $mode | 00755, $from_dir; # JONATHAN/Math-Calculus-TaylorSeries-0.1.tar.gz has 0644
        my $dh2;
        unless ($dh2 = DirHandle->new($from_dir)) {
            my $why = sprintf
                (
                 "Couldn't opendir '%s', mode '%o': %s",
                 $from_dir,
                 $mode,
                 $!,
                );
            $CPAN::Frontend->mywarn("$why\n");
            $self->{writemakefile} = CPAN::Distrostatus->new("NO -- $why");
            return;
        }
        @dirents = grep $_ !~ /^\.\.?(?!\n)\Z/s, $dh2->read; ### MAC??
    } else {
        my $userid = $self->cpan_userid;
        CPAN->debug("userid[$userid]");
        if (!$userid or $userid eq "N/A") {
            $userid = "anon";
        }
        $tdir_base = $userid;
        $from_dir = File::Spec->curdir;
        @dirents = @readdir;
    }
    my $packagedir;
    my $eexist = ($CPAN::META->has_usable("Errno") && defined &Errno::EEXIST)
        ? &Errno::EEXIST : undef;
    for(my $suffix = 0; ; $suffix++) {
        $packagedir = File::Spec->catdir($builddir, "$tdir_base-$suffix");
        my $parent = $builddir;
        mkdir($packagedir, 0777) and last;
        if((defined($eexist) && $! != $eexist) || $suffix == 999) {
            $CPAN::Frontend->mydie("Cannot create directory $packagedir: $!\n");
        }
    }
    my $f;
    for $f (@dirents) { # is already without "." and ".."
        my $from = File::Spec->catfile($from_dir,$f);
        my($mode) = (stat $from)[2];
        chmod $mode | 00755, $from if -d $from; # OTTO/Pod-Trial-LinkImg-0.005.tgz
        my $to = File::Spec->catfile($packagedir,$f);
        unless (File::Copy::move($from,$to)) {
            my $err = $!;
            $from = File::Spec->rel2abs($from);
            $CPAN::Frontend->mydie(
                "Couldn't move $from to $to: $err; #82295? ".
                "CPAN::VERSION=$CPAN::VERSION; ".
                "File::Copy::VERSION=$File::Copy::VERSION; ".
                "$from " . (-e $from ? "exists; " : "does not exist; ").
                "$to " . (-e $to ? "exists; " : "does not exist; ").
                "cwd=" . CPAN::anycwd() . ";"
            );
        }
    }
    $self->{build_dir} = $packagedir;
    $self->safe_chdir($builddir);
    File::Path::rmtree("tmp-$$");

    $self->safe_chdir($packagedir);
    $self->_signature_business();
    $self->safe_chdir($builddir);

    return($packagedir,$local_file);
}

#-> sub CPAN::Distribution::pick_meta_file ;
sub pick_meta_file {
    my($self, $filter) = @_;
    $filter = '.' unless defined $filter;

    my $build_dir;
    unless ($build_dir = $self->{build_dir}) {
        # maybe permission on build_dir was missing
        $CPAN::Frontend->mywarn("Warning: cannot determine META.yml without a build_dir.\n");
        return;
    }

    my $has_cm = $CPAN::META->has_usable("CPAN::Meta");
    my $has_pcm = $CPAN::META->has_usable("Parse::CPAN::Meta");

    my @choices;
    push @choices, 'MYMETA.json' if $has_cm;
    push @choices, 'MYMETA.yml' if $has_cm || $has_pcm;
    push @choices, 'META.json' if $has_cm;
    push @choices, 'META.yml' if $has_cm || $has_pcm;

    for my $file ( grep { /$filter/ } @choices ) {
        my $path = File::Spec->catfile( $build_dir, $file );
        return $path if -f $path
    }

    return;
}

#-> sub CPAN::Distribution::parse_meta_yml ;
sub parse_meta_yml {
    my($self, $yaml) = @_;
    $self->debug(sprintf("parse_meta_yml[%s]",$yaml||'undef')) if $CPAN::DEBUG;
    my $build_dir = $self->{build_dir} or die "PANIC: cannot parse yaml without a build_dir";
    $yaml ||= File::Spec->catfile($build_dir,"META.yml");
    $self->debug("meta[$yaml]") if $CPAN::DEBUG;
    return unless -f $yaml;
    my $early_yaml;
    eval {
        $CPAN::META->has_inst("Parse::CPAN::Meta") or die;
        die "Parse::CPAN::Meta yaml too old" unless $Parse::CPAN::Meta::VERSION >= "1.40";
        # P::C::M returns last document in scalar context
        $early_yaml = Parse::CPAN::Meta::LoadFile($yaml);
    };
    unless ($early_yaml) {
        eval { $early_yaml = CPAN->_yaml_loadfile($yaml)->[0]; };
    }
    $self->debug(sprintf("yaml[%s]", $early_yaml || 'UNDEF')) if $CPAN::DEBUG;
    $self->debug($early_yaml) if $CPAN::DEBUG && $early_yaml;
    if (!ref $early_yaml or ref $early_yaml ne "HASH"){
        # fix rt.cpan.org #95271
        $CPAN::Frontend->mywarn("The content of '$yaml' is not a HASH reference. Cannot use it.\n");
        return {};
    }
    return $early_yaml || undef;
}

#-> sub CPAN::Distribution::satisfy_requires ;
# return values: 1 means requirements are satisfied;
# and 0 means not satisfied (and maybe queued)
sub satisfy_requires {
    my ($self) = @_;
    $self->debug("Entering satisfy_requires") if $CPAN::DEBUG;
    if (my @prereq = $self->unsat_prereq("later")) {
        if ($CPAN::DEBUG){
            require Data::Dumper;
            my $prereq = Data::Dumper->new(\@prereq)->Terse(1)->Indent(0)->Dump;
            $self->debug("unsatisfied[$prereq]");
        }
        if ($prereq[0][0] eq "perl") {
            my $need = "requires perl '$prereq[0][1]'";
            my $id = $self->pretty_id;
            $CPAN::Frontend->mywarn("$id $need; you have only $]; giving up\n");
            $self->{make} = CPAN::Distrostatus->new("NO $need");
            $self->store_persistent_state;
            die "[prereq] -- NOT OK\n";
        } else {
            my $follow = eval { $self->follow_prereqs("later",@prereq); };
            if (0) {
            } elsif ($follow) {
                return; # we need deps
            } elsif ($@ && ref $@ && $@->isa("CPAN::Exception::RecursiveDependency")) {
                $CPAN::Frontend->mywarn($@);
                die "[depend] -- NOT OK\n";
            }
        }
    }
    return 1;
}

#-> sub CPAN::Distribution::satisfy_configure_requires ;
# return values: 1 means configure_require is satisfied;
# and 0 means not satisfied (and maybe queued)
sub satisfy_configure_requires {
    my($self) = @_;
    $self->debug("Entering satisfy_configure_requires") if $CPAN::DEBUG;
    my $enable_configure_requires = 1;
    if (!$enable_configure_requires) {
        return 1;
        # if we return 1 here, everything is as before we introduced
        # configure_requires that means, things with
        # configure_requires simply fail, all others succeed
    }
    my @prereq = $self->unsat_prereq("configure_requires_later");
    $self->debug(sprintf "configure_requires[%s]", join(",",map {join "/",@$_} @prereq)) if $CPAN::DEBUG;
    return 1 unless @prereq;
    $self->debug(\@prereq) if $CPAN::DEBUG;
    if ($self->{configure_requires_later}) {
        for my $k (sort keys %{$self->{configure_requires_later_for}||{}}) {
            if ($self->{configure_requires_later_for}{$k}>1) {
                my $type = "";
                for my $p (@prereq) {
                    if ($p->[0] eq $k) {
                        $type = $p->[1];
                    }
                }
                $type = " $type" if $type;
                $CPAN::Frontend->mywarn("Warning: unmanageable(?) prerequisite $k$type");
                sleep 1;
            }
        }
    }
    if ($prereq[0][0] eq "perl") {
        my $need = "requires perl '$prereq[0][1]'";
        my $id = $self->pretty_id;
        $CPAN::Frontend->mywarn("$id $need; you have only $]; giving up\n");
        $self->{make} = CPAN::Distrostatus->new("NO $need");
        $self->store_persistent_state;
        return $self->goodbye("[prereq] -- NOT OK");
    } else {
        my $follow = eval {
            $self->follow_prereqs("configure_requires_later", @prereq);
        };
        if (0) {
        } elsif ($follow) {
            return; # we need deps
        } elsif ($@ && ref $@ && $@->isa("CPAN::Exception::RecursiveDependency")) {
            $CPAN::Frontend->mywarn($@);
            return $self->goodbye("[depend] -- NOT OK");
        }
        else {
          return $self->goodbye("[configure_requires] -- NOT OK");
        }
    }
    die "never reached";
}

#-> sub CPAN::Distribution::choose_MM_or_MB ;
sub choose_MM_or_MB {
    my($self) = @_;
    $self->satisfy_configure_requires() or return;
    my $local_file = $self->{localfile};
    my($mpl) = File::Spec->catfile($self->{build_dir},"Makefile.PL");
    my($mpl_exists) = -f $mpl;
    unless ($mpl_exists) {
        # NFS has been reported to have racing problems after the
        # renaming of a directory in some environments.
        # This trick helps.
        $CPAN::Frontend->mysleep(1);
        my $mpldh = DirHandle->new($self->{build_dir})
            or Carp::croak("Couldn't opendir $self->{build_dir}: $!");
        $mpl_exists = grep /^Makefile\.PL$/, $mpldh->read;
        $mpldh->close;
    }
    my $prefer_installer = "eumm"; # eumm|mb
    if (-f File::Spec->catfile($self->{build_dir},"Build.PL")) {
        if ($mpl_exists) { # they *can* choose
            if ($CPAN::META->has_inst("Module::Build")) {
                $prefer_installer = CPAN::HandleConfig->prefs_lookup(
                  $self, q{prefer_installer}
                );
                # M::B <= 0.35 left a DATA handle open that
                # causes problems upgrading M::B on Windows
                close *Module::Build::Version::DATA
                  if fileno *Module::Build::Version::DATA;
            }
        } else {
            $prefer_installer = "mb";
        }
    }
    if (lc($prefer_installer) eq "rand") {
        $prefer_installer = rand()<.5 ? "eumm" : "mb";
    }
    if (lc($prefer_installer) eq "mb") {
        $self->{modulebuild} = 1;
    } elsif ($self->{archived} eq "patch") {
        # not an edge case, nothing to install for sure
        my $why = "A patch file cannot be installed";
        $CPAN::Frontend->mywarn("Refusing to handle this file: $why\n");
        $self->{writemakefile} = CPAN::Distrostatus->new("NO $why");
    } elsif (! $mpl_exists) {
        $self->_edge_cases($mpl,$local_file);
    }
    if ($self->{build_dir}
        &&
        $CPAN::Config->{build_dir_reuse}
       ) {
        $self->store_persistent_state;
    }
    return $self;
}

# see also reanimate_build_dir
#-> CPAN::Distribution::store_persistent_state
sub store_persistent_state {
    my($self) = @_;
    my $dir = $self->{build_dir};
    unless (defined $dir && length $dir) {
        my $id = $self->id;
        $CPAN::Frontend->mywarnonce("build_dir of $id is not known, ".
                                    "will not store persistent state\n");
        return;
    }
    # self-build-dir
    my $sbd = Cwd::realpath(
        File::Spec->catdir($dir,                       File::Spec->updir ())
                           );
    # config-build-dir
    my $cbd = Cwd::realpath(
        # the catdir is a workaround for bug https://rt.cpan.org/Ticket/Display.html?id=101283
        File::Spec->catdir($CPAN::Config->{build_dir}, File::Spec->curdir())
    );
    unless ($sbd eq $cbd) {
        $CPAN::Frontend->mywarnonce("Directory '$dir' not below $CPAN::Config->{build_dir}, ".
                                    "will not store persistent state\n");
        return;
    }
    my $file = sprintf "%s.yml", $dir;
    my $yaml_module = CPAN::_yaml_module();
    if ($CPAN::META->has_inst($yaml_module)) {
        CPAN->_yaml_dumpfile(
                             $file,
                             {
                              time => time,
                              perl => CPAN::_perl_fingerprint(),
                              distribution => $self,
                             }
                            );
    } else {
        $CPAN::Frontend->myprintonce("'$yaml_module' not installed, ".
                                    "will not store persistent state\n");
    }
}

#-> CPAN::Distribution::try_download
sub try_download {
    my($self,$patch) = @_;
    my $norm = $self->normalize($patch);
    my($local_wanted) =
        File::Spec->catfile(
                            $CPAN::Config->{keep_source_where},
                            "authors",
                            "id",
                            split(/\//,$norm),
                           );
    $self->debug("Doing localize") if $CPAN::DEBUG;
    return CPAN::FTP->localize("authors/id/$norm",
                               $local_wanted);
}

{
    my $stdpatchargs = "";
    #-> CPAN::Distribution::patch
    sub patch {
        my($self) = @_;
        $self->debug("checking patches id[$self->{ID}]") if $CPAN::DEBUG;
        my $patches = $self->prefs->{patches};
        $patches ||= "";
        $self->debug("patches[$patches]") if $CPAN::DEBUG;
        if ($patches) {
            return unless @$patches;
            $self->safe_chdir($self->{build_dir});
            CPAN->debug("patches[$patches]") if $CPAN::DEBUG;
            my $patchbin = $CPAN::Config->{patch};
            unless ($patchbin && length $patchbin) {
                $CPAN::Frontend->mydie("No external patch command configured\n\n".
                                       "Please run 'o conf init /patch/'\n\n");
            }
            unless (MM->maybe_command($patchbin)) {
                $CPAN::Frontend->mydie("No external patch command available\n\n".
                                       "Please run 'o conf init /patch/'\n\n");
            }
            $patchbin = CPAN::HandleConfig->safe_quote($patchbin);
            local $ENV{PATCH_GET} = 0; # formerly known as -g0
            unless ($stdpatchargs) {
                my $system = "$patchbin --version |";
                local *FH;
                open FH, $system or die "Could not fork '$system': $!";
                local $/ = "\n";
                my $pversion;
              PARSEVERSION: while (<FH>) {
                    if (/^patch\s+([\d\.]+)/) {
                        $pversion = $1;
                        last PARSEVERSION;
                    }
                }
                if ($pversion) {
                    $stdpatchargs = "-N --fuzz=3";
                } else {
                    $stdpatchargs = "-N";
                }
            }
            my $countedpatches = @$patches == 1 ? "1 patch" : (scalar @$patches . " patches");
            $CPAN::Frontend->myprint("Applying $countedpatches:\n");
            my $patches_dir = $CPAN::Config->{patches_dir};
            for my $patch (@$patches) {
                if ($patches_dir && !File::Spec->file_name_is_absolute($patch)) {
                    my $f = File::Spec->catfile($patches_dir, $patch);
                    $patch = $f if -f $f;
                }
                unless (-f $patch) {
                    CPAN->debug("not on disk: patch[$patch]") if $CPAN::DEBUG;
                    if (my $trydl = $self->try_download($patch)) {
                        $patch = $trydl;
                    } else {
                        my $fail = "Could not find patch '$patch'";
                        $CPAN::Frontend->mywarn("$fail; cannot continue\n");
                        $self->{unwrapped} = CPAN::Distrostatus->new("NO -- $fail");
                        delete $self->{build_dir};
                        return;
                    }
                }
                $CPAN::Frontend->myprint("  $patch\n");
                my $readfh = CPAN::Tarzip->TIEHANDLE($patch);

                my $pcommand;
                my($ppp,$pfiles) = $self->_patch_p_parameter($readfh);
                if ($ppp eq "applypatch") {
                    $pcommand = "$CPAN::Config->{applypatch} -verbose";
                } else {
                    my $thispatchargs = join " ", $stdpatchargs, $ppp;
                    $pcommand = "$patchbin $thispatchargs";
                    require Config; # usually loaded from CPAN.pm
                    if ($Config::Config{osname} eq "solaris") {
                        # native solaris patch cannot patch readonly files
                        for my $file (@{$pfiles||[]}) {
                            my @stat = stat $file or next;
                            chmod $stat[2] | 0600, $file; # may fail
                        }
                    }
                }

                $readfh = CPAN::Tarzip->TIEHANDLE($patch); # open again
                my $writefh = FileHandle->new;
                $CPAN::Frontend->myprint("  $pcommand\n");
                unless (open $writefh, "|$pcommand") {
                    my $fail = "Could not fork '$pcommand'";
                    $CPAN::Frontend->mywarn("$fail; cannot continue\n");
                    $self->{unwrapped} = CPAN::Distrostatus->new("NO -- $fail");
                    delete $self->{build_dir};
                    return;
                }
                binmode($writefh);
                while (my $x = $readfh->READLINE) {
                    print $writefh $x;
                }
                unless (close $writefh) {
                    my $fail = "Could not apply patch '$patch'";
                    $CPAN::Frontend->mywarn("$fail; cannot continue\n");
                    $self->{unwrapped} = CPAN::Distrostatus->new("NO -- $fail");
                    delete $self->{build_dir};
                    return;
                }
            }
            $self->{patched}++;
        }
        return 1;
    }
}

# may return
# - "applypatch"
# - ("-p0"|"-p1", $files)
sub _patch_p_parameter {
    my($self,$fh) = @_;
    my $cnt_files   = 0;
    my $cnt_p0files = 0;
    my @files;
    local($_);
    while ($_ = $fh->READLINE) {
        if (
            $CPAN::Config->{applypatch}
            &&
            /\#\#\#\# ApplyPatch data follows \#\#\#\#/
           ) {
            return "applypatch"
        }
        next unless /^[\*\+]{3}\s(\S+)/;
        my $file = $1;
        push @files, $file;
        $cnt_files++;
        $cnt_p0files++ if -f $file;
        CPAN->debug("file[$file]cnt_files[$cnt_files]cnt_p0files[$cnt_p0files]")
            if $CPAN::DEBUG;
    }
    return "-p1" unless $cnt_files;
    my $opt_p = $cnt_files==$cnt_p0files ? "-p0" : "-p1";
    return ($opt_p, \@files);
}

#-> sub CPAN::Distribution::_edge_cases
# with "configure" or "Makefile" or single file scripts
sub _edge_cases {
    my($self,$mpl,$local_file) = @_;
    $self->debug(sprintf("makefilepl[%s]anycwd[%s]",
                         $mpl,
                         CPAN::anycwd(),
                        )) if $CPAN::DEBUG;
    my $build_dir = $self->{build_dir};
    my($configure) = File::Spec->catfile($build_dir,"Configure");
    if (-f $configure) {
        # do we have anything to do?
        $self->{configure} = $configure;
    } elsif (-f File::Spec->catfile($build_dir,"Makefile")) {
        $CPAN::Frontend->mywarn(qq{
Package comes with a Makefile and without a Makefile.PL.
We\'ll try to build it with that Makefile then.
});
        $self->{writemakefile} = CPAN::Distrostatus->new("YES");
        $CPAN::Frontend->mysleep(2);
    } else {
        my $cf = $self->called_for || "unknown";
        if ($cf =~ m|/|) {
            $cf =~ s|.*/||;
            $cf =~ s|\W.*||;
        }
        $cf =~ s|[/\\:]||g;     # risk of filesystem damage
        $cf = "unknown" unless length($cf);
        if (my $crud = $self->_contains_crud($build_dir)) {
            my $why = qq{Package contains $crud; not recognized as a perl package, giving up};
            $CPAN::Frontend->mywarn("$why\n");
            $self->{writemakefile} = CPAN::Distrostatus->new(qq{NO -- $why});
            return;
        }
        $CPAN::Frontend->mywarn(qq{Package seems to come without Makefile.PL.
  (The test -f "$mpl" returned false.)
  Writing one on our own (setting NAME to $cf)\a\n});
        $self->{had_no_makefile_pl}++;
        $CPAN::Frontend->mysleep(3);

        # Writing our own Makefile.PL

        my $exefile_stanza = "";
        if ($self->{archived} eq "maybe_pl") {
            $exefile_stanza = $self->_exefile_stanza($build_dir,$local_file);
        }

        my $fh = FileHandle->new;
        $fh->open(">$mpl")
            or Carp::croak("Could not open >$mpl: $!");
        $fh->print(
                   qq{# This Makefile.PL has been autogenerated by the module CPAN.pm
# because there was no Makefile.PL supplied.
# Autogenerated on: }.scalar localtime().qq{

use ExtUtils::MakeMaker;
WriteMakefile(
              NAME => q[$cf],$exefile_stanza
             );
});
        $fh->close;
    }
}

#-> CPAN;:Distribution::_contains_crud
sub _contains_crud {
    my($self,$dir) = @_;
    my(@dirs, $dh, @files);
    opendir $dh, $dir or return;
    my $dirent;
    for $dirent (readdir $dh) {
        next if $dirent =~ /^\.\.?$/;
        my $path = File::Spec->catdir($dir,$dirent);
        if (-d $path) {
            push @dirs, $dirent;
        } elsif (-f $path) {
            push @files, $dirent;
        }
    }
    if (@dirs && @files) {
        return "both files[@files] and directories[@dirs]";
    } elsif (@files > 2) {
        return "several files[@files] but no Makefile.PL or Build.PL";
    }
    return;
}

#-> CPAN;:Distribution::_exefile_stanza
sub _exefile_stanza {
    my($self,$build_dir,$local_file) = @_;

            my $fh = FileHandle->new;
            my $script_file = File::Spec->catfile($build_dir,$local_file);
            $fh->open($script_file)
                or Carp::croak("Could not open script '$script_file': $!");
            local $/ = "\n";
            # parse name and prereq
            my($state) = "poddir";
            my($name, $prereq) = ("", "");
            while (<$fh>) {
                if ($state eq "poddir" && /^=head\d\s+(\S+)/) {
                    if ($1 eq 'NAME') {
                        $state = "name";
                    } elsif ($1 eq 'PREREQUISITES') {
                        $state = "prereq";
                    }
                } elsif ($state =~ m{^(name|prereq)$}) {
                    if (/^=/) {
                        $state = "poddir";
                    } elsif (/^\s*$/) {
                        # nop
                    } elsif ($state eq "name") {
                        if ($name eq "") {
                            ($name) = /^(\S+)/;
                            $state = "poddir";
                        }
                    } elsif ($state eq "prereq") {
                        $prereq .= $_;
                    }
                } elsif (/^=cut\b/) {
                    last;
                }
            }
            $fh->close;

            for ($name) {
                s{.*<}{};       # strip X<...>
                s{>.*}{};
            }
            chomp $prereq;
            $prereq = join " ", split /\s+/, $prereq;
            my($PREREQ_PM) = join("\n", map {
                s{.*<}{};       # strip X<...>
                s{>.*}{};
                if (/[\s\'\"]/) { # prose?
                } else {
                    s/[^\w:]$//; # period?
                    " "x28 . "'$_' => 0,";
                }
            } split /\s*,\s*/, $prereq);

            if ($name) {
                my $to_file = File::Spec->catfile($build_dir, $name);
                rename $script_file, $to_file
                    or die "Can't rename $script_file to $to_file: $!";
            }

    return "
              EXE_FILES => ['$name'],
              PREREQ_PM => {
$PREREQ_PM
                           },
";
}

#-> CPAN::Distribution::_signature_business
sub _signature_business {
    my($self) = @_;
    my $check_sigs = CPAN::HandleConfig->prefs_lookup($self,
                                                      q{check_sigs});
    if ($check_sigs) {
        if ($CPAN::META->has_inst("Module::Signature")) {
            if (-f "SIGNATURE") {
                $self->debug("Module::Signature is installed, verifying") if $CPAN::DEBUG;
                my $rv = Module::Signature::verify();
                if ($rv != Module::Signature::SIGNATURE_OK() and
                    $rv != Module::Signature::SIGNATURE_MISSING()) {
                    $CPAN::Frontend->mywarn(
                                            qq{\nSignature invalid for }.
                                            qq{distribution file. }.
                                            qq{Please investigate.\n\n}
                                           );

                    my $wrap =
                        sprintf(qq{I'd recommend removing %s. Some error occurred   }.
                                qq{while checking its signature, so it could        }.
                                qq{be invalid. Maybe you have configured            }.
                                qq{your 'urllist' with a bad URL. Please check this }.
                                qq{array with 'o conf urllist' and retry. Or        }.
                                qq{examine the distribution in a subshell. Try
  look %s
and run
  cpansign -v
},
                                $self->{localfile},
                                $self->pretty_id,
                               );
                    $self->{signature_verify} = CPAN::Distrostatus->new("NO");
                    $CPAN::Frontend->mywarn(Text::Wrap::wrap("","",$wrap));
                    $CPAN::Frontend->mysleep(5) if $CPAN::Frontend->can("mysleep");
                } else {
                    $self->{signature_verify} = CPAN::Distrostatus->new("YES");
                    $self->debug("Module::Signature has verified") if $CPAN::DEBUG;
                }
            } else {
                $CPAN::Frontend->mywarn(qq{Package came without SIGNATURE\n\n});
            }
        } else {
            $self->debug("Module::Signature is NOT installed") if $CPAN::DEBUG;
        }
    }
}

#-> CPAN::Distribution::untar_me ;
sub untar_me {
    my($self,$ct) = @_;
    $self->{archived} = "tar";
    my $result = eval { $ct->untar() };
    if ($result) {
        $self->{unwrapped} = CPAN::Distrostatus->new("YES");
    } else {
        # unfortunately we have no $@ here, Tarzip is using mydie which dies with "\n"
        $self->{unwrapped} = CPAN::Distrostatus->new("NO -- untar failed");
    }
}

# CPAN::Distribution::unzip_me ;
sub unzip_me {
    my($self,$ct) = @_;
    $self->{archived} = "zip";
    if (eval { $ct->unzip() }) {
        $self->{unwrapped} = CPAN::Distrostatus->new("YES");
    } else {
        $self->{unwrapped} = CPAN::Distrostatus->new("NO -- unzip failed during unzip");
    }
    return;
}

sub handle_singlefile {
    my($self,$local_file) = @_;

    if ( $local_file =~ /\.pm(\.(gz|Z))?(?!\n)\Z/ ) {
        $self->{archived} = "pm";
    } elsif ( $local_file =~ /\.patch(\.(gz|bz2))?(?!\n)\Z/ ) {
        $self->{archived} = "patch";
    } else {
        $self->{archived} = "maybe_pl";
    }

    my $to = File::Basename::basename($local_file);
    if ($to =~ s/\.(gz|Z)(?!\n)\Z//) {
        if (eval{CPAN::Tarzip->new($local_file)->gunzip($to)}) {
            $self->{unwrapped} = CPAN::Distrostatus->new("YES");
        } else {
            $self->{unwrapped} = CPAN::Distrostatus->new("NO -- uncompressing failed");
        }
    } else {
        if (File::Copy::cp($local_file,".")) {
            $self->{unwrapped} = CPAN::Distrostatus->new("YES");
        } else {
            $self->{unwrapped} = CPAN::Distrostatus->new("NO -- copying failed");
        }
    }
    return $to;
}

#-> sub CPAN::Distribution::new ;
sub new {
    my($class,%att) = @_;

    # $CPAN::META->{cachemgr} ||= CPAN::CacheMgr->new();

    my $this = { %att };
    return bless $this, $class;
}

#-> sub CPAN::Distribution::look ;
sub look {
    my($self) = @_;

    if ($^O eq 'MacOS') {
      $self->Mac::BuildTools::look;
      return;
    }

    if (  $CPAN::Config->{'shell'} ) {
        $CPAN::Frontend->myprint(qq{
Trying to open a subshell in the build directory...
});
    } else {
        $CPAN::Frontend->myprint(qq{
Your configuration does not define a value for subshells.
Please define it with "o conf shell <your shell>"
});
        return;
    }
    my $dist = $self->id;
    my $dir;
    unless ($dir = $self->dir) {
        $self->get;
    }
    unless ($dir ||= $self->dir) {
        $CPAN::Frontend->mywarn(qq{
Could not determine which directory to use for looking at $dist.
});
        return;
    }
    my $pwd  = CPAN::anycwd();
    $self->safe_chdir($dir);
    $CPAN::Frontend->myprint(qq{Working directory is $dir\n});
    {
        local $ENV{CPAN_SHELL_LEVEL} = $ENV{CPAN_SHELL_LEVEL}||0;
        $ENV{CPAN_SHELL_LEVEL} += 1;
        my $shell = CPAN::HandleConfig->safe_quote($CPAN::Config->{'shell'});

        local $ENV{PERL5LIB} = defined($ENV{PERL5LIB})
            ? $ENV{PERL5LIB}
                : ($ENV{PERLLIB} || "");

        local $ENV{PERL5OPT} = defined $ENV{PERL5OPT} ? $ENV{PERL5OPT} : "";
        # local $ENV{PERL_USE_UNSAFE_INC} = exists $ENV{PERL_USE_UNSAFE_INC} ? $ENV{PERL_USE_UNSAFE_INC} : 1; # look
        $CPAN::META->set_perl5lib;
        local $ENV{MAKEFLAGS}; # protect us from outer make calls

        unless (system($shell) == 0) {
            my $code = $? >> 8;
            $CPAN::Frontend->mywarn("Subprocess shell exit code $code\n");
        }
    }
    $self->safe_chdir($pwd);
}

# CPAN::Distribution::cvs_import ;
sub cvs_import {
    my($self) = @_;
    $self->get;
    my $dir = $self->dir;

    my $package = $self->called_for;
    my $module = $CPAN::META->instance('CPAN::Module', $package);
    my $version = $module->cpan_version;

    my $userid = $self->cpan_userid;

    my $cvs_dir = (split /\//, $dir)[-1];
    $cvs_dir =~ s/-\d+[^-]+(?!\n)\Z//;
    my $cvs_root =
      $CPAN::Config->{cvsroot} || $ENV{CVSROOT};
    my $cvs_site_perl =
      $CPAN::Config->{cvs_site_perl} || $ENV{CVS_SITE_PERL};
    if ($cvs_site_perl) {
        $cvs_dir = "$cvs_site_perl/$cvs_dir";
    }
    my $cvs_log = qq{"imported $package $version sources"};
    $version =~ s/\./_/g;
    # XXX cvs: undocumented and unclear how it was meant to work
    my @cmd = ('cvs', '-d', $cvs_root, 'import', '-m', $cvs_log,
               "$cvs_dir", $userid, "v$version");

    my $pwd  = CPAN::anycwd();
    chdir($dir) or $CPAN::Frontend->mydie(qq{Could not chdir to "$dir": $!});

    $CPAN::Frontend->myprint(qq{Working directory is $dir\n});

    $CPAN::Frontend->myprint(qq{@cmd\n});
    system(@cmd) == 0 or
    # XXX cvs
        $CPAN::Frontend->mydie("cvs import failed");
    chdir($pwd) or $CPAN::Frontend->mydie(qq{Could not chdir to "$pwd": $!});
}

#-> sub CPAN::Distribution::readme ;
sub readme {
    my($self) = @_;
    my($dist) = $self->id;
    my($sans,$suffix) = $dist =~ /(.+)\.(tgz|tar[\._-]gz|tar\.Z|zip)$/;
    $self->debug("sans[$sans] suffix[$suffix]\n") if $CPAN::DEBUG;
    my($local_file);
    my($local_wanted) =
        File::Spec->catfile(
                            $CPAN::Config->{keep_source_where},
                            "authors",
                            "id",
                            split(/\//,"$sans.readme"),
                           );
    my $readme = "authors/id/$sans.readme";
    $self->debug("Doing localize for '$readme'") if $CPAN::DEBUG;
    $local_file = CPAN::FTP->localize($readme,
                                      $local_wanted)
        or $CPAN::Frontend->mydie(qq{No $sans.readme found});

    if ($^O eq 'MacOS') {
        Mac::BuildTools::launch_file($local_file);
        return;
    }

    my $fh_pager = FileHandle->new;
    local($SIG{PIPE}) = "IGNORE";
    my $pager = $CPAN::Config->{'pager'} || "cat";
    $fh_pager->open("|$pager")
        or die "Could not open pager $pager\: $!";
    my $fh_readme = FileHandle->new;
    $fh_readme->open($local_file)
        or $CPAN::Frontend->mydie(qq{Could not open "$local_file": $!});
    $CPAN::Frontend->myprint(qq{
Displaying file
  $local_file
with pager "$pager"
});
    $fh_pager->print(<$fh_readme>);
    $fh_pager->close;
}

#-> sub CPAN::Distribution::verifyCHECKSUM ;
sub verifyCHECKSUM {
    my($self) = @_;
  EXCUSE: {
        my @e;
        $self->{CHECKSUM_STATUS} ||= "";
        $self->{CHECKSUM_STATUS} eq "OK" and push @e, "Checksum was ok";
        $CPAN::Frontend->myprint(join "", map {"  $_\n"} @e) and return if @e;
    }
    my($lc_want,$lc_file,@local,$basename);
    @local = split(/\//,$self->id);
    pop @local;
    push @local, "CHECKSUMS";
    $lc_want =
        File::Spec->catfile($CPAN::Config->{keep_source_where},
                            "authors", "id", @local);
    local($") = "/";
    if (my $size = -s $lc_want) {
        $self->debug("lc_want[$lc_want]size[$size]") if $CPAN::DEBUG;
        my @stat = stat $lc_want;
        my $epoch_starting_support_of_cpan_path = 1637471530;
        if ($stat[9] >= $epoch_starting_support_of_cpan_path) {
            if ($self->CHECKSUM_check_file($lc_want, 1)) {
                return $self->{CHECKSUM_STATUS} = "OK";
            }
        } else {
            unlink $lc_want;
        }
    }
    $lc_file = CPAN::FTP->localize("authors/id/@local",
                                   $lc_want,1);
    unless ($lc_file) {
        $CPAN::Frontend->myprint("Trying $lc_want.gz\n");
        $local[-1] .= ".gz";
        $lc_file = CPAN::FTP->localize("authors/id/@local",
                                       "$lc_want.gz",1);
        if ($lc_file) {
            $lc_file =~ s/\.gz(?!\n)\Z//;
            eval{CPAN::Tarzip->new("$lc_file.gz")->gunzip($lc_file)};
        } else {
            return;
        }
    }
    if ($self->CHECKSUM_check_file($lc_file)) {
        return $self->{CHECKSUM_STATUS} = "OK";
    }
}

#-> sub CPAN::Distribution::SIG_check_file ;
sub SIG_check_file {
    my($self,$chk_file) = @_;
    my $rv = eval { Module::Signature::_verify($chk_file) };

    if ($rv eq Module::Signature::CANNOT_VERIFY()) {
        $CPAN::Frontend->myprint(qq{\nSignature for }.
                                 qq{file $chk_file could not be verified for an unknown reason. }.
                                 $self->as_string.
                                 qq{Module::Signature verification returned value $rv\n\n}
                                );

        my $wrap = qq{The manual says for this case: Cannot verify the
OpenPGP signature, maybe due to the lack of a network connection to
the key server, or if neither gnupg nor Crypt::OpenPGP exists on the
system. You probably want to analyse the situation and if you cannot
fix it you will have to decide whether you want to stop this session
or you want to turn off signature verification. The latter would be
done with the command 'o conf init check_sigs'};

        $CPAN::Frontend->mydie(Text::Wrap::wrap("","",$wrap));
    } if ($rv == Module::Signature::SIGNATURE_OK()) {
        $CPAN::Frontend->myprint("Signature for $chk_file ok\n");
        return $self->{SIG_STATUS} = "OK";
    } else {
        $CPAN::Frontend->mywarn(qq{\nSignature invalid for }.
                                 qq{file $chk_file. }.
                                 qq{Please investigate.\n\n}.
                                 $self->as_string.
                                 qq{Module::Signature verification returned value $rv\n\n}
                                );

        my $wrap = qq{I\'d recommend removing $chk_file. Its signature
is invalid. Maybe you have configured your 'urllist' with
a bad URL. Please check this array with 'o conf urllist', and
retry.};

        $CPAN::Frontend->mydie(Text::Wrap::wrap("","",$wrap));
    }
}

#-> sub CPAN::Distribution::CHECKSUM_check_file ;

# sloppy is 1 when we have an old checksums file that maybe is good
# enough

sub CHECKSUM_check_file {
    my($self,$chk_file,$sloppy) = @_;
    my($cksum,$file,$basename);

    $sloppy ||= 0;
    $self->debug("chk_file[$chk_file]sloppy[$sloppy]") if $CPAN::DEBUG;
    my $check_sigs = CPAN::HandleConfig->prefs_lookup($self,
                                                      q{check_sigs});
    if ($check_sigs) {
        if ($CPAN::META->has_inst("Module::Signature")) {
            $self->debug("Module::Signature is installed, verifying") if $CPAN::DEBUG;
            $self->SIG_check_file($chk_file);
        } else {
            $self->debug("Module::Signature is NOT installed") if $CPAN::DEBUG;
        }
    }

    $file = $self->{localfile};
    $basename = File::Basename::basename($file);
    my($signed_data);
    my $fh = FileHandle->new;
    if ($check_sigs) {
        my $tempdir;
        if ($CPAN::META->has_usable("File::Temp")) {
            $tempdir = File::Temp::tempdir("CHECKSUMS-XXXX", CLEANUP => 1, DIR => "/tmp" );
        } else {
            $tempdir = File::Spec->catdir(File::Spec->tmpdir, "CHECKSUMS-$$");
            File::Path::mkpath($tempdir);
        }
        my $tempfile = File::Spec->catfile($tempdir, "CHECKSUMS.$$");
        unlink $tempfile; # ignore missing file
        my $devnull = File::Spec->devnull;
        my $gpg = $CPAN::Config->{gpg} or
            $CPAN::Frontend->mydie("Your configuration suggests that you do not have 'gpg' installed. This is needed to verify checksums with the config variable 'check_sigs' on. Please configure it with 'o conf init gpg'");
        my $system = qq{"$gpg" --verify --batch --no-tty --output "$tempfile" "$chk_file" 2> "$devnull"};
        0 == system $system or $CPAN::Frontend->mydie("gpg run was failing, cannot continue: $system");
        open $fh, $tempfile or $CPAN::Frontend->mydie("Could not open $tempfile: $!");
        local $/;
        $signed_data = <$fh>;
        close $fh;
        File::Path::rmtree($tempdir);
    } else {
        my $fh = FileHandle->new;
        if (open $fh, $chk_file) {
            local($/);
            $signed_data = <$fh>;
        } else {
            $CPAN::Frontend->mydie("Could not open $chk_file for reading");
        }
        close $fh;
    }
    $signed_data =~ s/\015?\012/\n/g;
    my($compmt) = Safe->new();
    $cksum = $compmt->reval($signed_data);
    if ($@) {
        rename $chk_file, "$chk_file.bad";
        Carp::confess($@) if $@;
    }

    if (! ref $cksum or ref $cksum ne "HASH") {
        $CPAN::Frontend->mywarn(qq{
Warning: checksum file '$chk_file' broken.

When trying to read that file I expected to get a hash reference
for further processing, but got garbage instead.
});
        my $answer = CPAN::Shell::colorable_makemaker_prompt("Proceed nonetheless?", "no");
        $answer =~ /^\s*y/i or $CPAN::Frontend->mydie("Aborted.\n");
        $self->{CHECKSUM_STATUS} = "NIL -- CHECKSUMS file broken";
        return;
    } elsif (exists $cksum->{$basename} && ! exists $cksum->{$basename}{cpan_path}) {
        $CPAN::Frontend->mywarn(qq{
Warning: checksum file '$chk_file' not conforming.

The cksum does not contain the key 'cpan_path' for '$basename'.
});
        my $answer = CPAN::Shell::colorable_makemaker_prompt("Proceed nonetheless?", "no");
        $answer =~ /^\s*y/i or $CPAN::Frontend->mydie("Aborted.\n");
        $self->{CHECKSUM_STATUS} = "NIL -- CHECKSUMS file without cpan_path";
        return;
    } elsif (exists $cksum->{$basename} && substr($self->{ID},0,length($cksum->{$basename}{cpan_path}))
             ne $cksum->{$basename}{cpan_path}) {
        $CPAN::Frontend->mywarn(qq{
Warning: checksum file not matching path '$self->{ID}'.

The cksum contain the key 'cpan_path=$cksum->{$basename}{cpan_path}'
which does not match the ID of the distribution '$self->{ID}'.
Something's suspicious might be going on here. Please investigate.

});
        my $answer = CPAN::Shell::colorable_makemaker_prompt("Proceed nonetheless?", "no");
        $answer =~ /^\s*y/i or $CPAN::Frontend->mydie("Aborted.\n");
        $self->{CHECKSUM_STATUS} = "NIL -- CHECKSUMS non-matching cpan_path vs. ID";
        return;
    } elsif (exists $cksum->{$basename}{sha256}) {
        $self->debug("Found checksum for $basename:" .
                     "$cksum->{$basename}{sha256}\n") if $CPAN::DEBUG;

        open($fh, $file);
        binmode $fh;
        my $eq = $self->eq_CHECKSUM($fh,$cksum->{$basename}{sha256});
        $fh->close;
        $fh = CPAN::Tarzip->TIEHANDLE($file);

        unless ($eq) {
            my $dg = Digest::SHA->new(256);
            my($data,$ref);
            $ref = \$data;
            while ($fh->READ($ref, 4096) > 0) {
                $dg->add($data);
            }
            my $hexdigest = $dg->hexdigest;
            $eq += $hexdigest eq $cksum->{$basename}{'sha256-ungz'};
        }

        if ($eq) {
            $CPAN::Frontend->myprint("Checksum for $file ok\n");
            return $self->{CHECKSUM_STATUS} = "OK";
        } else {
            $CPAN::Frontend->myprint(qq{\nChecksum mismatch for }.
                                     qq{distribution file. }.
                                     qq{Please investigate.\n\n}.
                                     $self->as_string,
                                     $CPAN::META->instance(
                                                           'CPAN::Author',
                                                           $self->cpan_userid
                                                          )->as_string);

            my $wrap = qq{I\'d recommend removing $file. Its
checksum is incorrect. Maybe you have configured your 'urllist' with
a bad URL. Please check this array with 'o conf urllist', and
retry.};

            $CPAN::Frontend->mydie(Text::Wrap::wrap("","",$wrap));

            # former versions just returned here but this seems a
            # serious threat that deserves a die

            # $CPAN::Frontend->myprint("\n\n");
            # sleep 3;
            # return;
        }
        # close $fh if fileno($fh);
    } else {
        return if $sloppy;
        unless ($self->{CHECKSUM_STATUS}) {
            $CPAN::Frontend->mywarn(qq{
Warning: No checksum for $basename in $chk_file.

The cause for this may be that the file is very new and the checksum
has not yet been calculated, but it may also be that something is
going awry right now.
});
            my $answer = CPAN::Shell::colorable_makemaker_prompt("Proceed?", "yes");
            $answer =~ /^\s*y/i or $CPAN::Frontend->mydie("Aborted.\n");
        }
        $self->{CHECKSUM_STATUS} = "NIL -- distro not in CHECKSUMS file";
        return;
    }
}

#-> sub CPAN::Distribution::eq_CHECKSUM ;
sub eq_CHECKSUM {
    my($self,$fh,$expect) = @_;
    if ($CPAN::META->has_inst("Digest::SHA")) {
        my $dg = Digest::SHA->new(256);
        my($data);
        while (read($fh, $data, 4096)) {
            $dg->add($data);
        }
        my $hexdigest = $dg->hexdigest;
        # warn "fh[$fh] hex[$hexdigest] aexp[$expectMD5]";
        return $hexdigest eq $expect;
    }
    return 1;
}

#-> sub CPAN::Distribution::force ;

# Both CPAN::Modules and CPAN::Distributions know if "force" is in
# effect by autoinspection, not by inspecting a global variable. One
# of the reason why this was chosen to work that way was the treatment
# of dependencies. They should not automatically inherit the force
# status. But this has the downside that ^C and die() will return to
# the prompt but will not be able to reset the force_update
# attributes. We try to correct for it currently in the read_metadata
# routine, and immediately before we check for a Signal. I hope this
# works out in one of v1.57_53ff

# "Force get forgets previous error conditions"

#-> sub CPAN::Distribution::fforce ;
sub fforce {
  my($self, $method) = @_;
  $self->force($method,1);
}

#-> sub CPAN::Distribution::force ;
sub force {
  my($self, $method,$fforce) = @_;
  my %phase_map = (
                   get => [
                           "unwrapped",
                           "build_dir",
                           "archived",
                           "localfile",
                           "CHECKSUM_STATUS",
                           "signature_verify",
                           "prefs",
                           "prefs_file",
                           "prefs_file_doc",
                           "cleanup_after_install_done",
                          ],
                   make => [
                            "writemakefile",
                            "make",
                            "modulebuild",
                            "prereq_pm",
                            "cleanup_after_install_done",
                           ],
                   test => [
                            "badtestcnt",
                            "make_test",
                            "cleanup_after_install_done",
                          ],
                   install => [
                               "install",
                               "cleanup_after_install_done",
                              ],
                   unknown => [
                               "reqtype",
                               "yaml_content",
                               "cleanup_after_install_done",
                              ],
                  );
  my $methodmatch = 0;
  my $ldebug = 0;
 PHASE: for my $phase (qw(unknown get make test install)) { # order matters
      $methodmatch = 1 if $fforce || ($method && $phase eq $method);
      next unless $methodmatch;
    ATTRIBUTE: for my $att (@{$phase_map{$phase}}) {
          if ($phase eq "get") {
              if (substr($self->id,-1,1) eq "."
                  && $att =~ /(unwrapped|build_dir|archived)/ ) {
                  # cannot be undone for local distros
                  next ATTRIBUTE;
              }
              if ($att eq "build_dir"
                  && $self->{build_dir}
                  && $CPAN::META->{is_tested}
                 ) {
                  delete $CPAN::META->{is_tested}{$self->{build_dir}};
              }
          } elsif ($phase eq "test") {
              if ($att eq "make_test"
                  && $self->{make_test}
                  && $self->{make_test}{COMMANDID}
                  && $self->{make_test}{COMMANDID} == $CPAN::CurrentCommandId
                 ) {
                  # endless loop too likely
                  next ATTRIBUTE;
              }
          }
          delete $self->{$att};
          if ($ldebug || $CPAN::DEBUG) {
              # local $CPAN::DEBUG = 16; # Distribution
              CPAN->debug(sprintf "id[%s]phase[%s]att[%s]", $self->id, $phase, $att);
          }
      }
  }
  if ($method && $method =~ /make|test|install/) {
    $self->{force_update} = 1; # name should probably have been force_install
  }
}

#-> sub CPAN::Distribution::notest ;
sub notest {
  my($self, $method) = @_;
  # $CPAN::Frontend->mywarn("XDEBUG: set notest for $self $method");
  $self->{"notest"}++; # name should probably have been force_install
}

#-> sub CPAN::Distribution::unnotest ;
sub unnotest {
  my($self) = @_;
  # warn "XDEBUG: deleting notest";
  delete $self->{notest};
}

#-> sub CPAN::Distribution::unforce ;
sub unforce {
  my($self) = @_;
  delete $self->{force_update};
}

#-> sub CPAN::Distribution::isa_perl ;
sub isa_perl {
  my($self) = @_;
  my $file = File::Basename::basename($self->id);
  if ($file =~ m{ ^ perl
                  (
                   -(5\.\d+\.\d+)
                   |
                   (5)[._-](00[0-5](?:_[0-4][0-9])?)
                  )
                  \.tar[._-](?:gz|bz2)
                  (?!\n)\Z
                }xs) {
    my $perl_version;
    if ($2) {
        $perl_version = $2;
    } else {
        $perl_version = "$3.$4";
    }
    return $perl_version;
  } elsif ($self->cpan_comment
           &&
           $self->cpan_comment =~ /isa_perl\(.+?\)/) {
    return $1;
  }
}


#-> sub CPAN::Distribution::perl ;
sub perl {
    my ($self) = @_;
    if (! $self) {
        use Carp qw(carp);
        carp __PACKAGE__ . "::perl was called without parameters.";
    }
    return CPAN::HandleConfig->safe_quote($CPAN::Perl);
}

#-> sub CPAN::Distribution::shortcut_prepare ;
# return values: undef means don't shortcut; 0 means shortcut as fail;
# and 1 means shortcut as success

sub shortcut_prepare {
    my ($self) = @_;

    $self->debug("checking archive type[$self->{ID}]") if $CPAN::DEBUG;
    if (!$self->{archived} || $self->{archived} eq "NO") {
        return $self->goodbye("Is neither a tar nor a zip archive.");
    }

    $self->debug("checking unwrapping[$self->{ID}]") if $CPAN::DEBUG;
    if (!$self->{unwrapped}
        || (
            UNIVERSAL::can($self->{unwrapped},"failed") ?
            $self->{unwrapped}->failed :
            $self->{unwrapped} =~ /^NO/
            )) {
        return $self->goodbye("Had problems unarchiving. Please build manually");
    }

    $self->debug("checking signature[$self->{ID}]") if $CPAN::DEBUG;
    if ( ! $self->{force_update}
        && exists $self->{signature_verify}
        && (
                UNIVERSAL::can($self->{signature_verify},"failed") ?
                $self->{signature_verify}->failed :
                $self->{signature_verify} =~ /^NO/
            )
    ) {
        return $self->goodbye("Did not pass the signature test.");
    }

    $self->debug("checking writemakefile[$self->{ID}]") if $CPAN::DEBUG;
    if ($self->{writemakefile}) {
        if (
                UNIVERSAL::can($self->{writemakefile},"failed") ?
                $self->{writemakefile}->failed :
                $self->{writemakefile} =~ /^NO/
            ) {
            # XXX maybe a retry would be in order?
            my $err = UNIVERSAL::can($self->{writemakefile},"text") ?
                $self->{writemakefile}->text :
                    $self->{writemakefile};
            $err =~ s/^NO\s*(--\s+)?//;
            $err ||= "Had some problem writing Makefile";
            $err .= ", not re-running";
            return $self->goodbye($err);
        } else {
            return $self->success("Has already been prepared");
        }
    }

    $self->debug("checking configure_requires_later[$self->{ID}]") if $CPAN::DEBUG;
    if( my $later = $self->{configure_requires_later} ) { # see also undelay
        return $self->goodbye($later);
    }

    return undef; # no shortcut
}

sub prepare {
    my ($self) = @_;

    $self->get
        or return;

    if ( defined( my $sc = $self->shortcut_prepare) ) {
        return $sc;
    }

    local $ENV{PERL5LIB} = defined($ENV{PERL5LIB})
                           ? $ENV{PERL5LIB}
                           : ($ENV{PERLLIB} || "");
    local $ENV{PERL5OPT} = defined $ENV{PERL5OPT} ? $ENV{PERL5OPT} : "";
    local $ENV{PERL_USE_UNSAFE_INC} =
        exists $ENV{PERL_USE_UNSAFE_INC} && defined $ENV{PERL_USE_UNSAFE_INC}
        ? $ENV{PERL_USE_UNSAFE_INC} : 1; # prepare
    $CPAN::META->set_perl5lib;
    local $ENV{MAKEFLAGS}; # protect us from outer make calls

    if ($CPAN::Signal) {
        delete $self->{force_update};
        return;
    }

    my $builddir = $self->dir or
        $CPAN::Frontend->mydie("PANIC: Cannot determine build directory\n");

    unless (chdir $builddir) {
        $CPAN::Frontend->mywarn("Couldn't chdir to '$builddir': $!");
        return;
    }

    if ($CPAN::Signal) {
        delete $self->{force_update};
        return;
    }

    $self->debug("Changed directory to $builddir") if $CPAN::DEBUG;

    local $ENV{PERL_AUTOINSTALL} = $ENV{PERL_AUTOINSTALL} || '';
    local $ENV{PERL_EXTUTILS_AUTOINSTALL} = $ENV{PERL_EXTUTILS_AUTOINSTALL} || '';
    $self->choose_MM_or_MB
        or return;

    my $configurator = $self->{configure} ? "Configure"
                     : $self->{modulebuild} ? "Build.PL"
                     : "Makefile.PL";

    $CPAN::Frontend->myprint("Configuring ".$self->id." with $configurator\n");

    if ($CPAN::Config->{prerequisites_policy} eq "follow") {
        $ENV{PERL_AUTOINSTALL}          ||= "--defaultdeps";
        $ENV{PERL_EXTUTILS_AUTOINSTALL} ||= "--defaultdeps";
    }

    my $system;
    my $pl_commandline;
    if ($self->prefs->{pl}) {
        $pl_commandline = $self->prefs->{pl}{commandline};
    }
    local $ENV{PERL} = defined $ENV{PERL}? $ENV{PERL} : $^X;
    local $ENV{PERL5_CPAN_IS_EXECUTING} = $ENV{PERL5_CPAN_IS_EXECUTING} || '';
    local $ENV{PERL_MM_USE_DEFAULT} = 1 if $CPAN::Config->{use_prompt_default};
    local $ENV{NONINTERACTIVE_TESTING} = 1 if $CPAN::Config->{use_prompt_default};
    if ($pl_commandline) {
        $system = $pl_commandline;
        $ENV{PERL} = $^X;
    } elsif ($self->{'configure'}) {
        $system = $self->{'configure'};
    } elsif ($self->{modulebuild}) {
        my($perl) = $self->perl or die "Couldn\'t find executable perl\n";
        my $mbuildpl_arg = $self->_make_phase_arg("pl");
        $system = sprintf("%s Build.PL%s",
                          $perl,
                          $mbuildpl_arg ? " $mbuildpl_arg" : "",
                         );
    } else {
        my($perl) = $self->perl or die "Couldn\'t find executable perl\n";
        my $switch = "";
# This needs a handler that can be turned on or off:
#        $switch = "-MExtUtils::MakeMaker ".
#            "-Mops=:default,:filesys_read,:filesys_open,require,chdir"
#            if $] > 5.00310;
        my $makepl_arg = $self->_make_phase_arg("pl");
        $ENV{PERL5_CPAN_IS_EXECUTING} = File::Spec->catfile($self->{build_dir},
                                                            "Makefile.PL");
        $system = sprintf("%s%s Makefile.PL%s",
                          $perl,
                          $switch ? " $switch" : "",
                          $makepl_arg ? " $makepl_arg" : "",
                         );
    }
    my $pl_env;
    if ($self->prefs->{pl}) {
        $pl_env = $self->prefs->{pl}{env};
    }
    local @ENV{keys %$pl_env} = values %$pl_env if $pl_env;
    if (exists $self->{writemakefile}) {
    } else {
        local($SIG{ALRM}) = sub { die "inactivity_timeout reached\n" };
        my($ret,$pid,$output);
        $@ = "";
        my $go_via_alarm;
        if ($CPAN::Config->{inactivity_timeout}) {
            require Config;
            if ($Config::Config{d_alarm}
                &&
                $Config::Config{d_alarm} eq "define"
               ) {
                $go_via_alarm++
            } else {
                $CPAN::Frontend->mywarn("Warning: you have configured the config ".
                                        "variable 'inactivity_timeout' to ".
                                        "'$CPAN::Config->{inactivity_timeout}'. But ".
                                        "on this machine the system call 'alarm' ".
                                        "isn't available. This means that we cannot ".
                                        "provide the feature of intercepting long ".
                                        "waiting code and will turn this feature off.\n"
                                       );
                $CPAN::Config->{inactivity_timeout} = 0;
            }
        }
        if ($go_via_alarm) {
            if ( $self->_should_report('pl') ) {
                ($output, $ret) = CPAN::Reporter::record_command(
                    $system,
                    $CPAN::Config->{inactivity_timeout},
                );
                CPAN::Reporter::grade_PL( $self, $system, $output, $ret );
            }
            else {
                eval {
                    alarm $CPAN::Config->{inactivity_timeout};
                    local $SIG{CHLD}; # = sub { wait };
                    if (defined($pid = fork)) {
                        if ($pid) { #parent
                            # wait;
                            waitpid $pid, 0;
                        } else {    #child
                            # note, this exec isn't necessary if
                            # inactivity_timeout is 0. On the Mac I'd
                            # suggest, we set it always to 0.
                            exec $system;
                        }
                    } else {
                        $CPAN::Frontend->myprint("Cannot fork: $!");
                        return;
                    }
                };
                alarm 0;
                if ($@) {
                    kill 9, $pid;
                    waitpid $pid, 0;
                    my $err = "$@";
                    $CPAN::Frontend->myprint($err);
                    $self->{writemakefile} = CPAN::Distrostatus->new("NO $err");
                    $@ = "";
                    $self->store_persistent_state;
                    return $self->goodbye("$system -- TIMED OUT");
                }
            }
        } else {
            if (my $expect_model = $self->_prefs_with_expect("pl")) {
                # XXX probably want to check _should_report here and warn
                # about not being able to use CPAN::Reporter with expect
                $ret = $self->_run_via_expect($system,'writemakefile',$expect_model);
                if (! defined $ret
                    && $self->{writemakefile}
                    && $self->{writemakefile}->failed) {
                    # timeout
                    return;
                }
            }
            elsif ( $self->_should_report('pl') ) {
                ($output, $ret) = eval { CPAN::Reporter::record_command($system) };
                if (! defined $output or $@) {
                    my $err = $@ || "Unknown error";
                    $CPAN::Frontend->mywarn("Error while running PL phase: $err\n");
                    $self->{writemakefile} = CPAN::Distrostatus
                        ->new("NO '$system' returned status $ret and no output");
                    return $self->goodbye("$system -- NOT OK");
                }
                CPAN::Reporter::grade_PL( $self, $system, $output, $ret );
            }
            else {
                $ret = system($system);
            }
            if ($ret != 0) {
                $self->{writemakefile} = CPAN::Distrostatus
                    ->new("NO '$system' returned status $ret");
                $CPAN::Frontend->mywarn("Warning: No success on command[$system]\n");
                $self->store_persistent_state;
                return $self->goodbye("$system -- NOT OK");
            }
        }
        if (-f "Makefile" || -f "Build" || ($^O eq 'VMS' && (-f 'descrip.mms' || -f 'Build.com'))) {
            $self->{writemakefile} = CPAN::Distrostatus->new("YES");
            delete $self->{make_clean}; # if cleaned before, enable next
            $self->store_persistent_state;
            return $self->success("$system -- OK");
        } else {
            my $makefile = $self->{modulebuild} ? "Build" : "Makefile";
            my $why = "No '$makefile' created";
            $CPAN::Frontend->mywarn($why);
            $self->{writemakefile} = CPAN::Distrostatus
                ->new(qq{NO -- $why\n});
            $self->store_persistent_state;
            return $self->goodbye("$system -- NOT OK");
        }
    }
    $self->store_persistent_state;
    return 1; # success
}

#-> sub CPAN::Distribution::shortcut_make ;
# return values: undef means don't shortcut; 0 means shortcut as fail;
# and 1 means shortcut as success
sub shortcut_make {
    my ($self) = @_;

    $self->debug("checking make/build results[$self->{ID}]") if $CPAN::DEBUG;
    if (defined $self->{make}) {
        if (UNIVERSAL::can($self->{make},"failed") ?
            $self->{make}->failed :
            $self->{make} =~ /^NO/
        ) {
            if ($self->{force_update}) {
                # Trying an already failed 'make' (unless somebody else blocks)
                return undef; # no shortcut
            } else {
                # introduced for turning recursion detection into a distrostatus
                my $error = length $self->{make}>3
                    ? substr($self->{make},3) : "Unknown error";
                $self->store_persistent_state;
                return $self->goodbye("Could not make: $error\n");
            }
        } else {
            return $self->success("Has already been made")
        }
    }
    return undef; # no shortcut
}

#-> sub CPAN::Distribution::make ;
sub make {
    my($self) = @_;

    $self->pre_make();

    if (exists $self->{cleanup_after_install_done}) {
        $self->post_make();
        return $self->get;
    }

    $self->debug("checking goto id[$self->{ID}]") if $CPAN::DEBUG;
    if (my $goto = $self->prefs->{goto}) {
        $self->post_make();
        return $self->goto($goto);
    }
    # Emergency brake if they said install Pippi and get newest perl

    # XXX Would this make more sense in shortcut_prepare, since
    # that doesn't make sense on a perl dist either?  Broader
    # question: what is the purpose of suggesting force install
    # on a perl distribution?  That seems unlikely to result in
    # such a dependency being satisfied, even if the perl is
    # successfully installed.  This situation is tantamount to
    # a prereq on a version of perl greater than the current one
    # so I think we should just abort. -- xdg, 2012-04-06
    if ($self->isa_perl) {
        if (
            $self->called_for ne $self->id &&
            ! $self->{force_update}
        ) {
            # if we die here, we break bundles
            $CPAN::Frontend
                ->mywarn(sprintf(
                            qq{The most recent version "%s" of the module "%s"
is part of the perl-%s distribution. To install that, you need to run
  force install %s   --or--
  install %s
},
                             $CPAN::META->instance(
                                                   'CPAN::Module',
                                                   $self->called_for
                                                  )->cpan_version,
                             $self->called_for,
                             $self->isa_perl,
                             $self->called_for,
                             $self->pretty_id,
                            ));
            $self->{make} = CPAN::Distrostatus->new("NO isa perl");
            $CPAN::Frontend->mysleep(1);
            $self->post_make();
            return;
        }
    }

    unless ($self->prepare){
        $self->post_make();
        return;
    }

    if ( defined( my $sc = $self->shortcut_make) ) {
        $self->post_make();
        return $sc;
    }

    if ($CPAN::Signal) {
        delete $self->{force_update};
        $self->post_make();
        return;
    }

    my $builddir = $self->dir or
        $CPAN::Frontend->mydie("PANIC: Cannot determine build directory\n");

    unless (chdir $builddir) {
        $CPAN::Frontend->mywarn("Couldn't chdir to '$builddir': $!");
        $self->post_make();
        return;
    }

    my $make = $self->{modulebuild} ? "Build" : "make";
    $CPAN::Frontend->myprint(sprintf "Running %s for %s\n", $make, $self->id);
    local $ENV{PERL5LIB} = defined($ENV{PERL5LIB})
                           ? $ENV{PERL5LIB}
                           : ($ENV{PERLLIB} || "");
    local $ENV{PERL5OPT} = defined $ENV{PERL5OPT} ? $ENV{PERL5OPT} : "";
    local $ENV{PERL_USE_UNSAFE_INC} =
        exists $ENV{PERL_USE_UNSAFE_INC} && defined $ENV{PERL_USE_UNSAFE_INC}
        ? $ENV{PERL_USE_UNSAFE_INC} : 1; # make
    $CPAN::META->set_perl5lib;
    local $ENV{MAKEFLAGS}; # protect us from outer make calls

    if ($CPAN::Signal) {
        delete $self->{force_update};
        $self->post_make();
        return;
    }

    if ($^O eq 'MacOS') {
        Mac::BuildTools::make($self);
        $self->post_make();
        return;
    }

    my %env;
    while (my($k,$v) = each %ENV) {
        next if defined $v;
        $env{$k} = '';
    }
    local @ENV{keys %env} = values %env;
    my $satisfied = eval { $self->satisfy_requires };
    if ($@) {
        return $self->goodbye($@);
    }
    unless ($satisfied){
        $self->post_make();
        return;
    }
    if ($CPAN::Signal) {
        delete $self->{force_update};
        $self->post_make();
        return;
    }

    # need to chdir again, because $self->satisfy_requires might change the directory
    unless (chdir $builddir) {
        $CPAN::Frontend->mywarn("Couldn't chdir to '$builddir': $!");
        $self->post_make();
        return;
    }

    my $system;
    my $make_commandline;
    if ($self->prefs->{make}) {
        $make_commandline = $self->prefs->{make}{commandline};
    }
    local $ENV{PERL} = defined $ENV{PERL}? $ENV{PERL} : $^X;
    local $ENV{PERL_MM_USE_DEFAULT} = 1 if $CPAN::Config->{use_prompt_default};
    local $ENV{NONINTERACTIVE_TESTING} = 1 if $CPAN::Config->{use_prompt_default};
    if ($make_commandline) {
        $system = $make_commandline;
        $ENV{PERL} = CPAN::find_perl();
    } else {
        if ($self->{modulebuild}) {
            unless (-f "Build" || ($^O eq 'VMS' && -f 'Build.com')) {
                my $cwd = CPAN::anycwd();
                $CPAN::Frontend->mywarn("Alert: no Build file available for 'make $self->{id}'".
                                        " in cwd[$cwd]. Danger, Will Robinson!\n");
                $CPAN::Frontend->mysleep(5);
            }
            $system = join " ", $self->_build_command(), $CPAN::Config->{mbuild_arg};
        } else {
            $system = join " ", $self->_make_command(),  $CPAN::Config->{make_arg};
        }
        $system =~ s/\s+$//;
        my $make_arg = $self->_make_phase_arg("make");
        $system = sprintf("%s%s",
                          $system,
                          $make_arg ? " $make_arg" : "",
                         );
    }
    my $make_env;
    if ($self->prefs->{make}) {
        $make_env = $self->prefs->{make}{env};
    }
    local @ENV{keys %$make_env} = values %$make_env if $make_env;
    my $expect_model = $self->_prefs_with_expect("make");
    my $want_expect = 0;
    if ( $expect_model && @{$expect_model->{talk}} ) {
        my $can_expect = $CPAN::META->has_inst("Expect");
        if ($can_expect) {
            $want_expect = 1;
        } else {
            $CPAN::Frontend->mywarn("Expect not installed, falling back to ".
                                    "system()\n");
        }
    }
    my ($system_ok, $system_err);
    if ($want_expect) {
        # XXX probably want to check _should_report here and
        # warn about not being able to use CPAN::Reporter with expect
        $system_ok = $self->_run_via_expect($system,'make',$expect_model) == 0;
    }
    elsif ( $self->_should_report('make') ) {
        my ($output, $ret) = CPAN::Reporter::record_command($system);
        CPAN::Reporter::grade_make( $self, $system, $output, $ret );
        $system_ok = ! $ret;
    }
    else {
        my $rc = system($system);
        $system_ok = $rc == 0;
        $system_err = $! if $rc == -1;
    }
    $self->introduce_myself;
    if ( $system_ok ) {
        $CPAN::Frontend->myprint("  $system -- OK\n");
        $self->{make} = CPAN::Distrostatus->new("YES");
    } else {
        $self->{writemakefile} ||= CPAN::Distrostatus->new("YES");
        $self->{make} = CPAN::Distrostatus->new("NO");
        $CPAN::Frontend->mywarn("  $system -- NOT OK\n");
        $CPAN::Frontend->mywarn("  $system_err\n") if defined $system_err;
    }
    $self->store_persistent_state;

    $self->post_make();

    return !! $system_ok;
}

# CPAN::Distribution::goodbye ;
sub goodbye {
    my($self,$goodbye) = @_;
    my $id = $self->pretty_id;
    $CPAN::Frontend->mywarn("  $id\n  $goodbye\n");
    return 0; # must be explicit false, not undef
}

sub success {
    my($self,$why) = @_;
    my $id = $self->pretty_id;
    $CPAN::Frontend->myprint("  $id\n  $why\n");
    return 1;
}

# CPAN::Distribution::_run_via_expect ;
sub _run_via_expect {
    my($self,$system,$phase,$expect_model) = @_;
    CPAN->debug("system[$system]expect_model[$expect_model]") if $CPAN::DEBUG;
    if ($CPAN::META->has_inst("Expect")) {
        my $expo = Expect->new;  # expo Expect object;
        $expo->spawn($system);
        $expect_model->{mode} ||= "deterministic";
        if ($expect_model->{mode} eq "deterministic") {
            return $self->_run_via_expect_deterministic($expo,$phase,$expect_model);
        } elsif ($expect_model->{mode} eq "anyorder") {
            return $self->_run_via_expect_anyorder($expo,$phase,$expect_model);
        } else {
            die "Panic: Illegal expect mode: $expect_model->{mode}";
        }
    } else {
        $CPAN::Frontend->mywarn("Expect not installed, falling back to system()\n");
        return system($system);
    }
}

sub _run_via_expect_anyorder {
    my($self,$expo,$phase,$expect_model) = @_;
    my $timeout = $expect_model->{timeout} || 5;
    my $reuse = $expect_model->{reuse};
    my @expectacopy = @{$expect_model->{talk}}; # we trash it!
    my $but = "";
    my $timeout_start = time;
  EXPECT: while () {
        my($eof,$ran_into_timeout);
        # XXX not up to the full power of expect. one could certainly
        # wrap all of the talk pairs into a single expect call and on
        # success tweak it and step ahead to the next question. The
        # current implementation unnecessarily limits itself to a
        # single match.
        my @match = $expo->expect(1,
                                  [ eof => sub {
                                        $eof++;
                                    } ],
                                  [ timeout => sub {
                                        $ran_into_timeout++;
                                    } ],
                                  -re => eval"qr{.}",
                                 );
        if ($match[2]) {
            $but .= $match[2];
        }
        $but .= $expo->clear_accum;
        if ($eof) {
            $expo->soft_close;
            return $expo->exitstatus();
        } elsif ($ran_into_timeout) {
            # warn "DEBUG: they are asking a question, but[$but]";
            for (my $i = 0; $i <= $#expectacopy; $i+=2) {
                my($next,$send) = @expectacopy[$i,$i+1];
                my $regex = eval "qr{$next}";
                # warn "DEBUG: will compare with regex[$regex].";
                if ($but =~ /$regex/) {
                    # warn "DEBUG: will send send[$send]";
                    $expo->send($send);
                    # never allow reusing an QA pair unless they told us
                    splice @expectacopy, $i, 2 unless $reuse;
                    $but =~ s/(?s:^.*?)$regex//;
                    $timeout_start = time;
                    next EXPECT;
                }
            }
            my $have_waited = time - $timeout_start;
            if ($have_waited < $timeout) {
                # warn "DEBUG: have_waited[$have_waited]timeout[$timeout]";
                next EXPECT;
            }
            my $why = "could not answer a question during the dialog";
            $CPAN::Frontend->mywarn("Failing: $why\n");
            $self->{$phase} =
                CPAN::Distrostatus->new("NO $why");
            return 0;
        }
    }
}

sub _run_via_expect_deterministic {
    my($self,$expo,$phase,$expect_model) = @_;
    my $ran_into_timeout;
    my $ran_into_eof;
    my $timeout = $expect_model->{timeout} || 15; # currently unsettable
    my $expecta = $expect_model->{talk};
  EXPECT: for (my $i = 0; $i <= $#$expecta; $i+=2) {
        my($re,$send) = @$expecta[$i,$i+1];
        CPAN->debug("timeout[$timeout]re[$re]") if $CPAN::DEBUG;
        my $regex = eval "qr{$re}";
        $expo->expect($timeout,
                      [ eof => sub {
                            my $but = $expo->clear_accum;
                            $CPAN::Frontend->mywarn("EOF (maybe harmless)
expected[$regex]\nbut[$but]\n\n");
                            $ran_into_eof++;
                        } ],
                      [ timeout => sub {
                            my $but = $expo->clear_accum;
                            $CPAN::Frontend->mywarn("TIMEOUT
expected[$regex]\nbut[$but]\n\n");
                            $ran_into_timeout++;
                        } ],
                      -re => $regex);
        if ($ran_into_timeout) {
            # note that the caller expects 0 for success
            $self->{$phase} =
                CPAN::Distrostatus->new("NO timeout during expect dialog");
            return 0;
        } elsif ($ran_into_eof) {
            last EXPECT;
        }
        $expo->send($send);
    }
    $expo->soft_close;
    return $expo->exitstatus();
}

#-> CPAN::Distribution::_validate_distropref
sub _validate_distropref {
    my($self,@args) = @_;
    if (
        $CPAN::META->has_inst("CPAN::Kwalify")
        &&
        $CPAN::META->has_inst("Kwalify")
       ) {
        eval {CPAN::Kwalify::_validate("distroprefs",@args);};
        if ($@) {
            $CPAN::Frontend->mywarn($@);
        }
    } else {
        CPAN->debug("not validating '@args'") if $CPAN::DEBUG;
    }
}

#-> CPAN::Distribution::_find_prefs
sub _find_prefs {
    my($self) = @_;
    my $distroid = $self->pretty_id;
    #CPAN->debug("distroid[$distroid]") if $CPAN::DEBUG;
    my $prefs_dir = $CPAN::Config->{prefs_dir};
    return if $prefs_dir =~ /^\s*$/;
    eval { File::Path::mkpath($prefs_dir); };
    if ($@) {
        $CPAN::Frontend->mydie("Cannot create directory $prefs_dir");
    }
    # shortcut if there are no distroprefs files
    {
      my $dh = DirHandle->new($prefs_dir) or $CPAN::Frontend->mydie("Couldn't open '$prefs_dir': $!");
      my @files = map { /\.(yml|dd|st)\z/i } $dh->read;
      return unless @files;
    }
    my $yaml_module = CPAN::_yaml_module();
    my $ext_map = {};
    my @extensions;
    if ($CPAN::META->has_inst($yaml_module)) {
        $ext_map->{yml} = 'CPAN';
    } else {
        my @fallbacks;
        if ($CPAN::META->has_inst("Data::Dumper")) {
            push @fallbacks, $ext_map->{dd} = 'Data::Dumper';
        }
        if ($CPAN::META->has_inst("Storable")) {
            push @fallbacks, $ext_map->{st} = 'Storable';
        }
        if (@fallbacks) {
            local $" = " and ";
            unless ($self->{have_complained_about_missing_yaml}++) {
                $CPAN::Frontend->mywarnonce("'$yaml_module' not installed, falling back ".
                                            "to @fallbacks to read prefs '$prefs_dir'\n");
            }
        } else {
            unless ($self->{have_complained_about_missing_yaml}++) {
                $CPAN::Frontend->mywarnonce("'$yaml_module' not installed, cannot ".
                                            "read prefs '$prefs_dir'\n");
            }
        }
    }
    my $finder = CPAN::Distroprefs->find($prefs_dir, $ext_map);
    DIRENT: while (my $result = $finder->next) {
        if ($result->is_warning) {
            $CPAN::Frontend->mywarn($result->as_string);
            $CPAN::Frontend->mysleep(1);
            next DIRENT;
        } elsif ($result->is_fatal) {
            $CPAN::Frontend->mydie($result->as_string);
        }

        my @prefs = @{ $result->prefs };

      ELEMENT: for my $y (0..$#prefs) {
            my $pref = $prefs[$y];
            $self->_validate_distropref($pref->data, $result->abs, $y);

            # I don't know why we silently skip when there's no match, but
            # complain if there's an empty match hashref, and there's no
            # comment explaining why -- hdp, 2008-03-18
            unless ($pref->has_any_match) {
                next ELEMENT;
            }

            unless ($pref->has_valid_subkeys) {
                $CPAN::Frontend->mydie(sprintf
                    "Nonconforming .%s file '%s': " .
                    "missing match/* subattribute. " .
                    "Please remove, cannot continue.",
                    $result->ext, $result->abs,
                );
            }

            my $arg = {
                env          => \%ENV,
                distribution => $distroid,
                perl         => \&CPAN::find_perl,
                perlconfig   => \%Config::Config,
                module       => sub { [ $self->containsmods ] },
            };

            if ($pref->matches($arg)) {
                return {
                    prefs => $pref->data,
                    prefs_file => $result->abs,
                    prefs_file_doc => $y,
                };
            }

        }
    }
    return;
}

# CPAN::Distribution::prefs
sub prefs {
    my($self) = @_;
    if (exists $self->{negative_prefs_cache}
        &&
        $self->{negative_prefs_cache} != $CPAN::CurrentCommandId
       ) {
        delete $self->{negative_prefs_cache};
        delete $self->{prefs};
    }
    if (exists $self->{prefs}) {
        return $self->{prefs}; # XXX comment out during debugging
    }
    if ($CPAN::Config->{prefs_dir}) {
        CPAN->debug("prefs_dir[$CPAN::Config->{prefs_dir}]") if $CPAN::DEBUG;
        my $prefs = $self->_find_prefs();
        $prefs ||= ""; # avoid warning next line
        CPAN->debug("prefs[$prefs]") if $CPAN::DEBUG;
        if ($prefs) {
            for my $x (qw(prefs prefs_file prefs_file_doc)) {
                $self->{$x} = $prefs->{$x};
            }
            my $bs = sprintf(
                             "%s[%s]",
                             File::Basename::basename($self->{prefs_file}),
                             $self->{prefs_file_doc},
                            );
            my $filler1 = "_" x 22;
            my $filler2 = int(66 - length($bs))/2;
            $filler2 = 0 if $filler2 < 0;
            $filler2 = " " x $filler2;
            $CPAN::Frontend->myprint("
$filler1 D i s t r o P r e f s $filler1
$filler2 $bs $filler2
");
            $CPAN::Frontend->mysleep(1);
            return $self->{prefs};
        }
    }
    $self->{negative_prefs_cache} = $CPAN::CurrentCommandId;
    return $self->{prefs} = +{};
}

# CPAN::Distribution::_make_phase_arg
sub _make_phase_arg {
    my($self, $phase) = @_;
    my $_make_phase_arg;
    my $prefs = $self->prefs;
    if (
        $prefs
        && exists $prefs->{$phase}
        && exists $prefs->{$phase}{args}
        && $prefs->{$phase}{args}
       ) {
        $_make_phase_arg = join(" ",
                           map {CPAN::HandleConfig
                                 ->safe_quote($_)} @{$prefs->{$phase}{args}},
                          );
    }

# cpan[2]> o conf make[TAB]
# make                       make_install_make_command
# make_arg                   makepl_arg
# make_install_arg
# cpan[2]> o conf mbuild[TAB]
# mbuild_arg                    mbuild_install_build_command
# mbuild_install_arg            mbuildpl_arg

    my $mantra; # must switch make/mbuild here
    if ($self->{modulebuild}) {
        $mantra = "mbuild";
    } else {
        $mantra = "make";
    }
    my %map = (
               pl => "pl_arg",
               make => "_arg",
               test => "_test_arg", # does not really exist but maybe
                                    # will some day and now protects
                                    # us from unini warnings
               install => "_install_arg",
              );
    my $phase_underscore_meshup = $map{$phase};
    my $what = sprintf "%s%s", $mantra, $phase_underscore_meshup;

    $_make_phase_arg ||= $CPAN::Config->{$what};
    return $_make_phase_arg;
}

# CPAN::Distribution::_make_command
sub _make_command {
    my ($self) = @_;
    if ($self) {
        return
            CPAN::HandleConfig
                ->safe_quote(
                             CPAN::HandleConfig->prefs_lookup($self,
                                                              q{make})
                             || $Config::Config{make}
                             || 'make'
                            );
    } else {
        # Old style call, without object. Deprecated
        Carp::confess("CPAN::_make_command() used as function. Don't Do That.");
        return
          safe_quote(undef,
                     CPAN::HandleConfig->prefs_lookup($self,q{make})
                     || $CPAN::Config->{make}
                     || $Config::Config{make}
                     || 'make');
    }
}

sub _make_install_make_command {
    my ($self) = @_;
    my $mimc =
        CPAN::HandleConfig->prefs_lookup($self, q{make_install_make_command});
    return $self->_make_command() unless $mimc;

    # Quote the "make install" make command on Windows, where it is commonly
    # found in, e.g., C:\Program Files\... and therefore needs quoting. We can't
    # do this in general because the command maybe "sudo make..." (i.e. a
    # program with arguments), but that is unlikely to be the case on Windows.
    $mimc = CPAN::HandleConfig->safe_quote($mimc) if $^O eq 'MSWin32';

    return $mimc;
}

#-> sub CPAN::Distribution::is_locally_optional
sub is_locally_optional {
    my($self, $prereq_pm, $prereq) = @_;
    $prereq_pm ||= $self->{prereq_pm};
    my($nmo,$opt);
    for my $rt (qw(requires build_requires)) {
        if (exists $prereq_pm->{$rt}{$prereq}) {
            # rt 121914
            $nmo ||= $CPAN::META->instance("CPAN::Module",$prereq);
            my $av = $nmo->available_version;
            return 0 if !$av || CPAN::Version->vlt($av,$prereq_pm->{$rt}{$prereq});
        }
        if (exists $prereq_pm->{"opt_$rt"}{$prereq}) {
            $opt = 1;
        }
    }
    return $opt||0;
}

#-> sub CPAN::Distribution::follow_prereqs ;
sub follow_prereqs {
    my($self) = shift;
    my($slot) = shift;
    my(@prereq_tuples) = grep {$_->[0] ne "perl"} @_;
    return unless @prereq_tuples;
    my(@good_prereq_tuples);
    for my $p (@prereq_tuples) {
        # e.g. $p = ['Devel::PartialDump', 'r', 1]
        # promote if possible
        if ($p->[1] =~ /^(r|c)$/) {
            push @good_prereq_tuples, $p;
        } elsif ($p->[1] =~ /^(b)$/) {
            my $reqtype = CPAN::Queue->reqtype_of($p->[0]);
            if ($reqtype =~ /^(r|c)$/) {
                push @good_prereq_tuples, [$p->[0], $reqtype, $p->[2]];
            } else {
                push @good_prereq_tuples, $p;
            }
        } else {
            die "Panic: in follow_prereqs: reqtype[$p->[1]] seen, should never happen";
        }
    }
    my $pretty_id = $self->pretty_id;
    my %map = (
               b => "build_requires",
               r => "requires",
               c => "commandline",
              );
    my($filler1,$filler2,$filler3,$filler4);
    my $unsat = "Unsatisfied dependencies detected during";
    my $w = length($unsat) > length($pretty_id) ? length($unsat) : length($pretty_id);
    {
        my $r = int(($w - length($unsat))/2);
        my $l = $w - length($unsat) - $r;
        $filler1 = "-"x4 . " "x$l;
        $filler2 = " "x$r . "-"x4 . "\n";
    }
    {
        my $r = int(($w - length($pretty_id))/2);
        my $l = $w - length($pretty_id) - $r;
        $filler3 = "-"x4 . " "x$l;
        $filler4 = " "x$r . "-"x4 . "\n";
    }
    $CPAN::Frontend->
        myprint("$filler1 $unsat $filler2".
                "$filler3 $pretty_id $filler4".
                join("", map {sprintf "    %s \[%s%s]\n", $_->[0], $map{$_->[1]}, $self->is_locally_optional(undef,$_->[0]) ? ",optional" : ""} @good_prereq_tuples),
               );
    my $follow = 0;
    if ($CPAN::Config->{prerequisites_policy} eq "follow") {
        $follow = 1;
    } elsif ($CPAN::Config->{prerequisites_policy} eq "ask") {
        my $answer = CPAN::Shell::colorable_makemaker_prompt(
"Shall I follow them and prepend them to the queue
of modules we are processing right now?", "yes");
        $follow = $answer =~ /^\s*y/i;
    } else {
        my @prereq = map { $_->[0] } @good_prereq_tuples;
        local($") = ", ";
        $CPAN::Frontend->
            myprint("  Ignoring dependencies on modules @prereq\n");
    }
    if ($follow) {
        my $id = $self->id;
        my(@to_queue_mand,@to_queue_opt);
        for my $gp (@good_prereq_tuples) {
            my($prereq,$reqtype,$optional) = @$gp;
            my $qthing = +{qmod=>$prereq,reqtype=>$reqtype,optional=>$optional};
            if ($optional &&
                $self->is_locally_optional(undef,$prereq)
               ){
                # Since we do not depend on this one, we do not need
                # this in a mandatory arrangement:
                push @to_queue_opt, $qthing;
            } else {
                my $any = CPAN::Shell->expandany($prereq);
                $self->{$slot . "_for"}{$any->id}++;
                if ($any) {
                    unless ($optional) {
                        # No recursion check in an optional area of the tree
                        $any->color_cmd_tmps(0,2);
                    }
                } else {
                    $CPAN::Frontend->mywarn("Warning (maybe a bug): Cannot expand prereq '$prereq'\n");
                    $CPAN::Frontend->mysleep(2);
                }
                # order everything that is not locally_optional just
                # like mandatory items: this keeps leaves before
                # branches
                unshift @to_queue_mand, $qthing;
            }
        }
        if (@to_queue_mand) {
            unshift @to_queue_mand, {qmod => $id, reqtype => $self->{reqtype}, optional=> !$self->{mandatory}};
            CPAN::Queue->jumpqueue(@to_queue_opt,@to_queue_mand);
            $self->{$slot} = "Delayed until after prerequisites";
            return 1; # signal we need dependencies
        } elsif (@to_queue_opt) {
            CPAN::Queue->jumpqueue(@to_queue_opt);
        }
    }
    return;
}

sub _feature_depends {
    my($self) = @_;
    my $meta_yml = $self->parse_meta_yml();
    my $optf = $meta_yml->{optional_features} or return;
    if (!ref $optf or ref $optf ne "HASH"){
        $CPAN::Frontend->mywarn("The content of optional_features is not a HASH reference. Cannot use it.\n");
        $optf = {};
    }
    my $wantf = $self->prefs->{features} or return;
    if (!ref $wantf or ref $wantf ne "ARRAY"){
        $CPAN::Frontend->mywarn("The content of 'features' is not an ARRAY reference. Cannot use it.\n");
        $wantf = [];
    }
    my $dep = +{};
    for my $wf (@$wantf) {
        if (my $f = $optf->{$wf}) {
            $CPAN::Frontend->myprint("Found the demanded feature '$wf' that ".
                                     "is accompanied by this description:\n".
                                     $f->{description}.
                                     "\n\n"
                                    );
            # configure_requires currently not in the spec, unlikely to be useful anyway
            for my $reqtype (qw(configure_requires build_requires requires)) {
                my $reqhash = $f->{$reqtype} or next;
                while (my($k,$v) = each %$reqhash) {
                    $dep->{$reqtype}{$k} = $v;
                }
            }
        } else {
            $CPAN::Frontend->mywarn("The demanded feature '$wf' was not ".
                                    "found in the META.yml file".
                                    "\n\n"
                                   );
        }
    }
    $dep;
}

sub prereqs_for_slot {
    my($self,$slot) = @_;
    my($prereq_pm);
    unless ($CPAN::META->has_usable("CPAN::Meta::Requirements")) {
        my $whynot = "not available";
        if (defined $CPAN::Meta::Requirements::VERSION) {
            $whynot = "version $CPAN::Meta::Requirements::VERSION not sufficient";
        }
        $CPAN::Frontend->mywarn("CPAN::Meta::Requirements $whynot\n");
        my $before = "";
        if ($self->{CALLED_FOR}){
            if ($self->{CALLED_FOR} =~
                /^(
                     CPAN::Meta::Requirements
                 |CPAN::DistnameInfo
                 |version
                 |parent
                 |ExtUtils::MakeMaker
                 |Test::Harness
                 )$/x) {
                $CPAN::Frontend->mywarn("Please install CPAN::Meta::Requirements ".
                    "as soon as possible; it is needed for a reliable operation of ".
                    "the cpan shell; setting requirements to nil for '$1' for now ".
                    "to prevent deadlock during bootstrapping\n");
                return;
            }
            $before = " before $self->{CALLED_FOR}";
        }
        $CPAN::Frontend->mydie("Please install CPAN::Meta::Requirements manually$before");
    }
    my $merged = CPAN::Meta::Requirements->new;
    my $prefs_depends = $self->prefs->{depends}||{};
    my $feature_depends = $self->_feature_depends();
    if ($slot eq "configure_requires_later") {
        for my $hash (  $self->configure_requires,
                        $prefs_depends->{configure_requires},
                        $feature_depends->{configure_requires},
        ) {
            $merged->add_requirements(
                CPAN::Meta::Requirements->from_string_hash($hash)
            );
        }
        if (-f "Build.PL"
            && ! -f File::Spec->catfile($self->{build_dir},"Makefile.PL")
            && ! @{[ $merged->required_modules ]}
            && ! $CPAN::META->has_inst("Module::Build")
           ) {
            $CPAN::Frontend->mywarn(
              "  Warning: CPAN.pm discovered Module::Build as undeclared prerequisite.\n".
              "  Adding it now as such.\n"
            );
            $CPAN::Frontend->mysleep(5);
            $merged->add_minimum( "Module::Build" => 0 );
            delete $self->{writemakefile};
        }
        $prereq_pm = {}; # configure_requires defined as "b"
    } elsif ($slot eq "later") {
        my $prereq_pm_0 = $self->prereq_pm || {};
        for my $reqtype (qw(requires build_requires opt_requires opt_build_requires)) {
            $prereq_pm->{$reqtype} = {%{$prereq_pm_0->{$reqtype}||{}}}; # copy to not pollute it
            for my $dep ($prefs_depends,$feature_depends) {
                for my $k (keys %{$dep->{$reqtype}||{}}) {
                    $prereq_pm->{$reqtype}{$k} = $dep->{$reqtype}{$k};
                }
            }
        }
        # XXX what about optional_req|breq? -- xdg, 2012-04-01
        for my $hash (
            $prereq_pm->{requires},
            $prereq_pm->{build_requires},
            $prereq_pm->{opt_requires},
            $prereq_pm->{opt_build_requires},

        ) {
            $merged->add_requirements(
                CPAN::Meta::Requirements->from_string_hash($hash)
            );
        }
    } else {
        die "Panic: illegal slot '$slot'";
    }
    return ($merged->as_string_hash, $prereq_pm);
}

#-> sub CPAN::Distribution::unsat_prereq ;
# return ([Foo,"r"],[Bar,"b"]) for normal modules
# return ([perl=>5.008]) if we need a newer perl than we are running under
# (sorry for the inconsistency, it was an accident)
sub unsat_prereq {
    my($self,$slot) = @_;
    my($merged_hash,$prereq_pm) = $self->prereqs_for_slot($slot);
    my(@need);
    unless ($CPAN::META->has_usable("CPAN::Meta::Requirements")) {
        $CPAN::Frontend->mywarn("CPAN::Meta::Requirements not available, please install as soon as possible, trying to continue with severly limited capabilities\n");
        return;
    }
    my $merged = CPAN::Meta::Requirements->from_string_hash($merged_hash);
    my @merged = sort $merged->required_modules;
    CPAN->debug("all merged_prereqs[@merged]") if $CPAN::DEBUG;
  NEED: for my $need_module ( @merged ) {
        my $need_version = $merged->requirements_for_module($need_module);
        my($available_version,$inst_file,$available_file,$nmo);
        if ($need_module eq "perl") {
            $available_version = $];
            $available_file = CPAN::find_perl();
        } else {
            if (CPAN::_sqlite_running()) {
                CPAN::Index->reload;
                $CPAN::SQLite->search("CPAN::Module",$need_module);
            }
            $nmo = $CPAN::META->instance("CPAN::Module",$need_module);
            $inst_file = $nmo->inst_file || '';
            $available_file = $nmo->available_file || '';
            $available_version = $nmo->available_version;
            if ($nmo->uptodate) {
                my $accepts = eval {
                    $merged->accepts_module($need_module, $available_version);
                };
                unless ($accepts) {
                    my $rq = $merged->requirements_for_module( $need_module );
                    $CPAN::Frontend->mywarn(
                        "Warning: Version '$available_version' of ".
                        "'$need_module' is up to date but does not ".
                        "fulfill requirements ($rq). I will continue, ".
                        "but chances to succeed are low.\n");
                }
                next NEED;
            }

            # if they have not specified a version, we accept any
            # installed one; in that case inst_file is always
            # sufficient and available_file is sufficient on
            # both build_requires and configure_requires
            my $sufficient = $inst_file ||
                ( exists $prereq_pm->{requires}{$need_module} ? 0 : $available_file );
            if ( $sufficient
                and ( # a few quick short circuits
                     not defined $need_version
                     or $need_version eq '0'    # "==" would trigger warning when not numeric
                     or $need_version eq "undef"
                    )) {
                unless ($nmo->inst_deprecated) {
                    next NEED;
                }
            }
        }

        # We only want to install prereqs if either they're not installed
        # or if the installed version is too old. We cannot omit this
        # check, because if 'force' is in effect, nobody else will check.
        # But we don't want to accept a deprecated module installed as part
        # of the Perl core, so we continue if the available file is the installed
        # one and is deprecated

        if ( $available_file ) {
            my $fulfills_all_version_rqs = $self->_fulfills_all_version_rqs
                (
                 $need_module,
                 $available_file,
                 $available_version,
                 $need_version,
                );
            if ( $inst_file
                       && $available_file eq $inst_file
                       && $nmo->inst_deprecated
                     ) {
                # continue installing as a prereq. we really want that
                # because the deprecated module may spit out warnings
                # and third party did not know until today. Only one
                # exception is OK, because CPANPLUS is special after
                # all:
                if ( $fulfills_all_version_rqs and
                     $nmo->id =~ /^CPANPLUS(?:::Dist::Build)$/
                   ) {
                    # here we have an available version that is good
                    # enough although deprecated (preventing circular
                    # loop CPANPLUS => CPANPLUS::Dist::Build RT#83042)
                    next NEED;
                }
            } elsif (
                $self->{reqtype} # e.g. maybe we came via goto?
                && $self->{reqtype} =~ /^(r|c)$/
                && (   exists $prereq_pm->{requires}{$need_module}
                    || exists $prereq_pm->{opt_requires}{$need_module} )
                && $nmo
                && !$inst_file
            ) {
                # continue installing as a prereq; this may be a
                # distro we already used when it was a build_requires
                # so we did not install it. But suddenly somebody
                # wants it as a requires
                my $need_distro = $nmo->distribution;
                if ($need_distro->{install} && $need_distro->{install}->failed && $need_distro->{install}->text =~ /is only/) {
                    my $id = $need_distro->pretty_id;
                    $CPAN::Frontend->myprint("Promoting $id from build_requires to requires due $need_module\n");
                    delete $need_distro->{install}; # promote to another installation attempt
                    $need_distro->{reqtype} = "r";
                    $need_distro->install;
                    next NEED;
                }
            }
            else {
                next NEED if $fulfills_all_version_rqs;
            }
        }

        if ($need_module eq "perl") {
            return ["perl", $need_version];
        }
        $self->{sponsored_mods}{$need_module} ||= 0;
        CPAN->debug("need_module[$need_module]s/s/n[$self->{sponsored_mods}{$need_module}]") if $CPAN::DEBUG;
        if (my $sponsoring = $self->{sponsored_mods}{$need_module}++) {
            # We have already sponsored it and for some reason it's still
            # not available. So we do ... what??

            # if we push it again, we have a potential infinite loop

            # The following "next" was a very problematic construct.
            # It helped a lot but broke some day and had to be
            # replaced.

            # We must be able to deal with modules that come again and
            # again as a prereq and have themselves prereqs and the
            # queue becomes long but finally we would find the correct
            # order. The RecursiveDependency check should trigger a
            # die when it's becoming too weird. Unfortunately removing
            # this next breaks many other things.

            # The bug that brought this up is described in Todo under
            # "5.8.9 cannot install Compress::Zlib"

            # next; # this is the next that had to go away

            # The following "next NEED" are fine and the error message
            # explains well what is going on. For example when the DBI
            # fails and consequently DBD::SQLite fails and now we are
            # processing CPAN::SQLite. Then we must have a "next" for
            # DBD::SQLite. How can we get it and how can we identify
            # all other cases we must identify?

            my $do = $nmo->distribution;
            next NEED unless $do; # not on CPAN
            if (CPAN::Version->vcmp($need_version, $nmo->ro->{CPAN_VERSION}) > 0){
                $CPAN::Frontend->mywarn("Warning: Prerequisite ".
                                        "'$need_module => $need_version' ".
                                        "for '$self->{ID}' seems ".
                                        "not available according to the indices\n"
                                       );
                next NEED;
            }
          NOSAYER: for my $nosayer (
                                    "unwrapped",
                                    "writemakefile",
                                    "signature_verify",
                                    "make",
                                    "make_test",
                                    "install",
                                    "make_clean",
                                   ) {
                if ($do->{$nosayer}) {
                    my $selfid = $self->pretty_id;
                    my $did = $do->pretty_id;
                    if (UNIVERSAL::can($do->{$nosayer},"failed") ?
                        $do->{$nosayer}->failed :
                        $do->{$nosayer} =~ /^NO/) {
                        if ($nosayer eq "make_test"
                            &&
                            $do->{make_test}{COMMANDID} != $CPAN::CurrentCommandId
                           ) {
                            next NOSAYER;
                        }
                        ### XXX  don't complain about missing optional deps -- xdg, 2012-04-01
                        if ($self->is_locally_optional($prereq_pm, $need_module)) {
                            # don't complain about failing optional prereqs
                        }
                        else {
                            $CPAN::Frontend->mywarn("Warning: Prerequisite ".
                                                    "'$need_module => $need_version' ".
                                                    "for '$selfid' failed when ".
                                                    "processing '$did' with ".
                                                    "'$nosayer => $do->{$nosayer}'. Continuing, ".
                                                    "but chances to succeed are limited.\n"
                                                );
                            $CPAN::Frontend->mysleep($sponsoring/10);
                        }
                        next NEED;
                    } else { # the other guy succeeded
                        if ($nosayer =~ /^(install|make_test)$/) {
                            # we had this with
                            # DMAKI/DateTime-Calendar-Chinese-0.05.tar.gz
                            # in 2007-03 for 'make install'
                            # and 2008-04: #30464 (for 'make test')
                            # $CPAN::Frontend->mywarn("Warning: Prerequisite ".
                            #                         "'$need_module => $need_version' ".
                            #                         "for '$selfid' already built ".
                            #                         "but the result looks suspicious. ".
                            #                         "Skipping another build attempt, ".
                            #                         "to prevent looping endlessly.\n"
                            #                        );
                            next NEED;
                        }
                    }
                }
            }
        }
        my $needed_as;
        if (0) {
        } elsif (exists $prereq_pm->{requires}{$need_module}
            || exists $prereq_pm->{opt_requires}{$need_module}
        ) {
            $needed_as = "r";
        } elsif ($slot eq "configure_requires_later") {
            # in ae872487d5 we said: C< we have not yet run the
            # {Build,Makefile}.PL, we must presume "r" >; but the
            # meta.yml standard says C< These dependencies are not
            # required after the distribution is installed. >; so now
            # we change it back to "b" and care for the proper
            # promotion later.
            $needed_as = "b";
        } else {
            $needed_as = "b";
        }
        # here need to flag as optional for recommends/suggests
        # -- xdg, 2012-04-01
        $self->debug(sprintf "%s manadory?[%s]",
                     $self->pretty_id,
                     $self->{mandatory})
            if $CPAN::DEBUG;
        my $optional = !$self->{mandatory}
            || $self->is_locally_optional($prereq_pm, $need_module);
        push @need, [$need_module,$needed_as,$optional];
    }
    my @unfolded = map { "[".join(",",@$_)."]" } @need;
    CPAN->debug("returning from unsat_prereq[@unfolded]") if $CPAN::DEBUG;
    @need;
}

sub _fulfills_all_version_rqs {
    my($self,$need_module,$available_file,$available_version,$need_version) = @_;
    my(@all_requirements) = split /\s*,\s*/, $need_version;
    local($^W) = 0;
    my $ok = 0;
  RQ: for my $rq (@all_requirements) {
        if ($rq =~ s|>=\s*||) {
        } elsif ($rq =~ s|>\s*||) {
            # 2005-12: one user
            if (CPAN::Version->vgt($available_version,$rq)) {
                $ok++;
            }
            next RQ;
        } elsif ($rq =~ s|!=\s*||) {
            # 2005-12: no user
            if (CPAN::Version->vcmp($available_version,$rq)) {
                $ok++;
                next RQ;
            } else {
                $ok=0;
                last RQ;
            }
        } elsif ($rq =~ m|<=?\s*|) {
            # 2005-12: no user
            $CPAN::Frontend->mywarn("Downgrading not supported (rq[$rq])\n");
            $ok++;
            next RQ;
        } elsif ($rq =~ s|==\s*||) {
            # 2009-07: ELLIOTJS/Perl-Critic-1.099_002.tar.gz
            if (CPAN::Version->vcmp($available_version,$rq)) {
                $ok=0;
                last RQ;
            } else {
                $ok++;
                next RQ;
            }
        }
        if (! CPAN::Version->vgt($rq, $available_version)) {
            $ok++;
        }
        CPAN->debug(sprintf("need_module[%s]available_file[%s]".
                            "available_version[%s]rq[%s]ok[%d]",
                            $need_module,
                            $available_file,
                            $available_version,
                            CPAN::Version->readable($rq),
                            $ok,
                           )) if $CPAN::DEBUG;
    }
    my $ret = $ok == @all_requirements;
    CPAN->debug(sprintf("need_module[%s]ok[%s]all_requirements[%d]",$need_module, $ok, scalar @all_requirements)) if $CPAN::DEBUG;
    return $ret;
}

#-> sub CPAN::Distribution::read_meta
# read any sort of meta files, return CPAN::Meta object if no errors
sub read_meta {
    my($self) = @_;
    my $meta_file = $self->pick_meta_file
        or return;

    return unless $CPAN::META->has_usable("CPAN::Meta");
    my $meta = eval { CPAN::Meta->load_file($meta_file)}
        or return;

    # Very old EU::MM could have wrong META
    if ($meta_file eq 'META.yml'
        && $meta->generated_by =~ /ExtUtils::MakeMaker version ([\d\._]+)/
    ) {
        my $eummv = do { local $^W = 0; $1+0; };
        return if $eummv < 6.2501;
    }

    return $meta;
}

#-> sub CPAN::Distribution::read_yaml ;
# XXX This should be DEPRECATED -- dagolden, 2011-02-05
sub read_yaml {
    my($self) = @_;
    my $meta_file = $self->pick_meta_file('\.yml$');
    $self->debug("meta_file[$meta_file]") if $CPAN::DEBUG;
    return unless $meta_file;
    my $yaml;
    eval { $yaml = $self->parse_meta_yml($meta_file) };
    if ($@ or ! $yaml) {
        return undef; # if we die, then we cannot read YAML's own META.yml
    }
    # not "authoritative"
    if (defined $yaml && (! ref $yaml || ref $yaml ne "HASH")) {
        $CPAN::Frontend->mywarn("META.yml does not seem to be conforming, cannot use it.\n");
        $yaml = undef;
    }
    $self->debug(sprintf "yaml[%s]", $yaml || "UNDEF")
        if $CPAN::DEBUG;
    $self->debug($yaml) if $CPAN::DEBUG && $yaml;
    # MYMETA.yml is static and authoritative by definition
    if ( $meta_file =~ /MYMETA\.yml/ ) {
      return $yaml;
    }
    # META.yml is authoritative only if dynamic_config is defined and false
    if ( defined $yaml->{dynamic_config} && ! $yaml->{dynamic_config} ) {
      return $yaml;
    }
    # otherwise, we can't use what we found
    return undef;
}

#-> sub CPAN::Distribution::configure_requires ;
sub configure_requires {
    my($self) = @_;
    return unless my $meta_file = $self->pick_meta_file('^META');
    if (my $meta_obj = $self->read_meta) {
        my $prereqs = $meta_obj->effective_prereqs;
        my $cr = $prereqs->requirements_for(qw/configure requires/);
        return $cr ? $cr->as_string_hash : undef;
    }
    else {
        my $yaml = eval { $self->parse_meta_yml($meta_file) };
        return $yaml->{configure_requires};
    }
}

#-> sub CPAN::Distribution::prereq_pm ;
sub prereq_pm {
    my($self) = @_;
    return unless $self->{writemakefile}  # no need to have succeeded
                                          # but we must have run it
        || $self->{modulebuild};
    unless ($self->{build_dir}) {
        return;
    }
    # no Makefile/Build means configuration aborted, so don't look for prereqs
    my $makefile  = File::Spec->catfile($self->{build_dir}, $^O eq 'VMS' ? 'descrip.mms' : 'Makefile');
    my $buildfile = File::Spec->catfile($self->{build_dir}, $^O eq 'VMS' ? 'Build.com' : 'Build');
    return unless   -f $makefile || -f $buildfile;
    CPAN->debug(sprintf "writemakefile[%s]modulebuild[%s]",
                $self->{writemakefile}||"",
                $self->{modulebuild}||"",
               ) if $CPAN::DEBUG;
    my($req,$breq, $opt_req, $opt_breq);
    my $meta_obj = $self->read_meta;
    # META/MYMETA is only authoritative if dynamic_config is false
    if ($meta_obj && ! $meta_obj->dynamic_config) {
        my $prereqs = $meta_obj->effective_prereqs;
        my $requires = $prereqs->requirements_for(qw/runtime requires/);
        my $build_requires = $prereqs->requirements_for(qw/build requires/);
        my $test_requires = $prereqs->requirements_for(qw/test requires/);
        # XXX we don't yet distinguish build vs test, so merge them for now
        $build_requires->add_requirements($test_requires);
        $req = $requires->as_string_hash;
        $breq = $build_requires->as_string_hash;

        # XXX assemble optional_req && optional_breq from recommends/suggests
        # depending on corresponding policies -- xdg, 2012-04-01
        CPAN->use_inst("CPAN::Meta::Requirements");
        my $opt_runtime = CPAN::Meta::Requirements->new;
        my $opt_build   = CPAN::Meta::Requirements->new;
        if ( $CPAN::Config->{recommends_policy} ) {
            $opt_runtime->add_requirements( $prereqs->requirements_for(qw/runtime recommends/));
            $opt_build->add_requirements(   $prereqs->requirements_for(qw/build recommends/));
            $opt_build->add_requirements(   $prereqs->requirements_for(qw/test  recommends/));

        }
        if ( $CPAN::Config->{suggests_policy} ) {
            $opt_runtime->add_requirements( $prereqs->requirements_for(qw/runtime suggests/));
            $opt_build->add_requirements(   $prereqs->requirements_for(qw/build suggests/));
            $opt_build->add_requirements(   $prereqs->requirements_for(qw/test  suggests/));
        }
        $opt_req = $opt_runtime->as_string_hash;
        $opt_breq = $opt_build->as_string_hash;
    }
    elsif (my $yaml = $self->read_yaml) { # often dynamic_config prevents a result here
        $req =  $yaml->{requires} || {};
        $breq =  $yaml->{build_requires} || {};
        if ( $CPAN::Config->{recommends_policy} ) {
            $opt_req = $yaml->{recommends} || {};
        }
        undef $req unless ref $req eq "HASH" && %$req;
        if ($req) {
            if ($yaml->{generated_by} &&
                $yaml->{generated_by} =~ /ExtUtils::MakeMaker version ([\d\._]+)/) {
                my $eummv = do { local $^W = 0; $1+0; };
                if ($eummv < 6.2501) {
                    # thanks to Slaven for digging that out: MM before
                    # that could be wrong because it could reflect a
                    # previous release
                    undef $req;
                }
            }
            my $areq;
            my $do_replace;
            foreach my $k (sort keys %{$req||{}}) {
                my $v = $req->{$k};
                next unless defined $v;
                if ($v =~ /\d/) {
                    $areq->{$k} = $v;
                } elsif ($k =~ /[A-Za-z]/ &&
                         $v =~ /[A-Za-z]/ &&
                         $CPAN::META->exists("CPAN::Module",$v)
                        ) {
                    $CPAN::Frontend->mywarn("Suspicious key-value pair in META.yml's ".
                                            "requires hash: $k => $v; I'll take both ".
                                            "key and value as a module name\n");
                    $CPAN::Frontend->mysleep(1);
                    $areq->{$k} = 0;
                    $areq->{$v} = 0;
                    $do_replace++;
                }
            }
            $req = $areq if $do_replace;
        }
    }
    else {
        $CPAN::Frontend->mywarnonce("Could not read metadata file. Falling back to other ".
                                    "methods to determine prerequisites\n");
    }

    unless ($req || $breq) {
        my $build_dir;
        unless ( $build_dir = $self->{build_dir} ) {
            return;
        }
        my $makefile = File::Spec->catfile($build_dir,"Makefile");
        my $fh;
        if (-f $makefile
            and
            $fh = FileHandle->new("<$makefile\0")) {
            CPAN->debug("Getting prereq from Makefile") if $CPAN::DEBUG;
            local($/) = "\n";
            while (<$fh>) {
                last if /MakeMaker post_initialize section/;
                my($p) = m{^[\#]
                           \s+PREREQ_PM\s+=>\s+(.+)
                       }x;
                next unless $p;
                # warn "Found prereq expr[$p]";

                #  Regexp modified by A.Speer to remember actual version of file
                #  PREREQ_PM hash key wants, then add to
                while ( $p =~ m/(?:\s)([\w\:]+)=>(q\[.*?\]|undef),?/g ) {
                    my($m,$n) = ($1,$2);
                    # When a prereq is mentioned twice: let the bigger
                    # win; usual culprit is that they declared
                    # build_requires separately from requires; see
                    # rt.cpan.org #47774
                    my($prevn);
                    if ( defined $req->{$m} ) {
                        $prevn = $req->{$m};
                    }
                    if ($n =~ /^q\[(.*?)\]$/) {
                        $n = $1;
                    }
                    if (!$prevn || CPAN::Version->vlt($prevn, $n)){
                        $req->{$m} = $n;
                    }
                }
                last;
            }
        }
    }
    unless ($req || $breq) {
        my $build_dir = $self->{build_dir} or die "Panic: no build_dir?";
        my $buildfile = File::Spec->catfile($build_dir,"Build");
        if (-f $buildfile) {
            CPAN->debug("Found '$buildfile'") if $CPAN::DEBUG;
            my $build_prereqs = File::Spec->catfile($build_dir,"_build","prereqs");
            if (-f $build_prereqs) {
                CPAN->debug("Getting prerequisites from '$build_prereqs'") if $CPAN::DEBUG;
                my $content = do { local *FH;
                                   open FH, $build_prereqs
                                       or $CPAN::Frontend->mydie("Could not open ".
                                                                 "'$build_prereqs': $!");
                                   local $/;
                                   <FH>;
                               };
                my $bphash = eval $content;
                if ($@) {
                } else {
                    $req  = $bphash->{requires} || +{};
                    $breq = $bphash->{build_requires} || +{};
                }
            }
        }
    }
    # XXX needs to be adapted for optional_req & optional_breq -- xdg, 2012-04-01
    if ($req || $breq || $opt_req || $opt_breq ) {
        return $self->{prereq_pm} = {
           requires => $req,
           build_requires => $breq,
           opt_requires => $opt_req,
           opt_build_requires => $opt_breq,
       };
    }
}

#-> sub CPAN::Distribution::shortcut_test ;
# return values: undef means don't shortcut; 0 means shortcut as fail;
# and 1 means shortcut as success
sub shortcut_test {
    my ($self) = @_;

    $self->debug("checking badtestcnt[$self->{ID}]") if $CPAN::DEBUG;
    $self->{badtestcnt} ||= 0;
    if ($self->{badtestcnt} > 0) {
        require Data::Dumper;
        CPAN->debug(sprintf "NOREPEAT[%s]", Data::Dumper::Dumper($self)) if $CPAN::DEBUG;
        return $self->goodbye("Won't repeat unsuccessful test during this command");
    }

    for my $slot ( qw/later configure_requires_later/ ) {
        $self->debug("checking $slot slot[$self->{ID}]") if $CPAN::DEBUG;
        return $self->success($self->{$slot})
        if $self->{$slot};
    }

    $self->debug("checking if tests passed[$self->{ID}]") if $CPAN::DEBUG;
    if ( $self->{make_test} ) {
        if (
            UNIVERSAL::can($self->{make_test},"failed") ?
            $self->{make_test}->failed :
            $self->{make_test} =~ /^NO/
        ) {
            if (
                UNIVERSAL::can($self->{make_test},"commandid")
                &&
                $self->{make_test}->commandid == $CPAN::CurrentCommandId
            ) {
                return $self->goodbye("Has already been tested within this command");
            }
        } else {
            # if global "is_tested" has been cleared, we need to mark this to
            # be added to PERL5LIB if not already installed
            if ($self->tested_ok_but_not_installed) {
                $CPAN::META->is_tested($self->{build_dir},$self->{make_test}{TIME});
            }
            return $self->success("Has already been tested successfully");
        }
    }

    if ($self->{notest}) {
        $self->{make_test} = CPAN::Distrostatus->new("YES");
        return $self->success("Skipping test because of notest pragma");
    }

    return undef; # no shortcut
}

#-> sub CPAN::Distribution::_exe_files ;
sub _exe_files {
    my($self) = @_;
    return unless $self->{writemakefile}  # no need to have succeeded
                                          # but we must have run it
        || $self->{modulebuild};
    unless ($self->{build_dir}) {
        return;
    }
    CPAN->debug(sprintf "writemakefile[%s]modulebuild[%s]",
                $self->{writemakefile}||"",
                $self->{modulebuild}||"",
               ) if $CPAN::DEBUG;
    my $build_dir;
    unless ( $build_dir = $self->{build_dir} ) {
        return;
    }
    my $makefile = File::Spec->catfile($build_dir,"Makefile");
    my $fh;
    my @exe_files;
    if (-f $makefile
        and
        $fh = FileHandle->new("<$makefile\0")) {
        CPAN->debug("Getting exefiles from Makefile") if $CPAN::DEBUG;
        local($/) = "\n";
        while (<$fh>) {
            last if /MakeMaker post_initialize section/;
            my($p) = m{^[\#]
                       \s+EXE_FILES\s+=>\s+\[(.+)\]
                  }x;
            next unless $p;
            # warn "Found exefiles expr[$p]";
            my @p = split /,\s*/, $p;
            for my $p2 (@p) {
                if ($p2 =~ /^q\[(.+)\]/) {
                    push @exe_files, $1;
                }
            }
        }
    }
    return \@exe_files if @exe_files;
    my $buildparams = File::Spec->catfile($build_dir,"_build","build_params");
    if (-f $buildparams) {
        CPAN->debug("Found '$buildparams'") if $CPAN::DEBUG;
        my $x = do $buildparams;
        for my $sf ($x->[2]{script_files}) {
            if (my $reftype = ref $sf) {
                if ($reftype eq "ARRAY") {
                    push @exe_files, @$sf;
                }
                elsif ($reftype eq "HASH") {
                    push @exe_files, keys %$sf;
                }
                else {
                    $CPAN::Frontend->mywarn("Invalid reftype $reftype for Build.PL 'script_files'\n");
                }
            }
            elsif (defined $sf) {
                push @exe_files, $sf;
            }
        }
    }
    return \@exe_files;
}

#-> sub CPAN::Distribution::test ;
sub test {
    my($self) = @_;

    $self->pre_test();

    if (exists $self->{cleanup_after_install_done}) {
        $self->post_test();
        return $self->make;
    }

    $self->debug("checking goto id[$self->{ID}]") if $CPAN::DEBUG;
    if (my $goto = $self->prefs->{goto}) {
        $self->post_test();
        return $self->goto($goto);
    }

    unless ($self->make){
        $self->post_test();
        return;
    }

    if ( defined( my $sc = $self->shortcut_test ) ) {
        $self->post_test();
        return $sc;
    }

    if ($CPAN::Signal) {
        delete $self->{force_update};
        $self->post_test();
        return;
    }
    # warn "XDEBUG: checking for notest: $self->{notest} $self";
    my $make = $self->{modulebuild} ? "Build" : "make";

    local $ENV{PERL5LIB} = defined($ENV{PERL5LIB})
                           ? $ENV{PERL5LIB}
                           : ($ENV{PERLLIB} || "");

    local $ENV{PERL5OPT} = defined $ENV{PERL5OPT} ? $ENV{PERL5OPT} : "";
    local $ENV{PERL_USE_UNSAFE_INC} =
        exists $ENV{PERL_USE_UNSAFE_INC} && defined $ENV{PERL_USE_UNSAFE_INC}
        ? $ENV{PERL_USE_UNSAFE_INC} : 1; # test
    $CPAN::META->set_perl5lib;
    local $ENV{MAKEFLAGS}; # protect us from outer make calls
    local $ENV{PERL_MM_USE_DEFAULT} = 1 if $CPAN::Config->{use_prompt_default};
    local $ENV{NONINTERACTIVE_TESTING} = 1 if $CPAN::Config->{use_prompt_default};

    if ($run_allow_installing_within_test) {
        my($allow_installing, $why) = $self->_allow_installing;
        if (! $allow_installing) {
            $CPAN::Frontend->mywarn("Testing/Installation stopped: $why\n");
            $self->introduce_myself;
            $self->{make_test} = CPAN::Distrostatus->new("NO -- testing/installation stopped due $why");
            $CPAN::Frontend->mywarn("  [testing] -- NOT OK\n");
            delete $self->{force_update};
            $self->post_test();
            return;
        }
    }
    $CPAN::Frontend->myprint(sprintf "Running %s test for %s\n", $make, $self->pretty_id);

    my $builddir = $self->dir or
        $CPAN::Frontend->mydie("PANIC: Cannot determine build directory\n");

    unless (chdir $builddir) {
        $CPAN::Frontend->mywarn("Couldn't chdir to '$builddir': $!");
        $self->post_test();
        return;
    }

    $self->debug("Changed directory to $self->{build_dir}")
        if $CPAN::DEBUG;

    if ($^O eq 'MacOS') {
        Mac::BuildTools::make_test($self);
        $self->post_test();
        return;
    }

    if ($self->{modulebuild}) {
        my $thm = CPAN::Shell->expand("Module","Test::Harness");
        my $v = $thm->inst_version;
        if (CPAN::Version->vlt($v,2.62)) {
            # XXX Eric Wilhelm reported this as a bug: klapperl:
            # Test::Harness 3.0 self-tests, so that should be 'unless
            # installing Test::Harness'
            unless ($self->id eq $thm->distribution->id) {
                $CPAN::Frontend->mywarn(qq{The version of your Test::Harness is only
  '$v', you need at least '2.62'. Please upgrade your Test::Harness.\n});
                $self->{make_test} = CPAN::Distrostatus->new("NO Test::Harness too old");
                $self->post_test();
                return;
            }
        }
    }

    if ( ! $self->{force_update}  ) {
        # bypass actual tests if "trust_test_report_history" and have a report
        my $have_tested_fcn;
        if (   $CPAN::Config->{trust_test_report_history}
            && $CPAN::META->has_inst("CPAN::Reporter::History")
            && ( $have_tested_fcn = CPAN::Reporter::History->can("have_tested" ))) {
            if ( my @reports = $have_tested_fcn->( dist => $self->base_id ) ) {
                # Do nothing if grade was DISCARD
                if ( $reports[-1]->{grade} =~ /^(?:PASS|UNKNOWN)$/ ) {
                    $self->{make_test} = CPAN::Distrostatus->new("YES");
                    # if global "is_tested" has been cleared, we need to mark this to
                    # be added to PERL5LIB if not already installed
                    if ($self->tested_ok_but_not_installed) {
                        $CPAN::META->is_tested($self->{build_dir},$self->{make_test}{TIME});
                    }
                    $CPAN::Frontend->myprint("Found prior test report -- OK\n");
                    $self->post_test();
                    return;
                }
                elsif ( $reports[-1]->{grade} =~ /^(?:FAIL|NA)$/ ) {
                    $self->{make_test} = CPAN::Distrostatus->new("NO");
                    $self->{badtestcnt}++;
                    $CPAN::Frontend->mywarn("Found prior test report -- NOT OK\n");
                    $self->post_test();
                    return;
                }
            }
        }
    }

    my $system;
    my $prefs_test = $self->prefs->{test};
    if (my $commandline
        = exists $prefs_test->{commandline} ? $prefs_test->{commandline} : "") {
        $system = $commandline;
        $ENV{PERL} = CPAN::find_perl();
    } elsif ($self->{modulebuild}) {
        $system = sprintf "%s test", $self->_build_command();
        unless (-e "Build" || ($^O eq 'VMS' && -e "Build.com")) {
            my $id = $self->pretty_id;
            $CPAN::Frontend->mywarn("Alert: no 'Build' file found while trying to test '$id'");
        }
    } else {
        $system = join " ", $self->_make_command(), "test";
    }
    my $make_test_arg = $self->_make_phase_arg("test");
    $system = sprintf("%s%s",
                      $system,
                      $make_test_arg ? " $make_test_arg" : "",
                     );
    my($tests_ok);
    my $test_env;
    if ($self->prefs->{test}) {
        $test_env = $self->prefs->{test}{env};
    }
    local @ENV{keys %$test_env} = values %$test_env if $test_env;
    my $expect_model = $self->_prefs_with_expect("test");
    my $want_expect = 0;
    if ( $expect_model && @{$expect_model->{talk}} ) {
        my $can_expect = $CPAN::META->has_inst("Expect");
        if ($can_expect) {
            $want_expect = 1;
        } else {
            $CPAN::Frontend->mywarn("Expect not installed, falling back to ".
                                    "testing without\n");
        }
    }

 FORK: {
        my $pid = fork;
        if (! defined $pid) { # contention
            warn "Contention '$!', sleeping 2";
            sleep 2;
            redo FORK;
        } elsif ($pid) { # parent
            if ($^O eq "MSWin32") {
                wait;
            } else {
            SUPERVISE: while (waitpid($pid, WNOHANG) <= 0) {
                    if ($CPAN::Signal) {
                        kill 9, -$pid;
                    }
                    sleep 1;
                }
            }
            $tests_ok = !$?;
        } else { # child
            POSIX::setsid() unless $^O eq "MSWin32";
            my $c_ok;
            $|=1;
            if ($want_expect) {
                if ($self->_should_report('test')) {
                    $CPAN::Frontend->mywarn("Reporting via CPAN::Reporter is currently ".
                        "not supported when distroprefs specify ".
                        "an interactive test\n");
                }
                $c_ok = $self->_run_via_expect($system,'test',$expect_model) == 0;
            } elsif ( $self->_should_report('test') ) {
                $c_ok = CPAN::Reporter::test($self, $system);
            } else {
                $c_ok = system($system) == 0;
            }
            exit !$c_ok;
        }
    } # FORK

    $self->introduce_myself;
    my $but = $self->_make_test_illuminate_prereqs();
    if ( $tests_ok ) {
        if ($but) {
            $CPAN::Frontend->mywarn("Tests succeeded but $but\n");
            $self->{make_test} = CPAN::Distrostatus->new("NO $but");
            $self->store_persistent_state;
            $self->post_test();
            return $self->goodbye("[dependencies] -- NA");
        }
        $CPAN::Frontend->myprint("  $system -- OK\n");
        $self->{make_test} = CPAN::Distrostatus->new("YES");
        $CPAN::META->is_tested($self->{build_dir},$self->{make_test}{TIME});
        # probably impossible to need the next line because badtestcnt
        # has a lifespan of one command
        delete $self->{badtestcnt};
    } else {
        if ($but) {
            $but .= "; additionally test harness failed";
            $CPAN::Frontend->mywarn("$but\n");
            $self->{make_test} = CPAN::Distrostatus->new("NO $but");
        } elsif ( $self->{force_update} ) {
            $self->{make_test} = CPAN::Distrostatus->new(
                "NO but failure ignored because 'force' in effect"
            );
        } elsif ($CPAN::Signal) {
            $self->{make_test} = CPAN::Distrostatus->new("NO -- Interrupted");
        } else {
            $self->{make_test} = CPAN::Distrostatus->new("NO");
        }
        $self->{badtestcnt}++;
        $CPAN::Frontend->mywarn("  $system -- NOT OK\n");
        CPAN::Shell->optprint
              ("hint",
               sprintf
               ("//hint// to see the cpan-testers results for installing this module, try:
  reports %s\n",
                $self->pretty_id));
    }
    $self->store_persistent_state;

    $self->post_test();

    return $self->{force_update} ? 1 : !! $tests_ok;
}

sub _make_test_illuminate_prereqs {
    my($self) = @_;
    my @prereq;

    # local $CPAN::DEBUG = 16; # Distribution
    for my $m (sort keys %{$self->{sponsored_mods}}) {
        next unless $self->{sponsored_mods}{$m} > 0;
        my $m_obj = CPAN::Shell->expand("Module",$m) or next;
        # XXX we need available_version which reflects
        # $ENV{PERL5LIB} so that already tested but not yet
        # installed modules are counted.
        my $available_version = $m_obj->available_version;
        my $available_file = $m_obj->available_file;
        if ($available_version &&
            !CPAN::Version->vlt($available_version,$self->{prereq_pm}{$m})
           ) {
            CPAN->debug("m[$m] good enough available_version[$available_version]")
                if $CPAN::DEBUG;
        } elsif ($available_file
                 && (
                     !$self->{prereq_pm}{$m}
                     ||
                     $self->{prereq_pm}{$m} == 0
                    )
                ) {
            # lex Class::Accessor::Chained::Fast which has no $VERSION
            CPAN->debug("m[$m] have available_file[$available_file]")
                if $CPAN::DEBUG;
        } else {
            push @prereq, $m
                unless $self->is_locally_optional(undef, $m);
        }
    }
    my $but;
    if (@prereq) {
        my $cnt = @prereq;
        my $which = join ",", @prereq;
        $but = $cnt == 1 ? "one dependency not OK ($which)" :
            "$cnt dependencies missing ($which)";
    }
    $but;
}

sub _prefs_with_expect {
    my($self,$where) = @_;
    return unless my $prefs = $self->prefs;
    return unless my $where_prefs = $prefs->{$where};
    if ($where_prefs->{expect}) {
        return {
                mode => "deterministic",
                timeout => 15,
                talk => $where_prefs->{expect},
               };
    } elsif ($where_prefs->{"eexpect"}) {
        return $where_prefs->{"eexpect"};
    }
    return;
}

#-> sub CPAN::Distribution::clean ;
sub clean {
    my($self) = @_;
    my $make = $self->{modulebuild} ? "Build" : "make";
    $CPAN::Frontend->myprint(sprintf "Running %s clean for %s\n", $make, $self->pretty_id);
    unless (exists $self->{archived}) {
        $CPAN::Frontend->mywarn("Distribution seems to have never been unzipped".
                                "/untarred, nothing done\n");
        return 1;
    }
    unless (exists $self->{build_dir}) {
        $CPAN::Frontend->mywarn("Distribution has no own directory, nothing to do.\n");
        return 1;
    }
    if (exists $self->{writemakefile}
        and $self->{writemakefile}->failed
       ) {
        $CPAN::Frontend->mywarn("No Makefile, don't know how to 'make clean'\n");
        return 1;
    }
  EXCUSE: {
        my @e;
        exists $self->{make_clean} and $self->{make_clean} eq "YES" and
            push @e, "make clean already called once";
        $CPAN::Frontend->myprint(join "", map {"  $_\n"} @e) and return if @e;
    }
    chdir "$self->{build_dir}" or
        Carp::confess("Couldn't chdir to $self->{build_dir}: $!");
    $self->debug("Changed directory to $self->{build_dir}") if $CPAN::DEBUG;

    if ($^O eq 'MacOS') {
        Mac::BuildTools::make_clean($self);
        return;
    }

    my $system;
    if ($self->{modulebuild}) {
        unless (-f "Build") {
            my $cwd = CPAN::anycwd();
            $CPAN::Frontend->mywarn("Alert: no Build file available for 'clean $self->{id}".
                                    " in cwd[$cwd]. Danger, Will Robinson!");
            $CPAN::Frontend->mysleep(5);
        }
        $system = sprintf "%s clean", $self->_build_command();
    } else {
        $system  = join " ", $self->_make_command(), "clean";
    }
    my $system_ok = system($system) == 0;
    $self->introduce_myself;
    if ( $system_ok ) {
      $CPAN::Frontend->myprint("  $system -- OK\n");

      # $self->force;

      # Jost Krieger pointed out that this "force" was wrong because
      # it has the effect that the next "install" on this distribution
      # will untar everything again. Instead we should bring the
      # object's state back to where it is after untarring.

      for my $k (qw(
                    force_update
                    install
                    writemakefile
                    make
                    make_test
                   )) {
          delete $self->{$k};
      }
      $self->{make_clean} = CPAN::Distrostatus->new("YES");

    } else {
      # Hmmm, what to do if make clean failed?

      $self->{make_clean} = CPAN::Distrostatus->new("NO");
      $CPAN::Frontend->mywarn(qq{  $system -- NOT OK\n});

      # 2006-02-27: seems silly to me to force a make now
      # $self->force("make"); # so that this directory won't be used again

    }
    $self->store_persistent_state;
}

#-> sub CPAN::Distribution::check_disabled ;
sub check_disabled {
    my ($self) = @_;
    $self->debug("checking disabled id[$self->{ID}]") if $CPAN::DEBUG;
    if ($self->prefs->{disabled} && ! $self->{force_update}) {
        return sprintf(
                            "Disabled via prefs file '%s' doc %d",
                            $self->{prefs_file},
                            $self->{prefs_file_doc},
                            );
    }
    return;
}

#-> sub CPAN::Distribution::goto ;
sub goto {
    my($self,$goto) = @_;
    $goto = $self->normalize($goto);
    my $why = sprintf(
                      "Goto '$goto' via prefs file '%s' doc %d",
                      $self->{prefs_file},
                      $self->{prefs_file_doc},
                     );
    $self->{unwrapped} = CPAN::Distrostatus->new("NO $why");
    # 2007-07-16 akoenig : Better than NA would be if we could inherit
    # the status of the $goto distro but given the exceptional nature
    # of 'goto' I feel reluctant to implement it
    my $goodbye_message = "[goto] -- NA $why";
    $self->goodbye($goodbye_message);

    # inject into the queue

    CPAN::Queue->delete($self->id);
    CPAN::Queue->jumpqueue({qmod => $goto, reqtype => $self->{reqtype}});

    # and run where we left off

    my($method) = (caller(1))[3];
    my $goto_do = CPAN->instance("CPAN::Distribution",$goto);
    $goto_do->called_for($self->called_for) unless $goto_do->called_for;
    $goto_do->{mandatory} ||= $self->{mandatory};
    $goto_do->{reqtype}   ||= $self->{reqtype};
    $goto_do->{coming_from} = $self->pretty_id;
    $goto_do->$method();
    CPAN::Queue->delete_first($goto);
    # XXX delete_first returns undef; is that what this should return
    # up the call stack, eg. return $sefl->goto($goto) -- xdg, 2012-04-04
}

#-> sub CPAN::Distribution::shortcut_install ;
# return values: undef means don't shortcut; 0 means shortcut as fail;
# and 1 means shortcut as success
sub shortcut_install {
    my ($self) = @_;

    $self->debug("checking previous install results[$self->{ID}]") if $CPAN::DEBUG;
    if (exists $self->{install}) {
        my $text = UNIVERSAL::can($self->{install},"text") ?
            $self->{install}->text :
                $self->{install};
        if ($text =~ /^YES/) {
            $CPAN::META->is_installed($self->{build_dir});
            return $self->success("Already done");
        } elsif ($text =~ /is only/) {
            # e.g. 'is only build_requires': may be overruled later
            return $self->goodbye($text);
        } else {
            # comment in Todo on 2006-02-11; maybe retry?
            return $self->goodbye("Already tried without success");
        }
    }

    for my $slot ( qw/later configure_requires_later/ ) {
        return $self->success($self->{$slot})
        if $self->{$slot};
    }

    return undef;
}

#-> sub CPAN::Distribution::is_being_sponsored ;

# returns true if we find a distro object in the queue that has
# sponsored this one
sub is_being_sponsored {
    my($self) = @_;
    my $iterator = CPAN::Queue->iterator;
 QITEM: while (my $q = $iterator->()) {
        my $s = $q->as_string;
        my $obj = CPAN::Shell->expandany($s) or next QITEM;
        my $type = ref $obj;
        if ( $type eq 'CPAN::Distribution' ){
            for my $module (sort keys %{$obj->{sponsored_mods} || {}}) {
                return 1 if grep { $_ eq $module } $self->containsmods;
            }
        }
    }
    return 0;
}

#-> sub CPAN::Distribution::install ;
sub install {
    my($self) = @_;

    $self->pre_install();

    if (exists $self->{cleanup_after_install_done}) {
        return $self->test;
    }

    $self->debug("checking goto id[$self->{ID}]") if $CPAN::DEBUG;
    if (my $goto = $self->prefs->{goto}) {
        $self->goto($goto);
        $self->post_install();
        return;
    }

    unless ($self->test) {
        $self->post_install();
        return;
    }

    if ( defined( my $sc = $self->shortcut_install ) ) {
        $self->post_install();
        return $sc;
    }

    if ($CPAN::Signal) {
        delete $self->{force_update};
        $self->post_install();
        return;
    }

    my $builddir = $self->dir or
        $CPAN::Frontend->mydie("PANIC: Cannot determine build directory\n");

    unless (chdir $builddir) {
        $CPAN::Frontend->mywarn("Couldn't chdir to '$builddir': $!");
        $self->post_install();
        return;
    }

    $self->debug("Changed directory to $self->{build_dir}")
        if $CPAN::DEBUG;

    my $make = $self->{modulebuild} ? "Build" : "make";
    $CPAN::Frontend->myprint(sprintf "Running %s install for %s\n", $make, $self->pretty_id);

    if ($^O eq 'MacOS') {
        Mac::BuildTools::make_install($self);
        $self->post_install();
        return;
    }

    my $system;
    if (my $commandline = $self->prefs->{install}{commandline}) {
        $system = $commandline;
        $ENV{PERL} = CPAN::find_perl();
    } elsif ($self->{modulebuild}) {
        my($mbuild_install_build_command) =
            exists $CPAN::HandleConfig::keys{mbuild_install_build_command} &&
                $CPAN::Config->{mbuild_install_build_command} ?
                    $CPAN::Config->{mbuild_install_build_command} :
                        $self->_build_command();
        my $install_directive = $^O eq 'VMS' ? '"install"' : 'install';
        $system = sprintf("%s %s %s",
                          $mbuild_install_build_command,
                          $install_directive,
                          $CPAN::Config->{mbuild_install_arg},
                         );
    } else {
        my($make_install_make_command) = $self->_make_install_make_command();
        $system = sprintf("%s install %s",
                          $make_install_make_command,
                          $CPAN::Config->{make_install_arg},
                         );
    }

    my($stderr) = $^O eq "MSWin32" || $^O eq 'VMS' ? "" : " 2>&1 ";
    my $brip = CPAN::HandleConfig->prefs_lookup($self,
                                                q{build_requires_install_policy});
    $brip ||="ask/yes";
    my $id = $self->id;
    my $reqtype = $self->{reqtype} ||= "c"; # in doubt it was a command
    my $want_install = "yes";
    if ($reqtype eq "b") {
        if ($brip eq "no") {
            $want_install = "no";
        } elsif ($brip =~ m|^ask/(.+)|) {
            my $default = $1;
            $default = "yes" unless $default =~ /^(y|n)/i;
            $want_install =
                CPAN::Shell::colorable_makemaker_prompt
                      ("$id is just needed temporarily during building or testing. ".
                       "Do you want to install it permanently?",
                       $default);
        }
    }
    unless ($want_install =~ /^y/i) {
        my $is_only = "is only 'build_requires'";
        $self->{install} = CPAN::Distrostatus->new("NO -- $is_only");
        delete $self->{force_update};
        $self->goodbye("Not installing because $is_only");
        $self->post_install();
        return;
    }
    local $ENV{PERL5LIB} = defined($ENV{PERL5LIB})
                           ? $ENV{PERL5LIB}
                           : ($ENV{PERLLIB} || "");

    local $ENV{PERL5OPT} = defined $ENV{PERL5OPT} ? $ENV{PERL5OPT} : "";
    local $ENV{PERL_USE_UNSAFE_INC} =
        exists $ENV{PERL_USE_UNSAFE_INC} && defined $ENV{PERL_USE_UNSAFE_INC}
        ? $ENV{PERL_USE_UNSAFE_INC} : 1; # install
    $CPAN::META->set_perl5lib;
    local $ENV{PERL_MM_USE_DEFAULT} = 1 if $CPAN::Config->{use_prompt_default};
    local $ENV{NONINTERACTIVE_TESTING} = 1 if $CPAN::Config->{use_prompt_default};

    my $install_env;
    if ($self->prefs->{install}) {
        $install_env = $self->prefs->{install}{env};
    }
    local @ENV{keys %$install_env} = values %$install_env if $install_env;

    if (! $run_allow_installing_within_test) {
        my($allow_installing, $why) = $self->_allow_installing;
        if (! $allow_installing) {
            $CPAN::Frontend->mywarn("Installation stopped: $why\n");
            $self->introduce_myself;
            $self->{install} = CPAN::Distrostatus->new("NO -- installation stopped due $why");
            $CPAN::Frontend->mywarn("  $system -- NOT OK\n");
            delete $self->{force_update};
            $self->post_install();
            return;
        }
    }
    my($pipe) = FileHandle->new("$system $stderr |");
    unless ($pipe) {
        $CPAN::Frontend->mywarn("Can't execute $system: $!");
        $self->introduce_myself;
        $self->{install} = CPAN::Distrostatus->new("NO");
        $CPAN::Frontend->mywarn("  $system -- NOT OK\n");
        delete $self->{force_update};
        $self->post_install();
        return;
    }
    my($makeout) = "";
    while (<$pipe>) {
        print $_; # intentionally NOT use Frontend->myprint because it
                  # looks irritating when we markup in color what we
                  # just pass through from an external program
        $makeout .= $_;
    }
    $pipe->close;
    my $close_ok = $? == 0;
    $self->introduce_myself;
    if ( $close_ok ) {
        $CPAN::Frontend->myprint("  $system -- OK\n");
        $CPAN::META->is_installed($self->{build_dir});
        $self->{install} = CPAN::Distrostatus->new("YES");
        if ($CPAN::Config->{'cleanup_after_install'}
            && ! $self->is_dot_dist
            && ! $self->is_being_sponsored) {
            my $parent = File::Spec->catdir( $self->{build_dir}, File::Spec->updir );
            chdir $parent or $CPAN::Frontend->mydie("Couldn't chdir to $parent: $!\n");
            File::Path::rmtree($self->{build_dir});
            my $yml = "$self->{build_dir}.yml";
            if (-e $yml) {
                unlink $yml or $CPAN::Frontend->mydie("Couldn't unlink $yml: $!\n");
            }
            $self->{cleanup_after_install_done}=1;
        }
    } else {
        $self->{install} = CPAN::Distrostatus->new("NO");
        $CPAN::Frontend->mywarn("  $system -- NOT OK\n");
        my $mimc =
            CPAN::HandleConfig->prefs_lookup($self,
                                             q{make_install_make_command});
        if (
            $makeout =~ /permission/s
            && $> > 0
            && (
                ! $mimc
                || $mimc eq (CPAN::HandleConfig->prefs_lookup($self,
                                                              q{make}))
               )
           ) {
            $CPAN::Frontend->myprint(
                                     qq{----\n}.
                                     qq{  You may have to su }.
                                     qq{to root to install the package\n}.
                                     qq{  (Or you may want to run something like\n}.
                                     qq{    o conf make_install_make_command 'sudo make'\n}.
                                     qq{  to raise your permissions.}
                                    );
        }
    }
    delete $self->{force_update};
    unless ($CPAN::Config->{'cleanup_after_install'}) {
        $self->store_persistent_state;
    }

    $self->post_install();

    return !! $close_ok;
}

sub blib_pm_walk {
    my @queue = grep { -e $_ } File::Spec->catdir("blib","lib"), File::Spec->catdir("blib","arch");
    return sub {
    LOOP: {
            if (@queue) {
                my $file = shift @queue;
                if (-d $file) {
                    my $dh;
                    opendir $dh, $file or next;
                    my @newfiles = map {
                        my @ret;
                        my $maybedir = File::Spec->catdir($file, $_);
                        if (-d $maybedir) {
                            unless (File::Spec->catdir("blib","arch","auto") eq $maybedir) {
                                # prune the blib/arch/auto directory, no pm files there
                                @ret = $maybedir;
                            }
                        } elsif (/\.pm$/) {
                            my $mustbefile = File::Spec->catfile($file, $_);
                            if (-f $mustbefile) {
                                @ret = $mustbefile;
                            }
                        }
                        @ret;
                    } grep {
                        $_ ne "."
                            && $_ ne ".."
                        } readdir $dh;
                    push @queue, @newfiles;
                    redo LOOP;
                } else {
                    return $file;
                }
            } else {
                return;
            }
        }
    };
}

sub _allow_installing {
    my($self) = @_;
    my $id = my $pretty_id = $self->pretty_id;
    if ($self->{CALLED_FOR}) {
        $id .= " (called for $self->{CALLED_FOR})";
    }
    my $allow_down   = CPAN::HandleConfig->prefs_lookup($self,q{allow_installing_module_downgrades});
    $allow_down      ||= "ask/yes";
    my $allow_outdd  = CPAN::HandleConfig->prefs_lookup($self,q{allow_installing_outdated_dists});
    $allow_outdd     ||= "ask/yes";
    return 1 if
           $allow_down  eq "yes"
        && $allow_outdd eq "yes";
    if (($allow_outdd ne "yes") && ! $CPAN::META->has_inst('CPAN::DistnameInfo')) {
        return 1 if grep { $_ eq 'CPAN::DistnameInfo'} $self->containsmods;
        if ($allow_outdd ne "yes") {
            $CPAN::Frontend->mywarn("The current configuration of allow_installing_outdated_dists is '$allow_outdd', but for this option we would need 'CPAN::DistnameInfo' installed. Please install 'CPAN::DistnameInfo' as soon as possible. As long as we are not equipped with 'CPAN::DistnameInfo' this option does not take effect\n");
            $allow_outdd = "yes";
        }
    }
    return 1 if
           $allow_down  eq "yes"
        && $allow_outdd eq "yes";
    my($dist_version, $dist_dist);
    if ($allow_outdd ne "yes"){
        my $dni = CPAN::DistnameInfo->new($pretty_id);
        $dist_version = $dni->version;
        $dist_dist    = $dni->dist;
    }
    my $iterator = blib_pm_walk();
    my(@down,@outdd);
    while (my $file = $iterator->()) {
        my $version = CPAN::Module->parse_version($file);
        my($volume, $directories, $pmfile) = File::Spec->splitpath( $file );
        my @dirs = File::Spec->splitdir( $directories );
        my(@blib_plus1) = splice @dirs, 0, 2;
        my($pmpath) = File::Spec->catfile(grep { length($_) } @dirs, $pmfile);
        unless ($allow_down eq "yes") {
            if (my $inst_file = $self->_file_in_path($pmpath, \@INC)) {
                my $inst_version = CPAN::Module->parse_version($inst_file);
                my $cmp = CPAN::Version->vcmp($version, $inst_version);
                if ($cmp) {
                    if ($cmp < 0) {
                        push @down, { pmpath => $pmpath, version => $version, inst_version => $inst_version };
                    }
                }
                if (@down) {
                    my $why = "allow_installing_module_downgrades: $id contains downgrading module(s) (e.g. '$down[0]{pmpath}' would downgrade installed '$down[0]{inst_version}' to '$down[0]{version}')";
                    if (my($default) = $allow_down =~ m|^ask/(.+)|) {
                        $default = "yes" unless $default =~ /^(y|n)/i;
                        my $answer = CPAN::Shell::colorable_makemaker_prompt
                                ("$why. Do you want to allow installing it?",
                                 $default, "colorize_warn");
                        $allow_down = $answer =~ /^\s*y/i ? "yes" : "no";
                    }
                    if ($allow_down eq "no") {
                        return (0, $why);
                    }
                }
            }
        }
        unless ($allow_outdd eq "yes") {
            my @pmpath = (@dirs, $pmfile);
            $pmpath[-1] =~ s/\.pm$//;
            my $mo = CPAN::Shell->expand("Module",join "::", grep { length($_) } @pmpath);
            if ($mo) {
                my $cpan_version = $mo->cpan_version;
                my $is_lower = CPAN::Version->vlt($version, $cpan_version);
                my $other_dist;
                if (my $mo_dist = $mo->distribution) {
                    $other_dist = $mo_dist->pretty_id;
                    my $dni = CPAN::DistnameInfo->new($other_dist);
                    if ($dni->dist eq $dist_dist){
                        if (CPAN::Version->vgt($dni->version, $dist_version)) {
                            push @outdd, {
                                pmpath       => $pmpath,
                                cpan_path    => $dni->pathname,
                                dist_version => $dni->version,
                                dist_dist    => $dni->dist,
                            };
                        }
                    }
                }
            }
            if (@outdd && $allow_outdd ne "yes") {
                my $why = "allow_installing_outdated_dists: $id contains module(s) that are indexed on the CPAN with a different distro: (e.g. '$outdd[0]{pmpath}' is indexed with '$outdd[0]{cpan_path}')";
                if ($outdd[0]{dist_dist} eq $dist_dist) {
                    $why .= ", and this has a higher distribution-version, i.e. version '$outdd[0]{dist_version}' is higher than '$dist_version')";
                }
                if (my($default) = $allow_outdd =~ m|^ask/(.+)|) {
                    $default = "yes" unless $default =~ /^(y|n)/i;
                    my $answer = CPAN::Shell::colorable_makemaker_prompt
                        ("$why. Do you want to allow installing it?",
                         $default, "colorize_warn");
                    $allow_outdd = $answer =~ /^\s*y/i ? "yes" : "no";
                }
                if ($allow_outdd eq "no") {
                    return (0, $why);
                }
            }
        }
    }
    return 1;
}

sub _file_in_path { # similar to CPAN::Module::_file_in_path
    my($self,$pmpath,$incpath) = @_;
    my($dir,@packpath);
    foreach $dir (@$incpath) {
        my $pmfile = File::Spec->catfile($dir,$pmpath);
        if (-f $pmfile) {
            return $pmfile;
        }
    }
    return;
}
sub introduce_myself {
    my($self) = @_;
    $CPAN::Frontend->myprint(sprintf("  %s\n",$self->pretty_id));
}

#-> sub CPAN::Distribution::dir ;
sub dir {
    shift->{build_dir};
}

#-> sub CPAN::Distribution::perldoc ;
sub perldoc {
    my($self) = @_;

    my($dist) = $self->id;
    my $package = $self->called_for;

    if ($CPAN::META->has_inst("Pod::Perldocs")) {
        my($perl) = $self->perl
            or $CPAN::Frontend->mydie("Couldn't find executable perl\n");
        my @args = ($perl, q{-MPod::Perldocs}, q{-e},
                    q{Pod::Perldocs->run()}, $package);
        my($wstatus);
        unless ( ($wstatus = system(@args)) == 0 ) {
            my $estatus = $wstatus >> 8;
            $CPAN::Frontend->myprint(qq{
    Function system("@args")
    returned status $estatus (wstat $wstatus)
    });
        }
    }
    else {
        $self->_display_url( $CPAN::Defaultdocs . $package );
    }
}

#-> sub CPAN::Distribution::_check_binary ;
sub _check_binary {
    my ($dist,$shell,$binary) = @_;
    my ($pid,$out);

    $CPAN::Frontend->myprint(qq{ + _check_binary($binary)\n})
      if $CPAN::DEBUG;

    if ($CPAN::META->has_inst("File::Which")) {
        return File::Which::which($binary);
    } else {
        local *README;
        $pid = open README, "which $binary|"
            or $CPAN::Frontend->mywarn(qq{Could not fork 'which $binary': $!\n});
        return unless $pid;
        while (<README>) {
            $out .= $_;
        }
        close README
            or $CPAN::Frontend->mywarn("Could not run 'which $binary': $!\n")
                and return;
    }

    $CPAN::Frontend->myprint(qq{   + $out \n})
      if $CPAN::DEBUG && $out;

    return $out;
}

#-> sub CPAN::Distribution::_display_url ;
sub _display_url {
    my($self,$url) = @_;
    my($res,$saved_file,$pid,$out);

    $CPAN::Frontend->myprint(qq{ + _display_url($url)\n})
      if $CPAN::DEBUG;

    # should we define it in the config instead?
    my $html_converter = "html2text.pl";

    my $web_browser = $CPAN::Config->{'lynx'} || undef;
    my $web_browser_out = $web_browser
        ? CPAN::Distribution->_check_binary($self,$web_browser)
        : undef;

    if ($web_browser_out) {
        # web browser found, run the action
        my $browser = CPAN::HandleConfig->safe_quote($CPAN::Config->{'lynx'});
        $CPAN::Frontend->myprint(qq{system[$browser $url]})
            if $CPAN::DEBUG;
        $CPAN::Frontend->myprint(qq{
Displaying URL
  $url
with browser $browser
});
        $CPAN::Frontend->mysleep(1);
        system("$browser $url");
        if ($saved_file) { 1 while unlink($saved_file) }
    } else {
        # web browser not found, let's try text only
        my $html_converter_out =
            CPAN::Distribution->_check_binary($self,$html_converter);
        $html_converter_out = CPAN::HandleConfig->safe_quote($html_converter_out);

        if ($html_converter_out ) {
            # html2text found, run it
            $saved_file = CPAN::Distribution->_getsave_url( $self, $url );
            $CPAN::Frontend->mydie(qq{ERROR: problems while getting $url\n})
                unless defined($saved_file);

            local *README;
            $pid = open README, "$html_converter $saved_file |"
                or $CPAN::Frontend->mydie(qq{
Could not fork '$html_converter $saved_file': $!});
            my($fh,$filename);
            if ($CPAN::META->has_usable("File::Temp")) {
                $fh = File::Temp->new(
                                      dir      => File::Spec->tmpdir,
                                      template => 'cpan_htmlconvert_XXXX',
                                      suffix => '.txt',
                                      unlink => 0,
                                     );
                $filename = $fh->filename;
            } else {
                $filename = "cpan_htmlconvert_$$.txt";
                $fh = FileHandle->new();
                open $fh, ">$filename" or die;
            }
            while (<README>) {
                $fh->print($_);
            }
            close README or
                $CPAN::Frontend->mydie(qq{Could not run '$html_converter $saved_file': $!});
            my $tmpin = $fh->filename;
            $CPAN::Frontend->myprint(sprintf(qq{
Run '%s %s' and
saved output to %s\n},
                                             $html_converter,
                                             $saved_file,
                                             $tmpin,
                                            )) if $CPAN::DEBUG;
            close $fh;
            local *FH;
            open FH, $tmpin
                or $CPAN::Frontend->mydie(qq{Could not open "$tmpin": $!});
            my $fh_pager = FileHandle->new;
            local($SIG{PIPE}) = "IGNORE";
            my $pager = $CPAN::Config->{'pager'} || "cat";
            $fh_pager->open("|$pager")
                or $CPAN::Frontend->mydie(qq{
Could not open pager '$pager': $!});
            $CPAN::Frontend->myprint(qq{
Displaying URL
  $url
with pager "$pager"
});
            $CPAN::Frontend->mysleep(1);
            $fh_pager->print(<FH>);
            $fh_pager->close;
        } else {
            # coldn't find the web browser or html converter
            $CPAN::Frontend->myprint(qq{
You need to install lynx or $html_converter to use this feature.});
        }
    }
}

#-> sub CPAN::Distribution::_getsave_url ;
sub _getsave_url {
    my($dist, $shell, $url) = @_;

    $CPAN::Frontend->myprint(qq{ + _getsave_url($url)\n})
      if $CPAN::DEBUG;

    my($fh,$filename);
    if ($CPAN::META->has_usable("File::Temp")) {
        $fh = File::Temp->new(
                              dir      => File::Spec->tmpdir,
                              template => "cpan_getsave_url_XXXX",
                              suffix => ".html",
                              unlink => 0,
                             );
        $filename = $fh->filename;
    } else {
        $fh = FileHandle->new;
        $filename = "cpan_getsave_url_$$.html";
    }
    my $tmpin = $filename;
    if ($CPAN::META->has_usable('LWP')) {
        $CPAN::Frontend->myprint("Fetching with LWP:
  $url
");
        my $Ua;
        CPAN::LWP::UserAgent->config;
        eval { $Ua = CPAN::LWP::UserAgent->new; };
        if ($@) {
            $CPAN::Frontend->mywarn("ERROR: CPAN::LWP::UserAgent->new dies with $@\n");
            return;
        } else {
            my($var);
            $Ua->proxy('http', $var)
                if $var = $CPAN::Config->{http_proxy} || $ENV{http_proxy};
            $Ua->no_proxy($var)
                if $var = $CPAN::Config->{no_proxy} || $ENV{no_proxy};
        }

        my $req = HTTP::Request->new(GET => $url);
        $req->header('Accept' => 'text/html');
        my $res = $Ua->request($req);
        if ($res->is_success) {
            $CPAN::Frontend->myprint(" + request successful.\n")
                if $CPAN::DEBUG;
            print $fh $res->content;
            close $fh;
            $CPAN::Frontend->myprint(qq{ + saved content to $tmpin \n})
                if $CPAN::DEBUG;
            return $tmpin;
        } else {
            $CPAN::Frontend->myprint(sprintf(
                                             "LWP failed with code[%s], message[%s]\n",
                                             $res->code,
                                             $res->message,
                                            ));
            return;
        }
    } else {
        $CPAN::Frontend->mywarn("  LWP not available\n");
        return;
    }
}

#-> sub CPAN::Distribution::_build_command
sub _build_command {
    my($self) = @_;
    if ($^O eq "MSWin32") { # special code needed at least up to
                            # Module::Build 0.2611 and 0.2706; a fix
                            # in M:B has been promised 2006-01-30
        my($perl) = $self->perl or $CPAN::Frontend->mydie("Couldn't find executable perl\n");
        return "$perl ./Build";
    }
    elsif ($^O eq 'VMS') {
        return "$^X Build.com";
    }
    return "./Build";
}

#-> sub CPAN::Distribution::_should_report
sub _should_report {
    my($self, $phase) = @_;
    die "_should_report() requires a 'phase' argument"
        if ! defined $phase;

    return unless $CPAN::META->has_usable("CPAN::Reporter");

    # configured
    my $test_report = CPAN::HandleConfig->prefs_lookup($self,
                                                       q{test_report});
    return unless $test_report;

    # don't repeat if we cached a result
    return $self->{should_report}
        if exists $self->{should_report};

    # don't report if we generated a Makefile.PL
    if ( $self->{had_no_makefile_pl} ) {
        $CPAN::Frontend->mywarn(
            "Will not send CPAN Testers report with generated Makefile.PL.\n"
        );
        return $self->{should_report} = 0;
    }

    # available
    if ( ! $CPAN::META->has_inst("CPAN::Reporter")) {
        $CPAN::Frontend->mywarnonce(
            "CPAN::Reporter not installed.  No reports will be sent.\n"
        );
        return $self->{should_report} = 0;
    }

    # capable
    my $crv = CPAN::Reporter->VERSION;
    if ( CPAN::Version->vlt( $crv, 0.99 ) ) {
        # don't cache $self->{should_report} -- need to check each phase
        if ( $phase eq 'test' ) {
            return 1;
        }
        else {
            $CPAN::Frontend->mywarn(
                "Reporting on the '$phase' phase requires CPAN::Reporter 0.99, but \n" .
                "you only have version $crv\.  Only 'test' phase reports will be sent.\n"
            );
            return;
        }
    }

    # appropriate
    if ($self->is_dot_dist) {
        $CPAN::Frontend->mywarn("Reporting via CPAN::Reporter is disabled ".
                                "for local directories\n");
        return $self->{should_report} = 0;
    }
    if ($self->prefs->{patches}
        &&
        @{$self->prefs->{patches}}
        &&
        $self->{patched}
       ) {
        $CPAN::Frontend->mywarn("Reporting via CPAN::Reporter is disabled ".
                                "when the source has been patched\n");
        return $self->{should_report} = 0;
    }

    # proceed and cache success
    return $self->{should_report} = 1;
}

#-> sub CPAN::Distribution::reports
sub reports {
    my($self) = @_;
    my $pathname = $self->id;
    $CPAN::Frontend->myprint("Distribution: $pathname\n");

    unless ($CPAN::META->has_inst("CPAN::DistnameInfo")) {
        $CPAN::Frontend->mydie("CPAN::DistnameInfo not installed; cannot continue");
    }
    unless ($CPAN::META->has_usable("LWP")) {
        $CPAN::Frontend->mydie("LWP not installed; cannot continue");
    }
    unless ($CPAN::META->has_usable("File::Temp")) {
        $CPAN::Frontend->mydie("File::Temp not installed; cannot continue");
    }

    my $format;
    if ($CPAN::META->has_inst("YAML::XS") || $CPAN::META->has_inst("YAML::Syck")){
        $format = 'yaml';
    }
    elsif (!$format && $CPAN::META->has_inst("JSON::PP") ) {
        $format = 'json';
    }
    else {
        $CPAN::Frontend->mydie("JSON::PP not installed, cannot continue");
    }

    my $d = CPAN::DistnameInfo->new($pathname);

    my $dist      = $d->dist;      # "CPAN-DistnameInfo"
    my $version   = $d->version;   # "0.02"
    my $maturity  = $d->maturity;  # "released"
    my $filename  = $d->filename;  # "CPAN-DistnameInfo-0.02.tar.gz"
    my $cpanid    = $d->cpanid;    # "GBARR"
    my $distvname = $d->distvname; # "CPAN-DistnameInfo-0.02"

    my $url = sprintf "http://www.cpantesters.org/show/%s.%s", $dist, $format;

    CPAN::LWP::UserAgent->config;
    my $Ua;
    eval { $Ua = CPAN::LWP::UserAgent->new; };
    if ($@) {
        $CPAN::Frontend->mydie("CPAN::LWP::UserAgent->new dies with $@\n");
    }
    $CPAN::Frontend->myprint("Fetching '$url'...");
    my $resp = $Ua->get($url);
    unless ($resp->is_success) {
        $CPAN::Frontend->mydie(sprintf "Could not download '%s': %s\n", $url, $resp->code);
    }
    $CPAN::Frontend->myprint("DONE\n\n");
    my $unserialized;
    if ( $format eq 'yaml' ) {
        my $yaml = $resp->content;
        # what a long way round!
        my $fh = File::Temp->new(
                                 dir      => File::Spec->tmpdir,
                                 template => 'cpan_reports_XXXX',
                                 suffix => '.yaml',
                                 unlink => 0,
                                );
        my $tfilename = $fh->filename;
        print $fh $yaml;
        close $fh or $CPAN::Frontend->mydie("Could not close '$tfilename': $!");
        $unserialized = CPAN->_yaml_loadfile($tfilename)->[0];
        unlink $tfilename or $CPAN::Frontend->mydie("Could not unlink '$tfilename': $!");
    } else {
        require JSON::PP;
        $unserialized = JSON::PP->new->utf8->decode($resp->content);
    }
    my %other_versions;
    my $this_version_seen;
    for my $rep (@$unserialized) {
        my $rversion = $rep->{version};
        if ($rversion eq $version) {
            unless ($this_version_seen++) {
                $CPAN::Frontend->myprint ("$rep->{version}:\n");
            }
            my $arch = $rep->{archname} || $rep->{platform}        || '????';
            my $grade = $rep->{action}  || $rep->{status}          || '????';
            my $ostext = $rep->{ostext} || ucfirst($rep->{osname}) || '????';
            $CPAN::Frontend->myprint
                (sprintf("%1s%1s%-4s %s on %s %s (%s)\n",
                         $arch eq $Config::Config{archname}?"*":"",
                         $grade eq "PASS"?"+":$grade eq"FAIL"?"-":"",
                         $grade,
                         $rep->{perl},
                         $ostext,
                         $rep->{osvers},
                         $arch,
                        ));
        } else {
            $other_versions{$rep->{version}}++;
        }
    }
    unless ($this_version_seen) {
        $CPAN::Frontend->myprint("No reports found for version '$version'
Reports for other versions:\n");
        for my $v (sort keys %other_versions) {
            $CPAN::Frontend->myprint(" $v\: $other_versions{$v}\n");
        }
    }
    $url = substr($url,0,-4) . 'html';
    $CPAN::Frontend->myprint("See $url for details\n");
}

1;
PK7N%[C�����perl5/CPAN/Plugin.pmnu��6�$package CPAN::Plugin;

use strict;
use warnings;

our $VERSION = '0.97';

require CPAN;

######################################################################

sub new {                                # ;
    my ($class, %params) = @_;

    my $self = +{
        (ref $class ? (%$class) : ()),
        %params,
    };

    $self = bless $self, ref $class ? ref $class : $class;

    unless (ref $class) {
        local $_;
        no warnings 'once';
        $CPAN::META->use_inst ($_) for $self->plugin_requires;
    }

    $self;
}

######################################################################
sub plugin_requires {                    # ;
}

######################################################################
sub distribution_object {                # ;
    my ($self) = @_;
    $self->{distribution_object};
}

######################################################################
sub distribution {                       # ;
    my ($self) = @_;

    my $distribution = $self->distribution_object->id;
    CPAN::Shell->expand("Distribution",$distribution)
      or $self->frontend->mydie("Unknowns distribution '$distribution'\n");
}

######################################################################
sub distribution_info {                  # ;
    my ($self) = @_;

    CPAN::DistnameInfo->new ($self->distribution->id);
}

######################################################################
sub build_dir {                          # ;
    my ($self) = @_;

    my $build_dir = $self->distribution->{build_dir}
      or $self->frontend->mydie("Distribution has not been built yet, cannot proceed");
}

######################################################################
sub is_xs {                              #
    my ($self) = @_;

    my @xs = glob File::Spec->catfile ($self->build_dir, '*.xs'); # quick try

    unless (@xs) {
        require ExtUtils::Manifest;
        my $manifest_file = File::Spec->catfile ($self->build_dir, "MANIFEST");
        my $manifest = ExtUtils::Manifest::maniread($manifest_file);
        @xs = grep /\.xs$/, keys %$manifest;
    }

    scalar @xs;
}

######################################################################

package CPAN::Plugin;

1;

__END__

=pod

=head1 NAME

CPAN::Plugin - Base class for CPAN shell extensions

=head1 SYNOPSIS

   package CPAN::Plugin::Flurb;
   use parent 'CPAN::Plugin';

   sub post_test {
     my ($self, $distribution_object) = @_;
     $self = $self->new (distribution_object => $distribution_object);
     ...;
   }

=head1 DESCRIPTION

=head2 Alpha Status

The plugin system in the CPAN shell was introduced in version 2.07 and
is still considered experimental.

=head2 How Plugins work?

See L<CPAN/"Plugin support">.

=head1 METHODS

=head2 plugin_requires

returns list of packages given plugin requires for functionality.
This list is evaluated using C<< CPAN->use_inst >> method.

=head2 distribution_object

Get current distribution object.

=head2 distribution

=head2 distribution_info

=head2 build_dir

Simple delegatees for misc parameters derived from distribution

=head2 is_xs

Predicate to detect whether package contains XS.

=head1 AUTHOR

Branislav Zahradnik <barney@cpan.org>

=cut

PK7N%[z���66perl5/CPAN/Debug.pmnu��6�$# -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*-
package CPAN::Debug;
use strict;
use vars qw($VERSION);

$VERSION = "5.5001";
# module is internal to CPAN.pm

%CPAN::DEBUG = qw[
                  CPAN              1
                  Index             2
                  InfoObj           4
                  Author            8
                  Distribution     16
                  Bundle           32
                  Module           64
                  CacheMgr        128
                  Complete        256
                  FTP             512
                  Shell          1024
                  Eval           2048
                  HandleConfig   4096
                  Tarzip         8192
                  Version       16384
                  Queue         32768
                  FirstTime     65536
];

$CPAN::DEBUG ||= 0;

#-> sub CPAN::Debug::debug ;
sub debug {
    my($self,$arg) = @_;

    my @caller;
    my $i = 0;
    while () {
        my(@c) = (caller($i))[0 .. ($i ? 3 : 2)];
        last unless defined $c[0];
        push @caller, \@c;
        for (0,3) {
            last if $_ > $#c;
            $c[$_] =~ s/.*:://;
        }
        for (1) {
            $c[$_] =~ s|.*/||;
        }
        last if ++$i>=3;
    }
    pop @caller;
    if ($CPAN::DEBUG{$caller[0][0]} & $CPAN::DEBUG) {
        if ($arg and ref $arg) {
            eval { require Data::Dumper };
            if ($@) {
                $CPAN::Frontend->myprint("Debug(\n" . $arg->as_string . ")\n");
            } else {
                $CPAN::Frontend->myprint("Debug(\n" . Data::Dumper::Dumper($arg) . ")\n");
            }
        } else {
            my $outer = "";
            local $" = ",";
            if (@caller>1) {
                $outer = ",[@{$caller[1]}]";
            }
            $CPAN::Frontend->myprint("Debug(@{$caller[0]}$outer): $arg\n");
        }
    }
}

1;

__END__

=head1 NAME

CPAN::Debug - internal debugging for CPAN.pm

=head1 LICENSE

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

=cut
PK7N%[���((perl5/CPAN/HTTP/Client.pmnu��6�$# -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*-
# vim: ts=4 sts=4 sw=4:
package CPAN::HTTP::Client;
use strict;
use vars qw(@ISA);
use CPAN::HTTP::Credentials;
use HTTP::Tiny 0.005;

$CPAN::HTTP::Client::VERSION = $CPAN::HTTP::Client::VERSION = "1.9602";

# CPAN::HTTP::Client is adapted from parts of cpanm by Tatsuhiko Miyagawa
# and parts of LWP by Gisle Aas

sub new {
    my $class = shift;
    my %args = @_;
    for my $k ( keys %args ) {
        $args{$k} = '' unless defined $args{$k};
    }
    $args{no_proxy} = [split(",", $args{no_proxy}) ] if $args{no_proxy};
    return bless \%args, $class;
}

# This executes a request with redirection (up to 5) and returns the
# response structure generated by HTTP::Tiny
#
# If authentication fails, it will attempt to get new authentication
# information and repeat up to 5 times

sub mirror {
    my($self, $uri, $path) = @_;

    my $want_proxy = $self->_want_proxy($uri);
    my $http = HTTP::Tiny->new(
        verify_SSL => 1,
        $want_proxy ? (proxy => $self->{proxy}) : ()
    );

    my ($response, %headers);
    my $retries = 0;
    while ( $retries++ < 5 ) {
        $response = $http->mirror( $uri, $path, {headers => \%headers} );
        if ( $response->{status} eq '401' ) {
            last unless $self->_get_auth_params( $response, 'non_proxy' );
        }
        elsif ( $response->{status} eq '407' ) {
            last unless $self->_get_auth_params( $response, 'proxy' );
        }
        else {
            last; # either success or failure
        }
        my %headers = (
            $self->_auth_headers( $uri, 'non_proxy' ),
            ( $want_proxy ? $self->_auth_headers($uri, 'proxy') : () ),
        );
    }

    return $response;
}

sub _want_proxy {
    my ($self, $uri) = @_;
    return unless $self->{proxy};
    my($host) = $uri =~ m|://([^/:]+)|;
    return ! grep { $host =~ /\Q$_\E$/ } @{ $self->{no_proxy} || [] };
}

# Generates the authentication headers for a given mode
# C<mode> is 'proxy' or 'non_proxy'
# C<_${mode}_type> is 'basic' or 'digest'
# C<_${mode}_params> will be the challenge parameters from the 401/407 headers
sub _auth_headers {
    my ($self, $uri, $mode) = @_;
    # Get names for our mode-specific attributes
    my ($type_key, $param_key) = map {"_" . $mode . $_} qw/_type _params/;

    # If _prepare_auth has not been called, we can't prepare headers
    return unless $self->{$type_key};

    # Get user credentials for mode
    my $cred_method = "get_" . ($mode ? "proxy" : "non_proxy") ."_credentials";
    my ($user, $pass) = CPAN::HTTP::Credentials->$cred_method;

    # Generate the header for the mode & type
    my $header = $mode eq 'proxy' ? 'Proxy-Authorization' : 'Authorization';
    my $value_method = "_" . $self->{$type_key} . "_auth";
    my $value = $self->$value_method($user, $pass, $self->{$param_key}, $uri);

    # If we didn't get a value, we didn't have the right modules available
    return $value ? ( $header, $value ) : ();
}

# Extract authentication parameters from headers, but clear any prior
# credentials if we failed (so we might prompt user for password again)
sub _get_auth_params {
    my ($self, $response, $mode) = @_;
    my $prefix = $mode eq 'proxy' ? 'Proxy' : 'WWW';
    my ($type_key, $param_key) = map {"_" . $mode . $_} qw/_type _params/;
    if ( ! $response->{success} ) { # auth failed
        my $method = "clear_${mode}_credentials";
        CPAN::HTTP::Credentials->$method;
        delete $self->{$_} for $type_key, $param_key;
    }
    ($self->{$type_key}, $self->{$param_key}) =
        $self->_get_challenge( $response, "${prefix}-Authenticate");
    return $self->{$type_key};
}

# Extract challenge type and parameters for a challenge list
sub _get_challenge {
    my ($self, $response, $auth_header) = @_;

    my $auth_list = $response->{headers}(lc $auth_header);
    return unless defined $auth_list;
    $auth_list = [$auth_list] unless ref $auth_list;

    for my $challenge (@$auth_list) {
        $challenge =~ tr/,/;/;  # "," is used to separate auth-params!!
        ($challenge) = $self->split_header_words($challenge);
        my $scheme = shift(@$challenge);
        shift(@$challenge); # no value
        $challenge = { @$challenge };  # make rest into a hash

        unless ($scheme =~ /^(basic|digest)$/) {
            next; # bad scheme
        }
        $scheme = $1;  # untainted now

        return ($scheme, $challenge);
    }
    return;
}

# Generate a basic authentication header value
sub _basic_auth {
    my ($self, $user, $pass) = @_;
    unless ( $CPAN::META->has_usable('MIME::Base64') ) {
        $CPAN::Frontend->mywarn(
            "MIME::Base64 is required for 'Basic' style authentication"
        );
        return;
    }
    return "Basic " . MIME::Base64::encode_base64("$user\:$pass", q{});
}

# Generate a digest authentication header value
sub _digest_auth {
    my ($self, $user, $pass, $auth_param, $uri) = @_;
    unless ( $CPAN::META->has_usable('Digest::MD5') ) {
        $CPAN::Frontend->mywarn(
            "Digest::MD5 is required for 'Digest' style authentication"
        );
        return;
    }

    my $nc = sprintf "%08X", ++$self->{_nonce_count}{$auth_param->{nonce}};
    my $cnonce = sprintf "%8x", time;

    my ($path) = $uri =~ m{^\w+?://[^/]+(/.*)$};
    $path = "/" unless defined $path;

    my $md5 = Digest::MD5->new;

    my(@digest);
    $md5->add(join(":", $user, $auth_param->{realm}, $pass));
    push(@digest, $md5->hexdigest);
    $md5->reset;

    push(@digest, $auth_param->{nonce});

    if ($auth_param->{qop}) {
        push(@digest, $nc, $cnonce, ($auth_param->{qop} =~ m|^auth[,;]auth-int$|) ? 'auth' : $auth_param->{qop});
    }

    $md5->add(join(":", 'GET', $path));
    push(@digest, $md5->hexdigest);
    $md5->reset;

    $md5->add(join(":", @digest));
    my($digest) = $md5->hexdigest;
    $md5->reset;

    my %resp = map { $_ => $auth_param->{$_} } qw(realm nonce opaque);
    @resp{qw(username uri response algorithm)} = ($user, $path, $digest, "MD5");

    if (($auth_param->{qop} || "") =~ m|^auth([,;]auth-int)?$|) {
        @resp{qw(qop cnonce nc)} = ("auth", $cnonce, $nc);
    }

    my(@order) =
        qw(username realm qop algorithm uri nonce nc cnonce response opaque);
    my @pairs;
    for (@order) {
        next unless defined $resp{$_};
        push(@pairs, "$_=" . qq("$resp{$_}"));
    }

    my $auth_value  = "Digest " . join(", ", @pairs);
    return $auth_value;
}

# split_header_words adapted from HTTP::Headers::Util
sub split_header_words {
    my ($self, @words) = @_;
    my @res = $self->_split_header_words(@words);
    for my $arr (@res) {
        for (my $i = @$arr - 2; $i >= 0; $i -= 2) {
            $arr->[$i] = lc($arr->[$i]);
        }
    }
    return @res;
}

sub _split_header_words {
    my($self, @val) = @_;
    my @res;
    for (@val) {
        my @cur;
        while (length) {
            if (s/^\s*(=*[^\s=;,]+)//) {  # 'token' or parameter 'attribute'
                push(@cur, $1);
                # a quoted value
                if (s/^\s*=\s*\"([^\"\\]*(?:\\.[^\"\\]*)*)\"//) {
                    my $val = $1;
                    $val =~ s/\\(.)/$1/g;
                    push(@cur, $val);
                    # some unquoted value
                }
                elsif (s/^\s*=\s*([^;,\s]*)//) {
                    my $val = $1;
                    $val =~ s/\s+$//;
                    push(@cur, $val);
                    # no value, a lone token
                }
                else {
                    push(@cur, undef);
                }
            }
            elsif (s/^\s*,//) {
                push(@res, [@cur]) if @cur;
                @cur = ();
            }
            elsif (s/^\s*;// || s/^\s+//) {
                # continue
            }
            else {
                die "This should not happen: '$_'";
            }
        }
        push(@res, \@cur) if @cur;
    }
    @res;
}

1;
PK7N%[3�y�I
I
perl5/CPAN/HTTP/Credentials.pmnu��6�$# -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*-
# vim: ts=4 sts=4 sw=4:
package CPAN::HTTP::Credentials;
use strict;
use vars qw($USER $PASSWORD $PROXY_USER $PROXY_PASSWORD);

$CPAN::HTTP::Credentials::VERSION = $CPAN::HTTP::Credentials::VERSION = "1.9601";

sub clear_credentials {
   clear_non_proxy_credentials();
   clear_proxy_credentials();
}

sub clear_non_proxy_credentials {
    undef $USER;
    undef $PASSWORD;
}

sub clear_proxy_credentials {
    undef $PROXY_USER;
    undef $PROXY_PASSWORD;
}

sub get_proxy_credentials {
    my $self = shift;
    if ($PROXY_USER && $PROXY_PASSWORD) {
        return ($PROXY_USER, $PROXY_PASSWORD);
    }
    if ( defined $CPAN::Config->{proxy_user}
            && $CPAN::Config->{proxy_user}
    ) {
        $PROXY_USER = $CPAN::Config->{proxy_user};
        $PROXY_PASSWORD = $CPAN::Config->{proxy_pass} || "";
        return ($PROXY_USER, $PROXY_PASSWORD);
    }
    my $username_prompt = "\nProxy authentication needed!
 (Note: to permanently configure username and password run
   o conf proxy_user your_username
   o conf proxy_pass your_password
     )\nUsername:";
    ($PROXY_USER, $PROXY_PASSWORD) =
        _get_username_and_password_from_user($username_prompt);
    return ($PROXY_USER,$PROXY_PASSWORD);
}

sub get_non_proxy_credentials {
    my $self = shift;
    if ($USER && $PASSWORD) {
        return ($USER, $PASSWORD);
    }
    if ( defined $CPAN::Config->{username} ) {
        $USER = $CPAN::Config->{username};
        $PASSWORD = $CPAN::Config->{password} || "";
        return ($USER, $PASSWORD);
    }
    my $username_prompt = "\nAuthentication needed!
     (Note: to permanently configure username and password run
       o conf username your_username
       o conf password your_password
     )\nUsername:";

    ($USER, $PASSWORD) =
        _get_username_and_password_from_user($username_prompt);
    return ($USER,$PASSWORD);
}

sub _get_username_and_password_from_user {
    my $username_message = shift;
    my ($username,$password);

    ExtUtils::MakeMaker->import(qw(prompt));
    $username = prompt($username_message);
        if ($CPAN::META->has_inst("Term::ReadKey")) {
            Term::ReadKey::ReadMode("noecho");
        }
    else {
        $CPAN::Frontend->mywarn(
            "Warning: Term::ReadKey seems not to be available, your password will be echoed to the terminal!\n"
        );
    }
    $password = prompt("Password:");

        if ($CPAN::META->has_inst("Term::ReadKey")) {
            Term::ReadKey::ReadMode("restore");
        }
        $CPAN::Frontend->myprint("\n\n");
    return ($username,$password);
}

1;

PK7N%[ך�9LLperl5/CPAN/URL.pmnu��6�$# -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*-
# vim: ts=4 sts=4 sw=4:
package CPAN::URL;
use overload '""' => "as_string", fallback => 1;
# accessors: TEXT(the url string), FROM(DEF=>defaultlist,USER=>urllist),
# planned are things like age or quality

use vars qw(
            $VERSION
);
$VERSION = "5.5";

sub new {
    my($class,%args) = @_;
    bless {
           %args
          }, $class;
}
sub as_string {
    my($self) = @_;
    $self->text;
}
sub text {
    my($self,$set) = @_;
    if (defined $set) {
        $self->{TEXT} = $set;
    }
    $self->{TEXT};
}

1;
PK7N%[4A��'�'perl5/CPAN/Bundle.pmnu��6�$# -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*-
# vim: ts=4 sts=4 sw=4:
package CPAN::Bundle;
use strict;
use CPAN::Module;
@CPAN::Bundle::ISA = qw(CPAN::Module);

use vars qw(
            $VERSION
);
$VERSION = "5.5005";

sub look {
    my $self = shift;
    $CPAN::Frontend->myprint($self->as_string);
}

#-> CPAN::Bundle::undelay
sub undelay {
    my $self = shift;
    delete $self->{later};
    for my $c ( $self->contains ) {
        my $obj = CPAN::Shell->expandany($c) or next;
        if ($obj->id eq $self->id){
            my $id = $obj->id;
            $CPAN::Frontend->mywarn("$id seems to contain itself, skipping\n");
            next;
        }
        $obj->undelay;
    }
}

# mark as dirty/clean
#-> sub CPAN::Bundle::color_cmd_tmps ;
sub color_cmd_tmps {
    my($self) = shift;
    my($depth) = shift || 0;
    my($color) = shift || 0;
    my($ancestors) = shift || [];
    # a module needs to recurse to its cpan_file, a distribution needs
    # to recurse into its prereq_pms, a bundle needs to recurse into its modules

    return if exists $self->{incommandcolor}
        && $color==1
        && $self->{incommandcolor}==$color;
    if ($depth>=$CPAN::MAX_RECURSION) {
        my $e = CPAN::Exception::RecursiveDependency->new($ancestors);
        if ($e->is_resolvable) {
            return $self->{incommandcolor}=2;
        } else {
            die $e;
        }
    }
    # warn "color_cmd_tmps $depth $color " . $self->id; # sleep 1;

    for my $c ( $self->contains ) {
        my $obj = CPAN::Shell->expandany($c) or next;
        CPAN->debug("c[$c]obj[$obj]") if $CPAN::DEBUG;
        $obj->color_cmd_tmps($depth+1,$color,[@$ancestors, $self->id]);
    }
    # never reached code?
    #if ($color==0) {
      #delete $self->{badtestcnt};
    #}
    $self->{incommandcolor} = $color;
}

#-> sub CPAN::Bundle::as_string ;
sub as_string {
    my($self) = @_;
    $self->contains;
    # following line must be "=", not "||=" because we have a moving target
    $self->{INST_VERSION} = $self->inst_version;
    return $self->SUPER::as_string;
}

#-> sub CPAN::Bundle::contains ;
sub contains {
    my($self) = @_;
    my($inst_file) = $self->inst_file || "";
    my($id) = $self->id;
    $self->debug("inst_file[$inst_file]id[$id]") if $CPAN::DEBUG;
    if ($inst_file && CPAN::Version->vlt($self->inst_version,$self->cpan_version)) {
        undef $inst_file;
    }
    unless ($inst_file) {
        # Try to get at it in the cpan directory
        $self->debug("no inst_file") if $CPAN::DEBUG;
        my $cpan_file;
        $CPAN::Frontend->mydie("I don't know a bundle with ID '$id'\n") unless
              $cpan_file = $self->cpan_file;
        if ($cpan_file eq "N/A") {
            $CPAN::Frontend->mywarn("Bundle '$id' not found on disk and not on CPAN. Maybe stale symlink? Maybe removed during session?\n");
            return;
        }
        my $dist = $CPAN::META->instance('CPAN::Distribution',
                                         $self->cpan_file);
        $self->debug("before get id[$dist->{ID}]") if $CPAN::DEBUG;
        $dist->get;
        $self->debug("after get id[$dist->{ID}]") if $CPAN::DEBUG;
        my($todir) = $CPAN::Config->{'cpan_home'};
        my(@me,$from,$to,$me);
        @me = split /::/, $self->id;
        $me[-1] .= ".pm";
        $me = File::Spec->catfile(@me);
        my $build_dir;
        unless ($build_dir = $dist->{build_dir}) {
            $CPAN::Frontend->mywarn("Warning: cannot determine bundle content without a build_dir.\n");
            return;
        }
        $from = $self->find_bundle_file($build_dir,join('/',@me));
        $to = File::Spec->catfile($todir,$me);
        File::Path::mkpath(File::Basename::dirname($to));
        File::Copy::copy($from, $to)
              or Carp::confess("Couldn't copy $from to $to: $!");
        $inst_file = $to;
    }
    my @result;
    my $fh = FileHandle->new;
    local $/ = "\n";
    open($fh,$inst_file) or die "Could not open '$inst_file': $!";
    my $in_cont = 0;
    $self->debug("inst_file[$inst_file]") if $CPAN::DEBUG;
    while (<$fh>) {
        $in_cont = m/^=(?!head1\s+(?i-xsm:CONTENTS))/ ? 0 :
            m/^=head1\s+(?i-xsm:CONTENTS)/ ? 1 : $in_cont;
        next unless $in_cont;
        next if /^=/;
        s/\#.*//;
        next if /^\s+$/;
        chomp;
        push @result, (split " ", $_, 2)[0];
    }
    close $fh;
    delete $self->{STATUS};
    $self->{CONTAINS} = \@result;
    $self->debug("CONTAINS[@result]") if $CPAN::DEBUG;
    unless (@result) {
        $CPAN::Frontend->mywarn(qq{
The bundle file "$inst_file" may be a broken
bundlefile. It seems not to contain any bundle definition.
Please check the file and if it is bogus, please delete it.
Sorry for the inconvenience.
});
    }
    @result;
}

#-> sub CPAN::Bundle::find_bundle_file
# $where is in local format, $what is in unix format
sub find_bundle_file {
    my($self,$where,$what) = @_;
    $self->debug("where[$where]what[$what]") if $CPAN::DEBUG;
### The following two lines let CPAN.pm become Bundle/CPAN.pm :-(
###    my $bu = File::Spec->catfile($where,$what);
###    return $bu if -f $bu;
    my $manifest = File::Spec->catfile($where,"MANIFEST");
    unless (-f $manifest) {
        require ExtUtils::Manifest;
        my $cwd = CPAN::anycwd();
        $self->safe_chdir($where);
        ExtUtils::Manifest::mkmanifest();
        $self->safe_chdir($cwd);
    }
    my $fh = FileHandle->new($manifest)
        or Carp::croak("Couldn't open $manifest: $!");
    local($/) = "\n";
    my $bundle_filename = $what;
    $bundle_filename =~ s|Bundle.*/||;
    my $bundle_unixpath;
    while (<$fh>) {
        next if /^\s*\#/;
        my($file) = /(\S+)/;
        if ($file =~ m|\Q$what\E$|) {
            $bundle_unixpath = $file;
            # return File::Spec->catfile($where,$bundle_unixpath); # bad
            last;
        }
        # retry if she managed to have no Bundle directory
        $bundle_unixpath = $file if $file =~ m|\Q$bundle_filename\E$|;
    }
    return File::Spec->catfile($where, split /\//, $bundle_unixpath)
        if $bundle_unixpath;
    Carp::croak("Couldn't find a Bundle file in $where");
}

# needs to work quite differently from Module::inst_file because of
# cpan_home/Bundle/ directory and the possibility that we have
# shadowing effect. As it makes no sense to take the first in @INC for
# Bundles, we parse them all for $VERSION and take the newest.

#-> sub CPAN::Bundle::inst_file ;
sub inst_file {
    my($self) = @_;
    my($inst_file);
    my(@me);
    @me = split /::/, $self->id;
    $me[-1] .= ".pm";
    my($incdir,$bestv);
    foreach $incdir ($CPAN::Config->{'cpan_home'},@INC) {
        my $parsefile = File::Spec->catfile($incdir, @me);
        CPAN->debug("parsefile[$parsefile]") if $CPAN::DEBUG;
        next unless -f $parsefile;
        my $have = eval { MM->parse_version($parsefile); };
        if ($@) {
            $CPAN::Frontend->mywarn("Error while parsing version number in file '$parsefile'\n");
        }
        if (!$bestv || CPAN::Version->vgt($have,$bestv)) {
            $self->{INST_FILE} = $parsefile;
            $self->{INST_VERSION} = $bestv = $have;
        }
    }
    $self->{INST_FILE};
}

#-> sub CPAN::Bundle::inst_version ;
sub inst_version {
    my($self) = @_;
    $self->inst_file; # finds INST_VERSION as side effect
    $self->{INST_VERSION};
}

#-> sub CPAN::Bundle::rematein ;
sub rematein {
    my($self,$meth) = @_;
    $self->debug("self[$self] meth[$meth]") if $CPAN::DEBUG;
    my($id) = $self->id;
    Carp::croak( "Can't $meth $id, don't have an associated bundle file. :-(\n" )
        unless $self->inst_file || $self->cpan_file;
    my($s,%fail);
    for $s ($self->contains) {
        my($type) = $s =~ m|/| ? 'CPAN::Distribution' :
            $s =~ m|^Bundle::| ? 'CPAN::Bundle' : 'CPAN::Module';
        if ($type eq 'CPAN::Distribution') {
            $CPAN::Frontend->mywarn(qq{
The Bundle }.$self->id.qq{ contains
explicitly a file '$s'.
Going to $meth that.
});
            $CPAN::Frontend->mysleep(5);
        }
        # possibly noisy action:
        $self->debug("type[$type] s[$s]") if $CPAN::DEBUG;
        my $obj = $CPAN::META->instance($type,$s);
        $obj->{reqtype} = $self->{reqtype};
        $obj->{viabundle} ||= { id => $id, reqtype => $self->{reqtype}, optional => !$self->{mandatory}};
        # $obj->$meth();
        # XXX should optional be based on whether bundle was optional? -- xdg, 2012-04-01
        # A: Sure, what could demand otherwise? --andk, 2013-11-25
        CPAN::Queue->queue_item(qmod => $obj->id, reqtype => $self->{reqtype}, optional => !$self->{mandatory});
    }
}

# If a bundle contains another that contains an xs_file we have here,
# we just don't bother I suppose
#-> sub CPAN::Bundle::xs_file
sub xs_file {
    return 0;
}

#-> sub CPAN::Bundle::force ;
sub fforce   { shift->rematein('fforce',@_); }
#-> sub CPAN::Bundle::force ;
sub force   { shift->rematein('force',@_); }
#-> sub CPAN::Bundle::notest ;
sub notest  { shift->rematein('notest',@_); }
#-> sub CPAN::Bundle::get ;
sub get     { shift->rematein('get',@_); }
#-> sub CPAN::Bundle::make ;
sub make    { shift->rematein('make',@_); }
#-> sub CPAN::Bundle::test ;
sub test    {
    my $self = shift;
    # $self->{badtestcnt} ||= 0;
    $self->rematein('test',@_);
}
#-> sub CPAN::Bundle::install ;
sub install {
  my $self = shift;
  $self->rematein('install',@_);
}
#-> sub CPAN::Bundle::clean ;
sub clean   { shift->rematein('clean',@_); }

#-> sub CPAN::Bundle::uptodate ;
sub uptodate {
    my($self) = @_;
    return 0 unless $self->SUPER::uptodate; # we must have the current Bundle def
    my $c;
    foreach $c ($self->contains) {
        my $obj = CPAN::Shell->expandany($c);
        return 0 unless $obj->uptodate;
    }
    return 1;
}

#-> sub CPAN::Bundle::readme ;
sub readme  {
    my($self) = @_;
    my($file) = $self->cpan_file or $CPAN::Frontend->myprint(qq{
No File found for bundle } . $self->id . qq{\n}), return;
    $self->debug("self[$self] file[$file]") if $CPAN::DEBUG;
    $CPAN::META->instance('CPAN::Distribution',$file)->readme;
}

1;
PK7N%[�<����!perl5/CPAN/Kwalify/distroprefs.ddnu��6�$$VAR1 = {
  "mapping" => {
    "comment" => {
      "type" => "text"
    },
    "cpanconfig" => {
      "mapping" => {
        "=" => {
          "type" => "text"
        }
      },
      "type" => "map"
    },
    "depends" => {
      "mapping" => {
        "build_requires" => {
          "mapping" => {
            "=" => {
              "type" => "text"
            }
          },
          "type" => "map"
        },
        "configure_requires" => {},
        "requires" => {}
      },
      "type" => "map"
    },
    "disabled" => {
      "enum" => [
        0,
        1
      ],
      "type" => "int"
    },
    "features" => {
      "sequence" => [
        {
          "type" => "text"
        }
      ],
      "type" => "seq"
    },
    "goto" => {
      "type" => "text"
    },
    "install" => {
      "mapping" => {
        "args" => {
          "sequence" => [
            {
              "type" => "text"
            }
          ],
          "type" => "seq"
        },
        "commandline" => {
          "type" => "text"
        },
        "eexpect" => {
          "mapping" => {
            "mode" => {
              "enum" => [
                "deterministic",
                "anyorder"
              ],
              "type" => "text"
            },
            "reuse" => {
              "type" => "int"
            },
            "talk" => {
              "sequence" => [
                {
                  "type" => "text"
                }
              ],
              "type" => "seq"
            },
            "timeout" => {
              "type" => "number"
            }
          },
          "type" => "map"
        },
        "env" => {
          "mapping" => {
            "=" => {
              "type" => "text"
            }
          },
          "type" => "map"
        },
        "expect" => {
          "sequence" => [
            {
              "type" => "text"
            }
          ],
          "type" => "seq"
        }
      },
      "type" => "map"
    },
    "make" => {},
    "match" => {
      "mapping" => {
        "distribution" => {
          "type" => "text"
        },
        "env" => {
          "mapping" => {
            "=" => {
              "type" => "text"
            }
          },
          "type" => "map"
        },
        "module" => {
          "type" => "text"
        },
        "perl" => {
          "type" => "text"
        },
        "perlconfig" => {}
      },
      "type" => "map"
    },
    "patches" => {
      "sequence" => [
        {
          "type" => "text"
        }
      ],
      "type" => "seq"
    },
    "pl" => {},
    "reminder" => {
      "type" => "text"
    },
    "test" => {}
  },
  "type" => "map"
};
$VAR1->{"mapping"}{"depends"}{"mapping"}{"configure_requires"} = $VAR1->{"mapping"}{"depends"}{"mapping"}{"build_requires"};
$VAR1->{"mapping"}{"depends"}{"mapping"}{"requires"} = $VAR1->{"mapping"}{"depends"}{"mapping"}{"build_requires"};
$VAR1->{"mapping"}{"make"} = $VAR1->{"mapping"}{"install"};
$VAR1->{"mapping"}{"match"}{"mapping"}{"perlconfig"} = $VAR1->{"mapping"}{"match"}{"mapping"}{"env"};
$VAR1->{"mapping"}{"pl"} = $VAR1->{"mapping"}{"install"};
$VAR1->{"mapping"}{"test"} = $VAR1->{"mapping"}{"install"};
PK7N%[w)#99"perl5/CPAN/Kwalify/distroprefs.ymlnu��6�$--- 
type: map
mapping:
  comment:
    type: text
  depends:
    type: map
    mapping:
      configure_requires:
        &requires_common
        type: map
        mapping:
          =:
            type: text
      build_requires: *requires_common
      requires:       *requires_common
  match:
    type: map
    mapping:
      distribution:
        type: text
      module:
        type: text
      perl:
        type: text
      perlconfig:
        &matchhash_common
        type: map
        mapping:
          =:
            type: text
      env: *matchhash_common
  install:
    &args_env_expect
    type: map
    mapping:
      args:
        type: seq
        sequence:
          - type: text
      commandline:
        type: text
      env:
        type: map
        mapping:
          =:
            type: text
      expect:
        type: seq
        sequence:
          - type: text
      eexpect:
        type: map
        mapping:
          mode:
            type: text
            enum:
              - deterministic
              - anyorder
          timeout:
            type: number
          reuse:
            type: int
          talk:
            type: seq
            sequence:
              - type: text
  make: *args_env_expect
  pl:   *args_env_expect
  test: *args_env_expect
  patches:
    type: seq
    sequence:
      - type: text
  disabled:
    type: int
    enum:
      - 0
      - 1
  goto:
    type: text
  cpanconfig:
    type: map
    mapping:
      =:
        type: text
  features:
    type: seq
    sequence:
      - type: text
  reminder:
    type: text
PK7N%[ٷ��^�^perl5/CPAN/HandleConfig.pmnu��6�$package CPAN::HandleConfig;
use strict;
use vars qw(%can %keys $loading $VERSION);
use File::Path ();
use File::Spec ();
use File::Basename ();
use Carp ();

=head1 NAME

CPAN::HandleConfig - internal configuration handling for CPAN.pm

=cut 

$VERSION = "5.5013"; # see also CPAN::Config::VERSION at end of file

%can = (
        commit   => "Commit changes to disk",
        defaults => "Reload defaults from disk",
        help     => "Short help about 'o conf' usage",
        init     => "Interactive setting of all options",
);

# Q: where is the "How do I add a new config option" HOWTO?
# A1: svn diff -r 757:758 # where dagolden added test_report [git e997b71de88f1019a1472fc13cb97b1b7f96610f]
# A2: svn diff -r 985:986 # where andk added yaml_module [git 312b6d9b12b1bdec0b6e282d853482145475021f]
# A3: 1. add new config option to %keys below
#     2. add a Pod description in CPAN::FirstTime in the DESCRIPTION
#        section; it should include a prompt line; see others for
#        examples
#     3. add a "matcher" section in CPAN::FirstTime::init that includes
#        a prompt function; see others for examples
#     4. add config option to documentation section in CPAN.pm

%keys = map { $_ => undef }
    (
     "allow_installing_module_downgrades",
     "allow_installing_outdated_dists",
     "applypatch",
     "auto_commit",
     "build_cache",
     "build_dir",
     "build_dir_reuse",
     "build_requires_install_policy",
     "bzip2",
     "cache_metadata",
     "check_sigs",
     "cleanup_after_install",
     "colorize_debug",
     "colorize_output",
     "colorize_print",
     "colorize_warn",
     "commandnumber_in_prompt",
     "commands_quote",
     "connect_to_internet_ok",
     "cpan_home",
     "curl",
     "dontload_hash", # deprecated after 1.83_68 (rev. 581)
     "dontload_list",
     "ftp",
     "ftp_passive",
     "ftp_proxy",
     "ftpstats_size",
     "ftpstats_period",
     "getcwd",
     "gpg",
     "gzip",
     "halt_on_failure",
     "histfile",
     "histsize",
     "http_proxy",
     "inactivity_timeout",
     "index_expire",
     "inhibit_startup_message",
     "keep_source_where",
     "load_module_verbosity",
     "lynx",
     "make",
     "make_arg",
     "make_install_arg",
     "make_install_make_command",
     "makepl_arg",
     "mbuild_arg",
     "mbuild_install_arg",
     "mbuild_install_build_command",
     "mbuildpl_arg",
     "ncftp",
     "ncftpget",
     "no_proxy",
     "pager",
     "password",
     "patch",
     "patches_dir",
     "perl5lib_verbosity",
     "plugin_list",
     "prefer_external_tar",
     "prefer_installer",
     "prefs_dir",
     "prerequisites_policy",
     "proxy_pass",
     "proxy_user",
     "pushy_https",
     "randomize_urllist",
     "recommends_policy",
     "scan_cache",
     "shell",
     "show_unparsable_versions",
     "show_upload_date",
     "show_zero_versions",
     "suggests_policy",
     "tar",
     "tar_verbosity",
     "term_is_latin",
     "term_ornaments",
     "test_report",
     "trust_test_report_history",
     "unzip",
     "urllist",
     "urllist_ping_verbose",
     "urllist_ping_external",
     "use_prompt_default",
     "use_sqlite",
     "username",
     "version_timeout",
     "wait_list",
     "wget",
     "yaml_load_code",
     "yaml_module",
    );

my %prefssupport = map { $_ => 1 }
    (
     "allow_installing_module_downgrades",
     "allow_installing_outdated_dists",
     "build_requires_install_policy",
     "check_sigs",
     "make",
     "make_install_make_command",
     "prefer_installer",
     "test_report",
    );

# returns true on successful action
sub edit {
    my($self,@args) = @_;
    return unless @args;
    CPAN->debug("self[$self]args[".join(" | ",@args)."]");
    my($o,$str,$func,$args,$key_exists);
    $o = shift @args;
    if($can{$o}) {
        my $success = $self->$o(args => \@args); # o conf init => sub init => sub load
        unless ($success) {
            die "Panic: could not configure CPAN.pm for args [@args]. Giving up.";
        }
    } else {
        CPAN->debug("o[$o]") if $CPAN::DEBUG;
        unless (exists $keys{$o}) {
            $CPAN::Frontend->mywarn("Warning: unknown configuration variable '$o'\n");
        }
        require_myconfig_or_config();
        my $changed;

        # one day I used randomize_urllist for a boolean, so we must
        # list them explicitly --ak
        if (0) {
        } elsif ($o =~ /^(wait_list|urllist|dontload_list|plugin_list)$/) {

            #
            # ARRAYS
            #

            $func = shift @args;
            $func ||= "";
            CPAN->debug("func[$func]args[@args]") if $CPAN::DEBUG;
            # Let's avoid eval, it's easier to comprehend without.
            if ($func eq "push") {
                push @{$CPAN::Config->{$o}}, @args;
                $changed = 1;
            } elsif ($func eq "pop") {
                pop @{$CPAN::Config->{$o}};
                $changed = 1;
            } elsif ($func eq "shift") {
                shift @{$CPAN::Config->{$o}};
                $changed = 1;
            } elsif ($func eq "unshift") {
                unshift @{$CPAN::Config->{$o}}, @args;
                $changed = 1;
            } elsif ($func eq "splice") {
                my $offset = shift @args || 0;
                my $length = shift @args || 0;
                splice @{$CPAN::Config->{$o}}, $offset, $length, @args; # may warn
                $changed = 1;
            } elsif ($func) {
                $CPAN::Config->{$o} = [$func, @args];
                $changed = 1;
            } else {
                $self->prettyprint($o);
            }
            if ($changed) {
                if ($o eq "urllist") {
                    # reset the cached values
                    undef $CPAN::FTP::Thesite;
                    undef $CPAN::FTP::Themethod;
                    $CPAN::Index::LAST_TIME = 0;
                } elsif ($o eq "dontload_list") {
                    # empty it, it will be built up again
                    $CPAN::META->{dontload_hash} = {};
                }
            }
        } elsif ($o =~ /_hash$/) {

            #
            # HASHES
            #

            if (@args==1 && $args[0] eq "") {
                @args = ();
            } elsif (@args % 2) {
                push @args, "";
            }
            $CPAN::Config->{$o} = { @args };
            $changed = 1;
        } else {

            #
            # SCALARS
            #

            if (defined $args[0]) {
                $CPAN::CONFIG_DIRTY = 1;
                $CPAN::Config->{$o} = $args[0];
                $changed = 1;
            }
            $self->prettyprint($o)
                if exists $keys{$o} or defined $CPAN::Config->{$o};
        }
        if ($changed) {
            if ($CPAN::Config->{auto_commit}) {
                $self->commit;
            } else {
                $CPAN::CONFIG_DIRTY = 1;
                $CPAN::Frontend->myprint("Please use 'o conf commit' to ".
                                         "make the config permanent!\n\n");
            }
        }
    }
}

sub prettyprint {
    my($self,$k) = @_;
    my $v = $CPAN::Config->{$k};
    if (ref $v) {
        my(@report);
        if (ref $v eq "ARRAY") {
            @report = map {"\t$_ \[$v->[$_]]\n"} 0..$#$v;
        } else {
            @report = map
                {
                    sprintf "\t%-18s => %s\n",
                               "[$_]",
                                        defined $v->{$_} ? "[$v->{$_}]" : "undef"
                } sort keys %$v;
        }
        $CPAN::Frontend->myprint(
                                 join(
                                      "",
                                      sprintf(
                                              "    %-18s\n",
                                              $k
                                             ),
                                      @report
                                     )
                                );
    } elsif (defined $v) {
        $CPAN::Frontend->myprint(sprintf "    %-18s [%s]\n", $k, $v);
    } else {
        $CPAN::Frontend->myprint(sprintf "    %-18s undef\n", $k);
    }
}

# generally, this should be called without arguments so that the currently
# loaded config file is where changes are committed.
sub commit {
    my($self,@args) = @_;
    CPAN->debug("args[@args]") if $CPAN::DEBUG;
    if ($CPAN::RUN_DEGRADED) {
        $CPAN::Frontend->mydie(
            "'o conf commit' disabled in ".
            "degraded mode. Maybe try\n".
            " !undef \$CPAN::RUN_DEGRADED\n"
        );
    }
    my ($configpm, $must_reload);

    # XXX does anything do this? can it be simplified? -- dagolden, 2011-01-19
    if (@args) {
      if ($args[0] eq "args") {
        # we have not signed that contract
      } else {
        $configpm = $args[0];
      }
    }

    # use provided name or the current config or create a new MyConfig
    $configpm ||= require_myconfig_or_config() || make_new_config();

    # commit to MyConfig if we can't write to Config
    if ( ! -w $configpm && $configpm =~ m{CPAN/Config\.pm} ) {
        my $myconfig = _new_config_name();
        $CPAN::Frontend->mywarn(
            "Your $configpm file\n".
            "is not writable. I will attempt to write your configuration to\n" .
            "$myconfig instead.\n\n"
        );
        $configpm = make_new_config();
        $must_reload++; # so it gets loaded as $INC{'CPAN/MyConfig.pm'}
    }

    # XXX why not just "-w $configpm"? -- dagolden, 2011-01-19
    my($mode);
    if (-f $configpm) {
        $mode = (stat $configpm)[2];
        if ($mode && ! -w _) {
            _die_cant_write_config($configpm);
        }
    }

    $self->_write_config_file($configpm);
    require_myconfig_or_config() if $must_reload;

    #$mode = 0444 | ( $mode & 0111 ? 0111 : 0 );
    #chmod $mode, $configpm;
###why was that so?    $self->defaults;
    $CPAN::Frontend->myprint("commit: wrote '$configpm'\n");
    $CPAN::CONFIG_DIRTY = 0;
    1;
}

sub _write_config_file {
    my ($self, $configpm) = @_;
    my $msg;
    $msg = <<EOF if $configpm =~ m{CPAN/Config\.pm};

# This is CPAN.pm's systemwide configuration file. This file provides
# defaults for users, and the values can be changed in a per-user
# configuration file.

EOF
    $msg ||= "\n";
    my($fh) = FileHandle->new;
    rename $configpm, "$configpm~" if -f $configpm;
    open $fh, ">$configpm" or
        $CPAN::Frontend->mydie("Couldn't open >$configpm: $!");
    $fh->print(qq[$msg\$CPAN::Config = \{\n]);
    foreach (sort keys %$CPAN::Config) {
        unless (exists $keys{$_}) {
            # do not drop them: forward compatibility!
            $CPAN::Frontend->mywarn("Unknown config variable '$_'\n");
            next;
        }
        $fh->print(
            "  '$_' => ",
            $self->neatvalue($CPAN::Config->{$_}),
            ",\n"
        );
    }
    $fh->print("};\n1;\n__END__\n");
    close $fh;

    return;
}


# stolen from MakeMaker; not taking the original because it is buggy;
# bugreport will have to say: keys of hashes remain unquoted and can
# produce syntax errors
sub neatvalue {
    my($self, $v) = @_;
    return "undef" unless defined $v;
    my($t) = ref $v;
    unless ($t) {
        $v =~ s/\\/\\\\/g;
        return "q[$v]";
    }
    if ($t eq 'ARRAY') {
        my(@m, @neat);
        push @m, "[";
        foreach my $elem (@$v) {
            push @neat, "q[$elem]";
        }
        push @m, join ", ", @neat;
        push @m, "]";
        return join "", @m;
    }
    return "$v" unless $t eq 'HASH';
    my @m;
    foreach my $key (sort keys %$v) {
        my $val = $v->{$key};
        push(@m,"q[$key]=>".$self->neatvalue($val)) ;
    }
    return "{ ".join(', ',@m)." }";
}

sub defaults {
    my($self) = @_;
    if ($CPAN::RUN_DEGRADED) {
                             $CPAN::Frontend->mydie(
                                                    "'o conf defaults' disabled in ".
                                                    "degraded mode. Maybe try\n".
                                                    " !undef \$CPAN::RUN_DEGRADED\n"
                                                   );
    }
    my $done;
    for my $config (qw(CPAN/MyConfig.pm CPAN/Config.pm)) {
        if ($INC{$config}) {
            CPAN->debug("INC{'$config'}[$INC{$config}]") if $CPAN::DEBUG;
            CPAN::Shell->_reload_this($config,{reloforce => 1});
            $CPAN::Frontend->myprint("'$INC{$config}' reread\n");
            last;
        }
    }
    $CPAN::CONFIG_DIRTY = 0;
    1;
}

=head2 C<< CLASS->safe_quote ITEM >>

Quotes an item to become safe against spaces
in shell interpolation. An item is enclosed
in double quotes if:

  - the item contains spaces in the middle
  - the item does not start with a quote

This happens to avoid shell interpolation
problems when whitespace is present in
directory names.

This method uses C<commands_quote> to determine
the correct quote. If C<commands_quote> is
a space, no quoting will take place.


if it starts and ends with the same quote character: leave it as it is

if it contains no whitespace: leave it as it is

if it contains whitespace, then

if it contains quotes: better leave it as it is

else: quote it with the correct quote type for the box we're on

=cut

{
    # Instead of patching the guess, set commands_quote
    # to the right value
    my ($quotes,$use_quote)
        = $^O eq 'MSWin32'
            ? ('"', '"')
                : (q{"'}, "'")
                    ;

    sub safe_quote {
        my ($self, $command) = @_;
        # Set up quote/default quote
        my $quote = $CPAN::Config->{commands_quote} || $quotes;

        if ($quote ne ' '
            and defined($command )
            and $command =~ /\s/
            and $command !~ /[$quote]/) {
            return qq<$use_quote$command$use_quote>
        }
        return $command;
    }
}

sub init {
    my($self,@args) = @_;
    CPAN->debug("self[$self]args[".join(",",@args)."]");
    $self->load(do_init => 1, @args);
    1;
}

# Loads CPAN::MyConfig or fall-back to CPAN::Config. Will not reload a file
# if already loaded. Returns the path to the file %INC or else the empty string
#
# Note -- if CPAN::Config were loaded and CPAN::MyConfig subsequently
# created, calling this again will leave *both* in %INC

sub require_myconfig_or_config () {
    if (   $INC{"CPAN/MyConfig.pm"} || _try_loading("CPAN::MyConfig", cpan_home())) {
        return $INC{"CPAN/MyConfig.pm"};
    }
    elsif ( $INC{"CPAN/Config.pm"} || _try_loading("CPAN::Config") ) {
        return $INC{"CPAN/Config.pm"};
    }
    else {
        return q{};
    }
}

# Load a module, but ignore "can't locate..." errors
# Optionally take a list of directories to add to @INC for the load
sub _try_loading {
    my ($module, @dirs) = @_;
    (my $file = $module) =~ s{::}{/}g;
    $file .= ".pm";

    local @INC = @INC;
    for my $dir ( @dirs ) {
        if ( -f File::Spec->catfile($dir, $file) ) {
            unshift @INC, $dir;
            last;
        }
    }

    eval { require $file };
    my $err_myconfig = $@;
    if ($err_myconfig and $err_myconfig !~ m#locate \Q$file\E#) {
        die "Error while requiring ${module}:\n$err_myconfig";
    }
    return $INC{$file};
}

# prioritized list of possible places for finding "CPAN/MyConfig.pm"
sub cpan_home_dir_candidates {
    my @dirs;
    my $old_v = $CPAN::Config->{load_module_verbosity};
    $CPAN::Config->{load_module_verbosity} = q[none];
    if ($CPAN::META->has_usable('File::HomeDir')) {
        if ($^O ne 'darwin') {
            push @dirs, File::HomeDir->my_data;
            # my_data is ~/Library/Application Support on darwin,
            # which causes issues in the toolchain.
        }
        push @dirs, File::HomeDir->my_home;
    }
    # Windows might not have HOME, so check it first
    push @dirs, $ENV{HOME} if $ENV{HOME};
    # Windows might have these instead
    push( @dirs, File::Spec->catpath($ENV{HOMEDRIVE}, $ENV{HOMEPATH}, '') )
      if $ENV{HOMEDRIVE} && $ENV{HOMEPATH};
    push @dirs, $ENV{USERPROFILE} if $ENV{USERPROFILE};

    $CPAN::Config->{load_module_verbosity} = $old_v;
    my $dotcpan = $^O eq 'VMS' ? '_cpan' : '.cpan';
    @dirs = map { File::Spec->catdir($_, $dotcpan) } grep { defined } @dirs;
    return wantarray ? @dirs : $dirs[0];
}

sub load {
    my($self, %args) = @_;
    $CPAN::Be_Silent+=0; # protect against 'used only once'
    $CPAN::Be_Silent++ if $args{be_silent}; # do not use; planned to be removed in 2011
    my $do_init = delete $args{do_init} || 0;
    my $make_myconfig = delete $args{make_myconfig};
    $loading = 0 unless defined $loading;

    my $configpm = require_myconfig_or_config;
    my @miss = $self->missing_config_data;
    CPAN->debug("do_init[$do_init]loading[$loading]miss[@miss]") if $CPAN::DEBUG;
    return unless $do_init || @miss;
    if (@miss==1 and $miss[0] eq "pushy_https" && !$do_init) {
        $CPAN::Frontend->myprint(<<'END');

Starting with version 2.29 of the cpan shell, a new download mechanism
is the default which exclusively uses cpan.org as the host to download
from. The configuration variable pushy_https can be used to (de)select
the new mechanism. Please read more about it and make your choice
between the old and the new mechanism by running

    o conf init pushy_https

Once you have done that and stored the config variable this dialog
will disappear.
END

        return;
    }

    # I'm not how we'd ever wind up in a recursive loop, but I'm leaving
    # this here for safety's sake -- dagolden, 2011-01-19
    return if $loading;
    local $loading = ($loading||0) + 1;

    # Warn if we have a config file, but things were found missing
    if ($configpm && @miss && !$do_init) {
        if ($make_myconfig || ( ! -w $configpm && $configpm =~ m{CPAN/Config\.pm})) {
            $configpm = make_new_config();
            $CPAN::Frontend->myprint(<<END);
The system CPAN configuration file has provided some default values,
but you need to complete the configuration dialog for CPAN.pm.
Configuration will be written to
 <<$configpm>>
END
        }
        else {
            $CPAN::Frontend->myprint(<<END);
Sorry, we have to rerun the configuration dialog for CPAN.pm due to
some missing parameters. Configuration will be written to
 <<$configpm>>

END
        }
    }

    require CPAN::FirstTime;
    return CPAN::FirstTime::init($configpm || make_new_config(), %args);
}

# Creates a new, empty config file at the preferred location
# Any existing will be renamed with a ".bak" suffix if possible
# If the file cannot be created, an exception is thrown
sub make_new_config {
    my $configpm = _new_config_name();
    my $configpmdir = File::Basename::dirname( $configpm );
    File::Path::mkpath($configpmdir) unless -d $configpmdir;

    if ( -w $configpmdir ) {
        #_#_# following code dumped core on me with 5.003_11, a.k.
        if( -f $configpm ) {
            my $configpm_bak = "$configpm.bak";
            unlink $configpm_bak if -f $configpm_bak;
            if( rename $configpm, $configpm_bak ) {
                $CPAN::Frontend->mywarn(<<END);
Old configuration file $configpm
    moved to $configpm_bak
END
            }
        }
        my $fh = FileHandle->new;
        if ($fh->open(">$configpm")) {
            $fh->print("1;\n");
            return $configpm;
        }
    }
    _die_cant_write_config($configpm);
}

sub _die_cant_write_config {
    my ($configpm) = @_;
    $CPAN::Frontend->mydie(<<"END");
WARNING: CPAN.pm is unable to write a configuration file.  You
must be able to create and write to '$configpm'.

Aborting configuration.
END

}

# From candidate directories, we would like (in descending preference order):
#   * the one that contains a MyConfig file
#   * one that exists (even without MyConfig)
#   * the first one on the list
sub cpan_home {
    my @dirs = cpan_home_dir_candidates();
    for my $d (@dirs) {
        return $d if -f "$d/CPAN/MyConfig.pm";
    }
    for my $d (@dirs) {
        return $d if -d $d;
    }
    return $dirs[0];
}

sub _new_config_name {
    return File::Spec->catfile(cpan_home(), 'CPAN', 'MyConfig.pm');
}

# returns mandatory but missing entries in the Config
sub missing_config_data {
    my(@miss);
    for (
         "auto_commit",
         "build_cache",
         "build_dir",
         "cache_metadata",
         "cpan_home",
         "ftp_proxy",
         #"gzip",
         "http_proxy",
         "index_expire",
         #"inhibit_startup_message",
         "keep_source_where",
         #"make",
         "make_arg",
         "make_install_arg",
         "makepl_arg",
         "mbuild_arg",
         "mbuild_install_arg",
         ($^O eq "MSWin32" ? "" : "mbuild_install_build_command"),
         "mbuildpl_arg",
         "no_proxy",
         #"pager",
         "prerequisites_policy",
         "pushy_https",
         "scan_cache",
         #"tar",
         #"unzip",
         "urllist",
        ) {
        next unless exists $keys{$_};
        push @miss, $_ unless defined $CPAN::Config->{$_};
    }
    return @miss;
}

sub help {
    $CPAN::Frontend->myprint(q[
Known options:
  commit    commit session changes to disk
  defaults  reload default config values from disk
  help      this help
  init      enter a dialog to set all or a set of parameters

Edit key values as in the following (the "o" is a literal letter o):
  o conf build_cache 15
  o conf build_dir "/foo/bar"
  o conf urllist shift
  o conf urllist unshift ftp://ftp.foo.bar/
  o conf inhibit_startup_message 1

]);
    1; #don't reprint CPAN::Config
}

sub cpl {
    my($word,$line,$pos) = @_;
    $word ||= "";
    CPAN->debug("word[$word] line[$line] pos[$pos]") if $CPAN::DEBUG;
    my(@words) = split " ", substr($line,0,$pos+1);
    if (
        defined($words[2])
        and
        $words[2] =~ /list$/
        and
        (
        @words == 3
        ||
        @words == 4 && length($word)
        )
       ) {
        return grep /^\Q$word\E/, qw(splice shift unshift pop push);
    } elsif (defined($words[2])
             and
             $words[2] eq "init"
             and
            (
             @words == 3
             ||
             @words >= 4 && length($word)
            )) {
        return sort grep /^\Q$word\E/, keys %keys;
    } elsif (@words >= 4) {
        return ();
    }
    my %seen;
    my(@o_conf) =  sort grep { !$seen{$_}++ }
        keys %can,
            keys %$CPAN::Config,
                keys %keys;
    return grep /^\Q$word\E/, @o_conf;
}

sub prefs_lookup {
    my($self,$distro,$what) = @_;

    if ($prefssupport{$what}) {
        return $CPAN::Config->{$what} unless
            $distro
                and $distro->prefs
                    and $distro->prefs->{cpanconfig}
                        and defined $distro->prefs->{cpanconfig}{$what};
        return $distro->prefs->{cpanconfig}{$what};
    } else {
        $CPAN::Frontend->mywarn("Warning: $what not yet officially ".
                                "supported for distroprefs, doing a normal lookup\n");
        return $CPAN::Config->{$what};
    }
}


{
    package
        CPAN::Config; ####::###### #hide from indexer
    # note: J. Nick Koston wrote me that they are using
    # CPAN::Config->commit although undocumented. I suggested
    # CPAN::Shell->o("conf","commit") even when ugly it is at least
    # documented

    # that's why I added the CPAN::Config class with autoload and
    # deprecated warning

    use strict;
    use vars qw($AUTOLOAD $VERSION);
    $VERSION = "5.5013";

    # formerly CPAN::HandleConfig was known as CPAN::Config
    sub AUTOLOAD { ## no critic
        my $class = shift; # e.g. in dh-make-perl: CPAN::Config
        my($l) = $AUTOLOAD;
        $CPAN::Frontend->mywarn("Dispatching deprecated method '$l' to CPAN::HandleConfig\n");
        $l =~ s/.*:://;
        CPAN::HandleConfig->$l(@_);
    }
}

1;

__END__

=head1 LICENSE

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

=cut

# Local Variables:
# mode: cperl
# cperl-indent-level: 4
# End:
# vim: ts=4 sts=4 sw=4:
PK7N%[�$�d
d
perl5/CPAN/Kwalify.pmnu��6�$=head1 NAME

CPAN::Kwalify - Interface between CPAN.pm and Kwalify.pm

=head1 SYNOPSIS

  use CPAN::Kwalify;
  validate($schema_name, $data, $file, $doc);

=head1 DESCRIPTION

=over

=item _validate($schema_name, $data, $file, $doc)

$schema_name is the name of a supported schema. Currently only
C<distroprefs> is supported. $data is the data to be validated. $file
is the absolute path to the file the data are coming from. $doc is the
index of the document within $doc that is to be validated. The last
two arguments are only there for better error reporting.

Relies on being called from within CPAN.pm.

Dies if something fails. Does not return anything useful.

=item yaml($schema_name)

Returns the YAML text of that schema. Dies if something fails.

=back

=head1 AUTHOR

Andreas Koenig C<< <andk@cpan.org> >>

=head1 LICENSE

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

See L<http://www.perl.com/perl/misc/Artistic.html>



=cut


use strict;

package CPAN::Kwalify;
use vars qw($VERSION $VAR1);
$VERSION = "5.50";

use File::Spec ();

my %vcache = ();

my $schema_loaded = {};

sub _validate {
    my($schema_name,$data,$abs,$y) = @_;
    my $yaml_module = CPAN->_yaml_module;
    if (
        $CPAN::META->has_inst($yaml_module)
        &&
        $CPAN::META->has_inst("Kwalify")
       ) {
        my $load = UNIVERSAL::can($yaml_module,"Load");
        unless ($schema_loaded->{$schema_name}) {
            eval {
                my $schema_yaml = yaml($schema_name);
                $schema_loaded->{$schema_name} = $load->($schema_yaml);
            };
            if ($@) {
                # we know that YAML.pm 0.62 cannot parse the schema,
                # so we try a fallback
                my $content = do {
                    my $path = __FILE__;
                    $path =~ s/\.pm$//;
                    $path = File::Spec->catfile($path, "$schema_name.dd");
                    local *FH;
                    open FH, $path or die "Could not open '$path': $!";
                    local $/;
                    <FH>;
                };
                $VAR1 = undef;
                eval $content;
                if (my $err = $@) {
                    die "parsing of '$schema_name.dd' failed: $err";
                }
                $schema_loaded->{$schema_name} = $VAR1;
            }
        }
    }
    if (my $schema = $schema_loaded->{$schema_name}) {
        my $mtime = (stat $abs)[9];
        for my $k (keys %{$vcache{$abs}}) {
            delete $vcache{$abs}{$k} unless $k eq $mtime;
        }
        return if $vcache{$abs}{$mtime}{$y}++;
        eval { Kwalify::validate($schema, $data) };
        if (my $err = $@) {
            my $info = {}; yaml($schema_name, info => $info);
            die "validation of distropref '$abs'[$y] against schema '$info->{path}' failed: $err";
        }
    }
}

sub _clear_cache {
    %vcache = ();
}

sub yaml {
    my($schema_name, %opt) = @_;
    my $content = do {
        my $path = __FILE__;
        $path =~ s/\.pm$//;
        $path = File::Spec->catfile($path, "$schema_name.yml");
        if ($opt{info}) {
            $opt{info}{path} = $path;
        }
        local *FH;
        open FH, $path or die "Could not open '$path': $!";
        local $/;
        <FH>;
    };
    return $content;
}

1;

# Local Variables:
# mode: cperl
# cperl-indent-level: 4
# End:

PK7N%[����perl5/CPAN/InfoObj.pmnu��6�$# -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*-
# vim: ts=4 sts=4 sw=4:
package CPAN::InfoObj;
use strict;

use CPAN::Debug;
@CPAN::InfoObj::ISA = qw(CPAN::Debug);

use Cwd qw(chdir);

use vars qw(
            $VERSION
);
$VERSION = "5.5";

sub ro {
    my $self = shift;
    exists $self->{RO} and return $self->{RO};
}

#-> sub CPAN::InfoObj::cpan_userid
sub cpan_userid {
    my $self = shift;
    my $ro = $self->ro;
    if ($ro) {
        return $ro->{CPAN_USERID} || "N/A";
    } else {
        $self->debug("ID[$self->{ID}]");
        # N/A for bundles found locally
        return "N/A";
    }
}

sub id { shift->{ID}; }

#-> sub CPAN::InfoObj::new ;
sub new {
    my $this = bless {}, shift;
    %$this = @_;
    $this
}

# The set method may only be used by code that reads index data or
# otherwise "objective" data from the outside world. All session
# related material may do anything else with instance variables but
# must not touch the hash under the RO attribute. The reason is that
# the RO hash gets written to Metadata file and is thus persistent.

#-> sub CPAN::InfoObj::safe_chdir ;
sub safe_chdir {
  my($self,$todir) = @_;
  # we die if we cannot chdir and we are debuggable
  Carp::confess("safe_chdir called without todir argument")
        unless defined $todir and length $todir;
  if (chdir $todir) {
    $self->debug(sprintf "changed directory to %s", CPAN::anycwd())
        if $CPAN::DEBUG;
  } else {
    if (-e $todir) {
        unless (-x $todir) {
            unless (chmod 0755, $todir) {
                my $cwd = CPAN::anycwd();
                $CPAN::Frontend->mywarn("I have neither the -x permission nor the ".
                                        "permission to change the permission; cannot ".
                                        "chdir to '$todir'\n");
                $CPAN::Frontend->mysleep(5);
                $CPAN::Frontend->mydie(qq{Could not chdir from cwd[$cwd] }.
                                       qq{to todir[$todir]: $!});
            }
        }
    } else {
        $CPAN::Frontend->mydie("Directory '$todir' has gone. Cannot continue.\n");
    }
    if (chdir $todir) {
      $self->debug(sprintf "changed directory to %s", CPAN::anycwd())
          if $CPAN::DEBUG;
    } else {
      my $cwd = CPAN::anycwd();
      $CPAN::Frontend->mydie(qq{Could not chdir from cwd[$cwd] }.
                             qq{to todir[$todir] (a chmod has been issued): $!});
    }
  }
}

#-> sub CPAN::InfoObj::set ;
sub set {
    my($self,%att) = @_;
    my $class = ref $self;

    # This must be ||=, not ||, because only if we write an empty
    # reference, only then the set method will write into the readonly
    # area. But for Distributions that spring into existence, maybe
    # because of a typo, we do not like it that they are written into
    # the readonly area and made permanent (at least for a while) and
    # that is why we do not "allow" other places to call ->set.
    unless ($self->id) {
        CPAN->debug("Bug? Empty ID, rejecting");
        return;
    }
    my $ro = $self->{RO} =
        $CPAN::META->{readonly}{$class}{$self->id} ||= {};

    while (my($k,$v) = each %att) {
        $ro->{$k} = $v;
    }
}

#-> sub CPAN::InfoObj::as_glimpse ;
sub as_glimpse {
    my($self) = @_;
    my(@m);
    my $class = ref($self);
    $class =~ s/^CPAN:://;
    my $id = $self->can("pretty_id") ? $self->pretty_id : $self->{ID};
    push @m, sprintf "%-15s %s\n", $class, $id;
    join "", @m;
}

#-> sub CPAN::InfoObj::as_string ;
sub as_string {
    my($self) = @_;
    my(@m);
    my $class = ref($self);
    $class =~ s/^CPAN:://;
    push @m, $class, " id = $self->{ID}\n";
    my $ro;
    unless ($ro = $self->ro) {
        if (substr($self->{ID},-1,1) eq ".") { # directory
            $ro = +{};
        } else {
            $CPAN::Frontend->mywarn("Unknown object $self->{ID}\n");
            $CPAN::Frontend->mysleep(5);
            return;
        }
    }
    for (sort keys %$ro) {
        # next if m/^(ID|RO)$/;
        my $extra = "";
        if ($_ eq "CPAN_USERID") {
            $extra .= " (";
            $extra .= $self->fullname;
            my $email; # old perls!
            if ($email = $CPAN::META->instance("CPAN::Author",
                                               $self->cpan_userid
                                              )->email) {
                $extra .= " <$email>";
            } else {
                $extra .= " <no email>";
            }
            $extra .= ")";
        } elsif ($_ eq "FULLNAME") { # potential UTF-8 conversion
            push @m, sprintf "    %-12s %s\n", $_, $self->fullname;
            next;
        }
        next unless defined $ro->{$_};
        push @m, sprintf "    %-12s %s%s\n", $_, $ro->{$_}, $extra;
    }
  KEY: for (sort keys %$self) {
        next if m/^(ID|RO)$/;
        unless (defined $self->{$_}) {
            delete $self->{$_};
            next KEY;
        }
        if (ref($self->{$_}) eq "ARRAY") {
            push @m, sprintf "    %-12s %s\n", $_, "@{$self->{$_}}";
        } elsif (ref($self->{$_}) eq "HASH") {
            my $value;
            if (/^CONTAINSMODS$/) {
                $value = join(" ",sort keys %{$self->{$_}});
            } elsif (/^prereq_pm$/) {
                my @value;
                my $v = $self->{$_};
                for my $x (sort keys %$v) {
                    my @svalue;
                    for my $y (sort keys %{$v->{$x}}) {
                        push @svalue, "$y=>$v->{$x}{$y}";
                    }
                    push @value, "$x\:" . join ",", @svalue if @svalue;
                }
                $value = join ";", @value;
            } else {
                $value = $self->{$_};
            }
            push @m, sprintf(
                             "    %-12s %s\n",
                             $_,
                             $value,
                            );
        } else {
            push @m, sprintf "    %-12s %s\n", $_, $self->{$_};
        }
    }
    join "", @m, "\n";
}

#-> sub CPAN::InfoObj::fullname ;
sub fullname {
    my($self) = @_;
    $CPAN::META->instance("CPAN::Author",$self->cpan_userid)->fullname;
}

#-> sub CPAN::InfoObj::dump ;
sub dump {
    my($self, $what) = @_;
    unless ($CPAN::META->has_inst("Data::Dumper")) {
        $CPAN::Frontend->mydie("dump command requires Data::Dumper installed");
    }
    local $Data::Dumper::Sortkeys;
    $Data::Dumper::Sortkeys = 1;
    my $out = Data::Dumper::Dumper($what ? eval $what : $self);
    if (length $out > 100000) {
        my $fh_pager = FileHandle->new;
        local($SIG{PIPE}) = "IGNORE";
        my $pager = $CPAN::Config->{'pager'} || "cat";
        $fh_pager->open("|$pager")
            or die "Could not open pager $pager\: $!";
        $fh_pager->print($out);
        close $fh_pager;
    } else {
        $CPAN::Frontend->myprint($out);
    }
}

1;
PK7N%[>+���perl5/CPAN/LWP/UserAgent.pmnu��6�$# -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*-
# vim: ts=4 sts=4 sw=4:
package CPAN::LWP::UserAgent;
use strict;
use vars qw(@ISA $USER $PASSWD $SETUPDONE);
use CPAN::HTTP::Credentials;
# we delay requiring LWP::UserAgent and setting up inheritance until we need it

$CPAN::LWP::UserAgent::VERSION = $CPAN::LWP::UserAgent::VERSION = "1.9601";


sub config {
    return if $SETUPDONE;
    if ($CPAN::META->has_usable('LWP::UserAgent')) {
        require LWP::UserAgent;
        @ISA = qw(Exporter LWP::UserAgent); ## no critic
        $SETUPDONE++;
    } else {
        $CPAN::Frontend->mywarn("  LWP::UserAgent not available\n");
    }
}

sub get_basic_credentials {
    my($self, $realm, $uri, $proxy) = @_;
    if ( $proxy ) {
        return CPAN::HTTP::Credentials->get_proxy_credentials();
    } else {
        return CPAN::HTTP::Credentials->get_non_proxy_credentials();
    }
}

sub no_proxy {
    my ( $self, $no_proxy ) = @_;
    return $self->SUPER::no_proxy( split(',',$no_proxy) );
}

# mirror(): Its purpose is to deal with proxy authentication. When we
# call SUPER::mirror, we really call the mirror method in
# LWP::UserAgent. LWP::UserAgent will then call
# $self->get_basic_credentials or some equivalent and this will be
# $self->dispatched to our own get_basic_credentials method.

# Our own get_basic_credentials sets $USER and $PASSWD, two globals.

# 407 stands for HTTP_PROXY_AUTHENTICATION_REQUIRED. Which means
# although we have gone through our get_basic_credentials, the proxy
# server refuses to connect. This could be a case where the username or
# password has changed in the meantime, so I'm trying once again without
# $USER and $PASSWD to give the get_basic_credentials routine another
# chance to set $USER and $PASSWD.

sub mirror {
    my($self,$url,$aslocal) = @_;
    my $result = $self->SUPER::mirror($url,$aslocal);
    if ($result->code == 407) {
        CPAN::HTTP::Credentials->clear_credentials;
        $result = $self->SUPER::mirror($url,$aslocal);
    }
    $result;
}

1;
PK7N%[*�^��'perl5/CPAN/Exception/blocked_urllist.pmnu��6�$# -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*-
# vim: ts=4 sts=4 sw=4:
package CPAN::Exception::blocked_urllist;
use strict;
use overload '""' => "as_string";

use vars qw(
            $VERSION
);
$VERSION = "1.001";


sub new {
    my($class) = @_;
    bless {}, $class;
}

sub as_string {
    my($self) = shift;
    if ($CPAN::Config->{connect_to_internet_ok}) {
        return qq{

You have not configured a urllist for CPAN mirrors. Configure it with

    o conf init urllist

};
    } else {
        return qq{

You have not configured a urllist and do not allow connections to the
internet to get a list of mirrors.  If you wish to get a list of CPAN
mirrors to pick from, use this command

    o conf init connect_to_internet_ok urllist

If you do not wish to get a list of mirrors and would prefer to set
your urllist manually, use just this command instead

    o conf init urllist

};
    }
}

1;
PK7N%[T����*perl5/CPAN/Exception/yaml_not_installed.pmnu��6�$# -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*-
# vim: ts=4 sts=4 sw=4:
package CPAN::Exception::yaml_not_installed;
use strict;
use overload '""' => "as_string";

use vars qw(
            $VERSION
);
$VERSION = "5.5";


sub new {
    my($class,$module,$file,$during) = @_;
    bless { module => $module, file => $file, during => $during }, $class;
}

sub as_string {
    my($self) = shift;
    "'$self->{module}' not installed, cannot $self->{during} '$self->{file}'\n";
}

1;
PK7N%[�ܑH��*perl5/CPAN/Exception/yaml_process_error.pmnu��6�$# -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*-
# vim: ts=4 sts=4 sw=4:
package CPAN::Exception::yaml_process_error;
use strict;
use overload '""' => "as_string";

use vars qw(
            $VERSION
);
$VERSION = "5.5";


sub new {
    my($class,$module,$file,$during,$error) = @_;
    # my $at = Carp::longmess(""); # XXX find something more beautiful
    bless { module => $module,
            file => $file,
            during => $during,
            error => $error,
            # at => $at,
          }, $class;
}

sub as_string {
    my($self) = shift;
    if ($self->{during}) {
        if ($self->{file}) {
            if ($self->{module}) {
                if ($self->{error}) {
                    return "Alert: While trying to '$self->{during}' YAML file\n".
                        " '$self->{file}'\n".
                            "with '$self->{module}' the following error was encountered:\n".
                                "  $self->{error}\n";
                } else {
                    return "Alert: While trying to '$self->{during}' YAML file\n".
                        " '$self->{file}'\n".
                            "with '$self->{module}' some unknown error was encountered\n";
                }
            } else {
                return "Alert: While trying to '$self->{during}' YAML file\n".
                    " '$self->{file}'\n".
                        "some unknown error was encountered\n";
            }
        } else {
            return "Alert: While trying to '$self->{during}' some YAML file\n".
                    "some unknown error was encountered\n";
        }
    } else {
        return "Alert: unknown error encountered\n";
    }
}

1;
PK7N%[���1..+perl5/CPAN/Exception/RecursiveDependency.pmnu��6�$# -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*-
# vim: ts=4 sts=4 sw=4:
package CPAN::Exception::RecursiveDependency;
use strict;
use overload '""' => "as_string";

use vars qw(
            $VERSION
);
$VERSION = "5.5001";

{
    package CPAN::Exception::RecursiveDependency::na;
    use overload '""' => "as_string";
    sub new { bless {}, shift };
    sub as_string { "N/A" };
}

my $NA = CPAN::Exception::RecursiveDependency::na->new;

# a module sees its distribution (no version)
# a distribution sees its prereqs (which are module names) (usually with versions)
# a bundle sees its module names and/or its distributions (no version)

sub new {
    my($class) = shift;
    my($deps_arg) = shift;
    my (@deps,%seen,$loop_starts_with);
  DCHAIN: for my $dep (@$deps_arg) {
        push @deps, {name => $dep, display_as => $dep};
        if ($seen{$dep}++) {
            $loop_starts_with = $dep;
            last DCHAIN;
        }
    }
    my $in_loop = 0;
    my %mark;
 DWALK: for my $i (0..$#deps) {
        my $x = $deps[$i]{name};
        $in_loop ||= $loop_starts_with && $x eq $loop_starts_with;
        my $xo = CPAN::Shell->expandany($x) or next;
        if ($xo->isa("CPAN::Module")) {
            my $have = $xo->inst_version || $NA;
            my($want,$d,$want_type);
            if ($i>0 and $d = $deps[$i-1]{name}) {
                my $do = CPAN::Shell->expandany($d);
                $want = $do->{prereq_pm}{requires}{$x};
                if (defined $want) {
                    $want_type = "requires: ";
                } else {
                    $want = $do->{prereq_pm}{build_requires}{$x};
                    if (defined $want) {
                        $want_type = "build_requires: ";
                    } else {
                        $want_type = "unknown status";
                        $want = "???";
                    }
                }
            } else {
                $want = $xo->cpan_version;
                $want_type = "want: ";
            }
            $deps[$i]{have} = $have;
            $deps[$i]{want_type} = $want_type;
            $deps[$i]{want} = $want;
            $deps[$i]{display_as} = "$x (have: $have; $want_type$want)";
            if ((! ref $have || !$have->isa('CPAN::Exception::RecursiveDependency::na'))
                && CPAN::Version->vge($have, $want)) {
                # https://rt.cpan.org/Ticket/Display.html?id=115340
                undef $loop_starts_with;
                last DWALK;
            }
        } elsif ($xo->isa("CPAN::Distribution")) {
            my $pretty = $deps[$i]{display_as} = $xo->pretty_id;
            my $mark_as;
            if ($in_loop) {
                $mark_as = CPAN::Distrostatus->new("NO cannot resolve circular dependency");
            } else {
                $mark_as = CPAN::Distrostatus->new("NO one dependency ($loop_starts_with) is a circular dependency");
            }
            $mark{$pretty} = { xo => $xo, mark_as => $mark_as };
        }
    }
    if ($loop_starts_with) {
        while (my($k,$v) = each %mark) {
            my $xo = $v->{xo};
            $xo->{make} = $v->{mark_as};
            $xo->store_persistent_state; # otherwise I will not reach
                                         # all involved parties for
                                         # the next session
        }
    }
    bless { deps => \@deps, loop_starts_with => $loop_starts_with }, $class;
}

sub is_resolvable {
    ! defined shift->{loop_starts_with};
}

sub as_string {
    my($self) = shift;
    my $deps = $self->{deps};
    my $loop_starts_with = $self->{loop_starts_with};
    unless ($loop_starts_with) {
        return "--not a recursive/circular dependency--";
    }
    my $ret = "\nRecursive dependency detected:\n    ";
    $ret .= join("\n => ", map {$_->{display_as}} @$deps);
    $ret .= ".\nCannot resolve.\n";
    $ret;
}

1;
PK7N%[��Booperl5/CPAN/Admin.pmnu��6�$package CPAN::Admin;
use base CPAN;
use CPAN; # old base.pm did not load CPAN on previous line
use strict;
use vars qw(@EXPORT $VERSION);
use constant PAUSE_IP => "pause.perl.org";

@EXPORT = qw(shell);
$VERSION = "5.501";
push @CPAN::Complete::COMMANDS, qw(register modsearch);
$CPAN::Shell::COLOR_REGISTERED = 1;

sub shell {
    CPAN::shell($_[0]||"admin's cpan> ",$_[1]);
}

sub CPAN::Shell::register {
    my($self,$mod,@rest) = @_;
    unless ($mod) {
        print "register called without argument\n";
        return;
    }
    if ($CPAN::META->has_inst("URI::Escape")) {
        require URI::Escape;
    } else {
        print "register requires URI::Escape installed, otherwise it cannot work\n";
        return;
    }
    print "Got request for mod[$mod]\n";
    if (@rest) {
        my $modline = join " ", $mod, @rest;
        print "Sending to PAUSE [$modline]\n";
        my $emodline = URI::Escape::uri_escape($modline, '^\w ');
        $emodline =~ s/ /+/g;
        my $url =
            sprintf("https://%s/pause/authenquery?pause99_add_mod_modid=".
                    "%s;SUBMIT_pause99_add_mod_hint=hint",
                    PAUSE_IP,
                    $emodline,
                   );
        print "url[$url]\n\n";
        print ">>>>Trying to open a netscape window<<<<\n";
        sleep 1;
        system("netscape","-remote","openURL($url)");
        return;
    }
    my $m = CPAN::Shell->expand("Module",$mod);
    unless (ref $m) {
        print "Could not determine the object for $mod\n";
        return;
    }
    my $id = $m->id;
    print "Found module id[$id] in database\n";

    if (exists $m->{RO} && $m->{RO}{chapterid}) {
        print "$id is already registered\n";
        return;
    }

    my(@namespace) = split /::/, $id;
    my $rootns = $namespace[0];

    # Tk, XML and Apache need special treatment
    if ($rootns=~/^(Bundle)\b/) {
        print "Bundles are not yet ready for registering\n";
        return;
    }

    # make a good suggestion for the chapter
    my(@simile) = CPAN::Shell->expand("Module","/^$rootns(:|\$)/");
    print "Found within this namespace ", join(", ", map { $_->id } @simile), "\n";
    my(%seench);
    for my $ch (map { exists $_->{RO} ? $_->{RO}{chapterid} : ""} @simile) {
        next unless $ch;
        $seench{$ch}=undef;
    }
    my(@seench) = sort grep {length($_)} keys %seench;
    my $reco_ch = "";
    if (@seench>1) {
        print "Found rootnamespace[$rootns] in the chapters [", join(", ", @seench), "]\n";
        $reco_ch = $seench[0];
        print "Picking $reco_ch\n";
    } elsif (@seench==1) {
        print "Found rootnamespace[$rootns] in the chapter[$seench[0]]\n";
        $reco_ch = $seench[0];
    } else {
        print "The new rootnamespace[$rootns] needs to be introduced. Oh well.\n";
    }

    # Look closer at the dist
    my $d = CPAN::Shell->expand("Distribution", $m->cpan_file);
    printf "Module comes with dist[%s]\n", $d->id;
    for my $contm ($d->containsmods) {
        if ($CPAN::META->exists("CPAN::Module",$contm)) {
            my $contm_obj = CPAN::Shell->expand("Module",$contm) or next;
            my $is_reg = exists $contm_obj->{RO} && $contm_obj->{RO}{description};
            printf(" in same dist: %s%s\n",
                   $contm,
                   $is_reg ? " already in modulelist" : "",
                  );
        }
    }

    # get it so that m is better and we can inspect for XS
    CPAN::Shell->get($id);
    CPAN::Shell->m($id);
    CPAN::Shell->d($d->id);

    my $has_xs = 0;
    {
        my($mani,@mani);
        local $/ = "\n";
        open $mani, "$d->{build_dir}/MANIFEST" and @mani = <$mani>;
        my @xs = grep /\.xs\b/, @mani;
        if (@xs) {
            print "Found XS files: @xs";
            $has_xs=1;
        }
    }
    my $emodid = URI::Escape::uri_escape($id, '\W');
    my $ech = $reco_ch;
    $ech =~ s/ /+/g;
    my $description = $m->{MANPAGE} || "";
    $description =~ s/[A-Z]<//; # POD markup (and maybe more)
    $description =~ s/^\s+//; # leading spaces
    $description =~ s/>//; # POD
    $description =~ s/^\Q$id\E//; # usually this line starts with the modid
    $description =~ s/^[ \-]+//; # leading spaces and dashes
    substr($description,44) = "" if length($description)>44;
    $description = ucfirst($description);
    my $edescription = URI::Escape::uri_escape($description, '^\w ');
    $edescription =~ s/ /+/g;
    my $url =
        sprintf("https://%s/pause/authenquery?pause99_add_mod_modid=".
                "%s;pause99_add_mod_chapterid=%s;pause99_add_mod_statd=%s;".
                "pause99_add_mod_stats=%s;pause99_add_mod_statl=%s;".
                "pause99_add_mod_stati=%s;pause99_add_mod_description=%s;".
                "pause99_add_mod_userid=%s;SUBMIT_pause99_add_mod_preview=preview",
                PAUSE_IP,
                $emodid,
                $ech,
                "R",
                "d",
                $has_xs ? "c" : "p",
                "O",
                $edescription,
                $m->{RO}{CPAN_USERID},
               );
    print "$url\n\n";
    print ">>>>Trying to open a netscape window<<<<\n";
    system("netscape","-remote","openURL($url)");
}

sub CPAN::Shell::modsearch {
    my($self,@line) = @_;
    unless (@line) {
        print "modsearch called without argument\n";
        return;
    }
    my $request = join " ", @line;
    print "Got request[$request]\n";
    my $erequest = URI::Escape::uri_escape($request, '^\w ');
    $erequest =~ s/ /+/g;
    my $url =
        sprintf("http://www.xray.mpe.mpg.de/cgi-bin/w3glimpse/modules?query=%s".
                "&errors=0&case=on&maxfiles=100&maxlines=30",
                $erequest,
               );
    print "$url\n\n";
    print ">>>>Trying to open a netscape window<<<<\n";
    system("netscape","-remote","openURL('$url')");
}

1;

__END__

=head1 NAME

 CPAN::Admin - A CPAN Shell for CPAN admins

=head1 SYNOPSIS

 perl -MCPAN::Admin -e shell

=head1 STATUS

Note: this module is currently not maintained. If you need it and fix
it for your needs, please submit patches.

=head1 DESCRIPTION

CPAN::Admin is a subclass of CPAN that adds the commands C<register>
and C<modsearch> to the CPAN shell.

C<register> calls C<get> on the named module, assembles a couple of
informations (description, language), and calls Netscape with the
-remote argument so that a form is filled with all the assembled
informations and the registration can be performed with a single
click. If the command line has more than one argument, register does
not run a C<get>, instead it interprets the rest of the line as DSLI
status, description, and userid and sends them to netscape such that
the form is again mostly filled and can be edited or confirmed with a
single click. CPAN::Admin never performs the submission click for you,
it is only intended to fill in the form on PAUSE and leave the
confirmation to you.

C<modsearch> simply passes the arguments to the search engine for the
modules@perl.org mailing list at L<http://www.xray.mpe.mpg.de> where all
registration requests are stored. It does so in the same way as
register, namely with the C<netscape -remote> command.

An experimental feature has also been added, namely to color already
registered modules in listings. If you have L<Term::ANSIColor> installed,
the u, r, and m commands will show already registered modules in
green.

=head1 PREREQUISITES

L<URI::Escape>, a browser available in the path, the browser must
understand the -remote switch (as far as I know, this is only
available on UNIX); coloring of registered modules is only available
if L<Term::ANSIColor> is installed.

=head1 LICENSE

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

=cut
PK7N%[7�S��perl5/CPAN/Author.pmnu��6�$# -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*-
# vim: ts=4 sts=4 sw=4:
package CPAN::Author;
use strict;

use CPAN::InfoObj;
@CPAN::Author::ISA = qw(CPAN::InfoObj);
use vars qw(
            $VERSION
);
$VERSION = "5.5002";

package CPAN::Author;
use strict;

#-> sub CPAN::Author::force
sub force {
    my $self = shift;
    $self->{force}++;
}

#-> sub CPAN::Author::force
sub unforce {
    my $self = shift;
    delete $self->{force};
}

#-> sub CPAN::Author::id
sub id {
    my $self = shift;
    my $id = $self->{ID};
    $CPAN::Frontend->mydie("Illegal author id[$id]") unless $id =~ /^[A-Z]/;
    $id;
}

#-> sub CPAN::Author::as_glimpse ;
sub as_glimpse {
    my($self) = @_;
    my(@m);
    my $class = ref($self);
    $class =~ s/^CPAN:://;
    push @m, sprintf(qq{%-15s %s ("%s" <%s>)\n},
                     $class,
                     $self->{ID},
                     $self->fullname,
                     $self->email);
    join "", @m;
}

#-> sub CPAN::Author::fullname ;
sub fullname {
    shift->ro->{FULLNAME};
}
*name = \&fullname;

#-> sub CPAN::Author::email ;
sub email    { shift->ro->{EMAIL}; }

#-> sub CPAN::Author::ls ;
sub ls {
    my $self = shift;
    my $glob = shift || "";
    my $silent = shift || 0;
    my $id = $self->id;

    # adapted from CPAN::Distribution::verifyCHECKSUM ;
    my(@csf); # chksumfile
    @csf = $self->id =~ /(.)(.)(.*)/;
    $csf[1] = join "", @csf[0,1];
    $csf[2] = join "", @csf[1,2]; # ("A","AN","ANDK")
    my(@dl);
    @dl = $self->dir_listing([$csf[0],"CHECKSUMS"], 0, 1);
    unless (grep {$_->[2] eq $csf[1]} @dl) {
        $CPAN::Frontend->myprint("Directory $csf[1]/ does not exist\n") unless $silent ;
        return;
    }
    @dl = $self->dir_listing([@csf[0,1],"CHECKSUMS"], 0, 1);
    unless (grep {$_->[2] eq $csf[2]} @dl) {
        $CPAN::Frontend->myprint("Directory $id/ does not exist\n") unless $silent;
        return;
    }
    @dl = $self->dir_listing([@csf,"CHECKSUMS"], 1, 1);
    if ($glob) {
        if ($CPAN::META->has_inst("Text::Glob")) {
            $glob =~ s|/$|/*|;
            my $rglob = Text::Glob::glob_to_regex($glob);
            CPAN->debug("glob[$glob]rglob[$rglob]dl[@dl]") if $CPAN::DEBUG;
            my @tmpdl = grep { $_->[2] =~ /$rglob/ } @dl;
            if (1==@tmpdl && $tmpdl[0][0]==0) {
                $rglob = Text::Glob::glob_to_regex("$glob/*");
                @dl = grep { $_->[2] =~ /$rglob/ } @dl;
            } else {
                @dl = @tmpdl;
            }
            CPAN->debug("rglob[$rglob]dl[@dl]") if $CPAN::DEBUG;
        } else {
            $CPAN::Frontend->mydie("Text::Glob not installed, cannot proceed");
        }
    }
    unless ($silent >= 2) {
        $CPAN::Frontend->myprint
            (
             join "",
             map {
                 sprintf
                     (
                      "%8d %10s %s/%s%s\n",
                      $_->[0],
                      $_->[1],
                      $id,
                      $_->[2],
                      0==$_->[0]?"/":"",
                     )
                 } sort { $a->[2] cmp $b->[2] } @dl
            );
    }
    @dl;
}

# returns an array of arrays, the latter contain (size,mtime,filename)
#-> sub CPAN::Author::dir_listing ;
sub dir_listing {
    my $self = shift;
    my $chksumfile = shift;
    my $recursive = shift;
    my $may_ftp = shift;

    my $lc_want =
        File::Spec->catfile($CPAN::Config->{keep_source_where},
                            "authors", "id", @$chksumfile);

    my $fh;

    CPAN->debug("chksumfile[@$chksumfile]recursive[$recursive]may_ftp[$may_ftp]") if $CPAN::DEBUG;
    # Purge and refetch old (pre-PGP) CHECKSUMS; they are a security
    # hazard.  (Without GPG installed they are not that much better,
    # though.)
    $fh = FileHandle->new;
    if (open($fh, $lc_want)) {
        my $line = <$fh>; close $fh;
        unlink($lc_want) unless $line =~ /PGP/;
    }

    local($") = "/";
    # connect "force" argument with "index_expire".
    my $force = $self->{force};
    if (my @stat = stat $lc_want) {
        $force ||= $stat[9] + $CPAN::Config->{index_expire}*86400 <= time;
    }
    my $lc_file;
    if ($may_ftp) {
        $lc_file = eval {
            CPAN::FTP->localize
                    (
                     "authors/id/@$chksumfile",
                     $lc_want,
                     $force,
                    );
        };
        unless ($lc_file) {
            $CPAN::Frontend->myprint("Trying $lc_want.gz\n");
            $chksumfile->[-1] .= ".gz";
            $lc_file = eval {
                CPAN::FTP->localize
                        ("authors/id/@$chksumfile",
                         "$lc_want.gz",
                         1,
                        );
            };
            if ($lc_file) {
                $lc_file =~ s{\.gz(?!\n)\Z}{}; #};
                eval{CPAN::Tarzip->new("$lc_file.gz")->gunzip($lc_file)};
            } else {
                return;
            }
        }
    } else {
        $lc_file = $lc_want;
        # we *could* second-guess and if the user has a file: URL,
        # then we could look there. But on the other hand, if they do
        # have a file: URL, why did they choose to set
        # $CPAN::Config->{show_upload_date} to false?
    }

    # adapted from CPAN::Distribution::CHECKSUM_check_file ;
    $fh = FileHandle->new;
    my($cksum);
    if (open $fh, $lc_file) {
        local($/);
        my $eval = <$fh>;
        $eval =~ s/\015?\012/\n/g;
        close $fh;
        my($compmt) = Safe->new();
        $cksum = $compmt->reval($eval);
        if ($@) {
            rename $lc_file, "$lc_file.bad";
            Carp::confess($@) if $@;
        }
    } elsif ($may_ftp) {
        Carp::carp ("Could not open '$lc_file' for reading.");
    } else {
        # Maybe should warn: "You may want to set show_upload_date to a true value"
        return;
    }
    my(@result,$f);
    for $f (sort keys %$cksum) {
        if (exists $cksum->{$f}{isdir}) {
            if ($recursive) {
                my(@dir) = @$chksumfile;
                pop @dir;
                push @dir, $f, "CHECKSUMS";
                push @result, [ 0, "-", $f ];
                push @result, map {
                    [$_->[0], $_->[1], "$f/$_->[2]"]
                } $self->dir_listing(\@dir,1,$may_ftp);
            } else {
                push @result, [ 0, "-", $f ];
            }
        } else {
            push @result, [
                           ($cksum->{$f}{"size"}||0),
                           $cksum->{$f}{"mtime"}||"---",
                           $f
                          ];
        }
    }
    @result;
}

#-> sub CPAN::Author::reports
sub reports {
    $CPAN::Frontend->mywarn("reports on authors not implemented.
Please file a bugreport if you need this.\n");
}

1;
PK7N%[��Hperl5/CPAN/FTP/netrc.pmnu��6�$package CPAN::FTP::netrc;
use strict;

$CPAN::FTP::netrc::VERSION = $CPAN::FTP::netrc::VERSION = "1.01";

# package CPAN::FTP::netrc;
sub new {
    my($class) = @_;
    my $file = File::Spec->catfile($ENV{HOME},".netrc");

    my($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
       $atime,$mtime,$ctime,$blksize,$blocks)
        = stat($file);
    $mode ||= 0;
    my $protected = 0;

    my($fh,@machines,$hasdefault);
    $hasdefault = 0;
    $fh = FileHandle->new or die "Could not create a filehandle";

    if($fh->open($file)) {
        $protected = ($mode & 077) == 0;
        local($/) = "";
      NETRC: while (<$fh>) {
            my(@tokens) = split " ", $_;
          TOKEN: while (@tokens) {
                my($t) = shift @tokens;
                if ($t eq "default") {
                    $hasdefault++;
                    last NETRC;
                }
                last TOKEN if $t eq "macdef";
                if ($t eq "machine") {
                    push @machines, shift @tokens;
                }
            }
        }
    } else {
        $file = $hasdefault = $protected = "";
    }

    bless {
        'mach' => [@machines],
        'netrc' => $file,
        'hasdefault' => $hasdefault,
        'protected' => $protected,
    }, $class;
}

# CPAN::FTP::netrc::hasdefault;
sub hasdefault { shift->{'hasdefault'} }
sub netrc      { shift->{'netrc'}      }
sub protected  { shift->{'protected'}  }
sub contains {
    my($self,$mach) = @_;
    for ( @{$self->{'mach'}} ) {
        return 1 if $_ eq $mach;
    }
    return 0;
}

1;
PK7N%[��o��perl5/CPAN/CacheMgr.pmnu��6�$# -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*-
# vim: ts=4 sts=4 sw=4:
package CPAN::CacheMgr;
use strict;
use CPAN::InfoObj;
@CPAN::CacheMgr::ISA = qw(CPAN::InfoObj CPAN);
use Cwd qw(chdir);
use File::Find;

use vars qw(
            $VERSION
);
$VERSION = "5.5002";

package CPAN::CacheMgr;
use strict;

#-> sub CPAN::CacheMgr::as_string ;
sub as_string {
    eval { require Data::Dumper };
    if ($@) {
        return shift->SUPER::as_string;
    } else {
        return Data::Dumper::Dumper(shift);
    }
}

#-> sub CPAN::CacheMgr::cachesize ;
sub cachesize {
    shift->{DU};
}

#-> sub CPAN::CacheMgr::tidyup ;
sub tidyup {
  my($self) = @_;
  return unless $CPAN::META->{LOCK};
  return unless -d $self->{ID};
  my @toremove = grep { $self->{SIZE}{$_}==0 } @{$self->{FIFO}};
  for my $current (0..$#toremove) {
    my $toremove = $toremove[$current];
    $CPAN::Frontend->myprint(sprintf(
                                     "DEL(%d/%d): %s \n",
                                     $current+1,
                                     scalar @toremove,
                                     $toremove,
                                    )
                            );
    return if $CPAN::Signal;
    $self->_clean_cache($toremove);
    return if $CPAN::Signal;
  }
  $self->{FIFO} = [];
}

#-> sub CPAN::CacheMgr::dir ;
sub dir {
    shift->{ID};
}

#-> sub CPAN::CacheMgr::entries ;
sub entries {
    my($self,$dir) = @_;
    return unless defined $dir;
    $self->debug("reading dir[$dir]") if $CPAN::DEBUG;
    $dir ||= $self->{ID};
    my($cwd) = CPAN::anycwd();
    chdir $dir or Carp::croak("Can't chdir to $dir: $!");
    my $dh = DirHandle->new(File::Spec->curdir)
        or Carp::croak("Couldn't opendir $dir: $!");
    my(@entries);
    for ($dh->read) {
        next if $_ eq "." || $_ eq "..";
        if (-f $_) {
            push @entries, File::Spec->catfile($dir,$_);
        } elsif (-d _) {
            push @entries, File::Spec->catdir($dir,$_);
        } else {
            $CPAN::Frontend->mywarn("Warning: weird direntry in $dir: $_\n");
        }
    }
    chdir $cwd or Carp::croak("Can't chdir to $cwd: $!");
    sort { -M $a <=> -M $b} @entries;
}

#-> sub CPAN::CacheMgr::disk_usage ;
sub disk_usage {
    my($self,$dir,$fast) = @_;
    return if exists $self->{SIZE}{$dir};
    return if $CPAN::Signal;
    my($Du) = 0;
    if (-e $dir) {
        if (-d $dir) {
            unless (-x $dir) {
                unless (chmod 0755, $dir) {
                    $CPAN::Frontend->mywarn("I have neither the -x permission nor the ".
                                            "permission to change the permission; cannot ".
                                            "estimate disk usage of '$dir'\n");
                    $CPAN::Frontend->mysleep(5);
                    return;
                }
            }
        } elsif (-f $dir) {
            # nothing to say, no matter what the permissions
        }
    } else {
        $CPAN::Frontend->mywarn("File or directory '$dir' has gone, ignoring\n");
        return;
    }
    if ($fast) {
        $Du = 0; # placeholder
    } else {
        find(
             sub {
           $File::Find::prune++ if $CPAN::Signal;
           return if -l $_;
           if ($^O eq 'MacOS') {
             require Mac::Files;
             my $cat  = Mac::Files::FSpGetCatInfo($_);
             $Du += $cat->ioFlLgLen() + $cat->ioFlRLgLen() if $cat;
           } else {
             if (-d _) {
               unless (-x _) {
                 unless (chmod 0755, $_) {
                   $CPAN::Frontend->mywarn("I have neither the -x permission nor ".
                                           "the permission to change the permission; ".
                                           "can only partially estimate disk usage ".
                                           "of '$_'\n");
                   $CPAN::Frontend->mysleep(5);
                   return;
                 }
               }
             } else {
               $Du += (-s _);
             }
           }
         },
         $dir
            );
    }
    return if $CPAN::Signal;
    $self->{SIZE}{$dir} = $Du/1024/1024;
    unshift @{$self->{FIFO}}, $dir;
    $self->debug("measured $dir is $Du") if $CPAN::DEBUG;
    $self->{DU} += $Du/1024/1024;
    $self->{DU};
}

#-> sub CPAN::CacheMgr::_clean_cache ;
sub _clean_cache {
    my($self,$dir) = @_;
    return unless -e $dir;
    unless (File::Spec->canonpath(File::Basename::dirname($dir))
            eq File::Spec->canonpath($CPAN::Config->{build_dir})) {
        $CPAN::Frontend->mywarn("Directory '$dir' not below $CPAN::Config->{build_dir}, ".
                                "will not remove\n");
        $CPAN::Frontend->mysleep(5);
        return;
    }
    $self->debug("have to rmtree $dir, will free $self->{SIZE}{$dir}")
        if $CPAN::DEBUG;
    File::Path::rmtree($dir);
    my $id_deleted = 0;
    if ($dir !~ /\.yml$/ && -f "$dir.yml") {
        my $yaml_module = CPAN::_yaml_module();
        if ($CPAN::META->has_inst($yaml_module)) {
            my($peek_yaml) = eval { CPAN->_yaml_loadfile("$dir.yml"); };
            if ($@) {
                $CPAN::Frontend->mywarn("(parse error on '$dir.yml' removing anyway)");
                unlink "$dir.yml" or
                    $CPAN::Frontend->mywarn("(Could not unlink '$dir.yml': $!)");
                return;
            } elsif (my $id = $peek_yaml->[0]{distribution}{ID}) {
                $CPAN::META->delete("CPAN::Distribution", $id);

                # XXX we should restore the state NOW, otherwise this
                # distro does not exist until we read an index. BUG ALERT(?)

                # $CPAN::Frontend->mywarn (" +++\n");
                $id_deleted++;
            }
        }
        unlink "$dir.yml"; # may fail
        unless ($id_deleted) {
            CPAN->debug("no distro found associated with '$dir'");
        }
    }
    $self->{DU} -= $self->{SIZE}{$dir};
    delete $self->{SIZE}{$dir};
}

#-> sub CPAN::CacheMgr::new ;
sub new {
    my($class,$phase) = @_;
    $phase ||= "atstart";
    my $time = time;
    my($debug,$t2);
    $debug = "";
    my $self = {
        ID => $CPAN::Config->{build_dir},
        MAX => $CPAN::Config->{'build_cache'},
        SCAN => $CPAN::Config->{'scan_cache'} || 'atstart',
        DU => 0
    };
    $CPAN::Frontend->mydie("Unknown scan_cache argument: $self->{SCAN}")
        unless $self->{SCAN} =~ /never|atstart|atexit/;
    File::Path::mkpath($self->{ID});
    my $dh = DirHandle->new($self->{ID});
    bless $self, $class;
    $self->scan_cache($phase);
    $t2 = time;
    $debug .= "timing of CacheMgr->new: ".($t2 - $time);
    $time = $t2;
    CPAN->debug($debug) if $CPAN::DEBUG;
    $self;
}

#-> sub CPAN::CacheMgr::scan_cache ;
sub scan_cache {
    my ($self, $phase) = @_;
    $phase = '' unless defined $phase;
    return unless $phase eq $self->{SCAN};
    return unless $CPAN::META->{LOCK};
    $CPAN::Frontend->myprint(
                             sprintf("Scanning cache %s for sizes\n",
                             $self->{ID}));
    my $e;
    my @entries = $self->entries($self->{ID});
    my $i = 0;
    my $painted = 0;
    for $e (@entries) {
        my $symbol = ".";
        if ($self->{DU} > $self->{MAX}) {
            $symbol = "-";
            $self->disk_usage($e,1);
        } else {
            $self->disk_usage($e);
        }
        $i++;
        while (($painted/76) < ($i/@entries)) {
            $CPAN::Frontend->myprint($symbol);
            $painted++;
        }
        return if $CPAN::Signal;
    }
    $CPAN::Frontend->myprint("DONE\n");
    $self->tidyup;
}

1;
PK7N%[���bJGJGperl5/CPAN/Mirrors.pmnu��6�$# -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*-
# vim: ts=4 sts=4 sw=4:
=head1 NAME

CPAN::Mirrors - Get CPAN mirror information and select a fast one

=head1 SYNOPSIS

    use CPAN::Mirrors;

    my $mirrors = CPAN::Mirrors->new( $mirrored_by_file );

    my $seen = {};

    my $best_continent = $mirrors->find_best_continents( { seen => $seen } );
    my @mirrors        = $mirrors->get_mirrors_by_continents( $best_continent );

    my $callback = sub {
        my( $m ) = @_;
        printf "%s = %s\n", $m->hostname, $m->rtt
        };
    $mirrors->get_mirrors_timings( \@mirrors, $seen, $callback, %args );

    @mirrors = sort { $a->rtt <=> $b->rtt } @mirrors;

    print "Best mirrors are ", map( { $_->rtt } @mirrors[0..3] ), "\n";

=head1 DESCRIPTION

=over

=cut

package CPAN::Mirrors;
use strict;
use vars qw($VERSION $urllist $silent);
$VERSION = "2.27";

use Carp;
use FileHandle;
use Fcntl ":flock";
use Net::Ping ();
use CPAN::Version;

=item new( LOCAL_FILE_NAME )

Create a new CPAN::Mirrors object from LOCAL_FILE_NAME. This file
should look like that in http://www.cpan.org/MIRRORED.BY .

=cut

sub new {
    my ($class, $file) = @_;
    croak "CPAN::Mirrors->new requires a filename" unless defined $file;
    croak "The file [$file] was not found" unless -e $file;

    my $self = bless {
        mirrors      => [],
        geography    => {},
    }, $class;

    $self->parse_mirrored_by( $file );

    return $self;
}

sub parse_mirrored_by {
    my ($self, $file) = @_;
    my $handle = FileHandle->new;
    $handle->open($file)
        or croak "Couldn't open $file: $!";
    flock $handle, LOCK_SH;
    $self->_parse($file,$handle);
    flock $handle, LOCK_UN;
    $handle->close;
}

=item continents()

Return a list of continents based on those defined in F<MIRRORED.BY>.

=cut

sub continents {
    my ($self) = @_;
    return sort keys %{$self->{geography} || {}};
}

=item countries( [CONTINENTS] )

Return a list of countries based on those defined in F<MIRRORED.BY>.
It only returns countries for the continents you specify (as defined
in C<continents>). If you don't specify any continents, it returns all
of the countries listed in F<MIRRORED.BY>.

=cut

sub countries {
    my ($self, @continents) = @_;
    @continents = $self->continents unless @continents;
    my @countries;
    for my $c (@continents) {
        push @countries, sort keys %{ $self->{geography}{$c} || {} };
    }
    return @countries;
}

=item mirrors( [COUNTRIES] )

Return a list of mirrors based on those defined in F<MIRRORED.BY>.
It only returns mirrors for the countries you specify (as defined
in C<countries>). If you don't specify any countries, it returns all
of the mirrors listed in F<MIRRORED.BY>.

=cut

sub mirrors {
    my ($self, @countries) = @_;
    return @{$self->{mirrors}} unless @countries;
    my %wanted = map { $_ => 1 } @countries;
    my @found;
    for my $m (@{$self->{mirrors}}) {
        push @found, $m if exists $wanted{$m->country};
    }
    return @found;
}

=item get_mirrors_by_countries( [COUNTRIES] )

A more sensible synonym for mirrors.

=cut

sub get_mirrors_by_countries { &mirrors }

=item get_mirrors_by_continents( [CONTINENTS] )

Return a list of mirrors for all of continents you specify. If you don't
specify any continents, it returns all of the mirrors.

You can specify a single continent or an array reference of continents.

=cut

sub get_mirrors_by_continents {
    my ($self, $continents ) = @_;
    $continents = [ $continents ] unless ref $continents;

    eval {
        $self->mirrors( $self->get_countries_by_continents( @$continents ) );
        };
    }

=item get_countries_by_continents( [CONTINENTS] )

A more sensible synonym for countries.

=cut

sub get_countries_by_continents { &countries }

=item default_mirror

Returns the default mirror, http://www.cpan.org/ . This mirror uses
dynamic DNS to give a close mirror.

=cut

sub default_mirror {
    CPAN::Mirrored::By->new({ http => 'http://www.cpan.org/'});
}

=item best_mirrors

C<best_mirrors> checks for the best mirrors based on the list of
continents you pass, or, without that, all continents, as defined
by C<CPAN::Mirrored::By>. It pings each mirror, up to the value of
C<how_many>. In list context, it returns up to C<how_many> mirrors.
In scalar context, it returns the single best mirror.

Arguments

    how_many      - the number of mirrors to return. Default: 1
    callback      - a callback for find_best_continents
    verbose       - true or false on all the whining and moaning. Default: false
    continents    - an array ref of the continents to check
    external_ping - if true, use external ping via Net::Ping::External. Default: false

If you don't specify the continents, C<best_mirrors> calls
C<find_best_continents> to get the list of continents to check.

If you don't have L<Net::Ping> v2.13 or later, needed for timings,
this returns the default mirror.

C<external_ping> should be set and then C<Net::Ping::External> needs
to be installed, if the local network has a transparent proxy.

=cut

sub best_mirrors {
    my ($self, %args) = @_;
    my $how_many      = $args{how_many} || 1;
    my $callback      = $args{callback};
    my $verbose       = defined $args{verbose} ? $args{verbose} : 0;
    my $continents    = $args{continents} || [];
       $continents    = [$continents] unless ref $continents;
    $args{external_ping} = 0 unless defined $args{external_ping};
    my $external_ping = $args{external_ping};

    # Old Net::Ping did not do timings at all
    my $min_version = '2.13';
    unless( CPAN::Version->vgt(Net::Ping->VERSION, $min_version) ) {
        carp sprintf "Net::Ping version is %s (< %s). Returning %s",
            Net::Ping->VERSION, $min_version, $self->default_mirror;
        return $self->default_mirror;
    }

    my $seen = {};

    if ( ! @$continents ) {
        print "Searching for the best continent ...\n" if $verbose;
        my @best_continents = $self->find_best_continents(
            seen          => $seen,
            verbose       => $verbose,
            callback      => $callback,
            external_ping => $external_ping,
            );

        # Only add enough continents to find enough mirrors
        my $count = 0;
        for my $continent ( @best_continents ) {
            push @$continents, $continent;
            $count += $self->mirrors( $self->countries($continent) );
            last if $count >= $how_many;
        }
    }

    return $self->default_mirror unless @$continents;
    print "Scanning " . join(", ", @$continents) . " ...\n" if $verbose;

    my $trial_mirrors = $self->get_n_random_mirrors_by_continents( 3 * $how_many, $continents->[0] );

    my $timings = $self->get_mirrors_timings(
        $trial_mirrors,
        $seen,
        $callback,
        %args,
    );
    return $self->default_mirror unless @$timings;

    $how_many = @$timings if $how_many > @$timings;

    return wantarray ? @{$timings}[0 .. $how_many-1] : $timings->[0];
}

=item get_n_random_mirrors_by_continents( N, [CONTINENTS] )

Returns up to N random mirrors for the specified continents. Specify the
continents as an array reference.

=cut

sub get_n_random_mirrors_by_continents {
    my( $self, $n, $continents ) = @_;
    $n ||= 3;
    $continents = [ $continents ] unless ref $continents;

    if ( $n <= 0 ) {
        return wantarray ? () : [];
    }

    my @long_list = $self->get_mirrors_by_continents( $continents );

    if ( $n eq '*' or $n > @long_list ) {
        return wantarray ? @long_list : \@long_list;
    }

    @long_list = map  {$_->[0]}
                 sort {$a->[1] <=> $b->[1]}
                 map  {[$_, rand]} @long_list;

    splice @long_list, $n; # truncate

    \@long_list;
}

=item get_mirrors_timings( MIRROR_LIST, SEEN, CALLBACK, %ARGS );

Pings the listed mirrors and returns a list of mirrors sorted in
ascending ping times.

C<MIRROR_LIST> is an anonymous array of C<CPAN::Mirrored::By> objects to
ping.

The optional argument C<SEEN> is a hash reference used to track the
mirrors you've already pinged.

The optional argument C<CALLBACK> is a subroutine reference to call
after each ping. It gets the C<CPAN::Mirrored::By> object after each
ping.

=cut

sub get_mirrors_timings {
    my( $self, $mirror_list, $seen, $callback, %args ) = @_;

    $seen = {} unless defined $seen;
    croak "The mirror list argument must be an array reference"
        unless ref $mirror_list eq ref [];
    croak "The seen argument must be a hash reference"
        unless ref $seen eq ref {};
    croak "callback must be a subroutine"
        if( defined $callback and ref $callback ne ref sub {} );

    my $timings = [];
    for my $m ( @$mirror_list ) {
        $seen->{$m->hostname} = $m;
        next unless eval{ $m->http };

        if( $self->_try_a_ping( $seen, $m, ) ) {
            my $ping = $m->ping(%args);
            next unless defined $ping;
            # printf "m %s ping %s\n", $m, $ping;
            push @$timings, $m;
            $callback->( $m ) if $callback;
        }
        else {
            push @$timings, $seen->{$m->hostname}
                if defined $seen->{$m->hostname}->rtt;
        }
    }

    my @best = sort {
           if( defined $a->rtt and defined $b->rtt )     {
            $a->rtt <=> $b->rtt
            }
        elsif( defined $a->rtt and ! defined $b->rtt )   {
            return -1;
            }
        elsif( ! defined $a->rtt and defined $b->rtt )   {
            return 1;
            }
        elsif( ! defined $a->rtt and ! defined $b->rtt ) {
            return 0;
            }

        } @$timings;

    return wantarray ? @best : \@best;
}

=item find_best_continents( HASH_REF );

C<find_best_continents> goes through each continent and pings C<N>
random mirrors on that continent. It then orders the continents by
ascending median ping time. In list context, it returns the ordered list
of continent. In scalar context, it returns the same list as an
anonymous array.

Arguments:

    n        - the number of hosts to ping for each continent. Default: 3
    seen     - a hashref of cached hostname ping times
    verbose  - true or false for noisy or quiet. Default: false
    callback - a subroutine to run after each ping.
    ping_cache_limit - how long, in seconds, to reuse previous ping times.
        Default: 1 day

The C<seen> hash has hostnames as keys and anonymous arrays as values.
The anonymous array is a triplet of a C<CPAN::Mirrored::By> object, a
ping time, and the epoch time for the measurement.

The callback subroutine gets the C<CPAN::Mirrored::By> object, the ping
time, and measurement time (the same things in the C<seen> hashref) as
arguments. C<find_best_continents> doesn't care what the callback does
and ignores the return value.

With a low value for C<N>, a single mirror might skew the results enough
to choose a worse continent. If you have that problem, try a larger
value.

=cut

sub find_best_continents {
    my ($self, %args) = @_;

    $args{n}     ||= 3;
    $args{verbose} = 0 unless defined $args{verbose};
    $args{seen}    = {} unless defined $args{seen};
    croak "The seen argument must be a hash reference"
        unless ref $args{seen} eq ref {};
    $args{ping_cache_limit} = 24 * 60 * 60
        unless defined $args{ping_cache_limit};
    croak "callback must be a subroutine"
        if( defined $args{callback} and ref $args{callback} ne ref sub {} );

    my %medians;
    CONT: for my $c ( $self->continents ) {
        my @mirrors = $self->mirrors( $self->countries($c) );
        printf "Testing %s (%d mirrors)\n", $c, scalar @mirrors
            if $args{verbose};

        next CONT unless @mirrors;
        my $n = (@mirrors < $args{n}) ? @mirrors : $args{n};

        my @tests;
        my $tries = 0;
        RANDOM: while ( @mirrors && @tests < $n && $tries++ < 15 ) {
            my $m = splice( @mirrors, int(rand(@mirrors)), 1 );
            if( $self->_try_a_ping(
                    $args{seen}, $m, $args{ping_cache_limit}
                )) {
                $self->get_mirrors_timings(
                    [ $m ],
                    $args{seen},
                    $args{callback},
                    %args,
                );
                next RANDOM unless defined $args{seen}{$m->hostname}->rtt;
            }
            printf "(%s -> %0.2f ms)",
                $m->hostname,
                join ' ', 1000 * $args{seen}{$m->hostname}->rtt
                    if $args{verbose};

            push @tests, $args{seen}{$m->hostname}->rtt;
        }

        my $median = $self->_get_median_ping_time( \@tests, $args{verbose} );
        $medians{$c} = $median if defined $median;
    }

    my @best_cont = sort { $medians{$a} <=> $medians{$b} } keys %medians;

    if ( $args{verbose} ) {
        print "Median result by continent:\n";
        if ( @best_cont ) {
            for my $c ( @best_cont ) {
                printf( "  %7.2f ms  %s\n", $medians{$c}*1000, $c );
            }
        } else {
            print "  **** No results found ****\n"
        }
    }

    return wantarray ? @best_cont : $best_cont[0];
}

# retry if
sub _try_a_ping {
    my ($self, $seen, $mirror, $ping_cache_limit ) = @_;

    ( ! exists $seen->{$mirror->hostname}
        or
    ! defined $seen->{$mirror->hostname}->rtt
      or
    ! defined $ping_cache_limit
      or
      time - $seen->{$mirror->hostname}->ping_time
        > $ping_cache_limit
    )
}

sub _get_median_ping_time {
    my ($self, $tests, $verbose ) = @_;

    my @sorted = sort { $a <=> $b } @$tests;

    my $median = do {
           if ( @sorted == 0 ) { undef }
        elsif ( @sorted == 1 ) { $sorted[0] }
        elsif ( @sorted % 2 )  { $sorted[ int(@sorted / 2) ] }
        else {
            my $mid_high = int(@sorted/2);
            ($sorted[$mid_high-1] + $sorted[$mid_high])/2;
        }
    };

    if ($verbose){
        if ($median) {
            printf " => median time: %.2f ms\n", $median * 1000
        } else {
            printf " => **** no median time ****\n";
        }
    }

    return $median;
}

# Adapted from Parse::CPAN::MirroredBy by Adam Kennedy
sub _parse {
    my ($self, $file, $handle) = @_;
    my $output = $self->{mirrors};
    my $geo    = $self->{geography};

    local $/ = "\012";
    my $line = 0;
    my $mirror = undef;
    while ( 1 ) {
        # Next line
        my $string = <$handle>;
        last if ! defined $string;
        $line = $line + 1;

        # Remove the useless lines
        chomp( $string );
        next if $string =~ /^\s*$/;
        next if $string =~ /^\s*#/;

        # Hostname or property?
        if ( $string =~ /^\s/ ) {
            # Property
            unless ( $string =~ /^\s+(\w+)\s+=\s+\"(.*)\"$/ ) {
                croak("Invalid property on line $line");
            }
            my ($prop, $value) = ($1,$2);
            $mirror ||= {};
            if ( $prop eq 'dst_location' ) {
                my (@location,$continent,$country);
                @location = (split /\s*,\s*/, $value)
                    and ($continent, $country) = @location[-1,-2];
                $continent =~ s/\s\(.*//;
                $continent =~ s/\W+$//; # if Jarkko doesn't know latitude/longitude
                $geo->{$continent}{$country} = 1 if $continent && $country;
                $mirror->{continent} = $continent || "unknown";
                $mirror->{country} = $country || "unknown";
            }
            elsif ( $prop eq 'dst_http' ) {
                $mirror->{http} = $value;
            }
            elsif ( $prop eq 'dst_ftp' ) {
                $mirror->{ftp} = $value;
            }
            elsif ( $prop eq 'dst_rsync' ) {
                $mirror->{rsync} = $value;
            }
            else {
                $prop =~ s/^dst_//;
                $mirror->{$prop} = $value;
            }
        } else {
            # Hostname
            unless ( $string =~ /^([\w\.-]+)\:\s*$/ ) {
                croak("Invalid host name on line $line");
            }
            my $current = $mirror;
            $mirror     = { hostname => "$1" };
            if ( $current ) {
                push @$output, CPAN::Mirrored::By->new($current);
            }
        }
    }
    if ( $mirror ) {
        push @$output, CPAN::Mirrored::By->new($mirror);
    }

    return;
}

#--------------------------------------------------------------------------#

package CPAN::Mirrored::By;
use strict;
use Net::Ping   ();

sub new {
    my($self,$arg) = @_;
    $arg ||= {};
    bless $arg, $self;
}
sub hostname  { shift->{hostname}    }
sub continent { shift->{continent}   }
sub country   { shift->{country}     }
sub http      { shift->{http}  || '' }
sub ftp       { shift->{ftp}   || '' }
sub rsync     { shift->{rsync} || '' }
sub rtt       { shift->{rtt}         }
sub ping_time { shift->{ping_time}   }

sub url {
    my $self = shift;
    return $self->{http} || $self->{ftp};
}

sub ping {
    my($self, %args) = @_;

    my $external_ping = $args{external_ping};
    if ($external_ping) {
        eval { require Net::Ping::External }
            or die "Net::Ping::External required to use external ping command";
    }
    my $ping = Net::Ping->new(
        $external_ping ? 'external' : $^O eq 'VMS' ? 'icmp' : 'tcp',
        1
    );
    my ($proto) = $self->url =~ m{^([^:]+)};
    my $port = $proto eq 'http' ? 80 : 21;
    return unless $port;

    if ( $ping->can('port_number') ) {
        $ping->port_number($port);
    }
    else {
        $ping->{'port_num'} = $port;
    }

    $ping->hires(1) if $ping->can('hires');
    my ($alive,$rtt) = eval { $ping->ping($self->hostname); };
    my $verbose = $args{verbose};
    if ($verbose && !$alive) {
        printf "(host %s not alive)", $self->hostname;
    }

    $self->{rtt} = $alive ? $rtt : undef;
    $self->{ping_time} = time;

    $self->rtt;
}


1;

=back

=head1 AUTHOR

Andreas Koenig C<< <andk@cpan.org> >>, David Golden C<< <dagolden@cpan.org> >>,
brian d foy C<< <bdfoy@cpan.org> >>

=head1 LICENSE

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

See L<http://www.perl.com/perl/misc/Artistic.html>

=cut
PK7N%[���CvWvWperl5/CPAN/Module.pmnu��6�$# -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*-
# vim: ts=4 sts=4 sw=4:
package CPAN::Module;
use strict;
@CPAN::Module::ISA = qw(CPAN::InfoObj);

use vars qw(
            $VERSION
);
$VERSION = "5.5003";

BEGIN {
    # alarm() is not implemented in perl 5.6.x and earlier under Windows
    *ALARM_IMPLEMENTED = sub () { $] >= 5.007 || $^O !~ /MSWin/ };
}

# Accessors
#-> sub CPAN::Module::userid
sub userid {
    my $self = shift;
    my $ro = $self->ro;
    return unless $ro;
    return $ro->{userid} || $ro->{CPAN_USERID};
}
#-> sub CPAN::Module::description
sub description {
    my $self = shift;
    my $ro = $self->ro or return "";
    $ro->{description}
}

#-> sub CPAN::Module::distribution
sub distribution {
    my($self) = @_;
    CPAN::Shell->expand("Distribution",$self->cpan_file);
}

#-> sub CPAN::Module::_is_representative_module
sub _is_representative_module {
    my($self) = @_;
    return $self->{_is_representative_module} if defined $self->{_is_representative_module};
    my $pm = $self->cpan_file or return $self->{_is_representative_module} = 0;
    $pm =~ s|.+/||;
    $pm =~ s{\.(?:tar\.(bz2|gz|Z)|t(?:gz|bz)|zip)$}{}i; # see base_id
    $pm =~ s|-\d+\.\d+.+$||;
    $pm =~ s|-[\d\.]+$||;
    $pm =~ s/-/::/g;
    $self->{_is_representative_module} = $pm eq $self->{ID} ? 1 : 0;
    # warn "DEBUG: $pm eq $self->{ID} => $self->{_is_representative_module}";
    $self->{_is_representative_module};
}

#-> sub CPAN::Module::undelay
sub undelay {
    my $self = shift;
    delete $self->{later};
    if ( my $dist = CPAN::Shell->expand("Distribution", $self->cpan_file) ) {
        $dist->undelay;
    }
}

# mark as dirty/clean
#-> sub CPAN::Module::color_cmd_tmps ;
sub color_cmd_tmps {
    my($self) = shift;
    my($depth) = shift || 0;
    my($color) = shift || 0;
    my($ancestors) = shift || [];
    # a module needs to recurse to its cpan_file

    return if exists $self->{incommandcolor}
        && $color==1
        && $self->{incommandcolor}==$color;
    return if $color==0 && !$self->{incommandcolor};
    if ($color>=1) {
        if ( $self->uptodate ) {
            $self->{incommandcolor} = $color;
            return;
        } elsif (my $have_version = $self->available_version) {
            # maybe what we have is good enough
            if (@$ancestors) {
                my $who_asked_for_me = $ancestors->[-1];
                my $obj = CPAN::Shell->expandany($who_asked_for_me);
                if (0) {
                } elsif ($obj->isa("CPAN::Bundle")) {
                    # bundles cannot specify a minimum version
                    return;
                } elsif ($obj->isa("CPAN::Distribution")) {
                    if (my $prereq_pm = $obj->prereq_pm) {
                        for my $k (keys %$prereq_pm) {
                            if (my $want_version = $prereq_pm->{$k}{$self->id}) {
                                if (CPAN::Version->vcmp($have_version,$want_version) >= 0) {
                                    $self->{incommandcolor} = $color;
                                    return;
                                }
                            }
                        }
                    }
                }
            }
        }
    } else {
        $self->{incommandcolor} = $color; # set me before recursion,
                                          # so we can break it
    }
    if ($depth>=$CPAN::MAX_RECURSION) {
        my $e = CPAN::Exception::RecursiveDependency->new($ancestors);
        if ($e->is_resolvable) {
            return $self->{incommandcolor}=2;
        } else {
            die $e;
        }
    }
    # warn "color_cmd_tmps $depth $color " . $self->id; # sleep 1;

    if ( my $dist = CPAN::Shell->expand("Distribution", $self->cpan_file) ) {
        $dist->color_cmd_tmps($depth+1,$color,[@$ancestors, $self->id]);
    }
    # unreached code?
    # if ($color==0) {
    #    delete $self->{badtestcnt};
    # }
    $self->{incommandcolor} = $color;
}

#-> sub CPAN::Module::as_glimpse ;
sub as_glimpse {
    my($self) = @_;
    my(@m);
    my $class = ref($self);
    $class =~ s/^CPAN:://;
    my $color_on = "";
    my $color_off = "";
    if (
        $CPAN::Shell::COLOR_REGISTERED
        &&
        $CPAN::META->has_inst("Term::ANSIColor")
        &&
        $self->description
       ) {
        $color_on = Term::ANSIColor::color("green");
        $color_off = Term::ANSIColor::color("reset");
    }
    my $uptodateness = " ";
    unless ($class eq "Bundle") {
        my $u = $self->uptodate;
        $uptodateness = $u ? "=" : "<" if defined $u;
    };
    my $id = do {
        my $d = $self->distribution;
        $d ? $d -> pretty_id : $self->cpan_userid;
    };
    push @m, sprintf("%-7s %1s %s%-22s%s (%s)\n",
                     $class,
                     $uptodateness,
                     $color_on,
                     $self->id,
                     $color_off,
                     $id,
                    );
    join "", @m;
}

#-> sub CPAN::Module::dslip_status
sub dslip_status {
    my($self) = @_;
    my($stat);
    # development status
    @{$stat->{D}}{qw,i c a b R M S,}     = qw,idea
                                              pre-alpha alpha beta released
                                              mature standard,;
    # support level
    @{$stat->{S}}{qw,m d u n a,}         = qw,mailing-list
                                              developer comp.lang.perl.*
                                              none abandoned,;
    # language
    @{$stat->{L}}{qw,p c + o h,}         = qw,perl C C++ other hybrid,;
    # interface
    @{$stat->{I}}{qw,f r O p h n,}       = qw,functions
                                              references+ties
                                              object-oriented pragma
                                              hybrid none,;
    # public licence
    @{$stat->{P}}{qw,p g l b a 2 o d r n,} = qw,Standard-Perl
                                              GPL LGPL
                                              BSD Artistic Artistic_2
                                              open-source
                                              distribution_allowed
                                              restricted_distribution
                                              no_licence,;
    for my $x (qw(d s l i p)) {
        $stat->{$x}{' '} = 'unknown';
        $stat->{$x}{'?'} = 'unknown';
    }
    my $ro = $self->ro;
    return +{} unless $ro && $ro->{statd};
    return {
            D  => $ro->{statd},
            S  => $ro->{stats},
            L  => $ro->{statl},
            I  => $ro->{stati},
            P  => $ro->{statp},
            DV => $stat->{D}{$ro->{statd}},
            SV => $stat->{S}{$ro->{stats}},
            LV => $stat->{L}{$ro->{statl}},
            IV => $stat->{I}{$ro->{stati}},
            PV => $stat->{P}{$ro->{statp}},
           };
}

#-> sub CPAN::Module::as_string ;
sub as_string {
    my($self) = @_;
    my(@m);
    CPAN->debug("$self entering as_string") if $CPAN::DEBUG;
    my $class = ref($self);
    $class =~ s/^CPAN:://;
    local($^W) = 0;
    push @m, $class, " id = $self->{ID}\n";
    my $sprintf = "    %-12s %s\n";
    push @m, sprintf($sprintf, 'DESCRIPTION', $self->description)
        if $self->description;
    my $sprintf2 = "    %-12s %s (%s)\n";
    my($userid);
    $userid = $self->userid;
    if ( $userid ) {
        my $author;
        if ($author = CPAN::Shell->expand('Author',$userid)) {
            my $email = "";
            my $m; # old perls
            if ($m = $author->email) {
                $email = " <$m>";
            }
            push @m, sprintf(
                             $sprintf2,
                             'CPAN_USERID',
                             $userid,
                             $author->fullname . $email
                            );
        }
    }
    push @m, sprintf($sprintf, 'CPAN_VERSION', $self->cpan_version)
        if $self->cpan_version;
    if (my $cpan_file = $self->cpan_file) {
        push @m, sprintf($sprintf, 'CPAN_FILE', $cpan_file);
        if (my $dist = CPAN::Shell->expand("Distribution",$cpan_file)) {
            my $upload_date = $dist->upload_date;
            if ($upload_date) {
                push @m, sprintf($sprintf, 'UPLOAD_DATE', $upload_date);
            }
        }
    }
    my $sprintf3 = "    %-12s %1s%1s%1s%1s%1s (%s,%s,%s,%s,%s)\n";
    my $dslip = $self->dslip_status;
    push @m, sprintf(
                     $sprintf3,
                     'DSLIP_STATUS',
                     @{$dslip}{qw(D S L I P DV SV LV IV PV)},
                    ) if $dslip->{D};
    my $local_file = $self->inst_file;
    unless ($self->{MANPAGE}) {
        my $manpage;
        if ($local_file) {
            $manpage = $self->manpage_headline($local_file);
        } else {
            # If we have already untarred it, we should look there
            my $dist = $CPAN::META->instance('CPAN::Distribution',
                                             $self->cpan_file);
            # warn "dist[$dist]";
            # mff=manifest file; mfh=manifest handle
            my($mff,$mfh);
            if (
                $dist->{build_dir}
                and
                (-f  ($mff = File::Spec->catfile($dist->{build_dir}, "MANIFEST")))
                and
                $mfh = FileHandle->new($mff)
               ) {
                CPAN->debug("mff[$mff]") if $CPAN::DEBUG;
                my $lfre = $self->id; # local file RE
                $lfre =~ s/::/./g;
                $lfre .= "\\.pm\$";
                my($lfl); # local file file
                local $/ = "\n";
                my(@mflines) = <$mfh>;
                for (@mflines) {
                    s/^\s+//;
                    s/\s.*//s;
                }
                while (length($lfre)>5 and !$lfl) {
                    ($lfl) = grep /$lfre/, @mflines;
                    CPAN->debug("lfl[$lfl]lfre[$lfre]") if $CPAN::DEBUG;
                    $lfre =~ s/.+?\.//;
                }
                $lfl =~ s/\s.*//; # remove comments
                $lfl =~ s/\s+//g; # chomp would maybe be too system-specific
                my $lfl_abs = File::Spec->catfile($dist->{build_dir},$lfl);
                # warn "lfl_abs[$lfl_abs]";
                if (-f $lfl_abs) {
                    $manpage = $self->manpage_headline($lfl_abs);
                }
            }
        }
        $self->{MANPAGE} = $manpage if $manpage;
    }
    my($item);
    for $item (qw/MANPAGE/) {
        push @m, sprintf($sprintf, $item, $self->{$item})
            if exists $self->{$item};
    }
    for $item (qw/CONTAINS/) {
        push @m, sprintf($sprintf, $item, join(" ",@{$self->{$item}}))
            if exists $self->{$item} && @{$self->{$item}};
    }
    push @m, sprintf($sprintf, 'INST_FILE',
                     $local_file || "(not installed)");
    push @m, sprintf($sprintf, 'INST_VERSION',
                     $self->inst_version) if $local_file;
    if (%{$CPAN::META->{is_tested}||{}}) { # XXX needs to be methodified somehow
        my $available_file = $self->available_file;
        if ($available_file && $available_file ne $local_file) {
            push @m, sprintf($sprintf, 'AVAILABLE_FILE', $available_file);
            push @m, sprintf($sprintf, 'AVAILABLE_VERSION', $self->available_version);
        }
    }
    join "", @m, "\n";
}

#-> sub CPAN::Module::manpage_headline
sub manpage_headline {
    my($self,$local_file) = @_;
    my(@local_file) = $local_file;
    $local_file =~ s/\.pm(?!\n)\Z/.pod/;
    push @local_file, $local_file;
    my(@result,$locf);
    for $locf (@local_file) {
        next unless -f $locf;
        my $fh = FileHandle->new($locf)
            or $Carp::Frontend->mydie("Couldn't open $locf: $!");
        my $inpod = 0;
        local $/ = "\n";
        while (<$fh>) {
            $inpod = m/^=(?!head1\s+NAME\s*$)/ ? 0 :
                m/^=head1\s+NAME\s*$/ ? 1 : $inpod;
            next unless $inpod;
            next if /^=/;
            next if /^\s+$/;
            chomp;
            push @result, $_;
        }
        close $fh;
        last if @result;
    }
    for (@result) {
        s/^\s+//;
        s/\s+$//;
    }
    join " ", @result;
}

#-> sub CPAN::Module::cpan_file ;
# Note: also inherited by CPAN::Bundle
sub cpan_file {
    my $self = shift;
    # CPAN->debug(sprintf "id[%s]", $self->id) if $CPAN::DEBUG;
    unless ($self->ro) {
        CPAN::Index->reload;
    }
    my $ro = $self->ro;
    if ($ro && defined $ro->{CPAN_FILE}) {
        return $ro->{CPAN_FILE};
    } else {
        my $userid = $self->userid;
        if ( $userid ) {
            if ($CPAN::META->exists("CPAN::Author",$userid)) {
                my $author = $CPAN::META->instance("CPAN::Author",
                                                   $userid);
                my $fullname = $author->fullname;
                my $email = $author->email;
                unless (defined $fullname && defined $email) {
                    return sprintf("Contact Author %s",
                                   $userid,
                                  );
                }
                return "Contact Author $fullname <$email>";
            } else {
                return "Contact Author $userid (Email address not available)";
            }
        } else {
            return "N/A";
        }
    }
}

#-> sub CPAN::Module::cpan_version ;
sub cpan_version {
    my $self = shift;

    my $ro = $self->ro;
    unless ($ro) {
        # Can happen with modules that are not on CPAN
        $ro = {};
    }
    $ro->{CPAN_VERSION} = 'undef'
        unless defined $ro->{CPAN_VERSION};
    $ro->{CPAN_VERSION};
}

#-> sub CPAN::Module::force ;
sub force {
    my($self) = @_;
    $self->{force_update} = 1;
}

#-> sub CPAN::Module::fforce ;
sub fforce {
    my($self) = @_;
    $self->{force_update} = 2;
}

#-> sub CPAN::Module::notest ;
sub notest {
    my($self) = @_;
    # $CPAN::Frontend->mywarn("XDEBUG: set notest for Module");
    $self->{notest}++;
}

#-> sub CPAN::Module::rematein ;
sub rematein {
    my($self,$meth) = @_;
    $CPAN::Frontend->myprint(sprintf("Running %s for module '%s'\n",
                                     $meth,
                                     $self->id));
    my $cpan_file = $self->cpan_file;
    if ($cpan_file eq "N/A" || $cpan_file =~ /^Contact Author/) {
        $CPAN::Frontend->mywarn(sprintf qq{
  The module %s isn\'t available on CPAN.

  Either the module has not yet been uploaded to CPAN, or it is
  temporary unavailable. Please contact the author to find out
  more about the status. Try 'i %s'.
},
                                $self->id,
                                $self->id,
                               );
        return;
    }
    my $pack = $CPAN::META->instance('CPAN::Distribution',$cpan_file);
    $pack->called_for($self->id);
    if (exists $self->{force_update}) {
        if ($self->{force_update} == 2) {
            $pack->fforce($meth);
        } else {
            $pack->force($meth);
        }
    }
    $pack->notest($meth) if exists $self->{notest} && $self->{notest};

    $pack->{reqtype} ||= "";
    CPAN->debug("dist-reqtype[$pack->{reqtype}]".
                "self-reqtype[$self->{reqtype}]") if $CPAN::DEBUG;
        if ($pack->{reqtype}) {
            if ($pack->{reqtype} eq "b" && $self->{reqtype} =~ /^[rc]$/) {
                $pack->{reqtype} = $self->{reqtype};
                if (
                    exists $pack->{install}
                    &&
                    (
                     UNIVERSAL::can($pack->{install},"failed") ?
                     $pack->{install}->failed :
                     $pack->{install} =~ /^NO/
                    )
                   ) {
                    delete $pack->{install};
                    $CPAN::Frontend->mywarn
                        ("Promoting $pack->{ID} from 'build_requires' to 'requires'");
                }
            }
        } else {
            $pack->{reqtype} = $self->{reqtype};
        }

    my $success = eval {
        $pack->$meth();
    };
    my $err = $@;
    $pack->unforce if $pack->can("unforce") && exists $self->{force_update};
    $pack->unnotest if $pack->can("unnotest") && exists $self->{notest};
    delete $self->{force_update};
    delete $self->{notest};
    if ($err) {
        die $err;
    }
    return $success;
}

#-> sub CPAN::Module::perldoc ;
sub perldoc { shift->rematein('perldoc') }
#-> sub CPAN::Module::readme ;
sub readme  { shift->rematein('readme') }
#-> sub CPAN::Module::look ;
sub look    { shift->rematein('look') }
#-> sub CPAN::Module::cvs_import ;
sub cvs_import { shift->rematein('cvs_import') }
#-> sub CPAN::Module::get ;
sub get     { shift->rematein('get',@_) }
#-> sub CPAN::Module::make ;
sub make    { shift->rematein('make') }
#-> sub CPAN::Module::test ;
sub test   {
    my $self = shift;
    # $self->{badtestcnt} ||= 0;
    $self->rematein('test',@_);
}

#-> sub CPAN::Module::deprecated_in_core ;
sub deprecated_in_core {
    my ($self) = @_;
    return unless $CPAN::META->has_inst('Module::CoreList') && Module::CoreList->can('is_deprecated');
    return Module::CoreList::is_deprecated($self->{ID});
}

#-> sub CPAN::Module::inst_deprecated;
# Indicates whether the *installed* version of the module is a deprecated *and*
# installed as part of the Perl core library path
sub inst_deprecated {
    my ($self) = @_;
    my $inst_file = $self->inst_file or return;
    return $self->deprecated_in_core && $self->_in_priv_or_arch($inst_file);
}

#-> sub CPAN::Module::uptodate ;
sub uptodate {
    my ($self) = @_;
    local ($_);
    my $inst = $self->inst_version or return 0;
    my $cpan = $self->cpan_version;
    return 0 if CPAN::Version->vgt($cpan,$inst) || $self->inst_deprecated;
    CPAN->debug
        (join
         ("",
          "returning uptodate. ",
          "cpan[$cpan]inst[$inst]",
         )) if $CPAN::DEBUG;
    return 1;
}

# returns true if installed in privlib or archlib
sub _in_priv_or_arch {
    my($self,$inst_file) = @_;
    foreach my $pair (
        [qw(sitearchexp archlibexp)],
        [qw(sitelibexp privlibexp)]
    ) {
        my ($site, $priv) = @Config::Config{@$pair};
        if ($^O eq 'VMS') {
            for my $d ($site, $priv) { $d = VMS::Filespec::unixify($d) };
        }
        s!/*$!!g foreach $site, $priv;
        next if $site eq $priv;

        if ($priv eq substr($inst_file,0,length($priv))) {
            return 1;
        }
    }
    return 0;
}

#-> sub CPAN::Module::install ;
sub install {
    my($self) = @_;
    my($doit) = 0;
    if ($self->uptodate
        &&
        not exists $self->{force_update}
       ) {
        $CPAN::Frontend->myprint(sprintf("%s is up to date (%s).\n",
                                         $self->id,
                                         $self->inst_version,
                                        ));
    } else {
        $doit = 1;
    }
    my $ro = $self->ro;
    if ($ro && $ro->{stats} && $ro->{stats} eq "a") {
        $CPAN::Frontend->mywarn(qq{
\n\n\n     ***WARNING***
     The module $self->{ID} has no active maintainer (CPAN support level flag 'abandoned').\n\n\n
});
        $CPAN::Frontend->mysleep(5);
    }
    return $doit ? $self->rematein('install') : 1;
}
#-> sub CPAN::Module::clean ;
sub clean  { shift->rematein('clean') }

#-> sub CPAN::Module::inst_file ;
sub inst_file {
    my($self) = @_;
    $self->_file_in_path([@INC]);
}

#-> sub CPAN::Module::available_file ;
sub available_file {
    my($self) = @_;
    my $sep = $Config::Config{path_sep};
    my $perllib = $ENV{PERL5LIB};
    $perllib = $ENV{PERLLIB} unless defined $perllib;
    my @perllib = split(/$sep/,$perllib) if defined $perllib;
    my @cpan_perl5inc;
    if ($CPAN::Perl5lib_tempfile) {
        my $yaml = CPAN->_yaml_loadfile($CPAN::Perl5lib_tempfile);
        @cpan_perl5inc = @{$yaml->[0]{inc} || []};
    }
    $self->_file_in_path([@cpan_perl5inc,@perllib,@INC]);
}

#-> sub CPAN::Module::file_in_path ;
sub _file_in_path {
    my($self,$path) = @_;
    my($dir,@packpath);
    @packpath = split /::/, $self->{ID};
    $packpath[-1] .= ".pm";
    if (@packpath == 1 && $packpath[0] eq "readline.pm") {
        unshift @packpath, "Term", "ReadLine"; # historical reasons
    }
    foreach $dir (@$path) {
        my $pmfile = File::Spec->catfile($dir,@packpath);
        if (-f $pmfile) {
            return $pmfile;
        }
    }
    return;
}

#-> sub CPAN::Module::xs_file ;
sub xs_file {
    my($self) = @_;
    my($dir,@packpath);
    @packpath = split /::/, $self->{ID};
    push @packpath, $packpath[-1];
    $packpath[-1] .= "." . $Config::Config{'dlext'};
    foreach $dir (@INC) {
        my $xsfile = File::Spec->catfile($dir,'auto',@packpath);
        if (-f $xsfile) {
            return $xsfile;
        }
    }
    return;
}

#-> sub CPAN::Module::inst_version ;
sub inst_version {
    my($self) = @_;
    my $parsefile = $self->inst_file or return;
    my $have = $self->parse_version($parsefile);
    $have;
}

#-> sub CPAN::Module::inst_version ;
sub available_version {
    my($self) = @_;
    my $parsefile = $self->available_file or return;
    my $have = $self->parse_version($parsefile);
    $have;
}

#-> sub CPAN::Module::parse_version ;
sub parse_version {
    my($self,$parsefile) = @_;
    if (ALARM_IMPLEMENTED) {
        my $timeout = (exists($CPAN::Config{'version_timeout'}))
                            ? $CPAN::Config{'version_timeout'}
                            : 15;
        alarm($timeout);
    }
    my $have = eval {
        local $SIG{ALRM} = sub { die "alarm\n" };
        MM->parse_version($parsefile);
    };
    if ($@) {
        $CPAN::Frontend->mywarn("Error while parsing version number in file '$parsefile'\n");
    }
    alarm(0) if ALARM_IMPLEMENTED;
    my $leastsanity = eval { defined $have && length $have; };
    $have = "undef" unless $leastsanity;
    $have =~ s/^ //; # since the %vd hack these two lines here are needed
    $have =~ s/ $//; # trailing whitespace happens all the time

    $have = CPAN::Version->readable($have);

    $have =~ s/\s*//g; # stringify to float around floating point issues
    $have; # no stringify needed, \s* above matches always
}

#-> sub CPAN::Module::reports
sub reports {
    my($self) = @_;
    $self->distribution->reports;
}

1;
PK7N%[n3�y..perl5/CPAN/Version.pmnu��6�$package CPAN::Version;

use strict;
use vars qw($VERSION);
$VERSION = "5.5003";

# CPAN::Version::vcmp courtesy Jost Krieger
sub vcmp {
    my($self,$l,$r) = @_;
    local($^W) = 0;
    CPAN->debug("l[$l] r[$r]") if $CPAN::DEBUG;

    # treat undef as zero
    $l = 0 if $l eq 'undef';
    $r = 0 if $r eq 'undef';

    return 0 if $l eq $r; # short circuit for quicker success

    for ($l,$r) {
        s/_//g;
    }
    CPAN->debug("l[$l] r[$r]") if $CPAN::DEBUG;
    for ($l,$r) {
        next unless tr/.// > 1 || /^v/;
        s/^v?/v/;
        1 while s/\.0+(\d)/.$1/; # remove leading zeroes per group
    }
    CPAN->debug("l[$l] r[$r]") if $CPAN::DEBUG;
    if ($l=~/^v/ <=> $r=~/^v/) {
        for ($l,$r) {
            next if /^v/;
            $_ = $self->float2vv($_);
        }
    }
    CPAN->debug("l[$l] r[$r]") if $CPAN::DEBUG;
    my $lvstring = "v0";
    my $rvstring = "v0";
    if ($] >= 5.006
     && $l =~ /^v/
     && $r =~ /^v/) {
        $lvstring = $self->vstring($l);
        $rvstring = $self->vstring($r);
        CPAN->debug(sprintf "lv[%vd] rv[%vd]", $lvstring, $rvstring) if $CPAN::DEBUG;
    }

    return (
            ($l ne "undef") <=> ($r ne "undef")
            ||
            $lvstring cmp $rvstring
            ||
            $l <=> $r
            ||
            $l cmp $r
    );
}

sub vgt {
    my($self,$l,$r) = @_;
    $self->vcmp($l,$r) > 0;
}

sub vlt {
    my($self,$l,$r) = @_;
    $self->vcmp($l,$r) < 0;
}

sub vge {
    my($self,$l,$r) = @_;
    $self->vcmp($l,$r) >= 0;
}

sub vle {
    my($self,$l,$r) = @_;
    $self->vcmp($l,$r) <= 0;
}

sub vstring {
    my($self,$n) = @_;
    $n =~ s/^v// or die "CPAN::Version::vstring() called with invalid arg [$n]";
    pack "U*", split /\./, $n;
}

# vv => visible vstring
sub float2vv {
    my($self,$n) = @_;
    my($rev) = int($n);
    $rev ||= 0;
    my($mantissa) = $n =~ /\.(\d{1,12})/; # limit to 12 digits to limit
                                          # architecture influence
    $mantissa ||= 0;
    $mantissa .= "0" while length($mantissa)%3;
    my $ret = "v" . $rev;
    while ($mantissa) {
        $mantissa =~ s/(\d{1,3})// or
            die "Panic: length>0 but not a digit? mantissa[$mantissa]";
        $ret .= ".".int($1);
    }
    # warn "n[$n]ret[$ret]";
    $ret =~ s/(\.0)+/.0/; # v1.0.0 => v1.0
    $ret;
}

sub readable {
    my($self,$n) = @_;
    $n =~ /^([\w\-\+\.]+)/;

    return $1 if defined $1 && length($1)>0;
    # if the first user reaches version v43, he will be treated as "+".
    # We'll have to decide about a new rule here then, depending on what
    # will be the prevailing versioning behavior then.

    if ($] < 5.006) { # or whenever v-strings were introduced
        # we get them wrong anyway, whatever we do, because 5.005 will
        # have already interpreted 0.2.4 to be "0.24". So even if he
        # indexer sends us something like "v0.2.4" we compare wrongly.

        # And if they say v1.2, then the old perl takes it as "v12"

        if (defined $CPAN::Frontend) {
            $CPAN::Frontend->mywarn("Suspicious version string seen [$n]\n");
        } else {
            warn("Suspicious version string seen [$n]\n");
        }
        return $n;
    }
    my $better = sprintf "v%vd", $n;
    CPAN->debug("n[$n] better[$better]") if $CPAN::DEBUG;
    return $better;
}

1;

__END__

=head1 NAME

CPAN::Version - utility functions to compare CPAN versions

=head1 SYNOPSIS

  use CPAN::Version;

  CPAN::Version->vgt("1.1","1.1.1");    # 1 bc. 1.1 > 1.001001

  CPAN::Version->vlt("1.1","1.1");      # 0 bc. 1.1 not < 1.1

  CPAN::Version->vcmp("1.1","1.1.1");   # 1 bc. first is larger

  CPAN::Version->vcmp("1.1.1","1.1");   # -1 bc. first is smaller

  CPAN::Version->readable(v1.2.3);      # "v1.2.3"

  CPAN::Version->vstring("v1.2.3");     # v1.2.3

  CPAN::Version->float2vv(1.002003);    # "v1.2.3"

=head1 DESCRIPTION

This module mediates between some version that perl sees in a package
and the version that is published by the CPAN indexer.

It's only written as a helper module for both CPAN.pm and CPANPLUS.pm.

As it stands it predates version.pm but has the same goal: make
version strings visible and comparable.

=head1 LICENSE

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

=cut

# Local Variables:
# mode: cperl
# cperl-indent-level: 4
# End:
PK7N%[< $l:M:M%perl5/CPAN/Meta/Requirements/Range.pmnu��6�$use v5.10;
use strict;
use warnings;
package CPAN::Meta::Requirements::Range;
# ABSTRACT: a set of version requirements for a CPAN dist

our $VERSION = '2.143';

use Carp ();

#pod =head1 SYNOPSIS
#pod
#pod   use CPAN::Meta::Requirements::Range;
#pod
#pod   my $range = CPAN::Meta::Requirements::Range->with_minimum(1);
#pod
#pod   $range = $range->with_maximum('v2.2');
#pod
#pod   my $stringified = $range->as_string;
#pod
#pod =head1 DESCRIPTION
#pod
#pod A CPAN::Meta::Requirements::Range object models a set of version constraints like
#pod those specified in the F<META.yml> or F<META.json> files in CPAN distributions,
#pod and as defined by L<CPAN::Meta::Spec>;
#pod It can be built up by adding more and more constraints, and it will reduce them
#pod to the simplest representation.
#pod
#pod Logically impossible constraints will be identified immediately by thrown
#pod exceptions.
#pod
#pod =cut

use Carp ();

package
  CPAN::Meta::Requirements::Range::_Base;

# To help ExtUtils::MakeMaker bootstrap CPAN::Meta::Requirements on perls
# before 5.10, we fall back to the EUMM bundled compatibility version module if
# that's the only thing available.  This shouldn't ever happen in a normal CPAN
# install of CPAN::Meta::Requirements, as version.pm will be picked up from
# prereqs and be available at runtime.

BEGIN {
  eval "use version ()"; ## no critic
  if ( my $err = $@ ) {
    eval "use ExtUtils::MakeMaker::version" or die $err; ## no critic
  }
}

# from version::vpp
sub _find_magic_vstring {
  my $value = shift;
  my $tvalue = '';
  require B;
  my $sv = B::svref_2object(\$value);
  my $magic = ref($sv) eq 'B::PVMG' ? $sv->MAGIC : undef;
  while ( $magic ) {
    if ( $magic->TYPE eq 'V' ) {
      $tvalue = $magic->PTR;
      $tvalue =~ s/^v?(.+)$/v$1/;
      last;
    }
    else {
      $magic = $magic->MOREMAGIC;
    }
  }
  return $tvalue;
}

# Perl 5.10.0 didn't have "is_qv" in version.pm
*_is_qv = version->can('is_qv') ? sub { $_[0]->is_qv } : sub { exists $_[0]->{qv} };

# construct once, reuse many times
my $V0 = version->new(0);

# safe if given an unblessed reference
sub _isa_version {
  UNIVERSAL::isa( $_[0], 'UNIVERSAL' ) && $_[0]->isa('version')
}

sub _version_object {
  my ($self, $version, $module, $bad_version_hook) = @_;

  my ($vobj, $err);

  if (not defined $version or (!ref($version) && $version eq '0')) {
    return $V0;
  }
  elsif ( ref($version) eq 'version' || ( ref($version) && _isa_version($version) ) ) {
    $vobj = $version;
  }
  else {
    # hack around version::vpp not handling <3 character vstring literals
    if ( $INC{'version/vpp.pm'} || $INC{'ExtUtils/MakeMaker/version/vpp.pm'} ) {
      my $magic = _find_magic_vstring( $version );
      $version = $magic if length $magic;
    }
    # pad to 3 characters if before 5.8.1 and appears to be a v-string
    if ( $] < 5.008001 && $version !~ /\A[0-9]/ && substr($version,0,1) ne 'v' && length($version) < 3 ) {
      $version .= "\0" x (3 - length($version));
    }
    eval {
      local $SIG{__WARN__} = sub { die "Invalid version: $_[0]" };
      # avoid specific segfault on some older version.pm versions
      die "Invalid version: $version" if $version eq 'version';
      $vobj = version->new($version);
    };
    if ( my $err = $@ ) {
      $vobj = eval { $bad_version_hook->($version, $module) }
        if ref $bad_version_hook eq 'CODE';
      unless (eval { $vobj->isa("version") }) {
        $err =~ s{ at .* line \d+.*$}{};
        die "Can't convert '$version': $err";
      }
    }
  }

  # ensure no leading '.'
  if ( $vobj =~ m{\A\.} ) {
    $vobj = version->new("0$vobj");
  }

  # ensure normal v-string form
  if ( _is_qv($vobj) ) {
    $vobj = version->new($vobj->normal);
  }

  return $vobj;
}

#pod =method with_string_requirement
#pod
#pod   $req->with_string_requirement('>= 1.208, <= 2.206');
#pod   $req->with_string_requirement(v1.208);
#pod
#pod This method parses the passed in string and adds the appropriate requirement.
#pod A version can be a Perl "v-string".  It understands version ranges as described
#pod in the L<CPAN::Meta::Spec/Version Ranges>. For example:
#pod
#pod =over 4
#pod
#pod =item 1.3
#pod
#pod =item >= 1.3
#pod
#pod =item <= 1.3
#pod
#pod =item == 1.3
#pod
#pod =item != 1.3
#pod
#pod =item > 1.3
#pod
#pod =item < 1.3
#pod
#pod =item >= 1.3, != 1.5, <= 2.0
#pod
#pod A version number without an operator is equivalent to specifying a minimum
#pod (C<E<gt>=>).  Extra whitespace is allowed.
#pod
#pod =back
#pod
#pod =cut

my %methods_for_op = (
  '==' => [ qw(with_exact_version) ],
  '!=' => [ qw(with_exclusion) ],
  '>=' => [ qw(with_minimum)   ],
  '<=' => [ qw(with_maximum)   ],
  '>'  => [ qw(with_minimum with_exclusion) ],
  '<'  => [ qw(with_maximum with_exclusion) ],
);

sub with_string_requirement {
  my ($self, $req, $module, $bad_version_hook) = @_;
  $module //= 'module';

  unless ( defined $req && length $req ) {
    $req = 0;
    Carp::carp("Undefined requirement for $module treated as '0'");
  }

  my $magic = _find_magic_vstring( $req );
  if (length $magic) {
    return $self->with_minimum($magic, $module, $bad_version_hook);
  }

  my @parts = split qr{\s*,\s*}, $req;

  for my $part (@parts) {
    my ($op, $ver) = $part =~ m{\A\s*(==|>=|>|<=|<|!=)\s*(.*)\z};

    if (! defined $op) {
      $self = $self->with_minimum($part, $module, $bad_version_hook);
    } else {
      Carp::croak("illegal requirement string: $req")
        unless my $methods = $methods_for_op{ $op };

      $self = $self->$_($ver, $module, $bad_version_hook) for @$methods;
    }
  }

  return $self;
}

#pod =method with_range
#pod
#pod  $range->with_range($other_range)
#pod
#pod This creates a new range object that is a merge two others.
#pod
#pod =cut

sub with_range {
  my ($self, $other, $module, $bad_version_hook) = @_;
  for my $modifier($other->_as_modifiers) {
    my ($method, $arg) = @$modifier;
    $self = $self->$method($arg, $module, $bad_version_hook);
  }
  return $self;
}

package CPAN::Meta::Requirements::Range;

our @ISA = 'CPAN::Meta::Requirements::Range::_Base';

sub _clone {
  return (bless { } => $_[0]) unless ref $_[0];

  my ($s) = @_;
  my %guts = (
    (exists $s->{minimum} ? (minimum => version->new($s->{minimum})) : ()),
    (exists $s->{maximum} ? (maximum => version->new($s->{maximum})) : ()),

    (exists $s->{exclusions}
      ? (exclusions => [ map { version->new($_) } @{ $s->{exclusions} } ])
      : ()),
  );

  bless \%guts => ref($s);
}

#pod =method with_exact_version
#pod
#pod   $range->with_exact_version( $version );
#pod
#pod This sets the version required to I<exactly> the given
#pod version.  No other version would be considered acceptable.
#pod
#pod This method returns the version range object.
#pod
#pod =cut

sub with_exact_version {
  my ($self, $version, $module, $bad_version_hook) = @_;
  $module //= 'module';
  $self = $self->_clone;
  $version = $self->_version_object($version, $module, $bad_version_hook);

  unless ($self->accepts($version)) {
    $self->_reject_requirements(
      $module,
      "exact specification $version outside of range " . $self->as_string
    );
  }

  return CPAN::Meta::Requirements::Range::_Exact->_new($version);
}

sub _simplify {
  my ($self, $module) = @_;

  if (defined $self->{minimum} and defined $self->{maximum}) {
    if ($self->{minimum} == $self->{maximum}) {
      if (grep { $_ == $self->{minimum} } @{ $self->{exclusions} || [] }) {
        $self->_reject_requirements(
          $module,
          "minimum and maximum are both $self->{minimum}, which is excluded",
        );
      }

      return CPAN::Meta::Requirements::Range::_Exact->_new($self->{minimum});
    }

    if ($self->{minimum} > $self->{maximum}) {
      $self->_reject_requirements(
        $module,
        "minimum $self->{minimum} exceeds maximum $self->{maximum}",
      );
    }
  }

  # eliminate irrelevant exclusions
  if ($self->{exclusions}) {
    my %seen;
    @{ $self->{exclusions} } = grep {
      (! defined $self->{minimum} or $_ >= $self->{minimum})
      and
      (! defined $self->{maximum} or $_ <= $self->{maximum})
      and
      ! $seen{$_}++
    } @{ $self->{exclusions} };
  }

  return $self;
}

#pod =method with_minimum
#pod
#pod   $range->with_minimum( $version );
#pod
#pod This adds a new minimum version requirement.  If the new requirement is
#pod redundant to the existing specification, this has no effect.
#pod
#pod Minimum requirements are inclusive.  C<$version> is required, along with any
#pod greater version number.
#pod
#pod This method returns the version range object.
#pod
#pod =cut

sub with_minimum {
  my ($self, $minimum, $module, $bad_version_hook) = @_;
  $module //= 'module';
  $self = $self->_clone;
  $minimum = $self->_version_object( $minimum, $module, $bad_version_hook );

  if (defined (my $old_min = $self->{minimum})) {
    $self->{minimum} = (sort { $b cmp $a } ($minimum, $old_min))[0];
  } else {
    $self->{minimum} = $minimum;
  }

  return $self->_simplify($module);
}

#pod =method with_maximum
#pod
#pod   $range->with_maximum( $version );
#pod
#pod This adds a new maximum version requirement.  If the new requirement is
#pod redundant to the existing specification, this has no effect.
#pod
#pod Maximum requirements are inclusive.  No version strictly greater than the given
#pod version is allowed.
#pod
#pod This method returns the version range object.
#pod
#pod =cut

sub with_maximum {
  my ($self, $maximum, $module, $bad_version_hook) = @_;
  $module //= 'module';
  $self = $self->_clone;
  $maximum = $self->_version_object( $maximum, $module, $bad_version_hook );

  if (defined (my $old_max = $self->{maximum})) {
    $self->{maximum} = (sort { $a cmp $b } ($maximum, $old_max))[0];
  } else {
    $self->{maximum} = $maximum;
  }

  return $self->_simplify($module);
}

#pod =method with_exclusion
#pod
#pod   $range->with_exclusion( $version );
#pod
#pod This adds a new excluded version.  For example, you might use these three
#pod method calls:
#pod
#pod   $range->with_minimum( '1.00' );
#pod   $range->with_maximum( '1.82' );
#pod
#pod   $range->with_exclusion( '1.75' );
#pod
#pod Any version between 1.00 and 1.82 inclusive would be acceptable, except for
#pod 1.75.
#pod
#pod This method returns the requirements object.
#pod
#pod =cut

sub with_exclusion {
  my ($self, $exclusion, $module, $bad_version_hook) = @_;
  $module //= 'module';
  $self = $self->_clone;
  $exclusion = $self->_version_object( $exclusion, $module, $bad_version_hook );

  push @{ $self->{exclusions} ||= [] }, $exclusion;

  return $self->_simplify($module);
}

sub _as_modifiers {
  my ($self) = @_;
  my @mods;
  push @mods, [ with_minimum => $self->{minimum} ] if exists $self->{minimum};
  push @mods, [ with_maximum => $self->{maximum} ] if exists $self->{maximum};
  push @mods, map {; [ with_exclusion => $_ ] } @{$self->{exclusions} || []};
  return @mods;
}

#pod =method as_struct
#pod
#pod   $range->as_struct( $module );
#pod
#pod This returns a data structure containing the version requirements. This should
#pod not be used for version checks (see L</accepts_module> instead).
#pod
#pod =cut

sub as_struct {
  my ($self) = @_;

  return 0 if ! keys %$self;

  my @exclusions = @{ $self->{exclusions} || [] };

  my @parts;

  for my $tuple (
    [ qw( >= > minimum ) ],
    [ qw( <= < maximum ) ],
  ) {
    my ($op, $e_op, $k) = @$tuple;
    if (exists $self->{$k}) {
      my @new_exclusions = grep { $_ != $self->{ $k } } @exclusions;
      if (@new_exclusions == @exclusions) {
        push @parts, [ $op, "$self->{ $k }" ];
      } else {
        push @parts, [ $e_op, "$self->{ $k }" ];
        @exclusions = @new_exclusions;
      }
    }
  }

  push @parts, map {; [ "!=", "$_" ] } @exclusions;

  return \@parts;
}

#pod =method as_string
#pod
#pod   $range->as_string;
#pod
#pod This returns a string containing the version requirements in the format
#pod described in L<CPAN::Meta::Spec>. This should only be used for informational
#pod purposes such as error messages and should not be interpreted or used for
#pod comparison (see L</accepts> instead).
#pod
#pod =cut

sub as_string {
  my ($self) = @_;

  my @parts = @{ $self->as_struct };

  return $parts[0][1] if @parts == 1 and $parts[0][0] eq '>=';

  return join q{, }, map {; join q{ }, @$_ } @parts;
}

sub _reject_requirements {
  my ($self, $module, $error) = @_;
  Carp::croak("illegal requirements for $module: $error")
}

#pod =method accepts
#pod
#pod   my $bool = $range->accepts($version);
#pod
#pod Given a version, this method returns true if the version specification
#pod accepts the provided version.  In other words, given:
#pod
#pod   '>= 1.00, < 2.00'
#pod
#pod We will accept 1.00 and 1.75 but not 0.50 or 2.00.
#pod
#pod =cut

sub accepts {
  my ($self, $version) = @_;

  return if defined $self->{minimum} and $version < $self->{minimum};
  return if defined $self->{maximum} and $version > $self->{maximum};
  return if defined $self->{exclusions}
        and grep { $version == $_ } @{ $self->{exclusions} };

  return 1;
}

#pod =method is_simple
#pod
#pod This method returns true if and only if the range is an inclusive minimum
#pod -- that is, if their string expression is just the version number.
#pod
#pod =cut

sub is_simple {
  my ($self) = @_;
  # XXX: This is a complete hack, but also entirely correct.
  return if $self->as_string =~ /\s/;

  return 1;
}

package
  CPAN::Meta::Requirements::Range::_Exact;

our @ISA = 'CPAN::Meta::Requirements::Range::_Base';

our $VERSION = '2.141';

BEGIN {
  eval "use version ()"; ## no critic
  if ( my $err = $@ ) {
    eval "use ExtUtils::MakeMaker::version" or die $err; ## no critic
  }
}

sub _new      { bless { version => $_[1] } => $_[0] }

sub accepts { return $_[0]{version} == $_[1] }

sub _reject_requirements {
  my ($self, $module, $error) = @_;
  Carp::croak("illegal requirements for $module: $error")
}

sub _clone {
  (ref $_[0])->_new( version->new( $_[0]{version} ) )
}

sub with_exact_version {
  my ($self, $version, $module, $bad_version_hook) = @_;
  $module //= 'module';
  $version = $self->_version_object($version, $module, $bad_version_hook);

  return $self->_clone if $self->accepts($version);

  $self->_reject_requirements(
    $module,
    "can't be exactly $version when exact requirement is already $self->{version}",
  );
}

sub with_minimum {
  my ($self, $minimum, $module, $bad_version_hook) = @_;
  $module //= 'module';
  $minimum = $self->_version_object( $minimum, $module, $bad_version_hook );

  return $self->_clone if $self->{version} >= $minimum;
  $self->_reject_requirements(
    $module,
    "minimum $minimum exceeds exact specification $self->{version}",
  );
}

sub with_maximum {
  my ($self, $maximum, $module, $bad_version_hook) = @_;
  $module //= 'module';
  $maximum = $self->_version_object( $maximum, $module, $bad_version_hook );

  return $self->_clone if $self->{version} <= $maximum;
  $self->_reject_requirements(
    $module,
    "maximum $maximum below exact specification $self->{version}",
  );
}

sub with_exclusion {
  my ($self, $exclusion, $module, $bad_version_hook) = @_;
  $module //= 'module';
  $exclusion = $self->_version_object( $exclusion, $module, $bad_version_hook );

  return $self->_clone unless $exclusion == $self->{version};
  $self->_reject_requirements(
    $module,
    "tried to exclude $exclusion, which is already exactly specified",
  );
}

sub as_string { return "== $_[0]{version}" }

sub as_struct { return [ [ '==', "$_[0]{version}" ] ] }

sub _as_modifiers { return [ with_exact_version => $_[0]{version} ] }


1;

# vim: ts=2 sts=2 sw=2 et:

__END__

=pod

=encoding UTF-8

=head1 NAME

CPAN::Meta::Requirements::Range - a set of version requirements for a CPAN dist

=head1 VERSION

version 2.143

=head1 SYNOPSIS

  use CPAN::Meta::Requirements::Range;

  my $range = CPAN::Meta::Requirements::Range->with_minimum(1);

  $range = $range->with_maximum('v2.2');

  my $stringified = $range->as_string;

=head1 DESCRIPTION

A CPAN::Meta::Requirements::Range object models a set of version constraints like
those specified in the F<META.yml> or F<META.json> files in CPAN distributions,
and as defined by L<CPAN::Meta::Spec>;
It can be built up by adding more and more constraints, and it will reduce them
to the simplest representation.

Logically impossible constraints will be identified immediately by thrown
exceptions.

=head1 METHODS

=head2 with_string_requirement

  $req->with_string_requirement('>= 1.208, <= 2.206');
  $req->with_string_requirement(v1.208);

This method parses the passed in string and adds the appropriate requirement.
A version can be a Perl "v-string".  It understands version ranges as described
in the L<CPAN::Meta::Spec/Version Ranges>. For example:

=over 4

=item 1.3

=item >= 1.3

=item <= 1.3

=item == 1.3

=item != 1.3

=item > 1.3

=item < 1.3

=item >= 1.3, != 1.5, <= 2.0

A version number without an operator is equivalent to specifying a minimum
(C<E<gt>=>).  Extra whitespace is allowed.

=back

=head2 with_range

 $range->with_range($other_range)

This creates a new range object that is a merge two others.

=head2 with_exact_version

  $range->with_exact_version( $version );

This sets the version required to I<exactly> the given
version.  No other version would be considered acceptable.

This method returns the version range object.

=head2 with_minimum

  $range->with_minimum( $version );

This adds a new minimum version requirement.  If the new requirement is
redundant to the existing specification, this has no effect.

Minimum requirements are inclusive.  C<$version> is required, along with any
greater version number.

This method returns the version range object.

=head2 with_maximum

  $range->with_maximum( $version );

This adds a new maximum version requirement.  If the new requirement is
redundant to the existing specification, this has no effect.

Maximum requirements are inclusive.  No version strictly greater than the given
version is allowed.

This method returns the version range object.

=head2 with_exclusion

  $range->with_exclusion( $version );

This adds a new excluded version.  For example, you might use these three
method calls:

  $range->with_minimum( '1.00' );
  $range->with_maximum( '1.82' );

  $range->with_exclusion( '1.75' );

Any version between 1.00 and 1.82 inclusive would be acceptable, except for
1.75.

This method returns the requirements object.

=head2 as_struct

  $range->as_struct( $module );

This returns a data structure containing the version requirements. This should
not be used for version checks (see L</accepts_module> instead).

=head2 as_string

  $range->as_string;

This returns a string containing the version requirements in the format
described in L<CPAN::Meta::Spec>. This should only be used for informational
purposes such as error messages and should not be interpreted or used for
comparison (see L</accepts> instead).

=head2 accepts

  my $bool = $range->accepts($version);

Given a version, this method returns true if the version specification
accepts the provided version.  In other words, given:

  '>= 1.00, < 2.00'

We will accept 1.00 and 1.75 but not 0.50 or 2.00.

=head2 is_simple

This method returns true if and only if the range is an inclusive minimum
-- that is, if their string expression is just the version number.

=head1 AUTHORS

=over 4

=item *

David Golden <dagolden@cpan.org>

=item *

Ricardo Signes <rjbs@cpan.org>

=back

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2010 by David Golden and Ricardo Signes.

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

=cut
PK7N%[�somFUFUperl5/CPAN/Meta/Requirements.pmnu��6�$use v5.10;
use strict;
use warnings;
package CPAN::Meta::Requirements;
# ABSTRACT: a set of version requirements for a CPAN dist

our $VERSION = '2.143';

use CPAN::Meta::Requirements::Range;

#pod =head1 SYNOPSIS
#pod
#pod   use CPAN::Meta::Requirements;
#pod
#pod   my $build_requires = CPAN::Meta::Requirements->new;
#pod
#pod   $build_requires->add_minimum('Library::Foo' => 1.208);
#pod
#pod   $build_requires->add_minimum('Library::Foo' => 2.602);
#pod
#pod   $build_requires->add_minimum('Module::Bar'  => 'v1.2.3');
#pod
#pod   $METAyml->{build_requires} = $build_requires->as_string_hash;
#pod
#pod =head1 DESCRIPTION
#pod
#pod A CPAN::Meta::Requirements object models a set of version constraints like
#pod those specified in the F<META.yml> or F<META.json> files in CPAN distributions,
#pod and as defined by L<CPAN::Meta::Spec>.
#pod It can be built up by adding more and more constraints, and it will reduce them
#pod to the simplest representation.
#pod
#pod Logically impossible constraints will be identified immediately by thrown
#pod exceptions.
#pod
#pod =cut

use Carp ();

#pod =method new
#pod
#pod   my $req = CPAN::Meta::Requirements->new;
#pod
#pod This returns a new CPAN::Meta::Requirements object.  It takes an optional
#pod hash reference argument.  Currently, only one key is supported:
#pod
#pod =for :list
#pod * C<bad_version_hook> -- if provided, when a version cannot be parsed into
#pod   a version object, this code reference will be called with the invalid
#pod   version string as first argument, and the module name as second
#pod   argument.  It must return a valid version object.
#pod
#pod All other keys are ignored.
#pod
#pod =cut

my @valid_options = qw( bad_version_hook );

sub new {
  my ($class, $options) = @_;
  $options ||= {};
  Carp::croak "Argument to $class\->new() must be a hash reference"
    unless ref $options eq 'HASH';
  my %self = map {; $_ => $options->{$_}} @valid_options;

  return bless \%self => $class;
}

#pod =method add_minimum
#pod
#pod   $req->add_minimum( $module => $version );
#pod
#pod This adds a new minimum version requirement.  If the new requirement is
#pod redundant to the existing specification, this has no effect.
#pod
#pod Minimum requirements are inclusive.  C<$version> is required, along with any
#pod greater version number.
#pod
#pod This method returns the requirements object.
#pod
#pod =method add_maximum
#pod
#pod   $req->add_maximum( $module => $version );
#pod
#pod This adds a new maximum version requirement.  If the new requirement is
#pod redundant to the existing specification, this has no effect.
#pod
#pod Maximum requirements are inclusive.  No version strictly greater than the given
#pod version is allowed.
#pod
#pod This method returns the requirements object.
#pod
#pod =method add_exclusion
#pod
#pod   $req->add_exclusion( $module => $version );
#pod
#pod This adds a new excluded version.  For example, you might use these three
#pod method calls:
#pod
#pod   $req->add_minimum( $module => '1.00' );
#pod   $req->add_maximum( $module => '1.82' );
#pod
#pod   $req->add_exclusion( $module => '1.75' );
#pod
#pod Any version between 1.00 and 1.82 inclusive would be acceptable, except for
#pod 1.75.
#pod
#pod This method returns the requirements object.
#pod
#pod =method exact_version
#pod
#pod   $req->exact_version( $module => $version );
#pod
#pod This sets the version required for the given module to I<exactly> the given
#pod version.  No other version would be considered acceptable.
#pod
#pod This method returns the requirements object.
#pod
#pod =cut

BEGIN {
  for my $type (qw(maximum exclusion exact_version)) {
    my $method = "with_$type";
    my $to_add = $type eq 'exact_version' ? $type : "add_$type";

    my $code = sub {
      my ($self, $name, $version) = @_;

      $self->__modify_entry_for($name, $method, $version);

      return $self;
    };

    no strict 'refs';
    *$to_add = $code;
  }
}

# add_minimum is optimized compared to generated subs above because
# it is called frequently and with "0" or equivalent input
sub add_minimum {
  my ($self, $name, $version) = @_;

  # stringify $version so that version->new("0.00")->stringify ne "0"
  # which preserves the user's choice of "0.00" as the requirement
  if (not defined $version or "$version" eq '0') {
    return $self if $self->__entry_for($name);
    Carp::croak("can't add new requirements to finalized requirements")
      if $self->is_finalized;

    $self->{requirements}{ $name } =
      CPAN::Meta::Requirements::Range->with_minimum('0', $name);
  }
  else {
    $self->__modify_entry_for($name, 'with_minimum', $version);
  }
  return $self;
}

#pod =method version_range_for_module
#pod
#pod   $req->version_range_for_module( $another_req_object );
#pod
#pod =cut

sub version_range_for_module {
  my ($self, $module) = @_;
  return $self->{requirements}{$module};
}

#pod =method add_requirements
#pod
#pod   $req->add_requirements( $another_req_object );
#pod
#pod This method adds all the requirements in the given CPAN::Meta::Requirements
#pod object to the requirements object on which it was called.  If there are any
#pod conflicts, an exception is thrown.
#pod
#pod This method returns the requirements object.
#pod
#pod =cut

sub add_requirements {
  my ($self, $req) = @_;

  for my $module ($req->required_modules) {
    my $new_range = $req->version_range_for_module($module);
    $self->__modify_entry_for($module, 'with_range', $new_range);
  }

  return $self;
}

#pod =method accepts_module
#pod
#pod   my $bool = $req->accepts_module($module => $version);
#pod
#pod Given an module and version, this method returns true if the version
#pod specification for the module accepts the provided version.  In other words,
#pod given:
#pod
#pod   Module => '>= 1.00, < 2.00'
#pod
#pod We will accept 1.00 and 1.75 but not 0.50 or 2.00.
#pod
#pod For modules that do not appear in the requirements, this method will return
#pod true.
#pod
#pod =cut

sub accepts_module {
  my ($self, $module, $version) = @_;

  return 1 unless my $range = $self->__entry_for($module);
  return $range->accepts($version);
}

#pod =method clear_requirement
#pod
#pod   $req->clear_requirement( $module );
#pod
#pod This removes the requirement for a given module from the object.
#pod
#pod This method returns the requirements object.
#pod
#pod =cut

sub clear_requirement {
  my ($self, $module) = @_;

  return $self unless $self->__entry_for($module);

  Carp::croak("can't clear requirements on finalized requirements")
    if $self->is_finalized;

  delete $self->{requirements}{ $module };

  return $self;
}

#pod =method requirements_for_module
#pod
#pod   $req->requirements_for_module( $module );
#pod
#pod This returns a string containing the version requirements for a given module in
#pod the format described in L<CPAN::Meta::Spec> or undef if the given module has no
#pod requirements. This should only be used for informational purposes such as error
#pod messages and should not be interpreted or used for comparison (see
#pod L</accepts_module> instead).
#pod
#pod =cut

sub requirements_for_module {
  my ($self, $module) = @_;
  my $entry = $self->__entry_for($module);
  return unless $entry;
  return $entry->as_string;
}

#pod =method structured_requirements_for_module
#pod
#pod   $req->structured_requirements_for_module( $module );
#pod
#pod This returns a data structure containing the version requirements for a given
#pod module or undef if the given module has no requirements.  This should
#pod not be used for version checks (see L</accepts_module> instead).
#pod
#pod Added in version 2.134.
#pod
#pod =cut

sub structured_requirements_for_module {
  my ($self, $module) = @_;
  my $entry = $self->__entry_for($module);
  return unless $entry;
  return $entry->as_struct;
}

#pod =method required_modules
#pod
#pod This method returns a list of all the modules for which requirements have been
#pod specified.
#pod
#pod =cut

sub required_modules { keys %{ $_[0]{requirements} } }

#pod =method clone
#pod
#pod   $req->clone;
#pod
#pod This method returns a clone of the invocant.  The clone and the original object
#pod can then be changed independent of one another.
#pod
#pod =cut

sub clone {
  my ($self) = @_;
  my $new = (ref $self)->new;

  return $new->add_requirements($self);
}

sub __entry_for     { $_[0]{requirements}{ $_[1] } }

sub __modify_entry_for {
  my ($self, $name, $method, $version) = @_;

  my $fin = $self->is_finalized;
  my $old = $self->__entry_for($name);

  Carp::croak("can't add new requirements to finalized requirements")
    if $fin and not $old;

  my $new = ($old || 'CPAN::Meta::Requirements::Range')
          ->$method($version, $name, $self->{bad_version_hook});

  Carp::croak("can't modify finalized requirements")
    if $fin and $old->as_string ne $new->as_string;

  $self->{requirements}{ $name } = $new;
}

#pod =method is_simple
#pod
#pod This method returns true if and only if all requirements are inclusive minimums
#pod -- that is, if their string expression is just the version number.
#pod
#pod =cut

sub is_simple {
  my ($self) = @_;
  for my $module ($self->required_modules) {
    # XXX: This is a complete hack, but also entirely correct.
    return if not $self->__entry_for($module)->is_simple;
  }

  return 1;
}

#pod =method is_finalized
#pod
#pod This method returns true if the requirements have been finalized by having the
#pod C<finalize> method called on them.
#pod
#pod =cut

sub is_finalized { $_[0]{finalized} }

#pod =method finalize
#pod
#pod This method marks the requirements finalized.  Subsequent attempts to change
#pod the requirements will be fatal, I<if> they would result in a change.  If they
#pod would not alter the requirements, they have no effect.
#pod
#pod If a finalized set of requirements is cloned, the cloned requirements are not
#pod also finalized.
#pod
#pod =cut

sub finalize { $_[0]{finalized} = 1 }

#pod =method as_string_hash
#pod
#pod This returns a reference to a hash describing the requirements using the
#pod strings in the L<CPAN::Meta::Spec> specification.
#pod
#pod For example after the following program:
#pod
#pod   my $req = CPAN::Meta::Requirements->new;
#pod
#pod   $req->add_minimum('CPAN::Meta::Requirements' => 0.102);
#pod
#pod   $req->add_minimum('Library::Foo' => 1.208);
#pod
#pod   $req->add_maximum('Library::Foo' => 2.602);
#pod
#pod   $req->add_minimum('Module::Bar'  => 'v1.2.3');
#pod
#pod   $req->add_exclusion('Module::Bar'  => 'v1.2.8');
#pod
#pod   $req->exact_version('Xyzzy'  => '6.01');
#pod
#pod   my $hashref = $req->as_string_hash;
#pod
#pod C<$hashref> would contain:
#pod
#pod   {
#pod     'CPAN::Meta::Requirements' => '0.102',
#pod     'Library::Foo' => '>= 1.208, <= 2.206',
#pod     'Module::Bar'  => '>= v1.2.3, != v1.2.8',
#pod     'Xyzzy'        => '== 6.01',
#pod   }
#pod
#pod =cut

sub as_string_hash {
  my ($self) = @_;

  my %hash = map {; $_ => $self->{requirements}{$_}->as_string }
             $self->required_modules;

  return \%hash;
}

#pod =method add_string_requirement
#pod
#pod   $req->add_string_requirement('Library::Foo' => '>= 1.208, <= 2.206');
#pod   $req->add_string_requirement('Library::Foo' => v1.208);
#pod
#pod This method parses the passed in string and adds the appropriate requirement
#pod for the given module.  A version can be a Perl "v-string".  It understands
#pod version ranges as described in the L<CPAN::Meta::Spec/Version Ranges>. For
#pod example:
#pod
#pod =over 4
#pod
#pod =item 1.3
#pod
#pod =item >= 1.3
#pod
#pod =item <= 1.3
#pod
#pod =item == 1.3
#pod
#pod =item != 1.3
#pod
#pod =item > 1.3
#pod
#pod =item < 1.3
#pod
#pod =item >= 1.3, != 1.5, <= 2.0
#pod
#pod A version number without an operator is equivalent to specifying a minimum
#pod (C<E<gt>=>).  Extra whitespace is allowed.
#pod
#pod =back
#pod
#pod =cut

sub add_string_requirement {
  my ($self, $module, $req) = @_;

  $self->__modify_entry_for($module, 'with_string_requirement', $req);
}

#pod =method from_string_hash
#pod
#pod   my $req = CPAN::Meta::Requirements->from_string_hash( \%hash );
#pod   my $req = CPAN::Meta::Requirements->from_string_hash( \%hash, \%opts );
#pod
#pod This is an alternate constructor for a CPAN::Meta::Requirements
#pod object. It takes a hash of module names and version requirement
#pod strings and returns a new CPAN::Meta::Requirements object. As with
#pod add_string_requirement, a version can be a Perl "v-string". Optionally,
#pod you can supply a hash-reference of options, exactly as with the L</new>
#pod method.
#pod
#pod =cut

sub from_string_hash {
  my ($class, $hash, $options) = @_;

  my $self = $class->new($options);

  for my $module (keys %$hash) {
    my $req = $hash->{$module};
    $self->add_string_requirement($module, $req);
  }

  return $self;
}

1;
# vim: ts=2 sts=2 sw=2 et:

__END__

=pod

=encoding UTF-8

=head1 NAME

CPAN::Meta::Requirements - a set of version requirements for a CPAN dist

=head1 VERSION

version 2.143

=head1 SYNOPSIS

  use CPAN::Meta::Requirements;

  my $build_requires = CPAN::Meta::Requirements->new;

  $build_requires->add_minimum('Library::Foo' => 1.208);

  $build_requires->add_minimum('Library::Foo' => 2.602);

  $build_requires->add_minimum('Module::Bar'  => 'v1.2.3');

  $METAyml->{build_requires} = $build_requires->as_string_hash;

=head1 DESCRIPTION

A CPAN::Meta::Requirements object models a set of version constraints like
those specified in the F<META.yml> or F<META.json> files in CPAN distributions,
and as defined by L<CPAN::Meta::Spec>.
It can be built up by adding more and more constraints, and it will reduce them
to the simplest representation.

Logically impossible constraints will be identified immediately by thrown
exceptions.

=head1 METHODS

=head2 new

  my $req = CPAN::Meta::Requirements->new;

This returns a new CPAN::Meta::Requirements object.  It takes an optional
hash reference argument.  Currently, only one key is supported:

=over 4

=item *

C<bad_version_hook> -- if provided, when a version cannot be parsed into a version object, this code reference will be called with the invalid version string as first argument, and the module name as second argument.  It must return a valid version object.

=back

All other keys are ignored.

=head2 add_minimum

  $req->add_minimum( $module => $version );

This adds a new minimum version requirement.  If the new requirement is
redundant to the existing specification, this has no effect.

Minimum requirements are inclusive.  C<$version> is required, along with any
greater version number.

This method returns the requirements object.

=head2 add_maximum

  $req->add_maximum( $module => $version );

This adds a new maximum version requirement.  If the new requirement is
redundant to the existing specification, this has no effect.

Maximum requirements are inclusive.  No version strictly greater than the given
version is allowed.

This method returns the requirements object.

=head2 add_exclusion

  $req->add_exclusion( $module => $version );

This adds a new excluded version.  For example, you might use these three
method calls:

  $req->add_minimum( $module => '1.00' );
  $req->add_maximum( $module => '1.82' );

  $req->add_exclusion( $module => '1.75' );

Any version between 1.00 and 1.82 inclusive would be acceptable, except for
1.75.

This method returns the requirements object.

=head2 exact_version

  $req->exact_version( $module => $version );

This sets the version required for the given module to I<exactly> the given
version.  No other version would be considered acceptable.

This method returns the requirements object.

=head2 version_range_for_module

  $req->version_range_for_module( $another_req_object );

=head2 add_requirements

  $req->add_requirements( $another_req_object );

This method adds all the requirements in the given CPAN::Meta::Requirements
object to the requirements object on which it was called.  If there are any
conflicts, an exception is thrown.

This method returns the requirements object.

=head2 accepts_module

  my $bool = $req->accepts_module($module => $version);

Given an module and version, this method returns true if the version
specification for the module accepts the provided version.  In other words,
given:

  Module => '>= 1.00, < 2.00'

We will accept 1.00 and 1.75 but not 0.50 or 2.00.

For modules that do not appear in the requirements, this method will return
true.

=head2 clear_requirement

  $req->clear_requirement( $module );

This removes the requirement for a given module from the object.

This method returns the requirements object.

=head2 requirements_for_module

  $req->requirements_for_module( $module );

This returns a string containing the version requirements for a given module in
the format described in L<CPAN::Meta::Spec> or undef if the given module has no
requirements. This should only be used for informational purposes such as error
messages and should not be interpreted or used for comparison (see
L</accepts_module> instead).

=head2 structured_requirements_for_module

  $req->structured_requirements_for_module( $module );

This returns a data structure containing the version requirements for a given
module or undef if the given module has no requirements.  This should
not be used for version checks (see L</accepts_module> instead).

Added in version 2.134.

=head2 required_modules

This method returns a list of all the modules for which requirements have been
specified.

=head2 clone

  $req->clone;

This method returns a clone of the invocant.  The clone and the original object
can then be changed independent of one another.

=head2 is_simple

This method returns true if and only if all requirements are inclusive minimums
-- that is, if their string expression is just the version number.

=head2 is_finalized

This method returns true if the requirements have been finalized by having the
C<finalize> method called on them.

=head2 finalize

This method marks the requirements finalized.  Subsequent attempts to change
the requirements will be fatal, I<if> they would result in a change.  If they
would not alter the requirements, they have no effect.

If a finalized set of requirements is cloned, the cloned requirements are not
also finalized.

=head2 as_string_hash

This returns a reference to a hash describing the requirements using the
strings in the L<CPAN::Meta::Spec> specification.

For example after the following program:

  my $req = CPAN::Meta::Requirements->new;

  $req->add_minimum('CPAN::Meta::Requirements' => 0.102);

  $req->add_minimum('Library::Foo' => 1.208);

  $req->add_maximum('Library::Foo' => 2.602);

  $req->add_minimum('Module::Bar'  => 'v1.2.3');

  $req->add_exclusion('Module::Bar'  => 'v1.2.8');

  $req->exact_version('Xyzzy'  => '6.01');

  my $hashref = $req->as_string_hash;

C<$hashref> would contain:

  {
    'CPAN::Meta::Requirements' => '0.102',
    'Library::Foo' => '>= 1.208, <= 2.206',
    'Module::Bar'  => '>= v1.2.3, != v1.2.8',
    'Xyzzy'        => '== 6.01',
  }

=head2 add_string_requirement

  $req->add_string_requirement('Library::Foo' => '>= 1.208, <= 2.206');
  $req->add_string_requirement('Library::Foo' => v1.208);

This method parses the passed in string and adds the appropriate requirement
for the given module.  A version can be a Perl "v-string".  It understands
version ranges as described in the L<CPAN::Meta::Spec/Version Ranges>. For
example:

=over 4

=item 1.3

=item >= 1.3

=item <= 1.3

=item == 1.3

=item != 1.3

=item > 1.3

=item < 1.3

=item >= 1.3, != 1.5, <= 2.0

A version number without an operator is equivalent to specifying a minimum
(C<E<gt>=>).  Extra whitespace is allowed.

=back

=head2 from_string_hash

  my $req = CPAN::Meta::Requirements->from_string_hash( \%hash );
  my $req = CPAN::Meta::Requirements->from_string_hash( \%hash, \%opts );

This is an alternate constructor for a CPAN::Meta::Requirements
object. It takes a hash of module names and version requirement
strings and returns a new CPAN::Meta::Requirements object. As with
add_string_requirement, a version can be a Perl "v-string". Optionally,
you can supply a hash-reference of options, exactly as with the L</new>
method.

=for :stopwords cpan testmatrix url bugtracker rt cpants kwalitee diff irc mailto metadata placeholders metacpan

=head1 SUPPORT

=head2 Bugs / Feature Requests

Please report any bugs or feature requests through the issue tracker
at L<https://github.com/Perl-Toolchain-Gang/CPAN-Meta-Requirements/issues>.
You will be notified automatically of any progress on your issue.

=head2 Source Code

This is open source software.  The code repository is available for
public review and contribution under the terms of the license.

L<https://github.com/Perl-Toolchain-Gang/CPAN-Meta-Requirements>

  git clone https://github.com/Perl-Toolchain-Gang/CPAN-Meta-Requirements.git

=head1 AUTHORS

=over 4

=item *

David Golden <dagolden@cpan.org>

=item *

Ricardo Signes <rjbs@cpan.org>

=back

=head1 CONTRIBUTORS

=for stopwords Ed J Graham Knop Karen Etheridge Leon Timmermans Paul Howarth Ricardo Signes robario Tatsuhiko Miyagawa

=over 4

=item *

Ed J <mohawk2@users.noreply.github.com>

=item *

Graham Knop <haarg@haarg.org>

=item *

Karen Etheridge <ether@cpan.org>

=item *

Leon Timmermans <fawaka@gmail.com>

=item *

Paul Howarth <paul@city-fan.org>

=item *

Ricardo Signes <rjbs@semiotic.systems>

=item *

robario <webmaster@robario.com>

=item *

Tatsuhiko Miyagawa <miyagawa@bulknews.net>

=item *

Tatsuhiko Miyagawa <miyagawa@gmail.com>

=back

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2010 by David Golden and Ricardo Signes.

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

=cut
PK7N%[�:nn�i�iperl5/CPAN/Meta/YAML.pmnu��6�$use 5.008001; # sane UTF-8 support
use strict;
use warnings;
package CPAN::Meta::YAML; # git description: v1.75-3-g85169f1
# XXX-INGY is 5.8.1 too old/broken for utf8?
# XXX-XDG Lancaster consensus was that it was sufficient until
# proven otherwise
$CPAN::Meta::YAML::VERSION = '0.020';
; # original $VERSION removed by Doppelgaenger

#####################################################################
# The CPAN::Meta::YAML API.
#
# These are the currently documented API functions/methods and
# exports:

use Exporter;
our @ISA       = qw{ Exporter  };
our @EXPORT    = qw{ Load Dump };
our @EXPORT_OK = qw{ LoadFile DumpFile freeze thaw };

###
# Functional/Export API:

sub Dump {
    return CPAN::Meta::YAML->new(@_)->_dump_string;
}

# XXX-INGY Returning last document seems a bad behavior.
# XXX-XDG I think first would seem more natural, but I don't know
# that it's worth changing now
sub Load {
    my $self = CPAN::Meta::YAML->_load_string(@_);
    if ( wantarray ) {
        return @$self;
    } else {
        # To match YAML.pm, return the last document
        return $self->[-1];
    }
}

# XXX-INGY Do we really need freeze and thaw?
# XXX-XDG I don't think so.  I'd support deprecating them.
BEGIN {
    *freeze = \&Dump;
    *thaw   = \&Load;
}

sub DumpFile {
    my $file = shift;
    return CPAN::Meta::YAML->new(@_)->_dump_file($file);
}

sub LoadFile {
    my $file = shift;
    my $self = CPAN::Meta::YAML->_load_file($file);
    if ( wantarray ) {
        return @$self;
    } else {
        # Return only the last document to match YAML.pm,
        return $self->[-1];
    }
}


###
# Object Oriented API:

# Create an empty CPAN::Meta::YAML object
# XXX-INGY Why do we use ARRAY object?
# NOTE: I get it now, but I think it's confusing and not needed.
# Will change it on a branch later, for review.
#
# XXX-XDG I don't support changing it yet.  It's a very well-documented
# "API" of CPAN::Meta::YAML.  I'd support deprecating it, but Adam suggested
# we not change it until YAML.pm's own OO API is established so that
# users only have one API change to digest, not two
sub new {
    my $class = shift;
    bless [ @_ ], $class;
}

# XXX-INGY It probably doesn't matter, and it's probably too late to
# change, but 'read/write' are the wrong names. Read and Write
# are actions that take data from storage to memory
# characters/strings. These take the data to/from storage to native
# Perl objects, which the terms dump and load are meant. As long as
# this is a legacy quirk to CPAN::Meta::YAML it's ok, but I'd prefer not
# to add new {read,write}_* methods to this API.

sub read_string {
    my $self = shift;
    $self->_load_string(@_);
}

sub write_string {
    my $self = shift;
    $self->_dump_string(@_);
}

sub read {
    my $self = shift;
    $self->_load_file(@_);
}

sub write {
    my $self = shift;
    $self->_dump_file(@_);
}




#####################################################################
# Constants

# Printed form of the unprintable characters in the lowest range
# of ASCII characters, listed by ASCII ordinal position.
my @UNPRINTABLE = qw(
    0    x01  x02  x03  x04  x05  x06  a
    b    t    n    v    f    r    x0E  x0F
    x10  x11  x12  x13  x14  x15  x16  x17
    x18  x19  x1A  e    x1C  x1D  x1E  x1F
);

# Printable characters for escapes
my %UNESCAPES = (
    0 => "\x00", z => "\x00", N    => "\x85",
    a => "\x07", b => "\x08", t    => "\x09",
    n => "\x0a", v => "\x0b", f    => "\x0c",
    r => "\x0d", e => "\x1b", '\\' => '\\',
);

# XXX-INGY
# I(ngy) need to decide if these values should be quoted in
# CPAN::Meta::YAML or not. Probably yes.

# These 3 values have special meaning when unquoted and using the
# default YAML schema. They need quotes if they are strings.
my %QUOTE = map { $_ => 1 } qw{
    null true false
};

# The commented out form is simpler, but overloaded the Perl regex
# engine due to recursion and backtracking problems on strings
# larger than 32,000ish characters. Keep it for reference purposes.
# qr/\"((?:\\.|[^\"])*)\"/
my $re_capture_double_quoted = qr/\"([^\\"]*(?:\\.[^\\"]*)*)\"/;
my $re_capture_single_quoted = qr/\'([^\']*(?:\'\'[^\']*)*)\'/;
# unquoted re gets trailing space that needs to be stripped
my $re_capture_unquoted_key  = qr/([^:]+(?::+\S(?:[^:]*|.*?(?=:)))*)(?=\s*\:(?:\s+|$))/;
my $re_trailing_comment      = qr/(?:\s+\#.*)?/;
my $re_key_value_separator   = qr/\s*:(?:\s+(?:\#.*)?|$)/;





#####################################################################
# CPAN::Meta::YAML Implementation.
#
# These are the private methods that do all the work. They may change
# at any time.


###
# Loader functions:

# Create an object from a file
sub _load_file {
    my $class = ref $_[0] ? ref shift : shift;

    # Check the file
    my $file = shift or $class->_error( 'You did not specify a file name' );
    $class->_error( "File '$file' does not exist" )
        unless -e $file;
    $class->_error( "'$file' is a directory, not a file" )
        unless -f _;
    $class->_error( "Insufficient permissions to read '$file'" )
        unless -r _;

    # Open unbuffered with strict UTF-8 decoding and no translation layers
    open( my $fh, "<:unix:encoding(UTF-8)", $file );
    unless ( $fh ) {
        $class->_error("Failed to open file '$file': $!");
    }

    # flock if available (or warn if not possible for OS-specific reasons)
    if ( _can_flock() ) {
        flock( $fh, Fcntl::LOCK_SH() )
            or warn "Couldn't lock '$file' for reading: $!";
    }

    # slurp the contents
    my $contents = eval {
        use warnings FATAL => 'utf8';
        local $/;
        <$fh>
    };
    if ( my $err = $@ ) {
        $class->_error("Error reading from file '$file': $err");
    }

    # close the file (release the lock)
    unless ( close $fh ) {
        $class->_error("Failed to close file '$file': $!");
    }

    $class->_load_string( $contents );
}

# Create an object from a string
sub _load_string {
    my $class  = ref $_[0] ? ref shift : shift;
    my $self   = bless [], $class;
    my $string = $_[0];
    eval {
        unless ( defined $string ) {
            die \"Did not provide a string to load";
        }

        # Check if Perl has it marked as characters, but it's internally
        # inconsistent.  E.g. maybe latin1 got read on a :utf8 layer
        if ( utf8::is_utf8($string) && ! utf8::valid($string) ) {
            die \<<'...';
Read an invalid UTF-8 string (maybe mixed UTF-8 and 8-bit character set).
Did you decode with lax ":utf8" instead of strict ":encoding(UTF-8)"?
...
        }

        # Ensure Unicode character semantics, even for 0x80-0xff
        utf8::upgrade($string);

        # Check for and strip any leading UTF-8 BOM
        $string =~ s/^\x{FEFF}//;

        # Check for some special cases
        return $self unless length $string;

        # Split the file into lines
        my @lines = grep { ! /^\s*(?:\#.*)?\z/ }
                split /(?:\015{1,2}\012|\015|\012)/, $string;

        # Strip the initial YAML header
        @lines and $lines[0] =~ /^\%YAML[: ][\d\.]+.*\z/ and shift @lines;

        # A nibbling parser
        my $in_document = 0;
        while ( @lines ) {
            # Do we have a document header?
            if ( $lines[0] =~ /^---\s*(?:(.+)\s*)?\z/ ) {
                # Handle scalar documents
                shift @lines;
                if ( defined $1 and $1 !~ /^(?:\#.+|\%YAML[: ][\d\.]+)\z/ ) {
                    push @$self,
                        $self->_load_scalar( "$1", [ undef ], \@lines );
                    next;
                }
                $in_document = 1;
            }

            if ( ! @lines or $lines[0] =~ /^(?:---|\.\.\.)/ ) {
                # A naked document
                push @$self, undef;
                while ( @lines and $lines[0] !~ /^---/ ) {
                    shift @lines;
                }
                $in_document = 0;

            # XXX The final '-+$' is to look for -- which ends up being an
            # error later.
            } elsif ( ! $in_document && @$self ) {
                # only the first document can be explicit
                die \"CPAN::Meta::YAML failed to classify the line '$lines[0]'";
            } elsif ( $lines[0] =~ /^\s*\-(?:\s|$|-+$)/ ) {
                # An array at the root
                my $document = [ ];
                push @$self, $document;
                $self->_load_array( $document, [ 0 ], \@lines );

            } elsif ( $lines[0] =~ /^(\s*)\S/ ) {
                # A hash at the root
                my $document = { };
                push @$self, $document;
                $self->_load_hash( $document, [ length($1) ], \@lines );

            } else {
                # Shouldn't get here.  @lines have whitespace-only lines
                # stripped, and previous match is a line with any
                # non-whitespace.  So this clause should only be reachable via
                # a perlbug where \s is not symmetric with \S

                # uncoverable statement
                die \"CPAN::Meta::YAML failed to classify the line '$lines[0]'";
            }
        }
    };
    my $err = $@;
    if ( ref $err eq 'SCALAR' ) {
        $self->_error(${$err});
    } elsif ( $err ) {
        $self->_error($err);
    }

    return $self;
}

sub _unquote_single {
    my ($self, $string) = @_;
    return '' unless length $string;
    $string =~ s/\'\'/\'/g;
    return $string;
}

sub _unquote_double {
    my ($self, $string) = @_;
    return '' unless length $string;
    $string =~ s/\\"/"/g;
    $string =~
        s{\\([Nnever\\fartz0b]|x([0-9a-fA-F]{2}))}
         {(length($1)>1)?pack("H2",$2):$UNESCAPES{$1}}gex;
    return $string;
}

# Load a YAML scalar string to the actual Perl scalar
sub _load_scalar {
    my ($self, $string, $indent, $lines) = @_;

    # Trim trailing whitespace
    $string =~ s/\s*\z//;

    # Explitic null/undef
    return undef if $string eq '~';

    # Single quote
    if ( $string =~ /^$re_capture_single_quoted$re_trailing_comment\z/ ) {
        return $self->_unquote_single($1);
    }

    # Double quote.
    if ( $string =~ /^$re_capture_double_quoted$re_trailing_comment\z/ ) {
        return $self->_unquote_double($1);
    }

    # Special cases
    if ( $string =~ /^[\'\"!&]/ ) {
        die \"CPAN::Meta::YAML does not support a feature in line '$string'";
    }
    return {} if $string =~ /^{}(?:\s+\#.*)?\z/;
    return [] if $string =~ /^\[\](?:\s+\#.*)?\z/;

    # Regular unquoted string
    if ( $string !~ /^[>|]/ ) {
        die \"CPAN::Meta::YAML found illegal characters in plain scalar: '$string'"
            if $string =~ /^(?:-(?:\s|$)|[\@\%\`])/ or
                $string =~ /:(?:\s|$)/;
        $string =~ s/\s+#.*\z//;
        return $string;
    }

    # Error
    die \"CPAN::Meta::YAML failed to find multi-line scalar content" unless @$lines;

    # Check the indent depth
    $lines->[0]   =~ /^(\s*)/;
    $indent->[-1] = length("$1");
    if ( defined $indent->[-2] and $indent->[-1] <= $indent->[-2] ) {
        die \"CPAN::Meta::YAML found bad indenting in line '$lines->[0]'";
    }

    # Pull the lines
    my @multiline = ();
    while ( @$lines ) {
        $lines->[0] =~ /^(\s*)/;
        last unless length($1) >= $indent->[-1];
        push @multiline, substr(shift(@$lines), $indent->[-1]);
    }

    my $j = (substr($string, 0, 1) eq '>') ? ' ' : "\n";
    my $t = (substr($string, 1, 1) eq '-') ? ''  : "\n";
    return join( $j, @multiline ) . $t;
}

# Load an array
sub _load_array {
    my ($self, $array, $indent, $lines) = @_;

    while ( @$lines ) {
        # Check for a new document
        if ( $lines->[0] =~ /^(?:---|\.\.\.)/ ) {
            while ( @$lines and $lines->[0] !~ /^---/ ) {
                shift @$lines;
            }
            return 1;
        }

        # Check the indent level
        $lines->[0] =~ /^(\s*)/;
        if ( length($1) < $indent->[-1] ) {
            return 1;
        } elsif ( length($1) > $indent->[-1] ) {
            die \"CPAN::Meta::YAML found bad indenting in line '$lines->[0]'";
        }

        if ( $lines->[0] =~ /^(\s*\-\s+)[^\'\"]\S*\s*:(?:\s+|$)/ ) {
            # Inline nested hash
            my $indent2 = length("$1");
            $lines->[0] =~ s/-/ /;
            push @$array, { };
            $self->_load_hash( $array->[-1], [ @$indent, $indent2 ], $lines );

        } elsif ( $lines->[0] =~ /^\s*\-\s*\z/ ) {
            shift @$lines;
            unless ( @$lines ) {
                push @$array, undef;
                return 1;
            }
            if ( $lines->[0] =~ /^(\s*)\-/ ) {
                my $indent2 = length("$1");
                if ( $indent->[-1] == $indent2 ) {
                    # Null array entry
                    push @$array, undef;
                } else {
                    # Naked indenter
                    push @$array, [ ];
                    $self->_load_array(
                        $array->[-1], [ @$indent, $indent2 ], $lines
                    );
                }

            } elsif ( $lines->[0] =~ /^(\s*)\S/ ) {
                push @$array, { };
                $self->_load_hash(
                    $array->[-1], [ @$indent, length("$1") ], $lines
                );

            } else {
                die \"CPAN::Meta::YAML failed to classify line '$lines->[0]'";
            }

        } elsif ( $lines->[0] =~ /^\s*\-(\s*)(.+?)\s*\z/ ) {
            # Array entry with a value
            shift @$lines;
            push @$array, $self->_load_scalar(
                "$2", [ @$indent, undef ], $lines
            );

        } elsif ( defined $indent->[-2] and $indent->[-1] == $indent->[-2] ) {
            # This is probably a structure like the following...
            # ---
            # foo:
            # - list
            # bar: value
            #
            # ... so lets return and let the hash parser handle it
            return 1;

        } else {
            die \"CPAN::Meta::YAML failed to classify line '$lines->[0]'";
        }
    }

    return 1;
}

# Load a hash
sub _load_hash {
    my ($self, $hash, $indent, $lines) = @_;

    while ( @$lines ) {
        # Check for a new document
        if ( $lines->[0] =~ /^(?:---|\.\.\.)/ ) {
            while ( @$lines and $lines->[0] !~ /^---/ ) {
                shift @$lines;
            }
            return 1;
        }

        # Check the indent level
        $lines->[0] =~ /^(\s*)/;
        if ( length($1) < $indent->[-1] ) {
            return 1;
        } elsif ( length($1) > $indent->[-1] ) {
            die \"CPAN::Meta::YAML found bad indenting in line '$lines->[0]'";
        }

        # Find the key
        my $key;

        # Quoted keys
        if ( $lines->[0] =~
            s/^\s*$re_capture_single_quoted$re_key_value_separator//
        ) {
            $key = $self->_unquote_single($1);
        }
        elsif ( $lines->[0] =~
            s/^\s*$re_capture_double_quoted$re_key_value_separator//
        ) {
            $key = $self->_unquote_double($1);
        }
        elsif ( $lines->[0] =~
            s/^\s*$re_capture_unquoted_key$re_key_value_separator//
        ) {
            $key = $1;
            $key =~ s/\s+$//;
        }
        elsif ( $lines->[0] =~ /^\s*\?/ ) {
            die \"CPAN::Meta::YAML does not support a feature in line '$lines->[0]'";
        }
        else {
            die \"CPAN::Meta::YAML failed to classify line '$lines->[0]'";
        }

        if ( exists $hash->{$key} ) {
            warn "CPAN::Meta::YAML found a duplicate key '$key' in line '$lines->[0]'";
        }

        # Do we have a value?
        if ( length $lines->[0] ) {
            # Yes
            $hash->{$key} = $self->_load_scalar(
                shift(@$lines), [ @$indent, undef ], $lines
            );
        } else {
            # An indent
            shift @$lines;
            unless ( @$lines ) {
                $hash->{$key} = undef;
                return 1;
            }
            if ( $lines->[0] =~ /^(\s*)-/ ) {
                $hash->{$key} = [];
                $self->_load_array(
                    $hash->{$key}, [ @$indent, length($1) ], $lines
                );
            } elsif ( $lines->[0] =~ /^(\s*)./ ) {
                my $indent2 = length("$1");
                if ( $indent->[-1] >= $indent2 ) {
                    # Null hash entry
                    $hash->{$key} = undef;
                } else {
                    $hash->{$key} = {};
                    $self->_load_hash(
                        $hash->{$key}, [ @$indent, length($1) ], $lines
                    );
                }
            }
        }
    }

    return 1;
}


###
# Dumper functions:

# Save an object to a file
sub _dump_file {
    my $self = shift;

    require Fcntl;

    # Check the file
    my $file = shift or $self->_error( 'You did not specify a file name' );

    my $fh;
    # flock if available (or warn if not possible for OS-specific reasons)
    if ( _can_flock() ) {
        # Open without truncation (truncate comes after lock)
        my $flags = Fcntl::O_WRONLY()|Fcntl::O_CREAT();
        sysopen( $fh, $file, $flags )
            or $self->_error("Failed to open file '$file' for writing: $!");

        # Use no translation and strict UTF-8
        binmode( $fh, ":raw:encoding(UTF-8)");

        flock( $fh, Fcntl::LOCK_EX() )
            or warn "Couldn't lock '$file' for reading: $!";

        # truncate and spew contents
        truncate $fh, 0;
        seek $fh, 0, 0;
    }
    else {
        open $fh, ">:unix:encoding(UTF-8)", $file;
    }

    # serialize and spew to the handle
    print {$fh} $self->_dump_string;

    # close the file (release the lock)
    unless ( close $fh ) {
        $self->_error("Failed to close file '$file': $!");
    }

    return 1;
}

# Save an object to a string
sub _dump_string {
    my $self = shift;
    return '' unless ref $self && @$self;

    # Iterate over the documents
    my $indent = 0;
    my @lines  = ();

    eval {
        foreach my $cursor ( @$self ) {
            push @lines, '---';

            # An empty document
            if ( ! defined $cursor ) {
                # Do nothing

            # A scalar document
            } elsif ( ! ref $cursor ) {
                $lines[-1] .= ' ' . $self->_dump_scalar( $cursor );

            # A list at the root
            } elsif ( ref $cursor eq 'ARRAY' ) {
                unless ( @$cursor ) {
                    $lines[-1] .= ' []';
                    next;
                }
                push @lines, $self->_dump_array( $cursor, $indent, {} );

            # A hash at the root
            } elsif ( ref $cursor eq 'HASH' ) {
                unless ( %$cursor ) {
                    $lines[-1] .= ' {}';
                    next;
                }
                push @lines, $self->_dump_hash( $cursor, $indent, {} );

            } else {
                die \("Cannot serialize " . ref($cursor));
            }
        }
    };
    if ( ref $@ eq 'SCALAR' ) {
        $self->_error(${$@});
    } elsif ( $@ ) {
        $self->_error($@);
    }

    join '', map { "$_\n" } @lines;
}

sub _has_internal_string_value {
    my $value = shift;
    my $b_obj = B::svref_2object(\$value);  # for round trip problem
    return $b_obj->FLAGS & B::SVf_POK();
}

sub _dump_scalar {
    my $string = $_[1];
    my $is_key = $_[2];
    # Check this before checking length or it winds up looking like a string!
    my $has_string_flag = _has_internal_string_value($string);
    return '~'  unless defined $string;
    return "''" unless length  $string;
    if (Scalar::Util::looks_like_number($string)) {
        # keys and values that have been used as strings get quoted
        if ( $is_key || $has_string_flag ) {
            return qq['$string'];
        }
        else {
            return $string;
        }
    }
    if ( $string =~ /[\x00-\x09\x0b-\x0d\x0e-\x1f\x7f-\x9f\'\n]/ ) {
        $string =~ s/\\/\\\\/g;
        $string =~ s/"/\\"/g;
        $string =~ s/\n/\\n/g;
        $string =~ s/[\x85]/\\N/g;
        $string =~ s/([\x00-\x1f])/\\$UNPRINTABLE[ord($1)]/g;
        $string =~ s/([\x7f-\x9f])/'\x' . sprintf("%X",ord($1))/ge;
        return qq|"$string"|;
    }
    if ( $string =~ /(?:^[~!@#%&*|>?:,'"`{}\[\]]|^-+$|\s|:\z)/ or
        $QUOTE{$string}
    ) {
        return "'$string'";
    }
    return $string;
}

sub _dump_array {
    my ($self, $array, $indent, $seen) = @_;
    if ( $seen->{refaddr($array)}++ ) {
        die \"CPAN::Meta::YAML does not support circular references";
    }
    my @lines  = ();
    foreach my $el ( @$array ) {
        my $line = ('  ' x $indent) . '-';
        my $type = ref $el;
        if ( ! $type ) {
            $line .= ' ' . $self->_dump_scalar( $el );
            push @lines, $line;

        } elsif ( $type eq 'ARRAY' ) {
            if ( @$el ) {
                push @lines, $line;
                push @lines, $self->_dump_array( $el, $indent + 1, $seen );
            } else {
                $line .= ' []';
                push @lines, $line;
            }

        } elsif ( $type eq 'HASH' ) {
            if ( keys %$el ) {
                push @lines, $line;
                push @lines, $self->_dump_hash( $el, $indent + 1, $seen );
            } else {
                $line .= ' {}';
                push @lines, $line;
            }

        } else {
            die \"CPAN::Meta::YAML does not support $type references";
        }
    }

    @lines;
}

sub _dump_hash {
    my ($self, $hash, $indent, $seen) = @_;
    if ( $seen->{refaddr($hash)}++ ) {
        die \"CPAN::Meta::YAML does not support circular references";
    }
    my @lines  = ();
    foreach my $name ( sort keys %$hash ) {
        my $el   = $hash->{$name};
        my $line = ('  ' x $indent) . $self->_dump_scalar($name, 1) . ":";
        my $type = ref $el;
        if ( ! $type ) {
            $line .= ' ' . $self->_dump_scalar( $el );
            push @lines, $line;

        } elsif ( $type eq 'ARRAY' ) {
            if ( @$el ) {
                push @lines, $line;
                push @lines, $self->_dump_array( $el, $indent + 1, $seen );
            } else {
                $line .= ' []';
                push @lines, $line;
            }

        } elsif ( $type eq 'HASH' ) {
            if ( keys %$el ) {
                push @lines, $line;
                push @lines, $self->_dump_hash( $el, $indent + 1, $seen );
            } else {
                $line .= ' {}';
                push @lines, $line;
            }

        } else {
            die \"CPAN::Meta::YAML does not support $type references";
        }
    }

    @lines;
}



#####################################################################
# DEPRECATED API methods:

# Error storage (DEPRECATED as of 1.57)
our $errstr    = '';

# Set error
sub _error {
    require Carp;
    $errstr = $_[1];
    $errstr =~ s/ at \S+ line \d+.*//;
    Carp::croak( $errstr );
}

# Retrieve error
my $errstr_warned;
sub errstr {
    require Carp;
    Carp::carp( "CPAN::Meta::YAML->errstr and \$CPAN::Meta::YAML::errstr is deprecated" )
        unless $errstr_warned++;
    $errstr;
}




#####################################################################
# Helper functions. Possibly not needed.


# Use to detect nv or iv
use B;

# XXX-INGY Is flock CPAN::Meta::YAML's responsibility?
# Some platforms can't flock :-(
# XXX-XDG I think it is.  When reading and writing files, we ought
# to be locking whenever possible.  People (foolishly) use YAML
# files for things like session storage, which has race issues.
my $HAS_FLOCK;
sub _can_flock {
    if ( defined $HAS_FLOCK ) {
        return $HAS_FLOCK;
    }
    else {
        require Config;
        my $c = \%Config::Config;
        $HAS_FLOCK = grep { $c->{$_} } qw/d_flock d_fcntl_can_lock d_lockf/;
        require Fcntl if $HAS_FLOCK;
        return $HAS_FLOCK;
    }
}


# XXX-INGY Is this core in 5.8.1? Can we remove this?
# XXX-XDG Scalar::Util 1.18 didn't land until 5.8.8, so we need this
#####################################################################
# Use Scalar::Util if possible, otherwise emulate it

use Scalar::Util ();
BEGIN {
    local $@;
    if ( eval { Scalar::Util->VERSION(1.18); } ) {
        *refaddr = *Scalar::Util::refaddr;
    }
    else {
        eval <<'END_PERL';
# Scalar::Util failed to load or too old
sub refaddr {
    my $pkg = ref($_[0]) or return undef;
    if ( !! UNIVERSAL::can($_[0], 'can') ) {
        bless $_[0], 'Scalar::Util::Fake';
    } else {
        $pkg = undef;
    }
    "$_[0]" =~ /0x(\w+)/;
    my $i = do { no warnings 'portable'; hex $1 };
    bless $_[0], $pkg if defined $pkg;
    $i;
}
END_PERL
    }
}

delete $CPAN::Meta::YAML::{refaddr};

1;

# XXX-INGY Doc notes I'm putting up here. Changing the doc when it's wrong
# but leaving grey area stuff up here.
#
# I would like to change Read/Write to Load/Dump below without
# changing the actual API names.
#
# It might be better to put Load/Dump API in the SYNOPSIS instead of the
# dubious OO API.
#
# null and bool explanations may be outdated.

=pod

=encoding UTF-8

=head1 NAME

CPAN::Meta::YAML - Read and write a subset of YAML for CPAN Meta files

=head1 VERSION

version 0.020

=head1 SYNOPSIS

    use CPAN::Meta::YAML;

    # reading a META file
    open $fh, "<:utf8", "META.yml";
    $yaml_text = do { local $/; <$fh> };
    $yaml = CPAN::Meta::YAML->read_string($yaml_text)
      or die CPAN::Meta::YAML->errstr;

    # finding the metadata
    $meta = $yaml->[0];

    # writing a META file
    $yaml_text = $yaml->write_string
      or die CPAN::Meta::YAML->errstr;
    open $fh, ">:utf8", "META.yml";
    print $fh $yaml_text;

=head1 DESCRIPTION

This module implements a subset of the YAML specification for use in reading
and writing CPAN metadata files like F<META.yml> and F<MYMETA.yml>.  It should
not be used for any other general YAML parsing or generation task.

NOTE: F<META.yml> (and F<MYMETA.yml>) files should be UTF-8 encoded.  Users are
responsible for proper encoding and decoding.  In particular, the C<read> and
C<write> methods do B<not> support UTF-8 and should not be used.

=head1 SUPPORT

This module is currently derived from L<YAML::Tiny> by Adam Kennedy.  If
there are bugs in how it parses a particular META.yml file, please file
a bug report in the YAML::Tiny bugtracker:
L<https://github.com/Perl-Toolchain-Gang/YAML-Tiny/issues>

=head1 SEE ALSO

L<YAML::Tiny>, L<YAML>, L<YAML::XS>

=head1 AUTHORS

=over 4

=item *

Adam Kennedy <adamk@cpan.org>

=item *

David Golden <dagolden@cpan.org>

=back

=head1 CONTRIBUTOR

=for stopwords Karen Etheridge

Karen Etheridge <ether@cpan.org>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2010 by Adam Kennedy.

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

=cut

__END__


# ABSTRACT: Read and write a subset of YAML for CPAN Meta files


PK7N%[z¤��!�!perl5/CPAN/Plugin/Specfile.pmnu��6�$=head1 NAME

CPAN::Plugin::Specfile - Proof of concept implementation of a trivial CPAN::Plugin

=head1 SYNOPSIS

  # once in the cpan shell
  o conf plugin_list push CPAN::Plugin::Specfile

  # make permanent
  o conf commit

  # any time in the cpan shell to write a spec file
  test Acme::Meta

  # disable
  # if it is the last in plugin_list:
  o conf plugin_list pop
  # otherwise, determine the index to splice:
  o conf plugin_list
  # and then use splice, e.g. to splice position 3:
  o conf plugin_list splice 3 1

=head1 DESCRIPTION

Implemented as a post-test hook, this plugin writes a specfile after
every successful test run. The content is also written to the
terminal.

As a side effect, the timestamps of the written specfiles reflect the
linear order of all dependencies.

B<WARNING:> This code is just a small demo how to use the plugin
system of the CPAN shell, not a full fledged spec file writer. Do not
expect new features in this plugin.

=head2 OPTIONS

The target directory to store the spec files in can be set using C<dir>
as in

  o conf plugin_list push CPAN::Plugin::Specfile=dir,/tmp/specfiles-000042

The default directory for this is the
C<plugins/CPAN::Plugin::Specfile> directory in the I<cpan_home>
directory.

=head1 AUTHOR

Andreas Koenig <andk@cpan.org>, Branislav Zahradnik <barney@cpan.org>

=cut

package CPAN::Plugin::Specfile;

our $VERSION = '0.02';

use File::Path;
use File::Spec;

sub __accessor {
    my ($class, $key) = @_;
    no strict 'refs';
    *{$class . '::' . $key} = sub {
        my $self = shift;
        if (@_) {
            $self->{$key} = shift;
        }
        return $self->{$key};
    };
}
BEGIN { __PACKAGE__->__accessor($_) for qw(dir dir_default) }

sub new {
    my($class, @rest) = @_;
    my $self = bless {}, $class;
    while (my($arg,$val) = splice @rest, 0, 2) {
        $self->$arg($val);
    }
    $self->dir_default(File::Spec->catdir($CPAN::Config->{cpan_home},"plugins",__PACKAGE__));
    $self;
}

sub post_test {
    my $self = shift;
    my $distribution_object = shift;
    my $distribution = $distribution_object->pretty_id;
    unless ($CPAN::META->has_inst("CPAN::DistnameInfo")){
        $CPAN::Frontend->mydie("CPAN::DistnameInfo not installed; cannot continue");
    }
    my $d = CPAN::Shell->expand("Distribution",$distribution)
        or $CPAN::Frontend->mydie("Unknowns distribution '$distribution'\n");
    my $build_dir = $d->{build_dir} or $CPAN::Frontend->mydie("Distribution has not been built yet, cannot proceed");
    my %contains = map {($_ => undef)} $d->containsmods;
    my @m;
    my $width = 16;
    my $header = sub {
        my($header,$value) = @_;
        push @m, sprintf("%-s:%*s%s\n", $header, $width-length($header), "", $value);
    };
    my $dni = CPAN::DistnameInfo->new($distribution);
    my $dist = $dni->dist;
    my $summary = CPAN::Shell->_guess_manpage($d,\%contains,$dist);
    $header->("Name", "perl-$dist");
    my $version = $dni->version;
    $header->("Version", $version);
    $header->("Release", "1%{?dist}");
#Summary:        Template processing system
#Group:          Development/Libraries
#License:        GPL+ or Artistic
#URL:            http://www.template-toolkit.org/
#Source0:        http://search.cpan.org/CPAN/authors/id/A/AB/ABW/Template-Toolkit-%{version}.tar.gz
#Patch0:         Template-2.22-SREZIC-01.patch
#BuildRoot:      %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
    for my $h_tuple
        ([Summary    => $summary],
         [Group      => "Development/Libraries"],
         [License    =>],
         [URL        =>],
         [BuildRoot  => "%{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)"],
         [Requires   => "perl(:MODULE_COMPAT_%(eval \"`%{__perl} -V:version`\"; echo \$version))"],
        ) {
        my($h,$v) = @$h_tuple;
        $v = "unknown" unless defined $v;
        $header->($h, $v);
    }
    $header->("Source0", sprintf(
                                 "http://search.cpan.org/CPAN/authors/id/%s/%s/%s",
                                 substr($distribution,0,1),
                                 substr($distribution,0,2),
                                 $distribution
                                ));
    require POSIX;
    my @xs = glob "$build_dir/*.xs"; # quick try
    unless (@xs) {
        require ExtUtils::Manifest;
        my $manifest_file = "$build_dir/MANIFEST";
        my $manifest = ExtUtils::Manifest::maniread($manifest_file);
        @xs = grep /\.xs$/, keys %$manifest;
    }
    if (! @xs) {
        $header->('BuildArch', 'noarch');
    }
    for my $k (sort keys %contains) {
        my $m = CPAN::Shell->expand("Module",$k);
        my $v = $contains{$k} = $m->cpan_version;
        my $vspec = $v eq "undef" ? "" : " = $v";
        $header->("Provides", "perl($k)$vspec");
    }
    if (my $prereq_pm = $d->{prereq_pm}) {
        my %req;
        for my $reqkey (keys %$prereq_pm) {
            while (my($k,$v) = each %{$prereq_pm->{$reqkey}}) {
                $req{$k} = $v;
            }
        }
        if (-e "$build_dir/Build.PL" && ! exists $req{"Module::Build"}) {
            $req{"Module::Build"} = 0;
        }
        for my $k (sort keys %req) {
            next if $k eq "perl";
            my $v = $req{$k};
            my $vspec = defined $v && length $v && $v > 0 ? " >= $v" : "";
            $header->(BuildRequires => "perl($k)$vspec");
            next if $k =~ /^(Module::Build)$/; # MB is always only a
                                               # BuildRequires; if we
                                               # turn it into a
                                               # Requires, then we
                                               # would have to make it
                                               # a BuildRequires
                                               # everywhere we depend
                                               # on *one* MB built
                                               # module.
            $header->(Requires => "perl($k)$vspec");
        }
    }
    push @m, "\n%define _use_internal_dependency_generator     0
%define __find_requires %{nil}
%define __find_provides %{nil}
";
    push @m, "\n%description\n%{summary}.\n";
    push @m, "\n%prep\n%setup -q -n $dist-%{version}\n";
    if (-e "$build_dir/Build.PL") {
        # see http://www.redhat.com/archives/rpm-list/2002-July/msg00110.html about RPM_BUILD_ROOT vs %{buildroot}
        push @m, <<'EOF';

%build
%{__perl} Build.PL --installdirs=vendor --libdoc installvendorman3dir
./Build

%install
rm -rf $RPM_BUILD_ROOT
./Build install destdir=$RPM_BUILD_ROOT create_packlist=0
find $RPM_BUILD_ROOT -depth -type d -exec rmdir {} 2>/dev/null \;
%{_fixperms} $RPM_BUILD_ROOT/*

%check
./Build test
EOF
    } elsif (-e "$build_dir/Makefile.PL") {
        push @m, <<'EOF';

%build
%{__perl} Makefile.PL INSTALLDIRS=vendor
make %{?_smp_mflags}

%install
rm -rf $RPM_BUILD_ROOT
make pure_install DESTDIR=$RPM_BUILD_ROOT
find $RPM_BUILD_ROOT -type f -name .packlist -exec rm -f {} ';'
find $RPM_BUILD_ROOT -depth -type d -exec rmdir {} 2>/dev/null ';'
%{_fixperms} $RPM_BUILD_ROOT/*

%check
make test
EOF
    } else {
        $CPAN::Frontend->mydie("'$distribution' has neither a Build.PL nor a Makefile.PL\n");
    }
    push @m, "\n%clean\nrm -rf \$RPM_BUILD_ROOT\n";
    my $vendorlib = @xs ? "vendorarch" : "vendorlib";
    my $date = POSIX::strftime("%a %b %d %Y", gmtime);
    my @doc = grep { -e "$build_dir/$_" } qw(README Changes);
    my $exe_stanza = "\n";
    if (my $exe_files = $d->_exe_files) {
        if (@$exe_files) {
            $exe_stanza = "%{_mandir}/man1/*.1*\n";
            for my $e (@$exe_files) {
                unless (CPAN->has_inst("File::Basename")) {
                    $CPAN::Frontend->mydie("File::Basename not installed, cannot continue");
                }
                my $basename = File::Basename::basename($e);
                $exe_stanza .= "/usr/bin/$basename\n";
            }
        }
    }
    push @m, <<EOF;

%files
%defattr(-,root,root,-)
%doc @doc
%{perl_$vendorlib}/*
%{_mandir}/man3/*.3*
$exe_stanza
%changelog
* $date  <specfile\@specfile.cpan.org> - $version-1
- autogenerated by CPAN::Plugin::Specfile()

EOF

    my $ret = join "", @m;
    $CPAN::Frontend->myprint($ret);
    my $target_dir = $self->dir || $self->dir_default;
    File::Path::mkpath($target_dir);
    my $outfile = File::Spec->catfile($target_dir, "perl-$dist.spec");
    open my $specout, ">", $outfile
        or $CPAN::Frontend->mydie("Could not open >$outfile: $!");
    print $specout $ret;
    $CPAN::Frontend->myprint("Wrote $outfile");
    $ret;
}

1;
PK7N%[��:��perl5/CPAN/Complete.pmnu��6�$# -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*-
# vim: ts=4 sts=4 sw=4:
package CPAN::Complete;
use strict;
@CPAN::Complete::ISA = qw(CPAN::Debug);
# Q: where is the "How do I add a new command" HOWTO?
# A: git log -p -1 355c44e9caaec857e4b12f51afb96498833c3e36 where andk added the report command
@CPAN::Complete::COMMANDS = sort qw(
                                    ? ! a b d h i m o q r u
                                    autobundle
                                    bye
                                    clean
                                    cvs_import
                                    dump
                                    exit
                                    failed
                                    force
                                    fforce
                                    hosts
                                    install
                                    install_tested
                                    is_tested
                                    look
                                    ls
                                    make
                                    mkmyconfig
                                    notest
                                    perldoc
                                    quit
                                    readme
                                    recent
                                    recompile
                                    reload
                                    report
                                    reports
                                    scripts
                                    smoke
                                    test
                                    upgrade
);

use vars qw(
            $VERSION
);
$VERSION = "5.5001";

package CPAN::Complete;
use strict;

sub gnu_cpl {
    my($text, $line, $start, $end) = @_;
    my(@perlret) = cpl($text, $line, $start);
    # find longest common match. Can anybody show me how to peruse
    # T::R::Gnu to have this done automatically? Seems expensive.
    return () unless @perlret;
    my($newtext) = $text;
    for (my $i = length($text)+1;;$i++) {
        last unless length($perlret[0]) && length($perlret[0]) >= $i;
        my $try = substr($perlret[0],0,$i);
        my @tries = grep {substr($_,0,$i) eq $try} @perlret;
        # warn "try[$try]tries[@tries]";
        if (@tries == @perlret) {
            $newtext = $try;
        } else {
            last;
        }
    }
    ($newtext,@perlret);
}

#-> sub CPAN::Complete::cpl ;
sub cpl {
    my($word,$line,$pos) = @_;
    $word ||= "";
    $line ||= "";
    $pos ||= 0;
    CPAN->debug("word [$word] line[$line] pos[$pos]") if $CPAN::DEBUG;
    $line =~ s/^\s*//;
    if ($line =~ s/^((?:notest|f?force)\s*)//) {
        $pos -= length($1);
    }
    my @return;
    if ($pos == 0 || $line =~ /^(?:h(?:elp)?|\?)\s/) {
        @return = grep /^\Q$word\E/, @CPAN::Complete::COMMANDS;
    } elsif ( $line !~ /^[\!abcdghimorutl]/ ) {
        @return = ();
    } elsif ($line =~ /^a\s/) {
        @return = cplx('CPAN::Author',uc($word));
    } elsif ($line =~ /^ls\s/) {
        my($author,$rest) = $word =~ m|([^/]+)/?(.*)|;
        @return = $rest ? () : map {"$_/"} cplx('CPAN::Author',uc($author||""));
        if (0 && 1==@return) { # XXX too slow and even wrong when there is a * already
            @return = grep /^\Q$word\E/, map {"$author/$_->[2]"} CPAN::Shell->expand("Author",$author)->ls("$rest*","2");
        }
    } elsif ($line =~ /^b\s/) {
        CPAN::Shell->local_bundles;
        @return = cplx('CPAN::Bundle',$word);
    } elsif ($line =~ /^d\s/) {
        @return = cplx('CPAN::Distribution',$word);
    } elsif ($line =~ m/^(
                          [mru]|make|clean|dump|get|test|install|readme|look|cvs_import|perldoc|recent
                         )\s/x ) {
        if ($word =~ /^Bundle::/) {
            CPAN::Shell->local_bundles;
        }
        @return = (cplx('CPAN::Module',$word),cplx('CPAN::Bundle',$word));
    } elsif ($line =~ /^i\s/) {
        @return = cpl_any($word);
    } elsif ($line =~ /^reload\s/) {
        @return = cpl_reload($word,$line,$pos);
    } elsif ($line =~ /^o\s/) {
        @return = cpl_option($word,$line,$pos);
    } elsif ($line =~ m/^\S+\s/ ) {
        # fallback for future commands and what we have forgotten above
        @return = (cplx('CPAN::Module',$word),cplx('CPAN::Bundle',$word));
    } else {
        @return = ();
    }
    return @return;
}

#-> sub CPAN::Complete::cplx ;
sub cplx {
    my($class, $word) = @_;
    if (CPAN::_sqlite_running()) {
        $CPAN::SQLite->search($class, "^\Q$word\E");
    }
    my $method = "id";
    $method = "pretty_id" if $class eq "CPAN::Distribution";
    sort grep /^\Q$word\E/, map { $_->$method() } $CPAN::META->all_objects($class);
}

#-> sub CPAN::Complete::cpl_any ;
sub cpl_any {
    my($word) = shift;
    return (
            cplx('CPAN::Author',$word),
            cplx('CPAN::Bundle',$word),
            cplx('CPAN::Distribution',$word),
            cplx('CPAN::Module',$word),
           );
}

#-> sub CPAN::Complete::cpl_reload ;
sub cpl_reload {
    my($word,$line,$pos) = @_;
    $word ||= "";
    my(@words) = split " ", $line;
    CPAN->debug("word[$word] line[$line] pos[$pos]") if $CPAN::DEBUG;
    my(@ok) = qw(cpan index);
    return @ok if @words == 1;
    return grep /^\Q$word\E/, @ok if @words == 2 && $word;
}

#-> sub CPAN::Complete::cpl_option ;
sub cpl_option {
    my($word,$line,$pos) = @_;
    $word ||= "";
    my(@words) = split " ", $line;
    CPAN->debug("word[$word] line[$line] pos[$pos]") if $CPAN::DEBUG;
    my(@ok) = qw(conf debug);
    return @ok if @words == 1;
    return grep /^\Q$word\E/, @ok if @words == 2 && length($word);
    if (0) {
    } elsif ($words[1] eq 'index') {
        return ();
    } elsif ($words[1] eq 'conf') {
        return CPAN::HandleConfig::cpl(@_);
    } elsif ($words[1] eq 'debug') {
        return sort grep /^\Q$word\E/i,
            sort keys %CPAN::DEBUG, 'all';
    }
}

1;
PK7N%[��䍽�perl5/CPAN/DeferredCode.pmnu��6�$package CPAN::DeferredCode;

use strict;
use vars qw/$VERSION/;

use overload fallback => 1, map { ($_ => 'run') } qw/
    bool "" 0+
/;

$VERSION = "5.50";

sub run {
    $_[0]->();
}

1;
PK7N%[M :�.�.perl5/CPAN/Distroprefs.pmnu��6�$# -*- Mode: cperl; coding: utf-8; cperl-indent-level: 4 -*-
# vim: ts=4 sts=4 sw=4:

use 5.006;
use strict;
package CPAN::Distroprefs;

use vars qw($VERSION);
$VERSION = '6.0001';

package CPAN::Distroprefs::Result;

use File::Spec;

sub new { bless $_[1] || {} => $_[0] }

sub abs { File::Spec->catfile($_[0]->dir, $_[0]->file) }

sub __cloner {
    my ($class, $name, $newclass) = @_;
    $newclass = 'CPAN::Distroprefs::Result::' . $newclass;
    no strict 'refs';
    *{$class . '::' . $name} = sub {
        $newclass->new({
            %{ $_[0] },
            %{ $_[1] },
        });
    };
}
BEGIN { __PACKAGE__->__cloner(as_warning => 'Warning') }
BEGIN { __PACKAGE__->__cloner(as_fatal   => 'Fatal') }
BEGIN { __PACKAGE__->__cloner(as_success => 'Success') }

sub __accessor {
    my ($class, $key) = @_;
    no strict 'refs';
    *{$class . '::' . $key} = sub { $_[0]->{$key} };
}
BEGIN { __PACKAGE__->__accessor($_) for qw(type file ext dir) }

sub is_warning { 0 }
sub is_fatal   { 0 }
sub is_success { 0 }

package CPAN::Distroprefs::Result::Error;
use vars qw(@ISA);
BEGIN { @ISA = 'CPAN::Distroprefs::Result' } ## no critic
BEGIN { __PACKAGE__->__accessor($_) for qw(msg) }

sub as_string {
    my ($self) = @_;
    if ($self->msg) {
        return sprintf $self->fmt_reason, $self->file, $self->msg;
    } else {
        return sprintf $self->fmt_unknown, $self->file;
    }
}

package CPAN::Distroprefs::Result::Warning;
use vars qw(@ISA);
BEGIN { @ISA = 'CPAN::Distroprefs::Result::Error' } ## no critic
sub is_warning { 1 }
sub fmt_reason  { "Error reading distroprefs file %s, skipping: %s" }
sub fmt_unknown { "Unknown error reading distroprefs file %s, skipping." }

package CPAN::Distroprefs::Result::Fatal;
use vars qw(@ISA);
BEGIN { @ISA = 'CPAN::Distroprefs::Result::Error' } ## no critic
sub is_fatal { 1 }
sub fmt_reason  { "Error reading distroprefs file %s: %s" }
sub fmt_unknown { "Unknown error reading distroprefs file %s." }

package CPAN::Distroprefs::Result::Success;
use vars qw(@ISA);
BEGIN { @ISA = 'CPAN::Distroprefs::Result' } ## no critic
BEGIN { __PACKAGE__->__accessor($_) for qw(prefs extension) }
sub is_success { 1 }

package CPAN::Distroprefs::Iterator;

sub new { bless $_[1] => $_[0] }

sub next { $_[0]->() }

package CPAN::Distroprefs;

use Carp ();
use DirHandle;

sub _load_method {
    my ($self, $loader, $result) = @_;
    return '_load_yaml' if $loader eq 'CPAN' or $loader =~ /^YAML(::|$)/;
    return '_load_' . $result->ext;
}

sub _load_yaml {
    my ($self, $loader, $result) = @_;
    my $data = eval {
        $loader eq 'CPAN'
        ? $loader->_yaml_loadfile($result->abs)
        : [ $loader->can('LoadFile')->($result->abs) ]
    };
    if (my $err = $@) {
        die $result->as_warning({
            msg  => $err,
        });
    } elsif (!$data) {
        die $result->as_warning;
    } else {
        return @$data;
    }
}

sub _load_dd {
    my ($self, $loader, $result) = @_;
    my @data;
    {
        package CPAN::Eval;
        # this caused a die in CPAN.pm, and I am leaving it 'fatal', though I'm
        # not sure why we wouldn't just skip the file as we do for all other
        # errors. -- hdp
        my $abs = $result->abs;
        open FH, "<$abs" or die $result->as_fatal(msg => "$!");
        local $/;
        my $eval = <FH>;
        close FH;
        no strict;
        eval $eval;
        if (my $err = $@) {
            die $result->as_warning({ msg => $err });
        }
        my $i = 1;
        while (${"VAR$i"}) {
            push @data, ${"VAR$i"};
            $i++;
        }
    }
    return @data;
}

sub _load_st {
    my ($self, $loader, $result) = @_;
    # eval because Storable is never forward compatible
    my @data = eval { @{scalar $loader->can('retrieve')->($result->abs) } };
    if (my $err = $@) {
        die $result->as_warning({ msg => $err });
    }
    return @data;
}

sub _build_file_list {
    if (@_ > 3) {
        die "_build_file_list should be called with 3 arguments, was called with more. First argument is '$_[0]'.";
    }
    my ($dir, $dir1, $ext_re) = @_;
    my @list;
    my $dh;
    unless (opendir($dh, $dir)) {
        $CPAN::Frontend->mywarn("ignoring prefs directory '$dir': $!");
        return @list;
    }
    while (my $fn = readdir $dh) {
        next if $fn eq '.' || $fn eq '..';
        if (-d "$dir/$fn") {
            next if $fn =~ /^[._]/; # prune .svn, .git, .hg, _darcs and what the user wants to hide
            push @list, _build_file_list("$dir/$fn", "$dir1$fn/", $ext_re);
        } else {
            if ($fn =~ $ext_re) {
                push @list, "$dir1$fn";
            }
        }
    }
    return @list;
}

sub find {
    my ($self, $dir, $ext_map) = @_;

    return CPAN::Distroprefs::Iterator->new(sub { return }) unless %$ext_map;

    my $possible_ext = join "|", map { quotemeta } keys %$ext_map;
    my $ext_re = qr/\.($possible_ext)$/;

    my @files = _build_file_list($dir, '', $ext_re);
    @files = sort @files if @files;

    # label the block so that we can use redo in the middle
    return CPAN::Distroprefs::Iterator->new(sub { LOOP: {

        my $fn = shift @files;
        return unless defined $fn;
        my ($ext) = $fn =~ $ext_re;

        my $loader = $ext_map->{$ext};

        my $result = CPAN::Distroprefs::Result->new({
            file => $fn, ext => $ext, dir => $dir
        });
        # copied from CPAN.pm; is this ever actually possible?
        redo unless -f $result->abs;

        my $load_method = $self->_load_method($loader, $result);
        my @prefs = eval { $self->$load_method($loader, $result) };
        if (my $err = $@) {
            if (ref($err) && eval { $err->isa('CPAN::Distroprefs::Result') }) {
                return $err;
            }
            # rethrow any exceptions that we did not generate
            die $err;
        } elsif (!@prefs) {
            # the loader should have handled this, but just in case:
            return $result->as_warning;
        }
        return $result->as_success({
            prefs => [
                map { CPAN::Distroprefs::Pref->new({ data => $_ }) } @prefs
            ],
        });
    } });
}

package CPAN::Distroprefs::Pref;

use Carp ();

sub new { bless $_[1] => $_[0] }

sub data { shift->{data} }

sub has_any_match { $_[0]->data->{match} ? 1 : 0 }

sub has_match {
    my $match = $_[0]->data->{match} || return 0;
    exists $match->{$_[1]} || exists $match->{"not_$_[1]"}
}

sub has_valid_subkeys {
    grep { exists $_[0]->data->{match}{$_} }
        map { $_, "not_$_" }
        $_[0]->match_attributes
}

sub _pattern {
    my $re = shift;
    my $p = eval sprintf 'qr{%s}', $re;
    if ($@) {
        $@ =~ s/\n$//;
        die "Error in Distroprefs pattern qr{$re}\n$@";
    }
    return $p;
}

sub _match_scalar {
    my ($match, $data) = @_;
    my $qr = _pattern($match);
    return $data =~ /$qr/;
}

sub _match_hash {
    my ($match, $data) = @_;
    for my $mkey (keys %$match) {
	(my $dkey = $mkey) =~ s/^not_//;
        my $val = defined $data->{$dkey} ? $data->{$dkey} : '';
	if (_match_scalar($match->{$mkey}, $val)) {
	    return 0 if $mkey =~ /^not_/;
	}
	else {
	    return 0 if $mkey !~ /^not_/;
	}
    }
    return 1;
}

sub _match {
    my ($self, $key, $data, $matcher) = @_;
    my $m = $self->data->{match};
    if (exists $m->{$key}) {
	return 0 unless $matcher->($m->{$key}, $data);
    }
    if (exists $m->{"not_$key"}) {
	return 0 if $matcher->($m->{"not_$key"}, $data);
    }
    return 1;
}

sub _scalar_match {
    my ($self, $key, $data) = @_;
    return $self->_match($key, $data, \&_match_scalar);
}

sub _hash_match {
    my ($self, $key, $data) = @_;
    return $self->_match($key, $data, \&_match_hash);
}

# do not take the order of C<keys %$match> because "module" is by far the
# slowest
sub match_attributes { qw(env distribution perl perlconfig module) }

sub match_module {
    my ($self, $modules) = @_;
    return $self->_match("module", $modules, sub {
	my($match, $data) = @_;
	my $qr = _pattern($match);
	for my $module (@$data) {
	    return 1 if $module =~ /$qr/;
	}
	return 0;
    });
}

sub match_distribution { shift->_scalar_match(distribution => @_) }
sub match_perl         { shift->_scalar_match(perl         => @_) }

sub match_perlconfig   { shift->_hash_match(perlconfig => @_) }
sub match_env          { shift->_hash_match(env        => @_) }

sub matches {
    my ($self, $arg) = @_;

    my $default_match = 0;
    for my $key (grep { $self->has_match($_) } $self->match_attributes) {
        unless (exists $arg->{$key}) {
            Carp::croak "Can't match pref: missing argument key $key";
        }
        $default_match = 1;
        my $val = $arg->{$key};
        # make it possible to avoid computing things until we have to
        if (ref($val) eq 'CODE') { $val = $val->() }
        my $meth = "match_$key";
        return 0 unless $self->$meth($val);
    }

    return $default_match;
}

1;

__END__

=head1 NAME

CPAN::Distroprefs -- read and match distroprefs

=head1 SYNOPSIS

    use CPAN::Distroprefs;

    my %info = (... distribution/environment info ...);

    my $finder = CPAN::Distroprefs->find($prefs_dir, \%ext_map);

    while (my $result = $finder->next) {

        die $result->as_string if $result->is_fatal;

        warn($result->as_string), next if $result->is_warning;

        for my $pref (@{ $result->prefs }) {
            if ($pref->matches(\%info)) {
                return $pref;
            }
        }
    }


=head1 DESCRIPTION

This module encapsulates reading L<Distroprefs|CPAN> and matching them against CPAN distributions.

=head1 INTERFACE

    my $finder = CPAN::Distroprefs->find($dir, \%ext_map);

    while (my $result = $finder->next) { ... }

Build an iterator which finds distroprefs files in the tree below the
given directory. Within the tree directories matching C<m/^[._]/> are
pruned.

C<%ext_map> is a hashref whose keys are file extensions and whose values are
modules used to load matching files:

    {
        'yml' => 'YAML::Syck',
        'dd'  => 'Data::Dumper',
        ...
    }

Each time C<< $finder->next >> is called, the iterator returns one of two
possible values:

=over

=item * a CPAN::Distroprefs::Result object

=item * C<undef>, indicating that no prefs files remain to be found

=back

=head1 RESULTS

L<C<find()>|/INTERFACE> returns CPAN::Distroprefs::Result objects to
indicate success or failure when reading a prefs file.

=head2 Common

All results share some common attributes:

=head3 type

C<success>, C<warning>, or C<fatal>

=head3 file

the file from which these prefs were read, or to which this error refers (relative filename)

=head3 ext

the file's extension, which determines how to load it

=head3 dir

the directory the file was read from

=head3 abs

the absolute path to the file

=head2 Errors

Error results (warning and fatal) contain:

=head3 msg

the error message (usually either C<$!> or a YAML error)

=head2 Successes

Success results contain:

=head3 prefs

an arrayref of CPAN::Distroprefs::Pref objects

=head1 PREFS

CPAN::Distroprefs::Pref objects represent individual distroprefs documents.
They are constructed automatically as part of C<success> results from C<find()>.

=head3 data

the pref information as a hashref, suitable for e.g. passing to Kwalify

=head3 match_attributes

returns a list of the valid match attributes (see the Distroprefs section in L<CPAN>)

currently: C<env perl perlconfig distribution module>

=head3 has_any_match

true if this pref has a 'match' attribute at all

=head3 has_valid_subkeys

true if this pref has a 'match' attribute and at least one valid match attribute

=head3 matches

  if ($pref->matches(\%arg)) { ... }

true if this pref matches the passed-in hashref, which must have a value for
each of the C<match_attributes> (above)

=head1 LICENSE

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

=cut
PK7N%[�eE��"perl5/Alien/Build/Version/Basic.pmnu��6�$package Alien::Build::Version::Basic;

use strict;
use warnings;
use 5.008004;
use Carp ();
use Exporter qw( import );
use overload
  '<=>'    => sub { shift->cmp(@_) },
  'cmp'    => sub { shift->cmp(@_) },
  '""'     => sub { shift->as_string },
  bool     => sub { 1 },
  fallback => 1;

our @EXPORT_OK = qw( version );

# ABSTRACT: Very basic version object for Alien::Build
our $VERSION = '2.84'; # VERSION


sub new
{
  my($class, $value) = @_;
  $value =~ s/\.$//;  # trim trailing dot
  Carp::croak("invalud version: $value")
    unless $value =~ /^[0-9]+(\.[0-9]+)*$/;
  bless \$value, $class;
}


sub version ($)
{
  my($value) = @_;
  __PACKAGE__->new($value);
}


sub as_string
{
  my($self) = @_;
  "@{[ $$self ]}";
}


sub cmp
{
  my @x = split /\./, ${$_[0]};
  my @y = split /\./, ${ref($_[1]) ? $_[1] : version($_[1])};

  while(@x or @y)
  {
    my $x = (shift @x) || 0;
    my $y = (shift @y) || 0;
    return $x <=> $y if $x <=> $y;
  }

  0;
}


1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Version::Basic - Very basic version object for Alien::Build

=head1 VERSION

version 2.84

=head1 SYNOPSIS

OO interface:

 use Alien::Build::Version::Basic;
 
 my $version = Alien::Build::Version::Basic->new('1.2.3');
 if($version > '1.2.2')  # true
 {
   ...
 }

Function interface:

 use Alien::Build::Version::Basic qw( version );
 
 if(version('1.2.3') > version('1.2.2')) # true
 {
   ...
 }
 
 my @sorted = sort map { version($_) } qw( 2.1 1.2.3 1.2.2 );
 # will come out in the order 1.2.2, 1.2.3, 2.1

=head1 DESCRIPTION

This module provides a very basic class for comparing versions.
This is already a crowded space on CPAN.  Parts of L<Alien::Build>
already use L<Sort::Versions>, which is fine for sorting versions.
Sometimes you need to compare to see if versions match exact I<values>,
and the best candidates (such as L<Sort::Versions> on CPAN compare
C<1.2.3.0> and C<1.2.3> as being different.  This class compares
those two as the same.

This class is also quite limited, in that it only works with version
schemes using a doted version numbers or real numbers with a fixed
number of digits.  Versions with: dashes, letters, hex digits, or
anything else are not supported.

This class overloads both C<E<lt>=E<gt>> and C<cmp> to compare the version in
the way that you would expect for version numbers.  This way you can
compare versions like numbers, or sort them using sort.

 if(version($v1) > version($v2))
 {
   ...
 }
 
 my @sorted = sort map { version($_) } @unsorted;

it also overloads C<""> to stringify as whatever string value you
passed to the constructor.

=head1 CONSTRUCTOR

=head2 new

 my $version = Alien::Build::Version::Basic->new($value);

This is the long form of the constructor, if you don't want to import
anything into your namespace.

=head2 version

 my $version = version($value);

This is the short form of the constructor, if you are sane.  It is
NOT exported by default so you will have to explicitly import it.

=head1 METHODS

=head2 as_string

 my $string = $version->as_string;
 my $string = "$version";

Returns the string representation of the version object.

=head2 cmp

 my $bool = $version->cmp($other);
 my $bool = $version <=> $other;
 my $bool = $version cmp $other;

Returns C<-1>, C<0> or C<1> just like the regular C<E<lt>=E<gt>> and C<cmp>
operators.  Although C<$version> must be a version object, C<$other> may
be either a version object, or a string that could be used to create a
valid version object.

=head1 SEE ALSO

=over 4

=item L<Sort::Versions>

Good, especially if you have to support rpm style versions (like C<1.2.3-2-b>)
or don't care if trailing zeros (C<1.2.3> vs C<1.2.3.0>) are treated as
different values.

=item L<version>

Problematic for historical reasons.

=back

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK7N%[3�[c�#�#)perl5/Alien/Build/Manual/Contributing.podnu��6�$# PODNAME: Alien::Build::Manual::Contributing
# ABSTRACT: Over-detailed contributing guide
# VERSION

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Manual::Contributing - Over-detailed contributing guide

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 perldoc Alien::Build::Manual::Contributing

=head1 DESCRIPTION

Thank you for considering to contribute to my open source project!  If
you have a small patch please consider just submitting it.  Doing so
through the project GitHub is probably the best way:

L<https://github.com/plicease/Alien-Build/issues>

If you have a more invasive enhancement or bugfix to contribute, please
take the time to review these guidelines.  In general it is good idea to
work closely with the L<Alien::Build> developers, and the best way to
contact them is on the C<#native> IRC channel on irc.perl.org.

=head2 History

Joel Berger wrote the original L<Alien::Base>.  This distribution
included the runtime code L<Alien::Base> and an installer class
L<Alien::Base::ModuleBuild>.  The significant thing about L<Alien::Base>
was that it provided tools to make it relatively easy for people to roll
their own L<Alien> distributions.  Over time, the PerlAlien (github
organization) or "Alien::Base team" has taken over development of
L<Alien::Base> with myself (Graham Ollis) being responsible for
integration and releases.  Joel Berger is still involved in the project.

Since the original development of L<Alien::Base>, L<Module::Build>, on
which L<Alien::Base::ModuleBuild> is based, has been removed from the
core of Perl.  It seemed worthwhile to write a replacement installer
that works with L<ExtUtils::MakeMaker> which IS still bundled with the
Perl core.  Because this is a significant undertaking it is my intention
to integrate the many lessons learned by Joel Berger, myself and the
"Alien::Base team" as possible.  If the interface seems good then it is
because I've stolen the ideas from some pretty good places.

=head2 Philosophy

=head3 Alien runtime should be as config-only as possible.

Ideally the code for an L<Alien::Base> based L<Alien> should simply
inherit from L<Alien::Base>, like so:

 package Alien::libfoo;
 
 use parent qw( Alien::Base );
 
 1;

The detection logic should be done by the installer code (L<alienfile>
and L<Alien::Build>) and saved into runtime properties (see
L<Alien::Build/runtime_prop>).  And as much as
possible the runtime should be implemented in the base class (L<Alien::Base>).
Where reasonable, the base class should be expanded to meet the needs
of this arrangement.

=head3 when downloading a package grab the latest version

If the maintainer of an L<Alien> disappears for a while, and if the
version downloaded during a "share" install is hardcoded in the
L<alienfile>, it can be problematic for end-users.

There are exceptions, of course, in particular when a package provides
a very unstable interface from version to version it makes sense
to hard code the version and for the Alien developer and Alien consumer
developer to coordinate closely.

=head3 when installing a package the operating system as a whole should not be affected

The convenience of using an L<Alien> is that a user of a CPAN module
that consumes an L<Alien> doesn't need to know the exact incantation
to install the libraries on which it depends (or indeed it may not be
easily installed through the package manager anyway).

As a corollary, a user of a CPAN module that consumes an L<Alien>
module shouldn't expect operating system level packages to be
installed, or for these packages to be installed in common system
level directories, like C</usr/local> or C</opt>.  Instead a "share"
directory associated with the Perl install and L<Alien> module
should be used.

Plugins that require user opt-in could be written to prompt a user
to automatically install operating system packages, but this should
never be done by default or without consent by the user.

=head3 avoid dependencies

One of the challenges with L<Alien> development is that you are by the
nature of the problem, trying to make everyone happy.  Developers
working out of CPAN just want stuff to work, and some build environments
can be hostile in terms of tool availability, so for reliability you end
up pulling a lot of dependencies.  On the other hand, operating system
vendors who are building Perl modules usually want to use the system
version of a library so that they do not have to patch libraries in
multiple places.  Such vendors have to package any extra dependencies
and having to do so for packages that the don't even use makes them
understandably unhappy.

As general policy the L<Alien::Build> core should have as few
dependencies as possible, and should only pull extra dependencies if
they are needed.  Where dependencies cannot be avoidable, popular and
reliable CPAN modules, which are already available as packages in the
major Linux vendors (Debian, Red Hat) should be preferred.

As such L<Alien::Build> is hyper aggressive at using dynamic
prerequisites.

=head3 interface agnostic

One of the challenges with L<Alien::Base::ModuleBuild> was that
L<Module::Build> was pulled from the core.  In addition, there is a
degree of hostility toward L<Module::Build> in some corners of the Perl
community.  I agree with Joel Berger's rationale for choosing
L<Module::Build> at the time, as I believe its interface more easily
lends itself to building L<Alien> distributions.

That said, an important feature of L<Alien::Build> is that it is
installer agnostic.  Although it is initially designed to work with
L<ExtUtils::MakeMaker>, it has been designed from the ground up to work
with any installer (Perl, or otherwise).

As an extension of this, although L<Alien::Build> may have external CPAN
dependencies, they should not be exposed to developers USING
L<Alien::Build>.  As an example, L<Path::Tiny> is used heavily
internally because it does what L<File::Spec> does, plus the things that
it doesn't, and uses forward slashes on Windows (backslashes are the
"correct separator on windows, but actually using them tends to break
everything).  However, there aren't any interfaces in L<Alien::Build>
that will return a L<Path::Tiny> object (or if there are, then this is a
bug).

This means that if we ever need to port L<Alien::Build> to a platform
that doesn't support L<Path::Tiny> (such as VMS), then it may require
some work to L<Alien::Build> itself, modules that USE L<Alien::Build>
shouldn't need to be modified.

=head3 plugable

The actual logic that probes the system, downloads source and builds it
should be as pluggable as possible.  One of the challenges with
L<Alien::Base::ModuleBuild> was that it was designed to work well with
software that works with C<autoconf> and C<pkg-config>.  While you can
build with other tools, you have to know a bit of how the installer
logic works, and which hooks need to be tweaked.

L<Alien::Build> has plugins for C<autoconf>, C<pkgconf> (successor of
C<pkg-config>), vanilla Makefiles, and CMake.  If your build system
doesn't have a plugin, then all you have to do is write one!  Plugins
that prove their worth may be merged into the L<Alien::Build> core.
Plugins that after a while feel like maybe not such a good idea may be
removed from the core, or even from CPAN itself.

In addition, L<Alien::Build> has a special type of plugin, called a
negotiator which picks the best plugin for the particular environment
that it is running in.  This way, as development of the negotiator and
plugins develop over time modules that use L<Alien::Build> will benefit,
without having to change the way they interface with L<Alien::Build>

=head1 ACKNOWLEDGEMENT

I would like to that Joel Berger for getting things running in the first
place.  Also important to thank other members of the "Alien::Base team":

Zaki Mughal (SIVOAIS)

Ed J (ETJ, mohawk)

Also kind thanks to all of the developers who have contributed to
L<Alien::Base> over the years:

L<https://metacpan.org/pod/Alien::Base#CONTRIBUTORS>

=head1 SEE ALSO

=over 4

=item L<Alien::Build::Manual>

Other L<Alien::Build> manuals.

=back

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK7N%[��5WW"perl5/Alien/Build/Manual/Alien.podnu��6�$# PODNAME: Alien::Build::Manual::Alien
# ABSTRACT: General alien author documentation
# VERSION

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Manual::Alien - General alien author documentation

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 perldoc Alien::Build::Manual::Alien

=head1 DESCRIPTION

The goal of the L<Alien> namespace is to provide non-CPAN dependencies (so called "Alien" dependencies) for
CPAN modules. The history and intent of this idea is documented in the documentation-only L<Alien> module.
The C<Alien-Build> distribution provides a framework for building aliens. The intent is to fix bugs and
enhance the interface of a number of common tools so that all aliens may benefit. The distribution is broken
up into these parts:

=over 4

=item The Alien Installer (configure / build-time)

L<Alien::Build> and L<alienfile> are used to detect and install aliens. They are further documented in
L<Alien::Build::Manual::AlienAuthor>.

=item The Alien Runtime (runtime)

L<Alien::Base> is the base class for aliens in the C<Alien-Build> system. Its use by Alien consumers
is documented in L<Alien::Build::Manual::AlienUser>.

=item The Plugin system (configure / build-time)

Because many packages are implemented using different tools, the detection, build and install logic
for a particular L<Alien> can vary a lot.  As such, much of L<Alien::Build> is implemented as a
series of plugins that inherit from L<Alien::Build::Plugin>.  An overview of building your own
plugins is documented in L<Alien::Build::Manual::PluginAuthor>.

=back

Additional useful documentation may be found here:

=over 4

=item FAQ

L<Alien::Build::Manual::FAQ>

=item Contributing

L<Alien::Build::Manual::Contributing>

=back

=head1 SEE ALSO

=over 4

=item L<Alien::Build::Manual>

Other L<Alien::Build> manuals.

=back

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK7N%[=!�.�T�T)perl5/Alien/Build/Manual/PluginAuthor.podnu��6�$# PODNAME: Alien::Build::Manual::PluginAuthor
# ABSTRACT: Alien::Build plugin author documentation
# VERSION

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Manual::PluginAuthor - Alien::Build plugin author documentation

=head1 VERSION

version 2.84

=head1 SYNOPSIS

your plugin:

 package Alien::Build::Plugin::Build::MyPlugin;
 
 use strict;
 use warnings;
 use Alien::Build::Plugin;
 
 has arg1 => 'default_for arg1';
 has arg2 => sub { [ 'default', 'for', 'arg2' ] };
 
 sub init
 {
   my($self, $meta) = @_;
   ...
 }
 
 1;

and then from L<alienfile>:

 use alienfile;
 plugin 'Build::MyPlugin' => (
   arg1 => 'override for arg1',
   arg2 => [ 'something', 'else' ],
 );

=for html <p>flowchart</p>
<div style="display: flex"><div style="margin: 3px; flex: 1 1 50%">
<img src="image/PluginAuthor-flowchart.png" style="max-width: 100%">
</div></div>
<p><b>Notes</b>: The colored blocks indicate <tt>alienfile</tt> blocks.
Hooks are indicated as predefined process (rectangle with double struck
vertical edges).  Hooks that can easily be implemented from an
<tt>alienfile</tt> are indicated in blue (Note that <tt>[]</tt> is used
to indicate passing in an array reference, but a subroutine
reference can also be used).  For simplicity, the the flowchart does
not include when required modules are loaded.  Except for configure
time requirements, they are loaded when the corresponding <tt>alienfile</tt>
blocks are entered.  It is not shown, but generally any plugin can cause
a <b>Fail</b> by throwing an exception with <tt>die</tt>.</p>

Perlish pseudo code for how plugins are called:

 my $probe;
 my $override = override();
 
 if($override eq 'system') {
 
   $probe = probe();
 
   if($probe ne 'system') {
     die 'system tool or library not found';
   }
 
 }
 
 elsif($override eq 'default') {
   $probe = probe();
 
 } else { # $override eq 'share'
   # note that in this instance the
   # probe hook is never called
   $probe = 'share';
 }
 
 if($probe eq 'system') {
   gather_system();
 
 } else { # $probe eq 'share'
 
   download();
   extract();
   patch();
   build();
   gather_share();
 
   # Check to see if there isa build_ffi hook
   if(defined &build_ffi) {
     patch_ffi();
     build_ffi();
     gather_ffi();
   }
 }
 
 # By default this just returns the value of $ENV{ALIEN_INSTALL_TYPE}
 sub override {
   return $ENV{ALIEN_INSTALL_TYPE};
 }
 
 # Default download implementation; can be
 # replaced by specifying a different download
 # hook.  See Alien::Build::Plugin::Core::Download
 # for detailed implementation.
 sub download {
 
   my $response = fetch();
 
   if($response->{type} eq 'html' || $response->{type} eq 'dir_listing') {
     # decode will transform an HTML listing (html) or a FTP directory
     # listing (dir_listing) into a regular list
     $response = decode($response);
   }
 
   if($response->{type} eq 'list') {
 
     # prefer will filter bad entries in the list
     # and sort them so that the first one is
     # the one that we want
     $response = prefer($response);
 
     my $first_preferred = $res->{list}->[0];
 
     # prefer can sometimes infer the version from the
     # filename.
     if(defined $first_preferred->{version}) {
       # not a hook
       runtime_prop->{version} = $first_preferred->{version};
     }
 
     $response = fetch($first_preferred);
 
   }
 
   if($response->{type} eq 'file') {
     # not a hook
     write_file_to_disk $response;
   }
 
 }

=head1 DESCRIPTION

This document explains how to write L<Alien::Build> plugins using the
L<Alien::Build::Plugin> base class.

=head2 Writing plugins

Plugins use L<Alien::Build::Plugin>, which sets the appropriate base
class, and provides you with the C<has> property builder.  C<has> takes
two arguments, the name of the property and the default value.  (As
with L<Moose> and L<Moo>, you should use a code reference to specify
default values for non-string defaults).  No B<not> set this as your
plugin's base class directly:

 use parent qw( Alien::Build::Plugin );  # wrong
 use Alien::Build::Plugin;               # right

The only method that you need to implement is C<init>.  From this method
you can add hooks to change the behavior of the L<alienfile> recipe.
This is a very simple example of a probe hook, with the actual probe
logic removed:

 sub init
 {
   my($self, $meta) = @_;
   $meta->register_hook(
     probe => sub {
       my($build) = @_;
       if( ... )
       {
         return 'system';
       }
       else
       {
         return 'share';
       }
     },
   );
 }

Hooks get the L<Alien::Build> instance as their first argument, and depending
on the hook may get additional arguments.

=head2 Modifying hooks

You can also modify hooks using C<before_hook>, C<around_hook> and C<after_hook>,
similar to L<Moose> modifiers:

 sub init
 {
   my($self, $meta) = @_;
 
   $meta->before_hook(
     build => sub {
       my($build) = @_;
       $build->log('this runs before the build');
     },
   );
 
   $meta->after_hook(
     build => sub {
       my($build) = @_;
       $build->log('this runs after the build');
     },
   );
 
   $meta->around_hook(
     build => sub {
       my $orig = shift;
 
       # around hooks are useful for setting environment variables
       local $ENV{CPPFLAGS} = '-I/foo/include';
 
       $orig->(@_);
     },
   );
 }

=head2 Testing plugins

You can and should write tests for your plugin.  The best way to do
this is using L<Test::Alien::Build>, which allows you to write an
inline L<alienfile> in your test.  Here is an example:

 use Test::V0;
 use Test::Alien::Build;
 
 my $build = alienfile_ok q{
   use alienfile;
   plugin 'Build::MyPlugin' => (
     arg1 => 'override for arg1',
     arg2 => [ 'something', 'else' ],
   );
   ...
 };
 
 # you can interrogate $build, it is an instance of L<Alien::Build>.
 
 my $alien = alien_build_ok;
 
 # you can interrogate $alien, it is an instance of L<Alien::Base>.

=head2 Negotiator plugins

A Negotiator plugin doesn't itself typically implement anything on
its own, but picks the best plugin to achieve a particular goal.

The "best" plugin can in some cases vary depending on the platform
or tools that are available.  For example The
L<download negotiator|Alien::Build::Plugin::Download::Negotiate>
might choose to use the fetch plugin that relies on the command line
C<curl>, or it might choose the fetch plugin that relies on the Perl
module L<HTTP::Tiny> depending on the platform and what is already
installed.  (For either to be useful they have to support SSL).

The Negotiator plugin is by convention named something like
C<Alien::Build::Plugin::*::Negotiate>, but is typically invoked
without the C<::Negotiate> suffix.  For example:

 plugin 'Download'; # is short for Alien::Build::Plugin::Download::Negotiator

Here is a simple example of a negotiator which picks C<curl> if already
installed and L<HTTP::Tiny> otherwise.  (The actual download plugin
is a lot smarter and complicated than this, but this is a good
simplified example).

 package Alien::Build::Plugin::Download::Negotiate;
 
 use strict;
 use warnings;
 use Alien::Build::Plugin;
 use File::Which qw( which );
 
 sub init
 {
   my($self, $meta) = @_;
 
   if(which('curl')) {
     $meta->apply_plugin('Fetch::Curl');
   } else {
     $meta->apply_plugin('Fetch::HTTPTiny');
   }
 }

=head2 Hooks

The remainder of this document is a reference for the hooks that you
can register.  Generally speaking you can register any hook that you
like, but some care must be taken as some hooks have default behavior
that will be overridden when you register a hook.  The hooks are
presented in alphabetical order.  The execution order is shown
in the flowchart above (if you are browsing the HTML version of this
document), or the Perlish pseudo code in the synopsis section.

=head1 HOOKS

=head2 build hook

 $meta->register_hook( build => sub {
   my($build) = @_;
   ...
 });

This does the main build of the alienized project and installs it into
the staging area.  The current directory is the build root.  You need
to run whatever tools are necessary for the project, and install them
into C<$build->install_prop->{prefix}> (C<%{.install.prefix}>).

=head2 build_ffi hook

 $meta->register_hook( build_ffi => sub {
   my($build) = @_;
   ...
 });

This is the same as L<build|/"build hook">, except it fires only on a FFI build.

=head2 decode hook

 $meta->register_hook( decode => sub {
   my($build, $res) = @_;
   ...
 }

This hook takes a response hash reference from the C<fetch> hook above
with a type of C<html> or C<dir_listing> and converts it into a response
hash reference of type C<list>.  In short it takes an HTML or FTP file
listing response from a fetch hook and converts it into a list of filenames
and links that can be used by the prefer hook to choose the correct file to
download.  See the L<fetch hook|/"fetch hook"> for the specification of the
input and response hash references.

=head2 check_digest hook

 # implement the well known FOO-92 digest
 $meta->register_hook( check_digest => sub {
   my($build, $file, $algorithm, $digest) = @_;
   if($algorithm ne 'FOO92') {
     return 0;
   }
   my $actual = foo92_hex_digest($file);
   if($actual eq $digest) {
     return 1;
   } else {
     die "Digest FOO92 does not match: got $actual, expected $digest";
   }
 });

This hook should check the given C<$file> (the format is the same as used by
L<the fetch hook|/"fetch hook">) matches the given C<$digest> using the
given C<$algorithm>.  If the plugin does not support the given algorithm,
then it should return a false value.  If the digest does not match, it
should throw an exception.  If the digest matches, it should return a
true value.

=head2 clean_install

 $meta->register_hook( clean_install => sub {
   my($build) = @_;
 });

This hook allows you to remove files from the final install location before
the files are installed by the installer layer (examples: L<Alien::Build::MM>,
L<Alien::Build::MB> or L<App::af>).  This hook is not called by default,
and must be enabled via the interface to the installer layer
(example: L<Alien::Build::MM/clean_install>).

This hook SHOULD NOT remove the C<_alien> directory or its content from the
install location.

The default implementation removes all the files EXCEPT the C<_alien> directory
and its content.

=head2 download hook

 $meta->register_hook( download => sub {
   my($build) = @_;
   ...
 });

This hook is used to download from the internet the source.  Either as
an archive (like tar, zip, etc), or as a directory of files (C<git clone>,
etc).  When the hook is called, the current working directory will be a
new empty directory, so you can save the download to the current
directory.  If you store a single file in the directory, L<Alien::Build>
will assume that it is an archive, which will be processed by the
L<extract hook|/"extract hook">.  If you store multiple files, L<Alien::Build> will
assume the current directory is the source root.  If no files are stored
at all, an exception with an appropriate diagnostic will be thrown.

B<Note>: If you register this hook, then the fetch, decode and prefer
hooks will NOT be called, unless you call them yourself from this hook.

=head2 extract hook

 $meta->register_hook( extract => sub {
   my($build, $archive) = @_;
   ...
 });

This hook is used to extract an archive that has already been downloaded.
L<Alien::Build> already has plugins for the most common archive formats,
so you will likely only need this to add support for new or novel archive
formats.  When this hook is called, the current working directory will
be a new empty directory, so you can save the content of the archive to
the current directory.  If a single directory is written to the current
directory, L<Alien::Build> will assume that is the root directory of the
package.  If multiple files and/or directories are present, that will
indicate that the current working directory is the root of the package.
The logic typically handles correctly the default behavior for tar
(where packages are typically extracted to a subdirectory) and for
zip (where packages are typically extracted to the current directory).

=head2 fetch hook

 package Alien::Build::Plugin::MyPlugin;
 
 use strict;
 use warnings;
 use Alien::Build::Plugin;
 use Carp ();
 
 has '+url' => sub { Carp::croak "url is required property" };
 
 sub init
 {
   my($self, $meta) = @_;
 
   $meta->register_hook( fetch => sub {
     my($build, $url, %options) = @_;
     ...
   }
 }
 
 1;

Used to fetch a resource.  The first time it will be called without an
argument (or with C<$url> set to C<undef>, so the configuration used to
find the resource should be specified by the plugin's properties.  On
subsequent calls the first argument will be a URL.

The C<%options> hash may contain these options:

=over 4

=item http_headers

HTTP request headers, if an appropriate protocol is being used.  The
headers are provided as an array reference of key/value pairs, which
allows for duplicate header keys with multiple values.

If a non-HTTP protocol is used, or if the plugin cannot otherwise
send HTTP request headers, the plugin SHOULD issue a warning using
the C<< $build->log >> method, but because this option wasn't part
of the original spec, the plugin MAY no issue that warning while
ignoring it.

=back

Note that versions of L<Alien::Build> prior to 2.39 did not pass the
options hash into the fetch plugin.

Normally the first fetch will be to either a file or a directory listing.
If it is a file then the content should be returned as a hash reference
with the following keys:

 # content of file stored in Perl
 return {
   type     => 'file',
   filename => $filename,
   content  => $content,
   version  => $version,  # optional, if known
   protocol => $protocol, # AB 2.60 optional, but recommended
 };
 
 # content of file stored in the filesystem
 return {
   type     => 'file',
   filename => $filename,
   path     => $path,     # full file system path to file
   version  => $version,  # optional, if known
   tmp      => $tmp,      # optional
   protocol => $protocol, # AB 2.60 optional, but recommended
 };

C<$tmp> if set will indicate if the file is temporary or not, and can
be used by L<Alien::Build> to save a copy in some cases.  The default
is true, so L<Alien::Build> assumes the file or directory is temporary
if you don't tell it otherwise.  Probably the most common situation
when you would set C<tmp> to false, is when the file is bundled inside
the L<Alien> distribution.  See L<Alien::Build::Plugin::Fetch::Local>
for example.

If the URL points to a directory listing you should return it as either
a hash reference containing a list of files:

 return {
   type => 'list',
   list => [
     # filename: each filename should be just the
     #   filename portion, no path or url.
     # url: each url should be the complete url
     #   needed to fetch the file.
     # version: OPTIONAL, may be provided by some fetch or prefer
     { filename => $filename1, url => $url1, version => $version1 },
     { filename => $filename2, url => $url2, version => $version2 },
   ],
   protocol => $protocol, # AB 2.60 optional, but recommended
 };

or if the listing is in HTML format as a hash reference containing the
HTML information:

 return {
   type => 'html',
   charset  => $charset, # optional
   base     => $base,    # the base URL: used for computing relative URLs
   content  => $content, # the HTML content
   protocol => $protocol, # optional, but recommended
 };

or a directory listing (usually produced by an FTP servers) as a hash
reference:

 return {
   type     => 'dir_listing',
   base     => $base,
   content  => $content,
   protocol => $protocol, # AB 2.60 optional, but recommended
 };

[version 2.60]

For all of these responses C<$protocol> is optional, since it was not part
of the original spec, however it is strongly recommended that you include
this field, because future versions of L<Alien::Build> will use this to
determine if a file was downloaded securely (that is via a secure protocol
such as SSL).

Some plugins (like L<decode plugins |Alien::Build::Plugin::Decode>) trans
late a file hash from one type to another, they should maintain the
C<$protocol> from the old to the new representation of the file.

=head2 gather_ffi hook

 $meta->register_hook( gather_ffi => sub {
   my($build) = @_;
   $build->runtime_prop->{cflags}  = ...;
   $build->runtime_prop->{libs}    = ...;
   $build->runtime_prop->{version} = ...;
 });

This hook is called for a FFI build to determine the properties
necessary for using the library or tool.  These properties should be
stored in the L<runtime_prop|Alien::Build/runtime_prop> hash as shown above.
Typical properties that are needed for libraries are cflags and libs.
If at all possible you should also try to determine the version of the
library or tool.

=head2 gather_share hook

 $meta->register_hook( gather_share => sub {
   my($build) = @_;
   $build->runtime_prop->{cflags}  = ...;
   $build->runtime_prop->{libs}    = ...;
   $build->runtime_prop->{version} = ...;
 });

This hook is called for a share install to determine the properties
necessary for using the library or tool.  These properties should be
stored in the L<runtime_prop|Alien::Build/runtime_prop> hash as shown above.
Typical properties that are needed for libraries are cflags and libs.
If at all possible you should also try to determine the version of the
library or tool.

=head2 gather_system hook

 $meta->register_hook( gather_system => sub {
   my($build) = @_;
   $build->runtime_prop->{cflags}  = ...;
   $build->runtime_prop->{libs}    = ...;
   $build->runtime_prop->{version} = ...;
 });

This hook is called for a system install to determine the properties
necessary for using the library or tool.  These properties should be
stored in the L<runtime_prop|Alien::Build/runtime_prop> hash as shown above.
Typical properties that are needed for libraries are cflags and libs.
If at all possible you should also try to determine the version of the
library or tool.

=head2 override hook

 $meta->register_hook( override => sub {
   my($build) = @_;
   return $ENV{ALIEN_INSTALL_TYPE} || '';
 });

This allows you to alter the override logic.  It should return one of
C<share>, C<system>, C<default> or C<''>.  The default implementation
is shown above.  L<Alien::Build::Plugin::Probe::Override> and
L<Alien::Build::Plugin::Probe::OverrideCI> are examples of how you
can use this hook.

=head2 patch hook

 $meta->register_hook( patch => sub {
   my($build) = @_;
   ...
 });

This hook is completely optional.  If registered, it will be triggered after
extraction and before build.  It allows you to apply any patches or make any
modifications to the source if they are necessary.

=head2 patch_ffi hook

 $meta->register_hook( patch_ffi => sub {
   my($build) = @_;
   ...
 });

This hook is exactly like the L<patch hook|/"patch hook">, except it fires only on an
FFI build.

=head2 prefer hook

 $meta->register_hook( prefer => sub {
   my($build, $res) = @_;
   return {
     type => 'list',
     list => [sort @{ $res->{list} }],
   };
 }

This hook sorts candidates from a listing generated from either the C<fetch>
or C<decode> hooks.  It should return a new list hash reference with the
candidates sorted from best to worst.  It may also remove candidates
that are totally unacceptable.

=head2 probe hook

 $meta->register_hook( probe => sub {
   my($build) = @_;
   return 'system' if ...; # system install
   return 'share';         # otherwise
 });
 
 $meta->register_hook( probe => [ $command ] );

This hook should return the string C<system> if the operating
system provides the library or tool.  It should return C<share>
otherwise.

You can also use a command that returns true when the tool
or library is available.  For example for use with C<pkg-config>:

 $meta->register_hook( probe =>
   [ '%{pkgconf} --exists libfoo' ] );

Or if you needed a minimum version:

 $meta->register_hook( probe =>
   [ '%{pkgconf} --atleast-version=1.00 libfoo' ] );

Note that this hook SHOULD NOT gather system properties, such as
cflags, libs, versions, etc, because the probe hook will be skipped
in the event the environment variable C<ALIEN_INSTALL_TYPE> is set.
The detection of these properties should instead be done by the
L<gather_system|/"gather_system hook"> hook.

Multiple probe hooks can be given.  These will be used in sequence,
stopping at the first that detects a system installation.

=head1 SEE ALSO

=over 4

=item L<Alien::Build::Manual>

Other L<Alien::Build> manuals.

=back

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK7N%[1yjbjb(perl5/Alien/Build/Manual/AlienAuthor.podnu��6�$# PODNAME: Alien::Build::Manual::AlienAuthor
# ABSTRACT: Alien author documentation
# VERSION

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Manual::AlienAuthor - Alien author documentation

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 perldoc Alien::Build::Manual::AlienAuthor

=head1 DESCRIPTION

B<Note>: Please read the entire document before you get started in
writing your own L<alienfile>.  The section on dynamic vs. static
libraries will likely save you a lot of grief if you read it now!

This document is intended to teach L<Alien> authors how to build their
own L<Alien> distribution using L<Alien::Build> and L<Alien::Base>.
Such an L<Alien> distribution consists of three essential parts:

=over 4

=item An L<alienfile>

This is a recipe for how to 1) detect an already installed version of
the library or tool you are alienizing 2) download and build the library
or tool that you are alienizing and 3) gather the configuration settings
necessary for the use of that library or tool.

=item An installer C<Makefile.PL> or C<Build.PL> or a C<dist.ini> if you are using L<Dist::Zilla>

This is a thin layer between your L<alienfile> recipe, and the Perl
installer (either L<ExtUtils::MakeMaker> or L<Module::Build>.

=item A Perl class (.pm file) that inherits from L<Alien::Base>

For most L<Alien>s this does not need to be customized at all, since
L<Alien::Base> usually does what you need.

=back

For example if you were alienizing a library called libfoo, you might
have these files:

 Alien-Libfoo-1.00/Makefile.PL
 Alien-Libfoo-1.00/alienfile
 Alien-Libfoo-1.00/lib/Alien/Libfoo.pm

This document will focus mainly on instructing you how to construct an
L<alienfile>, but we will also briefly cover making a simple
C<Makefile.PL> or C<dist.ini> to go along with it.  We will also touch
on when you might want to extend your subclass to add non-standard
functionality.

=head2 Using commands

Most software libraries and tools will come with instructions for how to
install them in the form of commands that you are intended to type into
a shell manually.  The easiest way to automate those instructions is to
just put the commands in your L<alienfile>.  For example, lets suppose
that libfoo is built using autoconf and provides a C<pkg-config> C<.pc>
file.

We will also later discuss plugins.  For common build systems like
autoconf or CMake, it is usually better to use the appropriate plugin
because they will handle corner cases better than a simple set of
commands.  We're going to take a look at commands first because it's
easier to understand the different phases with commands.

(Aside, autoconf is a series of tools and macros used to configure
(usually) a C or C++ library or tool by generating any number of
Makefiles.  It is the C equivalent to L<ExtUtils::MakeMaker>, if you
will.  Basically, if your library or tool instructions start with
'./configure' it is most likely an autoconf based library or tool).

(Aside2, C<pkg-config> is a standard-ish way to provide the compiler and
linker flags needed for compiling and linking against the library.  If
your tool installs a C<.pc> file, usually in C<$PREFIX/lib/pkgconfig>
then, your tool uses C<pkg-config>).

Here is the L<alienfile> that you might have:

 use alienfile;
 
 probe [ 'pkg-config --exists libfoo' ];
 
 share {
 
   start_url 'http://www.libfoo.org/src/libfoo-1.00.tar.gz';
 
   download [ 'wget %{.meta.start_url}' ];
 
   extract [ 'tar zxf %{.install.download}' ];
 
   build [
     [ './configure --prefix=%{.install.prefix} --disable-shared' ],
     [ '%{make}' ],
     [ '%{make} install' ],
   ];
 
 };
 
 gather [
   [ 'pkg-config --modversion libfoo', \'%{.runtime.version}' ],
   [ 'pkg-config --cflags     libfoo', \'%{.runtime.cflags}'  ],
   [ 'pkg-config --libs       libfoo', \'%{.runtime.libs}'    ],
 ];

There is a lot going on here, so lets decode it a little bit.  An
L<alienfile> is just some Perl with some alien specific sugar.  The
first line

 use alienfile;

imports the sugar into the L<alienfile>.  It also is a flag for the
reader to see that this is an L<alienfile> and not some other kind of
Perl script.

The second line is the probe directive:

 probe [ 'pkg-config --exists libfoo' ];

is used to see if the library is already installed on the target system.
If C<pkg-config> is in the path, and if libfoo is installed, this should
exit with a success (0) and tell L<Alien::Build> to use the system
library.  If either C<pkg-config> in the PATH, or if libfoo is not
installed, then it will exist with non-success (!= 0) and tells
L<Alien::Build> to download and build from source.

You can provide as many probe directives as you want.  This is useful if
there are different ways to probe for the system.  L<Alien::Build> will
stop on the first successfully found system library found.  Say our
library libfoo comes with a C<.pc> file for use with C<pkg-config> and
also provides a C<foo-config> program to find the same values.  You
could then specify this in your L<alienfile>

 probe [ 'pkg-config --exists libfoo' ];
 probe [ 'foo-config --version' ];

Other directives can be specified multiple times if there are different
methods that can be tried for the various steps.

Sometimes it is easier to probe for a library from Perl rather than with
a command.  For that you can use a code reference.  For example, another
way to call C<pkg-config> would be from Perl:

 probe sub {
   my($build) = @_;  # $build is the Alien::Build instance.
   system 'pkg-config --exists libfoo';
   $? == 0 ? 'system' : 'share';
 };

The Perl code should return 'system' if the library is installed, and
'share' if not.  (Other directives should return a true value on
success, and a false value on failure).  You can also throw an exception with
C<die> to indicate a failure.

The next part of the L<alienfile> is the C<share> block, which is used
to group the directives which are used to download and install the
library or tool in the event that it is not already installed.

 share {
   start_url 'http://www.libfoo.org/src/libfoo-1.00.tar.gz';
   download [ 'wget %{.meta.start_url}' ];
   extract [ 'tar zxf %{.install.download}' ];
   build [
     [ './configure --prefix=%{.install.prefix} --disable-shared' ],
     [ '%{make}' ],
     [ '%{make} install' ],
   ];
 };

The start_url specifies where to find the package that you are alienizing.
It should be either a tarball (or zip file, or what have you) or an
HTML index.  The download directive as you might imagine specifies how
to download  the library or tool.  The extract directive specifies how
to extract the archive once it is downloaded.  In the extract step, you
can use the variable C<%{.install.download}> as a placeholder for the archive
that was downloaded in the download step.  This is also accessible if
you use a code reference from the L<Alien::Build> instance:

 share {
   ...
   requires 'Archive::Extract';
   extract sub {
     my($build) = @_;
     my $tarball = $build->install_prop->{download};
     my $ae = Archive::Extract->new( archive => $tarball );
     $ae->extract;
     1;
   }
   ...
 };

The build directive specifies how to build the library or tool once it
has been downloaded and extracted.  Note the special variable
C<%{.install.prefix}> is the location where the library should be
installed.  C<%{make}> is a helper which will be replaced by the
appropriate C<make>, which may be called something different on some
platforms (on Windows for example, it frequently may be called C<nmake>
or C<dmake>).

The final part of the L<alienfile> has a gather directive which
specifies how to get the details on how to compile and link against the
library.  For this, once again we use the C<pkg-config> command:

 gather [
   [ 'pkg-config --modversion libfoo', \'%{.runtime.version}' ],
   [ 'pkg-config --cflags     libfoo', \'%{.runtime.cflags}'  ],
   [ 'pkg-config --libs       libfoo', \'%{.runtime.libs}'    ],
 ];

The scalar reference as the final item in the command list tells
L<Alien::Build> that the output from the command should be stored in the
given variable.  The runtime variables are the ones that will be
available to C<Alien::Libfoo> once it is installed.  (Install
properties, which are the ones that we have seen up till now are thrown
away once the L<Alien> distribution is installed.

You can also provide a C<sys> block for directives that should be used
when a system install is detected.  Normally you only need to do this if
the gather step is different between share and system installs.  For
example, the above is equivalent to:

 build {
   ...
   gather [
     [ 'pkg-config --modversion libfoo', \'%{.runtime.version}' ],
     [ 'pkg-config --cflags     libfoo', \'%{.runtime.cflags}'  ],
     [ 'pkg-config --libs       libfoo', \'%{.runtime.libs}'    ],
   ];
 };
 
 sys {
   gather [
     [ 'pkg-config --modversion libfoo', \'%{.runtime.version}' ],
     [ 'pkg-config --cflags     libfoo', \'%{.runtime.cflags}'  ],
     [ 'pkg-config --libs       libfoo', \'%{.runtime.libs}'    ],
   ];
 };

(Aside3, the reason it is called C<sys> and not C<system> is so that it
does not conflict with the built in C<system> function)!

=head2 Using plugins

The first example is a good way of showing the full manual path that you
can choose, but there is a lot of repetition, if you are doing many
L<Alien>s that use autoconf and C<pkg-config> (which are quite common.
L<alienfile> allows you to use plugins.  See L<Alien::Build::Plugin> for
a list of some of the plugin categories.

For now, I will just show you how to write the L<alienfile> for libfoo
above using L<Alien::Build::Plugin::Build::Autoconf>,
L<Alien::Build::Plugin::PkgConfig::Negotiate>,
L<Alien::Build::Plugin::Download::Negotiate>, and
L<Alien::Build::Plugin::Extract::Negotiate>

 use alienfile;
 
 plugin 'PkgConfig' => (
   pkg_name => 'libfoo',
 );
 
 share {
   start_url 'http://www.libfoo.org/src';
   plugin 'Download' => (
     filter => qr/^libfoo-[0-9\.]+\.tar\.gz$/,
     version => qr/^libfoo-([0-9\.]+)\.tar\.gz$/,
   );
   plugin 'Extract' => 'tar.gz';
   plugin 'Build::Autoconf';
   build [
     '%{configure} --disable-shared',
     '%{make}',
     '%{make} install',
   ];
 };

The first plugin that we use is the C<pkg-config> negotiation plugin.  A
negotiation plugin is one which doesn't do the actual work but selects
the best one from a set of plugins depending on your platform and
environment.  (In the case of
L<Alien::Build::Plugin::PkgConfig::Negotiate>, it may choose to use
command line tools, a pure Perl implementation (L<PkgConfig>), or
libpkgconf, depending on what is available).  When using negotiation
plugins you may omit the C<::Negotiate> suffix.  So as you can see using
the plugin here is an advantage because it is more reliable than just
specifying a command which may not be installed!

Next we use the download negotiation plugin.  This is also better than
the version above, because again, C<wget> my not be installed on the
target system.  Also you can specify a URL which will be scanned for
links, and use the most recent version.

We use the Extract negotiation plugin to use either command line tools,
or Perl libraries to extract from the archive once it is downloaded.

Finally we use the Autoconf plugin
(L<Alien::Build::Plugin::Build::Autoconf>).  This is a lot more
sophisticated and reliable than in the previous example, for a number of
reasons.  This version will even work on Windows assuming the library or
tool you are alienizing supports that platform!

Strictly speaking the build directive is not necessary, because the
autoconf plugin provides a default which is reasonable.  The only reason
that you would want to include it is if you need to provide additional
flags to the configure step.

 share {
   ...
   build [
     '%{configure} --enable-bar --enable-baz --disable-shared',
     '%{make}',
     '%{make} install',
   ];
 };

=head2 Multiple .pc files

Some packages come with multiple libraries paired with multiple C<.pc>
files.  In this case you want to provide the
L<Alien::Build::Plugin::PkgConfig::Negotiate> with an array reference
of package names.

 plugin 'PkgConfig' => (
   pkg_name => [ 'foo', 'bar', 'baz' ],
 );

All packages must be found in order for the C<system> install to succeed.
Once installed the first C<pkg_name> will be used by default (in this
example C<foo>), and you can retrieve any other C<pkg_name> using
the L<Alien::Base alt method|Alien::Base/alt>.

=head2 A note about dynamic vs. static libraries

If you are using your L<Alien> to build an XS module, it is important
that you use static libraries if possible.  If you have a package that
refuses to build a static library, then you can use L<Alien::Role::Dino>.

Actually let me back up a minute.  For a C<share> install it is best
to use static libraries to build your XS extension.  This is because
if your L<Alien> is ever upgraded to a new version it can break your
existing XS modules.  For a C<system> install shared libraries are
usually best because you can often get security patches without having
to re-build anything in perl land.

If you looked closely at the "Using commands" and "Using plugins"
sections above, you may notice that we went out of our way where
possible to tell Autotools to build only static libraries using the
C<--disable-shared> command.  The Autoconf plugin also does this by
default.

Sometimes though you will have a package that builds both, or maybe
you I<want> both static and dynamic libraries to work with XS and FFI.
For that case, there is the L<Alien::Build::Plugin::Gather::IsolateDynamic>
plugin.

 use alienfile;
 ...
 plugin 'Gather::IsolateDynamic';

What it does, is that it moves the dynamic libraries (usually .so on
Unix and .DLL on Windows) to a place where they can be found by FFI,
and where they won't be used by the compiler for building XS.  It usually
doesn't do any harm to include this plugin, so if you are just starting
out you might want to add it anyway.  Arguably it should have been the
default behavior from the beginning.

If you have already published an Alien that does not isolate its
dynamic libraries, then you might get some fails from old upgraded
aliens because the share directory isn't cleaned up by default (this is
perhaps a design bug in the way that share directories work, but it
is a long standing characteristic).  One work around for this is to
use the C<clean_install> property on L<Alien::Build::MM>, which will
clean out the share directory on upgrade, and possibly save you a lot
of grief.

=head2 Verifying and debugging your alienfile

You could feed your alienfile directly into L<Alien::Build>, or
L<Alien::Build::MM>, but it is sometimes useful to test your alienfile
using the C<af> command (it does not come with L<Alien::Build>, you need
to install L<App::af>).  By default C<af> will use the C<alienfile> in
the current directory (just as C<make> uses the C<Makefile> in the
current directory; just like C<make> you can use the C<-f> option to
specify a different L<alienfile>).

You can test your L<alienfile> in dry run mode:

 % af install --dry-run
 Alien::Build::Plugin::Core::Legacy> adding legacy hash to config
 Alien::Build::Plugin::Core::Gather> mkdir -p /tmp/I2YXRyxb0r/_alien
 ---
 cflags: ''
 cflags_static: ''
 install_type: system
 legacy:
   finished_installing: 1
   install_type: system
   name: libfoo
   original_prefix: /tmp/7RtAusykNN
   version: 1.2.3
 libs: '-lfoo '
 libs_static: '-lfoo '
 prefix: /tmp/7RtAusykNN
 version: 1.2.3

You can use the C<--type> option to force a share install (download and
build from source):

 % af install --type=share --dry-run
 Alien::Build::Plugin::Core::Download> decoding html
 Alien::Build::Plugin::Core::Download> candidate *https://www.libfoo.org/download/libfoo-1.2.4.tar.gz
 Alien::Build::Plugin::Core::Download> candidate  https://www.libfoo.org/download/libfoo-1.2.3.tar.gz
 Alien::Build::Plugin::Core::Download> candidate  https://www.libfoo.org/download/libfoo-1.2.2.tar.gz
 Alien::Build::Plugin::Core::Download> candidate  https://www.libfoo.org/download/libfoo-1.2.1.tar.gz
 Alien::Build::Plugin::Core::Download> candidate  https://www.libfoo.org/download/libfoo-1.2.0.tar.gz
 Alien::Build::Plugin::Core::Download> candidate  https://www.libfoo.org/download/libfoo-1.1.9.tar.gz
 Alien::Build::Plugin::Core::Download> candidate  https://www.libfoo.org/download/libfoo-1.1.8.tar.gz
 Alien::Build::Plugin::Core::Download> candidate  https://www.libfoo.org/download/libfoo-1.1.7.tar.gz
 Alien::Build::Plugin::Core::Download> candidate  ...
 Alien::Build::Plugin::Core::Download> setting version based on archive to 1.2.4
 Alien::Build::Plugin::Core::Download> downloaded libfoo-1.2.4.tar.gz
 Alien::Build::CommandSequence> + ./configure --prefix=/tmp/P22WEXj80r --with-pic --disable-shared
 ... snip ...
 Alien::Build::Plugin::Core::Gather> mkdir -p /tmp/WsoLAQ889w/_alien
 ---
 cflags: ''
 cflags_static: ''
 install_type: share
 legacy:
   finished_installing: 1
   install_type: share
   original_prefix: /tmp/P22WEXj80r
   version: 1.2.4
 libs: '-L/tmp/P22WEXj80r/lib -lfoo '
 libs_static: '-L/tmp/P22WEXj80r/lib -lfoo '
 prefix: /tmp/P22WEXj80r
 version: 1.2.4

You can also use the C<--before> and C<--after> options to take a peek
at what the build environment looks like at different stages as well,
which can sometimes be useful:

 % af install --dry-run --type=share --before build bash
 Alien::Build::Plugin::Core::Download> decoding html
 Alien::Build::Plugin::Core::Download> candidate *https://www.libfoo.org/download/libfoo-1.2.4.tar.gz
 Alien::Build::Plugin::Core::Download> candidate  https://www.libfoo.org/download/libfoo-1.2.3.tar.gz
 Alien::Build::Plugin::Core::Download> candidate  https://www.libfoo.org/download/libfoo-1.2.2.tar.gz
 Alien::Build::Plugin::Core::Download> candidate  https://www.libfoo.org/download/libfoo-1.2.1.tar.gz
 Alien::Build::Plugin::Core::Download> candidate  https://www.libfoo.org/download/libfoo-1.2.0.tar.gz
 Alien::Build::Plugin::Core::Download> candidate  https://www.libfoo.org/download/libfoo-1.1.9.tar.gz
 Alien::Build::Plugin::Core::Download> candidate  https://www.libfoo.org/download/libfoo-1.1.8.tar.gz
 Alien::Build::Plugin::Core::Download> candidate  https://www.libfoo.org/download/libfoo-1.1.7.tar.gz
 Alien::Build::Plugin::Core::Download> candidate  ...
 Alien::Build::Plugin::Core::Download> setting version based on archive to 1.2.4
 Alien::Build::Plugin::Core::Download> downloaded libfoo-1.2.4.tar.gz
 App::af::install>  [ before build ] + bash
 /tmp/fbVPu4LRTs/build_5AVn/libfoo-1.2.4$ ls
 CHANGES Makefile autoconf.ac lib
 /tmp/fbVPu4LRTs/build_5AVn/libfoo-1.2.4$

There are a lot of other useful things that you can do with the C<af>
command.  See L<af> for details.

=head2 Integrating with MakeMaker

Once you have a working L<alienfile> you can write your C<Makefile.PL>.

 use ExtUtils::MakeMaker;
 use Alien::Build::MM;
 
 my $abmm = Alien::Build::MM->new;
 
 WriteMakefile($abmm->mm_args(
   ABSTRACT           => 'Discover or download and install libfoo',
   DISTNAME           => 'Alien-Libfoo',
   NAME               => 'Alien::Libfoo',
   VERSION_FROM       => 'lib/Alien/Libfoo.pm',
   CONFIGURE_REQUIRES => {
     'Alien::Build::MM' => 0,
   },
   BUILD_REQUIRES => {
     'Alien::Build::MM' => 0,
   },
   PREREQ_PM => {
     'Alien::Base' => 0,
   },
   # If you are going to write the recommended
   # tests you will will want these:
   TEST_REQUIRES => {
     'Test::Alien' => 0,
     'Test2::V0'   => 0,
   },
 ));
 
 sub MY::postamble {
   $abmm->mm_postamble;
 }

The C<lib/Alien/Libfoo.pm> that goes along with it is very simple:

 package Alien::Libfoo;
 
 use strict;
 use warnings;
 use parent qw( Alien::Base );
 
 1;

You are done and can install it normally:

 % perl Makefile.PL
 % make
 % make test
 % make install

=head2 Integrating with Module::Build

Please don't!  Okay if you have to there is L<Alien::Build::MB>.

=head2 Non standard configuration

L<Alien::Base> support most of the things that your L<Alien> will need,
like compiler flags (cflags), linker flags (libs) and binary directory
(bin_dir).  Your library or tool may have other configuration items
which are not supported by default.  You can store the values in the
L<alienfile> into the runtime properties:

 gather [
   # standard:
   [ 'foo-config --version libfoo', \'%{.runtime.version}' ],
   [ 'foo-config --cflags  libfoo', \'%{.runtime.cflags}'  ],
   [ 'foo-config --libs    libfoo', \'%{.runtime.libs}'    ],
   # non-standard
   [ 'foo-config --bar-baz libfoo', \'%{.runtime.bar_baz}' ],
 ];

then you can expose them in your L<Alien::Base> subclass:

 package Alien::Libfoo;
 
 use strict;
 use warnings;
 use parent qw( Alien::Base );
 
 sub bar_baz {
   my($self) = @_;
   $self->runtime_prop->{bar_baz},
 };
 
 1;

=head2 Testing

(optional, but highly recommended)

You should write a test using L<Test::Alien> to make sure that your
alien will work with any XS modules that are going to use it:

 use Test2::V0;
 use Test::Alien;
 use Alien::Libfoo;
 
 alien_ok 'Alien::Libfoo';
 
 xs_ok do { local $/; <DATA> }, with_subtest {
   is Foo::something(), 1, 'Foo::something() returns 1';
 };
 
 done_testing;
 
 __DATA__
 #include "EXTERN.h"
 #include "perl.h"
 #include "XSUB.h"
 #include <foo.h>
 
 MODULE = Foo PACKAGE = Foo
 
 int something()

You can also use L<Test::Alien> to test tools instead of libraries:

 use Test2::V0;
 use Test::Alien;
 use Alien::Libfoo;
 
 alien_ok 'Alien::Libfoo';
 run_ok(['foo', '--version'])
   ->exit_is(0);
 
 done_testing;

You can also write tests specifically for L<FFI::Platypus>, if your
alien is going to be used to write FFI bindings.  (the test below
is the FFI equivalent to the XS example above).

 use Test2::V0;
 use Test::Alien;
 use Alien::Libfoo;
 
 alien_ok 'Alien::Libfoo';
 ffi_ok { symbols => [ 'something' ] }, with_subtest {
   # $ffi is an instance of FFI::Platypus with the lib
   # set appropriately.
   my($ffi) = @_;
   my $something = $ffi->function( something => [] => 'int' );
   is $something->call(), 1, 'Foo::something() returns 1';
 };

If you do use C<ffi_ok> you want to make sure that your alien reliably
produces dynamic libraries.  If it isn't consistent (if for example
some platforms tend not to provide or build dynamic libraries), you can
check that C<dynamic_libs> doesn't return an empty list.

 ...
 alien_ok 'Alien::Libfoo';
 SKIP: {
   skip "This test requires a dynamic library"
     unless Alien::Libfoo->dynamic_libs;
   ffi_ok { symbols [ 'something' ] }, with_subtest {
     ...
   };
 }

More details on testing L<Alien> modules can be found in the
L<Test::Alien> documentation.

You can also run the tests that come with the package that you are alienizing,
by using a C<test> block in your L<alienfile>.  Keep in mind that some packages
use testing tools or have other prerequisites that will not be available on your
users machines when they attempt to install your alien.  So you do not want to
blindly add a test block without checking what the prereqs are.  For Autoconf
style packages you typically test a package using the C<make check> command:

 use alienfile;
 
 plugin 'PkgConfig' => 'libfoo';
 
 share {
   ... # standard build steps.
   test [ '%{make} check' ];
 };

=head2 Dist::Zilla

(optional, mildly recommended)

You can also use the L<Alien::Build> L<Dist::Zilla> plugin
L<Dist::Zilla::Plugin::AlienBuild>:

 name    = Alien-Libfoo
 author  = E. Xavier Ample <example@cpan.org>
 license = Perl_5
 copyright_holder = E. Xavier Ample <example@cpan.org>
 copyright_year   = 2017
 version = 0.01
 
 [@Basic]
 [AlienBuild]

The plugin takes care of a lot of details like making sure that the
correct minimum versions of L<Alien::Build> and L<Alien::Base> are used.
See the plugin documentation for additional details.

=head2 Using your Alien

Once you have installed you can use your Alien.  See
L<Alien::Build::Manual::AlienUser> for guidance on that.

=head1 SEE ALSO

=over 4

=item L<Alien::Build::Manual>

Other L<Alien::Build> manuals.

=back

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK7N%[����&perl5/Alien/Build/Manual/AlienUser.podnu��6�$# PODNAME: Alien::Build::Manual::AlienUser
# ABSTRACT: Alien user documentation
# VERSION

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Manual::AlienUser - Alien user documentation

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 perldoc Alien::Build::Manual::AlienUser

=head1 DESCRIPTION

This document is intended for a user of an L<Alien::Base> based L<Alien>
module's user.  Although specifically geared for L<Alien::Base>
subclasses, it may have some useful hints for L<Alien> in general.

Full working examples of how to use an L<Alien> module are also bundled
with L<Alien::Build> in the distribution's C<example/user> directory.
Those examples use L<Alien::xz>, which uses L<alienfile> + L<Alien::Build>
+ L<Alien::Base>.

The following documentation will assume you are trying to use an L<Alien>
called C<Alien::Foo> which provides the library C<libfoo> and the command
line tool C<foo>.  Many L<Alien>s will only provide one or the other.

The best interface to use for using L<Alien::Base> based aliens is
L<Alien::Base::Wrapper>.  This allows you to combine multiple aliens together
and handles a number of corner obscure corner cases that using L<Alien>s
directly does not.  Also as of 0.64, L<Alien::Base::Wrapper> comes bundled
with L<Alien::Build> and L<Alien::Base> anyway, so it is not an extra
dependency.

What follows are the main use cases.

=head2 ExtUtils::MakeMaker

 use ExtUtils::MakeMaker;
 use Alien::Base::Wrapper ();
 
 WriteMakefile(
   Alien::Base::Wrapper->new('Alien::Foo')->mm_args2(
     NAME => 'FOO::XS',
     ...
   ),
 );

L<Alien::Base::Wrapper> will take a hash of C<WriteMakefile> arguments
and insert the appropriate compiler and linker flags for you.  This
is recommended over doing this yourself as the exact incantation to
get EUMM to work is tricky to get right.

The C<mm_args2> method will also set your C<CONFIGURE_REQUIRES> for
L<Alien::Base::Wrapper>, L<ExtUtils::MakeMaker> and any aliens that
you specify.

=head2 Module::Build

 use Module::Build;
 use Alien::Base::Wrapper qw( Alien::Foo !export );
 use Alien::Foo;
 
 my $build = Module::Build->new(
   ...
   configure_requires => {
     'Alien::Base::Wrapper' => '0',
     'Alien::Foo'           => '0',
     ...
   },
   Alien::Base::Wrapper->mb_args,
   ...
 );
 
 $build->create_build_script;

For L<Module::Build> you can also use L<Alien::Base::Wrapper>, but
you will have to specify the C<configure_requires> yourself.

=head2 Inline::C / Inline::CPP

 use Inline 0.56 with => 'Alien::Foo';

L<Inline::C> and L<Inline::CPP> can be configured
to use an L<Alien::Base> based L<Alien> with the C<with> keyword.

=head2 ExtUtils::Depends

 use ExtUtils::MakeMaker;
 use ExtUtils::Depends;
 
 my $pkg = ExtUtils::Depends->new("Alien::Foo");
 
 WriteMakefile(
   ...
   $pkg->get_makefile_vars,
   ...
 );

L<ExtUtils::Depends> works similar to L<Alien::Base::Wrapper>, but uses
the L<Inline> interface under the covers.

=head2 Dist::Zilla

 [@Filter]
 -bundle = @Basic
 -remove = MakeMaker
 
 [Prereqs / ConfigureRequires]
 Alien::Foo = 0
 
 [MakeMaker::Awesome]
 header = use Alien::Base::Wrapper qw( Alien::Foo !export );
 WriteMakefile_arg = Alien::Base::Wrapper->mm_args

=head2 FFI::Platypus

Requires C<Alien::Foo> always:

 use FFI::Platypus;
 use Alien::Foo;
 
 my $ffi = FFI::Platypus->new(
   lib => [ Alien::Foo->dynamic_libs ],
 );

Use C<Alien::Foo> in fallback mode:

 use FFI::Platypus;
 use FFI::CheckLib 0.28 qw( find_lib_or_die );
 use Alien::Foo;
 
 my $ffi = FFI::Platypus->new(
   lib => [ find_lib_or_die lib => 'foo', alien => ['Alien::Foo'] ],
 );

If you are going to always require an L<Alien> you can just call C<dynamic_libs>
and pass it into L<FFI::Platypus>' lib method.  You should consider
using L<FFI::CheckLib> to use the L<Alien> in fallback mode instead.
This way you only need to install the L<Alien> if the system doesn't
provide it.

For fallback mode to work correctly you need to be using L<FFI::CheckLib>
0.28 or better.

=head2 Inline::C

 use Inline with => 'Alien::Foo';
 use Inline C => <<~'END';
   #include <foo.h>
 
   const char *my_foo_wrapper()
   {
     foo();
   }
   END
 
 sub exported_foo()
 {
   my_foo_wrapper();
 }

=head2 tool

 use Alien::Foo;
 use Env qw( @PATH );
 
 unshift @PATH, Alien::Foo->bin_dir;
 system 'foo', '--bar', '--baz';

Some L<Alien>s provide tools instead of or in addition to a library.
You need to add them to the C<PATH> environment variable though.
(Unless the tool is already provided by the system, in which case
it is already in the path and the C<bin_dir> method will return an
empty list).

=head1 ENVIRONMENT

=over 4

=item ALIEN_INSTALL_TYPE

Although the recommended way for a consumer to use an L<Alien::Base> based L<Alien>
is to declare it as a static configure and build-time dependency, some consumers
may prefer to fallback on using an L<Alien> only when the consumer itself cannot
detect the necessary package. In some cases the consumer may want the user to opt-in
to using an L<Alien> before requiring it.

To keep the interface consistent among Aliens, the consumer of the fallback opt-in
L<Alien> may fallback on the L<Alien> if the environment variable C<ALIEN_INSTALL_TYPE>
is set to any value. The rationale is that by setting this environment variable the
user is aware that L<Alien> modules may be installed and have indicated consent.
The actual implementation of this, by its nature would have to be in the consuming
CPAN module.

This behavior should be documented in the consumer's POD.

See L<Alien::Build/ENVIRONMENT> for more details on the usage of this environment
variable.

=back

=head1 SEE ALSO

=over 4

=item L<Alien::Build::Manual>

Other L<Alien::Build> manuals.

=back

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK7N%[AMW�R�R perl5/Alien/Build/Manual/FAQ.podnu��6�$# PODNAME: Alien::Build::Manual::FAQ
# ABSTRACT: Frequently Asked Questions about Alien::Build
# VERSION

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Manual::FAQ - Frequently Asked Questions about Alien::Build

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 perldoc Alien::Build::Manual::FAQ

=head1 DESCRIPTION

This document serves to answer the most frequently asked questions made by developers
creating L<Alien> modules using L<Alien::Build>.

=head1 QUESTIONS

=head2 What is Alien, Alien::Base and Alien::Build?

Alien in a Perl namespace for defining dependencies in CPAN for libraries and tools which
are not "native" to CPAN.  For a manifesto style description of the Why, and How see
L<Alien>.  L<Alien::Base> is a base class for the L<Alien> runtime.  L<Alien::Build> is
a tool for probing the operating system for existing libraries and tools, and downloading, building
and installing packages.  L<alienfile> is a recipe format for describing how to probe,
download, build and install a package.

=head2 How do I build a package that uses I<build system>

=head3 autoconf

Use the autoconf plugin (L<Alien::Build::Plugin::Build::Autoconf>).  If your package
provides a pkg-config C<.pc> file, then you can also use the PkgConfig plugin
(L<Alien::Build::Plugin::PkgConfig::Negotiate>).

 use alienfile
 plugin PkgConfig => 'libfoo';
 share {
   start_url => 'http://example.org/dist';
   plugin Download => (
     version => qr/libfoo-([0-9\.])\.tar\.gz$/,
   );
   plugin Extract => 'tar.gz';
   plugin 'Build::Autoconf';
 };

If you need to provide custom flags to configure, you can do that too:

 share {
   plugin 'Build::Autoconf';
   build [
     '%{configure} --disable-shared --enable-foo',
     '%{make}',
     '%{make} install',
   ];
 };

If your package requires GNU Make, use C<%{gmake}> instead of C<%{make}>.

=head3 autoconf without configure script

A number of Open Source projects are using autotools, but do not provide the
C<configure> script.  When alienizing these types of packages you have a
few choices:

=over 4

=item build configure using autotools

The Alien L<Alien::Autotools> is designed to provide autotools for building
such packages from source.  The advantage is that this is how the upstream
developers intend on having their package built.  The downside is that it
is also adds more prereqs to your Alien.  The silver lining is that if you
require this Alien in the C<share> block (as you should), then these prereqs
will only be pulled in during a share install when they are needed.

Please see the L<Alien::Autotools> documentation for specifics on how it
can be used in your L<alienfile>.

=item patch the package locally before build

You can use the L<alienfile/patch> directive to patch the alienized package
locally before building.  This can sometimes be challenging because Autotools
uses timestamps in order to decide what needs to be rebuilt, and patching
can sometimes confuse it into thinking more needs to be rebuilt than what
actually does.

=item build configure and tarball

You can also build the configure script during development of your alien,
generate the tarball and provide it somewhere like GitHub and use that
as the source instead of the original source.  This should usually be
a last resort if the other two methods prove too difficult.

=back

=head3 autoconf-like

If you see an error like this:

 Unknown option "--with-pic".

It is because the autoconf plugin uses the C<--with-pic> option by default, since
it makes sense most of the time, and autoconf usually ignores options that it does
not recognize.  Some autoconf style build systems fail when they see an option that
they do not recognize.  You can turn this behavior off for these packages:

 plugin 'Build::Autoconf' => (
   with_pic => 0,
 );

Another thing about the autoconf plugin is that it uses C<DESTDIR> to do a double
staged install.  If you see an error like "nothing was installed into destdir", that
means that your package does not support C<DESTDIR>.  You should instead use the
MSYS plugin and use a command sequence to do the build like this:

 share {
   plugin 'Build::MSYS';
   build [
     # explicitly running configure with "sh" will make sure that
     # it works on windows as well as UNIX.
     'sh configure --prefix=%{.install.prefix} --disable-shared',
     '%{make}',
     '%{make} install',
   ];
 };

=head3 CMake

There is an alien L<Alien::cmake3> that provides C<cmake> 3.x or better (It is preferred to the
older L<Alien::CMake>).  Though it is recommended that you use the C<cmake>
(L<Alien::Build::Plugin::Build::CMake>) plugin instead of using L<Alien::cmake3>.

 use alienfile;
 
 share {
   plugin 'Build::CMake';
   build [
     # this is the default build step, if you do not specify one.
     [ '%{cmake}',
         @{ meta->prop->{plugin_build_cmake}->{args} },
         # ... put extra cmake args here ...
         '.'
     ],
     '%{make}',
     '%{make} install',
   ];
 };

=head3 vanilla Makefiles

L<Alien::Build> provides a helper (C<%{make}>) for the C<make> that is used by Perl and
L<ExtUtils::MakeMaker> (EUMM).  Unfortunately the C<make> supported by Perl and EUMM on
Windows (C<nmake> and C<dmake>) are not widely supported by most open source projects.
(Thankfully recent perls and EUMM support GNU Make on windows now).

You can use the C<make> plugin (L<Alien::Build::Plugin::Build::Make>) to tell the
L<Alien::Build> system which make the project that you are alienizing requires.

 plugin 'Build::Make' => 'umake';
 # umake makes %{make} either GNU Make or BSD Make on Unix and GNU Make on Windows.
 build {
   build [
     # You can use the Perl config compiler and cflags using the %{perl.config...} helper
     [ '%{make}', 'CC=%{perl.config.cc}', 'CFLAGS=%{perl.config.cccdlflags} %{perl.config.optimize}' ],
     [ '%{make}', 'install', 'PREFIX=%{.install.prefix}' ],
   ],
 };

Some open source projects require GNU Make, and you can specify that, and L<Alien::gmake>
will be pulled in on platforms that do not already have it.

 plugin 'Build::Make' => 'gmake';
 ...

=head2 How do I probe for a package that uses pkg-config?

Use the C<pkg-config> plugin (L<Alien::Build::Plugin::PkgConfig::Negotiate>):

 use alienfile;
 plugin 'PkgConfig' => (
   pkg_name => 'libfoo',
 );

It will probe for a system version of the library.  It will also add the appropriate C<version>
C<cflags> and C<libs> properties on either a C<system> or C<share> install.

=head2 How do I specify a minimum or exact version requirement for packages that use pkg-config?

The various pkg-config plugins all support atleast_version, exact_version and maximum_version
fields, which have the same meaning as the C<pkg-config> command line interface:

 use alienfile;
 
 plugin 'PkgConfig', pkg_name => 'foo', atleast_version => '1.2.3';

or

 use alienfile;
 
 plugin 'PkgConfig', pkg_name => foo, exact_version => '1.2.3';

=head2 How do I probe for a package that uses multiple .pc files?

Each of the C<PkgConfig> plugins will take an array reference instead of a string:

 use alienfile;
 
 plugin 'PkgConfig' => ( pkg_name => [ 'foo', 'bar', 'baz' ] );

The first C<pkg_name> given will be used by default once your alien is installed.
To get the configuration for C<foo> and C<bar> you can use the
L<Alien::Base alt method|Alien::Base/alt>:

 use Alien::libfoo;
 
 $cflags = Alien::libfoo->cflags;               # compiler flags for 'foo'
 $cflags = Alien::libfoo->alt('bar')->cflags ;  # compiler flags for 'bar'
 $cflags = Alien::libfoo->alt('baz')->cflags ;  # compiler flags for 'baz'

=head2 How to create an Alien module for packages that do not support pkg-config?

=head3 Packages that provide a configuration script

Many packages provide a command that you can use to get the appropriate version, compiler
and linker flags.  For those packages you can just use the commands in your L<alienfile>.
Something like this:

 use alienfile;
 
 probe [ 'foo-config --version' ];
 
 share {
   ...
 
   build [
     '%{make} PREFIX=%{.runtime.prefix}',
     '%{make} install PREFIX=%{.runtime.prefix}',
   ];
 };
 
 gather [
   [ 'foo-config', '--version', \'%{.runtime.version}' ],
   [ 'foo-config', '--cflags',  \'%{.runtime.cflags}'  ],
   [ 'foo-config', '--libs',    \'%{.runtime.libs}'    ],
 ];

=head3 Packages that require a compile test

Some packages just expect you do know that C<-lfoo> will work.  For those you can use
the C<cbuilder> plugin (L<Alien::Build::Plugin::Probe::CBuilder>).

 use alienfile;
 plugin 'Probe::CBuilder' => (
   cflags => '-I/opt/libfoo/include',
   libs   => '-L/opt/libfoo/lib -lfoo',
 );
 
 share {
   ...
   gather sub {
     my($build) = @_;
     my $prefix = $build->runtime_prop->{prefix};
     $build->runtime_prop->{cflags} = "-I$prefix/include ";
     $build->runtime_prop->{libs}   = "-L$prefix/lib -lfoo ";
   };
 }

This plugin will build a small program with these flags and test that it works.  (There
are also options to provide a program that can make simple tests to ensure the library
works).  If the probe works, it will set the compiler and linker flags.  (There are also
options for extracting the version from the test program).  If you do a share install
you will need to set the compiler and linker flags yourself in the gather step, if you
aren't using a build plugin that will do that for you.

=head2 Can/Should I write a tool oriented Alien module?

Certainly.  The original intent was to provide libraries, but tools are also quite doable using
the L<Alien::Build> toolset.  A good example of how to do this is L<Alien::nasm>.  You will want
to use the 'Probe::CommandLine':

 use alienfile;
 
 plugin 'Probe::CommandLine' => (
   command => 'gzip',
 );

=head2 How do I test my package once it is built (before it is installed)?

Use L<Test::Alien>.  It has extensive documentation, and integrates nicely with L<Alien::Base>.

=head2 How do I patch packages that need alterations?

If you have a diff file you can use patch:

 use alienfile;
 
 probe sub { 'share' }; # replace with appropriate probe
 
 share {
   ...
   patch [ '%{patch} -p1 < %{.install.patch}/mypatch.diff' ];
   build [ ... ] ;
 }
 
 ...

You can also patch using Perl if that is easier:

 use alienfile;
 
 probe sub { 'share' };
 
 share {
   ...
   patch sub {
     my($build) = @_;
     # make changes to source prior to build
   };
   build [ ... ];
 };

=head2 The flags that a plugin produces are wrong!

Sometimes, the compiler or linker flags that the PkgConfig plugin comes up with are not quite
right.  (Frequently this is actually because a package maintainer is providing a broken
C<.pc> file).  (Other plugins may also have problems).  You could replace the plugin's C<gather> step
but a better way is to provide a subroutine callback to be called after the gather stage
is complete.  You can do this with the L<alienfile> C<after> directive:

 use alienfile;
 
 plugin 'PkgConfig' => 'libfoo';
 
 share {
   ...
   after 'gather' => sub {
     my($build) = @_;
     $build->runtime_prop->{libs}        .= " -lbar";        # libfoo also requires libbar
     $build->runtime_prop->{libs_static} .= " -lbar -lbaz";  # libfoo also requires libbaz under static linkage
   };
 };

Sometimes you only need to do this on certain platforms.  You can adjust the logic based on C<$^O>
appropriately.

 use alienfile;
 
 plugin 'PkgConfig' => 'libfoo';
 
 share {
   ...
   after 'gather' => sub {
     my($build) = @_;
     if($^O eq 'MSWin32') {
       $build->runtime_prop->{libs} .= " -lpsapi";
     }
   };
 };

=head2 "cannot open shared object file" trying to load XS

The error looks something like this:

 t/acme_alien_dontpanic2.t ....... 1/?
 # Failed test 'xs'
 # at t/acme_alien_dontpanic2.t line 13.
 #   XSLoader failed
 #     Can't load '/home/cip/.cpanm/work/1581635869.456/Acme-Alien-DontPanic2-2.0401/_alien/tmp/test-alien-lyiQNX/auto/Test/Alien/XS/Mod0/Mod0.so' for module Test::Alien::XS::Mod0: libdontpanic.so.0: cannot open shared object file: No such file or directory at /opt/perl/5.30.1/lib/5.30.1/x86_64-linux/DynaLoader.pm line 193.
 #  at /home/cip/perl5/lib/perl5/Test/Alien.pm line 414.
 # Compilation failed in require at /home/cip/perl5/lib/perl5/Test/Alien.pm line 414.
 # BEGIN failed--compilation aborted at /home/cip/perl5/lib/perl5/Test/Alien.pm line 414.
 t/acme_alien_dontpanic2.t ....... Dubious, test returned 1 (wstat 256, 0x100)
 Failed 1/6 subtests
 t/acme_alien_dontpanic2__ffi.t .. ok

This error happened at test time for the Alien, but depending on your environment and Alien it might
happen later and the actual diagnostic wording might vary.

This is usually because your XS or Alien tries to use dynamic libraries instead of static ones.
Please consult the section about dynamic vs. static libraries in L<Alien::Build::Manual::AlienAuthor>.
The TL;DR is that L<Alien::Build::Plugin::Gather::IsolateDynamic> might help.
If you are the Alien author and the package you are alienizing doesn't have a static option you can
use L<Alien::Role::Dino>, but please note the extended set of caveats!

=head2 599 Internal Exception errors downloading packages from the internet

 Alien::Build::Plugin::Fetch::HTTPTiny> 599 Internal Exception fetching http://dist.libuv.org/dist/v1.15.0
 Alien::Build::Plugin::Fetch::HTTPTiny> exception: IO::Socket::SSL 1.42 must be installed for https support
 Alien::Build::Plugin::Fetch::HTTPTiny> exception: Net::SSLeay 1.49 must be installed for https support
 Alien::Build::Plugin::Fetch::HTTPTiny> An attempt at a SSL URL https was made, but your HTTP::Tiny does not appear to be able to use https.
 Alien::Build::Plugin::Fetch::HTTPTiny> Please see: https://metacpan.org/pod/Alien::Build::Manual::FAQ#599-Internal-Exception-errors-downloading-packages-from-the-internet
 error fetching http://dist.libuv.org/dist/v1.15.0: 599 Internal Exception at /Users/ollisg/.perlbrew/libs/perl-5.26.0@test1/lib/perl5/Alien/Build/Plugin/Fetch/HTTPTiny.pm line 68.

(Older versions of L<Alien::Build> produced a less verbose more confusing version of this diagnostic).

TL;DR, instead of this:

 share {
   start_url => 'http://example.org/dist';
   ...
 };

do this:

 share {
   start_url => 'https://example.org/dist';
 };

If the website is going to redirect to a secure URL anyway.

The "599 Internal Exception" indicates an "internal" exception from L<HTTP::Tiny> and is not a real
HTTP status code or error.  This could mean a number of different problems, but most frequently
indicates that a SSL request was made without the required modules (L<Net::SSLeay> and
L<IO::Socket::SSL>).  Normally the L<Alien::Build::Plugin::Download::Negotiate>
and L<Alien::Build::Plugin::Fetch::HTTPTiny> will make sure that the appropriate modules are added
to your prerequisites for you if you specify a C<https> URL.  Some websites allow an initial request
from C<http> but then redirect to C<https>.  If you can it is better to specify C<https>, if you
cannot, then you can instead use the C<ssl> property on either of those two plugins.

=head2 Does not detect system package even though it is installed

This could just be because the alien requires a more recent package that what is provided by your
operating system.

It could also be because you do not have the development package installed.  Many Linux vendors
in particular separate packages into runtime and development pages.  On RPM based systems these
development packages usually have C<-devel> suffix (example runtime: C<libffi> and development:
C<libffi-devel>).  On Debian based systems these development packages usually have a C<-dev>
suffix (example runtime: C<libffi> and development: C<libffi-dev>).

=head2 Network fetch is turned off

If you get an error like this:

 Alien::Build> install type share requested or detected, but network fetch is turned off
 Alien::Build> see see https://metacpan.org/pod/Alien::Build::Manual::FAQ#Network-fetch-is-turned-off

This is because your environment is setup not to install aliens that require the network.  You
can turn network fetch back on by setting C<ALIEN_INSTALL_NETWORK> to true, or by unsetting it.
This environment variable is designed for environments that don't ever want to install aliens that
require downloading source packages over the internet.

=head2 I would really prefer you not download stuff off the internet

The idea of L<Alien> is to download missing packages and build them automatically to make installing
easier.  Some people may not like this, or may even have security requirements that they not download
random package over the internet (caveat, downloading random stuff off of CPAN may not be any safer,
so make sure you audit all of the open source software that you use appropriately).  Another reason
you may not want to download from the internet is if you are packaging up an alien for an operating
system vendor, which will always want to use the system version of a library.  In that situation you
don't want L<Alien::Build> to go off and download something from the internet because the probe failed
for some reason.

This is easy to take care of, simply set C<ALIEN_INSTALL_TYPE> to C<system> and a build from source
code will never be attempted.  On systems that do not provide system versions of the library or tool
you will get an error, allowing you to install the library, and retry the alien install.  You can
also set the environment variable on just some aliens.

 % export ALIEN_INSTALL_TYPE=system  # for everyone
 
 % env ALIEN_INSTALL_TYPE=system cpanm -v Alien::libfoo

=head2 For testing I would like to test both system and share installs!

You can use the C<ALIEN_INSTALL_TYPE> environment variable.  It will force either a C<share> or
C<system> install depending on how it is set.  For Travis-CI you can do something like this:

 env:
   matrix:
     - ALIEN_INSTALL_TYPE=share
     - ALIEN_INSTALL_TYPE=system

=head2 How do I use Alien::Build from Dist::Zilla?

For creating L<Alien::Base> and L<Alien::Build> based dist from L<Dist::Zilla> you can use the
dzil plugin L<Dist::Zilla::Plugin::AlienBuild>.

=head2 Cannot find either a share directory or a ConfigData module

If you see an error like this:

 Cannot find either a share directory or a ConfigData module for Alien::libfoo.
 (Alien::libfoo loaded from lib/Alien/libfoo.pm)
 Please see https://metacpan.org/pod/distribution/Alien-Build/lib/Alien/Build/Manual/FAQ.pod#Cannot-find-either-a-share-directory-or-a-ConfigData-module
 Can't locate Alien/libfoo/ConfigData.pm in @INC (you may need to install the Alien::libfoo::ConfigData module) (@INC contains: ...)

it means you are trying to use an Alien that hasn't been properly installed.  An L<Alien::Base>
based Alien needs to have either the share directory build during the install process or for
older legacy L<Alien::Base::ModuleBuild> based Aliens, a ConfigData module generated by
L<Module::Build>.

This usually happens if you try to use an Alien module from the lib directory as part of the
Alien's distribution.  You need to build the alien and use C<blib/lib> instead of C<lib> or
install the alien and use the installed path.

It is also possible that your Alien installer is not set up correctly.  Make sure your
C<Makefile.PL> is using L<Alien::Build::MM> correctly.

=head2 I have a question not listed here!

There are a number of forums available to people working on L<Alien>, L<Alien::Base> and
L<Alien::Build> modules:

=over 4

=item C<#native> on irc.perl.org

This is intended for native interfaces in general so is a good place for questions about L<Alien>
generally or L<Alien::Base> and L<Alien::Build> specifically.

=item mailing list

The C<perl5-alien> google group is intended for L<Alien> issues generally, including L<Alien::Base>
and L<Alien::Build>.

L<https://groups.google.com/forum/#!forum/perl5-alien>

=item Open a support ticket

If you have an issue with L<Alien::Build> itself, then please open a support ticket on the project's GitHub issue
tracker.

L<https://github.com/PerlAlien/Alien-Build/issues>

=back

=head1 SEE ALSO

=over 4

=item L<Alien::Build::Manual>

Other L<Alien::Build> manuals.

=back

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK7N%[�6���"�"%perl5/Alien/Build/Manual/Security.podnu��6�$# PODNAME: Alien::Build::Manual::Security
# ABSTRACT: General alien author documentation
# VERSION

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Manual::Security - General alien author documentation

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 perldoc Alien::Build::Manual::Security

=head1 DESCRIPTION

You are rightly concerned that an L<Alien> might be downloading something random
off the internet.  This manual will describe some of the real risks and go over
how you can mitigate them.

=head2 no warranty

L<Alien::Build> provides L<Alien> authors with tools to add external non-Perl
dependencies to CPAN modules.  It is open source software that is entirely
volunteer driven, meaning the people writing this software are not getting
compensated monetarily for the work.  As such, we do our best not to
intentionally introduce security vulnerabilities into our modules, or their
dependencies.  But it is also not our responsibility either.  If you are
operating in an environment where you need absolute security, you need to
carefully audit I<all> of the software that you use.

=head2 L<Alien::Build> vs. L<CPAN>

I suppose you could argue that L<Alien::Build> based L<Alien>s and L<Alien>s
in general are inherently less secure than the the Perl modules on L<CPAN>
that don't download random stuff off the internet.  Worse yet, L<Alien>s
might be downloading from insecure sources like C<http> or C<ftp>.

This argument falls apart pretty quickly when you realize that

=over 4

=item 1

Perl modules from L<CPAN> are in fact random stuff off the internet.
Most modules, when installed execute a C<Makefile.PL> which can execute
completely arbitrary Perl code.  Without a proper audit or firewalls
that L<CPAN> code could be making connections to insecure sources
like C<http> if they are not themselves doing something nefarious.

=item 2

By default, the most frequently used L<CPAN> client L<App::cpanminus|cpanm>
uses C<http> to fetch L<CPAN> modules.  So unless you have specifically
configured it to connect to a secure source you are downloading
even more random stuff than usual off the internet.

=back

The TL;DR is that if you are using a Perl module, whether it be
C<Foo::PP>, C<Foo::XS> or C<Alien::libfoo> and you are concerned about
security you need to audit all of your Perl modules, not just the L<Alien>
ones.

=head2 Restricting L<Alien::Build> by environment

Okay, granted you need to audit software for security regardless of
if it is L<Alien>, you still don't like the idea of downloading external
dependencies and you can't firewall just the L<CPAN> module installs.

L<Alien::Build> based L<Alien>s respect a number of environment variables
that at least give you some control over how aggresive L<Alien::Build>
will be at fetching random stuff off the internet.

=over 4

=item C<ALIEN_DOWNLOAD_RULE>

This environment variable configures how L<Alien::Build> will deal
with insecure protocols and files that do not include a cryptographic
signature.

Part of the design of the L<Alien::Build> system is that it typically
tries to download the latest version of a package instead of a fixed
version, so that the L<Alien> doesn't need to be updated when a new
alienized package is released.  This means that we frequently have
to rely on TLS or bundled alienized packages to ensure that the
alienized package is fetched securely.

Recently (as of L<Alien::Build> 2.59) we started supporting cryptographic
signatures defined in L<alienfile>s, but they are not yet very common,
and they only really work when a single alienized package URL is hard
coded into the L<alienfile> instead of the more typical mode of operation
where the latest version is downloaded.

=over 4

=item warn

This mode will warn you if an L<Alien::Build> based L<Alien> attempts
to fetch a alienized package insecurely.  It will also warn you if
a package doesn't have a cryptographic signature.  Neither of these
things wild stop the L<Alien> from being installed.

This is unfortunately currently the default mode of L<Alien::Build>,
for historical reasons.  Once plugins and L<Alien>s are updated to
either use secure fetch (TLS or bundled alienized packages), or
cryptographic signatures, the default will be changed to
C<digest_or_encrypt>.

=item digest_or_encrypt

This mode will require that before an alienized package is extracted
that it is either fetched via a secure protocol (C<http> or C<file>),
or the package matches a cryptographic signature.

This will likely be the default for L<Alien::Build> in the near future,
but it doesn't hurt to set it now, if you don't mind submitting
tickets to L<Alien>s or L<plugins|Alien::Build::Plugin> that don't
support this mode yet.

=back

=item C<ALIEN_INSTALL_NETWORK>

By design L<Alien>s should use local installs of libraries and tools
before downloading source from the internet.  Setting this environment
variable to false, will instruct L<Alien::Build> to not attempt to
fetch the alienized package off the internet if it is not available
locally or as a bundled package.

This is similar to setting C<ALIEN_INSTALL_TYPE> to C<system> (see
below), except it does allow L<Alien>s that bundle their alienized
package inside the L<CPAN> package tarball.

Some L<Alien>s will not install properly at first, but when they error
you can install the system package and try to re-install the L<Alien>.

=item C<ALIEN_INSTALL_TYPE>

Setting C<ALIEN_INSTALL_TYPE> to C<system> is similar to setting
C<ALIEN_INSTALL_NETWORK> to false, except that bundled alienized
packages will also be rejected.  This environment variable is really
intended for use by operating system vendors packaging L<Alien>s,
or for L<Alien> developer testing (in CI for example).  For some
who want to restrict how L<Alien>s install this might be the right
tool to reach for.

=back

Note that this is definitely best effort.  If the L<Alien> author makes
a mistake or is malicious they could override these environment variables
inside the C<Makefile.PL>, so you still need to audit any software to
ensure that it doesn't fetch source off the internet.

=head2 Security Related Plugins

There are a number of plugins that give the user or installer control
over how L<Alien::Build> behaves, and may be useful for rudimentary
security.

=over 4

=item L<Alien::Build::Plugin::Fetch::Prompt>

This plugin will prompt before fetching any remote files.  This only
really works when you are installing L<Alien>s interactively.

=item L<Alien::Build::Plugin::Fetch::HostAllowList>

This plugin will only allow fetching from hosts that are in an allow list.

=item L<Alien::Build::Plugin::Fetch::HostBlockList>

This plugin will not allow fetching from hosts that are in a block list.

=item L<Alien::Build::Plugin::Fetch::Rewrite>

This plugin can re-write fetched URLs before the request is made.  This
can be useful if you have a local mirror of certain sources that you
want to use instead of fetching from the wider internet.

=item L<Alien::Build::Plugin::Probe::Override>

This plugin can override the C<ALIEN_INSTALL_TYPE> on a perl-Alien basis.
This can be useful if you want to install some L<Alien>s in C<share>
mode, but generally want to enforce C<system> mode.

=back

=head2 local configuration

You can configure the way L<Alien::Build> based L<Alien>s are installed with the
local configuration file C<~/.alienbuild/rc.pl>.  See L<Alien::Build::rc> for
details.

=head1 CAVEATS

This whole document is caveats, but if you haven't gotten it by now then,
fundamentally if you need to use Perl modules securely then you need to
audit the code for security vulnerabilities.  If you think that the security
of L<Alien::Build> and the L<Alien>s that depend on it, then I<patches welcome>.

=head1 SEE ALSO

=over 4

=item L<Alien::Build::Manual>

Other L<Alien::Build> manuals.

=back

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK7N%[9��ROOperl5/Alien/Build/rc.pmnu��6�$package Alien::Build::rc;

use strict;
use warnings;
use 5.008004;

# ABSTRACT: Alien::Build local config
our $VERSION = '2.84'; # VERSION


sub logx ($)
{
  unshift @_, 'Alien::Build';
  goto &Alien::Build::log;
}


sub preload_plugin
{
  my(@args) = @_;
  push @Alien::Build::rc::PRELOAD, sub {
    shift->apply_plugin(@args);
  };
}


sub postload_plugin
{
  my(@args) = @_;
  push @Alien::Build::rc::POSTLOAD, sub {
    shift->apply_plugin(@args);
  };
}


sub preload ($)
{
  push @Alien::Build::rc::PRELOAD, $_[0];
}


sub postload ($)
{
  push @Alien::Build::rc::POSTLOAD, $_[0];
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::rc - Alien::Build local config

=head1 VERSION

version 2.84

=head1 SYNOPSIS

in your C<~/.alienbuild/rc.pl>:

 preload 'Foo::Bar';
 postload 'Baz::Frooble';

=head1 DESCRIPTION

L<Alien::Build> will load your C<~/.alienbuild/rc.pl> file, if it exists
before running the L<alienfile> recipe.  This allows you to alter the
behavior of L<Alien::Build> based L<Alien>s if you have local configuration
requirements.  For example you can prompt before downloading remote content
or fetch from a local mirror.

=head1 FUNCTIONS

=head2 logx

 log $message;

Send a message to the L<Alien::Build> log.

=head2 preload_plugin

 preload_plugin $plugin, @args;

Preload the given plugin, with arguments.

=head2 postload_plugin

 postload_plugin $plugin, @args;

Postload the given plugin, with arguments.

=head2 preload

[deprecated]

 preload $plugin;

Preload the given plugin.

=head2 postload

[deprecated]

 postload $plugin;

Postload the given plugin.

=head1 SEE ALSO

=over 4

=item L<Alien::Build::Plugin::Fetch::Cache>

=item L<Alien::Build::Plugin::Fetch::Prompt>

=item L<Alien::Build::Plugin::Fetch::Rewrite>

=item L<Alien::Build::Plugin::Probe::Override>

=back

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK7N%[)RM߂ � (perl5/Alien/Build/Interpolate/Default.pmnu��6�$package Alien::Build::Interpolate::Default;

use strict;
use warnings;
use 5.008004;
use parent qw( Alien::Build::Interpolate );
use File::chdir;
use File::Which qw( which );
use Capture::Tiny qw( capture );

# ABSTRACT: Default interpolator for Alien::Build
our $VERSION = '2.84'; # VERSION

sub _config
{
  $Config::Config{$_[0]};
}


sub new
{
  my($class) = @_;
  my $self = $class->SUPER::new(@_);


  $self->add_helper( ar => sub { _config 'ar' }, 'Config' );


  $self->add_helper( bison => undef, sub {
    my $helper = shift;
    if(which 'bison')
    {
      $helper->code(sub { 'bison' });
      return  ();
    }
    else
    {
      return 'Alien::bison' => '0.17';
    }
  });


  $self->add_helper( bzip2 => undef, sub {
    my $helper = shift;
    if(which 'bzip2')
    {
      $helper->code( sub { 'bzip2' });
      return ();
    }
    else
    {
      return 'Alien::Libbz2' => '0.04';
    }
  });


  $self->add_helper( cc => sub { _config 'cc' }, 'Config' );


  $self->add_helper( cmake => sub { 'cmake' }, sub {
    if(which 'cmake')
    {
      return ();
    }
    else
    {
      return 'Alien::CMake' => '0.07';
    }
  });


  $self->add_helper( cp => sub { _config 'cp' }, 'Config' );


  $self->add_helper( devnull => sub { $^O eq 'MSWin32' ? 'NUL' : '/dev/null' });


  $self->add_helper( flex => undef, sub {
    my $helper = shift;
    if(which 'flex')
    {
      $helper->code(sub { 'flex' });
      return  ();
    }
    else
    {
      return 'Alien::flex' => '0.08';
    }
  });


  $self->add_helper( gmake => undef, 'Alien::gmake' => '0.11' );


  $self->add_helper( install => sub { 'install' });


  $self->add_helper( ld => sub { _config 'ld' }, 'Config' );


  $self->add_helper( m4 => undef, 'Alien::m4' => '0.08' );


  if($^O eq 'MSWin32')
  {
    # TL;DR: dmake is bad, and shouldn't be used to build anything but older
    # versions of Windows Perl that don't support gmake.
    my $perl_make = _config 'make';
    my $my_make;
    $self->add_helper( make => sub {
      return $my_make if defined $my_make;

      if( $perl_make ne 'dmake' && which $perl_make )
      {
        # assume if it is called nmake or gmake that it really is what it
        # says it is.
        if( $perl_make eq 'nmake' || $perl_make eq 'gmake' )
        {
          return $my_make = $perl_make;
        }

        my $out = capture { system $perl_make, '--version' };
        if( $out =~ /GNU make/i || $out =~ /Microsoft \(R\) Program Maintenance/ )
        {
          return $my_make = $perl_make;
        }

      }

      # if we see something that looks like it might be gmake, use that.
      foreach my $try (qw( gmake mingw32-make ))
      {
        return $my_make = $try if which $try;
      }

      if( which 'make' )
      {
        my $out = capture { system 'make', '--version' };
        if( $out =~ /GNU make/i || $out =~ /Microsoft \(R\) Program Maintenance/ )
        {
          return $my_make = 'make';
        }
      }

      # if we see something that looks like it might be nmake, use that.
      foreach my $try (qw( nmake ))
      {
        return $my_make = $try if which $try;
      }

      $my_make = $perl_make;
    });
  }
  else
  {
    $self->add_helper( make => sub { _config 'make' }, 'Config' );
  }


  $self->add_helper( mkdir_deep => sub { $^O eq 'MSWin32' ? 'md' : 'mkdir -p'}, 'Alien::Build' => '1.04' );
  $self->add_helper( make_path  => sub { $^O eq 'MSWin32' ? 'md' : 'mkdir -p'}, 'Alien::Build' => '1.05' );


  $self->add_helper( nasm => undef, sub {
    my $helper = shift;
    if(which 'nasm')
    {
      $helper->code(sub { 'nasm' });
      return  ();
    }
    else
    {
      return 'Alien::nasm' => '0.11';
    }
  });


  $self->add_helper( patch => undef, sub {
    my $helper = shift;
    if(which 'patch')
    {
      if($^O eq 'MSWin32')
      {
        $helper->code(sub { 'patch --binary' });
      }
      else
      {
        $helper->code(sub { 'patch' });
      }
      return  ();
    }
    else
    {
      return 'Alien::patch' => '0.09';
    }
  });


  $self->add_helper( perl => sub {
      my $perl = Devel::FindPerl::find_perl_interpreter();
      $perl =~ s{\\}{/}g if $^O eq 'MSWin32';
      $perl;
  }, 'Devel::FindPerl' );


  $self->add_helper( pkgconf => undef, 'Alien::pkgconf' => 0.06 );


  $self->add_helper( cwd => sub {
    my $cwd = "$CWD";
    $cwd =~ s{\\}{/}g if $^O eq 'MSWin32';
    $cwd;
  } );


  $self->add_helper( sh => sub { 'sh' }, 'Alien::MSYS' => '0.07' );


  $self->add_helper( rm => sub { _config 'rm' }, 'Config' );



  $self->add_helper( xz => undef, sub {
    my $helper = shift;
    if(which 'xz')
    {
      $helper->code(sub { 'xz' });
      return  ();
    }
    else
    {
      return 'Alien::xz' => '0.02';
    }
  });

  $self;
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Interpolate::Default - Default interpolator for Alien::Build

=head1 VERSION

version 2.84

=head1 CONSTRUCTOR

=head2 new

 my $intr = Alien::Build::Interpolate::Default->new;

=head1 HELPERS

=head2 ar

 %{ar}

The ar command.

=head2 bison

 %{bison}

Requires: L<Alien::bison> 0.17 if not already in C<PATH>.

=head2 bzip2

 %{bzip2}

Requires: L<Alien::Libbz2> 0.04 if not already in C<PATH>.

=head2 cc

 %{cc}

The C Compiler used to build Perl

=head2 cmake

 %{cmake}

Requires: L<Alien::CMake> 0.07 if cmake is not already in C<PATH>.

Deprecated: Use the L<Alien::Build::Plugin::Build::CMake> plugin instead (which will replace
this helper with one that works with L<Alien::cmake3> that works better).

=head2 cp

 %{cp}

The copy command.

=head2 devnull

 %{devnull}

The null device, if available.  On Unix style operating systems this will be C</dev/null> on Windows it is C<NUL>.

=head2 flex

 %{flex}

Requires: L<Alien::flex> 0.08 if not already in C<PATH>.

=head2 gmake

 %{gmake}

Requires: L<Alien::gmake> 0.11

Deprecated: use L<Alien::Build::Plugin::Build::Make> instead.

=head2 install

 %{install}

The Unix C<install> command.  Not normally available on Windows.

=head2 ld

 %{ld}

The linker used to build Perl

=head2 m4

 %{m4}

Requires: L<Alien::m4> 0.08

L<Alien::m4> should pull in a version of C<m4> that will work with Autotools.

=head2 make

 %{make}

Make.  On Unix this will be the same make used by Perl.  On Windows this will be
C<gmake> or C<nmake> if those are available, and only C<dmake> if the first two
are not available.

=head2 make_path

 %{make_path}

Make directory, including all parent directories as needed.  This is usually C<mkdir -p>
on Unix and simply C<md> on windows.

=head2 nasm

 %{nasm}

Requires: L<Alien::nasm> 0.11 if not already in the C<PATH>.

=head2 patch

 %{patch}

Requires: L<Alien::patch> 0.09 if not already in the C<PATH>.

On Windows this will normally render C<patch --binary>, which makes patch work like it does on Unix.

=head2 perl

 %{perl}

Requires: L<Devel::FindPerl>

=head2 pkgconf

 %{pkgconf}

Requires: L<Alien::pkgconf> 0.06.

=head2 cwd

 %{cwd}

=head2 sh

 %{sh}

Unix style command interpreter (/bin/sh).

Deprecated: use the L<Alien::Build::Plugin::Build::MSYS> plugin instead.

=head2 rm

 %{rm}

The remove command

=head2 xz

 %{xz}

Requires: L<Alien::xz> 0.02 if not already in the C<PATH>.

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK7N%[���

 perl5/Alien/Build/Log/Default.pmnu��6�$package Alien::Build::Log::Default;

use strict;
use warnings;
use 5.008004;
use parent qw( Alien::Build::Log );

# ABSTRACT: Default Alien::Build log class
our $VERSION = '2.84'; # VERSION


sub log
{
  my(undef, %args) = @_;
  my($message) = $args{message};
  my ($package, $filename, $line) = @{ $args{caller} };
  print "$package> $message\n";
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Log::Default - Default Alien::Build log class

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 Alien::Build->log("message1");
 $build->log("message2");

=head1 DESCRIPTION

This is the default log class for L<Alien::Build>.  It does
the sensible thing of sending the message to stdout, along
with the class that made the log call.  For more details
about logging with L<Alien::Build>, see L<Alien::Build::Log>.

=head1 METHODS

=head2 log

 $log->log(%opts);

Send single log line to stdout.

=head1 SEE ALSO

=over 4

=item L<Alien::Build>

=item L<Alien::Build::Log>

=back

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK7N%[�>��<
<
#perl5/Alien/Build/Log/Abbreviate.pmnu��6�$package Alien::Build::Log::Abbreviate;

use strict;
use warnings;
use 5.008004;
use Term::ANSIColor ();
use Path::Tiny qw( path );
use File::chdir;
use parent qw( Alien::Build::Log );

# ABSTRACT: Log class for Alien::Build which is less verbose
our $VERSION = '2.84'; # VERSION


sub _colored
{
  my($code, @out) = @_;
  -t STDOUT ? Term::ANSIColor::colored($code, @out) : @out;
}

my $root = path("$CWD");

sub log
{
  my(undef, %args) = @_;
  my($message) = $args{message};
  my ($package, $filename, $line) = @{ $args{caller} };

  my $source = $package;
  $source =~ s/^Alien::Build::Auto::[^:]+::Alienfile/alienfile/;

  my $expected = $package;
  $expected .= '.pm' unless $package eq 'alienfile';
  $expected =~ s/::/\//g;
  if($filename !~ /\Q$expected\E$/)
  {
    $source = path($filename)->relative($root);
  }
  else
  {
    $source =~ s/^Alien::Build::Plugin/ABP/;
    $source =~ s/^Alien::Build/AB/;
  }

  print _colored([ "bold on_black"          ], '[');
  print _colored([ "bright_green on_black"  ], $source);
  print _colored([ "on_black"               ], ' ');
  print _colored([ "bright_yellow on_black" ], $line);
  print _colored([ "bold on_black"          ], ']');
  print _colored([ "white on_black"         ], ' ', $message);
  print "\n";
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Log::Abbreviate - Log class for Alien::Build which is less verbose

=head1 VERSION

version 2.84

=head1 SYNOPSIS

=head1 DESCRIPTION

=head1 METHODS

=head2 log

 $log->log(%opts);

Send single log line to stdout.

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK7N%[@�?��perl5/Alien/Build/Plugin.pmnu��6�$package Alien::Build::Plugin;

use strict;
use warnings;
use 5.008004;
use Data::Dumper ();
use Carp ();
use Digest::SHA ();

our @CARP_NOT = qw( alienfile Alien::Build Alien::Build::Meta );

# ABSTRACT: Plugin base class for Alien::Build
our $VERSION = '2.84'; # VERSION


sub new
{
  my $class = shift;
  my %args = @_ == 1 ? ($class->meta->default => $_[0]) : @_;

  my $instance_id = Digest::SHA::sha1_hex(Data::Dumper->new([$class, \%args])->Sortkeys(1)->Dump);
  my $self = bless { instance_id => $instance_id }, $class;

  my $prop = $self->meta->prop;
  foreach my $name (keys %$prop)
  {
    $self->{$name} = defined $args{$name}
      ? delete $args{$name}
      : ref($prop->{$name}) eq 'CODE'
        ? $prop->{$name}->()
        : $prop->{$name};
  }

  foreach my $name (keys %args)
  {
    Carp::carp "$class has no $name property";
  }

  $self;
}


sub instance_id { shift->{instance_id} }


sub init
{
  my($self) = @_;
  $self;
}

sub import
{
  my($class) = @_;

  return if $class ne __PACKAGE__;

  my $caller = caller;
  { no strict 'refs'; @{ "${caller}::ISA" } = __PACKAGE__ }

  my $meta = $caller->meta;
  my $has = sub {
    my($name, $default) = @_;
    $meta->add_property($name, $default);
  };

  { no strict 'refs'; *{ "${caller}::has" } = $has }
}


my %meta;
sub meta
{
  my($class) = @_;
  $class = ref $class if ref $class;
  $meta{$class} ||= Alien::Build::PluginMeta->new( class => $class );
}

package Alien::Build::PluginMeta;

sub new
{
  my($class, %args) = @_;
  my $self = bless {
    prop => {},
    %args,
  }, $class;
}

sub default
{
  my($self) = @_;
  $self->{default} || do {
    Carp::croak "No default for @{[ $self->{class} ]}";
  };
}

sub add_property
{
  my($self, $name, $default) = @_;
  my $single = $name =~ s{^(\+)}{};
  $self->{default} = $name if $single;
  $self->{prop}->{$name} = $default;

  my $accessor = sub {
    my($self, $new) = @_;
    $self->{$name} = $new if defined $new;
    $self->{$name};
  };

  # add the accessor
  { no strict 'refs'; *{ $self->{class} . '::' . $name} = $accessor }

  $self;
}

sub prop
{
  shift->{prop};
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin - Plugin base class for Alien::Build

=head1 VERSION

version 2.84

=head1 SYNOPSIS

Create your plugin:

 package Alien::Build::Plugin::Type::MyPlugin;
 
 use Alien::Build::Plugin;
 use Carp ();
 
 has prop1 => 'default value';
 has prop2 => sub { 'default value' };
 has prop3 => sub { Carp::croak 'prop3 is a required property' };
 
 sub init
 {
   my($self, $meta) = @_;
 
   my $prop1 = $self->prop1;
   my $prop2 = $self->prop2;
   my $prop3 = $self->prop3;
 
   $meta->register_hook(sub {
     build => [ '%{make}', '%{make} install' ],
   });
 }

From your L<alienfile>

 use alienfile;
 plugin 'Type::MyPlugin' => (
   prop2 => 'different value',
   prop3 => 'need to provide since it is required',
 );

=head1 DESCRIPTION

This document describes the L<Alien::Build> plugin base class.  For details
on how to write a plugin, see L<Alien::Build::Manual::PluginAuthor>.

Listed are some common types of plugins:

=over 4

=item L<Alien::Build::Plugin::Build>

Tools for building.

=item L<Alien::Build::Plugin::Core>

Tools already included.

=item L<Alien::Build::Plugin::Decode>

Normally use Download plugins which will pick the correct Decode plugins.

=item L<Alien::Build::Plugin::Digest>

Tools for checking cryptographic signatures during a C<share> install.

=item L<Alien::Build::Plugin::Download>

Methods for retrieving from the internet.

=item L<Alien::Build::Plugin::Extract>

Extract from archives that have been downloaded.

=item L<Alien::Build::Plugin::Fetch>

Normally use Download plugins which will pick the correct Fetch plugins.

=item L<Alien::Build::Plugin::Gather>

Plugins that modify or enhance the gather step.

=item L<Alien::Build::Plugin::PkgConfig>

Plugins that work with C<pkg-config> or libraries that provide the same
functionality.

=item L<Alien::Build::Plugin::Prefer>

Normally use Download plugins which will pick the correct Prefer plugins.

=item L<Alien::Build::Plugin::Probe>

Look for packages already installed on the system.

=item L<Alien::Build::Plugin::Probe>

Plugins useful for unit testing L<Alien::Build> itself, or plugins for it.

=back

=head1 CONSTRUCTOR

=head2 new

 my $plugin = Alien::Build::Plugin->new(%props);

=head2 PROPERTIES

=head2 instance_id

 my $id = $plugin->instance_id;

Returns an instance id for the plugin.  This is computed from the class and
arguments that are passed into the plugin constructor, so technically two
instances with the exact same arguments will have the same instance id, but
in practice you should never have two instances with the exact same arguments.

=head1 METHODS

=head2 init

 $plugin->init($ab_class->meta); # $ab is an Alien::Build class name

You provide the implementation for this.  The intent is to register
hooks and set meta properties on the L<Alien::Build> class.

=head2 has

 has $prop_name;
 has $prop_name => $default;

Specifies a property of the plugin.  You may provide a default value as either
a string scalar, or a code reference.  The code reference will be called to
compute the default value, and if you want the default to be a list or hash
reference, this is how you want to do it:

 has foo => sub { [1,2,3] };

=head2 meta

 my $meta = $plugin->meta;

Returns the plugin meta object.

=head1 SEE ALSO

L<Alien::Build>, L<alienfile>, L<Alien::Build::Manual::PluginAuthor>

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK7N%[�ݪ5�� perl5/Alien/Build/Interpolate.pmnu��6�$package Alien::Build::Interpolate;

use strict;
use warnings;
use 5.008004;

# ABSTRACT: Advanced interpolation engine for Alien builds
our $VERSION = '2.84'; # VERSION


sub new
{
  my($class) = @_;
  my $self = bless {
    helper  => {},
    classes => {},
  }, $class;
  $self;
}


sub add_helper
{
  my $self = shift;
  my $name = shift;
  my $code = shift;

  if(defined $self->{helper}->{$name})
  {
    require Carp;
    Carp::croak("duplicate implementation for interpolated key $name");
  }

  my $require;

  if(ref $_[0] eq 'CODE')
  {
    $require = shift;
  }
  else
  {
    $require = [];
    while(@_)
    {
      my $module = shift;
      my $version = shift;
      $version ||= 0;
      push @$require, $module => $version;
    }
  }

  $self->{helper}->{$name} = Alien::Build::Helper->new(
    $name,
    $code,
    $require,
  );
}


sub replace_helper
{
  my $self = shift;
  my($name) = @_;
  delete $self->{helper}->{$name};
  $self->add_helper(@_);
}


sub has_helper
{
  my($self, $name) = @_;

  return unless defined $self->{helper}->{$name};

  my @require = $self->{helper}->{$name}->require;

  while(@require)
  {
    my $module  = shift @require;
    my $version = shift @require;

    {
      my $pm = "$module.pm";
      $pm =~ s/::/\//g;
      require $pm;
      $module->VERSION($version) if $version;
    }

    unless($self->{classes}->{$module})
    {
      if($module->can('alien_helper'))
      {
        my $helpers = $module->alien_helper;
        foreach my $k (keys %$helpers)
        {
          $self->{helper}->{$k}->code($helpers->{$k});
        }
      }
      $self->{classes}->{$module} = 1;
    }
  }

  my $code = $self->{helper}->{$name}->code;

  return unless defined $code;

  if(ref($code) ne 'CODE')
  {
    my $perl = $code;
    package Alien::Build::Interpolate::Helper;
    $code = sub {
      ##  no critic
      my $value = eval $perl;
      ## use critic
      die $@ if $@;
      $value;
    };
  }

  $code;
}


sub execute_helper
{
  my($self, $name) = @_;

  my $code = $self->has_helper($name);
  die "no helper defined for $name" unless defined $code;

  $code->();
}


sub _get_prop
{
  my($name, $prop, $orig) = @_;

  $name =~ s/^\./alien./;

  if($name =~ /^(.*?)\.(.*)$/)
  {
    my($key,$rest) = ($1,$2);
    return _get_prop($rest, $prop->{$key}, $orig);
  }
  elsif(exists $prop->{$name})
  {
    return $prop->{$name};
  }
  else
  {
    require Carp;
    Carp::croak("No property $orig is defined");
  }
}

sub interpolate
{
  my($self, $string, $build) = @_;

  my $prop = defined $build && eval { $build->isa('Alien::Build') }
  ? $build->_command_prop
  : {};

  $string =~ s{(?<!\%)\%\{([a-zA-Z_][a-zA-Z_0-9]+)\}}{$self->execute_helper($1)}eg;
  $string =~ s{(?<!\%)\%\{([a-zA-Z_\.][a-zA-Z_0-9\.]+)\}}{_get_prop($1,$prop,$1)}eg;
  $string =~ s/\%(?=\%)//g;
  $string;
}


sub requires
{
  my($self, $string) = @_;
  map {
    my $helper = $self->{helper}->{$_};
    $helper ? $helper->require : ();
  } $string =~ m{(?<!\%)\%\{([a-zA-Z_][a-zA-Z_0-9]+)\}}g;
}


sub clone
{
  my($self) = @_;

  require Storable;

  my %helper;
  foreach my $name (keys %{ $self->{helper} })
  {
    $helper{$name} = $self->{helper}->{$name}->clone;
  }

  my $new = bless {
    helper => \%helper,
    classes => Storable::dclone($self->{classes}),
  }, ref $self;
}

package Alien::Build::Helper;

sub new
{
  my($class, $name, $code, $require) = @_;
  bless {
    name    => $name,
    code    => $code,
    require => $require,
  }, $class;
}

sub name { shift->{name} }

sub code
{
  my($self, $code) = @_;
  $self->{code} = $code if $code;
  $self->{code};
}

sub require
{
  my($self) = @_;
  if(ref $self->{require} eq 'CODE')
  {
    $self->{require} = [ $self->{require}->($self) ];
  }
  @{ $self->{require} };
}

sub clone
{
  my($self) = @_;
  my $class = ref $self;
  $class->new(
    $self->name,
    $self->code,
    [ $self->require ],
  );
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Interpolate - Advanced interpolation engine for Alien builds

=head1 VERSION

version 2.84

=head1 CONSTRUCTOR

=head2 new

 my $intr = Alien::Build::Interpolate->new;

=head2 add_helper

 $intr->add_helper($name => $code);
 $intr->add_helper($name => $code, %requirements);

=head2 replace_helper

 $intr->replace_helper($name => $code);
 $intr->replace_helper($name => $code, %requirements);

=head2 has_helper

 my $coderef = $intr->has_helper($name);

Used to discover if a helper exists with the given name.
Returns the code reference.

=head2 execute_helper

 my $value = $intr->execute_helper($name);

This evaluates the given helper and returns the result.

=head2 interpolate

 my $string = $intr->interpolate($template, $build);
 my $string = $intr->interpolate($template);

This takes a template and fills in the appropriate values of any helpers used
in the template.

[version 2.58]

If you pass in an L<Alien::Build> instance as the second argument, you can use
properties as well as helpers in the template.  Example:

 my $patch = $intr->template("%{.install.patch}/foo-%{.runtime.version}.patch", $build);

=head2 requires

 my %requires = $intr->requires($template);

This returns a hash of modules required in order to execute the given template.
The keys are the module names and the values are the versions.  Version will be
set to C<0> if any version is sufficient.

=head2 clone

 my $intr2 = $intr->clone;

This creates a clone of the interpolator.

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK7N%[�����$perl5/Alien/Build/CommandSequence.pmnu��6�$package Alien::Build::CommandSequence;

use strict;
use warnings;
use 5.008004;
use Text::ParseWords qw( shellwords );
use Capture::Tiny qw( capture );

# ABSTRACT: Alien::Build command sequence
our $VERSION = '2.84'; # VERSION


sub new
{
  my($class, @commands) = @_;
  my $self = bless {
    commands => \@commands,
  }, $class;
  $self;
}


sub apply_requirements
{
  my($self, $meta, $phase) = @_;
  my $intr = $meta->interpolator;
  foreach my $command (@{ $self->{commands} })
  {
    next if ref $command eq 'CODE';
    if(ref $command eq 'ARRAY')
    {
      foreach my $arg (@$command)
      {
        next if ref $arg eq 'CODE';
        $meta->add_requires($phase, $intr->requires($arg))
      }
    }
    else
    {
      $meta->add_requires($phase, $intr->requires($command));
    }
  }
  $self;
}

my %built_in = (

  cd => sub {
    my(undef, $dir) = @_;
    if(!defined $dir)
    {
      die "undef passed to cd";
    }
    elsif(-d $dir)
    {
      chdir($dir) || die "unable to cd $dir $!";
    }
    else
    {
      die "unable to cd $dir, does not exist";
    }
  },

);

sub _run_list
{
  my($build, @cmd) = @_;
  $build->log("+ @cmd");
  return $built_in{$cmd[0]}->(@cmd) if $built_in{$cmd[0]};
  system @cmd;
  die "external command failed" if $?;
}

sub _run_string
{
  my($build, $cmd) = @_;
  $build->log("+ $cmd");

  {
    my $cmd = $cmd;
    $cmd =~ s{\\}{\\\\}g if $^O eq 'MSWin32';
    my @cmd = shellwords($cmd);
    return $built_in{$cmd[0]}->(@cmd) if $built_in{$cmd[0]};
  }

  system $cmd;
  die "external command failed" if $?;
}

sub _run_with_code
{
  my($build, @cmd) = @_;
  my $code = pop @cmd;
  $build->log("+ @cmd");
  my %args = ( command => \@cmd );

  if($built_in{$cmd[0]})
  {
    my $error;
    ($args{out}, $args{err}, $error) = capture {
      eval { $built_in{$cmd[0]}->(@cmd) };
      $@;
    };
    $args{exit} = $error eq '' ? 0 : 2;
    $args{builtin} = 1;
  }
  else
  {
    ($args{out}, $args{err}, $args{exit}) = capture {
      system @cmd; $?
    };
  }
  $build->log("[output consumed by Alien::Build recipe]");
  $code->($build, \%args);
}


sub _apply
{
  my($where, $prop, $value) = @_;
  if($where =~ /^(.*?)\.(.*?)$/)
  {
    _apply($2, $prop->{$1}, $value);
  }
  else
  {
    $prop->{$where} = $value;
  }
}

sub execute
{
  my($self, $build) = @_;
  my $intr = $build->meta->interpolator;

  foreach my $command (@{ $self->{commands} })
  {
    if(ref($command) eq 'CODE')
    {
      $command->($build);
    }
    elsif(ref($command) eq 'ARRAY')
    {
      my($command, @args) = @$command;
      my $code;
      $code = pop @args if $args[-1] && ref($args[-1]) eq 'CODE';

      if($args[-1] && ref($args[-1]) eq 'SCALAR')
      {
        my $dest = ${ pop @args };
        if($dest =~ /^\%\{((?:alien|)\.(?:install|runtime|hook)\.[a-z\.0-9_]+)\}$/)
        {
          $dest = $1;
          $dest =~ s/^\./alien./;
          $code = sub {
            my($build, $args) = @_;
            die "external command failed" if $args->{exit};
            my $out = $args->{out};
            chomp $out;
            _apply($dest, $build->_command_prop, $out);
          };
        }
        else
        {
          die "illegal destination: $dest";
        }
      }

      ($command, @args) = map { $intr->interpolate($_, $build) } ($command, @args);

      if($code)
      {
        _run_with_code $build, $command, @args, $code;
      }
      else
      {
        _run_list $build, $command, @args;
      }
    }
    else
    {
      my $command = $intr->interpolate($command, $build);
      _run_string $build, $command;
    }
  }
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::CommandSequence - Alien::Build command sequence

=head1 VERSION

version 2.84

=head1 CONSTRUCTOR

=head2 new

 my $seq = Alien::Build::CommandSequence->new(@commands);

=head1 METHODS

=head2 apply_requirements

 $seq->apply_requirements($meta, $phase);

=head2 execute

 $seq->execute($build);

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK7N%[��2l�;�;perl5/Alien/Build/MM.pmnu��6�$package Alien::Build::MM;

use strict;
use warnings;
use 5.008004;
use Alien::Build;
use Path::Tiny ();
use Capture::Tiny qw( capture );
use Carp ();

# ABSTRACT: Alien::Build installer code for ExtUtils::MakeMaker
our $VERSION = '2.84'; # VERSION


sub new
{
  my($class, %prop) = @_;

  my $self = bless {}, $class;

  my %meta = map { $_ => $prop{$_} } grep /^my_/, keys %prop;

  my $build = $self->{build} =
    Alien::Build->load('alienfile',
      root     => "_alien",
      (-d 'patch' ? (patch => 'patch') : ()),
      meta_prop => \%meta,
    )
  ;

  if(%meta)
  {
    $build->meta->add_requires(configure => 'Alien::Build::MM' => '1.20');
    $build->meta->add_requires(configure => 'Alien::Build' => '1.20');
  }

  if(defined $prop{alienfile_meta})
  {
    $self->{alienfile_meta} = $prop{alienfile_meta};
  }
  else
  {
    $self->{alienfile_meta} = 1;
  }

  $self->{clean_install} = $prop{clean_install};

  $self->build->load_requires('configure');
  $self->build->root;
  $self->build->checkpoint;

  $self;
}


sub build
{
  shift->{build};
}


sub alienfile_meta
{
  shift->{alienfile_meta};
}


sub clean_install
{
  shift->{clean_install};
}


sub mm_args
{
  my($self, %args) = @_;

  if($args{DISTNAME})
  {
    $self->build->set_stage(Path::Tiny->new("blib/lib/auto/share/dist/$args{DISTNAME}")->absolute->stringify);
    $self->build->install_prop->{mm}->{distname} = $args{DISTNAME};
    my $module = $args{DISTNAME};
    $module =~ s/-/::/g;
    # See if there is an existing version installed, without pulling it into this process
    my($old_prefix, $err, $ret) = capture { system $^X, "-M$module", -e => "print $module->dist_dir"; $? };
    if($ret == 0)
    {
      chomp $old_prefix;
      my $file = Path::Tiny->new($old_prefix, qw( _alien alien.json ));
      if(-r $file)
      {
        my $old_runtime = eval {
          require JSON::PP;
          JSON::PP::decode_json($file->slurp);
        };
        unless($@)
        {
          $self->build->install_prop->{old}->{runtime} = $old_runtime;
          $self->build->install_prop->{old}->{prefix}  = $old_prefix;
        }
      }
    }
  }
  else
  {
    Carp::croak "DISTNAME is required";
  }

  my $ab_version = '0.25';

  if($self->clean_install)
  {
    $ab_version = '1.74';
  }

  $args{CONFIGURE_REQUIRES} = Alien::Build::_merge(
    'Alien::Build::MM' => $ab_version,
    %{ $args{CONFIGURE_REQUIRES} || {} },
    %{ $self->build->requires('configure') || {} },
  );

  if($self->build->install_type eq 'system')
  {
    $args{BUILD_REQUIRES} = Alien::Build::_merge(
      'Alien::Build::MM' => $ab_version,
      %{ $args{BUILD_REQUIRES} || {} },
      %{ $self->build->requires('system') || {} },
    );
  }
  elsif($self->build->install_type eq 'share')
  {
    $args{BUILD_REQUIRES} = Alien::Build::_merge(
      'Alien::Build::MM' => $ab_version,
      %{ $args{BUILD_REQUIRES} || {} },
      %{ $self->build->requires('share') || {} },
    );
  }
  else
  {
    die "unknown install type: @{[ $self->build->install_type ]}"
  }

  $args{PREREQ_PM} = Alien::Build::_merge(
    'Alien::Build' => $ab_version,
    %{ $args{PREREQ_PM} || {} },
  );

  #$args{META_MERGE}->{'meta-spec'}->{version} = 2;
  $args{META_MERGE}->{dynamic_config} = 1;

  if($self->alienfile_meta)
  {
    $args{META_MERGE}->{x_alienfile} = {
      generated_by => "@{[ __PACKAGE__ ]} version @{[ __PACKAGE__->VERSION || 'dev' ]}",
      requires => {
        map {
          my %reqs = %{ $self->build->requires($_) };
          $reqs{$_} = "$reqs{$_}" for keys %reqs;
          $_ => \%reqs;
        } qw( share system )
      },
    };
  }

  $self->build->checkpoint;
  %args;
}


sub mm_postamble
{
  # NOTE: older versions of the Alien::Build::MM documentation
  # didn't include $mm and @rest args, so anything that this
  # method uses them for has to be optional.
  # (as of this writing they are unused, but are being added
  #  to match the way mm_install works).

  my($self, $mm, @rest) = @_;

  my $postamble = '';

  # remove the _alien directory on a make realclean:
  $postamble .= "realclean :: alien_realclean\n" .
                "\n" .
                "alien_realclean:\n" .
                "\t\$(RM_RF) _alien\n\n";

  # remove the _alien directory on a make clean:
  $postamble .= "clean :: alien_clean\n" .
                "\n" .
                "alien_clean:\n" .
                "\t\$(RM_RF) _alien\n\n";

  my $dirs = $self->build->meta_prop->{arch}
    ? '$(INSTALLARCHLIB) $(INSTALLSITEARCH) $(INSTALLVENDORARCH)'
    : '$(INSTALLPRIVLIB) $(INSTALLSITELIB) $(INSTALLVENDORLIB)'
  ;

  # set prefix
  $postamble .= "alien_prefix : _alien/mm/prefix\n\n" .
                "_alien/mm/prefix :\n" .
                "\t\$(FULLPERL) -MAlien::Build::MM=cmd -e prefix \$(INSTALLDIRS) $dirs\n\n";

  # set version
  $postamble .= "alien_version : _alien/mm/version\n\n" .
                "_alien/mm/version : _alien/mm/prefix\n" .
                "\t\$(FULLPERL) -MAlien::Build::MM=cmd -e version \$(VERSION)\n\n";

  # download
  $postamble .= "alien_download : _alien/mm/download\n\n" .
                "_alien/mm/download : _alien/mm/prefix _alien/mm/version\n" .
                "\t\$(FULLPERL) -MAlien::Build::MM=cmd -e download\n\n";

  # build
  $postamble .= "alien_build : _alien/mm/build\n\n" .
                "_alien/mm/build : _alien/mm/download\n" .
                "\t\$(FULLPERL) -MAlien::Build::MM=cmd -e build\n\n";

  # append to all
  $postamble .= "pure_all :: _alien/mm/build\n\n";

  $postamble .= "subdirs-test_dynamic subdirs-test_static subdirs-test :: alien_test\n\n";
  $postamble .= "alien_test :\n" .
                "\t\$(FULLPERL) -MAlien::Build::MM=cmd -e test\n\n";

  # prop
  $postamble .= "alien_prop :\n" .
                "\t\$(FULLPERL) -MAlien::Build::MM=cmd -e dumpprop\n\n";
  $postamble .= "alien_prop_meta :\n" .
                "\t\$(FULLPERL) -MAlien::Build::MM=cmd -e dumpprop meta\n\n";
  $postamble .= "alien_prop_install :\n" .
                "\t\$(FULLPERL) -MAlien::Build::MM=cmd -e dumpprop install\n\n";
  $postamble .= "alien_prop_runtime :\n" .
                "\t\$(FULLPERL) -MAlien::Build::MM=cmd -e dumpprop runtime\n\n";

  # install
  $postamble .= "alien_clean_install : _alien/mm/prefix\n" .
                "\t\$(FULLPERL) -MAlien::Build::MM=cmd -e clean_install\n\n";

  $postamble;
}


sub mm_install
{
  # NOTE: older versions of the Alien::Build::MM documentation
  # didn't include this method, so anything that this method
  # does has to be optional

  my($self, $mm, @rest) = @_;

  my $section = do {
    package
      MY;
    $mm->SUPER::install(@rest);
  };

  return
      ".NOTPARALLEL : \n\n"
    . ".NO_PARALLEL : \n\n"
    . "install :: alien_clean_install\n\n"
    . $section;
}

sub import
{
  my(undef, @args) = @_;
  foreach my $arg (@args)
  {
    if($arg eq 'cmd')
    {
      package main;

      *_args = sub
      {
        my $build = Alien::Build->resume('alienfile', '_alien');
        $build->load_requires('configure');
        $build->load_requires($build->install_type);
        ($build, @ARGV)
      };

      *_touch = sub {
        my($name) = @_;
        my $path = Path::Tiny->new("_alien/mm/$name");
        $path->parent->mkpath;
        $path->touch;
      };

      *prefix = sub
      {
        my($build, $type, $perl, $site, $vendor) = _args();

        my $distname = $build->install_prop->{mm}->{distname};

        my $prefix = $type eq 'perl'
          ? $perl
          : $type eq 'site'
            ? $site
            : $type eq 'vendor'
              ? $vendor
              : die "unknown INSTALLDIRS ($type)";
        $prefix = Path::Tiny->new($prefix)->child("auto/share/dist/$distname")->absolute->stringify;

        $build->log("prefix $prefix");
        $build->set_prefix($prefix);
        $build->checkpoint;
        _touch('prefix');
      };

      *version = sub
      {
        my($build, $version) = _args();

        $build->runtime_prop->{perl_module_version} = $version;
        $build->checkpoint;
        _touch('version');
      };

      *download = sub
      {
        my($build) = _args();
        $build->download;
        $build->checkpoint;
       _touch('download');
      };

      *build = sub
      {
        my($build) = _args();

        $build->build;

        my $distname = $build->install_prop->{mm}->{distname};

        if($build->meta_prop->{arch})
        {
          my $archdir = Path::Tiny->new("blib/arch/auto/@{[ join '/', split /-/, $distname ]}");
          $archdir->mkpath;
          my $archfile = $archdir->child($archdir->basename . '.txt');
          $archfile->spew('Alien based distribution with architecture specific file in share');
        }

        my $cflags = $build->runtime_prop->{cflags};
        my $libs   = $build->runtime_prop->{libs};

        if(($cflags && $cflags !~ /^\s*$/)
        || ($libs   && $libs   !~ /^\s*$/))
        {
          my $mod = join '::', split /-/, $distname;
          my $install_files_pm = Path::Tiny->new("blib/lib/@{[ join '/', split /-/, $distname ]}/Install/Files.pm");
          $install_files_pm->parent->mkpath;
          $install_files_pm->spew(
            "package ${mod}::Install::Files;\n",
            "use strict;\n",
            "use warnings;\n",
            "require ${mod};\n",
            "sub Inline { shift; ${mod}->Inline(\@_) }\n",
            "1;\n",
            "\n",
            "=begin Pod::Coverage\n",
            "\n",
            "  Inline\n",
            "\n",
            "=cut\n",
          ) unless -f "$install_files_pm";
        }

        $build->checkpoint;
        _touch('build');
      };

      *test = sub
      {
        my($build) = _args();
        $build->test;
        $build->checkpoint;
      };

      *clean_install = sub
      {
        my($build) = _args();
        $build->clean_install;
        $build->checkpoint;
      };

      *dumpprop = sub
      {
        my($build, $type) = _args();

        my %h = (
          meta    => $build->meta_prop,
          install => $build->install_prop,
          runtime => $build->runtime_prop,
        );

        require Alien::Build::Util;
        print Alien::Build::Util::_dump($type ? $h{$type} : \%h);
      }
    }
  }
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::MM - Alien::Build installer code for ExtUtils::MakeMaker

=head1 VERSION

version 2.84

=head1 SYNOPSIS

In your C<Makefile.PL>:

 use ExtUtils::MakeMaker;
 use Alien::Build::MM;
 
 my $abmm = Alien::Build::MM->new;
 
 WriteMakefile($abmm->mm_args(
   ABSTRACT     => 'Discover or download and install libfoo',
   DISTNAME     => 'Alien-Libfoo',
   NAME         => 'Alien::Libfoo',
   VERSION_FROM => 'lib/Alien/Libfoo.pm',
   ...
 ));
 
 sub MY::postamble {
   $abmm->mm_postamble(@_);
 }
 
 sub MY::install {
   $abmm->mm_install(@_);
 }

In your C<lib/Alien/Libfoo.pm>:

 package Alien::Libfoo;
 use parent qw( Alien::Base );
 1;

In your alienfile (needs to be named C<alienfile> and should be in the root of your dist):

 use alienfile;
 
 plugin 'PkgConfig' => 'libfoo';
 
 share {
   start_url 'http://libfoo.org';
   ...
 };

=head1 DESCRIPTION

This class allows you to use Alien::Build and Alien::Base with L<ExtUtils::MakeMaker>.
It load the L<alienfile> recipe in the root of your L<Alien> dist, updates the prereqs
passed into C<WriteMakefile> if any are specified by your L<alienfile> or its plugins,
and adds a postamble to the C<Makefile> that will download/build/test the alienized
package as appropriate.

The L<alienfile> must be named C<alienfile>.

If you are using L<Dist::Zilla> to author your L<Alien> dist, you should consider using
the L<Dist::Zilla::Plugin::AlienBuild> plugin.

I personally don't recommend it, but if you want to use L<Module::Build> instead, you
can use L<Alien::Build::MB>.

=head1 CONSTRUCTOR

=head2 new

 my $abmm = Alien::Build::MM->new;

Create a new instance of L<Alien::Build::MM>.

=head1 PROPERTIES

=head2 build

 my $build = $abmm->build;

The L<Alien::Build> instance.

=head2 alienfile_meta

 my $bool = $abmm->alienfile_meta

Set to a false value, in order to turn off the x_alienfile meta

=head2 clean_install

 my $bool = $abmm->clean_install;

Set to a true value, in order to clean the share directory prior to
installing.  If you use this you have to make sure that you install
the install handler in your C<Makefile.PL>:

 $abmm = Alien::Build::MM->new(
   clean_install => 1,
 );
 
 ...
 
 sub MY::install {
   $abmm->mm_install(@_);
 }

=head1 METHODS

=head2 mm_args

 my %args = $abmm->mm_args(%args);

Adjust the arguments passed into C<WriteMakefile> as needed by L<Alien::Build>.

=head2 mm_postamble

 my $postamble $abmm->mm_postamble;
 my $postamble $abmm->mm_postamble($mm);

Returns the postamble for the C<Makefile> needed for L<Alien::Build>.
This adds the following C<make> targets which are normally called when
you run C<make all>, but can be run individually if needed for debugging.

=over 4

=item alien_prefix

Determines the final install prefix (C<%{.install.prefix}>).

=item alien_version

Determine the perl_module_version (C<%{.runtime.perl_module_version}>)

=item alien_download

Downloads the source from the internet.  Does nothing for a system install.

=item alien_build

Build from source (if a share install).  Gather configuration (for either
system or share install).

=item alien_prop, alien_prop_meta, alien_prop_install, alien_prop_runtime

Prints the meta, install and runtime properties for the Alien.

=item alien_realclean, alien_clean

Removes the alien specific files.  These targets are executed when you call
the C<realclean> and C<clean> targets respectively.

=item alien_clean_install

Cleans out the Alien's share directory.  Caution should be used in invoking
this target directly, as if you do not understand what you are doing you
are likely to break your already installed Alien.

=back

=head2 mm_install

 sub MY::install {
   $abmm->mm_install(@_);
 }

B<EXPERIMENTAL>

Adds an install rule to clean the final install dist directory prior to installing.

=head1 SEE ALSO

L<Alien::Build>, L<Alien::Base>, L<Alien>, L<Dist::Zilla::Plugin::AlienBuild>, L<Alien::Build::MB>

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK7N%[��x�ppperl5/Alien/Build/Temp.pmnu��6�$package Alien::Build::Temp;

use strict;
use warnings;
use 5.008004;
use Carp ();
use Path::Tiny ();
use File::Temp ();
use File::Spec ();

# ABSTRACT: Temp Dir support for Alien::Build
our $VERSION = '2.84'; # VERSION


# problem with vanilla File::Temp is that is often uses
# as /tmp that has noexec turned on.  Workaround is to
# create a temp directory in the build directory, but
# we have to be careful about cleanup.  This puts all that
# (attempted) carefulness in one place so that when we
# later discover it isn't so careful we can fix it in
# one place rather than all the places that we need
# temp directories.

# we also have a speical case for Windows, which often
# has problems with long paths if we try to use the
# current directory for temp files, so for those we
# use the system tmp directory.

my %root;

sub _root
{
  return File::Spec->tmpdir if $^O eq 'MSWin32';

  my $root = Path::Tiny->new(-d "_alien" ? "_alien/tmp" : ".tmp")->absolute;
  unless(-d $root)
  {
    mkdir $root or die "unable to create temp root $!";
  }

  # TODO: doesn't account for fork...
  my $lock = $root->child("l$$");
  unless(-f $lock)
  {
    open my $fh, '>', $lock;
    close $fh;
  }
  $root{"$root"} = 1;
  $root;
}

END {
  foreach my $root (keys %root)
  {
    my $lock = Path::Tiny->new($root)->child("l$$");
    unlink $lock;
    # try to delete if possible.
    # if not possible then punt
    rmdir $root if -d $root;
  }
}

sub newdir
{
  my $class = shift;
  Carp::croak "uneven" if @_ % 2;
  File::Temp->newdir(DIR => _root, @_);
}

sub new
{
  my $class = shift;
  Carp::croak "uneven" if @_ % 2;
  File::Temp->new(DIR => _root, @_);
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Temp - Temp Dir support for Alien::Build

=head1 VERSION

version 2.84

=head1 DESCRIPTION

This class is private to L<Alien::Build>.

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK7N%[3V��	�	"perl5/Alien/Build/Plugin/Build.podnu��6�$# PODNAME: Alien::Build::Plugin::Build
# ABSTRACT: Build Alien::Build plugins
# VERSION

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::Build - Build Alien::Build plugins

=head1 VERSION

version 2.84

=head1 SYNOPSIS

For autoconf:

 use alienfile;
 plugin 'Build::Autoconf';

for unixy (even on windows):

 use alienfile;
 plugin 'Build::MSYS';

=head1 DESCRIPTION

Build plugins provide tools for building your package once it has been
downloaded and extracted.

=over 4

=item L<Alien::Build::Plugin::Build::Autoconf>

For dealing with packages that are configured using autotools,
or an autotools-like C<configure> script.

=item L<Alien::Build::Plugin::Build::CMake>

For dealing with packages that are configured and built using CMake.

=item L<Alien::Build::Plugin::Build::Copy>

For dealing with packages that do not require any build, and can just
be copied into their final location.

=item L<Alien::Build::Plugin::Build::MSYS>

For dealing with packages that require MSYS on Windows in order to
build.  This plugin is typically a no-op on other platforms.

=item L<Alien::Build::Plugin::Build::Make>

For dealing with packages that require Make to build.  Several
flavors of Make are supported, including GNU Make and BSD Make.

=item L<Alien::Build::Plugin::Build::SearchDep>

Add other L<Alien>s as dependencies.

=back

=head1 SEE ALSO

L<Alien::Build>, L<Alien::Build::Plugin>

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK7N%[��r9-9-%perl5/Alien/Build/Plugin/Test/Mock.pmnu��6�$package Alien::Build::Plugin::Test::Mock;

use strict;
use warnings;
use 5.008004;
use Alien::Build::Plugin;
use Carp ();
use Path::Tiny ();
use File::chdir;

# ABSTRACT: Mock plugin for testing
our $VERSION = '2.84'; # VERSION


has 'probe';


has 'download';


has 'extract';


has 'build';


has 'gather';


has check_digest => 1;

sub init
{
  my($self, $meta) = @_;

  if(my $probe = $self->probe)
  {
    if($probe =~ /^(share|system)$/)
    {
      $meta->register_hook(
        probe => sub {
          $probe;
        },
      );
    }
    elsif($probe eq 'die')
    {
      $meta->register_hook(
        probe => sub {
          die "fail";
        },
      );
    }
    else
    {
      Carp::croak("usage: plugin 'Test::Mock' => ( probe => $probe ); where $probe is one of share, system or die");
    }
  }

  if(my $download = $self->download)
  {
    $download = { 'foo-1.00.tar.gz' => _tarball() } unless ref $download eq 'HASH';
    $meta->register_hook(
      download => sub {
        my($build) = @_;
        _fs($build, $download, 1);
      },
    );
  }

  if(my $extract = $self->extract)
  {
    $extract = {
      'foo-1.00' => {
        'configure' => _tarball_configure(),
        'foo.c'     => _tarball_foo_c(),
      },
    } unless ref $extract eq 'HASH';
    $meta->register_hook(
      extract => sub {
        my($build) = @_;
        _fs($build, $extract);
      },
    );
  }

  if(my $build = $self->build)
  {
    $build = [
      {
        'foo.o',   => _build_foo_o(),
        'libfoo.a' => _build_libfoo_a(),
      },
      {
        'lib' => {
          'libfoo.a' => _build_libfoo_a(),
          'pkgconfig' => {
            'foo.pc' => sub {
              my($build) = @_;
              "prefix=$CWD\n" .
              "exec_prefix=\${prefix}\n" .
              "libdir=\${prefix}/lib\n" .
              "includedir=\${prefix}/include\n" .
              "\n" .
              "Name: libfoo\n" .
              "Description: libfoo\n" .
              "Version: 1.0.0\n" .
              "Cflags: -I\${includedir}\n" .
              "Libs: -L\${libdir} -lfoo\n";
            },
          },
        },
      },
    ] unless ref $build eq 'ARRAY';

    my($build_dir, $install_dir) = @$build;

    $meta->register_hook(
      build => sub {
        my($build) = @_;
        _fs($build, $build_dir);
        local $CWD = $build->install_prop->{prefix};
        _fs($build, $install_dir);
      },
    );
  }

  if(my $gather = $self->gather)
  {
    $meta->register_hook(
      $_ => sub {
        my($build) = @_;
        if(ref $gather eq 'HASH')
        {
          foreach my $key (keys %$gather)
          {
            $build->runtime_prop->{$key} = $gather->{$key};
          }
        }
        else
        {
          my $prefix = $build->runtime_prop->{prefix};
          $build->runtime_prop->{cflags} = "-I$prefix/include";
          $build->runtime_prop->{libs}   = "-L$prefix/lib -lfoo";
        }
      },
    ) for qw( gather_share gather_system );
  }

  if(my $cd = $self->check_digest)
  {
    $meta->register_hook(
      check_digest => ref($cd) eq 'CODE' ? $cd : sub {
        my($build, $file, $algorithm, $digest) = @_;
        if($algorithm ne 'FOO92')
        {
          return 'FAKE';
        }
        if($digest eq 'deadbeaf')
        {
          return 1;
        }
        else
        {
          die "Digest FAKE does not match: got deadbeaf, expected $digest";
        }
      }
    );
    $meta->register_hook(
      check_download => sub {
        my($build) = @_;
        my $path = $build->install_prop->{download};
        if(defined $path)
        {
          $build->check_digest($path);
        }
      },
    );
  }
}

sub _fs
{
  my($build, $hash, $download) = @_;

  foreach my $key (sort keys %$hash)
  {
    my $val = $hash->{$key};
    if(ref $val eq 'HASH')
    {
      mkdir $key;
      local $CWD = $key;
      _fs($build,$val);
    }
    elsif(ref $val eq 'CODE')
    {
      my $path = Path::Tiny->new($key)->absolute;
      $path->spew_raw($val->($build));
      if($download)
      {
        $build->install_prop->{download_detail}->{"$path"}->{protocol} = 'file';
        $build->install_prop->{download_detail}->{"$path"}->{digest}   = [ FAKE => 'deadbeaf' ];
      }
    }
    elsif(defined $val)
    {
      my $path = Path::Tiny->new($key)->absolute;
      $path->spew_raw($val);
      if($download)
      {
        $build->install_prop->{download_detail}->{"$path"}->{protocol} = 'file';
        $build->install_prop->{download_detail}->{"$path"}->{digest}   = [ FAKE => 'deadbeaf' ];
      }
    }
  }
}

sub _tarball
{
  return unpack 'u', <<'EOF';
M'XL(`+DM@5@``^V4P4K$,!"&>YZGF-V]J*SM9#=)#RN^B'BHV;0)U`32U(OX
M[D;0*LJREZVRF.\R?TA@)OS\TWI_S4JBJI@/(JJ%P%19+>AKG4"V)4Z;C922
M(;T=6(%BQIDFQB$V(8WB^]X.W>%WQ^[?_S'5,Z']\%]YU]IN#/KT/8[ZO^6?
M_B=-C-=<%$BG'^4G_]S_U:)ZL*X:#(!6QN/26(Q&![W<P5_/EIF?*?])E&J>
M'BD/DO/#^6<DON__6O*<_]]@99WJQ[W&FR'NK2_-+8!U$1X;ZRZ2P"9T:HW*
D-`&ODGZZN[^$9T`,.H[!(>W@)2^*3":3.3]>`:%LBYL`#@``
`
EOF
}

sub _tarball_configure
{
  return unpack 'u', <<'EOF';
<(R$O8FEN+W-H"@IE8VAO(")H:2!T:&5R92(["@``
`
EOF
}

sub _tarball_foo_c
{
  return unpack 'u', <<'EOF';
M(VEN8VQU9&4@/'-T9&EO+F@^"@II;G0*;6%I;BAI;G0@87)G8RP@8VAA<B`J
887)G=EM=*0I["B`@<F5T=7)N(#`["GT*
`
EOF
}

sub _build_foo_o
{
  return unpack 'u', <<'EOF';
MS_KM_@<```$#`````0````0```"P`0```"`````````9````.`$`````````
M`````````````````````````&@`````````T`$```````!H``````````<`
M```'`````P````````!?7W1E>'0`````````````7U]415A4````````````
M````````````"`````````#0`0``!`````````````````0`@```````````
M`````%]?8V]M<&%C=%]U;G=I;F1?7TQ$````````````````"``````````@
M`````````-@!```#````.`(```$````````"````````````````7U]E:%]F
M<F%M90```````%]?5$585``````````````H`````````$``````````^`$`
M``,```````````````L``&@````````````````D````$``````-"@``````
M`@```!@```!``@```0```%`"```(````"P```%`````````````````````!
M`````0``````````````````````````````````````````````````````
M``````````````````!52(GE,<!=PP``````````"`````````$`````````
M````````````%``````````!>E(``7@0`1`,!PB0`0``)````!P```"X____
M_____P@``````````$$.$(8"0PT&```````````````!```&`0````\!````
/``````````!?;6%I;@``
`
EOF
}

sub _build_libfoo_a
{
  return unpack 'u', <<'EOF';
M(3QA<F-H/@HC,2\R,"`@("`@("`@("`@,34S,S$U-38Q."`@-3`Q("`@,C`@
M("`@,3`P-C0T("`T-"`@("`@("`@8`I?7RY364U$148@4T]25$5$``````@`
M````````<`````@```!?;6%I;@```",Q+S$R("`@("`@("`@("`Q-3,S,34U
M-#8X("`U,#$@("`R,"`@("`Q,#`V-#0@(#8Q,B`@("`@("!@"F9O;RYO````
M`````,_Z[?X'```!`P````$````$````L`$````@````````&0```#@!````
M``````````````````````````````!H`````````-`!````````:```````
M```'````!P````,`````````7U]T97AT`````````````%]?5$585```````
M``````````````````@`````````T`$```0````````````````$`(``````
M``````````!?7V-O;7!A8W1?=6YW:6YD7U],1`````````````````@`````
M````(`````````#8`0```P```#@"```!`````````@```````````````%]?
M96A?9G)A;64```````!?7U1%6%0`````````````*`````````!`````````
M`/@!```#```````````````+``!H````````````````)````!``````#0H`
M``````(````8````0`(```$```!0`@``"`````L```!0````````````````
M`````0````$`````````````````````````````````````````````````
M````````````````````````54B)Y3'`7<,```````````@````````!````
M`````````````````!0``````````7I2``%X$`$0#`<(D`$``"0````<````
MN/________\(``````````!!#A"&`D,-!@```````````````0``!@$````/
3`0``````````````7VUA:6X`````
`
EOF
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::Test::Mock - Mock plugin for testing

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use alienfile;
 plugin 'Test::Mock' => (
   probe    => 'share',
   download => 1,
   extract  => 1,
   build    => 1,
   gather   => 1,
 );

=head1 DESCRIPTION

This plugin is used for testing L<Alien::Build> plugins.  Usually you only want to test
one or two phases in an L<alienfile> for your plugin, but you still have to have a fully
formed L<alienfile> that contains all required phases.  This plugin lets you fill in the
other phases with the appropriate hooks.  This is usually better than using real plugins
which may pull in additional dynamic requirements that you do not want to rely on at
test time.

=head1 PROPERTIES

=head2 probe

 plugin 'Test::Mock' => (
   probe => $probe,
 );

Override the probe behavior by one of the following:

=over

=item share

For a C<share> build.

=item system

For a C<system> build.

=item die

To throw an exception in the probe hook.  This will usually cause L<Alien::Build>
to try the next probe hook, if available, or to assume a C<share> install.

=back

=head2 download

 plugin 'Test::Mock' => (
   download => \%fs_spec,
 );
 
 plugin 'Test::Mock' => (
   download => 1,
 );

Mock out a download.  The C<%fs_spec> is a hash where the hash values are directories
and the string values are files.  This a spec like this:

 plugin 'Test::Mock' => (
   download => {
     'foo-1.00' => {
       'README.txt' => "something to read",
       'foo.c' => "#include <stdio.h>\n",
                  "int main() {\n",
                  "  printf(\"hello world\\n\");\n",
                  "}\n",
     }
   },
 );

Would generate two files in the directory 'foo-1.00', a C<README.txt> and a C file named C<foo.c>.
The default, if you provide a true non-hash value is to generate a single tarball with the name
C<foo-1.00.tar.gz>.

=head2 extract

 plugin 'Test::Mock' => (
   extract => \%fs_spec,
 );
 
 plugin 'Test::Mock' => (
   extract => 1,
 );

Similar to C<download> above, but for the C<extract> phase.

=head2 build

 plugin 'Test::Mock' => (
   build => [ \%fs_spec_build, \%fs_spec_install ],
 );
 
 plugin 'Test::Mock' => (
   build => 1,
 );

=head2 gather

 plugin 'Test::Mock' => (
   gather => \%runtime_prop,
 );
 
 plugin 'Test::Mock' => (
   gather => 1,
 );

This adds a gather hook (for both C<share> and C<system>) that adds the given runtime properties, or
if a true non-hash value is provided, some reasonable runtime properties for testing.

=head2 check_digest

 plugin 'Test::Mock' => (
   check_digest => 1,  # the default
 );

This adds a check_digest hook that uses fake algorithm FAKE that hashes everything to C<deadbeaf>.
The mock download above will set the digest for download_details so that this will pass the
signature check.

 plugin 'Test::Mock' => (
   check_digest => sub {
     my($build, $file, $algo, $digest) = @_;
     ...
   },
 );

If you give it a code reference then you can write your own faux digest.  See the
L<check_digest hook|Alien::Build::Manual::PluginAuthor/"check_digest hook"> in
L<Alien::Build::Manual::PluginAuthor> for details.

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK7N%[�[�		$perl5/Alien/Build/Plugin/Extract.podnu��6�$# PODNAME: Alien::Build::Plugin::Extract
# ABSTRACT: Extract Alien::Build plugins
# VERSION

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::Extract - Extract Alien::Build plugins

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use alienfile
 share {
   plugin 'Extract' => 'tar.gz';
 };

=head1 DESCRIPTION

Extract plugins extract packages that have been downloaded from the internet.
Unless you are doing something unusual you will likely want to use the
L<Alien::Build::Plugin::Extract::Negotiate> plugin to select the best
Extract plugin available.

=over 4

=item L<Alien::Build::Plugin::Extract::ArchiveTar>

Extract using C<tar>.  Typically also works with compressed tarballs like C<tar.gz>.

=item L<Alien::Build::Plugin::Extract::ArchiveZip>

Extract using L<Archive::Zip>.

=item L<Alien::Build::Plugin::Extract::CommandLine>

Extract using command line tools like C<tar> or C<unxip>.

=item L<Alien::Build::Plugin::Extract::Directory>

Extract a local directory.

=item L<Alien::Build::Plugin::Extract::File>

"Extract" a single file.

=item L<Alien::Build::Plugin::Extract::Negotiate>

Pick the best extract plugin based on the extension of the package archive.

=back

=head1 SEE ALSO

L<Alien::Build>, L<Alien::Build::Plugin>

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK7N%[�QM:��#perl5/Alien/Build/Plugin/Gather.podnu��6�$# PODNAME: Alien::Build::Plugin::Gather
# ABSTRACT: Gather Alien::Build plugins
# VERSION

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::Gather - Gather Alien::Build plugins

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use alienfile;
 plugin 'Gather::IsolateDynamic';  # just as an example

=head1 DESCRIPTION

Gather plugins enhance L<alienfile> recipes at the gather stage, either
during a C<system> or C<share> install.

=over 4

=item L<Alien::Build::Plugin::Gather::IsolateDynamic>

Isolate dynamic libraries (C<.so>, <.DLL> or <.dylib>) so that they aren't used
by XS.

=back

=head1 SEE ALSO

L<Alien::Build>, L<Alien::Build::Plugin>

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK7N%[�*�)��&perl5/Alien/Build/Plugin/PkgConfig.podnu��6�$# PODNAME: Alien::Build::Plugin::PkgConfig
# ABSTRACT: PkgConfig Alien::Build plugins
# VERSION

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::PkgConfig - PkgConfig Alien::Build plugins

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use alienfile;
 plugin 'PkgConfig' => (
   pkg_name => 'foo',
 );

=head1 DESCRIPTION

PkgConfig plugins use C<pkg-config> or a compatible library to retrieve flags
at probe and gather stages.

=over 4

=item L<Alien::Build::Plugin::PkgConfig::CommandLine>

Use the command-line C<pkg-config> or C<pkgconf> to get compiler and linker flags.

=item L<Alien::Build::Plugin::PkgConfig::LibPkgConf>

Use the XS L<PkgConfig::LibPkgConf> to get compiler and linker flags.

=item L<Alien::Build::Plugin::PkgConfig::MakeStatic>

Convert .pc file to use static linkage by default.

=item L<Alien::Build::Plugin::PkgConfig::MakeStatic>

Choose the best plugin to do C<pkg-config> work.  The best choice is typically
platform and configuration dependent.

=item L<Alien::Build::Plugin::PkgConfig::PP>

Use the pure-perl L<PkgConfig> to get compiler and linker flags.

=back

=head1 SEE ALSO

L<Alien::Build>, L<Alien::Build::Plugin>

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK7N%[M��(__-perl5/Alien/Build/Plugin/Extract/Negotiate.pmnu��6�$package Alien::Build::Plugin::Extract::Negotiate;

use strict;
use warnings;
use 5.008004;
use Alien::Build::Plugin;
use Alien::Build::Plugin::Extract::ArchiveTar;
use Alien::Build::Plugin::Extract::ArchiveZip;
use Alien::Build::Plugin::Extract::CommandLine;
use Alien::Build::Plugin::Extract::Directory;

# ABSTRACT: Extraction negotiation plugin
our $VERSION = '2.84'; # VERSION


has '+format' => 'tar';

sub init
{
  my($self, $meta) = @_;

  my $format = $self->format;
  $format = 'tar.gz'  if $format eq 'tgz';
  $format = 'tar.bz2' if $format eq 'tbz';
  $format = 'tar.xz'  if $format eq 'txz';

  my $plugin = $self->pick($format);
  $meta->apply_plugin($plugin, format => $format);
  $self;
}


sub pick
{
  my(undef, $format) = @_;

  if($format =~ /^tar(\.(gz|bz2))?$/)
  {
    if(Alien::Build::Plugin::Extract::ArchiveTar->available($format))
    {
      return 'Extract::ArchiveTar';
    }
    else
    {
      return 'Extract::CommandLine';
    }
  }
  elsif($format eq 'zip')
  {
    # Archive::Zip is not that reliable.  But if it is already installed it is probably working
    if(Alien::Build::Plugin::Extract::ArchiveZip->available($format))
    {
      return 'Extract::ArchiveZip';
    }

    # If it isn't available, then use the command-line unzip.  Alien::unzip will be used
    # as necessary in environments where it isn't already installed.
    else
    {
      return 'Extract::CommandLine';
    }
  }
  elsif($format eq 'tar.xz')
  {
    # The windows version of tar.exe (which is based on BSD tar) will try to use external
    # program xz to decompress tar.xz files if it is available.  The default windows
    # install does not have this in the PATH, but if it IS in the PATH then it often
    # or always can hang, so the pure Perl Archive::Tar is more reliable on that platform,
    # but will require a newer version of Archive::Tar and IO::Uncompress::UnXz
    if(Alien::Build::Plugin::Extract::ArchiveTar->available('tar.xz') || $^O eq 'MSWin32')
    {
      return 'Extract::ArchiveTar';
    }
    else
    {
      return 'Extract::CommandLine';
    }
  }
  elsif($format eq 'tar.Z')
  {
    return 'Extract::CommandLine';
  }
  elsif($format eq 'd')
  {
    return 'Extract::Directory';
  }
  elsif($format eq 'f')
  {
    return 'Extract::File';
  }
  else
  {
    die "do not know how to handle format: $format";
  }
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::Extract::Negotiate - Extraction negotiation plugin

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use alienfile;
 plugin 'Extract' => (
   format => 'tar.gz',
 );

=head1 DESCRIPTION

This is a negotiator plugin for extracting packages downloaded from the internet.
This plugin picks the best Extract plugin to do the actual work.  Which plugins are
picked depend on the properties you specify, your platform and environment.  It is
usually preferable to use a negotiator plugin rather than using a specific Extract
Plugin from your L<alienfile>.

=head1 PROPERTIES

=head2 format

The expected format for the download.  Possible values include:
C<tar>, C<tar.gz>, C<tar.bz2>, C<tar.xz>, C<zip>, C<d>.

=head1 METHODS

=head2 pick

 my $name = Alien::Build::Plugin::Extract::Negotiate->pick($format);

Returns the name of the best plugin for the given format.

=head1 SEE ALSO

L<Alien::Build>, L<alienfile>, L<Alien::Build::MM>, L<Alien>

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK7N%[�u�xx.perl5/Alien/Build/Plugin/Extract/ArchiveZip.pmnu��6�$package Alien::Build::Plugin::Extract::ArchiveZip;

use strict;
use warnings;
use 5.008004;
use Alien::Build::Plugin;

# ABSTRACT: Plugin to extract a tarball using Archive::Zip
our $VERSION = '2.84'; # VERSION


has '+format' => 'zip';


sub handles
{
  my($class, $ext) = @_;

  return 1 if $ext eq 'zip';

  return 0;
}


sub available
{
  my(undef, $ext) = @_;

  !! ( $ext eq 'zip' && eval { require Archive::Zip; 1} );
}

sub init
{
  my($self, $meta) = @_;

  $meta->add_requires('share' => 'Archive::Zip' => 0);

  $meta->register_hook(
    extract => sub {
      my($build, $src) = @_;
      my $zip = Archive::Zip->new;
      $zip->read($src);
      $zip->extractTree;
    }
  );
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::Extract::ArchiveZip - Plugin to extract a tarball using Archive::Zip

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use alienfile;
 plugin 'Extract::ArchiveZip' => (
   format => 'zip',
 );

=head1 DESCRIPTION

Note: in most case you will want to use L<Alien::Build::Plugin::Extract::Negotiate>
instead.  It picks the appropriate Extract plugin based on your platform and environment.
In some cases you may need to use this plugin directly instead.

B<Note>: Seriously do NOT use this plugin! L<Archive::Zip> is pretty unreliable and
breaks all-the-time.  If you use the negotiator plugin mentioned above, then it will
prefer installing L<Alien::unzip>, which is much more reliable than L<Archive::Zip>.

This plugin extracts from an archive in zip format using L<Archive::Zip>.

=head2 format

Gives a hint as to the expected format.  This should always be C<zip>.

=head1 METHODS

=head2 handles

 Alien::Build::Plugin::Extract::ArchiveZip->handles($ext);
 $plugin->handles($ext);

Returns true if the plugin is able to handle the archive of the
given format.

=head2 available

 Alien::Build::Plugin::Extract::ArchiveZip->available($ext);

Returns true if the plugin has what it needs right now to extract from the given format

=head1 SEE ALSO

L<Alien::Build::Plugin::Extract::Negotiate>, L<Alien::Build>, L<alienfile>, L<Alien::Build::MM>, L<Alien>

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK7N%[�4��
�
-perl5/Alien/Build/Plugin/Extract/Directory.pmnu��6�$package Alien::Build::Plugin::Extract::Directory;

use strict;
use warnings;
use 5.008004;
use Alien::Build::Plugin;
use Alien::Build::Util qw( _mirror );
use Path::Tiny ();

# ABSTRACT: Plugin to extract a downloaded directory to a build directory
our $VERSION = '2.84'; # VERSION


has '+format' => 'd';


sub handles
{
  my(undef, $ext) = @_;
  $ext eq 'd' ? 1 : ();
}


sub available
{
  my(undef, $ext) = @_;
  __PACKAGE__->handles($ext);
}

sub init
{
  my($self, $meta) = @_;

  $meta->register_hook(
    extract => sub {
      my($build, $src) = @_;

      die "not a directory: $src" unless -d $src;

      if($build->meta_prop->{out_of_source})
      {
        $build->install_prop->{extract} = Path::Tiny->new($src)->absolute->stringify;
      }
      else
      {
        my $dst = Path::Tiny->new('.')->absolute;
        # Please note: _mirror and Alien::Build::Util are ONLY
        # allowed to be used by core plugins.  If you are writing
        # a non-core plugin it may be removed.  That is why it
        # is private.
        _mirror $src => $dst, { verbose => 1 };
      }
    }
  );
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::Extract::Directory - Plugin to extract a downloaded directory to a build directory

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use alienfile;
 plugin 'Extract::Directory';

=head1 DESCRIPTION

Some Download or Fetch plugins may produce a directory instead of an archive
file.  This plugin is used to mirror the directory from the Download step
into a fresh directory in the Extract step.  An example of when you might use
this plugin is if you were using the C<git> command in the Download step,
which results in a directory hierarchy.

=head1 PROPERTIES

=head2 format

Should always set to C<d> (for directories).

=head1 METHODS

=head2 handles

 Alien::Build::Plugin::Extract::Directory->handles($ext);
 $plugin->handles($ext);

Returns true if the plugin is able to handle the archive of the
given format.  Only returns true for C<d> (for directory).

=head2 available

 Alien::Build::Plugin::Extract::Directory->available($ext);
 $plugin->available($ext);

Returns true if the plugin can extract the given format with
what is already installed.

=head1 SEE ALSO

L<Alien::Build::Plugin::Extract::Negotiate>, L<Alien::Build::Plugin::Extract::File>, L<Alien::Build>, L<alienfile>, L<Alien::Build::MM>, L<Alien>

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK7N%[�.�i��(perl5/Alien/Build/Plugin/Extract/File.pmnu��6�$package Alien::Build::Plugin::Extract::File;

use strict;
use warnings;
use 5.008004;
use Alien::Build::Plugin;
use Alien::Build::Util qw( _mirror );
use Path::Tiny ();

# ABSTRACT: Plugin to extract a downloaded file to a build directory
our $VERSION = '2.84'; # VERSION


has '+format' => 'f';


sub handles
{
  my(undef, $ext) = @_;
  $ext eq 'f' ? 1 : ();
}


sub available
{
  my(undef, $ext) = @_;
  __PACKAGE__->handles($ext);
}

sub init
{
  my($self, $meta) = @_;

  $meta->register_hook(
    extract => sub {
      my($build, $src) = @_;

      die "not a file: $src" unless -f $src;

      $src = Path::Tiny->new($src)->absolute->parent;;

      my $dst = Path::Tiny->new('.')->absolute;
      # Please note: _mirror and Alien::Build::Util are ONLY
      # allowed to be used by core plugins.  If you are writing
      # a non-core plugin it may be removed.  That is why it
      # is private.

      $build->log("extracting $src => $dst");
      _mirror $src => $dst, { verbose => 1 };
    }
  );
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::Extract::File - Plugin to extract a downloaded file to a build directory

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use alienfile;
 plugin 'Extract::File';

=head1 DESCRIPTION

Some Download or Fetch plugins may produce a single file (usually an executable)
instead of an archive file.  This plugin is used to mirror the file from
the Download step into a fresh directory in the Extract step.

=head1 PROPERTIES

=head2 format

Should always set to C<f> (for file).

=head1 METHODS

=head2 handles

 Alien::Build::Plugin::Extract::File->handles($ext);
 $plugin->handles($ext);

Returns true if the plugin is able to handle the archive of the
given format.  Only returns true for C<f> (for file).

=head2 available

 Alien::Build::Plugin::Extract::File->available($ext);
 $plugin->available($ext);

Returns true if the plugin can extract the given format with
what is already installed.

=head1 SEE ALSO

L<Alien::Build::Plugin::Extract::Negotiate>, L<Alien::Build::Plugin::Extract::File>, L<Alien::Build>, L<alienfile>, L<Alien::Build::MM>, L<Alien>

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK7N%[�Y

.perl5/Alien/Build/Plugin/Extract/ArchiveTar.pmnu��6�$package Alien::Build::Plugin::Extract::ArchiveTar;

use strict;
use warnings;
use 5.008004;
use Alien::Build::Plugin;
use File::chdir;
use File::Temp ();
use Path::Tiny ();

# ABSTRACT: Plugin to extract a tarball using Archive::Tar
our $VERSION = '2.84'; # VERSION


has '+format' => 'tar';


sub handles
{
  my(undef, $ext) = @_;

  return 1 if $ext =~ /^(tar|tar\.gz|tar\.bz2|tar\.xz|tbz|taz|txz)$/;

  return 0;
}


sub available
{
  my(undef, $ext) = @_;

  if($ext eq 'tar.gz')
  {
    return !! eval { require Archive::Tar; Archive::Tar->has_zlib_support };
  }
  elsif($ext eq 'tar.bz2')
  {
    return !! eval { require Archive::Tar; Archive::Tar->has_bzip2_support && __PACKAGE__->_can_bz2 };
  }
  elsif($ext eq 'tar.xz')
  {
    return !! eval { require Archive::Tar; Archive::Tar->has_xz_support };
  }
  else
  {
    return $ext eq 'tar';
  }
}

sub init
{
  my($self, $meta) = @_;

  $meta->add_requires('share' => 'Archive::Tar' => 0);
  if($self->format eq 'tar.gz' || $self->format eq 'tgz')
  {
    $meta->add_requires('share' => 'IO::Zlib' => 0);
  }
  elsif($self->format eq 'tar.bz2' || $self->format eq 'tbz')
  {
    $meta->add_requires('share' => 'IO::Uncompress::Bunzip2' => 0);
    $meta->add_requires('share' => 'IO::Compress::Bzip2' => 0);
  }
  elsif($self->format eq 'tar.xz' || $self->format eq 'txz')
  {
    $meta->add_requires('share' => 'Archive::Tar' => 2.34);
    $meta->add_requires('share' => 'IO::Uncompress::UnXz' => 0);
  }

  $meta->register_hook(
    extract => sub {
      my($build, $src) = @_;
      my $tar = Archive::Tar->new;
      $tar->read($src);
      $tar->extract;
    }
  );
}

sub _can_bz2
{
  # even when Archive::Tar reports that it supports bz2, I can sometimes get this error:
  # 'Cannot read enough bytes from the tar file', so lets just probe for actual support!
  my $dir = Path::Tiny->new(File::Temp::tempdir( CLEANUP => 1 ));
  eval {
    local $CWD = $dir;
    my $tarball = unpack "u", q{M0EIH.3%!62936=+(]$0``$A[D-$0`8!``7^``!!AI)Y`!```""``=!JGIH-(MT#0]0/2!**---&F@;4#0&:D;X?(6@JH(2<%'N$%3VHC-9E>S/N@"6&I*1@GNJNHCC2>$I5(<0BKR.=XBZ""HVZ;T,CV\LJ!K&*?9`#\7<D4X4)#2R/1$`};
    Path::Tiny->new('xx.tar.bz2')->spew_raw($tarball);
    require Archive::Tar;
    my $tar = Archive::Tar->new;
    $tar->read('xx.tar.bz2');
    $tar->extract;
    my $content = Path::Tiny->new('xx.txt')->slurp;
    die unless $content && $content eq "xx\n";
  };
  my $error = $@;
  $dir->remove_tree;
  !$error;
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::Extract::ArchiveTar - Plugin to extract a tarball using Archive::Tar

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use alienfile;
 plugin 'Extract::ArchiveTar' => (
   format => 'tar.gz',
 );

=head1 DESCRIPTION

Note: in most case you will want to use L<Alien::Build::Plugin::Extract::Negotiate>
instead.  It picks the appropriate Extract plugin based on your platform and environment.
In some cases you may need to use this plugin directly instead.

This plugin extracts from an archive in tarball format (optionally compressed by either
gzip or bzip2) using L<Archive::Tar>.

=head1 PROPERTIES

=head2 format

Gives a hint as to the expected format.  This helps make sure the prerequisites are set
correctly, since compressed archives require extra Perl modules to be installed.

=head1 METHODS

=head2 handles

 Alien::Build::Plugin::Extract::ArchiveTar->handles($ext);
 $plugin->handles($ext);

Returns true if the plugin is able to handle the archive of the
given format.

=head2 available

 Alien::Build::Plugin::Extract::ArchiveTar->available($ext);

Returns true if the plugin has what it needs right now to extract from the given format

=head1 SEE ALSO

L<Alien::Build::Plugin::Extract::Negotiate>, L<Alien::Build>, L<alienfile>, L<Alien::Build::MM>, L<Alien>

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK7N%[ø.�Y5Y5/perl5/Alien/Build/Plugin/Extract/CommandLine.pmnu��6�$package Alien::Build::Plugin::Extract::CommandLine;

use strict;
use warnings;
use 5.008004;
use Alien::Build::Plugin;
use Path::Tiny ();
use File::Which ();
use File::chdir;
use File::Temp qw( tempdir );
use Capture::Tiny qw( capture_merged );

# ABSTRACT: Plugin to extract an archive using command line tools
our $VERSION = '2.84'; # VERSION


has '+format' => 'tar';


sub gzip_cmd
{
  _which('gzip') ? 'gzip' : undef;
}


sub _which { scalar File::Which::which(@_) }

sub bzip2_cmd
{
  _which('bzip2') ? 'bzip2' : undef;
}


sub xz_cmd
{
  _which('xz') ? 'xz' : undef;
}


{
  my $bsd_tar;

  # Note: GNU tar can be iffy to very bad on windows, where absolute
  # paths get confused with remote tars.  We used to assume that 'tar.exe'
  # is borked on Windows, but recent versions of Windows 10 come bundled
  # with bsdtar (libarchive) named 'tar.exe', and we should definitely
  # prefer that to ptar.
  sub _windows_tar_is_bsdtar
  {
    return 1 if $^O ne 'MSWin32';
    return $bsd_tar if defined $bsd_tar;
    my($out) = capture_merged {
      system 'tar', '--version';
    };
    return $bsd_tar = $out =~ /bsdtar/ ? 1 : 0
  }
}

sub tar_cmd
{
  _which('bsdtar')
    ? 'bsdtar'
    # Slowlaris /usr/bin/tar doesn't seem to like pax global header
    # but seems to have gtar in the path by default, which is okay with it
    : $^O eq 'solaris' && _which('gtar')
      ? 'gtar'
      # See note above for Windows logic.
      : _which('tar') && _windows_tar_is_bsdtar()
        ? 'tar'
        : _which('ptar')
          ? 'ptar'
          : undef;
};


sub unzip_cmd
{
  if($^O eq 'MSWin32' && _which('tar') && _windows_tar_is_bsdtar())
  {
    (_which('tar'), 'xf');
  }
  else
  {
    _which('unzip') ? 'unzip' : undef;
  }
}

sub _run
{
  my(undef, $build, @cmd) = @_;
  $build->log("+ @cmd");
  system @cmd;
  die "execute failed" if $?;
}

sub _cp
{
  my(undef, $build, $from, $to) = @_;
  require File::Copy;
  $build->log("copy $from => $to");
  File::Copy::cp($from, $to) || die "unable to copy: $!";
}

sub _mv
{
  my(undef, $build, $from, $to) = @_;
  $build->log("move $from => $to");
  rename($from, $to) || die "unable to rename: $!";
}

sub _dcon
{
  my($self, $src) = @_;

  my $name;
  my $cmd;

  if($src =~ /\.(gz|tgz|Z|taz)$/)
  {
    $self->gzip_cmd(_which('gzip')) unless defined $self->gzip_cmd;
    if($src =~ /\.(gz|tgz)$/)
    {
      $cmd = $self->gzip_cmd unless $self->_tar_can('tar.gz');
    }
    elsif($src =~ /\.(Z|taz)$/)
    {
      $cmd = $self->gzip_cmd unless $self->_tar_can('tar.Z');
    }
  }
  elsif($src =~ /\.(bz2|tbz)$/)
  {
    $self->bzip2_cmd(_which('bzip2')) unless defined $self->bzip2_cmd;
    $cmd = $self->bzip2_cmd unless $self->_tar_can('tar.bz2');
  }
  elsif($src =~ /\.(xz|txz)$/)
  {
    $self->xz_cmd(_which('xz')) unless defined $self->xz_cmd;
    $cmd = $self->xz_cmd unless $self->_tar_can('tar.xz');
  }

  if($cmd && $src =~ /\.(gz|bz2|xz|Z)$/)
  {
    $name = $src;
    $name =~ s/\.(gz|bz2|xz|Z)$//g;
  }
  elsif($cmd && $src =~ /\.(tgz|tbz|txz|taz)$/)
  {
    $name = $src;
    $name =~ s/\.(tgz|tbz|txz|taz)$/.tar/;
  }

  ($name,$cmd);
}


sub handles
{
  my($class, $ext) = @_;

  my $self = ref $class
  ? $class
  : __PACKAGE__->new;

  $ext = 'tar.Z'   if $ext eq 'taz';
  $ext = 'tar.gz'  if $ext eq 'tgz';
  $ext = 'tar.bz2' if $ext eq 'tbz';
  $ext = 'tar.xz'  if $ext eq 'txz';

  return 1 if $ext eq 'tar.gz'  && $self->_tar_can('tar.gz');
  return 1 if $ext eq 'tar.Z'   && $self->_tar_can('tar.Z');
  return 1 if $ext eq 'tar.bz2' && $self->_tar_can('tar.bz2');
  return 1 if $ext eq 'tar.xz'  && $self->_tar_can('tar.xz');

  return 0 if $ext =~ s/\.(gz|Z)$// && (!$self->gzip_cmd);
  return 0 if $ext =~ s/\.bz2$//    && (!$self->bzip2_cmd);
  return 0 if $ext =~ s/\.xz$//     && (!$self->xz_cmd);

  return 1 if $ext eq 'tar' && $self->_tar_can('tar');
  return 1 if $ext eq 'zip' && $self->_tar_can('zip');

  return 0;
}


sub available
{
  my(undef, $ext) = @_;

  # this is actually the same as handles
  __PACKAGE__->handles($ext);
}

sub init
{
  my($self, $meta) = @_;

  if($self->format eq 'tar.xz' && !$self->handles('tar.xz'))
  {
    $meta->add_requires('share' => 'Alien::xz' => '0.06');
  }
  elsif($self->format eq 'tar.bz2' && !$self->handles('tar.bz2'))
  {
    $meta->add_requires('share' => 'Alien::Libbz2' => '0.22');
  }
  elsif($self->format =~ /^tar\.(gz|Z)$/ && !$self->handles($self->format))
  {
    $meta->add_requires('share' => 'Alien::gzip' => '0.03');
  }
  elsif($self->format eq 'zip' && !$self->handles('zip'))
  {
    $meta->add_requires('share' => 'Alien::unzip' => '0');
  }

  $meta->register_hook(
    extract => sub {
      my($build, $src) = @_;

      my($dcon_name, $dcon_cmd) = _dcon($self, $src);

      if($dcon_name)
      {
        unless($dcon_cmd)
        {
          die "unable to decompress $src";
        }
        # if we have already decompressed, then keep it.
        unless(-f $dcon_name)
        {
          # we don't use pipes, because that may not work on Windows.
          # keep the original archive, in case another extract
          # plugin needs it.  keep the decompressed archive
          # in case WE need it again.
          my $src_tmp = Path::Tiny::path($src)
            ->parent
            ->child('x'.Path::Tiny::path($src)->basename);
          my $dcon_tmp = Path::Tiny::path($dcon_name)
            ->parent
            ->child('x'.Path::Tiny::path($dcon_name)->basename);
          $self->_cp($build, $src, $src_tmp);
          $self->_run($build, $dcon_cmd, "-d", $src_tmp);
          $self->_mv($build, $dcon_tmp, $dcon_name);
        }
        $src = $dcon_name;
      }

      if($src =~ /\.zip$/i)
      {
        $self->_run($build, $self->unzip_cmd, $src);
      }
      elsif($src =~ /\.tar/ || $src =~ /(\.tgz|\.tbz|\.txz|\.taz)$/i)
      {
        $self->_run($build, $self->tar_cmd, '-xf', $src);
      }
      else
      {
        die "not sure of archive type from extension";
      }
    }
  );
}

my %tars;

sub _tar_can
{
  my($self, $ext) = @_;

  unless(%tars)
  {
    my $name = '';
    local $_; # to avoid dynamically scoped read-only $_ from upper scopes
    while(my $line = <DATA>)
    {
      if($line =~ /^\[ (.*) \]$/)
      {
        $name = $1;
      }
      else
      {
        $tars{$name} .= $line;
      }
    }

    foreach my $key (keys %tars)
    {
      $tars{$key} = unpack "u", $tars{$key};
    }
  }

  my $name = "xx.$ext";

  return 0 unless $tars{$name};

  local $CWD = tempdir( CLEANUP => 1 );

  my $cleanup = sub {
    my $save = $CWD;
    unlink $name;
    unlink 'xx.txt';
    $CWD = '..';
    rmdir $save;
  };

  Path::Tiny->new($name)->spew_raw($tars{$name});

  my @cmd = ($self->tar_cmd, 'xf', $name);
  if($ext eq 'zip')
  {
    @cmd = ($self->unzip_cmd, $name);
  }

  my(undef, $exit) = capture_merged {
    system(@cmd);
    $?;
  };

  if($exit)
  {
    $cleanup->();
    return 0;
  }

  my $content = eval { Path::Tiny->new('xx.txt')->slurp };
  $cleanup->();

  return defined $content && $content eq "xx\n";
}

1;

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::Extract::CommandLine - Plugin to extract an archive using command line tools

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use alienfile;
 plugin 'Extract::CommandLine' => (
   format => 'tar.gz',
 );

=head1 DESCRIPTION

Note: in most case you will want to use L<Alien::Build::Plugin::Extract::Negotiate>
instead.  It picks the appropriate Extract plugin based on your platform and environment.
In some cases you may need to use this plugin directly instead.

This plugin extracts from an archive in various formats using command line tools.

=head1 PROPERTIES

=head2 format

Gives a hint as to the expected format.

=head2 gzip_cmd

The C<gzip> command, if available.  C<undef> if not available.

=head2 bzip2_cmd

The C<bzip2> command, if available.  C<undef> if not available.

=head2 xz_cmd

The C<xz> command, if available.  C<undef> if not available.

=head2 tar_cmd

The C<tar> command, if available.  C<undef> if not available.

=head2 unzip_cmd

The C<unzip> command, if available.  C<undef> if not available.

=head1 METHODS

=head2 handles

 Alien::Build::Plugin::Extract::CommandLine->handles($ext);
 $plugin->handles($ext);

Returns true if the plugin is able to handle the archive of the
given format.

=head2 available

 Alien::Build::Plugin::Extract::CommandLine->available($ext);

Returns true if the plugin is available to extract without
installing anything new.

=head1 SEE ALSO

L<Alien::Build::Plugin::Extract::Negotiate>, L<Alien::Build>, L<alienfile>, L<Alien::Build::MM>, L<Alien>

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut

__DATA__

[ xx.tar ]
M>'@N='AT````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M`````````````#`P,#8T-"``,#`P-S8U(``P,#`P,C0@`#`P,#`P,#`P,#`S
M(#$S-#,U,#0S-#(R(#`Q,C<P,P`@,```````````````````````````````
M````````````````````````````````````````````````````````````
M``````````````````````````````````````````!U<W1A<@`P,&]L;&ES
M9P``````````````````````````````````<W1A9F8`````````````````
M```````````````````P,#`P,#`@`#`P,#`P,"``````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M``````````````````````!X>`H`````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
7````````````````````````````````


[ xx.tar.Z ]
M'YV0>/"XH(.'#H"#"!,J7,BPH<.'$"-*1`BCH@T:-$``J`CCAHT:&CG"D)%Q
MH\B3,T#$F$%C1@T8+6G(D`$"1@P9-V#,`%!SHL^?0(,*!5!G#ITP<DR^8<,F
MS9PS0Q<:#6/&3-2%)V&$/*GQJM>O8,.*'1I0P=BS:-.J7<NVK=NW<./*G4NW
7KMV[>//JW<NWK]^_@`,+'DRXL.'#0P$`


[ xx.tar.bz2 ]
M0EIH.3%!629365(,+ID``$A[D-$0`8!``7^``!!AI)Y`!```""``=!JGIBC3
M30&CU`]($HHTTR:`>D#0)SI*Z'R%H*J"&3@H]P@J>U$F5BMHOC`$L-"8C!(V
I"`'?*WA:(9*4U)@4)+"(V%.G]#W(_E6B'J8G]D`/Q=R13A0D%(,+ID``


[ xx.tar.gz ]
M'XL("!)'=%P``WAX+G1A<@"KJ-`KJ2AAH"DP,#`P,S%1`-'F9J9@VL`(PH<"
M8P5#8Q-C4P,38Q,C(P4#0R-S`V,&!0/:.@L"2HM+$HN`3LG/R<DL3L>M#J@L
E+0V/.1"/*,#I(0(J*K@&V@FC8!2,@E$P"@8````U:,3F``@`````


[ xx.tar.xz ]
M_3=Z6%H```3FUK1&`@`A`18```!T+^6CX`?_`&!=`#Q@M.AX.4O&N38V648.
M[J6L\\<_[3M*R;CASOTX?B.F\V:^)+G;\YY4"!4MLF9`*\N40G=O+K,J0"NF
M0VU7J%NN(A,R^DM8@/(_YGR5CAO+1CS_YNHE:,1!G%6L1\GT``"[$^?"O*"!
9`P`!?(`0````:OY*7K'$9_L"``````196@``


[ xx.zip ]
M4$L#!`H``````%5V64X:^I"B`P````,````&`!P`>'@N='AT550)``,21W1<
M$D=T7'5X"P`!!/4!```$%````'AX"E!+`0(>`PH``````%5V64X:^I"B`P``
M``,````&`!@```````$```"D@0````!X>"YT>'155`4``Q)'=%QU>`L``03U
>`0``!!0```!02P4&``````$``0!,````0P``````


PK7N%[������'perl5/Alien/Build/Plugin/Build/CMake.pmnu��6�$package Alien::Build::Plugin::Build::CMake;

use strict;
use warnings;
use 5.008004;
use Config;
use Alien::Build::Plugin;
use Capture::Tiny qw( capture );

# ABSTRACT: CMake plugin for Alien::Build
our $VERSION = '2.84'; # VERSION


sub cmake_generator
{
  if($^O eq 'MSWin32')
  {
    return 'MinGW Makefiles' if is_dmake();

    {
      my($out, $err) = capture { system $Config{make}, '/?' };
      return 'NMake Makefiles' if $out =~ /NMAKE/;
    }

    {
      my($out, $err) = capture { system $Config{make}, '--version' };
      return 'MinGW Makefiles' if $out =~ /GNU Make/;
    }

    die 'make not detected';
  }
  else
  {
    return 'Unix Makefiles';
  }
}

sub init
{
  my($self, $meta) = @_;

  $meta->prop->{destdir} = $^O eq 'MSWin32' ? 0 : 1;

  $meta->add_requires('configure' => 'Alien::Build::Plugin::Build::CMake' => '0.99');
  $meta->add_requires('share'     => 'Alien::cmake3' => '0.02');

  if(is_dmake())
  {
    # even on at least some older versions of strawberry that do not
    # use it, come with gmake in the PATH.  So to save us the effort
    # of having to install Alien::gmake lets just use that version
    # if we can find it!
    my $found_gnu_make = 0;

    foreach my $exe (qw( gmake make mingw32-make ))
    {
      my($out, $err) = capture { system $exe, '--version' };
      if($out =~ /GNU Make/)
      {
        $meta->interpolator->replace_helper('make' => sub { $exe });
        $found_gnu_make = 1;
        last;
      }
    }

    if(!$found_gnu_make)
    {
      $meta->add_requires('share' => 'Alien::gmake' => '0.20');
      $meta->interpolator->replace_helper('make' => sub { require Alien::gmake; Alien::gmake->exe });
    }
  }

  $meta->interpolator->replace_helper('cmake' => sub { require Alien::cmake3; Alien::cmake3->exe });
  $meta->interpolator->add_helper('cmake_generator' => \&cmake_generator);

  my @args = (
    -G => '%{cmake_generator}',
    '-DCMAKE_POSITION_INDEPENDENT_CODE:BOOL=true',
    '-DCMAKE_INSTALL_PREFIX:PATH=%{.install.prefix}',
    '-DCMAKE_INSTALL_LIBDIR:PATH=lib',
    '-DCMAKE_MAKE_PROGRAM:PATH=%{make}',
  );

  $meta->prop->{plugin_build_cmake}->{args} = \@args;

  $meta->default_hook(
    build => [
      ['%{cmake}', @args, '%{.install.extract}' ],
      ['%{make}' ],
      ['%{make}', 'install' ],
    ],
  );

  # TODO: handle destdir on windows ??
}

my $is_dmake;

sub is_dmake
{
  unless(defined $is_dmake)
  {
    if($^O eq 'MSWin32')
    {
      my($out, $err) = capture { system $Config{make}, '-V' };
      $is_dmake = $out =~ /dmake/ ? 1 : 0;
    }
    else
    {
      $is_dmake = 0;
    }
  }

  $is_dmake;
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::Build::CMake - CMake plugin for Alien::Build

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use alienfile;
 
 share {
   plugin 'Build::CMake';
   build [
     # this is the default build step, if you do not specify one.
     [ '%{cmake}',
         @{ meta->prop->{plugin_build_cmake}->{args} },
         # ... put extra cmake args here ...
         '%{.install.extract}'
     ],
     '%{make}',
     '%{make} install',
   ];
 };

=head1 DESCRIPTION

This plugin helps build alienized projects that use C<cmake>.
The intention is to make this a core L<Alien::Build> plugin if/when
it becomes stable enough.

This plugin provides a meta property C<plugin_build_cmake.args> which may change over time
but for the moment includes:

 -G %{cmake_generator}                          \
 -DCMAKE_POSITION_INDEPENDENT_CODE:BOOL=true    \
 -DCMAKE_INSTALL_PREFIX:PATH=%{.install.prefix} \
 -DCMAKE_INSTALL_LIBDIR:PATH=lib                \
 -DCMAKE_MAKE_PROGRAM:PATH=%{make}

This plugin supports out-of-source builds via the meta property C<out_of_source>.

=head1 METHODS

=head2 cmake_generator

Returns the C<cmake> generator according to your Perl's C<make>.

=head2 is_dmake

Returns true if your Perls C<make> appears to be C<dmake>.

=head1 HELPERS

=head2 cmake

This plugin replaces the default C<cmake> helper with the one that comes from L<Alien::cmake3>.

=head2 cmake_generator

This is the appropriate C<cmake> generator to use based on the make used by your Perl.  This is
frequently C<Unix Makefiles>.  One place where it may be different is if your Windows Perl uses
C<nmake>, which comes with Visual C++.

=head2 make

This plugin I<may> replace the default C<make> helper if the default C<make> is not supported by
C<cmake>.  This is most often an issue with older versions of Strawberry Perl which used C<dmake>.
On Perls that use C<dmake>, this plugin will search for GNU Make in the PATH, and if it can't be
found will fallback on using L<Alien::gmake>.

=head1 SEE ALSO

=over 4

=item L<Alien::Build>

=item L<Alien::Build::Plugin::Build::Autoconf>

=item L<alienfile>

=back

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK7N%[��{&��&perl5/Alien/Build/Plugin/Build/Make.pmnu��6�$package Alien::Build::Plugin::Build::Make;

use strict;
use warnings;
use 5.008004;
use Carp ();
use Capture::Tiny qw( capture );
use Alien::Build::Plugin;

# ABSTRACT: Make plugin for Alien::Build
our $VERSION = '2.84'; # VERSION


has '+make_type' => undef;

sub init
{
  my($self, $meta) = @_;

  $meta->add_requires('configure', 'Alien::Build::Plugin::Build::Make', '0.99');

  my $type = $self->make_type;

  return unless defined $type;

  $type = 'gmake' if $^O eq 'MSWin32' && $type eq 'umake';

  if($type eq 'nmake')
  {
    $meta->interpolator->replace_helper( make => sub { 'nmake' } );
  }

  elsif($type eq 'dmake')
  {
    $meta->interpolator->replace_helper( make => sub { 'dmake' } );
  }

  elsif($type eq 'gmake')
  {
    my $found = 0;
    foreach my $make (qw( gmake make mingw32-make ))
    {
      my($out, $err) = capture { system $make, '--version' };
      if($out =~ /GNU Make/)
      {
        $meta->interpolator->replace_helper( make => sub { $make } );
        $found = 1;
      }
    }
    unless($found)
    {
      $meta->add_requires('share' => 'Alien::gmake' => '0.20');
      $meta->interpolator->replace_helper('make' => sub { require Alien::gmake; Alien::gmake->exe });
    }
  }

  elsif($type eq 'umake')
  {
    # nothing
  }

  else
  {
    Carp::croak("unknown make type = ", $self->make_type);
  }
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::Build::Make - Make plugin for Alien::Build

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use alienfile;
 # For a recipe that requires GNU Make
 plugin 'Build::Make' => 'gmake';

=head1 DESCRIPTION

By default L<Alien::Build> provides a helper for the C<make> that is used by Perl and L<ExtUtils::MakeMaker> itself.
This is handy, because it is the one make that you can mostly guarantee that you will have.  Unfortunately it may be
a C<make> that isn't supported by the library or tool that you are trying to alienize.  This is mostly a problem on
Windows, where the supported C<make>s for years were Microsoft's C<nmake> and Sun's C<dmake>, which many open source
projects do not use.  This plugin will alter the L<alienfile> recipe to use a different C<make>.  It may (as in the
case of C<gmake> / L<Alien::gmake>) automatically download and install an alienized version of that C<make> if it
is not already installed.

This plugin should NOT be used with other plugins that replace the C<make> helper, like
L<Alien::Build::Plugin::Build::CMake>, L<Alien::Build::Plugin::Build::Autoconf>,
L<Alien::Build::Plugin::Build::MSYS>.  This plugin is intended instead for projects that use vanilla makefiles of
a specific type.

This plugin is for now distributed separately from L<Alien::Build>, but the intention is for it to soon become
a core plugin for L<Alien::Build>.

=head1 PROPERTIES

=head2 make_type

The make type needed by the L<alienfile> recipe:

=over 4

=item dmake

Sun's dmake.

=item gmake

GNU Make.

=item nmake

Microsoft's nmake.  It comes with Visual C++.

=item umake

Any UNIX C<make>  Usually either BSD or GNU Make.

=back

=head1 HELPERS

=head2 make

 %{make}

This plugin may change the make helper used by your L<alienfile> recipe.

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK7N%[1uNnn+perl5/Alien/Build/Plugin/Build/SearchDep.pmnu��6�$package Alien::Build::Plugin::Build::SearchDep;

use strict;
use warnings;
use 5.008004;
use Alien::Build::Plugin;
use Text::ParseWords qw( shellwords );

# ABSTRACT: Add dependencies to library and header search path
our $VERSION = '2.84'; # VERSION


has aliens => {};


has public_I => 0;
has public_l => 0;

sub init
{
  my($self, $meta) = @_;

  $meta->add_requires('configure' => 'Alien::Build::Plugin::Build::SearchDep' => '0.35');
  $meta->add_requires('share'     => 'Env::ShellWords' => 0.01);

  if($self->public_I || $self->public_l)
  {
    $meta->add_requires('configure' => 'Alien::Build::Plugin::Build::SearchDep' => '0.53');
  }

  my @aliens;
  if(ref($self->aliens) eq 'HASH')
  {
    @aliens = keys %{ $self->aliens };
    $meta->add_requires('share' => $_ => $self->aliens->{$_}) for @aliens;
  }
  else
  {
    @aliens = ref $self->aliens ? @{ $self->aliens } : ($self->aliens);
    $meta->add_requires('share' => $_ => 0) for @aliens;
  }

  $meta->around_hook(
    build => sub {
      my($orig, $build) = @_;

      local $ENV{CFLAGS}   = $ENV{CFLAGS};
      local $ENV{CXXFLAGS} = $ENV{CXXFLAGS};
      local $ENV{LDFLAGS}  = $ENV{LDFLAGS};

      tie my @CFLAGS,   'Env::ShellWords', 'CFLAGS';
      tie my @CXXFLAGS, 'Env::ShellWords', 'CXXFLAGS';
      tie my @LDFLAGS,  'Env::ShellWords', 'LDFLAGS';

      my $cflags  = $build->install_prop->{plugin_build_searchdep_cflags}  = [];
      my $ldflags = $build->install_prop->{plugin_build_searchdep_ldflags} = [];
      my $libs    = $build->install_prop->{plugin_build_searchdep_libs}    = [];

      foreach my $other (@aliens)
      {
        my $other_cflags;
        my $other_libs;
        if($other->install_type('share'))
        {
          $other_cflags = $other->cflags_static;
          $other_libs   = $other->libs_static;
        }
        else
        {
          $other_cflags = $other->cflags;
          $other_libs   = $other->libs;
        }
        unshift @$cflags,  grep /^-I/, shellwords($other_cflags);
        unshift @$ldflags, grep /^-L/, shellwords($other_libs);
        unshift @$libs,    grep /^-l/, shellwords($other_libs);
      }

      unshift @CFLAGS, @$cflags;
      unshift @CXXFLAGS, @$cflags;
      unshift @LDFLAGS, @$ldflags;

      $orig->($build);

    },
  );

  $meta->after_hook(
    gather_share => sub {
      my($build) = @_;

      $build->runtime_prop->{libs}        = '' unless defined $build->runtime_prop->{libs};
      $build->runtime_prop->{libs_static} = '' unless defined $build->runtime_prop->{libs_static};

      if($self->public_l)
      {
        $build->runtime_prop->{$_} = join(' ', _space_escape(@{ $build->install_prop->{plugin_build_searchdep_libs} })) . ' ' . $build->runtime_prop->{$_}
          for qw( libs libs_static );
      }

      $build->runtime_prop->{$_} = join(' ', _space_escape(@{ $build->install_prop->{plugin_build_searchdep_ldflags} })) . ' ' . $build->runtime_prop->{$_}
        for qw( libs libs_static );

      if($self->public_I)
      {
        $build->runtime_prop->{cflags}        = '' unless defined $build->runtime_prop->{cflags};
        $build->runtime_prop->{cflags_static} = '' unless defined $build->runtime_prop->{cflags_static};
        $build->runtime_prop->{$_} = join(' ', _space_escape(@{ $build->install_prop->{plugin_build_searchdep_cflags} })) . ' ' . $build->runtime_prop->{$_}
          for qw( cflags cflags_static );
      }
    },
  );
}

sub _space_escape
{
  map {
    my $str = $_;
    $str =~ s{(\s)}{\\$1}g;
    $str;
  } @_;
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::Build::SearchDep - Add dependencies to library and header search path

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use alienfile;
 plugin 'Build::SearchDep' => (
   aliens => [qw( Alien::Foo Alien::Bar )],
 );

=head1 DESCRIPTION

This plugin adds the other aliens as prerequisites, and adds their header and library
search path to C<CFLAGS> and C<LDFLAGS> environment variable, so that tools that use
them (like autoconf) can pick them up.

=head1 PROPERTIES

=head2 aliens

Either a list reference or hash reference of the other aliens.  If a hash reference
then the keys are the class names and the values are the versions of those classes.

=head2 public_I

Include the C<-I> flags when setting the runtime cflags property.

=head2 public_l

Include the C<-l> flags when setting the runtime libs property.

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK7N%[���%�%*perl5/Alien/Build/Plugin/Build/Autoconf.pmnu��6�$package Alien::Build::Plugin::Build::Autoconf;

use strict;
use warnings;
use 5.008004;
use Alien::Build::Plugin;
use constant _win => $^O eq 'MSWin32';
use Path::Tiny ();
use File::Temp ();

# ABSTRACT: Autoconf plugin for Alien::Build
our $VERSION = '2.84'; # VERSION


has with_pic       => 1;
has ffi            => 0;
has msys_version   => undef;
has config_site    => sub {

  my $config_site  = "# file automatically generated by @{[ __FILE__ ]}\n";
     $config_site .= ". $ENV{CONFIG_SITE}\n" if defined $ENV{CONFIG_SITE};
     $config_site .= ". $ENV{ALIEN_BUILD_SITE_CONFIG}\n" if defined $ENV{ALIEN_BUILD_SITE_CONFIG};

     # on some platforms autofools sorry I mean autotools likes to install into
     # exec_prefix/lib64 or even worse exec_prefix/lib/64 but that messes everything
     # else up so we try to nip that in the bud.
     $config_site .= "libdir='\${prefix}/lib'\n";
   $config_site;
};

sub init
{
  my($self, $meta) = @_;

  $meta->apply_plugin('Build::MSYS',
    (defined $self->msys_version ? (msys_version => $self->msys_version) : ()),
  );

  $meta->prop->{destdir} = 1;
  $meta->prop->{autoconf} = 1;

  my $intr = $meta->interpolator;

  my $set_autoconf_prefix = sub {
    my($build) = @_;
    my $prefix = $build->install_prop->{prefix};
    die "Prefix is not set.  Did you forget to run 'make alien_prefix'?"
      unless $prefix;
    if(_win)
    {
      $prefix = Path::Tiny->new($prefix)->stringify;
      $prefix =~ s!^([a-z]):!/$1!i if _win;
    }
    $build->install_prop->{autoconf_prefix} = $prefix;
  };

  $meta->before_hook(
    build_ffi => $set_autoconf_prefix,
  );

  # FFI mode undocumented for now...

  if($self->ffi)
  {
    $meta->add_requires('configure', 'Alien::Build::Plugin::Build::Autoconf' => '0.41');
    $meta->default_hook(
      build_ffi => [
        '%{configure} --enable-shared --disable-static --libdir=%{.install.autoconf_prefix}/dynamic',
        '%{make}',
        '%{make} install',
      ]
    );

    if($^O eq 'MSWin32')
    {
      # for whatever reason autohell puts the .dll files in bin, even if you
      # point --bindir somewhere else.
      $meta->after_hook(
        build_ffi => sub {
          my($build) = @_;
          my $prefix = $build->install_prop->{autoconf_prefix};
          my $bin = Path::Tiny->new($ENV{DESTDIR})->child($prefix)->child('bin');
          my $lib = Path::Tiny->new($ENV{DESTDIR})->child($prefix)->child('dynamic');
          if(-d $bin)
          {
            foreach my $from (grep { $_->basename =~ /.dll$/i } $bin->children)
            {
              $lib->mkpath;
              my $to = $lib->child($from->basename);
              $build->log("copy $from => $to");
              $from->copy($to);
            }
          }
        }
      );
    }
  }

  $meta->around_hook(
    build => sub {
      my $orig = shift;
      my $build = shift;

      $set_autoconf_prefix->($build);
      my $prefix = $build->install_prop->{autoconf_prefix};
      die "Prefix is not set.  Did you forget to run 'make alien_prefix'?"
        unless $prefix;

      local $ENV{CONFIG_SITE} = do {
        my $site_config = Path::Tiny->new(File::Temp::tempdir( CLEANUP => 1 ))->child('config.site');
        $site_config->spew($self->config_site);
        "$site_config";
      };

      $intr->replace_helper(
        configure => sub {
          my $configure;

          if($build->meta_prop->{out_of_source})
          {
            my $extract = $build->install_prop->{extract};
            $configure = _win ? "sh $extract/configure" : "$extract/configure";
          }
          else
          {
            $configure = _win ? 'sh ./configure' : './configure';
          }
          $configure .= ' --prefix=' . $prefix;
          $configure .= ' --with-pic' if $self->with_pic;
          $configure;
        }
      );

      my $ret = $orig->($build, @_);

      if(_win)
      {
        my $real_prefix = Path::Tiny->new($build->install_prop->{prefix});
        my @pkgconf_dirs;
        push @pkgconf_dirs, Path::Tiny->new($ENV{DESTDIR})->child($prefix)->child("$_/pkgconfig") for qw(lib share);

        # for any pkg-config style .pc files that are dropped, we need
        # to convert the MSYS /C/Foo style paths to C:/Foo
        for my $pkgconf_dir (@pkgconf_dirs) {
            if(-d $pkgconf_dir)
            {
              foreach my $pc_file ($pkgconf_dir->children)
              {
                $pc_file->edit(sub {s/\Q$prefix\E/$real_prefix->stringify/eg;});
              }
            }
        }
      }

      $ret;
    },
  );


  $intr->add_helper(
    configure => sub {
      my $configure = _win ? 'sh configure' : './configure';
      $configure .= ' --with-pic' if $self->with_pic;
      $configure;
    },
  );

  $meta->default_hook(
    build => [
      '%{configure} --disable-shared',
      '%{make}',
      '%{make} install',
    ]
  );

  $self;
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::Build::Autoconf - Autoconf plugin for Alien::Build

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use alienfile;
 plugin 'Build::Autoconf';

=head1 DESCRIPTION

This plugin provides some tools for building projects that use autoconf.  The main thing
this provides is a C<configure> helper, documented below and the default build stage,
which is:

 '%{configure} --disable-shared',
 '%{make}',
 '%{make} install',

On Windows, this plugin also pulls in the L<Alien::Build::Plugin::Build::MSYS> which is
required for autoconf style projects on windows.

The other thing that this plugin does is that it does a double staged C<DESTDIR> install.
The author has found this improves the overall reliability of L<Alien> modules that are
based on autoconf packages.

This plugin supports out-of-source builds (known in autoconf terms as "VPATH" builds) via
the meta property C<out_of_source>.

B<NOTE>: by itself, this plugin is only intended for use on packages that include a
C<configure> script.  For packages that expect you to use Autotools to generate a
configure script before building, you can use L<Alien::Autotools> to generate the
C<configure> script and use this plugin to run it.  For more details see the
documentation for L<Alien::Autotools>.

=head1 PROPERTIES

=head2 with_pic

Adds C<--with-pic> option when running C<configure>.  If supported by your package, it
will generate position independent code on platforms that support it.  This is required
to XS modules, and generally what you want.

autoconf normally ignores options that it does not understand, so it is usually a safe
and reasonable default to include it.  A small number of projects look like they use
autoconf, but are really an autoconf style interface with a different implementation.
They may fail if you try to provide it with options such as C<--with-pic> that they do
not recognize.  Such packages are the rationale for this property.

=head2 msys_version

The version of L<Alien::MSYS> required if it is deemed necessary.  If L<Alien::MSYS>
isn't needed (if running under Unix, or MSYS2, for example) this will do nothing.

=head2 config_site

The content for the generated C<config.site>.

=head1 HELPERS

=head2 configure

 %{configure}

The correct incantation to start an autoconf style C<configure> script on your platform.
Some reasonable default flags will be provided.

=head1 ENVIRONMENT

=over 4

=item C<SITE_CONFIG>

For a share install, this plugin needs to alter the behavior of autotools using C<site.config>.
It does this by generating a C<site.config> file on the fly, and setting the C<SITE_CONFIG>
environment variable.  In the event that you already have your own C<SITE_CONFIG> set, that
file will be sourced from the generated one, so your local defaults should still be honored,
unless it is one that needs to be changed for a share install.

In particular, the C<lib> directory must be overridden, because on some platforms dynamic libraries
will otherwise be placed in directories that L<Alien::Build> doesn't normally look in.  Since
the alienized package will be installed in a share directory, and not a system directory,
that should be fine.

=item C<ALIEN_BUILD_SITE_CONFIG>

If defined, this file will be also be sourced in the generated C<site.config>.  This allows
you to have local defaults for alien share installs only.

=back

=head1 SEE ALSO

L<Alien::Build::Plugin::Build::MSYS>, L<Alien::Build::Plugin>, L<Alien::Build>, L<Alien::Base>, L<Alien>

L<https://www.gnu.org/software/autoconf/autoconf.html>

L<https://www.gnu.org/prep/standards/html_node/DESTDIR.html>

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK7N%['��d��&perl5/Alien/Build/Plugin/Build/MSYS.pmnu��6�$package Alien::Build::Plugin::Build::MSYS;

use strict;
use warnings;
use 5.008004;
use Alien::Build::Plugin;
use File::Which ();
use Env qw( @PATH );

# ABSTRACT: MSYS plugin for Alien::Build
our $VERSION = '2.84'; # VERSION


has msys_version   => '0.07';

sub init
{
  my($self, $meta) = @_;

  if($self->msys_version ne '0.07')
  {
    $meta->add_requires('configure' => 'Alien::Build::Plugin::Build::MSYS' => '0.84');
  }

  if(_win_and_needs_msys($meta))
  {
    $meta->add_requires('share' => 'Alien::MSYS' => $self->msys_version);

    $meta->around_hook(
      $_ => sub {
        my $orig = shift;
        my $build = shift;

        local $ENV{PATH} = $ENV{PATH};
        unshift @PATH, Alien::MSYS::msys_path();

        $orig->($build, @_);
      },
    ) for qw( build build_ffi test_share test_ffi );
  }


  if($^O eq 'MSWin32')
  {
    # Most likely if we are trying to build something unix-y and
    # we are using MSYS, then we want to use the make that comes
    # with MSYS.
    $meta->interpolator->replace_helper(
      make => sub { 'make' },
    );

  }

  $self;
}

sub _win_and_needs_msys
{
  my($meta) = @_;
  # check to see if we are running on windows.
  # if we are running on windows, check to see if
  # it is MSYS2, then we can just use that.  Otherwise
  # we are probably on Strawberry, or (less likely)
  # VC Perl, in which case we will still need Alien::MSYS
  return 0 unless $^O eq 'MSWin32';
  return 0 if $meta->prop->{platform}->{system_type} eq 'windows-mingw';
  return 1;
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::Build::MSYS - MSYS plugin for Alien::Build

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use alienfile;
 plugin 'Build::MSYS';

=head1 DESCRIPTION

This plugin sets up the MSYS environment for your build on Windows.  It does
not do anything on non-windows platforms.  MSYS provides the essential tools
for building software that is normally expected in a UNIX or POSIX environment.
This like C<sh>, C<awk> and C<make>.  To provide MSYS, this plugin uses
L<Alien::MSYS>.

=head1 PROPERTIES

=head2 msys_version

The version of L<Alien::MSYS> required if it is deemed necessary.  If L<Alien::MSYS>
isn't needed (if running under Unix, or MSYS2, for example) this will do nothing.

=head1 HELPERS

=head2 make

 %{make}

On windows the default C<%{make}> helper is replace with the make that comes with
L<Alien::MSYS>.  This is almost certainly what you want, as most unix style make
projects will not build with C<nmake> or C<dmake> typically used by Perl on Windows.

=head1 SEE ALSO

L<Alien::Build::Plugin::Build::Autoconf>, L<Alien::Build::Plugin>, L<Alien::Build>, L<Alien::Base>, L<Alien>

L<http://www.mingw.org/wiki/MSYS>

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK7N%[y�ݮOO&perl5/Alien/Build/Plugin/Build/Copy.pmnu��6�$package Alien::Build::Plugin::Build::Copy;

use strict;
use warnings;
use 5.008004;
use Alien::Build::Plugin;
use Path::Tiny ();

# ABSTRACT: Copy plugin for Alien::Build
our $VERSION = '2.84'; # VERSION


sub init
{
  my($self, $meta) = @_;

  $meta->add_requires( 'configure', __PACKAGE__, 0);

  if($^O eq 'MSWin32')
  {
    $meta->register_hook(build => sub {
      my($build) = @_;
      my $stage = Path::Tiny->new($build->install_prop->{stage})->canonpath;
      $build->system(qq{xcopy . "$stage" /E});
    });
  }
  elsif($^O eq 'darwin')
  {
    # On recent macOS -pPR is the same as -aR
    # on older Mac OS X (10.5 at least) -a is not supported but -pPR is.

    # Looks like -pPR should also work on coreutils if for some reason
    # someone is using  coreutils on macOS, although there are semantic
    # differences between -pPR and -aR on coreutils, that may or may not be
    # important enough to care about.

    $meta->register_hook(build => [
      'cp -pPR * "%{.install.stage}"',
    ]);
  }
  else
  {
    # TODO: some platforms might not support -a
    # I think most platforms will support -r
    $meta->register_hook(build => [
      'cp -aR * "%{.install.stage}"',
    ]);
  }
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::Build::Copy - Copy plugin for Alien::Build

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use alienfile;
 plugin 'Build::Copy';

=head1 DESCRIPTION

This plugin copies all of the files from the source to the staging prefix.
This is mainly useful for software packages that are provided as binary
blobs.  It works on both Unix and Windows using the appropriate commands
for those platforms without having worry about the platform details in your
L<alienfile>.

If you want to filter add or remove files from what gets installed you can
use a C<before> hook.

 build {
   ...
   before 'build' => sub {
     # remove or modify files
   };
   plugin 'Build::Copy';
   ...
 };

Some packages might have binary blobs on some platforms and require build
from source on others.  In that situation you can use C<if> statements
with the appropriate logic in your L<alienfile>.

 configure {
   # normally the Build::Copy plugin will insert itself
   # as a config requires, but since it is only used
   # on some platforms, you will want to explicitly
   # require it in your alienfile in case you build your
   # alien dist on a platform that doesn't use it.
   requires 'Alien::Build::Plugin::Build::Copy';
 };
 
 build {
   ...
   if($^O eq 'linux')
   {
     start_url 'http://example.com/binary-blob-linux.tar.gz';
     plugin 'Download';
     plugin 'Extract' => 'tar.gz';
     plugin 'Build::Copy';
   }
   else
   {
     start_url 'http://example.com/source.tar.gz';
     plugin 'Download';
     plugin 'Extract' => 'tar.gz';
     plugin 'Build::Autoconf';
   }
 };

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK7N%[00����!perl5/Alien/Build/Plugin/Test.podnu��6�$# PODNAME: Alien::Build::Plugin::Test
# ABSTRACT: Probe Alien::Build plugins
# VERSION

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::Test - Probe Alien::Build plugins

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use alienfile;
 plugin 'Test::Mock' => (
   probe    => 'share',
   download => 1,
   extract  => 1,
   build    => 1,
   gather   => 1,
 );

=head1 DESCRIPTION

Test plugins are used in unit tests for L<Alien::Build> and possibly
its plugins.

=over 4

=item L<Alien::Build::Plugin::Test::Mock>

Mocks common steps in an L<alienfile>.

=back

=head1 SEE ALSO

L<Alien::Build>, L<Alien::Build::Plugin>

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK7N%[{����$�$.perl5/Alien/Build/Plugin/Download/Negotiate.pmnu��6�$package Alien::Build::Plugin::Download::Negotiate;

use strict;
use warnings;
use 5.008004;
use Alien::Build::Plugin;
use Alien::Build::Util qw( _has_ssl );
use Carp ();

# ABSTRACT: Download negotiation plugin
our $VERSION = '2.84'; # VERSION


has '+url' => undef;


has 'filter'  => undef;


has 'version' => undef;


has 'ssl'     => 0;


has 'passive' => 0;

has 'scheme'  => undef;


has 'bootstrap_ssl' => 0;


has 'prefer' => 1;


has 'decoder' => undef;


sub pick
{
  my($self) = @_;
  my($fetch, @decoders) = $self->_pick;
  if($self->decoder)
  {
    @decoders = ref $self->decoder ? @{ $self->decoder } : ($self->decoder);
  }
  ($fetch, @decoders);
}

sub _pick_decoder
{
  my($self) = @_;

  if(eval { require Mojo::DOM58; Mojo::DOM58->VERSION(1.00); 1 })
  { return "Decode::Mojo" }
  elsif(eval { require Mojo::DOM; require Mojolicious; Mojolicious->VERSION('7.00'); 1 })
  { return "Decode::Mojo" }
  elsif(eval { require HTML::LinkExtor; 1; })
  { return "Decode::HTML" }
  else
  { return "Decode::Mojo" }
}

sub _pick
{
  my($self) = @_;

  $self->scheme(
    $self->url !~ m!(ftps?|https?|file):!i
      ? 'file'
      : $self->url =~ m!^([a-z]+):!i
  ) unless defined $self->scheme;

  if($self->scheme eq 'https' || ($self->scheme eq 'http' && $self->ssl))
  {
    if($self->bootstrap_ssl && ! _has_ssl)
    {
      return (['Fetch::CurlCommand','Fetch::Wget'], __PACKAGE__->_pick_decoder);
    }
    elsif(_has_ssl)
    {
      return ('Fetch::HTTPTiny', __PACKAGE__->_pick_decoder);
    }
    #elsif(do { require Alien::Build::Plugin::Fetch::CurlCommand; Alien::Build::Plugin::Fetch::CurlCommand->protocol_ok('https') })
    #{
    #  return ('Fetch::CurlCommand', __PACKAGE__->_pick_decoder);
    #}
    else
    {
      return ('Fetch::HTTPTiny', __PACKAGE__->_pick_decoder);
    }
  }
  elsif($self->scheme eq 'http')
  {
    return ('Fetch::HTTPTiny', __PACKAGE__->_pick_decoder);
  }
  elsif($self->scheme eq 'ftp')
  {
    if($ENV{ftp_proxy} || $ENV{all_proxy})
    {
      return $self->scheme =~ /^ftps?/
        ? ('Fetch::LWP', 'Decode::DirListing', __PACKAGE__->_pick_decoder)
        : ('Fetch::LWP', __PACKAGE__->_pick_decoder);
    }
    else
    {
      return ('Fetch::NetFTP');
    }
  }
  elsif($self->scheme eq 'file')
  {
    return ('Fetch::Local');
  }
  else
  {
    die "do not know how to handle scheme @{[ $self->scheme ]} for @{[ $self->url ]}";
  }
}

sub init
{
  my($self, $meta) = @_;

  unless(defined $self->url)
  {
    if(defined $meta->prop->{start_url})
    {
      $self->url($meta->prop->{start_url});
    }
    else
    {
      Carp::croak "url is a required property unless you use the start_url directive";
    }
  }

  if($self->url =~ /^http.*github.com.*releases$/)
  {
    Alien::Build->log('!! WARNING !! WARNING !!');
    Alien::Build->log('!! WARNING !! It looks like this alien is using the regular download negotiator');
    Alien::Build->log('plugin on a GitHub release page.  This will typically not work due to changes');
    Alien::Build->log('in the way GitHub release page works now.  The Alien should instead be updated');
    Alien::Build->log('to use the Download::GitHub plugin, which uses the GitHub API to find available');
    Alien::Build->log('releases.  See: https://metacpan.org/pod/Alien::Build::Plugin::Download::GitHub');
    Alien::Build->log('!! WARNING !! WARNING !!');
  }

  $meta->add_requires('share' => 'Alien::Build::Plugin::Download::Negotiate' => '0.61')
    if $self->passive;

  $meta->prop->{plugin_download_negotiate_default_url} = $self->url;

  my($fetch, @decoders) = $self->pick;

  $fetch = [ $fetch ] unless ref $fetch;

  foreach my $fetch (@$fetch)
  {
    my @args;
    push @args, ssl => $self->ssl;
    # For historical reasons, we pass the URL into older fetch plugins, because
    # this used to be the interface.  Using start_url is now preferred!
    push @args, url => $self->url if $fetch =~ /^Fetch::(HTTPTiny|LWP|Local|LocalDir|NetFTP|CurlCommand)$/;
    push @args, passive => $self->passive if $fetch eq 'Fetch::NetFTP';
    push @args, bootstrap_ssl => $self->bootstrap_ssl if $self->bootstrap_ssl;

    $meta->apply_plugin($fetch, @args);
  }

  if($self->version)
  {
    $meta->apply_plugin($_) for @decoders;

    if(defined $self->prefer && ref($self->prefer) eq 'CODE')
    {
      $meta->add_requires('share' => 'Alien::Build::Plugin::Download::Negotiate' => '1.30');
      $meta->register_hook(
        prefer => $self->prefer,
      );
    }
    elsif($self->prefer)
    {
      $meta->apply_plugin('Prefer::SortVersions',
        (defined $self->filter ? (filter => $self->filter) : ()),
        version => $self->version,
      );
    }
    else
    {
      $meta->add_requires('share' => 'Alien::Build::Plugin::Download::Negotiate' => '1.30');
    }
  }
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::Download::Negotiate - Download negotiation plugin

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use alienfile;
 share {
   start_url 'http://ftp.gnu.org/gnu/make';
   plugin 'Download' => (
     filter => qr/^make-.*\.tar\.gz$/,
     version => qr/([0-9\.]+)/,
   );
 };

=head1 DESCRIPTION

This is a negotiator plugin for downloading packages from the internet.  This
plugin picks the best Fetch, Decode and Prefer plugins to do the actual work.
Which plugins are picked depend on the properties you specify, your platform
and environment.  It is usually preferable to use a negotiator plugin rather
than the Fetch, Decode and Prefer plugins directly from your L<alienfile>.

=head1 PROPERTIES

=head2 url

[DEPRECATED] use C<start_url> instead.

The Initial URL for your package.  This may be a directory listing (either in
HTML or ftp listing format) or the final tarball intended to be downloaded.

=head2 filter

This is a regular expression that lets you filter out files that you do not
want to consider downloading.  For example, if the directory listing contained
tarballs and readme files like this:

 foo-1.0.0.tar.gz
 foo-1.0.0.readme

You could specify a filter of C<qr/\.tar\.gz$/> to make sure only tarballs are
considered for download.

=head2 version

Regular expression to parse out the version from a filename.  The regular expression
should store the result in C<$1>.

Note: if you provide a C<version> property, this plugin will assume that you will
be downloading an initial index to select package downloads from.  Depending on
the protocol (and typically this is the case for http and HTML) that may bring in
additional dependencies.  If start_url points to a tarball or other archive directly
(without needing to do through an index selection process), it is recommended that
you not specify this property.

=head2 ssl

If your initial URL does not need SSL, but you know ahead of time that a subsequent
request will need it (for example, if your directory listing is on C<http>, but includes
links to C<https> URLs), then you can set this property to true, and the appropriate
Perl SSL modules will be loaded.

=head2 passive

If using FTP, attempt a passive mode transfer first, before trying an active mode transfer.

=head2 bootstrap_ssl

If set to true, then the download negotiator will avoid using plugins that have a dependency
on L<Net::SSLeay>, or other Perl SSL modules.  The intent for this option is to allow
OpenSSL to be alienized and be a useful optional dependency for L<Net::SSLeay>.

The implementation may improve over time, but as of this writing, this option relies on you
having a working C<curl> or C<wget> with SSL support in your C<PATH>.

=head2 prefer

How to sort candidates for selection.  This should be one of three types of values:

=over 4

=item code reference

This will be used as the prefer hook.

=item true value

Use L<Alien::Build::Plugin::Prefer::SortVersions>.

=item false value

Don't set any preference at all.  A hook must be installed, or another prefer plugin specified.

=back

=head2 decoder

Override the detected decoder.

=head1 METHODS

=head2 pick

 my($fetch, @decoders) = $plugin->pick;

Returns the fetch plugin and any optional decoders that should be used.

=head1 SEE ALSO

L<Alien::Build::Plugin::Prefer::BadVersion>, L<Alien::Build::Plugin::Prefer::GoodVersion>

L<Alien::Build>, L<alienfile>, L<Alien::Build::MM>, L<Alien>

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK7N%[�V}KK+perl5/Alien/Build/Plugin/Download/GitLab.pmnu��6�$package Alien::Build::Plugin::Download::GitLab;

use strict;
use warnings;
use 5.008004;
use Carp qw( croak );
use URI;
use JSON::PP qw( decode_json );
use URI::Escape qw( uri_escape );
use Alien::Build::Plugin;
use File::Basename qw( basename );
use Path::Tiny qw( path );

# ABSTRACT: Alien::Build plugin to download from GitLab
our $VERSION = '0.01'; # VERSION


has gitlab_host    => 'https://gitlab.com';
has gitlab_user    => undef;
has gitlab_project => undef;


has type => 'source';  # source or link


has format => 'tar.gz';


has version_from    => 'tag_name'; # tag_name or name
has convert_version => undef;
has link_name       => undef;

sub init
{
  my($self, $meta) = @_;

  croak("No gitlab_user provided") unless defined $self->gitlab_user;
  croak("No gitlab_project provided") unless defined $self->gitlab_project;
  croak("Don't set set a start_url with the Download::GitLab plugin") if defined $meta->prop->{start_url};

  $meta->add_requires('configure' => 'Alien::Build::Plugin::Download::GitLab' => 0 );

  my $url = URI->new($self->gitlab_host);
  $url->path("/api/v4/projects/@{[ uri_escape(join '/', $self->gitlab_user, $self->gitlab_project) ]}/releases");
  $meta->prop->{start_url} ||= "$url";

  $meta->apply_plugin('Download');
  $meta->apply_plugin('Extract', format => $self->format );

  # we assume that GitLab returns the releases in reverse
  # chronological order.
  $meta->register_hook(
    prefer => sub {
      my($build, $res) = @_;
      return $res;
    },
  );

  croak "type must be one of source or link" if $self->type !~ /^(source|link)$/;
  croak "version_from must be one of tag_name or name" if $self->version_from !~ /^(tag_name|name)$/;

  ## TODO insert tokens as header if possible
  ## This may help with rate limiting (or if not then don't bother)
  # curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/24/releases"

  $meta->around_hook(
    fetch => sub {
      my $orig = shift;
      my($build, $url, @the_rest) = @_;

      # only modify the response if we are using the GitLab API
      # to get the release list
      return $orig->($build, $url, @the_rest)
        if defined $url && $url ne $meta->prop->{start_url};

      my $res = $orig->($build, $url, @the_rest);

      my $res2 = {
        type => 'list',
        list => [],
      };

      $res2->{protocol} = $res->{protocol} if exists $res->{protocol};

      my $rel;
      if($res->{content})
      {
        $rel = decode_json $res->{content};
      }
      elsif($res->{path})
      {
        $rel = decode_json path($res->{path})->slurp_raw;
      }
      else
      {
        croak("malformed response object: no content or path");
      }

      foreach my $release (@$rel)
      {
        my $version = $self->version_from eq 'name' ? $release->{name} : $release->{tag_name};
        $version = $self->convert_version->($version) if $self->convert_version;

        if($self->type eq 'source')
        {
          foreach my $source (@{ $release->{assets}->{sources} })
          {
            next unless $source->{format} eq $self->format;
            my $url = URI->new($source->{url});
            my $filename = basename $url->path;
            push @{ $res2->{list} }, {
              filename => $filename,
              url      => $source->{url},
              version  => $version,
            };
          }
        }
        else # link
        {
          foreach my $link (@{ $release->{assets}->{links} })
          {
            my $url = URI->new($link->{url});
            my $filename => basename $url->path;
            if($self->link_name)
            {
              next unless $filename =~ $self->link_name;
            }
            push @{ $res2->{list} }, {
              filename => $filename,
              url      => $link->{url},
              version  => $version,
            };
          }
        }
      }

      return $res2;

    },
  );
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::Download::GitLab - Alien::Build plugin to download from GitLab

=head1 VERSION

version 0.01

=head1 SYNOPSIS

 use alienfile;
 
 plugin 'Download::GitLab' => (
   gitlab_user    => 'plicease',
   gitlab_project => 'dontpanic',
 );

=head1 DESCRIPTION

This plugin is designed for downloading assets from a GitLab instance.

=head1 PROPERTIES

=head2 gitlab_host

The host to fetch from L<https://gitlab.com> by default.

=head2 gitlab_user

The user to fetch from.

=head2 gitlab_project

The project to fetch from.

=head2 type

The asset type to fetch.  This must be one of C<source> or C<link>.

=head2 format

The expected format of the asset.  This should be one that
L<Alien::Build::Plugin::Extract::Negotiate> understands.  The
default is C<tar.gz>.

=head2 version_from

Where to compute the version from.  This should be one of
C<tag_name> or C<name>.  The default is C<tag_name>.

=head2 convert_version

This is an optional code reference, which can be used to modify
the version.  For example, if tags have a C<v> prefix you could
remove it like so:

 plugin 'Download::GitLab' => (
   gitlab_user     => 'plicease',
   gitlab_project  => 'dontpanic',
   convert_version => sub {
     my $version = shift;
     $version =~ s/^v//;
     return $version;
   },
 );

=head2 link_name

For C<link> types, this is a regular expression that filters the
asset filenames.  For example, if there are multiple archive
formats provided, you can get just the gzip'd tarball by setting
this to C<qr/\.tar\.gz$/>.

=head1 SEE ALSO

=over 4

=item L<Alien>

=item L<Alien::Build::Plugin::Download::GitHub>

=item L<alienfile>

=item L<Alien::Build>

=back

=head1 AUTHOR

Graham Ollis <plicease@cpan.org>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2022 by Graham Ollis.

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

=cut
PK7N%[.���RR%perl5/Alien/Build/Plugin/Download.podnu��6�$# PODNAME: Alien::Build::Plugin::Download
# ABSTRACT: Download Alien::Build plugins
# VERSION

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::Download - Download Alien::Build plugins

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use alienfile
 share {
   start_url 'http://ftp.gnu.org/gnu/make';
   plugin 'Download';
 };

=head1 DESCRIPTION

Download plugins download packages from the internet.

=over 4

=item L<Alien::Build::Plugin::Download::Negotiate>

=back

=head1 SEE ALSO

L<Alien::Build>, L<Alien::Build::Plugin>

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK7N%[�15��#perl5/Alien/Build/Plugin/Prefer.podnu��6�$# PODNAME: Alien::Build::Plugin::Prefer
# ABSTRACT: Prefer Alien::Build plugins
# VERSION

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::Prefer - Prefer Alien::Build plugins

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use alienfile;
 share {
   start_url 'http://ftp.gnu.org/gnu/make';
   plugin 'Download';
 };

=head1 DESCRIPTION

Prefer plugins sort

Decode plugins decode HTML and FTP file listings.  Normally you
will want to use the L<Alien::Build::Plugin::Download::Negotiate>
plugin which will automatically load the appropriate Prefer plugins.

=over 4

=item L<Alien::Build::Plugin::Prefer::BadVersion>

Filter out known bad versions from a candidate list.

=item L<Alien::Build::Plugin::Prefer::GoodVersion>

Require specific known good versions from a candidate list.

=item L<Alien::Build::Plugin::Prefer::SortVersions>

Sort candidates by version.

=back

=head1 SEE ALSO

L<Alien::Build>, L<Alien::Build::Plugin>

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK7N%[V5�	�	#perl5/Alien/Build/Plugin/Decode.podnu��6�$# PODNAME: Alien::Build::Plugin::Decode
# ABSTRACT: Decode Alien::Build plugins
# VERSION

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::Decode - Decode Alien::Build plugins

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use alienfile;
 plugin 'Decode::HTML';
 plugin 'Decode::DirListing';

=head1 DESCRIPTION

Decode plugins decode HTML and FTP file listings.  Normally you
will want to use the L<Alien::Build::Plugin::Download::Negotiate>
plugin which will automatically load the appropriate Decode plugins.

=over 4

=item L<Alien::Build::Plugin::Decode::DirListing>

Default decoder for FTP file listings, that uses the pure-perl L<File::Listing>.

=item L<Alien::Build::Plugin::Decode::DirListingFtpcopy>

Another decoder for FTP file listings, that uses the XS module L<File::Listing::Ftpcopy>.

=item L<Alien::Build::Plugin::Decode::HTML>

Older decoder for HTML file listings, which uses the XS module L<HTML::LinkExtor>.  This
used to be the default decoder until L<Alien::Build> version 1.75.  In some cases, this
will be used as the HTML decoder if you configure with L<Alien::Build> prior to 1.75
and but upgrade to a more recent version for the build stage of your L<Alien>

=item L<Alien::Build::Plugin::Decode::Mojo>

Newer decoder for HTML file listings, which uses the pure-perl L<Mojo::DOM> or L<Mojo::DOM58>.
This became the default decoder at L<Alien::Build> version 1.75.

=back

=head1 SEE ALSO

L<Alien::Build>, L<Alien::Build::Plugin>

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK7N%[�X�"SS/perl5/Alien/Build/Plugin/PkgConfig/Negotiate.pmnu��6�$package Alien::Build::Plugin::PkgConfig::Negotiate;

use strict;
use warnings;
use 5.008004;
use Alien::Build::Plugin;
use Alien::Build::Plugin::PkgConfig::PP;
use Alien::Build::Plugin::PkgConfig::LibPkgConf;
use Alien::Build::Plugin::PkgConfig::CommandLine;
use Alien::Build::Util qw( _perl_config );
use Carp ();

# ABSTRACT: Package configuration negotiation plugin
our $VERSION = '2.84'; # VERSION


has '+pkg_name' => sub {
  Carp::croak "pkg_name is a required property";
};


has atleast_version => undef;


has exact_version => undef;


has max_version => undef;


has minimum_version => undef;


sub pick
{
  my($class) = @_;

  return $ENV{ALIEN_BUILD_PKG_CONFIG} if $ENV{ALIEN_BUILD_PKG_CONFIG};

  if(Alien::Build::Plugin::PkgConfig::LibPkgConf->available)
  {
    return 'PkgConfig::LibPkgConf';
  }

  if(Alien::Build::Plugin::PkgConfig::CommandLine->available)
  {
    # TODO: determine environment or flags necessary for using pkg-config
    # on solaris 64 bit.
    # Some advice on pkg-config and 64 bit Solaris
    # https://docs.oracle.com/cd/E53394_01/html/E61689/gplhi.html
    my $is_solaris64 = (_perl_config('osname') eq 'solaris' && _perl_config('ptrsize') == 8);

    # PkgConfig.pm is more reliable on windows
    my $is_windows = _perl_config('osname') eq 'MSWin32';

    if(!$is_solaris64 && !$is_windows)
    {
      return 'PkgConfig::CommandLine';
    }
  }

  if(Alien::Build::Plugin::PkgConfig::PP->available)
  {
    return 'PkgConfig::PP';
  }
  else
  {
    # this is a fata error.  because we check for a pkg-config implementation
    # at configure time, we expect at least one of these to work.  (and we
    # fallback on installing PkgConfig.pm as a prereq if nothing else is avail).
    # we therefore expect at least one of these to work, if not, then the configuration
    # of the system has shifted from underneath us.
    Carp::croak("Could not find an appropriate pkg-config or pkgconf implementation, please install PkgConfig.pm, PkgConfig::LibPkgConf, pkg-config or pkgconf");
  }
}

sub init
{
  my($self, $meta) = @_;

  my $plugin = $self->pick;
  Alien::Build->log("Using PkgConfig plugin: $plugin");

  if(ref($self->pkg_name) eq 'ARRAY')
  {
    $meta->add_requires('configure', 'Alien::Build::Plugin::PkgConfig::Negotiate' => '0.79');
  }

  if($self->atleast_version || $self->exact_version || $self->max_version)
  {
    $meta->add_requires('configure', 'Alien::Build::Plugin::PkgConfig::Negotiate' => '1.53');
  }

  my @args;
  push @args, pkg_name         => $self->pkg_name;
  push @args, register_prereqs => 0;

  foreach my $method (map { "${_}_version" } qw( minimum atleast exact max ))
  {
    push @args, $method => $self->$method if defined $self->$method;
  }

  $meta->apply_plugin($plugin, @args);

  $self;
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::PkgConfig::Negotiate - Package configuration negotiation plugin

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use alienfile;
 plugin 'PkgConfig' => (
   pkg_name => 'libfoo',
 );

=head1 DESCRIPTION

This plugin provides Probe and Gather steps for pkg-config based packages.  It picks
the best C<PkgConfig> plugin depending your platform and environment.

=head1 PROPERTIES

=head2 pkg_name

The package name.  If this is a list reference then .pc files with all those package
names must be present.  The first name will be the primary and used by default once
installed.  For the subsequent C<.pc> files you can use the
L<Alien::Base alt method|Alien::Base/alt> to retrieve the alternate configurations
once the L<Alien> is installed.

=head2 atleast_version

The minimum required version that is acceptable version as provided by the system.

=head2 exact_version

The exact required version that is acceptable version as provided by the system.

=head2 max_version

The max required version that is acceptable version as provided by the system.

=head2 minimum_version

Alias for C<atleast_version> for backward compatibility.

=head1 METHODS

=head2 pick

 my $name = Alien::Build::Plugin::PkgConfig::Negotiate->pick;

Returns the name of the negotiated plugin.

=head1 ENVIRONMENT

=over 4

=item ALIEN_BUILD_PKG_CONFIG

If set, this plugin will be used instead of the build in logic
which attempts to automatically pick the best plugin.

=back

=head1 SEE ALSO

L<Alien::Build>, L<alienfile>, L<Alien::Build::MM>, L<Alien>

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK8N%[�x¹cc(perl5/Alien/Build/Plugin/PkgConfig/PP.pmnu��6�$package Alien::Build::Plugin::PkgConfig::PP;

use strict;
use warnings;
use 5.008004;
use Alien::Build::Plugin;
use Carp ();
use File::Which ();
use Env qw( @PKG_CONFIG_PATH );

# ABSTRACT: Probe system and determine library or tool properties using PkgConfig.pm
our $VERSION = '2.84'; # VERSION


has '+pkg_name' => sub {
  Carp::croak "pkg_name is a required property";
};


has atleast_version => undef;


has exact_version => undef;


has max_version => undef;


has minimum_version => undef;


use constant _min_version => '0.14026';

# private for now, used by negotiator
has register_prereqs => 1;

sub available
{
  !!eval { require PkgConfig; PkgConfig->VERSION(_min_version) };
}

sub _cleanup
{
  my($value) = @_;
  $value =~ s{\s*$}{ };
  $value;
}

sub init
{
  my($self, $meta) = @_;

  unless(defined $meta->prop->{env}->{PKG_CONFIG})
  {
    # TODO: Better would be to to "execute" lib/PkgConfig.pm
    # as that should always be available, and will match the
    # exact version of PkgConfig.pm that we are using here.
    # there are a few corner cases to deal with before we
    # can do this.  What is here should handle most use cases.
    my $command_line =
      File::Which::which('ppkg-config')
      ? 'ppkg-config'
      : File::Which::which('pkg-config.pl')
        ? 'pkg-config.pl'
        : File::Which::which('pkg-config')
          ? 'pkg-config'
          : undef;
    $meta->prop->{env}->{PKG_CONFIG} = $command_line
      if defined $command_line;
  }

  if($self->register_prereqs)
  {
    $meta->add_requires('configure' => 'PkgConfig' => _min_version);
  }

  my($pkg_name, @alt_names) = (ref $self->pkg_name) ? (@{ $self->pkg_name }) : ($self->pkg_name);

  $meta->register_hook(
    probe => sub {
      my($build) = @_;

      $build->runtime_prop->{legacy}->{name} ||= $pkg_name;
      $build->hook_prop->{probe_class} = __PACKAGE__;
      $build->hook_prop->{probe_instance_id} = $self->instance_id;

      require PkgConfig;
      my $pkg = PkgConfig->find($pkg_name);
      die "package @{[ $pkg_name ]} not found" if $pkg->errmsg;

      $build->hook_prop->{version} = $pkg->pkg_version;
      my $version = PkgConfig::Version->new($pkg->pkg_version);

      my $atleast_version = $self->atleast_version;
      $atleast_version = $self->minimum_version unless defined $atleast_version;
      if(defined $atleast_version)
      {
        my $need    = PkgConfig::Version->new($atleast_version);
        if($version < $need)
        {
          die "package @{[ $pkg_name ]} is @{[ $pkg->pkg_version ]}, but at least $atleast_version is required.";
        }
      }

      if(defined $self->exact_version)
      {
        my $need = PkgConfig::Version->new($self->exact_version);
        if($version != $need)
        {
          die "package @{[ $pkg_name ]} is @{[ $pkg->pkg_version ]}, but exactly @{[ $self->exact_version ]} is required.";
        }
      }

      if(defined $self->max_version)
      {
        my $need = PkgConfig::Version->new($self->max_version);
        if($version > $need)
        {
          die "package @{[ $pkg_name ]} is @{[ $pkg->pkg_version ]}, but max of @{[ $self->max_version ]} is required.";
        }
      }

      foreach my $alt (@alt_names)
      {
        my $pkg = PkgConfig->find($alt);
        die "package $alt not found" if $pkg->errmsg;
      }

      'system';
    },
  );

  $meta->register_hook(
    $_ => sub {
      my($build) = @_;

      return if $build->hook_prop->{name} eq 'gather_system'
      &&        ($build->install_prop->{system_probe_instance_id} || '') ne $self->instance_id;

      require PkgConfig;

      foreach my $name ($pkg_name, @alt_names)
      {
        require PkgConfig;
        my $pkg = PkgConfig->find($name, search_path => [@PKG_CONFIG_PATH]);
        if($pkg->errmsg)
        {
          $build->log("Trying to load the pkg-config information from the source code build");
          $build->log("of your package failed");
          $build->log("You are currently using the pure-perl implementation of pkg-config");
          $build->log("(AB Plugin is named PkgConfig::PP, which uses PkgConfig.pm");
          $build->log("It may work better with the real pkg-config.");
          $build->log("Try installing your OS' version of pkg-config or unset ALIEN_BUILD_PKG_CONFIG");
          die "second load of PkgConfig.pm @{[ $name ]} failed: @{[ $pkg->errmsg ]}"
        }
        my %prop;
        $prop{cflags}  = _cleanup scalar $pkg->get_cflags;
        $prop{libs}    = _cleanup scalar $pkg->get_ldflags;
        $prop{version} = $pkg->pkg_version;
        $pkg = PkgConfig->find($name, static => 1, search_path => [@PKG_CONFIG_PATH]);
        $prop{cflags_static} = _cleanup scalar $pkg->get_cflags;
        $prop{libs_static}   = _cleanup scalar $pkg->get_ldflags;
        $build->runtime_prop->{alt}->{$name} = \%prop;
      }
      foreach my $key (keys %{ $build->runtime_prop->{alt}->{$pkg_name} })
      {
        $build->runtime_prop->{$key} = $build->runtime_prop->{alt}->{$pkg_name}->{$key};
      }
      if(keys %{ $build->runtime_prop->{alt} } == 1)
      {
        delete $build->runtime_prop->{alt};
      }
    }
  ) for qw( gather_system gather_share );

  $self;
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::PkgConfig::PP - Probe system and determine library or tool properties using PkgConfig.pm

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use alienfile;
 plugin 'PkgConfig::PP' => (
   pkg_name => 'libfoo',
 );

=head1 DESCRIPTION

Note: in most case you will want to use L<Alien::Build::Plugin::PkgConfig::Negotiate>
instead.  It picks the appropriate fetch plugin based on your platform and environment.
In some cases you may need to use this plugin directly instead.

This plugin provides Probe and Gather steps for pkg-config based packages.  It uses
L<PkgConfig> to accomplish this task.

=head1 PROPERTIES

=head2 pkg_name

The package name.  If this is a list reference then .pc files with all those package
names must be present.  The first name will be the primary and used by default once
installed.  For the subsequent C<.pc> files you can use the
L<Alien::Base alt method|Alien::Base/alt> to retrieve the alternate configurations
once the L<Alien> is installed.

=head2 atleast_version

The minimum required version that is acceptable version as provided by the system.

=head2 exact_version

The exact required version that is acceptable version as provided by the system.

=head2 max_version

The max required version that is acceptable version as provided by the system.

=head2 minimum_version

Alias for C<atleast_version> for backward compatibility.

=head1 METHODS

=head2 available

 my $bool = Alien::Build::Plugin::PkgConfig::PP->available;

Returns true if the necessary prereqs for this plugin are I<already> installed.

=head1 SEE ALSO

L<Alien::Build::Plugin::PkgConfig::Negotiate>, L<Alien::Build>, L<alienfile>, L<Alien::Build::MM>, L<Alien>

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK8N%[�����0perl5/Alien/Build/Plugin/PkgConfig/LibPkgConf.pmnu��6�$package Alien::Build::Plugin::PkgConfig::LibPkgConf;

use strict;
use warnings;
use 5.008004;
use Alien::Build::Plugin;
use Carp ();

# ABSTRACT: Probe system and determine library or tool properties using PkgConfig::LibPkgConf
our $VERSION = '2.84'; # VERSION


has '+pkg_name' => sub {
  Carp::croak "pkg_name is a required property";
};


has atleast_version => undef;


has exact_version => undef;


has max_version => undef;


has minimum_version => undef;

# private for now, used by negotiator
has register_prereqs => 1;


use constant _min_version => '0.04';

sub available
{
  !!eval { require PkgConfig::LibPkgConf; PkgConfig::LibPkgConf->VERSION(_min_version) };
}

sub init
{
  my($self, $meta) = @_;

  unless(defined $meta->prop->{env}->{PKG_CONFIG})
  {
    # TODO: this doesn't yet find pkgconf in the bin dir of a share
    # install.
    my $command_line =
      File::Which::which('pkgconf')
      ? 'pkgconf'
      : File::Which::which('pkg-config')
        ? 'pkg-config'
        : undef;
    $meta->prop->{env}->{PKG_CONFIG} = $command_line
      if defined $command_line;
  }

  if($self->register_prereqs)
  {
    # Also update in Neotiate.pm
    $meta->add_requires('configure' => 'PkgConfig::LibPkgConf::Client' => _min_version);

    if(defined $self->minimum_version || defined $self->atleast_version || defined $self->exact_version || defined $self->max_version)
    {
      $meta->add_requires('configure' => 'PkgConfig::LibPkgConf::Util' => _min_version);
    }
  }

  my($pkg_name, @alt_names) = (ref $self->pkg_name) ? (@{ $self->pkg_name }) : ($self->pkg_name);

  $meta->register_hook(
    probe => sub {
      my($build) = @_;
      $build->runtime_prop->{legacy}->{name} ||= $pkg_name;

      $build->hook_prop->{probe_class} = __PACKAGE__;
      $build->hook_prop->{probe_instance_id} = $self->instance_id;

      require PkgConfig::LibPkgConf::Client;
      my $client = PkgConfig::LibPkgConf::Client->new;
      my $pkg = $client->find($pkg_name);
      die "package $pkg_name not found" unless $pkg;

      $build->hook_prop->{version} = $pkg->version;
      my $atleast_version = $self->atleast_version;
      $atleast_version = $self->minimum_version unless defined $self->atleast_version;
      if($atleast_version)
      {
        require PkgConfig::LibPkgConf::Util;
        if(PkgConfig::LibPkgConf::Util::compare_version($pkg->version, $atleast_version) < 0)
        {
          die "package $pkg_name is version @{[ $pkg->version ]}, but at least $atleast_version is required.";
        }
      }

      if($self->exact_version)
      {
        require PkgConfig::LibPkgConf::Util;
        if(PkgConfig::LibPkgConf::Util::compare_version($pkg->version, $self->exact_version) != 0)
        {
          die "package $pkg_name is version @{[ $pkg->version ]}, but exactly @{[ $self->exact_version ]} is required.";
        }
      }

      if($self->max_version)
      {
        require PkgConfig::LibPkgConf::Util;
        if(PkgConfig::LibPkgConf::Util::compare_version($pkg->version, $self->max_version) > 0)
        {
          die "package $pkg_name is version @{[ $pkg->version ]}, but max @{[ $self->max_version ]} is required.";
        }
      }

      foreach my $alt (@alt_names)
      {
        my $pkg = $client->find($alt);
        die "package $alt not found" unless $pkg;
      }

      'system';
    },
  );

  $meta->register_hook(
    $_ => sub {
      my($build) = @_;

      return if $build->hook_prop->{name} eq 'gather_system'
      &&        ($build->install_prop->{system_probe_instance_id} || '') ne $self->instance_id;

      require PkgConfig::LibPkgConf::Client;
      my $client = PkgConfig::LibPkgConf::Client->new;

      foreach my $name ($pkg_name, @alt_names)
      {
        my $pkg = $client->find($name);
        die "reload of package $name failed" unless defined $pkg;

        my %prop;
        $prop{version}        = $pkg->version;
        $prop{cflags}         = $pkg->cflags;
        $prop{libs}           = $pkg->libs;
        $prop{cflags_static}  = $pkg->cflags_static;
        $prop{libs_static}    = $pkg->libs_static;
        $build->runtime_prop->{alt}->{$name} = \%prop;
      }

      foreach my $key (keys %{ $build->runtime_prop->{alt}->{$pkg_name} })
      {
        $build->runtime_prop->{$key} = $build->runtime_prop->{alt}->{$pkg_name}->{$key};
      }

      if(keys %{ $build->runtime_prop->{alt} } == 1)
      {
        delete $build->runtime_prop->{alt};
      }
    },
  ) for qw( gather_system gather_share );

  $self;
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::PkgConfig::LibPkgConf - Probe system and determine library or tool properties using PkgConfig::LibPkgConf

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use alienfile;
 plugin 'PkgConfig::LibPkgConf' => (
   pkg_name => 'libfoo',
 );

=head1 DESCRIPTION

Note: in most case you will want to use L<Alien::Build::Plugin::PkgConfig::Negotiate>
instead.  It picks the appropriate fetch plugin based on your platform and environment.
In some cases you may need to use this plugin directly instead.

This plugin provides Probe and Gather steps for pkg-config based packages.  It uses
L<PkgConfig::LibPkgConf> to accomplish this task.

This plugin is part of the Alien::Build core For Now, but may be removed in a future
date.  While It Seemed Like A Good Idea at the time, it may not be appropriate to keep
it in core.  If it is spun off it will get its own distribution some time in the future.

=head1 PROPERTIES

=head2 pkg_name

The package name.  If this is a list reference then .pc files with all those package
names must be present.  The first name will be the primary and used by default once
installed.  For the subsequent C<.pc> files you can use the
L<Alien::Base alt method|Alien::Base/alt> to retrieve the alternate configurations
once the L<Alien> is installed.

=head2 atleast_version

The minimum required version that is acceptable version as provided by the system.

=head2 exact_version

The exact required version that is acceptable version as provided by the system.

=head2 max_version

The max required version that is acceptable version as provided by the system.

=head2 minimum_version

Alias for C<atleast_version> for backward compatibility.

=head1 METHODS

=head2 available

 my $bool = Alien::Build::Plugin::PkgConfig::LibPkgConf->available;

Returns true if the necessary prereqs for this plugin are I<already> installed.

=head1 SEE ALSO

L<Alien::Build::Plugin::PkgConfig::Negotiate>, L<Alien::Build>, L<alienfile>, L<Alien::Build::MM>, L<Alien>

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK8N%[
l7�g
g
0perl5/Alien/Build/Plugin/PkgConfig/MakeStatic.pmnu��6�$package Alien::Build::Plugin::PkgConfig::MakeStatic;

use strict;
use warnings;
use 5.008004;
use Alien::Build::Plugin;
use Path::Tiny ();

# ABSTRACT: Convert .pc files into static
our $VERSION = '2.84'; # VERSION


has path => undef;

sub _convert
{
  my($self, $build, $path) = @_;

  die "unable to read $path" unless -r $path;
  die "unable to write $path" unless -w $path;

  $build->log("converting $path to static");

  my %h = map {
    my($key, $value) = /^(.*?):(.*?)$/;
    $value =~ s{^\s+}{};
    $value =~ s{\s+$}{};
    ($key => $value);
  } grep /^(?:Libs|Cflags)(?:\.private)?:/, $path->lines;

  $h{Cflags} = '' unless defined $h{Cflags};
  $h{Libs}   = '' unless defined $h{Libs};

  $h{Cflags} .= ' ' . $h{"Cflags.private"} if defined $h{"Cflags.private"};
  $h{Libs}   .= ' ' . $h{"Libs.private"} if defined $h{"Libs.private"};

  $h{"Cflags.private"} = '';
  $h{"Libs.private"}  = '';

  $path->edit_lines(sub {

    if(/^(.*?):/)
    {
      my $key = $1;
      if(defined $h{$key})
      {
        s/^(.*?):.*$/$1: $h{$key} /;
        delete $h{$key};
      }
    }

  });

  $path->append("$_: $h{$_}\n") foreach keys %h;
}

sub _recurse
{
  my($self, $build, $dir) = @_;

  foreach my $child ($dir->children)
  {
    if(-d $child)
    {
      $self->_recurse($build, $child);
    }
    elsif($child->basename =~ /\.pc$/)
    {
      $self->_convert($build, $child);
    }
  }
}

sub init
{
  my($self, $meta) = @_;

  $meta->add_requires('configure' => 'Alien::Build::Plugin::Build::SearchDep' => '0.35');

  $meta->before_hook(
    gather_share => sub {
      my($build) = @_;

      if($self->path)
      {
        $self->_convert($build, Path::Tiny->new($self->path)->absolute);
      }
      else
      {
        $self->_recurse($build, Path::Tiny->new(".")->absolute);
      }

    },
  );
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::PkgConfig::MakeStatic - Convert .pc files into static

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use alienfile;
 
 plugin 'PkgConfig::MakeStatic' => (
   path => 'lib/pkgconfig/foo.pc',
 );

=head1 DESCRIPTION

Convert C<.pc> file to use static linkage by default.  This is an experimental
plugin, so use with caution.

=head1 PROPERTIES

=head2 path

The path to the C<.pc> file.  If not provided, all C<.pc> files in the stage
directory will be converted.

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK8N%[�O*a��1perl5/Alien/Build/Plugin/PkgConfig/CommandLine.pmnu��6�$package Alien::Build::Plugin::PkgConfig::CommandLine;

use strict;
use warnings;
use 5.008004;
use Alien::Build::Plugin;
use Carp ();

# ABSTRACT: Probe system and determine library or tool properties using the pkg-config command line interface
our $VERSION = '2.84'; # VERSION


has '+pkg_name' => sub {
  Carp::croak "pkg_name is a required property";
};

# NOT used, for compat with other PkgConfig plugins
has register_prereqs => 1;

sub _bin_name {

  # We prefer pkgconf to pkg-config because it seems to be the future.

  require File::Which;
  File::Which::which($ENV{PKG_CONFIG})
    ? $ENV{PKG_CONFIG}
    : File::Which::which('pkgconf')
      ? 'pkgconf'
      : File::Which::which('pkg-config')
        ? 'pkg-config'
        : undef;
};

has bin_name => \&_bin_name;


has atleast_version => undef;


has exact_version => undef;


has max_version => undef;


has minimum_version => undef;

sub _val
{
  my($build, $args, $prop_name) = @_;
  my $string = $args->{out};
  chomp $string;
  $string =~ s{^\s+}{};
  if($prop_name =~ /version$/)
  { $string =~ s{\s*$}{} }
  else
  { $string =~ s{\s*$}{ } }
  if($prop_name =~ /^(.*?)\.(.*?)\.(.*?)$/)
  { $build->runtime_prop->{$1}->{$2}->{$3} = $string }
  else
  { $build->runtime_prop->{$prop_name} = $string }
  ();
}


sub available
{
  !!_bin_name();
}

sub init
{
  my($self, $meta) = @_;

  my @probe;
  my @gather;

  my $pkgconf = $self->bin_name;

  unless(defined $meta->prop->{env}->{PKG_CONFIG})
  {
    $meta->prop->{env}->{PKG_CONFIG} = $pkgconf;
  }

  my($pkg_name, @alt_names) = (ref $self->pkg_name) ? (@{ $self->pkg_name }) : ($self->pkg_name);

  push @probe, map { [$pkgconf, '--exists', $_] } ($pkg_name, @alt_names);

  if(defined $self->minimum_version)
  {
    push @probe, [ $pkgconf, '--atleast-version=' . $self->minimum_version, $pkg_name ];
  }
  elsif(defined $self->atleast_version)
  {
    push @probe, [ $pkgconf, '--atleast-version=' . $self->atleast_version, $pkg_name ];
  }

  if(defined $self->exact_version)
  {
    push @probe, [ $pkgconf, '--exact-version=' . $self->exact_version, $pkg_name ];
  }

  if(defined $self->max_version)
  {
    push @probe, [ $pkgconf, '--max-version=' . $self->max_version, $pkg_name ];
  }

  push @probe, [ $pkgconf, '--modversion', $pkg_name, sub {
    my($build, $args) = @_;
    my $version = $args->{out};
    $version =~ s{^\s+}{};
    $version =~ s{\s*$}{};
    $build->hook_prop->{version} = $version;
  }];

  unshift @probe, sub {
    my($build) = @_;
    $build->runtime_prop->{legacy}->{name} ||= $pkg_name;
    $build->hook_prop->{probe_class} = __PACKAGE__;
    $build->hook_prop->{probe_instance_id} = $self->instance_id;
  };

  $meta->register_hook(
    probe => \@probe
  );

  push @gather, sub {
    my($build) = @_;
    die 'pkg-config command line probe does not match gather' if $build->hook_prop->{name} eq 'gather_system'
    &&                                                        ($build->install_prop->{system_probe_instance_id} || '') ne $self->instance_id;
  };
  push @gather, map { [ $pkgconf, '--exists', $_] } ($pkg_name, @alt_names);

  foreach my $prop_name (qw( cflags libs version ))
  {
    my $flag = $prop_name eq 'version' ? '--modversion' : "--$prop_name";
    push @gather,
      [ $pkgconf, $flag, $pkg_name, sub { _val @_, $prop_name } ];
    if(@alt_names)
    {
      foreach my $alt ($pkg_name, @alt_names)
      {
        push @gather,
          [ $pkgconf, $flag, $alt, sub { _val @_, "alt.$alt.$prop_name" } ];
      }
    }
  }

  foreach my $prop_name (qw( cflags libs ))
  {
    push @gather,
      [ $pkgconf, '--static', "--$prop_name", $pkg_name, sub { _val @_, "${prop_name}_static" } ];
    if(@alt_names)
    {
      foreach my $alt ($pkg_name, @alt_names)
      {
        push @gather,
          [ $pkgconf, '--static', "--$prop_name", $alt, sub { _val @_, "alt.$alt.${prop_name}_static" } ];
      }
    }
  }

  $meta->register_hook(gather_system => [@gather]);

  if($meta->prop->{platform}->{system_type} eq 'windows-mingw')
  {
    @gather = map {
      if(ref $_ eq 'ARRAY') {
        my($pkgconf, @rest) = @$_;
        [$pkgconf, '--dont-define-prefix', @rest],
      } else {
        $_
      }
    } @gather;
  }

  $meta->register_hook(gather_share => [@gather]);

  $meta->after_hook(
    $_ => sub {
      my($build) = @_;
      if(keys %{ $build->runtime_prop->{alt} } < 2)
      {
        delete $build->runtime_prop->{alt};
      }
    },
  ) for qw( gather_system gather_share );

  $self;
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::PkgConfig::CommandLine - Probe system and determine library or tool properties using the pkg-config command line interface

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use alienfile;
 plugin 'PkgConfig::CommandLine' => (
   pkg_name => 'libfoo',
 );

=head1 DESCRIPTION

Note: in most case you will want to use L<Alien::Build::Plugin::PkgConfig::Negotiate>
instead.  It picks the appropriate fetch plugin based on your platform and environment.
In some cases you may need to use this plugin directly instead.

This plugin provides Probe and Gather steps for pkg-config based packages.  It uses
the best command line tools to accomplish this task.

=head1 PROPERTIES

=head2 pkg_name

The package name.  If this is a list reference then .pc files with all those package
names must be present.  The first name will be the primary and used by default once
installed.  For the subsequent C<.pc> files you can use the
L<Alien::Base alt method|Alien::Base/alt> to retrieve the alternate configurations
once the L<Alien> is installed.

=head2 atleast_version

The minimum required version that is acceptable version as provided by the system.

=head2 exact_version

The exact required version that is acceptable version as provided by the system.

=head2 max_version

The max required version that is acceptable version as provided by the system.

=head2 minimum_version

Alias for C<atleast_version> for backward compatibility.

=head1 METHODS

=head2 available

 my $bool = Alien::Build::Plugin::PkgConfig::CommandLine->available;

Returns true if the necessary prereqs for this plugin are I<already> installed.

=head1 SEE ALSO

L<Alien::Build::Plugin::PkgConfig::Negotiate>, L<Alien::Build>, L<alienfile>, L<Alien::Build::MM>, L<Alien>

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK8N%[�M��'perl5/Alien/Build/Plugin/Probe/Vcpkg.pmnu��6�$package Alien::Build::Plugin::Probe::Vcpkg;

use strict;
use warnings;
use 5.008004;
use Alien::Build::Plugin;

# ABSTRACT: Probe for system libraries using Vcpkg
our $VERSION = '2.84'; # VERSION


has '+name';
has 'lib';
has 'ffi_name';
has 'include';

sub init
{
  my($self, $meta) = @_;

  if(defined $self->include)
  {
    $meta->add_requires('configure' => 'Alien::Build::Plugin::Probe::Vcpkg' => '2.16' );
  }
  elsif(defined $self->ffi_name)
  {
    $meta->add_requires('configure' => 'Alien::Build::Plugin::Probe::Vcpkg' => '2.14' );
  }
  else
  {
    $meta->add_requires('configure' => 'Alien::Build::Plugin::Probe::Vcpkg' => '0' );
  }

  if($meta->prop->{platform}->{compiler_type} eq 'microsoft')
  {
    $meta->register_hook(
      probe => sub {
        my($build) = @_;

        $build->hook_prop->{probe_class} = __PACKAGE__;
        $build->hook_prop->{probe_instance_id} = $self->instance_id;

        eval {
          require Win32::Vcpkg;
          require Win32::Vcpkg::List;
          require Win32::Vcpkg::Package;
          Win32::Vcpkg->VERSION('0.02');
        };
        if(my $error = $@)
        {
          $build->log("unable to load Win32::Vcpkg: $error");
          return 'share';
        }

        my $package;
        if($self->name)
        {
          $package = Win32::Vcpkg::List->new
                                       ->search($self->name, include => $self->include);
        }
        elsif($self->lib)
        {
          $package = eval { Win32::Vcpkg::Package->new( lib => $self->lib, include => $self->include) };
          return 'share' if $@;
        }
        else
        {
          $build->log("you must provode either name or lib property for Probe::Vcpkg");
          return 'share';
        }

        my $version = $package->version;
        $version = 'unknown' unless defined $version;

        $build->install_prop->{plugin_probe_vcpkg}->{$self->instance_id} = {
          version  => $version,
          cflags   => $package->cflags,
          libs     => $package->libs,
        };
        $build->hook_prop->{version} = $version;
        $build->install_prop->{plugin_probe_vcpkg}->{$self->instance_id}->{ffi_name} = $self->ffi_name
          if defined $self->ffi_name;
        return 'system';
      },
    );

    $meta->register_hook(
      gather_system => sub {
        my($build) = @_;

        return if $build->hook_prop->{name} eq 'gather_system'
        &&        ($build->install_prop->{system_probe_instance_id} || '') ne $self->instance_id;

        if(my $c = $build->install_prop->{plugin_probe_vcpkg}->{$self->instance_id})
        {
          $build->runtime_prop->{version} = $c->{version} unless defined $build->runtime_prop->{version};
          $build->runtime_prop->{$_} = $c->{$_} for grep { defined $c->{$_} } qw( cflags libs ffi_name );
        }
      },
    );
  }
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::Probe::Vcpkg - Probe for system libraries using Vcpkg

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use alienfile;
 
 plugin 'Probe::Vcpkg' => 'libffi';

=head1 DESCRIPTION

This plugin probe can be used to find "system" packages using Microsoft's C<Vcpkg> package manager for
Visual C++ builds of Perl.  C<Vcpkg> is a package manager for Visual C++ that includes a number of
open source packages.  Although C<Vcpkg> does also support Linux and macOS, this plugin does not
support finding C<Vcpkg> packages on those platforms.  For more details on C<Vcpkg>, see the project
github page here:

L<https://github.com/microsoft/vcpkg>

Here is the quick start guide for getting L<Alien::Build> to work with C<Vpkg>:

 # install Vcpkg
 C:\> git clone https://github.com/Microsoft/vcpkg.git
 C:\> cd vcpkg
 C:\vcpkg> .\bootstrap-vcpkg.bat
 C:\vcpkg> .\vcpkg integrate install
 
 # update PATH to include the bin directory
 # so that .DLL files can be found by Perl
 C:\vcpkg> path c:\vcpkg\installed\x64-windows\bin;%PATH%
 
 # install the packages that you want
 C:\vcpkg> .\vcpkg install libffi
 
 # install the alien that uses it
 C:\vcpkg> cpanm Alien::FFI

If you are using 32 bit build of Perl, then substitute C<x86-windows> for C<x64-windows>.  If you do
not want to add the C<bin> directory to the C<PATH>, then you can use C<x64-windows-static> instead,
which will provide static libraries.  (As of this writing static libraries for 32 bit Windows are not
available).  The main downside to using C<x64-windows-static> is that Aliens that require dynamic
libraries for FFI will not be installable.

If you do not want to install C<Vcpkg> user wide (the C<integrate install> command above), then you
can use the C<PERL_WIN32_VCPKG_ROOT> environment variable instead:

 # install Vcpkg
 C:\> git clone https://github.com/Microsoft/vcpkg.git
 C:\> cd vcpkg
 C:\vcpkg> .\bootstrap-vcpkg.bat
 C:\vcpkg> set PERL_WIN32_VCPKG_ROOT=c:\vcpkg

=head1 PROPERTIES

=head2 name

Specifies the name of the Vcpkg.  This should not be used with the C<lib> property below, choose only one.

This is the default property, so these two are equivalent:

 plugin 'Probe::Vcpkg' => (name => 'foo');

and

 plugin 'Probe::Vcpkg' => 'foo';

=head2 lib

Specifies the list of libraries that make up the Vcpkg.  This should not be used with the C<name> property
above, choose only one.  Note that using this detection method, the version number of the package will
not be automatically determined (since multiple packages could potentially make up the list of libraries),
so you need to determine the version number another way if you need it.

This must be an array reference.  Do not include the C<.lib> extension.

 plugin 'Probe::Vcpkg' => (lib => ['foo','bar']);

=head2 ffi_name

Specifies an alternate ffi_name for finding dynamic libraries.

=head1 SEE ALSO

L<Alien::Build>, L<alienfile>, L<Alien::Build::MM>, L<Alien>

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK8N%[�	M�*perl5/Alien/Build/Plugin/Probe/CBuilder.pmnu��6�$package Alien::Build::Plugin::Probe::CBuilder;

use strict;
use warnings;
use 5.008004;
use Alien::Build::Plugin;
use File::chdir;
use File::Temp ();
use Capture::Tiny qw( capture_merged capture );
use Alien::Util qw( version_cmp );

# ABSTRACT: Probe for system libraries by guessing with ExtUtils::CBuilder
our $VERSION = '2.84'; # VERSION


has options => sub { {} };


has cflags  => '';


has libs    => '';


has program => 'int main(int argc, char *argv[]) { return 0; }';


has version => undef;


has 'atleast_version' => undef;


has aliens => [];


has lang => 'C';

sub init
{
  my($self, $meta) = @_;

  $meta->add_requires('configure' => 'ExtUtils::CBuilder' => 0 );

  if(@{ $self->aliens })
  {
    die "You can't specify both 'aliens' and either 'cflags' or 'libs' for the Probe::CBuilder plugin" if $self->cflags || $self->libs;

    $meta->add_requires('configure' => $_ => 0 ) for @{ $self->aliens };
    $meta->add_requires('Alien::Build::Plugin::Probe::CBuilder' => '0.53');

    my $cflags = '';
    my $libs   = '';
    foreach my $alien (@{ $self->aliens })
    {
      my $pm = "$alien.pm";
      $pm =~ s/::/\//g;
      require $pm;
      $cflags .= $alien->cflags . ' ';
      $libs   .= $alien->libs   . ' ';
    }
    $self->cflags($cflags);
    $self->libs($libs);
  }

  my @cpp;

  if($self->lang ne 'C')
  {
    $meta->add_requires('Alien::Build::Plugin::Probe::CBuilder' => '0.53');
    @cpp = ('C++' => 1) if $self->lang eq 'C++';
  }

  $meta->register_hook(
    probe => sub {
      my($build) = @_;

      $build->hook_prop->{probe_class} = __PACKAGE__;
      $build->hook_prop->{probe_instance_id} = $self->instance_id;

      local $CWD = File::Temp::tempdir( CLEANUP => 1, DIR => $CWD );

      open my $fh, '>', 'mytest.c';
      print $fh $self->program;
      close $fh;

      $build->log("trying: cflags=@{[ $self->cflags ]} libs=@{[ $self->libs ]}");

      my $cb = ExtUtils::CBuilder->new(%{ $self->options });

      my($out1, $obj) = capture_merged { eval {
        $cb->compile(
          source               => 'mytest.c',
          extra_compiler_flags => $self->cflags,
          @cpp,
        );
      } };

      if(my $error = $@)
      {
        $build->log("compile failed: $error");
        $build->log("compile failed: $out1");
        die $error;
      }

      my($out2, $exe) = capture_merged { eval {
        $cb->link_executable(
          objects              => [$obj],
          extra_linker_flags   => $self->libs,
        );
      } };

      if(my $error = $@)
      {
        $build->log("link failed: $error");
        $build->log("link failed: $out2");
        die $error;
      }

      my($out, $err, $ret) = capture { system($^O eq 'MSWin32' ? $exe : "./$exe") };
      die "execute failed" if $ret;

      my $cflags = $self->cflags;
      my $libs   = $self->libs;

      $cflags =~ s{\s*$}{ };
      $libs =~ s{\s*$}{ };

      $build->install_prop->{plugin_probe_cbuilder_gather}->{$self->instance_id} = {
        cflags  => $cflags,
        libs    => $libs,
      };

      if(defined $self->version)
      {
        my($version) = $out =~ $self->version;
        if (defined $self->atleast_version)
        {
          if(version_cmp ($version, $self->atleast_version) < 0)
          {
            die "CBuilder probe found version $version, but at least @{[ $self->atleast_version ]} is required.";
          }
        }
        $build->hook_prop->{version} = $version;
        $build->install_prop->{plugin_probe_cbuilder_gather}->{$self->instance_id}->{version} = $version;
      }

      'system';
    }
  );

  $meta->register_hook(
    gather_system => sub {
      my($build) = @_;

      return if $build->hook_prop->{name} eq 'gather_system'
      &&        ($build->install_prop->{system_probe_instance_id} || '') ne $self->instance_id;

      if(my $p = $build->install_prop->{plugin_probe_cbuilder_gather}->{$self->instance_id})
      {
        $build->runtime_prop->{$_} = $p->{$_} for keys %$p;
      }
    },
  );
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::Probe::CBuilder - Probe for system libraries by guessing with ExtUtils::CBuilder

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use alienfile;
 plugin 'Probe::CBuilder' => (
   cflags => '-I/opt/libfoo/include',
   libs   => '-L/opt/libfoo/lib -lfoo',
 );

alternately:

 ues alienfile;
 plugin 'Probe::CBuilder' => (
   aliens => [ 'Alien::libfoo', 'Alien::libbar' ],
 );

=head1 DESCRIPTION

This plugin probes for compiler and linker flags using L<ExtUtils::CBuilder>.  This is a useful
alternative to L<Alien::Build::Plugin::PkgConfig::Negotiate> for packages that do not provide
a pkg-config C<.pc> file, or for when those C<.pc> files may not be available.  (For example,
on FreeBSD, C<libarchive> is a core part of the operating system, but doesn't include a C<.pc>
file which is usually provided when you install the C<libarchive> package on Linux).

=head1 PROPERTIES

=head2 options

Any extra options that you want to have passed into the constructor to L<ExtUtils::CBuilder>.

=head2 cflags

The compiler flags.

=head2 libs

The linker flags

=head2 program

The program to use in the test.

=head2 version

This is a regular expression to parse the version out of the output from the
test program.

=head2 atleast_version

The minimum required version as provided by the system.

=head2 aliens

List of aliens to query fro compiler and linker flags.

=head2 lang

The programming language to use.  One of either C<C> or C<C++>.

=head1 SEE ALSO

L<Alien::Build>, L<alienfile>, L<Alien::Build::MM>, L<Alien>

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK8N%[\1��-perl5/Alien/Build/Plugin/Probe/CommandLine.pmnu��6�$package Alien::Build::Plugin::Probe::CommandLine;

use strict;
use warnings;
use 5.008004;
use Alien::Build::Plugin;
use Carp ();
use Capture::Tiny qw( capture );
use File::Which ();
use Alien::Util qw( version_cmp );

# ABSTRACT: Probe for tools or commands already available
our $VERSION = '2.84'; # VERSION


has '+command' => sub { Carp::croak "@{[ __PACKAGE__ ]} requires command property" };


has 'args'       => [];


has 'secondary' => 0;


has 'match'     => undef;


has 'match_stderr' => undef;


has 'version'   => undef;


has 'version_stderr' => undef;


has 'atleast_version' => undef;


sub init
{
  my($self, $meta) = @_;

  my $check = sub {
    my($build) = @_;

    unless(File::Which::which($self->command))
    {
      die 'Command not found ' . $self->command;
    }

    if(defined $self->match || defined $self->match_stderr || defined $self->version || defined $self->version_stderr)
    {
      my($out,$err,$ret) = capture {
        system( $self->command, @{ $self->args } );
      };
      die 'Command did not return a true value' if $ret;
      die 'Command output did not match' if defined $self->match && $out !~ $self->match;
      die 'Command standard error did not match' if defined $self->match_stderr && $err !~ $self->match_stderr;
      if (defined $self->version or defined $self->version_stderr)
      {
        my $found_version = '0';
        if(defined $self->version)
        {
          if($out =~ $self->version)
          {
            $found_version = $1;
            $build->runtime_prop->{version} = $found_version;
          }
        }
        if(defined $self->version_stderr)
        {
          if($err =~ $self->version_stderr)
          {
            $found_version = $1;
            $build->hook_prop->{version} = $found_version;
            $build->runtime_prop->{version} = $found_version;
          }
        }
        if (my $atleast_version = $self->atleast_version)
        {
          if(version_cmp ($found_version, $self->atleast_version) < 0)
          {
            #  reset the versions
            $build->runtime_prop->{version} = undef;
            $build->hook_prop->{version} = undef;
            die "CommandLine probe found version $found_version, but at least $atleast_version is required.";
          }
        }
      }
    }

    $build->runtime_prop->{command} = $self->command;
    'system';
  };

  if($self->secondary)
  {
    $meta->around_hook(
      probe => sub {
        my $orig = shift;
        my $build = shift;
        my $type = $orig->($build, @_);
        return $type unless $type eq 'system';
        $check->($build);
      },
    );
  }
  else
  {
    $meta->register_hook(
      probe => $check,
    );
  }
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::Probe::CommandLine - Probe for tools or commands already available

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use alienfile;
 plugin 'Probe::CommandLine' => (
   command => 'gzip',
   args    => [ '--version' ],
   match   => qr/gzip/,
   version => qr/gzip ([0-9\.]+)/,
 );

=head1 DESCRIPTION

This plugin probes for the existence of the given command line program.

=head1 PROPERTIES

=head2 command

The name of the command.

=head2 args

The arguments to pass to the command.

=head2 secondary

If you are using another probe plugin (such as L<Alien::Build::Plugin::Probe::CBuilder> or
L<Alien::Build::Plugin::PkgConfig::Negotiate>) to detect the existence of a library, but
also need a program to exist, then you should set secondary to a true value.  For example
when you need both:

 use alienfile;
 # requires both liblzma library and xz program
 plugin 'PkgConfig' => 'liblzma';
 plugin 'Probe::CommandLine' => (
   command   => 'xz',
   secondary => 1,
 );

When you don't:

 use alienfile;
 plugin 'Probe::CommandLine' => (
   command   => 'gzip',
   secondary => 0, # default
 );

=head2 match

Regular expression for which the program output should match.

=head2 match_stderr

Regular expression for which the program standard error should match.

=head2 version

Regular expression to parse out the version from the program output.
The regular expression should store the version number in C<$1>.

=head2 version_stderr

Regular expression to parse out the version from the program standard error.
The regular expression should store the version number in C<$1>.

=head2 atleast_version

The minimum required version as provided by the system.

=head1 SEE ALSO

L<Alien::Build>, L<alienfile>, L<Alien::Build::MM>, L<Alien>

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK8N%[��ٴ  'perl5/Alien/Build/Plugin/Decode/Mojo.pmnu��6�$package Alien::Build::Plugin::Decode::Mojo;

use strict;
use warnings;
use 5.008004;
use Alien::Build::Plugin;

# ABSTRACT: Plugin to extract links from HTML using Mojo::DOM or Mojo::DOM58
our $VERSION = '2.84'; # VERSION


sub _load ($;$)
{
  my($class, $version) = @_;
  my $pm = "$class.pm";
  $pm =~ s/::/\//g;
  eval { require $pm };
  return 0 if $@;
  if(defined $version)
  {
    eval { $class->VERSION($version) };
    return 0 if $@;
  }
  return 1;
}

has _class => sub {
  return 'Mojo::DOM58' if _load 'Mojo::DOM58';
  return 'Mojo::DOM'   if _load 'Mojo::DOM' and _load 'Mojolicious', 7.00;
  return 'Mojo::DOM58';
};

sub init
{
  my($self, $meta) = @_;

  $meta->add_requires('share' => 'URI' => 0);
  $meta->add_requires('share' => 'URI::Escape' => 0);

  my $class = $meta->prop->{plugin_decode_mojo_class} ||= $self->_class;

  if($class eq 'Mojo::DOM58')
  {
    $meta->add_requires('share' => 'Mojo::DOM58' => '1.00');
  }
  elsif($class eq 'Mojo::DOM')
  {
    $meta->add_requires('share' => 'Mojolicious' => '7.00');
    $meta->add_requires('share' => 'Mojo::DOM'   => '0');
  }
  else
  {
    die "bad class";
  }

  $meta->register_hook( decode => sub {
    my(undef, $res) = @_;

    die "do not know how to decode @{[ $res->{type} ]}"
      unless $res->{type} eq 'html';

    my $dom = $class->new($res->{content});

    my $base = URI->new($res->{base});

    if(my $base_element = $dom->find('head base')->first)
    {
      my $href = $base_element->attr('href');
      $base = URI->new($href) if defined $href;
    }

    my @list = map {
                 my $url = URI->new_abs($_, $base);
                 my $path = $url->path;
                 $path =~ s{/$}{}; # work around for Perl 5.8.7- gh#8
                 {
                   filename => URI::Escape::uri_unescape(File::Basename::basename($path)),
                   url      => URI::Escape::uri_unescape($url->as_string),
                 }
               }
               grep !/^\.\.?\/?$/,
               map { $_->attr('href') || () }
               @{ $dom->find('a')->to_array };

    return {
      type => 'list',
      list => \@list,
    };
  })


}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::Decode::Mojo - Plugin to extract links from HTML using Mojo::DOM or Mojo::DOM58

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use alienfile;
 plugin 'Decode::Mojo';

Force using C<Decode::Mojo> via the download negotiator:

 use alienfile 1.68;
 
 configure {
   requires 'Alien::Build::Plugin::Decode::Mojo';
 };
 
 plugin 'Download' => (
   ...
   decoder => 'Decode::Mojo',
 );

=head1 DESCRIPTION

Note: in most cases you will want to use L<Alien::Build::Plugin::Download::Negotiate>
instead.  It picks the appropriate decode plugin based on your platform and environment.
In some cases you may need to use this plugin directly instead.

This plugin decodes an HTML file listing into a list of candidates for your Prefer plugin.
It works just like L<Alien::Build::Plugin::Decode::HTML> except it uses either L<Mojo::DOM>
or L<Mojo::DOM58> to do its job.

This plugin is much lighter than The C<Decode::HTML> plugin, and doesn't require XS.  It
is the default decode plugin used by L<Alien::Build::Plugin::Download::Negotiate> if it
detects that you need to parse an HTML index.

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK8N%[�> 
33'perl5/Alien/Build/Plugin/Decode/HTML.pmnu��6�$package Alien::Build::Plugin::Decode::HTML;

use strict;
use warnings;
use 5.008004;
use Alien::Build::Plugin;
use File::Basename ();

# ABSTRACT: Plugin to extract links from HTML
our $VERSION = '2.84'; # VERSION


sub init
{
  my($self, $meta) = @_;

  $meta->add_requires('share' => 'HTML::LinkExtor' => 0);
  $meta->add_requires('share' => 'URI' => 0);
  $meta->add_requires('share' => 'URI::Escape' => 0);

  $meta->register_hook( decode => sub {
    my(undef, $res) = @_;

    die "do not know how to decode @{[ $res->{type} ]}"
      unless $res->{type} eq 'html';

    my $base = URI->new($res->{base});

    my @list;

    my $p = HTML::LinkExtor->new(sub {
      my($tag, %links) = @_;
      if($tag eq 'base' && $links{href})
      {
        $base = URI->new($links{href});
      }
      elsif($tag eq 'a' && $links{href})
      {
        my $href = $links{href};
        return if $href =~ m!^\.\.?/?$!;
        my $url = URI->new_abs($href, $base);
        my $path = $url->path;
        $path =~ s{/$}{}; # work around for Perl 5.8.7- gh#8
        push @list, {
          filename => URI::Escape::uri_unescape(File::Basename::basename($path)),
          url      => URI::Escape::uri_unescape($url->as_string),
        };
      }
    });

    $p->parse($res->{content});

    return {
      type => 'list',
      list => \@list,
    };
  });

  $self;
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::Decode::HTML - Plugin to extract links from HTML

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use alienfile;
 plugin 'Decode::HTML';

=head1 DESCRIPTION

Note: in most case you will want to use L<Alien::Build::Plugin::Download::Negotiate>
instead.  It picks the appropriate decode plugin based on your platform and environment.
In some cases you may need to use this plugin directly instead.

This plugin decodes an HTML file listing into a list of candidates for your Prefer plugin.

=head1 SEE ALSO

L<Alien::Build::Plugin::Download::Negotiate>, L<Alien::Build>, L<alienfile>, L<Alien::Build::MM>, L<Alien>

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK8N%[�B��

4perl5/Alien/Build/Plugin/Decode/DirListingFtpcopy.pmnu��6�$package Alien::Build::Plugin::Decode::DirListingFtpcopy;

use strict;
use warnings;
use 5.008004;
use Alien::Build::Plugin;
use File::Basename ();

# ABSTRACT: Plugin to extract links from a directory listing using ftpcopy
our $VERSION = '2.84'; # VERSION


sub init
{
  my($self, $meta) = @_;

  $meta->add_requires('share' => 'File::Listing::Ftpcopy' => 0);
  $meta->add_requires('share' => 'URI' => 0);

  $meta->register_hook( decode => sub {
    my(undef, $res) = @_;

    die "do not know how to decode @{[ $res->{type} ]}"
      unless $res->{type} eq 'dir_listing';

    my $base = URI->new($res->{base});

    return {
      type => 'list',
      list => [
        map {
          my($name) = @$_;
          my $basename = $name;
          $basename =~ s{/$}{};
          my %h = (
            filename => File::Basename::basename($basename),
            url      => URI->new_abs($name, $base)->as_string,
          );
          \%h;
        } File::Listing::Ftpcopy::parse_dir($res->{content})
      ],
    };
  });

  $self;
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::Decode::DirListingFtpcopy - Plugin to extract links from a directory listing using ftpcopy

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use alienfile;
 plugin 'Decode::DirListingFtpcopy';

=head1 DESCRIPTION

Note: in most case you will want to use L<Alien::Build::Plugin::Download::Negotiate>
instead.  It picks the appropriate decode plugin based on your platform and environment.
In some cases you may need to use this plugin directly instead.

This plugin decodes a ftp file listing into a list of candidates for your Prefer plugin.
It is useful when fetching from an FTP server via L<Alien::Build::Plugin::Fetch::LWP>.
It is different from the similarly named L<Alien::Build::Plugin::Decode::DirListingFtpcopy>
in that it uses L<File::Listing::Ftpcopy> instead of L<File::Listing>.  The rationale for
the C<Ftpcopy> version is that it supports a different set of FTP servers, including
OpenVMS.  In most cases, however, you probably want to use the non C<Ftpcopy> version
since it is pure perl.

=head1 SEE ALSO

L<Alien::Build::Plugin::Download::Negotiate>, L<Alien::Build::Plugin::Decode::DirListing>, L<Alien::Build>, L<alienfile>, L<Alien::Build::MM>, L<Alien>

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK8N%[}�gg-perl5/Alien/Build/Plugin/Decode/DirListing.pmnu��6�$package Alien::Build::Plugin::Decode::DirListing;

use strict;
use warnings;
use 5.008004;
use Alien::Build::Plugin;
use File::Basename ();

# ABSTRACT: Plugin to extract links from a directory listing
our $VERSION = '2.84'; # VERSION


sub init
{
  my($self, $meta) = @_;

  $meta->add_requires('share' => 'File::Listing' => 0);
  $meta->add_requires('share' => 'URI' => 0);

  $meta->register_hook( decode => sub {
    my(undef, $res) = @_;

    die "do not know how to decode @{[ $res->{type} ]}"
      unless $res->{type} eq 'dir_listing';

    my $base = URI->new($res->{base});

    return {
      type => 'list',
      list => [
        map {
          my($name) = @$_;
          my $basename = $name;
          $basename =~ s{/$}{};
          my %h = (
            filename => File::Basename::basename($basename),
            url      => URI->new_abs($name, $base)->as_string,
          );
          \%h;
        } File::Listing::parse_dir($res->{content})
      ],
    };
  });

  $self;
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::Decode::DirListing - Plugin to extract links from a directory listing

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use alienfile;
 plugin 'Decode::DirListing';

=head1 DESCRIPTION

Note: in most case you will want to use L<Alien::Build::Plugin::Download::Negotiate>
instead.  It picks the appropriate decode plugin based on your platform and environment.
In some cases you may need to use this plugin directly instead.

This plugin decodes a ftp file listing into a list of candidates for your Prefer plugin.
It is useful when fetching from an FTP server via L<Alien::Build::Plugin::Fetch::LWP>.

=head1 SEE ALSO

L<Alien::Build::Plugin::Download::Negotiate>, L<Alien::Build::Plugin::Decode::DirListingFtpcopy>, L<Alien::Build>, L<alienfile>, L<Alien::Build::MM>, L<Alien>

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK8N%[����%perl5/Alien/Build/Plugin/Core/Tail.pmnu��6�$package Alien::Build::Plugin::Core::Tail;

use strict;
use warnings;
use 5.008004;
use Alien::Build::Plugin;

# ABSTRACT: Core tail setup plugin
our $VERSION = '2.84'; # VERSION


sub init
{
  my($self, $meta) = @_;

  if($meta->prop->{out_of_source})
  {
    $meta->add_requires('configure' => 'Alien::Build' => '1.08');
  }
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::Core::Tail - Core tail setup plugin

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use alienfile;
 # already loaded

=head1 DESCRIPTION

This plugin does some core tail setup for you.

=head1 SEE ALSO

L<Alien::Build>, L<Alien::Base::ModuleBuild>

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK8N%[��MUU&perl5/Alien/Build/Plugin/Core/Setup.pmnu��6�$package Alien::Build::Plugin::Core::Setup;

use strict;
use warnings;
use 5.008004;
use Alien::Build::Plugin;
use Config;
use File::Which qw( which );

# ABSTRACT: Core setup plugin
our $VERSION = '2.84'; # VERSION


sub init
{
  my($self, $meta) = @_;
  $meta->prop->{platform} ||= {};
  $self->_platform($meta->prop->{platform});
}

sub _platform
{
  my(undef, $hash) = @_;

  if($^O eq 'MSWin32' && $Config{ccname} eq 'cl')
  {
    $hash->{compiler_type} = 'microsoft';
  }
  else
  {
    $hash->{compiler_type} = 'unix';
  }

  if($^O eq 'MSWin32')
  {
    $hash->{system_type} = 'windows-unknown';

    if(defined &Win32::BuildNumber)
    {
      $hash->{system_type} = 'windows-activestate';
    }
    elsif($Config{myuname} =~ /strawberry-perl/)
    {
      $hash->{system_type} = 'windows-strawberry';
    }
    elsif($hash->{compiler_type} eq 'microsoft')
    {
      $hash->{system_type} = 'windows-microsoft';
    }
    else
    {
      my $uname_exe = which('uname');
      if($uname_exe)
      {
        my $uname = `$uname_exe`;
        if($uname =~ /^(MINGW)(32|64)_NT/)
        {
          $hash->{system_type} = 'windows-' . lc $1;
        }
      }
    }
  }
  elsif($^O =~ /^(VMS)$/)
  {
    # others probably belong in here...
    $hash->{system_type} = lc $^O;
  }
  else
  {
    $hash->{system_type} = 'unix';
  }

  $hash->{cpu}{count} =
    exists $ENV{ALIEN_CPU_COUNT} && $ENV{ALIEN_CPU_COUNT} > 0
    ? $ENV{ALIEN_CPU_COUNT}
    : _cpu_count();

  $hash->{cpu}{arch} = _cpu_arch(\%Config);
}

# Retrieve number of available CPU cores. Adopted from
# <https://metacpan.org/release/MARIOROY/MCE-1.879/source/lib/MCE/Util.pm#L49>
# which is in turn adopted from Test::Smoke::Util with improvements.
sub _cpu_count {
  local $ENV{PATH} = $ENV{PATH};
  if( $^O ne 'MSWin32' ) {
    $ENV{PATH} = "/usr/sbin:/sbin:/usr/bin:/bin:$ENV{PATH}";
  }
  $ENV{PATH} =~ /(.*)/; $ENV{PATH} = $1;   ## Remove tainted'ness

  my $ncpu = 1;

  OS_CHECK: {
    local $_ = lc $^O;

    /linux/ && do {
      my ( $count, $fh );
      if ( open $fh, '<', '/proc/stat' ) {
        $count = grep { /^cpu\d/ } <$fh>;
        close $fh;
      }
      $ncpu = $count if $count;
      last OS_CHECK;
    };

    /bsd|darwin|dragonfly/ && do {
      chomp( my @output = `sysctl -n hw.ncpu 2>/dev/null` );
      $ncpu = $output[0] if @output;
      last OS_CHECK;
    };

    /aix/ && do {
      my @output = `lparstat -i 2>/dev/null | grep "^Online Virtual CPUs"`;
      if ( @output ) {
        $output[0] =~ /(\d+)\n$/;
        $ncpu = $1 if $1;
      }
      if ( !$ncpu ) {
        @output = `pmcycles -m 2>/dev/null`;
        if ( @output ) {
          $ncpu = scalar @output;
        } else {
          @output = `lsdev -Cc processor -S Available 2>/dev/null`;
          $ncpu = scalar @output if @output;
        }
      }
      last OS_CHECK;
    };

    /gnu/ && do {
      chomp( my @output = `nproc 2>/dev/null` );
      $ncpu = $output[0] if @output;
      last OS_CHECK;
    };

    /haiku/ && do {
      my @output = `sysinfo -cpu 2>/dev/null | grep "^CPU #"`;
      $ncpu = scalar @output if @output;
      last OS_CHECK;
    };

    /hp-?ux/ && do {
      my $count = grep { /^processor/ } `ioscan -fkC processor 2>/dev/null`;
      $ncpu = $count if $count;
      last OS_CHECK;
    };

    /irix/ && do {
      my @out = grep { /\s+processors?$/i } `hinv -c processor 2>/dev/null`;
      $ncpu = (split ' ', $out[0])[0] if @out;
      last OS_CHECK;
    };

    /osf|solaris|sunos|svr5|sco/ && do {
      if (-x '/usr/sbin/psrinfo') {
        my $count = grep { /on-?line/ } `psrinfo 2>/dev/null`;
        $ncpu = $count if $count;
      }
      else {
        my @output = grep { /^NumCPU = \d+/ } `uname -X 2>/dev/null`;
        $ncpu = (split ' ', $output[0])[2] if @output;
      }
      last OS_CHECK;
    };

    /mswin|mingw|msys|cygwin/ && do {
      if (exists $ENV{NUMBER_OF_PROCESSORS}) {
        $ncpu = $ENV{NUMBER_OF_PROCESSORS};
      }
      last OS_CHECK;
    };

    warn "CPU count: unknown operating system";
  }

  $ncpu = 1 if (!$ncpu || $ncpu < 1);

  $ncpu;
}

sub _cpu_arch {
  my ($my_config) = @_;

  my $arch = {};

  my %Config = %$my_config;

  die "Config missing archname" unless exists $Config{archname};
  die "Config missing ptrsize"  unless exists $Config{ptrsize};

  if( $Config{archname} =~ m/
      \b x64    \b # MSWin32-x64
    | \b x86_64 \b # x86_64-linux
    | \b amd64  \b # amd64-freebsd
    /ix) {
    $arch = { name => 'x86_64' };
  } elsif( $Config{archname} =~ m/
      \b x86  \b   # MSWin32-x86
    | \b i386 \b   # freebsd-i386
    | \b i486 \b   # i486-linux
    | \b i686 \b   # i686-cygwin
    /ix ) {
    $arch = { name => 'x86' };
  } elsif( $Config{archname} =~ m/
      \b darwin \b
    /ix ) {
    chomp( my $hw_machine = `sysctl -n hw.machine 2>/dev/null` );
    HW_MACHINE:
    for($hw_machine) {
      $_ eq 'arm64' && do {
        $arch = { name => 'aarch64' };
        last HW_MACHINE;
      };
      $_ eq 'x86_64' && do {
        $arch = { name => $Config{ptrsize} == 8 ? 'x86_64' : 'x86' };
        last HW_MACHINE;
      };
      $_ eq 'i386' && do {
        $arch = { name => 'x86' };
        last HW_MACHINE;
      };
      $_ eq 'Power Macintosh' && do {
        $arch = { name => $Config{ptrsize} == 8 ? 'ppc64' : 'ppc' };
        last HW_MACHINE;
      };

      warn "Architecture detection: unknown macOS arch hw.machine = $_, ptrsize = $Config{ptrsize}";
      $arch = { name => 'unknown' };
    }
  } elsif( $Config{archname} =~ /
      \b aarch64 \b
    | \b arm64 \b    # arm64-freebsd (FreeBSD can have either aarch64 or arm64)
    /ix ) {
    $arch = { name => 'aarch64' };   # ARM64
  } elsif( $Config{archname} =~ m/
      \b arm-linux-gnueabi \b
    /ix ) {
    # 32-bit ARM soft-float
    $arch = { name => 'armel' };
  } elsif( $Config{archname} =~ m/
      \b arm-linux-gnueabihf \b
    /ix ) {
    # 32-bit ARM hard-float
    $arch = { name => 'armhf' };
  }

  unless(exists $arch->{name}) {
    warn "Architecture detection: Unknown archname '$Config{archname}'.";
    $arch->{name} = 'unknown';
  }

  return $arch;
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::Core::Setup - Core setup plugin

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use alienfile;
 # already loaded

=head1 DESCRIPTION

This plugin does some core setup for you.

=head1 SEE ALSO

L<Alien::Build>, L<Alien::Base::ModuleBuild>

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK8N%[xn;��-perl5/Alien/Build/Plugin/Core/CleanInstall.pmnu��6�$package Alien::Build::Plugin::Core::CleanInstall;

use strict;
use warnings;
use 5.008004;
use Alien::Build::Plugin;
use Path::Tiny ();

# ABSTRACT: Implementation for clean_install hook.
our $VERSION = '2.84'; # VERSION


sub init
{
  my($self, $meta) = @_;

  $meta->default_hook(
    clean_install => sub {
      my($build) = @_;
      my $root = Path::Tiny->new(
        $build->runtime_prop->{prefix}
      );
      if(-d $root)
      {
        foreach my $child ($root->children)
        {
          if($child->basename eq '_alien')
          {
            $build->log("keeping  $child");
          }
          else
          {
            $build->log("removing $child");
            $child->remove_tree({ safe => 0});
          }
        }
      }
    }
  );
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::Core::CleanInstall - Implementation for clean_install hook.

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use alienfile;
 # already loaded

=head1 DESCRIPTION

This plugin implements the default C<clean_install> hook.
You shouldn't use it directly.

=head1 SEE ALSO

L<Alien::Build>, L<Alien::Base::ModuleBuild>

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK8N%[�����)perl5/Alien/Build/Plugin/Core/Override.pmnu��6�$package Alien::Build::Plugin::Core::Override;

use strict;
use warnings;
use 5.008004;
use Alien::Build::Plugin;

# ABSTRACT: Core override plugin
our $VERSION = '2.84'; # VERSION


sub init
{
  my($self, $meta) = @_;

  $meta->default_hook(
    override => sub {
      my($build) = @_;
      return $ENV{ALIEN_INSTALL_TYPE} || '';
    },
  );
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::Core::Override - Core override plugin

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use alienfile;
 # already loaded

=head1 DESCRIPTION

This plugin implements the C<ALIEN_INSTALL_TYPE> environment variable.

=head1 SEE ALSO

L<Alien::Build>, L<Alien::Base::ModuleBuild>

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK8N%[��P���'perl5/Alien/Build/Plugin/Core/Gather.pmnu��6�$package Alien::Build::Plugin::Core::Gather;

use strict;
use warnings;
use 5.008004;
use Alien::Build::Plugin;
use Env qw( @PATH @PKG_CONFIG_PATH );
use Path::Tiny ();
use File::chdir;
use Alien::Build::Util qw( _mirror _destdir_prefix );
use JSON::PP ();

# ABSTRACT: Core gather plugin
our $VERSION = '2.84'; # VERSION


sub init
{
  my($self, $meta) = @_;

  $meta->default_hook(
    $_ => sub {},
  ) for qw( gather_system gather_share );

  $meta->around_hook(
    gather_share => sub {
      my($orig, $build) = @_;

      local $ENV{PATH} = $ENV{PATH};
      local $ENV{PKG_CONFIG_PATH} = $ENV{PKG_CONFIG_PATH};
      unshift @PATH, Path::Tiny->new('bin')->absolute->stringify
        if -d 'bin';

      for my $dir (qw(share lib)) {
          unshift @PKG_CONFIG_PATH, Path::Tiny->new("$dir/pkgconfig")->absolute->stringify
            if -d "$dir/pkgconfig";
      }

      $orig->($build)
    }
  );

  foreach my $type (qw( share ffi ))
  {
    $meta->around_hook(
      "gather_$type" => sub {
        my($orig, $build) = @_;

        if($build->meta_prop->{destdir})
        {
          my $destdir = $ENV{DESTDIR};
          if(-d $destdir)
          {
            my $src = Path::Tiny->new(_destdir_prefix($ENV{DESTDIR}, $build->install_prop->{prefix}));
            my $dst = Path::Tiny->new($build->install_prop->{stage});

            my $res = do {
              local $CWD = "$src";
              $orig->($build);
            };

            $build->log("mirror $src => $dst");

            $dst->mkpath;
            # Please note: _mirror and Alien::Build::Util are ONLY
            # allowed to be used by core plugins.  If you are writing
            # a non-core plugin it may be removed.  That is why it
            # is private.
            _mirror("$src", "$dst", {
              verbose => 1,
              filter => $build->meta_prop->{$type eq 'share' ? 'destdir_filter' : 'destdir_ffi_filter'},
            });

            return $res;
          }
          else
          {
            die "nothing was installed into destdir" if $type eq 'share';
          }
        }
        else
        {
          local $CWD = $build->install_prop->{stage};
          my $ret = $orig->($build);

          # if we are not doing a double staged install we want to substitute the install
          # prefix with the runtime prefix.
          my $old = $build->install_prop->{prefix};
          my $new = $build->runtime_prop->{prefix};

          foreach my $flag (qw( cflags cflags_static libs libs_static ))
          {
            next unless defined $build->runtime_prop->{$flag};
            $build->runtime_prop->{$flag} =~ s{(-I|-L|-LIBPATH:)\Q$old\E}{$1 . $new}eg;
          }

          return $ret;
        }
      }
    );
  }

  $meta->after_hook(
    $_ => sub {
      my($build) = @_;

      die "stage is not defined.  be sure to call set_stage on your Alien::Build instance"
        unless $build->install_prop->{stage};

      my $stage = Path::Tiny->new($build->install_prop->{stage});
      $build->log("mkdir -p $stage/_alien");
      $stage->child('_alien')->mkpath;

      # drop a alien.json file for the runtime properties
      $stage->child('_alien/alien.json')->spew(
        JSON::PP->new->pretty->canonical(1)->ascii->encode($build->runtime_prop)
      );

      # copy the alienfile, if we managed to keep it around.
      if($build->meta->filename                 &&
         -r $build->meta->filename              &&
         $build->meta->filename !~ /\.(pm|pl)$/ &&
         ! -d $build->meta->filename)
      {
        Path::Tiny->new($build->meta->filename)
                  ->copy($stage->child('_alien/alienfile'));
      }

      if($build->install_prop->{patch} && -d $build->install_prop->{patch})
      {
        # Please note: _mirror and Alien::Build::Util are ONLY
        # allowed to be used by core plugins.  If you are writing
        # a non-core plugin it may be removed.  That is why it
        # is private.
        _mirror($build->install_prop->{patch},
                $stage->child('_alien/patch')->stringify);
      }

    },
  ) for qw( gather_share gather_system );
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::Core::Gather - Core gather plugin

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use alienfile;
 # already loaded

=head1 DESCRIPTION

This plugin helps make the gather stage work.

=head1 SEE ALSO

L<Alien::Build>, L<Alien::Base::ModuleBuild>

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK8N%[�Cb�	�	'perl5/Alien/Build/Plugin/Core/Legacy.pmnu��6�$package Alien::Build::Plugin::Core::Legacy;

use strict;
use warnings;
use 5.008004;
use Alien::Build::Plugin;

# ABSTRACT: Core Alien::Build plugin to maintain compatibility with legacy Alien::Base
our $VERSION = '2.84'; # VERSION


sub init
{
  my($self, $meta) = @_;

  $meta->after_hook(
    $_ => sub {
      my($build) = @_;

      $build->log("adding legacy hash to config");

      my $runtime = $build->runtime_prop;

      if($runtime->{cflags} && ! defined $runtime->{cflags_static})
      {
        $runtime->{cflags_static} = $runtime->{cflags};
      }

      if($runtime->{libs} && ! defined $runtime->{libs_static})
      {
        $runtime->{libs_static} = $runtime->{libs};
      }

      $runtime->{legacy}->{finished_installing} = 1;
      $runtime->{legacy}->{install_type}        = $runtime->{install_type};
      $runtime->{legacy}->{version}             = $runtime->{version};
      $runtime->{legacy}->{original_prefix}     = $runtime->{prefix};
    }
  ) for qw( gather_system gather_share );
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::Core::Legacy - Core Alien::Build plugin to maintain compatibility with legacy Alien::Base

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use alienfile;
 # already loaded

=head1 DESCRIPTION

This plugin provides some compatibility with the legacy L<Alien::Base::ModuleBuild>
interfaces.

=head1 SEE ALSO

L<Alien::Build>, L<Alien::Base::ModuleBuild>

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK8N%[X�ߕ��)perl5/Alien/Build/Plugin/Core/Download.pmnu��6�$package Alien::Build::Plugin::Core::Download;

use strict;
use warnings;
use 5.008004;
use Alien::Build::Plugin;
use Path::Tiny ();
use Alien::Build::Util qw( _mirror );

# ABSTRACT: Core download plugin
our $VERSION = '2.84'; # VERSION


sub _hook
{
  my($build) = @_;

  my $res = $build->fetch;

  if($res->{type} =~ /^(?:html|dir_listing)$/)
  {
    my $type = $res->{type};
    $type =~ s/_/ /;
    $build->log("decoding $type");
    $res = $build->decode($res);
  }

  if($res->{type} eq 'list')
  {
    my $orig = $res;
    $res = $build->prefer($res);

    my @exclude;
    if($build->meta->prop->{start_url} =~ /^https:/)
    {
      @{ $res->{list} } = grep {
        $_->{url} =~ /https:/ ? 1 : do {
          push @exclude, $_->{url};
          0;
        }
      } @{ $res->{list} };
    }

    if(@{ $res->{list} } == 0)
    {
      my @excluded = map { $_->{url} } @{ $orig->{list} };
      if(@excluded)
      {
        if(@excluded > 15)
        {
          splice @excluded , 14;
          push @excluded, '...';
        }
        $build->log("These files were excluded by the filter stage:");
        $build->log("excluded $_") for @excluded;
      }
      else
      {
        $build->log("No files found prior to the filter stage");
      }
      die "no matching files in listing";
    }
    my $version = $res->{list}->[0]->{version};
    my($pick, @other) = map { $_->{url} } @{ $res->{list} };

    if(@other > 8)
    {
      splice @other, 7;
      push @other, '...';
    }
    $build->log("candidate *$pick");
    $build->log("candidate  $_") for @other;

    if(@exclude)
    {
      if(@exclude > 8)
      {
        splice @exclude, 7;
        push @exclude, '...';
      }
      $build->log("excluded insecure URLs:");
      $build->log($_) for @exclude;
    }

    $res = $build->fetch($pick);

    if($version)
    {
      $version =~ s/\.+$//;
      $build->log("setting version based on archive to $version");
      $build->runtime_prop->{version} = $version;
    }
  }

  if($res->{type} eq 'file')
  {
    my $alienfile = $res->{filename};
    $build->log("downloaded $alienfile");
    if($res->{content})
    {
      my $tmp = Alien::Build::TempDir->new($build, "download");
      my $path = Path::Tiny->new("$tmp/$alienfile");
      $path->spew_raw($res->{content});
      $build->install_prop->{download} = $path->stringify;
      $build->install_prop->{complete}->{download} = 1;
      $build->install_prop->{download_detail}->{"$path"}->{protocol} = $res->{protocol} if defined $res->{protocol};
      return $build;
    }
    elsif($res->{path})
    {
      if(defined $res->{tmp} && !$res->{tmp})
      {
        if(-e $res->{path})
        {
          $build->install_prop->{download} = $res->{path};
          $build->install_prop->{complete}->{download} = 1;
          $build->install_prop->{download_detail}->{$res->{path}}->{protocol} = $res->{protocol} if defined $res->{protocol};
        }
        else
        {
          die "not a file or directory: @{[ $res->{path} ]}";
        }
      }
      else
      {
        my $from = Path::Tiny->new($res->{path});
        my $tmp = Alien::Build::TempDir->new($build, "download");
        my $to   = Path::Tiny->new("$tmp/@{[ $from->basename ]}");
        if(-d $res->{path})
        {
          # Please note: _mirror and Alien::Build::Util are ONLY
          # allowed to be used by core plugins.  If you are writing
          # a non-core plugin it may be removed.  That is why it
          # is private.
          _mirror $from, $to;
        }
        else
        {
          require File::Copy;
          File::Copy::copy(
            "$from" => "$to",
          ) || die "copy $from => $to failed: $!";
        }
        $build->install_prop->{download} = $to->stringify;
        $build->install_prop->{complete}->{download} = 1;
        $build->install_prop->{download_detail}->{"$to"}->{protocol} = $res->{protocol} if defined $res->{protocol};
      }
      return $build;
    }
    die "file without content or path";
  }
  die "unknown fetch response type: @{[ $res->{type} ]}";
}

sub init
{
  my($self, $meta) = @_;

  $meta->default_hook(download => \&_hook);
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::Core::Download - Core download plugin

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use alienfile;
 # already loaded

=head1 DESCRIPTION

This plugin does some core download logic.

=head1 SEE ALSO

L<Alien::Build>, L<Alien::Base::ModuleBuild>

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK8N%[�A]��$perl5/Alien/Build/Plugin/Core/FFI.pmnu��6�$package Alien::Build::Plugin::Core::FFI;

use strict;
use warnings;
use 5.008004;
use Alien::Build::Plugin;

# ABSTRACT: Core FFI plugin
our $VERSION = '2.84'; # VERSION


sub init
{
  my($self, $meta) = @_;

  $meta->default_hook(
    $_ => sub {},
  ) for qw( build_ffi gather_ffi );

  $meta->prop->{destdir_ffi_filter} = '^dynamic';

}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::Core::FFI - Core FFI plugin

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use alienfile;
 # already loaded

=head1 DESCRIPTION

This plugin helps make the build_ffi work.  You should not
need to interact with it directly.

=head1 SEE ALSO

L<Alien::Build>, L<Alien::Base::ModuleBuild>

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK8N%[s}W;	;	"perl5/Alien/Build/Plugin/Probe.podnu��6�$# PODNAME: Alien::Build::Plugin::Probe
# ABSTRACT: Probe Alien::Build plugins
# VERSION

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::Probe - Probe Alien::Build plugins

=head1 VERSION

version 2.84

=head1 SYNOPSIS

look for libraries in known location:

 use alienfile;
 plugin 'Probe::CBuilder' => (
   cflags => '-I/opt/libfoo/include',
   libs   => '-L/opt/libfoo/lib -lfoo',
 );

look for tools in the path:

 use alienfile;
 plugin 'Probe::CommandLine' => (
   command => 'gzip',
   args    => [ '--version' ],
   match   => qr/gzip/,
   version => qr/gzip ([0-9\.]+)/,
 );

Use C<vcpkg> for Visual C++ Perl:

 use alienfile;
 plugin 'Probe::Vcpkg' => 'libffi';

=head1 DESCRIPTION

Probe plugins try to find existing libraries and tools
I<already> installed on the system.  If found they can
be used instead of downloading the source from the
internet and building.

=over 4

=item L<Alien::Build::Plugin::Probe::CBuilder>

Use L<ExtUtils::CBuilder> to probe for existing installed
library.

=item L<Alien::Build::Plugin::Probe::CommandLine>

Execute commands to probe for existing tools.

=item L<Alien::Build::Plugin::Probe::Vcpkg>

Use L<Win32::Vcpkg> to probe for existing installed library.

=back

=head1 SEE ALSO

L<Alien::Build>, L<Alien::Build::Plugin>

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK8N%[H̻)),perl5/Alien/Build/Plugin/Digest/Negotiate.pmnu��6�$package Alien::Build::Plugin::Digest::Negotiate;

use strict;
use warnings;
use Alien::Build::Plugin;

# ABSTRACT: Plugin negotiator for cryptographic signatures
our $VERSION = '2.84'; # VERSION


has '+sig' => sub { {} };

has check_fetch    => 1;
has check_download => 1;
has allow_listing  => 1;

sub init
{
  my($self, $meta) = @_;
  $meta->add_requires('configure' => 'Alien::Build::Plugin::Digest::Negotiate' => "0" );

  $meta->prop->{check_digest} = 1;

  my $sigs = $meta->prop->{digest} ||= {};

  if(ref($self->sig) eq 'HASH') {

    foreach my $filename (keys %{ $self->sig })
    {
      my $signature = $self->sig->{$filename};
      my($algo) = @$signature;
      die "Unknown digest algorithm $algo" unless $algo =~ /^SHA(1|224|256|384|512|512224|512256)$/; # reportedly what is supported by Digest::SHA
      $sigs->{$filename} = $signature;
    }

  } elsif(ref($self->sig) eq 'ARRAY') {

    my $signature = $self->sig;
    my($algo) = @$signature;
    die "Unknown digest algorithm $algo" unless $algo =~ /^SHA(1|224|256|384|512|512224|512256)$/; # reportedly what is supported by Digest::SHA
    $sigs->{'*'} = $signature;
  }

  # In the future if this negotiator supports algorithms other
  # than SHA, we should probably ajust this to keep track of
  # which ones we actually need when we are looping through them
  # above.  Also technically you could call this plugin without
  # any sigs, and we shouldn't in theory need to apply Digest::SHA,
  # but stuff won't work that way so that is a corner case we
  # are not going to worry about.
  $meta->apply_plugin('Digest::SHA');

  $meta->around_hook(
    fetch => sub {
      my($orig, $build, @rest) = @_;
      my $res = $orig->($build, @rest);
      if($res->{type} eq 'file')
      {
        $build->check_digest($res);
      }
      else
      {
        die "listing fetch not allowed" unless $self->allow_listing;
      }
      $res;
    },
  ) if $self->check_fetch;

  # Note that check_download hook is currently undocumented and
  # may change in the future.
  $meta->register_hook(
    check_download => sub {
      my($build) = @_;
      my $path = $build->install_prop->{download};
      die "Checking cryptographic signatures on download only works for single archive" unless defined $path;
      $build->check_digest($path);
    },
  ) if $self->check_download;
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::Digest::Negotiate - Plugin negotiator for cryptographic signatures

=head1 VERSION

version 2.84

=head1 SYNOPSIS

for a single file:

 use alienfile;
 plugin 'Digest' => [ SHA256 => $digest ];

or for multiple files:

 use alienfile;
 plugin 'Digest' => {
   file1 => [ SHA256 => $digest1 ],
   file2 => [ SHA256 => $digest2 ],
 };

=head1 DESCRIPTION

This plugin is experimental.

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK8N%[���4t	t	(perl5/Alien/Build/Plugin/Digest/SHAPP.pmnu��6�$package Alien::Build::Plugin::Digest::SHAPP;

use strict;
use warnings;
use Alien::Build::Plugin;

# ABSTRACT: Plugin to check SHA digest with Digest::SHA::PurePerl
our $VERSION = '2.84'; # VERSION


sub init
{
  my($self, $meta) = @_;

  $meta->add_requires('configure' => 'Alien::Build'          => "2.57" );
  $meta->add_requires('share'     => 'Digest::SHA::PurePerl' =>    "0" );

  $meta->register_hook( check_digest => sub {
    my($build, $file, $algo, $expected_digest) = @_;

    return 0 unless $algo =~ /^SHA[0-9]+$/;

    my $sha = Digest::SHA::PurePerl->new($algo);
    return 0 unless defined $sha;

    if(defined $file->{content})
    {
      $sha->add($file->{content});
    }
    elsif(defined $file->{path})
    {
      $sha->addfile($file->{path}, "b");
    }
    else
    {
      die "unknown file type";
    }

    my $actual_digest = $sha->hexdigest;

    return 1 if $expected_digest eq $actual_digest;
    die "@{[ $file->{filename} ]} SHA@{[ $sha->algorithm ]} digest does not match: got $actual_digest, expected $expected_digest";

  });
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::Digest::SHAPP - Plugin to check SHA digest with Digest::SHA::PurePerl

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use alienfile;
 plugin 'Digest::SHAPP';

=head1 DESCRIPTION

This plugin is experimental.

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK8N%[~Oc�		&perl5/Alien/Build/Plugin/Digest/SHA.pmnu��6�$package Alien::Build::Plugin::Digest::SHA;

use strict;
use warnings;
use Alien::Build::Plugin;

# ABSTRACT: Plugin to check SHA digest with Digest::SHA
our $VERSION = '2.84'; # VERSION


sub init
{
  my($self, $meta) = @_;

  $meta->add_requires('configure' => 'Alien::Build'          => "2.57" );

  $meta->register_hook( check_digest => sub {
    my($build, $file, $algo, $expected_digest) = @_;

    return 0 unless $algo =~ /^SHA[0-9]+$/;

    my $sha = Digest::SHA->new($algo);
    return 0 unless defined $sha;

    if(defined $file->{content})
    {
      $sha->add($file->{content});
    }
    elsif(defined $file->{path})
    {
      $sha->addfile($file->{path}, "b");
    }
    else
    {
      die "unknown file type";
    }

    my $actual_digest = $sha->hexdigest;

    return 1 if $expected_digest eq $actual_digest;
    die "@{[ $file->{filename} ]} SHA@{[ $sha->algorithm ]} digest does not match: got $actual_digest, expected $expected_digest";

  });
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::Digest::SHA - Plugin to check SHA digest with Digest::SHA

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use alienfile;
 plugin 'Digest::SHA';

=head1 DESCRIPTION

This plugin is experimental.

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK8N%[+'$5uu*perl5/Alien/Build/Plugin/Fetch/LocalDir.pmnu��6�$package Alien::Build::Plugin::Fetch::LocalDir;

use strict;
use warnings;
use 5.008004;
use Alien::Build::Plugin;
use File::chdir;
use Path::Tiny ();

# ABSTRACT: Plugin for fetching a local directory
our $VERSION = '2.84'; # VERSION


has root => undef;


has ssl => 0;

sub init
{
  my($self, $meta) = @_;

  my $url = $meta->prop->{start_url} || 'patch';

  $meta->add_requires('configure' => 'Alien::Build::Plugin::Fetch::LocalDir' => '0.72' );

  if($url =~ /^file:/)
  {
    $meta->add_requires('share' => 'URI' => 0 );
    $meta->add_requires('share' => 'URI::file' => 0 );
  }

  {
    my $root = $self->root;
    if(defined $root)
    {
      $root = Path::Tiny->new($root)->absolute->stringify;
    }
    else
    {
      $root = "$CWD";
    }
    $self->root($root);
  }

  $meta->register_hook(
    fetch => sub {
      my($build, $path, %options) = @_;

      $build->log("plugin Fetch::LocalDir does not support http_headers option") if $options{http_headers};

      $path ||= $url;

      if($path =~ /^file:/)
      {
        my $root = URI::file->new($self->root);
        my $url  = URI->new_abs($path, $root);
        $path = $url->path;
        $path =~ s{^/([a-z]:)}{$1}i if $^O eq 'MSWin32';
      }

      $path = Path::Tiny->new($path)->absolute($self->root);

      if(-d $path)
      {
        return {
          type     => 'file',
          filename => $path->basename,
          path     => $path->stringify,
          tmp      => 0,
          protocol => 'file',
        };
      }
      else
      {
        $build->log("path $path is not a directory");
        $build->log("(you specified $url with root @{[ $self->root ]})");
        die "$path is not a directory";
      }
    }
  );
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::Fetch::LocalDir - Plugin for fetching a local directory

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use alienfile;
 share {
   start_url 'patch/libfoo-1.00/';
   plugin 'Fetch::LocalDir';
 };

=head1 DESCRIPTION

Note: in most case you will want to use L<Alien::Build::Plugin::Download::Negotiate>
instead.  It picks the appropriate fetch plugin based on your platform and environment.
In some cases you may need to use this plugin directly instead.

This fetch plugin fetches files from the local file system.  It is mostly useful if you
intend to bundle source with your Alien.  If you are bundling tarballs see
L<Alien::Build::Plugin::Fetch::Local>.

=head1 PROPERTIES

=head2 root

The directory from which the start URL should be relative.  The default is usually reasonable.

=head2 ssl

This property is for compatibility with other fetch plugins, but is not used.

=head1 SEE ALSO

=over 4

=item L<Alien::Build::Plugin::Download::Negotiate>

=item L<Alien::Build::Plugin::Fetch::Local>

=item L<Alien::Build>

=item L<alienfile>

=item L<Alien::Build::MM>

=item L<Alien>

=back

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK9N%[�}T		%perl5/Alien/Build/Plugin/Fetch/LWP.pmnu��6�$package Alien::Build::Plugin::Fetch::LWP;

use strict;
use warnings;
use 5.008004;
use Alien::Build::Plugin;
use Carp ();

# ABSTRACT: Plugin for fetching files using LWP
our $VERSION = '2.84'; # VERSION


has '+url' => '';


has ssl => 0;

sub init
{
  my($self, $meta) = @_;

  $meta->add_requires('share' => 'LWP::UserAgent' => 0 );

  $meta->prop->{start_url} ||= $self->url;
  $self->url($meta->prop->{start_url});
  $self->url || Carp::croak('url is a required property');

  if($self->url =~ /^https:/ || $self->ssl)
  {
    $meta->add_requires('share' => 'LWP::Protocol::https' => 0 );
  }

  $meta->register_hook( fetch => sub {
    my($build, $url, %options) = @_;
    $url ||= $self->url;

    my @headers;
    if(my $headers = $options{http_headers})
    {
      if(ref $headers eq 'ARRAY')
      {
        @headers = @$headers;
      }
      else
      {
        $build->log("Fetch for $url with http_headers that is not an array reference");
      }
    }

    my $ua = LWP::UserAgent->new;
    $ua->env_proxy;
    my $res = $ua->get($url, @headers);

    my($protocol) = $url =~ /^([a-z]+):/;

    die "error fetching $url: @{[ $res->status_line ]}"
      unless $res->is_success;

    my($type, $charset) = $res->content_type_charset;
    my $base            = $res->base;
    my $filename        = $res->filename;

    if($type eq 'text/html')
    {
      return {
        type     => 'html',
        charset  => $charset,
        base     => "$base",
        content  => $res->decoded_content || $res->content,
        protocol => $protocol,
      };
    }
    elsif($type eq 'text/ftp-dir-listing')
    {
      return {
        type     => 'dir_listing',
        base     => "$base",
        content  => $res->decoded_content || $res->content,
        protocol => $protocol,
      };
    }
    else
    {
      return {
        type     => 'file',
        filename => $filename || 'downloadedfile',
        content  => $res->content,
        protocol => $protocol,
      };
    }

  });

  $self;
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::Fetch::LWP - Plugin for fetching files using LWP

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use alienfile;
 share {
   start_url 'http://ftp.gnu.org/gnu/make';
   plugin 'Fetch::LWP';
 };

=head1 DESCRIPTION

Note: in most case you will want to use L<Alien::Build::Plugin::Download::Negotiate>
instead.  It picks the appropriate fetch plugin based on your platform and environment.
In some cases you may need to use this plugin directly instead.

This fetch plugin fetches files and directory listings via the C<http> C<https>, C<ftp>,
C<file> protocol using L<LWP>.  If the URL specified uses the C<https> scheme, then
the required SSL modules will automatically be injected as requirements.  If your
initial URL is not C<https>, but you know that it will be needed on a subsequent
request you can use the ssl property below.

=head1 PROPERTIES

=head2 url

The initial URL to fetch.  This may be a directory listing (in HTML) or the final file.

=head2 ssl

If set to true, then the SSL modules required to make an C<https> connection will be
added as prerequisites.

=head1 SEE ALSO

L<Alien::Build::Plugin::Download::Negotiate>, L<Alien::Build>, L<alienfile>, L<Alien::Build::MM>, L<Alien>

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK9N%[{����&perl5/Alien/Build/Plugin/Fetch/Wget.pmnu��6�$package Alien::Build::Plugin::Fetch::Wget;

use strict;
use warnings;
use 5.008004;
use Alien::Build::Plugin;
use File::Temp qw( tempdir );
use Path::Tiny qw( path );
use File::Which qw( which );
use Capture::Tiny qw( capture capture_merged );
use File::chdir;
use List::Util qw( pairmap );

# ABSTRACT: Plugin for fetching files using wget
our $VERSION = '2.84'; # VERSION


sub _wget
{
  my $wget = defined $ENV{WGET} ? which($ENV{WGET}) : which('wget');
  return undef unless defined $wget;
  my $output = capture_merged { system $wget, '--help' };

  # The wget that BusyBox implements does not follow that same interface
  # as GNU wget and may not check ssl certs which is not good.
  return undef if $output =~ /BusyBox/;
  return $wget;
}

has wget_command => sub { _wget() };
has ssl => 0;

# when bootstrapping we have to specify this plugin as a prereq
# 1 is the default so that when this plugin is used directly
# you also get the prereq
has bootstrap_ssl => 1;

sub init
{
  my($self, $meta) = @_;

  $meta->add_requires('configure', 'Alien::Build::Plugin::Fetch::Wget' => '1.19')
    if $self->bootstrap_ssl;

  $meta->register_hook(
    fetch => sub {
      my($build, $url, %options) = @_;
      $url ||= $meta->prop->{start_url};

      my($scheme) = $url =~ /^([a-z0-9]+):/i;

      if($scheme eq 'http' || $scheme eq 'https')
      {
        local $CWD = tempdir( CLEANUP => 1 );

        my @headers;
        if(my $headers = $options{http_headers})
        {
          if(ref $headers eq 'ARRAY')
          {
            my @copy = @$headers;
            my %headers;
            while(@copy)
            {
              my $key = shift @copy;
              my $value = shift @copy;
              push @{ $headers{$key} }, $value;
            }
            @headers = pairmap { "--header=$a: @{[ join ', ', @$b ]}" } %headers;
          }
          else
          {
            $build->log("Fetch for $url with http_headers that is not an array reference");
          }
        }

        my($stdout, $stderr) = $self->_execute(
          $build,
          $self->wget_command,
          '-k', '--content-disposition', '-S',
          @headers,
          $url,
        );

        my($path) = path('.')->children;
        die "no file found after wget" unless $path;
        my($type) = $stderr =~ /Content-Type:\s*(.*?)$/m;
        $type =~ s/;.*$// if $type;
        if($type eq 'text/html')
        {
          return {
            type     => 'html',
            base     => $url,
            content  => scalar $path->slurp,
            protocol => $scheme,
          };
        }
        else
        {
          return {
            type     => 'file',
            filename => $path->basename,
            path     => $path->absolute->stringify,
            protocol => $scheme,
          };
        }
      }
      else
      {
        die "scheme $scheme is not supported by the Fetch::Wget plugin";
      }
    },
  ) if $self->wget_command;
}

sub _execute
{
  my($self, $build, @command) = @_;
  $build->log("+ @command");
  my($stdout, $stderr, $err) = capture {
    system @command;
    $?;
  };
  if($err)
  {
    chomp $stderr;
    $stderr = [split /\n/, $stderr]->[-1];
    die "error in wget fetch: $stderr";
  }
  ($stdout, $stderr);
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::Fetch::Wget - Plugin for fetching files using wget

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use alienfile;
 
 share {
   start_url 'https://www.openssl.org/source/';
   plugin 'Fetch::Wget';
 };

=head1 DESCRIPTION

B<WARNING>: This plugin is somewhat experimental at this time.

This plugin provides a fetch based on the C<wget> command.  It works with other fetch
plugins (that is, the first one which succeeds will be used).  Most of the time the best plugin
to use will be L<Alien::Build::Plugin::Download::Negotiate>, but for some SSL bootstrapping
it may be desirable to try C<wget> first.

Protocols supported: C<http>, C<https>

=head1 PROPERTIES

=head2 wget_command

The full path to the C<wget> command.  The default is usually correct.

=head2 ssl

Ignored by this plugin.  Provided for compatibility with some other fetch plugins.

=head1 SEE ALSO

=over 4

=item L<alienfile>

=item L<Alien::Build>

=back

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK9N%[J4Ԫ� � -perl5/Alien/Build/Plugin/Fetch/CurlCommand.pmnu��6�$package Alien::Build::Plugin::Fetch::CurlCommand;

use strict;
use warnings;
use 5.008004;
use Alien::Build::Plugin;
use File::Which qw( which );
use Path::Tiny qw( path );
use Capture::Tiny qw( capture );
use File::Temp qw( tempdir );
use List::Util 1.33 qw( any pairmap );
use File::chdir;

# ABSTRACT: Plugin for fetching files using curl
our $VERSION = '2.84'; # VERSION


sub curl_command
{
  defined $ENV{CURL} ? scalar which($ENV{CURL}) : scalar which('curl');
}

has ssl => 0;
has _see_headers => 0;
has '+url' => '';

# when bootstrapping we have to specify this plugin as a prereq
# 1 is the default so that when this plugin is used directly
# you also get the prereq
has bootstrap_ssl => 1;


sub protocol_ok
{
  my($class, $protocol) = @_;
  my $curl = $class->curl_command;
  return 0 unless defined $curl;
  my($out, $err, $exit) = capture {
    system $curl, '--version';
  };

  {
    # make sure curl supports the -J option.
    # CentOS 6 for example is recent enough
    # that it does not.  gh#147, gh#148, gh#149
    local $CWD = tempdir( CLEANUP => 1 );
    my $file1 = path('foo/foo.txt');
    $file1->parent->mkpath;
    $file1->spew("hello world\n");
    my $url = 'file://' . $file1->absolute;
    my($out, $err, $exit) = capture {
      system $curl, '-O', '-J', $url;
    };
    my $file2 = $file1->parent->child($file1->basename);
    unlink "$file1";
    unlink "$file2";
    rmdir($file1->parent);
    return 0 if $exit;
  }

  foreach my $line (split /\n/, $out)
  {
    if($line =~ /^Protocols:\s*(.*)\s*$/)
    {
      my %proto = map { $_ => 1 } split /\s+/, $1;
      return $proto{$protocol} if $proto{$protocol};
    }
  }
  return 0;
}

sub init
{
  my($self, $meta) = @_;

  $meta->prop->{start_url} ||= $self->url;
  $self->url($meta->prop->{start_url});
  $self->url || Carp::croak('url is a required property');

  $meta->add_requires('configure', 'Alien::Build::Plugin::Fetch::CurlCommand' => '1.19')
    if $self->bootstrap_ssl;

  $meta->register_hook(
    fetch => sub {
      my($build, $url, %options) = @_;
      $url ||= $self->url;

      my($scheme) = $url =~ /^([a-z0-9]+):/i;

      if($scheme =~ /^https?$/)
      {
        local $CWD = tempdir( CLEANUP => 1 );

        my @writeout = (
          "ab-filename     :%{filename_effective}",
          "ab-content_type :%{content_type}",
          "ab-url          :%{url_effective}",
        );

        $build->log("writeout: $_\\n") for @writeout;
        path('writeout')->spew(join("\\n", @writeout));

        my @headers;
        if(my $headers = $options{http_headers})
        {
          if(ref $headers eq 'ARRAY')
          {
            @headers = pairmap { -H => "$a: $b" } @$headers;
          }
          else
          {
            $build->log("Fetch for $url with http_headers that is not an array reference");
          }
        }

        my @command = (
          $self->curl_command,
          '-L', '-f', '-O', '-J',
          -w => '@writeout',
          @headers,
        );

        push @command, -D => 'head' if $self->_see_headers;

        push @command, $url;

        my($stdout, $stderr) = $self->_execute($build, @command);

        my %h = map { /^ab-(.*?)\s*:(.*)$/ ? ($1 => $2) : () } split /\n/, $stdout;

        if(-e 'head')
        {
          $build->log(" ~ $_ => $h{$_}") for sort keys %h;
          $build->log(" header: $_") for path('headers')->lines;
        }

        my($type) = split /;/, $h{content_type};

        if($type eq 'text/html')
        {
          return {
            type     => 'html',
            base     => $h{url},
            content  => scalar path($h{filename})->slurp,
            protocol => $scheme,
          };
        }
        else
        {
          return {
            type     => 'file',
            filename => $h{filename},
            path     => path($h{filename})->absolute->stringify,
            protocol => $scheme,
          };
        }
      }
#      elsif($scheme eq 'ftp')
#      {
#        if($url =~ m{/$})
#        {
#          my($stdout, $stderr) = $self->_execute($build, $self->curl_command, -l => $url);
#          chomp $stdout;
#          return {
#            type => 'list',
#            list => [
#              map { { filename => $_, url => "$url$_" } } sort split /\n/, $stdout,
#            ],
#          };
#        }
#
#        my $first_error;
#
#        {
#          local $CWD = tempdir( CLEANUP => 1 );
#
#          my($filename) = $url =~ m{/([^/]+)$};
#          $filename = 'unknown' if (! defined $filename) || ($filename eq '');
#          my($stdout, $stderr) = eval { $self->_execute($build, $self->curl_command, -o => $filename, $url) };
#          $first_error = $@;
#          if($first_error eq '')
#          {
#            return {
#              type     => 'file',
#              filename => $filename,
#              path     => path($filename)->absolute->stringify,
#            };
#          }
#        }
#
#        {
#          my($stdout, $stderr) = eval { $self->_execute($build, $self->curl_command, -l => "$url/") };
#          if($@ eq '')
#          {
#            chomp $stdout;
#            return {
#              type => 'list',
#              list => [
#                map { { filename => $_, url => "$url/$_" } } sort split /\n/, $stdout,
#              ],
#            };
#          };
#        }
#
#        $first_error ||= 'unknown error';
#        die $first_error;
#
#      }
      else
      {
        die "scheme $scheme is not supported by the Fetch::CurlCommand plugin";
      }

    },
  ) if $self->curl_command;

  $self;
}

sub _execute
{
  my($self, $build, @command) = @_;
  $build->log("+ @command");
  my($stdout, $stderr, $err) = capture {
    system @command;
    $?;
  };
  if($err)
  {
    chomp $stderr;
    $build->log($_) for split /\n/, $stderr;
    if($stderr =~ /Remote filename has no length/ && !!(any { /^-O$/ } @command))
    {
      my @new_command = map {
        /^-O$/ ? ( -o => 'index.html' ) : /^-J$/ ? () : ($_)
      } @command;
      return $self->_execute($build, @new_command);
    }
    die "error in curl fetch";
  }
  ($stdout, $stderr);
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::Fetch::CurlCommand - Plugin for fetching files using curl

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use alienfile;
 
 share {
   start_url 'https://www.openssl.org/source/';
   plugin 'Fetch::CurlCommand';
 };

=head1 DESCRIPTION

This plugin provides a fetch based on the C<curl> command.  It works with other fetch
plugins (that is, the first one which succeeds will be used).  Most of the time the best plugin
to use will be L<Alien::Build::Plugin::Download::Negotiate>, but for some SSL bootstrapping
it may be desirable to try C<curl> first.

Protocols supported: C<http>, C<https>

C<https> support requires that curl was built with SSL support.

=head1 PROPERTIES

=head2 curl_command

The full path to the C<curl> command.  The default is usually correct.

=head2 ssl

Ignored by this plugin.  Provided for compatibility with some other fetch plugins.

=head1 METHODS

=head2 protocol_ok

 my $bool = $plugin->protocol_ok($protocol);
 my $bool = Alien::Build::Plugin::Fetch::CurlCommand->protocol_ok($protocol);

=head1 SEE ALSO

=over 4

=item L<alienfile>

=item L<Alien::Build>

=back

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK9N%[�׳�'perl5/Alien/Build/Plugin/Fetch/Local.pmnu��6�$package Alien::Build::Plugin::Fetch::Local;

use strict;
use warnings;
use 5.008004;
use Alien::Build::Plugin;
use File::chdir;
use Path::Tiny ();

# ABSTRACT: Plugin for fetching a local file
our $VERSION = '2.84'; # VERSION


has '+url' => '';


has root => undef;


has ssl => 0;

sub init
{
  my($self, $meta) = @_;

  $meta->prop->{start_url} ||= $self->url;
  $self->url($meta->prop->{start_url} || 'patch');

  if($self->url =~ /^file:/)
  {
    $meta->add_requires('share' => 'URI'         => 0 );
    $meta->add_requires('share' => 'URI::file'   => 0 );
    $meta->add_requires('share' => 'URI::Escape' => 0 );
  }

  {
    my $root = $self->root;
    if(defined $root)
    {
      $root = Path::Tiny->new($root)->absolute->stringify;
    }
    else
    {
      $root = "$CWD";
    }
    $self->root($root);
  }

  $meta->register_hook( fetch => sub {
    my($build, $path, %options) = @_;

    $build->log("plugin Fetch::Local does not support http_headers option") if $options{http_headers};

    $path ||= $self->url;

    if($path =~ /^file:/)
    {
      my $root = URI::file->new($self->root);
      my $url = URI->new_abs($path, $root);
      $path = URI::Escape::uri_unescape($url->path);
      $path =~ s{^/([a-z]:)}{$1}i if $^O eq 'MSWin32';
    }

    $path = Path::Tiny->new($path)->absolute($self->root);

    if(-d $path)
    {
      return {
        type     => 'list',
        protocol => 'file',
        list     => [
          map { { filename => $_->basename, url => $_->stringify } }
          sort { $a->basename cmp $b->basename } $path->children,
        ],
      };
    }
    elsif(-f $path)
    {
      return {
        type     => 'file',
        filename => $path->basename,
        path     => $path->stringify,
        tmp      => 0,
        protocol => 'file',
      };
    }
    else
    {
      die "no such file or directory $path";
    }


  });
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::Fetch::Local - Plugin for fetching a local file

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use alienfile;
 share {
   start_url 'patch/libfoo-1.00.tar.gz';
   plugin 'Fetch::Local';
 };

=head1 DESCRIPTION

Note: in most case you will want to use L<Alien::Build::Plugin::Download::Negotiate>
instead.  It picks the appropriate fetch plugin based on your platform and environment.
In some cases you may need to use this plugin directly instead.

This fetch plugin fetches files from the local file system.  It is mostly useful if you
intend to bundle packages (as tarballs or zip files) with your Alien.  If you intend to
bundle a source tree, use L<Alien::Build::Plugin::Fetch::LocalDir>.

=head1 PROPERTIES

=head2 url

The initial URL to fetch.  This may be a C<file://> style URL, or just the path on the
local system.

=head2 root

The directory from which the URL should be relative.  The default is usually reasonable.

=head2 ssl

This property is for compatibility with other fetch plugins, but is not used.

=head1 SEE ALSO

=over 4

=item L<Alien::Build::Plugin::Download::Negotiate>

=item L<Alien::Build::Plugin::Fetch::LocalDir>

=item L<Alien::Build>

=item L<alienfile>

=item L<Alien::Build::MM>

=item L<Alien>

=back

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK9N%[�t_��*perl5/Alien/Build/Plugin/Fetch/HTTPTiny.pmnu��6�$package Alien::Build::Plugin::Fetch::HTTPTiny;

use strict;
use warnings;
use 5.008004;
use Alien::Build::Plugin;
use File::Basename ();
use Alien::Build::Util qw( _ssl_reqs );
use Carp ();

# ABSTRACT: Plugin for fetching files using HTTP::Tiny
our $VERSION = '2.84'; # VERSION


has '+url' => '';


has ssl => 0;

# ignored for compatability
has bootstrap_ssl => 1;

sub init
{
  my($self, $meta) = @_;

  $meta->add_requires('share' => 'HTTP::Tiny'  => '0.044' );
  $meta->add_requires('share' => 'URI'         => '0'     );
  $meta->add_requires('share' => 'Mozilla::CA' => '0'     );

  $meta->prop->{start_url} ||= $self->url;
  $self->url($meta->prop->{start_url});
  $self->url || Carp::croak('url is a required property');

  if($self->url =~ /^https:/ || $self->ssl)
  {
    my $reqs = _ssl_reqs;
    foreach my $mod (sort keys %$reqs)
    {
      $meta->add_requires('share' => $mod => $reqs->{$mod});
    }
  }

  $meta->register_hook( fetch => sub {
    my($build, $url, %options) = @_;
    $url ||= $self->url;

    $url = URI->new($url) unless ref($url) && $url->isa('URI');

    my %headers;
    if(my $headers = $options{http_headers})
    {
      if(ref $headers eq 'ARRAY')
      {
        my @headers = @$headers;
        while(@headers)
        {
          my $key = shift @headers;
          my $value = shift @headers;
          unless(defined $key && defined $value)
          {
            $build->log("Fetch for $url with http_headers contains undef key or value");
            next;
          }
          push @{ $headers{$key} }, $value;
        }
      }
      else
      {
        $build->log("Fetch for $url with http_headers that is not an array reference");
      }
    }

    my $ua = HTTP::Tiny->new(
      agent      => "Alien-Build/@{[ $Alien::Build::VERSION || 'dev' ]} ",
      verify_SSL => $build->download_rule =~ /encrypt/ ? 1 : 0,
    );
    my $res = $ua->get($url, { headers => \%headers });

    unless($res->{success})
    {
      my $status = $res->{status} || '---';
      my $reason = $res->{reason} || 'unknown';

      $build->log("$status $reason fetching $url");
      if($status == 599)
      {
        $build->log("exception: $_") for split /\n/, $res->{content};

        my($can_ssl, $why_ssl) = HTTP::Tiny->can_ssl;
        if(! $can_ssl)
        {
          if($res->{redirects}) {
            foreach my $redirect (@{ $res->{redirects} })
            {
              if(defined $redirect->{headers}->{location} && $redirect->{headers}->{location} =~ /^https:/)
              {
                $build->log("An attempt at a SSL URL https was made, but your HTTP::Tiny does not appear to be able to use https.");
                $build->log("Please see: https://metacpan.org/pod/Alien::Build::Manual::FAQ#599-Internal-Exception-errors-downloading-packages-from-the-internet");
              }
            }
          }
        }
      }

      die "error fetching $url: $status $reason";
    }

    my($type) = split /;/, $res->{headers}->{'content-type'};
    $type = lc $type;
    my $base            = URI->new($res->{url});
    my $filename        = File::Basename::basename do { my $name = $base->path; $name =~ s{/$}{}; $name };

    # TODO: this doesn't get exercised by t/bin/httpd
    if(my $disposition = $res->{headers}->{"content-disposition"})
    {
      # Note: from memory without quotes does not match the spec,
      # but many servers actually return this sort of value.
      if($disposition =~ /filename="([^"]+)"/ || $disposition =~ /filename=([^\s]+)/)
      {
        $filename = $1;
      }
    }

    if($type eq 'text/html')
    {
      return {
        type     => 'html',
        base     => $base->as_string,
        content  => $res->{content},
        protocol => $url->scheme,
      };
    }
    else
    {
      return {
        type     => 'file',
        filename => $filename || 'downloadedfile',
        content  => $res->{content},
        protocol => $url->scheme,
      };
    }

  });

  $self;
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::Fetch::HTTPTiny - Plugin for fetching files using HTTP::Tiny

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use alienfile;
 share {
   start_url 'http://ftp.gnu.org/gnu/make';
   plugin 'Fetch::HTTPTiny';
 };

=head1 DESCRIPTION

Note: in most case you will want to use L<Alien::Build::Plugin::Download::Negotiate>
instead.  It picks the appropriate fetch plugin based on your platform and environment.
In some cases you may need to use this plugin directly instead.

This fetch plugin fetches files and directory listings via the C<http> and C<https>
protocol using L<HTTP::Tiny>.  If the URL specified uses the C<https> scheme, then
the required SSL modules will automatically be injected as requirements.  If your
initial URL is not C<https>, but you know that it will be needed on a subsequent
request you can use the ssl property below.

=head1 PROPERTIES

=head2 url

The initial URL to fetch.  This may be a directory listing (in HTML) or the final file.

=head2 ssl

If set to true, then the SSL modules required to make an C<https> connection will be
added as prerequisites.

=head1 SEE ALSO

L<Alien::Build::Plugin::Download::Negotiate>, L<Alien::Build>, L<alienfile>, L<Alien::Build::MM>, L<Alien>

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK9N%[X;�X��(perl5/Alien/Build/Plugin/Fetch/NetFTP.pmnu��6�$package Alien::Build::Plugin::Fetch::NetFTP;

use strict;
use warnings;
use 5.008004;
use Alien::Build::Plugin;
use Carp ();
use File::Temp ();
use Path::Tiny qw( path );

# ABSTRACT: Plugin for fetching files using Net::FTP
our $VERSION = '2.84'; # VERSION


has '+url' => '';


has ssl => 0;


has passive => 0;

sub init
{
  my($self, $meta) = @_;

  $meta->prop->{start_url} ||= $self->url;
  $self->url($meta->prop->{start_url});
  $self->url || Carp::croak('url is a required property');

  $meta->add_requires('share' => 'Net::FTP' => 0 );
  $meta->add_requires('share' => 'URI' => 0 );
  $meta->add_requires('share' => 'Alien::Build::Plugin::Fetch::NetFTP' => '0.61')
    if $self->passive;

  $meta->register_hook( fetch => sub {
    my($build, $url, %options) = @_;
    $url ||= $self->url;

    $build->log("plugin Fetch::NetFTP does not support http_headers option") if $options{http_headers};

    $url = URI->new($url);

    die "Fetch::NetFTP does not support @{[ $url->scheme ]}"
      unless $url->scheme eq 'ftp';

    $build->log("trying passive mode FTP first") if $self->passive;
    my $ftp = _ftp_connect($url, $self->passive);

    my $path = $url->path;

    unless($path =~ m!/$!)
    {
      my(@parts) = split /\//, $path;
      my $filename = pop @parts;
      my $dir      = join '/', @parts;

      my $path = eval {
        $ftp->cwd($dir) or die;
        my $tdir = File::Temp::tempdir( CLEANUP => 1);
        my $path = path("$tdir/$filename")->stringify;

        unless(eval { $ftp->get($filename, $path) }) # NAT problem? try to use passive mode
        {
          $ftp->quit;

          $build->log("switching to @{[ $self->passive ? 'active' : 'passive' ]} mode");
          $ftp = _ftp_connect($url, !$self->passive);

          $ftp->cwd($dir) or die;

          $ftp->get($filename, $path) or die;
        }

        $path;
      };

      if(defined $path)
      {
        return {
          type     => 'file',
          filename => $filename,
          path     => $path,
          protocol => 'ftp',
        };
      }

      $path .= "/";
    }

    $ftp->quit;
    $ftp = _ftp_connect($url, $self->passive);
    $ftp->cwd($path) or die "unable to fetch $url as either a directory or file";

    my $list = eval { $ftp->ls };
    unless(defined $list) # NAT problem? try to use passive mode
    {
      $ftp->quit;

      $build->log("switching to @{[ $self->passive ? 'active' : 'passive' ]} mode");
      $ftp = _ftp_connect($url, !$self->passive);

      $ftp->cwd($path) or die "unable to fetch $url as either a directory or file";

      $list = $ftp->ls;

      die "cannot list directory $path on $url" unless defined $list;
    }

    die "no files found at $url" unless @$list;

    $path .= '/' unless $path =~ /\/$/;

    return {
      type     => 'list',
      protocol => 'ftp',
      list     => [
        map {
          my $filename = $_;
          my $furl = $url->clone;
          $furl->path($path . $filename);
          my %h = (
            filename => $filename,
            url      => $furl->as_string,
          );
          \%h;
        } sort @$list,
      ],
    };

  });

  $self;
}

sub _ftp_connect {
  my $url = shift;
  my $is_passive = shift || 0;

  my $ftp = Net::FTP->new(
    $url->host, Port =>$url->port, Passive =>$is_passive,
  ) or die "error fetching $url: $@";

  $ftp->login($url->user, $url->password)
    or die "error on login $url: @{[ $ftp->message ]}";

  $ftp->binary;

  $ftp;
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::Fetch::NetFTP - Plugin for fetching files using Net::FTP

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use alienfile;
 share {
   start_url 'ftp://ftp.gnu.org/gnu/make';
   plugin 'Fetch::NetFTP';
 };

=head1 DESCRIPTION

Note: in most case you will want to use L<Alien::Build::Plugin::Download::Negotiate>
instead.  It picks the appropriate fetch plugin based on your platform and environment.
In some cases you may need to use this plugin directly instead.

This fetch plugin fetches files and directory listings via the C<ftp>, protocol using
L<Net::FTP>.

=head1 PROPERTIES

=head2 url

The initial URL to fetch.  This may be a directory or the final file.

=head2 ssl

This property is for compatibility with other fetch plugins, but is not used.

=head2 passive

If set to true, try passive mode FIRST.  By default it will try an active mode, then
passive mode.

=head1 SEE ALSO

L<Alien::Build::Plugin::Download::Negotiate>, L<Alien::Build>, L<alienfile>, L<Alien::Build::MM>, L<Alien>

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK9N%[Hk����!perl5/Alien/Build/Plugin/Core.podnu��6�$# PODNAME: Alien::Build::Plugin::Core
# ABSTRACT: Core Alien::Build plugins
# VERSION

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::Core - Core Alien::Build plugins

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use alienfile;
 # core plugins are already loaded

=head1 DESCRIPTION

Core plugins are special plugins that are always loaded, usually first.

=over 4

=item L<Alien::Build::Plugin::Core::CleanInstall>

=item L<Alien::Build::Plugin::Core::Download>

This contains the default machinery for downloading packages, if no
other download plugin or commands are provided.

=item L<Alien::Build::Plugin::Core::FFI>

=item L<Alien::Build::Plugin::Core::Gather>

=item L<Alien::Build::Plugin::Core::Legacy>

Add interoperability with L<Alien::Base::ModuleBuild>

=item L<Alien::Build::Plugin::Core::Override>

The machinery which allows you to override the type of install
with the C<ALIEN_INSTALL_TYPE> environment variable.

=item L<Alien::Build::Plugin::Core::Setup>

=item L<Alien::Build::Plugin::Core::Tail>

=back

=head1 SEE ALSO

L<Alien::Build>, L<Alien::Build::Plugin>

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK9N%[Y����#perl5/Alien/Build/Plugin/Digest.podnu��6�$# PODNAME: Alien::Build::Plugin::Digest
# ABSTRACT: Fetch Alien::Digest plugins
# VERSION

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::Digest - Fetch Alien::Digest plugins

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use alienfile;
 share {
   start_url 'http://ftp.gnu.org/gnu/make/make-3.75.tar.gz';
   plugin 'Digest' => [ SHA256 => '2bc876304905aee78abf0f7163ba55a2efcec803034f75c75d1b94650c36aba7';
   plugin 'Download';
 };

=head1 DESCRIPTION

Digest plugins checks the cryptographic signatures of downloaded files.
Typically you will probably want to use SHA256 via the
L<Digest Negotiator plugin|Alien::Build::Plugin::Digest::Negotiate>.

=over 4

=item L<Alien::Build::Plugin::Digest::Negotiate>

Negotiate the most appropriate plugin to calculate digest.

=item L<Alien::Build::Plugin::Digest::SHA>

Use the XS based L<Digest::SHA> for computing SHA digests.  This is the default since
L<Digest::SHA> comes with recent versions of Perl.

=item L<Alien::Build::Plugin::Digest::SHAPP>

Use the pure-perl based L<Digest::SHA::PurePerl> for computing SHA digests.

=back

=head1 SEE ALSO

L<Alien::Build>, L<Alien::Build::Plugin>

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK9N%[��j
j
"perl5/Alien/Build/Plugin/Fetch.podnu��6�$# PODNAME: Alien::Build::Plugin::Fetch
# ABSTRACT: Fetch Alien::Build plugins
# VERSION

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::Fetch - Fetch Alien::Build plugins

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use alienfile;
 share {
   start_url 'http://ftp.gnu.org/gnu/make';
   plugin 'Download';
 };

=head1 DESCRIPTION

Fetch plugins retrieve single resources from the internet.  The difference
between a Fetch plugin and a Download plugin is that Download
plugin may fetch several resources from the internet (usually using
a Fetch plugin), before finding the final archive.  Normally you
will not need to use Fetch plugins directly but should instead
use the L<Alien::Build::Plugin::Download::Negotiate> plugin, which
will pick the best plugins for your given URL.

=over 4

=item L<Alien::Build::Plugin::Fetch::CurlCommand>

Fetch using the C<curl> command.

=item L<Alien::Build::Plugin::Fetch::HTTPTiny>

Fetch using L<HTTP::Tiny>.

=item L<Alien::Build::Plugin::Fetch::LWP>

Fetch using L<LWP::UserAgent>.

=item L<Alien::Build::Plugin::Fetch::Local>

Fetch from a local file.  This is typically used to bundle packages with your L<Alien>.

=item L<Alien::Build::Plugin::Fetch::LocalDir>

Fetch from a local directory.  This is typically used to bundle packages with your L<Alien>.

=item L<Alien::Build::Plugin::Fetch::NetFTP>

Fetch using L<Net::FTP>.  Use of FTP should be discouraged as of this writing (August 2022).

=item L<Alien::Build::Plugin::Fetch::Wget>

Fetch using C<wget>.

=back

=head1 SEE ALSO

L<Alien::Build>, L<Alien::Build::Plugin>

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK9N%[-���E
E
1perl5/Alien/Build/Plugin/Gather/IsolateDynamic.pmnu��6�$package Alien::Build::Plugin::Gather::IsolateDynamic;

use strict;
use warnings;
use 5.008004;
use Alien::Build::Plugin;
use Path::Tiny ();
use Alien::Build::Util qw( _destdir_prefix );
use File::Copy ();

# ABSTRACT: Plugin to gather dynamic libraries into a separate directory
our $VERSION = '2.84'; # VERSION


sub init
{
  my($self, $meta) = @_;

  # plugin was introduced in 0.42, but had a bug which was fixed in 0.48
  $meta->add_requires('share' => 'Alien::Build::Plugin::Gather::IsolateDynamic' => '0.48' );

  $meta->after_hook(
    gather_share => sub {
      my($build) = @_;
      $build->log("Isolating dynamic libraries ...");

      my $install_root;
      if($build->meta_prop->{destdir})
      {
        my $destdir = $ENV{DESTDIR};
        $install_root = Path::Tiny->new(_destdir_prefix($ENV{DESTDIR}, $build->install_prop->{prefix}));
      }
      else
      {
        $install_root = Path::Tiny->new($build->install_prop->{stage});
      }

      foreach my $dir (map { $install_root->child($_) } qw( bin lib ))
      {
        next unless -d $dir;
        foreach my $from ($dir->children)
        {
          next unless $from->basename =~ /\.so/
          ||          $from->basename =~ /\.(dylib|bundle|la|dll|dll\.a)$/;
          my $to = $install_root->child('dynamic', $from->basename);
          $to->parent->mkpath;
          unlink "$to" if -e $to;
          $build->log("move @{[ $from->parent->basename ]}/@{[ $from->basename ]} => dynamic/@{[ $to->basename ]}");
          File::Copy::move("$from", "$to") || die "unable to move $from => $to $!";
        }
      }

      $build->log("                            Done!");
    },
  );
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::Gather::IsolateDynamic - Plugin to gather dynamic libraries into a separate directory

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use alienfile;
 plugin 'Gather::IsolateDynamic';

=head1 DESCRIPTION

This plugin moves dynamic libraries from the C<lib> and C<bin> directories and puts them in
their own C<dynamic> directory.  This allows them to be used by FFI modules, but to be ignored
by XS modules.

This plugin provides the equivalent functionality of the C<alien_isolate_dynamic> attribute
from L<Alien::Base::ModuleBuild>.

=head1 SEE ALSO

L<Alien::Build>, L<alienfile>

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK9N%[7j����-perl5/Alien/Build/Plugin/Prefer/BadVersion.pmnu��6�$package Alien::Build::Plugin::Prefer::BadVersion;

use strict;
use warnings;
use 5.008004;
use Alien::Build::Plugin;
use Carp ();

# ABSTRACT: Plugin to filter out known bad versions
our $VERSION = '2.84'; # VERSION


has '+filter' => sub { Carp::croak("The filter property is required for the Prefer::BadVersion plugin") };

sub init
{
  my($self, $meta) = @_;

  $meta->add_requires('configure', __PACKAGE__, '1.05');

  my $filter;

  if(ref($self->filter) eq '')
  {
    my $string = $self->filter;
    $filter = sub {
      my($file) = @_;
      $file->{version} ne $string;
    };
  }
  elsif(ref($self->filter) eq 'ARRAY')
  {
    my %filter = map { $_ => 1 } @{ $self->filter };
    $filter = sub {
      my($file) = @_;
      ! $filter{$file->{version}};
    };
  }
  elsif(ref($self->filter) eq 'CODE')
  {
    my $code = $self->filter;
    $filter = sub { ! $code->($_[0]) };
  }
  else
  {
    Carp::croak("unknown filter type for Prefer::BadVersion");
  }

  $meta->around_hook(
    prefer => sub {
      my($orig, $build, @therest) = @_;
      my $res1 = $orig->($build, @therest);
      return $res1 unless $res1->{type} eq 'list';

      return {
        type => 'list',
        list => [
          grep { $filter->($_) } @{ $res1->{list} }
        ],
      };
    },
  );
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::Prefer::BadVersion - Plugin to filter out known bad versions

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use alienfile;
 plugin 'Prefer::BadVersion' => '1.2.3';

=head1 DESCRIPTION

This plugin allows you to easily filter out known bad versions of libraries in a share install.
It doesn't affect a system install at all.  You need a Prefer plugin that filters and sorts files
first.  You may specify the filter in one of three ways:

=over

=item as a string

Filter out any files that match the given version.

 use alienfile;
 plugin 'Prefer::BadVersion' => '1.2.3';

=item as an array

Filter out all files that match any of the given versions.

 use alienfile;
 plugin 'Prefer::BadVersion' => [ '1.2.3', '1.2.4' ];

=item as a code reference

Filter out any files return a true value.

 use alienfile;
 plugin 'Prefer::BadVersion' => sub {
   my($file) = @_;
   $file->{version} eq '1.2.3'; # same as the string version above
 };

=back

This plugin can also be used to filter out known bad versions of a library on just one platform.
For example, if you know that version 1.2.3 if bad on windows, but okay on other platforms:

 use alienfile;
 plugin 'Prefer::BadVersion' => '1.2.3' if $^O eq 'MSWin32';

=head1 PROPERTIES

=head2 filter

Filter out entries that match the filter.

=head1 CAVEATS

If you are using the string or array mode, then you need an existing Prefer plugin that sets the
version number for each file candidate, such as L<Alien::Build::Plugin::Prefer::SortVersions>.

Unless you want to exclude the latest version from a share install, this plugin isn't really
that useful.  It has no effect on system installs, which may not be obvious at first.

=head1 SEE ALSO

=over 4

=item L<alienfile>

=item L<Alien::Build>

=item L<Alien::Build::Plugin::Prefer::SortVersions>

=back

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK9N%[át���.perl5/Alien/Build/Plugin/Prefer/GoodVersion.pmnu��6�$package Alien::Build::Plugin::Prefer::GoodVersion;

use strict;
use warnings;
use 5.008004;
use Alien::Build::Plugin;
use Carp ();

# ABSTRACT: Plugin to filter known good versions
our $VERSION = '2.84'; # VERSION


has '+filter' => sub { Carp::croak("The filter property is required for the Prefer::GoodVersion plugin") };

sub init
{
  my($self, $meta) = @_;

  $meta->add_requires('configure', __PACKAGE__, '1.44');

  my $filter;

  if(ref($self->filter) eq '')
  {
    my $string = $self->filter;
    $filter = sub {
      my($file) = @_;
      $file->{version} eq $string;
    };
  }
  elsif(ref($self->filter) eq 'ARRAY')
  {
    my %filter = map { $_ => 1 } @{ $self->filter };
    $filter = sub {
      my($file) = @_;
      !! $filter{$file->{version}};
    };
  }
  elsif(ref($self->filter) eq 'CODE')
  {
    my $code = $self->filter;
    $filter = sub { !! $code->($_[0]) };
  }
  else
  {
    Carp::croak("unknown filter type for Prefer::GoodVersion");
  }

  $meta->around_hook(
    prefer => sub {
      my($orig, $build, @therest) = @_;
      my $res1 = $orig->($build, @therest);
      return $res1 unless $res1->{type} eq 'list';

      return {
        type => 'list',
        list => [
          grep { $filter->($_) } @{ $res1->{list} }
        ],
      };
    },
  );
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::Prefer::GoodVersion - Plugin to filter known good versions

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use alienfile;
 plugin 'Prefer::GoodVersion' => '1.2.3';

=head1 DESCRIPTION

This plugin allows you to specify one or more good versions of a library.  This doesn't affect
a system install at all.  This plugin does the opposite of the C<Prefer::BadVersion> plugin.
You need need a Prefer plugin that filters and sorts files first.  You may specify the filter
in one of three ways:

=over

=item as a string

Filter any files that match the given version.

 use alienfile;
 plugin 'Prefer::GoodVersion' => '1.2.3';

=item as an array

Filter all files that match any of the given versions.

 use alienfile;
 plugin 'Prefer::GoodVersion' => [ '1.2.3', '1.2.4' ];

=item as a code reference

Filter any files return a true value.

 use alienfile;
 plugin 'Prefer::GoodVersion' => sub {
   my($file) = @_;
   $file->{version} eq '1.2.3'; # same as the string version above
 };

=back

This plugin can also be used to filter known good versions of a library on just one platform.
For example, if you know that version 1.2.3 if good on windows, but the default logic is fine
on other platforms:

 use alienfile;
 plugin 'Prefer::GoodVersion' => '1.2.3' if $^O eq 'MSWin32';

=head1 PROPERTIES

=head2 filter

Filter entries that match the filter.

=head1 CAVEATS

If you are using the string or array mode, then you need an existing Prefer plugin that sets the
version number for each file candidate, such as L<Alien::Build::Plugin::Prefer::SortVersions>.

Unless you want to exclude the latest version from a share install, this plugin isn't really
that useful.  It has no effect on system installs, which may not be obvious at first.

=head1 SEE ALSO

=over 4

=item L<alienfile>

=item L<Alien::Build>

=item L<Alien::Build::Plugin::Prefer::SortVersions>

=back

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK9N%[xotrgg/perl5/Alien/Build/Plugin/Prefer/SortVersions.pmnu��6�$package Alien::Build::Plugin::Prefer::SortVersions;

use strict;
use warnings;
use 5.008004;
use Alien::Build::Plugin;

# ABSTRACT: Plugin to sort candidates by most recent first
our $VERSION = '2.84'; # VERSION


has 'filter'   => undef;


has '+version' => qr/([0-9](?:[0-9\.]*[0-9])?)/;

sub init
{
  my($self, $meta) = @_;

  $meta->add_requires('share' => 'Sort::Versions' => 0);

  $meta->register_hook( prefer => sub {
    my(undef, $res) = @_;

    my $cmp = sub {
      my($A,$B) = map { ($_ =~ $self->version)[0] } @_;
      Sort::Versions::versioncmp($B,$A);
    };

    my @list = sort { $cmp->($a->{filename}, $b->{filename}) }
               map {
                 ($_->{version}) = $_->{filename} =~ $self->version;
                 $_ }
               grep { $_->{filename} =~ $self->version }
               grep { defined $self->filter ? $_->{filename} =~ $self->filter : 1 }
               @{ $res->{list} };

    return {
      type => 'list',
      list => \@list,
    };
  });
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Plugin::Prefer::SortVersions - Plugin to sort candidates by most recent first

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use alienfile;
 
 plugin 'Prefer::SortVersions';

=head1 DESCRIPTION

Note: in most case you will want to use L<Alien::Build::Plugin::Download::Negotiate>
instead.  It picks the appropriate fetch plugin based on your platform and environment.
In some cases you may need to use this plugin directly instead.

This Prefer plugin sorts the packages that were retrieved from a dir listing, either
directly from a Fetch plugin, or from a Decode plugin.  It Returns a listing with the
items sorted from post preferable to least, and filters out any undesirable candidates.

This plugin updates the file list to include the versions that are extracted, so they
can be used by other plugins, such as L<Alien::Build::Plugin::Prefer::BadVersion>.

=head1 PROPERTIES

=head2 filter

This is a regular expression that lets you filter out files that you do not
want to consider downloading.  For example, if the directory listing contained
tarballs and readme files like this:

 foo-1.0.0.tar.gz
 foo-1.0.0.readme

You could specify a filter of C<qr/\.tar\.gz$/> to make sure only tarballs are
considered for download.

=head2 version

Regular expression to parse out the version from a filename.  The regular expression
should store the result in C<$1>.  The default C<qr/([0-9\.]+)/> is frequently
reasonable.

=head1 SEE ALSO

L<Alien::Build::Plugin::Download::Negotiate>, L<Alien::Build>, L<alienfile>, L<Alien::Build::MM>, L<Alien>

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK9N%[�
g�DDperl5/Alien/Build/Util.pmnu��6�$package Alien::Build::Util;

use strict;
use warnings;
use 5.008004;
use Exporter qw( import );
use Path::Tiny qw( path );
use Config;

# ABSTRACT: Private utility functions for Alien::Build
our $VERSION = '2.84'; # VERSION


our @EXPORT_OK = qw( _mirror _dump _destdir_prefix _perl_config _ssl_reqs _has_ssl );

# usage: _mirror $source_directory, $dest_direction, \%options
#
# options:
#  - filter -> regex for files that should match
#  - empty_directory -> if true, create all directories, including empty ones.
#  - verbose -> turn on verbosity

sub _mirror
{
  my($src_root, $dst_root, $opt) = @_;
  ($src_root, $dst_root) = map { path($_) } ($src_root, $dst_root);
  $opt ||= {};

  require Alien::Build;
  require File::Find;
  require File::Copy;

  File::Find::find({
    wanted => sub {
      next unless -e $File::Find::name;
      my $src = path($File::Find::name)->relative($src_root);
      return if $opt->{filter} && "$src" !~ $opt->{filter};
      return if "$src" eq '.';
      my $dst = $dst_root->child("$src");
      $src = $src->absolute($src_root);
      if(-l "$src")
      {
        unless(-d $dst->parent)
        {
          Alien::Build->log("mkdir -p @{[ $dst->parent ]}") if $opt->{verbose};
          $dst->parent->mkpath;
        }
        # TODO: rmtree if a directory?
        if(-e "$dst")
        { unlink "$dst" }
        my $target = readlink "$src";
        Alien::Build->log("ln -s $target $dst") if $opt->{verbose};
        symlink($target, $dst) || die "unable to symlink $target => $dst";
      }
      elsif(-d "$src")
      {
        if($opt->{empty_directory})
        {
          unless(-d $dst)
          {
            Alien::Build->log("mkdir $dst") if $opt->{verbose};
            mkdir($dst) || die "unable to create directory $dst: $!";
          }
        }
      }
      elsif(-f "$src")
      {
        unless(-d $dst->parent)
        {
          Alien::Build->log("mkdir -p @{[ $dst->parent ]}") if $opt->{verbose};
          $dst->parent->mkpath;
        }
        # TODO: rmtree if a directory?
        if(-e "$dst")
        { unlink "$dst" }
        Alien::Build->log("cp $src $dst") if $opt->{verbose};
        File::Copy::cp("$src", "$dst") || die "copy error $src => $dst: $!";
        if($] < 5.012 && -x "$src" && $^O ne 'MSWin32')
        {
          # apparently Perl 5.8 and 5.10 do not preserver perms
          my $mode = [stat "$src"]->[2] & oct(777);
          eval { chmod $mode, "$dst" };
        }
      }
    },
    no_chdir => 1,
  }, "$src_root");

  ();
}

sub _dump
{
  if(eval { require YAML })
  {
    return YAML::Dump(@_);
  }
  else
  {
    require Data::Dumper;
    return Data::Dumper::Dumper(@_);
  }
}

sub _destdir_prefix
{
  my($destdir, $prefix) = @_;
  $prefix =~ s{^/?([a-z]):}{$1}i if $^O eq 'MSWin32';
  path($destdir)->child($prefix)->stringify;
}

sub _perl_config
{
  my($key) = @_;
  $Config{$key};
}

sub _ssl_reqs
{
  return {
    'Net::SSLeay' => '1.49',
    'IO::Socket::SSL' => '1.56',
  };
}

sub _has_ssl
{
  my %reqs = %{ _ssl_reqs() };
  eval {
    require Net::SSLeay;
    die "need Net::SSLeay $reqs{'Net::SSLeay'}" unless Net::SSLeay->VERSION($reqs{'Net::SSLeay'});
    require IO::Socket::SSL;
    die "need IO::Socket::SSL $reqs{'IO::Socket::SSL'}" unless IO::Socket::SSL->VERSION($reqs{'IO::Socket::SSL'});
  };
  $@ eq '';
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Util - Private utility functions for Alien::Build

=head1 VERSION

version 2.84

=head1 DESCRIPTION

This module contains some private utility functions used internally by
L<Alien::Build>.  It shouldn't be used by any distribution other than
C<Alien-Build>.  That includes L<Alien::Build> plugins that are not
part of the L<Alien::Build> core.

You have been warned.  The functionality within may be removed at
any time!

=head1 SEE ALSO

L<Alien::Build>

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK9N%[�x&�	�	perl5/Alien/Build/Manual.podnu��6�$# PODNAME: Alien::Build::Manual
# ABSTRACT: The Alien::Build Manual
# VERSION

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Manual - The Alien::Build Manual

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 perldoc Alien::Build::Manual::Alien
 perldoc Alien::Build::Manual::AlienAuthor
 perldoc Alien::Build::Manual::AlienUser
 perldoc Alien::Build::Manual::Contributing
 perldoc Alien::Build::Manual::FAQ
 perldoc Alien::Build::Manual::PluginAuthor

=head1 DESCRIPTION

L<Alien::Build> comes with a number of manuals that are useful depending on how you
are using L<Alien>.

=over 4

=item L<Alien::Build::Manual::Alien>

General alien author documentation.

=item L<Alien::Build::Manual::AlienAuthor>

Alien author documentation.

=item L<Alien::Build::Manual::AlienUser>

Alien user documentation.

=item L<Alien::Build::Manual::Contributing>

Overly-detailed contributing guide.

=item L<Alien::Build::Manual::FAQ>

Frequently Asked Questions about L<Alien::Build>.

=item L<Alien::Build::Manual::PluginAuthor>

L<Alien::Build> plugin author documentation — or how to extend L<Alien::Build> with the plugin system.

=item L<Alien::Build::Manual::Security>

Documents some of the challenges and configuration tools related to security of L<Alien>s.

=back

=head1 SEE ALSO

=over 4

=item L<Alien::Base>

=item L<Alien::Build>

=item L<alienfile>

=back

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK9N%[�J	��perl5/Alien/Build/Log.pmnu��6�$package Alien::Build::Log;

use strict;
use warnings;
use 5.008004;
use Carp ();

# ABSTRACT: Alien::Build logging
our $VERSION = '2.84'; # VERSION


my $log_class;
my $self;

sub new
{
  my($class) = @_;
  Carp::croak("Cannot instantiate base class") if $class eq 'Alien::Build::Log';
  return bless {}, $class;
}


sub default
{
  $self || do {
    my $class = $log_class || $ENV{ALIEN_BUILD_LOG} || 'Alien::Build::Log::Default';
    unless(eval { $class->can('new') })
    {
      my $pm = "$class.pm";
      $pm =~ s/::/\//g;
      require $pm;
    }
    $class->new;
  }
}


sub set_log_class
{
  my(undef, $class) = @_;
  return if defined $class && ($class eq ($log_class || ''));
  $log_class = $class;
  undef $self;
}


sub log
{
  Carp::croak("AB Log base class");
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build::Log - Alien::Build logging

=head1 VERSION

version 2.84

=head1 SYNOPSIS

Create your custom log class:

 package Alien::Build::Log::MyLog;
 
 use parent qw( Alien::Build::Log );
 
 sub log
 {
   my(undef, %opt)  = @_;
   my($package, $filename, $line) = @{ $opt{caller} };
   my $message = $opt{message};
 
   ...;
 }

override log class:

 % env ALIEN_BUILD_LOG=Alien::Build::Log::MyLog cpanm Alien::libfoo

=head1 DESCRIPTION

=head1 CONSTRUCTORS

=head2 new

 my $log = Alien::Build::Log->new;

Create an instance of the log class.

=head2 default

 my $log = Alien::Build::Log->default;

Return singleton instance of log class used by L<Alien::Build>.

=head1 METHODS

=head2 set_log_class

 Alien::Build::Log->set_log_class($class);

Set the default log class used by L<Alien::Build>.  This method will also reset the
default instance used by L<Alien::Build>.  If not specified, L<Alien::Build::Log::Default>
will be used.

=head2 log

 $log->log(%options);

Overridable method which does the actual work of the log class.  Options:

=over 4

=item caller

Array references containing the package, file and line number of where the
log was called.

=item message

The message to log.

=back

=head1 ENVIRONMENT

=over 4

=item ALIEN_BUILD_LOG

The default log class used by L<Alien::Build>.

=back

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK9N%[b'e�		perl5/Alien/Role.pmnu��6�$package Alien::Role;

use strict;
use warnings;
use 5.008004;

# ABSTRACT: Extend Alien::Base with roles!
our $VERSION = '2.84'; # VERSION


1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Role - Extend Alien::Base with roles!

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 package Alien::libfoo;
 
 use parent qw( Alien::Base );
 use Role::Tiny::With qw( with );
 
 with 'Alien::Role::Dino';
 
 1;

=head1 DESCRIPTION

The C<Alien::Role> namespace is intended for writing roles that can be
applied to L<Alien::Base> to extend its functionality.  You could of
course write subclasses that extend L<Alien::Base>, but then you have
to either stick with just one subclass or deal with multiple inheritance!
It is recommended that you use L<Role::Tiny> since it can be used on
plain old Perl classes which is good since L<Alien::Base> doesn't use
anything fancy like L<Moose> or L<Moo>.  There is one working example
that use this technique that are worth checking out in the event you
are interested: L<Alien::Role::Dino>.

This class itself doesn't do anything, it just documents the technique.

=head1 SEE ALSO

=over 4

=item L<Alien>

=item L<Alien::Base>

=item L<alienfile>

=item L<Alien::Build>

=item L<Alien::Role::Dino>

=back

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK9N%[�@{��perl5/Alien/Build.pmnu��6�$package Alien::Build;

use strict;
use warnings;
use 5.008004;
use Path::Tiny ();
use Carp ();
use File::chdir;
use JSON::PP ();
use Env qw( @PATH @PKG_CONFIG_PATH );
use Config ();
use Alien::Build::Log;

# ABSTRACT: Build external dependencies for use in CPAN
our $VERSION = '2.84'; # VERSION


sub _path { goto \&Path::Tiny::path }


sub new
{
  my($class, %args) = @_;
  my $self = bless {
    install_prop => {
      root  => _path($args{root} || "_alien")->absolute->stringify,
      patch => (defined $args{patch}) ? _path($args{patch})->absolute->stringify : undef,
    },
    runtime_prop => {
      alien_build_version => $Alien::Build::VERSION || 'dev',
    },
    plugin_instance_prop => {},
    bin_dir => [],
    pkg_config_path => [],
    aclocal_path => [],
  }, $class;

  # force computing this as soon as possible
  $self->download_rule;

  $self->meta->filename(
    $args{filename} || do {
      my(undef, $filename) = caller;
      _path($filename)->absolute->stringify;
    }
  );

  if($args{meta_prop})
  {
    $self->meta->prop->{$_} = $args{meta_prop}->{$_} for keys %{ $args{meta_prop} };
  }

  $self;
}


my $count = 0;

sub load
{
  my(undef, $alienfile, @args) = @_;

  my $rcfile = Path::Tiny->new($ENV{ALIEN_BUILD_RC} || '~/.alienbuild/rc.pl')->absolute;
  if(-r $rcfile)
  {
    require Alien::Build::rc;
    package Alien::Build::rc;
    require $rcfile;
  }

  unless(-r $alienfile)
  {
    Carp::croak "Unable to read alienfile: $alienfile";
  }

  my $file = _path $alienfile;
  my $name = $file->parent->basename;
  $name =~ s/^alien-//i;
  $name =~ s/[^a-z]//g;
  $name = 'x' if $name eq '';
  $name = ucfirst $name;

  my $class = "Alien::Build::Auto::$name@{[ $count++ ]}";

  { no strict 'refs';
  @{ "${class}::ISA" } = ('Alien::Build');
  *{ "${class}::Alienfile::meta" } = sub {
    $class =~ s{::Alienfile$}{};
    $class->meta;
  }};

  my @preload = qw( Core::Setup Core::Download Core::FFI Core::Override Core::CleanInstall );
  push @preload, @Alien::Build::rc::PRELOAD;
  push @preload, split /;/, $ENV{ALIEN_BUILD_PRELOAD}
    if defined $ENV{ALIEN_BUILD_PRELOAD};

  my @postload = qw( Core::Legacy Core::Gather Core::Tail );
  push @postload, @Alien::Build::rc::POSTLOAD;
  push @postload, split /;/, $ENV{ALIEN_BUILD_POSTLOAD}
    if defined $ENV{ALIEN_BUILD_POSTLOAD};

  my $self = $class->new(
    filename => $file->absolute->stringify,
    @args,
  );

  require alienfile;

  foreach my $preload (@preload)
  {
    ref $preload eq 'CODE' ? $preload->($self->meta) : $self->meta->apply_plugin($preload);
  }

  # TODO: do this without a string eval ?
  ## no critic
  eval '# line '. __LINE__ . ' "' . __FILE__ . qq("\n) . qq{
    package ${class}::Alienfile;
    do '@{[ $file->absolute->stringify ]}';
    die \$\@ if \$\@;
  };
  die $@ if $@;
  ## use critic

  foreach my $postload (@postload)
  {
    ref $postload eq 'CODE' ? $postload->($self->meta) : $self->meta->apply_plugin($postload);
  }

  $self->{args} = \@args;
  unless(defined $self->meta->prop->{arch})
  {
    $self->meta->prop->{arch} = 1;
  }

  unless(defined $self->meta->prop->{network})
  {
    $self->meta->prop->{network} = 1;
    ## https://github.com/PerlAlien/Alien-Build/issues/23#issuecomment-341114414
    #$self->meta->prop->{network} = 0 if $ENV{NO_NETWORK_TESTING};
    $self->meta->prop->{network} = 0 if (defined $ENV{ALIEN_INSTALL_NETWORK}) && ! $ENV{ALIEN_INSTALL_NETWORK};
  }

  unless(defined $self->meta->prop->{local_source})
  {
    if(! defined $self->meta->prop->{start_url})
    {
      $self->meta->prop->{local_source} = 0;
    }
    # we assume URL schemes are at least two characters, that
    # way Windows absolute paths can be used as local start_url
    elsif($self->meta->prop->{start_url} =~ /^([a-z]{2,}):/i)
    {
      my $scheme = $1;
      $self->meta->prop->{local_source} = $scheme eq 'file';
    }
    else
    {
      $self->meta->prop->{local_source} = 1;
    }
  }

  return $self;
}


sub resume
{
  my(undef, $alienfile, $root) = @_;
  my $h = JSON::PP::decode_json(_path("$root/state.json")->slurp);
  my $self = Alien::Build->load("$alienfile", @{ $h->{args} });
  $self->{install_prop}         = $h->{install};
  $self->{plugin_instance_prop} = $h->{plugin_instance};
  $self->{runtime_prop}         = $h->{runtime};
  $self;
}


sub meta_prop
{
  my($class) = @_;
  $class->meta->prop;
}


sub install_prop
{
  shift->{install_prop};
}


sub plugin_instance_prop
{
  my($self, $plugin) = @_;
  my $instance_id = $plugin->instance_id;
  $self->{plugin_instance_prop}->{$instance_id} ||= {};
}


sub runtime_prop
{
  shift->{runtime_prop};
}


sub hook_prop
{
  shift->{hook_prop};
}

sub _command_prop
{
  my($self) = @_;

  return {
    alien => {
      install => $self->install_prop,
      runtime => $self->runtime_prop,
      hook    => $self->hook_prop,
      meta    => $self->meta_prop,
    },
    perl => {
      config => \%Config::Config,
    },
    env => \%ENV,
  };
}


sub checkpoint
{
  my($self) = @_;
  my $root = $self->root;
  _path("$root/state.json")->spew(
    JSON::PP->new->pretty->canonical(1)->ascii->encode({
      install         => $self->install_prop,
      runtime         => $self->runtime_prop,
      plugin_instance => $self->{plugin_instance_prop},
      args            => $self->{args},
    })
  );
  $self;
}


sub root
{
  my($self) = @_;
  my $root = $self->install_prop->{root};
  _path($root)->mkpath unless -d $root;
  $root;
}


sub install_type
{
  my($self) = @_;
  $self->{runtime_prop}->{install_type} ||= $self->probe;
}


sub is_system_install
{
  my($self) = @_;
  $self->install_type eq 'system';
}


sub is_share_install
{
  my($self) = @_;
  $self->install_type eq 'share';
}



sub download_rule
{
  my($self) = @_;

  $self->install_prop->{download_rule} ||= do {
    my $dr = $ENV{ALIEN_DOWNLOAD_RULE};
    $dr = 'warn' unless defined $dr;
    $dr = 'warn' if $dr eq 'default';
    unless($dr =~ /^(warn|digest|encrypt|digest_or_encrypt|digest_and_encrypt)$/)
    {
      $self->log("unknown ALIEN_DOWNLOAD_RULE \"$dr\", using \"warn\" instead");
      $dr = 'warn';
    }
    $dr;
  };
}


sub set_prefix
{
  my($self, $prefix) = @_;

  if($self->meta_prop->{destdir})
  {
    $self->runtime_prop->{prefix} =
    $self->install_prop->{prefix} = $prefix;
  }
  else
  {
    $self->runtime_prop->{prefix} = $prefix;
    $self->install_prop->{prefix} = $self->install_prop->{stage};
  }
}


sub set_stage
{
  my($self, $dir) = @_;
  $self->install_prop->{stage} = $dir;
}

sub _merge
{
  my %h;
  while(@_)
  {
    my $mod = shift;
    my $ver = shift;
    if((!defined $h{$mod}) || $ver > $h{$mod})
    { $h{$mod} = $ver }
  }
  \%h;
}


sub requires
{
  my($self, $phase) = @_;
  $phase ||= 'any';
  my $meta = $self->meta;
  $phase =~ /^(?:any|configure)$/
  ? $meta->{require}->{$phase} || {}
  : _merge %{ $meta->{require}->{any} }, %{ $meta->{require}->{$phase} };
}


sub load_requires
{
  my($self, $phase, $eval) = @_;
  my $reqs = $self->requires($phase);
  foreach my $mod (keys %$reqs)
  {
    my $ver = $reqs->{$mod};
    my $check = sub {
      my $pm = "$mod.pm";
      $pm =~ s{::}{/}g;
      require $pm;
    };
    if($eval)
    {
      eval { $check->() };
      die "Required $mod @{[ $ver || 'undef' ]}, missing" if $@;
    }
    else
    {
      $check->();
    }
    # note Test::Alien::Build#alienfile_skip_if_missing_prereqs does a regex
    # on this diagnostic, so if you change it here, change it there too.
    die "Required $mod $ver, have @{[ $mod->VERSION || 0 ]}" if $ver && ! $mod->VERSION($ver);

    # allow for requires on Alien::Build or Alien::Base
    next if $mod eq 'Alien::Build';
    next if $mod eq 'Alien::Base';

    if($mod->can('bin_dir'))
    {
      push @{ $self->{bin_dir} }, $mod->bin_dir;
    }

    if(($mod->can('runtime_prop') && $mod->runtime_prop)
    || ($mod->isa('Alien::Base')  && $mod->install_type('share')))
    {
      for my $dir (qw(lib share)) {
          my $path = _path($mod->dist_dir)->child("$dir/pkgconfig");
          if(-d $path)
          {
            push @{ $self->{pkg_config_path} }, $path->stringify;
          }
      }
      my $path = _path($mod->dist_dir)->child('share/aclocal');
      if(-d $path)
      {
        $path = "$path";
        if($^O eq 'MSWin32')
        {
          # convert to MSYS path
          $path =~ s{^([a-z]):}{/$1/}i;
        }
        push @{ $self->{aclocal_path} }, $path;
      }
    }

    # sufficiently new Autotools have a aclocal_dir which will
    # give us the directories we need.
    if($mod eq 'Alien::Autotools' && $mod->can('aclocal_dir'))
    {
      push @{ $self->{aclocal_path} }, $mod->aclocal_dir;
    }

    if($mod->can('alien_helper'))
    {
      my $helpers = $mod->alien_helper;
      foreach my $name (sort keys %$helpers)
      {
        my $code = $helpers->{$name};
        $self->meta->interpolator->replace_helper($name => $code);
      }
    }

  }
  1;
}

sub _call_hook
{
  my $self = shift;

  local $ENV{PATH} = $ENV{PATH};
  unshift @PATH, @{ $self->{bin_dir} };

  local $ENV{PKG_CONFIG_PATH} = $ENV{PKG_CONFIG_PATH};
  unshift @PKG_CONFIG_PATH, @{ $self->{pkg_config_path} };

  local $ENV{ACLOCAL_PATH} = $ENV{ACLOCAL_PATH};
  # autoconf uses MSYS paths, even for the ACLOCAL_PATH environment variable, so we can't use Env for this.
  {
    my @path;
    @path = split /:/, $ENV{ACLOCAL_PATH} if defined $ENV{ACLOCAL_PATH};
    unshift @path, @{ $self->{aclocal_path} };
    $ENV{ACLOCAL_PATH} = join ':', @path;
  }

  my $config = ref($_[0]) eq 'HASH' ? shift : {};
  my($name, @args) = @_;

  local $self->{hook_prop} = {};

  $self->meta->call_hook( $config, $name => $self, @args );
}


sub probe
{
  my($self) = @_;
  local $CWD = $self->root;
  my $dir;

  my $env = $self->_call_hook('override');
  my $type;
  my $error;

  $env = '' if $env eq 'default';

  if($env eq 'share')
  {
    $type = 'share';
  }
  else
  {
    $type = eval {
      $self->_call_hook(
        {
          before   => sub {
            $dir = Alien::Build::TempDir->new($self, "probe");
            $CWD = "$dir";
          },
          after    => sub {
            $CWD = $self->root;
          },
          ok       => 'system',
          continue => sub {
            if($_[0] eq 'system')
            {
              foreach my $name (qw( probe_class probe_instance_id ))
              {
                if(exists $self->hook_prop->{$name} && defined $self->hook_prop->{$name})
                {
                  $self->install_prop->{"system_$name"} = $self->hook_prop->{$name};
                }
              }
              return undef;
            }
            else
            {
              return 1;
            }
          },
        },
        'probe',
      );
    };
    $error = $@;
    $type = 'share' unless defined $type;
  }

  if($error)
  {
    if($env eq 'system')
    {
      die $error;
    }
    $self->log("error in probe (will do a share install): $@");
    $self->log("Don't panic, we will attempt a share build from source if possible.");
    $self->log("Do not file a bug unless you expected a system install to succeed.");
    $type = 'share';
  }

  if($env && $env ne $type)
  {
    die "requested $env install not available";
  }

  if($type !~ /^(system|share)$/)
  {
    Carp::croak "probe hook returned something other than system or share: $type";
  }

  if($type eq 'share' && (!$self->meta_prop->{network}) && (!$self->meta_prop->{local_source}))
  {
    $self->log("install type share requested or detected, but network fetch is turned off");
    $self->log("see https://metacpan.org/pod/Alien::Build::Manual::FAQ#Network-fetch-is-turned-off");
    Carp::croak "network fetch is turned off";
  }

  $self->runtime_prop->{install_type} = $type;

  $type;
}


sub download
{
  my($self) = @_;

  return $self unless $self->install_type eq 'share';
  return $self if $self->install_prop->{complete}->{download};

  if($self->meta->has_hook('download'))
  {
    my $tmp;
    local $CWD;
    my $valid = 0;

    $self->_call_hook(
      {
        before => sub {
          $tmp = Alien::Build::TempDir->new($self, "download");
          $CWD = "$tmp";
        },
        verify => sub {
          my @list = grep { $_->basename !~ /^\./, } _path('.')->children;

          my $count = scalar @list;

          if($count == 0)
          {
            die "no files downloaded";
          }
          elsif($count == 1)
          {
            my($archive) = $list[0];
            if(-d $archive)
            {
              # TODO: this is probably a bug that we don't set
              # download or compelte properties?
              $self->log("single dir, assuming directory");
            }
            else
            {
              $self->log("single file, assuming archive");
            }
            $self->install_prop->{download} = $archive->absolute->stringify;
            $self->install_prop->{complete}->{download} = 1;
            $valid = 1;
          }
          else
          {
            $self->log("multiple files, assuming directory");
            $self->install_prop->{complete}->{download} = 1;
            $self->install_prop->{download} = _path('.')->absolute->stringify;
            $valid = 1;
          }
        },
        after  => sub {
          $CWD = $self->root;
        },
      },
      'download',
    );

    # experimental and undocumented for now
    if($self->meta->has_hook('check_download'))
    {
      $self->meta->call_hook(check_download => $self);
    }

    return $self if $valid;
  }
  else
  {
    # This will call the default download hook
    # defined in Core::Download since the recipe
    # does not provide a download hook
    my $ret = $self->_call_hook('download');

    # experimental and undocumented for now
    if($self->meta->has_hook('check_download'))
    {
      $self->meta->call_hook(check_download => $self);
    }

    return $self;
  }

  die "download failed";
}


sub fetch
{
  my $self = shift;
  my $url = $_[0] || $self->meta_prop->{start_url};

  my $secure = 0;

  if(defined $url && ($url =~ /^(https|file):/ || $url !~ /:/))
  {
    # considered secure when either https or a local file
    $secure = 1;
  }
  elsif(!defined $url)
  {
    $self->log("warning: undefined url in fetch");
  }
  else
  {
    $self->log("warning: attempting to fetch a non-TLS or bundled URL: @{[ $url ]}");
  }

  die "insecure fetch is not allowed" if $self->download_rule =~ /^(encrypt|digest_and_encrypt)$/ && !$secure;

  my $file = $self->_call_hook( 'fetch' => @_ );

  $secure = 0;

  if(ref($file) ne 'HASH')
  {
    $self->log("warning: fetch returned non-hash reference");
  }
  elsif(!defined $file->{protocol})
  {
    $self->log("warning: fetch did not return a protocol");
  }
  elsif($file->{protocol} !~ /^(https|file)$/)
  {
    $self->log("warning: fetch did not use a secure protocol: @{[ $file->{protocol} ]}");
  }
  else
  {
    $secure = 1;
  }

  die "insecure fetch is not allowed" if $self->download_rule =~ /^(encrypt|digest_and_encrypt)$/ && !$secure;

  $file;
}


sub check_digest
{
  my($self, $file) = @_;

  return '' unless $self->meta_prop->{check_digest};

  unless(ref($file) eq 'HASH')
  {
    my $path = Path::Tiny->new($file);
    $file = {
      type     => 'file',
      filename => $path->basename,
      path     => "$path",
      tmp      => 0,
    };
  }

  my $path = $file->{path};
  if(defined $path)
  {
    # there is technically a race condition here
    die "Missing file in digest check: @{[ $file->{filename} ]}" unless -f $path;
    die "Unreadable file in digest check: @{[ $file->{filename} ]}" unless -r $path;
  }
  else
  {
    die "File is wrong type" unless defined $file->{type} && $file->{type} eq 'file';
    die "File has no filename" unless defined $file->{filename};
    die "@{[ $file->{filename} ]} has no content" unless defined $file->{content};
  }

  my $filename = $file->{filename};
  my $signature = $self->meta_prop->{digest}->{$filename} || $self->meta_prop->{digest}->{'*'};

  die "No digest for $filename" unless defined $signature && ref $signature eq 'ARRAY';

  my($algo, $expected) = @$signature;

  if($self->meta->call_hook( check_digest => $self, $file, $algo, $expected ))
  {
    # record the verification here so that we can check in the extract step that the signature
    # was checked.
    $self->install_prop->{download_detail}->{$path}->{digest} = [$algo, $expected] if defined $path; return 1;
  }
  else
  {
    die "No plugin provides digest algorithm for $algo";
  }
}


sub decode
{
  my($self, $res) = @_;
  my $res2 = $self->_call_hook( decode => $res );
  $res2->{protocol} = $res->{protocol}
    if !defined $res2->{protocol}
    &&  defined $res->{protocol};
  return $res2;
}


sub prefer
{
  my($self, $res) = @_;
  my $res2 = $self->_call_hook( prefer => $res );
  $res2->{protocol} = $res->{protocol}
    if !defined $res2->{protocol}
    &&  defined $res->{protocol};
  return $res2;
}


sub extract
{
  my($self, $archive) = @_;

  $archive ||= $self->install_prop->{download};

  unless(defined $archive)
  {
    die "tried to call extract before download";
  }

  {
    my $checked_digest  = 0;
    my $encrypted_fetch = 0;
    my $detail = $self->install_prop->{download_detail}->{$archive};
    if(defined $detail)
    {
      if(defined $detail->{digest})
      {
        my($algo, $expected) = @{ $detail->{digest} };
        my $file = {
          type     => 'file',
          filename => Path::Tiny->new($archive)->basename,
          path     => $archive,
          tmp      => 0,
        };
        $checked_digest = $self->meta->call_hook( check_digest => $self, $file, $algo, $expected )
      }
      if(!defined $detail->{protocol})
      {
        $self->log("warning: extract did not receive protocol details for $archive") unless $checked_digest;
      }
      elsif($detail->{protocol} !~ /^(https|file)$/)
      {
        $self->log("warning: extracting from a file that was fetched via insecure protocol @{[ $detail->{protocol} ]}") unless $checked_digest ;
      }
      else
      {
        $encrypted_fetch = 1;
      }
    }
    else
    {
      $self->log("warning: extract received no download details for $archive");
    }

    if($self->download_rule eq 'digest')
    {
      die "required digest missing for $archive" unless $checked_digest;
    }
    elsif($self->download_rule eq 'encrypt')
    {
      die "file was fetched insecurely for $archive" unless $encrypted_fetch;
    }
    elsif($self->download_rule eq 'digest_or_encrypt')
    {
      die "file was fetched insecurely and required digest missing for $archive" unless $checked_digest || $encrypted_fetch;
    }
    elsif($self->download_rule eq 'digest_and_encrypt')
    {
      die "file was fetched insecurely and required digest missing for $archive" unless $checked_digest || $encrypted_fetch;
      die "required digest missing for $archive" unless $checked_digest;
      die "file was fetched insecurely for $archive" unless $encrypted_fetch;
    }
    elsif($self->download_rule eq 'warn')
    {
      unless($checked_digest || $encrypted_fetch)
      {
        $self->log("!!! NOTICE OF FUTURE CHANGE IN BEHAVIOR !!!");
        $self->log("a future version of Alien::Build will die here by default with this exception: file was fetched insecurely and required digest missing for $archive");
        $self->log("!!! NOTICE OF FUTURE CHANGE IN BEHAVIOR !!!");
      }
    }
    else
    {
      die "internal error, unknown download rule: @{[ $self->download_rule ]}";
    }

  }

  my $nick_name = 'build';

  if($self->meta_prop->{out_of_source})
  {
    $nick_name = 'extract';
    my $extract = $self->install_prop->{extract};
    return $extract if defined $extract && -d $extract;
  }

  my $tmp;
  local $CWD;
  my $ret;

  $self->_call_hook({

    before => sub {
      # called build instead of extract, because this
      # will be used for the build step, and technically
      # extract is a substage of build anyway.
      $tmp = Alien::Build::TempDir->new($self, $nick_name);
      $CWD = "$tmp";
    },
    verify => sub {

      my $path = '.';
      if($self->meta_prop->{out_of_source} && $self->install_prop->{extract})
      {
        $path = $self->install_prop->{extract};
      }

      my @list = grep { $_->basename !~ /^\./ && $_->basename ne 'pax_global_header' } _path($path)->children;

      my $count = scalar @list;

      if($count == 0)
      {
        die "no files extracted";
      }
      elsif($count == 1 && -d $list[0])
      {
        $ret = $list[0]->absolute->stringify;
      }
      else
      {
        $ret = "$tmp";
      }

    },
    after => sub {
      $CWD = $self->root;
    },

  }, 'extract', $archive);

  $self->install_prop->{extract} ||= $ret;
  $ret ? $ret : ();
}


sub build
{
  my($self) = @_;

  # save the evironment, in case some plugins decide
  # to alter it.  Or us!  See just a few lines below.
  local %ENV = %ENV;

  my $stage = _path($self->install_prop->{stage});
  $stage->mkpath;

  my $tmp;

  if($self->install_type eq 'share')
  {
    foreach my $suffix ('', '_ffi')
    {
      local $CWD;
      delete $ENV{DESTDIR} unless $self->meta_prop->{destdir};

      my %env_meta = %{ $self->meta_prop   ->{env} || {} };
      my %env_inst = %{ $self->install_prop->{env} || {} };

      if($self->meta_prop->{env_interpolate})
      {
        foreach my $key (keys %env_meta)
        {
          $env_meta{$key} = $self->meta->interpolator->interpolate($env_meta{$key}, $self);
        }
      }

      %ENV = (%ENV, %env_meta);
      %ENV = (%ENV, %env_inst);

      my $destdir;

      $self->_call_hook(
      {
        before => sub {
          if($self->meta_prop->{out_of_source})
          {
            $self->extract;
            $CWD = $tmp = Alien::Build::TempDir->new($self, 'build');
          }
          else
          {
            $CWD = $tmp = $self->extract;
          }
          if($self->meta_prop->{destdir})
          {
            $destdir = Alien::Build::TempDir->new($self, 'destdir');
            $ENV{DESTDIR} = "$destdir";
          }
          $self->_call_hook({ all => 1 }, "patch${suffix}");
        },
        after => sub {
          $destdir = "$destdir" if $destdir;
        },
      }, "build${suffix}");

      $self->install_prop->{"_ab_build@{[ $suffix || '_share' ]}"} = "$CWD";

      $self->_call_hook("gather@{[ $suffix || '_share' ]}");
    }
  }

  elsif($self->install_type eq 'system')
  {
    local $CWD = $self->root;
    my $dir;

    $self->_call_hook(
      {
        before => sub {
          $dir = Alien::Build::TempDir->new($self, "gather");
          $CWD = "$dir";
        },
        after  => sub {
          $CWD = $self->root;
        },
      },
      'gather_system',
    );

    $self->install_prop->{finished} = 1;
    $self->install_prop->{complete}->{gather_system} = 1;
  }

  $self;
}


sub test
{
  my($self) = @_;

  if($self->install_type eq 'share')
  {
    foreach my $suffix ('_share', '_ffi')
    {
      if($self->meta->has_hook("test$suffix"))
      {
        my $dir = $self->install_prop->{"_ab_build$suffix"};
        Carp::croak("no build directory to run tests") unless $dir && -d $dir;
        local $CWD = $dir;
        $self->_call_hook("test$suffix");
      }
    }
  }
  else
  {
    if($self->meta->has_hook("test_system"))
    {
      my $dir = Alien::Build::TempDir->new($self, "test");
      local $CWD = "$dir";
      $self->_call_hook("test_system");
    }
  }

}


sub clean_install
{
  my($self) = @_;
  if($self->install_type eq 'share')
  {
    $self->_call_hook("clean_install");
  }
}


sub system
{
  my($self, $command, @args) = @_;

  my $prop = $self->_command_prop;

  ($command, @args) = map {
    $self->meta->interpolator->interpolate($_, $prop)
  } ($command, @args);

  $self->log("+ $command @args");

  scalar @args
    ? system $command, @args
    : system $command;
}


sub log
{
  my(undef, $message) = @_;
  my $caller = [caller];
  chomp $message;
  foreach my $line (split /\n/, $message)
  {
    Alien::Build::Log->default->log(
      caller  => $caller,
      message => $line,
    );
  }
}


{
  my %meta;

  sub meta
  {
    my($class) = @_;
    $class = ref $class if ref $class;
    $meta{$class} ||= Alien::Build::Meta->new( class => $class );
  }
}

package Alien::Build::Meta;

our @CARP_NOT = qw( alienfile );

sub new
{
  my($class, %args) = @_;
  my $self = bless {
    phase => 'any',
    build_suffix => '',
    require => {
      any    => {},
      share  => {},
      system => {},
    },
    around => {},
    prop => {},
    %args,
  }, $class;
  $self;
}


sub prop
{
  shift->{prop};
}

sub filename
{
  my($self, $new) = @_;
  $self->{filename} = $new if defined $new;
  $self->{filename};
}


sub add_requires
{
  my $self = shift;
  my $phase = shift;
  while(@_)
  {
    my $module = shift;
    my $version = shift;
    my $old = $self->{require}->{$phase}->{$module};
    if((!defined $old) || $version > $old)
    { $self->{require}->{$phase}->{$module} = $version }
  }
  $self;
}


sub interpolator
{
  my($self, $new) = @_;
  if(defined $new)
  {
    if(defined $self->{intr})
    {
      Carp::croak "tried to set interpolator twice";
    }
    if(ref $new)
    {
      $self->{intr} = $new;
    }
    else
    {
      $self->{intr} = $new->new;
    }
  }
  elsif(!defined $self->{intr})
  {
    require Alien::Build::Interpolate::Default;
    $self->{intr} = Alien::Build::Interpolate::Default->new;
  }
  $self->{intr};
}


sub has_hook
{
  my($self, $name) = @_;
  defined $self->{hook}->{$name};
}


sub _instr
{
  my($self, $name, $instr) = @_;
  if(ref($instr) eq 'CODE')
  {
    return $instr;
  }
  elsif(ref($instr) eq 'ARRAY')
  {
    my %phase = (
      download      => 'share',
      fetch         => 'share',
      decode        => 'share',
      prefer        => 'share',
      extract       => 'share',
      patch         => 'share',
      patch_ffi     => 'share',
      build         => 'share',
      build_ffi     => 'share',
      stage         => 'share',
      gather_ffi    => 'share',
      gather_share  => 'share',
      gather_system => 'system',
      test_ffi      => 'share',
      test_share    => 'share',
      test_system   => 'system',
    );
    require Alien::Build::CommandSequence;
    my $seq = Alien::Build::CommandSequence->new(@$instr);
    $seq->apply_requirements($self, $phase{$name} || 'any');
    return $seq;
  }
  else
  {
    Carp::croak "type not supported as a hook";
  }
}

sub register_hook
{
  my($self, $name, $instr) = @_;
  push @{ $self->{hook}->{$name} }, _instr $self, $name, $instr;
  $self;
}


sub default_hook
{
  my($self, $name, $instr) = @_;
  $self->{default_hook}->{$name} = _instr $self, $name, $instr;
  $self;
}


sub around_hook
{
  my($self, $name, $code) = @_;
  if(my $old = $self->{around}->{$name})
  {
    # this is the craziest shit I have ever
    # come up with.
    $self->{around}->{$name} = sub {
      my $orig = shift;
      $code->(sub { $old->($orig, @_) }, @_);
    };
  }
  else
  {
    $self->{around}->{$name} = $code;
  }
}


sub after_hook
{
  my($self, $name, $code) = @_;
  $self->around_hook(
    $name => sub {
      my $orig = shift;
      my $ret = $orig->(@_);
      $code->(@_);
      $ret;
    }
  );
}


sub before_hook
{
  my($self, $name, $code) = @_;
  $self->around_hook(
    $name => sub {
      my $orig = shift;
      $code->(@_);
      my $ret = $orig->(@_);
      $ret;
    }
  );
}


sub call_hook
{
  my $self = shift;
  my %args = ref $_[0] ? %{ shift() } : ();
  my($name, @args) = @_;
  my $error;

  my @hooks = @{ $self->{hook}->{$name} || []};

  if(@hooks == 0)
  {
    if(defined $self->{default_hook}->{$name})
    {
      @hooks = ($self->{default_hook}->{$name})
    }
    elsif(!$args{all})
    {
      Carp::croak "No hooks registered for $name";
    }
  }

  my $value;

  foreach my $hook (@hooks)
  {
    if(eval { $args[0]->isa('Alien::Build') })
    {
      %{ $args[0]->{hook_prop} } = (
        name => $name,
      );
    }

    my $wrapper = $self->{around}->{$name} || sub { my $code = shift; $code->(@_) };
    my $value;
    $args{before}->() if $args{before};
    if(ref($hook) eq 'CODE')
    {
      $value = eval {
        my $value = $wrapper->(sub { $hook->(@_) }, @args);
        $args{verify}->('code') if $args{verify};
        $value;
      };
    }
    else
    {
      $value = $wrapper->(sub {
        eval {
          $hook->execute(@_);
          $args{verify}->('command') if $args{verify};
        };
        defined $args{ok} ? $args{ok} : 1;
      }, @args);
    }
    $error = $@;
    $args{after}->() if $args{after};
    if($args{all})
    {
      die if $error;
    }
    else
    {
      next if $error;
      next if $args{continue} && $args{continue}->($value);
      return $value;
    }
  }

  die $error if $error && ! $args{all};

  $value;
}


sub apply_plugin
{
  my($self, $name, @args) = @_;

  my $class;
  my $pm;
  my $found;

  if($name =~ /^=(.*)$/)
  {
    $class = $1;
    $pm    = "$class.pm";
    $pm    =~ s!::!/!g;
    $found = 1;
  }

  if($name !~ /::/ && !$found)
  {
    foreach my $inc (@INC)
    {
      # TODO: allow negotiators to work with @INC hooks
      next if ref $inc;
      my $file = Path::Tiny->new("$inc/Alien/Build/Plugin/$name/Negotiate.pm");
      if(-r $file)
      {
        $class = "Alien::Build::Plugin::${name}::Negotiate";
        $pm    = "Alien/Build/Plugin/$name/Negotiate.pm";
        $found = 1;
        last;
      }
    }
  }

  unless($found)
  {
    $class = "Alien::Build::Plugin::$name";
    $pm    = "Alien/Build/Plugin/$name.pm";
    $pm    =~ s{::}{/}g;
  }

  require $pm unless $class->can('new');
  my $plugin = $class->new(@args);
  $plugin->init($self);
  $self;
}

package Alien::Build::TempDir;

# TODO: it's confusing that there is both a AB::TempDir and AB::Temp
# although they do different things.  there could maybe be a better
# name for AB::TempDir (maybe AB::TempBuildDir, though that is a little
# redundant).  Happily both are private classes, and either are able to
# rename, if a good name can be thought of.

use overload '""' => sub { shift->as_string }, bool => sub { 1 }, fallback => 1;
use File::Temp qw( tempdir );

sub new
{
  my($class, $build, $name) = @_;
  my $root = $build->install_prop->{root};
  Path::Tiny->new($root)->mkpath unless -d $root;
  bless {
    dir => Path::Tiny->new(tempdir( "${name}_XXXX", DIR => $root)),
  }, $class;
}

sub as_string
{
  shift->{dir}->stringify;
}

sub DESTROY
{
  my($self) = @_;
  if(-d $self->{dir} && $self->{dir}->children == 0)
  {
    rmdir($self->{dir}) || warn "unable to remove @{[ $self->{dir} ]} $!";
  }
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Build - Build external dependencies for use in CPAN

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 my $build = Alien::Build->load('./alienfile');
 $build->load_requires('configure');
 $build->set_prefix('/usr/local');
 $build->set_stage('/foo/mystage');  # needs to be absolute
 $build->load_requires($build->install_type);
 $build->download;
 $build->build;
 # files are now in /foo/mystage, it is your job (or
 # ExtUtils::MakeMaker, Module::Build, etc) to copy
 # those files into /usr/local

=head1 DESCRIPTION

This module provides tools for building external (non-CPAN) dependencies
for CPAN.  It is mainly designed to be used at install time of a CPAN
client, and work closely with L<Alien::Base> which is used at runtime.

This is the detailed documentation for the L<Alien::Build> class.
If you are starting out you probably want to do so from one of these documents:

=over 4

=item L<Alien::Build::Manual::Alien>

A broad overview of C<Alien-Build> and its ecosystem.

=item L<Alien::Build::Manual::AlienUser>

For users of an C<Alien::libfoo> that is implemented using L<Alien::Base>.
(The developer of C<Alien::libfoo> I<should> provide the documentation
necessary, but if not, this is the place to start).

=item L<Alien::Build::Manual::AlienAuthor>

If you are writing your own L<Alien> based on L<Alien::Build> and L<Alien::Base>.

=item L<Alien::Build::Manual::FAQ>

If you have a common question that has already been answered, like
"How do I use L<alienfile> with some build system".

=item L<Alien::Build::Manual::PluginAuthor>

This is for the brave souls who want to write plugins that will work with
L<Alien::Build> + L<alienfile>.

=item L<Alien::Build::Manual::Security>

If you are concerned that L<Alien>s might be downloading tarballs off
the internet, then this is the place for you.  This will discuss some
of the risks of downloading (really any) software off the internet
and will give you some tools to remediate these risks.

=back

Note that you will not usually create a L<Alien::Build> instance
directly, but rather be using a thin installer layer, such as
L<Alien::Build::MM> (for use with L<ExtUtils::MakeMaker>) or
L<Alien::Build::MB> (for use with L<Module::Build>).  One of the
goals of this project is to remain installer agnostic.

=head1 CONSTRUCTORS

=head2 new

 my $build = Alien::Build->new;

This creates a new empty instance of L<Alien::Build>.  Normally you will
want to use C<load> below to create an instance of L<Alien::Build> from
an L<alienfile> recipe.

=head2 load

 my $build = Alien::Build->load($alienfile);

This creates an L<Alien::Build> instance with the given L<alienfile>
recipe.

=head2 resume

 my $build = Alien::Build->resume($alienfile, $root);

Load a checkpointed L<Alien::Build> instance.  You will need the original
L<alienfile> and the build root (usually C<_alien>), and a build that
had been properly checkpointed using the C<checkpoint> method below.

=head1 PROPERTIES

There are three main properties for L<Alien::Build>.  There are a number
of properties documented here with a specific usage.  Note that these
properties may need to be serialized into something primitive like JSON
that does not support: regular expressions, code references of blessed
objects.

If you are writing a plugin (L<Alien::Build::Plugin>) you should use a
prefix like "plugin_I<name>" (where I<name> is the name of your plugin)
so that it does not interfere with other plugin or future versions of
L<Alien::Build>.  For example, if you were writing
C<Alien::Build::Plugin::Fetch::NewProtocol>, please use the prefix
C<plugin_fetch_newprotocol>:

 sub init
 {
   my($self, $meta) = @_;
 
   $meta->prop( plugin_fetch_newprotocol_foo => 'some value' );
 
   $meta->register_hook(
     some_hook => sub {
       my($build) = @_;
       $build->install_prop->{plugin_fetch_newprotocol_bar} = 'some other value';
       $build->runtime_prop->{plugin_fetch_newprotocol_baz} = 'and another value';
     }
   );
 }

If you are writing a L<alienfile> recipe please use the prefix C<my_>:

 use alienfile;
 
 meta_prop->{my_foo} = 'some value';
 
 probe sub {
   my($build) = @_;
   $build->install_prop->{my_bar} = 'some other value';
   $build->install_prop->{my_baz} = 'and another value';
 };

Any property may be used from a command:

 probe [ 'some command %{.meta.plugin_fetch_newprotocol_foo}' ];
 probe [ 'some command %{.install.plugin_fetch_newprotocol_bar}' ];
 probe [ 'some command %{.runtime.plugin_fetch_newprotocol_baz}' ];
 probe [ 'some command %{.meta.my_foo}' ];
 probe [ 'some command %{.install.my_bar}' ];
 probe [ 'some command %{.runtime.my_baz}' ];

=head2 meta_prop

 my $href = $build->meta_prop;
 my $href = Alien::Build->meta_prop;

Meta properties have to do with the recipe itself, and not any particular
instance that probes or builds that recipe.  Meta properties can be changed
from within an L<alienfile> using the C<meta_prop> directive, or from
a plugin from its C<init> method (though should NOT be modified from any
hooks registered within that C<init> method).  This is not strictly enforced,
but if you do not follow this rule your recipe will likely be broken.

=over

=item arch

This is a hint to an installer like L<Alien::Build::MM> or L<Alien::Build::MB>,
that the library or tool contains architecture dependent files and so should
be stored in an architecture dependent location.  If not specified by your
L<alienfile> then it will be set to true.

=item check_digest

True if cryptographic digest should be checked when files are fetched
or downloaded.  This is set by
L<Digest negotiator plugin|Alien::Build::Plugin::Digest::Negotiate>.

=item destdir

Some plugins (L<Alien::Build::Plugin::Build::Autoconf> for example) support
installing via C<DESTDIR>.  They will set this property to true if they
plan on doing such an install.  This helps L<Alien::Build> find the staged
install files and how to locate them.

If available, C<DESTDIR> is used to stage install files in a sub directory before
copying the files into C<blib>.  This is generally preferred method
if available.

=item destdir_filter

Regular expression for the files that should be copied from the C<DESTDIR>
into the stage directory.  If not defined, then all files will be copied.

=item destdir_ffi_filter

Same as C<destdir_filter> except applies to C<build_ffi> instead of C<build>.

=item digest

This properties contains the cryptographic digests (if any) that should
be used when verifying any fetched and downloaded files.  It is a hash
reference where the key is the filename and the value is an array
reference containing a pair of values, the first being the algorithm
('SHA256' is recommended) and the second is the actual digest.  The
special filename C<*> may be specified to indicate that any downloaded
file should match that digest.  If there are both real filenames and
the C<*> placeholder, the real filenames will be used for filenames
that match and any other files will use the placeholder.  Example:

 $build->meta_prop->{digest} = {
   'foo-1.00.tar.gz' => [ SHA256 => '9feac593aa49a44eb837de52513a57736457f1ea70078346c60f0bfc5f24f2c1' ],
   'foo-1.01.tar.gz' => [ SHA256 => '6bbde6a7f10ae5924cf74afc26ff5b7bc4b4f9dfd85c6b534c51bd254697b9e7' ],
   '*'               => [ SHA256 => '33a20aae3df6ecfbe812b48082926d55391be4a57d858d35753ab1334b9fddb3' ],
 };

Cryptographic signatures will only be checked
if the L<check_digest meta property|/check_digest> is set and if the
L<Digest negotiator plugin|Alien::Build::Plugin::Digest::Negotiate> is loaded.
(The Digest negotiator can be used directly, but is also loaded automatically
if you use the L<digest directive|alienfile/digest> is used by the L<alienfile>).

=item env

Environment variables to override during the build stage.

=item env_interpolate

Environment variable values will be interpolated with helpers.  Example:

 meta->prop->{env_interpolate} = 1;
 meta->prop->{env}->{PERL} = '%{perl}';

=item local_source

Set to true if source code package is available locally.  (that is not fetched
over the internet).  This is computed by default based on the C<start_url>
property.  Can be set by an L<alienfile> or plugin.

=item platform

Hash reference.  Contains information about the platform beyond just C<$^O>.

=over 4

=item platform.compiler_type

Refers to the type of flags that the compiler accepts.  May be expanded in the
future, but for now, will be one of:

=over 4

=item microsoft

On Windows when using Microsoft Visual C++

=item unix

Virtually everything else, including gcc on windows.

=back

The main difference is that with Visual C++ C<-LIBPATH> should be used instead
of C<-L>, and static libraries should have the C<.LIB> suffix instead of C<.a>.

=item platform.system_type

C<$^O> is frequently good enough to make platform specific logic in your
L<alienfile>, this handles the case when $^O can cover platforms that provide
multiple environments that Perl might run under.  The main example is windows,
but others may be added in the future.

=over 4

=item unix

=item vms

=item windows-activestate

=item windows-microsoft

=item windows-mingw

=item windows-strawberry

=item windows-unknown

=back

Note that C<cygwin> and C<msys> are considered C<unix> even though they run
on windows!

=item platform.cpu.count

Contains a non-negative integer of available (possibly virtual) CPUs on the
system. This can be used by build plugins to build in parallel. The environment
variable C<ALIEN_CPU_COUNT> can be set to override the CPU count.

=item platform.cpu.arch.name

Contains a normalized name for the architecture of the current Perl. This can
be used by fetch plugins to determine which binary packages to download.
The value may be one of the following, but this list will be expanded as
needed.

=over 4

=item C<armel>

32-bit ARM soft-float

=item C<armhf>

32-bit ARM hard-float

=item C<aarch64>

64-bit ARM

=item C<ppc>

32-bit PowerPC (big-endian)

=item C<ppc64>

64-bit PowerPC (big-endian)

=item C<x86>

32-bit Intel (i386, i486, i686)

=item C<x86_64>

64-bit Intel (AMD64)

=item C<unknown>

Unable to detect architecture. Please report this if needed.

=back

=back

=item out_of_source

Build in a different directory from the where the source code is stored.
In autoconf this is referred to as a "VPATH" build.  Everyone else calls this
an "out-of-source" build.  When this property is true, instead of extracting
to the source build root, the downloaded source will be extracted to an source
extraction directory and the source build root will be empty.  You can use the
C<extract> install property to get the location of the extracted source.

=item network

True if a network fetch is available.  This should NOT be set by an L<alienfile>
or plugin.  This is computed based on the C<ALIEN_INSTALL_NETWORK> environment
variables.

=item start_url

The default or start URL used by fetch plugins.

=back

=head2 install_prop

 my $href = $build->install_prop;

Install properties are used during the install phase (either
under C<share> or C<system> install).  They are remembered for
the entire install phase, but not kept around during the runtime
phase.  Thus they cannot be accessed from your L<Alien::Base>
based module.

=over

=item autoconf_prefix

The prefix as understood by autoconf.  This is only different on Windows
Where MSYS is used and paths like C<C:/foo> are  represented as C</C/foo>
which are understood by the MSYS tools, but not by Perl.  You should
only use this if you are using L<Alien::Build::Plugin::Build::Autoconf> in
your L<alienfile>.  This is set during before the
L<build hook|Alien::Build::Manual::PluginAuthor/"build hook"> is run.

=item download

The location of the downloaded archive (tar.gz, or similar) or directory.
This will be undefined until the archive is actually downloaded.

=item download_detail

This property contains optional details about a downloaded file.  This
property is populated by L<Alien::Build> core.  This property is a
hash reference.  The key is the path to the file that has been downloaded
and the value is a hash reference with additional detail.  All fields
are optional.

=over 4

=item download_detail.digest

This, if available, with the cryptographic signature that was successfully
matched against the downloaded file.  It is an array reference with a
pair of values, the algorithm (typically something like C<SHA256>) and
the digest.

=item download_detail.protocol

This, if available, will be the URL protocol used to fetch the downloaded
file.

=back

=item env

Environment variables to override during the build stage.  Plugins are
free to set additional overrides using this hash.

=item extract

The location of the last source extraction.  For a "out-of-source" build
(see the C<out_of_source> meta property above), this will only be set once.
For other types of builds, the source code may be extracted multiple times,
and thus this property may change.

=item old

[deprecated]

Hash containing information on a previously installed Alien of the same
name, if available.  This may be useful in cases where you want to
reuse the previous install if it is still sufficient.

=over 4

=item old.prefix

[deprecated]

The prefix for the previous install.  Versions prior to 1.42 unfortunately
had this in typo form of C<preifx>.

=item old.runtime

[deprecated]

The runtime properties from the previous install.

=back

=item patch

Directory with patches, if available.  This will be C<undef> if there
are no patches.  When initially installing an alien this will usually
be a sibling of the C<alienfile>, a directory called C<patch>.  Once
installed this will be in the share directory called C<_alien/patch>.
The former is useful for rebuilding an alienized package using
L<af>.

=item prefix

The install time prefix.  Under a C<destdir> install this is the
same as the runtime or final install location.  Under a non-C<destdir>
install this is the C<stage> directory (usually the appropriate
share directory under C<blib>).

=item root

The build root directory.  This will be an absolute path.  It is the
absolute form of C<./_alien> by default.

=item stage

The stage directory where files will be copied.  This is usually the
root of the blib share directory.

=item system_probe_class

After the probe step this property may contain the plugin class that
performed the system probe.  It shouldn't be filled in directly by
the plugin (instead if should use the hook property C<probe_class>,
see below).  This is optional, and not all probe plugins will provide
this information.

=item system_probe_instance_id

After the probe step this property may contain the plugin instance id that
performed the system probe.  It shouldn't be filled in directly by
the plugin (instead if should use the hook property C<probe_instance_id>,
see below).  This is optional, and not all probe plugins will provide
this information.

=back

=head2 plugin_instance_prop

 my $href = $build->plugin_instance_prop($plugin);

This returns the private plugin instance properties for a given plugin.
This method should usually only be called internally by plugins themselves
to keep track of internal state.  Because the content can be used arbitrarily
by the owning plugin because it is private to the plugin, and thus is not
part of the L<Alien::Build> spec.

=head2 runtime_prop

 my $href = $build->runtime_prop;

Runtime properties are used during the install and runtime phases
(either under C<share> or C<system> install).  This should include
anything that you will need to know to use the library or tool
during runtime, and shouldn't include anything that is no longer
relevant once the install process is complete.

=over 4

=item alien_build_version

The version of L<Alien::Build> used to install the library or tool.

=item alt

Alternate configurations.  If the alienized package has multiple
libraries this could be used to store the different compiler or
linker flags for each library.  Typically this will be set by a
plugin in the gather stage (for either share or system installs).

=item cflags

The compiler flags.  This is typically set by a plugin in the
gather stage (for either share or system installs).

=item cflags_static

The static compiler flags.  This is typically set by a plugin in the
gather stage (for either share or system installs).

=item command

The command name for tools where the name my differ from platform to
platform.  For example, the GNU version of make is usually C<make> in
Linux and C<gmake> on FreeBSD.  This is typically set by a plugin in the
gather stage (for either share or system installs).

=item ffi_name

The name DLL or shared object "name" to use when searching for dynamic
libraries at runtime.  This is passed into L<FFI::CheckLib>, so if
your library is something like C<libarchive.so> or C<archive.dll> you
would set this to C<archive>.  This may be a string or an array of
strings.  This is typically set by a plugin in the gather stage
(for either share or system installs).

=item ffi_checklib

This property contains two sub properties:

=over 4

=item ffi_checklib.share

 $build->runtime_prop->{ffi_checklib}->{share} = [ ... ];

Array of additional L<FFI::CheckLib> flags to pass in to C<find_lib>
for a C<share> install.

=item ffi_checklib.system

Array of additional L<FFI::CheckLib> flags to pass in to C<find_lib>
for a C<system> install.

Among other things, useful for specifying the C<try_linker_script>
flag:

 $build->runtime_prop->{ffi_checklib}->{system} = [ try_linker_script => 1 ];

=back

This is typically set by a plugin in the gather stage
(for either share or system installs).

=item inline_auto_include

[version 2.53]

This property is an array reference of C code that will be passed into
L<Inline::C> to make sure that appropriate headers are automatically
included.  See L<Inline::C/auto_include> for details.

=item install_type

The install type.  This is set by AB core after the
L<probe hook|Alien::Build::Manual::PluginAuthor/"probe hook"> is
executed.  Is one of:

=over 4

=item system

For when the library or tool is provided by the operating system, can be
detected by L<Alien::Build>, and is considered satisfactory by the
C<alienfile> recipe.

=item share

For when a system install is not possible, the library source will be
downloaded from the internet or retrieved in another appropriate fashion
and built.

=back

=item libs

The library flags.  This is typically set by a plugin in the
gather stage (for either share or system installs).

=item libs_static

The static library flags.  This is typically set by a plugin in the
gather stage (for either share or system installs).

=item perl_module_version

The version of the Perl module used to install the alien (if available).
For example if L<Alien::curl> is installing C<libcurl> this would be the
version of L<Alien::curl> used during the install step.

=item prefix

The final install root.  This is usually they share directory.

=item version

The version of the library or tool.  This is typically set by a plugin in the
gather stage (for either share or system installs).

=back

=head2 hook_prop

 my $href = $build->hook_prop;

Hook properties are for the currently running (if any) hook.  They are
used only during the execution of each hook and are discarded after.
If no hook is currently running then C<hook_prop> will return C<undef>.

=over 4

=item name

The name of the currently running hook.

=item version (probe)

Probe and PkgConfig plugins I<may> set this property indicating the
version of the alienized package.  Not all plugins and configurations
may be able to provide this.

=item probe_class (probe)

Probe and PkgConfig plugins I<may> set this property indicating the
plugin class that made the probe.  If the probe results in a system
install this will be propagated to C<system_probe_class> for later
use.

=item probe_instance_id (probe)

Probe and PkgConfig plugins I<may> set this property indicating the
plugin instance id that made the probe.  If the probe results in a
system install this will be propagated to C<system_probe_instance_id>
for later use.

=back

=head1 METHODS

=head2 checkpoint

 $build->checkpoint;

Save any install or runtime properties so that they can be reloaded on
a subsequent run in a separate process.  This is useful if your build
needs to be done in multiple stages from a C<Makefile>, such as with
L<ExtUtils::MakeMaker>.  Once checkpointed you can use the C<resume>
constructor (documented above) to resume the probe/build/install]
process.

=head2 root

 my $dir = $build->root;

This is just a shortcut for:

 my $root = $build->install_prop->{root};

Except that it will be created if it does not already exist.

=head2 install_type

 my $type = $build->install_type;

This will return the install type.  (See the like named install property
above for details).  This method will call C<probe> if it has not already
been called.

=head2 is_system_install

 my $boolean = $build->is_system_install;

Returns true if the alien is a system install type.  

=head2 is_share_install

 my $boolean = $build->is_share_install;

Returns true if the alien is a share install type.

=head2 download_rule

 my $rule = $build->download_rule;

This returns install rule as a string.  This is determined by the environment
and should be one of:

=over 4

=item C<warn>

Warn only if fetching via non secure source (secure sources include C<https>,
and bundled files, may include other encrypted protocols in the future).

=item C<digest>

Require that any downloaded source package have a cryptographic signature in
the L<alienfile> and that signature matches what was downloaded.

=item C<encrypt>

Require that any downloaded source package is fetched via secure source.

=item C<digest_or_encrypt>

Require that any downloaded source package is B<either> fetched via a secure source
B<or> has a cryptographic signature in the L<alienfile> and that signature matches
what was downloaded.

=item C<digest_and_encrypt>

Require that any downloaded source package is B<both> fetched via a secure source
B<and> has a cryptographic signature in the L<alienfile> and that signature matches
what was downloaded.

=back

The current default is C<warn>, but in the near future this will be upgraded to
C<digest_or_encrypt>.

=head2 set_prefix

 $build->set_prefix($prefix);

Set the final (unstaged) prefix.  This is normally only called by L<Alien::Build::MM>
and similar modules.  It is not intended for use from plugins or from an L<alienfile>.

=head2 set_stage

 $build->set_stage($dir);

Sets the stage directory.  This is normally only called by L<Alien::Build::MM>
and similar modules.  It is not intended for use from plugins or from an L<alienfile>.

=head2 requires

 my $hash = $build->requires($phase);

Returns a hash reference of the modules required for the given phase.  Phases
include:

=over 4

=item configure

These modules must already be available when the L<alienfile> is read.

=item any

These modules are used during either a C<system> or C<share> install.

=item share

These modules are used during the build phase of a C<share> install.

=item system

These modules are used during the build phase of a C<system> install.

=back

=head2 load_requires

 $build->load_requires($phase);

This loads the appropriate modules for the given phase (see C<requires> above
for a description of the phases).

=head2 probe

 my $install_type = $build->probe;

Attempts to determine if the operating system has the library or
tool already installed.  If so, then the string C<system> will
be returned and a system install will be performed.  If not,
then the string C<share> will be installed and the tool or
library will be downloaded and built from source.

If the environment variable C<ALIEN_INSTALL_TYPE> is set, then that
will force a specific type of install.  If the detection logic
cannot accommodate the install type requested then it will fail with
an exception.

=head2 download

 $build->download;

Download the source, usually as a tarball, usually from the internet.

Under a C<system> install this does not do anything.

=head2 fetch

 my $res = $build->fetch;
 my $res = $build->fetch($url, %options);

Fetch a resource using the fetch hook.  Returns the same hash structure
described below in the
L<fetch hook|Alien::Build::Manual::PluginAuthor/"fetch hook"> documentation.

[version 2.39]

As of L<Alien::Build> 2.39, these options are supported:

=over 4

=item http_headers

 my $res = $build->fetch($url, http_headers => [ $key1 => $value1, $key2 => $value 2, ... ]);

Set the HTTP request headers on all outgoing HTTP requests.  Note that not all
protocols or fetch plugins support setting request headers, but the ones that
do not I<should> issue a warning if you try to set request headers and they
are not supported.

=back

=head2 check_digest

[experimental]

 my $bool = $build->check_digest($path);

Checks any cryptographic signatures for the given file.  The
file is specified by C<$path> which may be one of:

=over 4

=item string

Containing the path to the file to be checked.

=item L<Path::Tiny>

Containing the path to the file to be checked.

=item C<HASH>

A Hash reference containing information about a file.  See
the L<fetch hook|Alien::Build::Manual::PluginAuthor/"fetch hook"> for details
on the format.

=back

Returns true if the cryptographic signature matches, false if cryptographic
signatures are disabled.  Will throw an exception if the signature does not
match, or if no plugin provides the correct algorithm for checking the
signature.

=head2 decode

 my $decoded_res = $build->decode($res);

Decode the HTML or file listing returned by C<fetch>.  Returns the same
hash structure described below in the
L<decode hook|Alien::Build::Manual::PluginAuthor/"decode hook"> documentation.

=head2 prefer

 my $sorted_res = $build->prefer($res);

Filter and sort candidates.  The preferred candidate will be returned first in the list.
The worst candidate will be returned last.  Returns the same hash structure described
below in the
L<prefer hook|Alien::Build::Manual::PluginAuthor/"prefer hook"> documentation.

=head2 extract

 my $dir = $build->extract;
 my $dir = $build->extract($archive);

Extracts the given archive into a fresh directory.  This is normally called internally
to L<Alien::Build>, and for normal usage is not needed from a plugin or L<alienfile>.

=head2 build

 $build->build;

Run the build step.  It is expected that C<probe> and C<download>
have already been performed.  What it actually does depends on the
type of install:

=over 4

=item share

The source is extracted, and built as determined by the L<alienfile>
recipe.  If there is a C<gather_share> that will be executed last.

=item system

The
L<gather_system hook|Alien::Build::Manual::PluginAuthor/"gather_system hook">
will be executed.

=back

=head2 test

 $build->test;

Run the test phase

=head2 clean_install

 $build->clean_install

Clean files from the final install location.  The default implementation removes all
files recursively except for the C<_alien> directory.  This is helpful when you have
an old install with files that may break the new build.

For a non-share install this doesn't do anything.

=head2 system

 $build->system($command);
 $build->system($command, @args);

Interpolates the command and arguments and run the results using
the Perl C<system> command.

=head2 log

 $build->log($message);

Send a message to the log.  By default this prints to C<STDOUT>.

=head2 meta

 my $meta = Alien::Build->meta;
 my $meta = $build->meta;

Returns the meta object for your L<Alien::Build> class or instance.  The
meta object is a way to manipulate the recipe, and so any changes to the
meta object should be made before the C<probe>, C<download> or C<build> steps.

=head1 META METHODS

=head2 prop

 my $href = $build->meta->prop;

Meta properties.  This is the same as calling C<meta_prop> on
the class or L<Alien::Build> instance.

=head2 add_requires

 Alien::Build->meta->add_requires($phase, $module => $version, ...);

Add the requirement to the given phase.  Phase should be one of:

=over 4

=item configure

=item any

=item share

=item system

=back

=head2 interpolator

 my $interpolator = $build->meta->interpolator;
 my $interpolator = Alien::Build->interpolator;

Returns the L<Alien::Build::Interpolate> instance for the L<Alien::Build> class.

=head2 has_hook

 my $bool = $build->meta->has_hook($name);
 my $bool = Alien::Build->has_hook($name);

Returns if there is a usable hook registered with the given name.

=head2 register_hook

 $build->meta->register_hook($name, $instructions);
 Alien::Build->meta->register_hook($name, $instructions);

Register a hook with the given name.  C<$instruction> should be either
a code reference, or a command sequence, which is an array reference.

=head2 default_hook

 $build->meta->default_hook($name, $instructions);
 Alien::Build->meta->default_hook($name, $instructions);

Register a default hook, which will be used if the L<alienfile> does not
register its own hook with that name.

=head2 around_hook

 $build->meta->around_hook($hook_name, $code);
 Alien::Build->meta->around_hook($hook_name, $code);

Wrap the given hook with a code reference.  This is similar to a L<Moose>
method modifier, except that it wraps around the given hook instead of
a method.  For example, this will add a probe system requirement:

 $build->meta->around_hook(
   probe => sub {
     my $orig = shift;
     my $build = shift;
     my $type = $orig->($build, @_);
     return $type unless $type eq 'system';
     # also require a configuration file
     if(-f '/etc/foo.conf')
     {
       return 'system';
     }
     else
     {
       return 'share';
     }
   },
 );

=head2 after_hook

 $build->meta->after_hook($hook_name, sub {
   my(@args) = @_;
   ...
 });

Execute the given code reference after the hook.  The original
arguments are passed into the code reference.

=head2 before_hook

 $build->meta->before_hook($hook_name, sub {
   my(@args) = @_;
   ...
 });

Execute the given code reference before the hook.  The original
arguments are passed into the code reference.

=head2 apply_plugin

 Alien::Build->meta->apply_plugin($name);
 Alien::Build->meta->apply_plugin($name, @args);

Apply the given plugin with the given arguments.

=head1 ENVIRONMENT

L<Alien::Build> responds to these environment variables:

=over 4

=item ALIEN_BUILD_LOG

The default log class used.  See L<Alien::Build::Log> and L<Alien::Build::Log::Default>.

=item ALIEN_BUILD_PKG_CONFIG

Override the logic in L<Alien::Build::Plugin::PkgConfig::Negotiate> which
chooses the best C<pkg-config> plugin.

=item ALIEN_BUILD_POSTLOAD

semicolon separated list of plugins to automatically load after parsing
your L<alienfile>.

=item ALIEN_BUILD_PRELOAD

semicolon separated list of plugins to automatically load before parsing
your L<alienfile>.

=item ALIEN_BUILD_RC

Perl source file which can override some global defaults for L<Alien::Build>,
by, for example, setting preload and postload plugins.

=item ALIEN_DOWNLOAD_RULE

This value determines the rules by which types of downloads are allowed.  The legal
values listed under L</download_rule>, plus C<default> which will be the default for
the current version of L<Alien::Build>.  For this version that default is C<warn>.

=item ALIEN_INSTALL_NETWORK

If set to true (the default), then network fetch will be allowed.  If set to
false, then network fetch will not be allowed.

What constitutes a local vs. network fetch is determined based on the C<start_url>
and C<local_source> meta properties.  An L<alienfile> or plugin C<could> override
this detection (possibly inappropriately), so this variable is not a substitute
for properly auditing of Perl modules for environments that require that.

=item ALIEN_INSTALL_TYPE

If set to C<share> or C<system>, it will override the system detection logic.
If set to C<default>, it will use the default setting for the L<alienfile>.
The behavior of other values is undefined.

Although the recommended way for a consumer to use an L<Alien::Base> based L<Alien>
is to declare it as a static configure and build-time dependency, some consumers
may prefer to fallback on using an L<Alien> only when the consumer itself cannot
detect the necessary package. In some cases the consumer may want the user to opt-in
to using an L<Alien> before requiring it.

To keep the interface consistent among Aliens, the consumer of the fallback opt-in
L<Alien> may fallback on the L<Alien> if the environment variable C<ALIEN_INSTALL_TYPE>
is set to any value. The rationale is that by setting this environment variable the
user is aware that L<Alien> modules may be installed and have indicated consent.
The actual implementation of this, by its nature would have to be in the consuming
CPAN module.

=item DESTDIR

This environment variable will be manipulated during a destdir install.

=item PKG_CONFIG

This environment variable can be used to override the program name for C<pkg-config>
when using the command line plugin: L<Alien::Build::Plugin::PkgConfig::CommandLine>.

=item ftp_proxy, all_proxy

If these environment variables are set, it may influence the Download negotiation
plugin L<Alien::Build::Plugin::Download::Negotiate>.  Other proxy variables may
be used by some Fetch plugins, if they support it.

=back

=head1 SUPPORT

The intent of the C<Alien-Build> team is to support the same versions of
Perl that are supported by the Perl toolchain.  As of this writing that
means 5.16 and better.

Please feel encouraged to report issues that you encounter to the
project GitHub Issue tracker:

=over 4

=item L<https://github.com/PerlAlien/Alien-Build/issues>

=back

Better if you can fix the issue yourself, please feel encouraged to open
pull-request on the project GitHub:

=over 4

=item L<https://github.com/PerlAlien/Alien-Build/pulls>

=back

If you are confounded and have questions, join us on the C<#native>
channel on irc.perl.org.  The C<Alien-Build> developers frequent this
channel and can probably help point you in the right direction.  If you
don't have an IRC client handy, you can use this web interface:

=over 4

=item L<https://chat.mibbit.com/?channel=%23native&server=irc.perl.org>

=back

=head1 SEE ALSO

L<Alien::Build::Manual::AlienAuthor>,
L<Alien::Build::Manual::AlienUser>,
L<Alien::Build::Manual::Contributing>,
L<Alien::Build::Manual::FAQ>,
L<Alien::Build::Manual::PluginAuthor>

L<alienfile>, L<Alien::Build::MM>, L<Alien::Build::Plugin>, L<Alien::Base>, L<Alien>

=head1 THANKS

L<Alien::Base> was originally written by Joel Berger, the rest of this project would
not have been possible without him getting the project started.  Thanks to his support
I have been able to augment the original L<Alien::Base> system with a reliable set
of tools (L<Alien::Build>, L<alienfile>, L<Test::Alien>), which make up this toolset.

The original L<Alien::Base> is still copyright (c) 2012-2020 Joel Berger.  It has
the same license as the rest of the Alien::Build and related tools distributed as
C<Alien-Build>.  Joel Berger thanked a number of people who helped in in the development
of L<Alien::Base>, in the documentation for that module.

I would also like to acknowledge the other members of the PerlAlien github
organization, Zakariyya Mughal (sivoais, ZMUGHAL) and mohawk (ETJ).  Also important
in the early development of L<Alien::Build> were the early adopters Chase Whitener
(genio, CAPOEIRAB, author of L<Alien::libuv>), William N. Braswell, Jr (willthechill,
WBRASWELL, author of L<Alien::JPCRE2> and L<Alien::PCRE2>) and Ahmad Fatoum (a3f,
ATHREEF, author of L<Alien::libudev> and L<Alien::LibUSB>).

The Alien ecosystem owes a debt to Dan Book, who goes by Grinnz on IRC, for answering
question about how to use L<Alien::Build> and friends.

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK9N%[���perl5/Alien/Base/Authoring.podnu��6�$# ABSTRACT: Authoring an Alien distribution using Alien::Base
# PODNAME: Alien::Base::Authoring

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Base::Authoring - Authoring an Alien distribution using Alien::Base

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 % perldoc Alien::Build::Manual::AlienAuthor
 % perldoc Alien::Base::ModuleBuild::Authoring

=head1 DESCRIPTION

This used to document the only way to author an L<Alien> distribution, which
was with L<Alien::Base::ModuleBuild>.  You should now seriously consider using
the newer more reliable method which is via L<Alien::Build> and L<alienfile>. Read all about it in L<Alien::Build::Manual::AlienAuthor> and L<Alien::Base::ModuleBuild::Authoring>

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK9N%[�ܖu((perl5/Alien/Base/PkgConfig.pmnu��6�$package Alien::Base::PkgConfig;

use strict;
use warnings;
use 5.008004;
use Carp;
use Config;
use Path::Tiny qw( path );
use Capture::Tiny qw( capture_stderr );

# ABSTRACT: Private legacy pkg-config class for Alien::Base
our $VERSION = '2.84'; # VERSION


sub new {
  my $class   = shift;

  # allow creation of an object from a full spec.
  if (ref $_[0] eq 'HASH') {
    return bless $_[0], $class;
  }

  my ($path) = @_;
  croak "Must specify a file" unless defined $path;

  $path = path( $path )->absolute;

  my($name) = $path->basename =~ /^(.*)\.pc$/;

  my $self = {
    package  => $name,
    vars     => { pcfiledir => $path->parent->stringify },
    keywords => {},
  };

  bless $self, $class;

  $self->read($path);

  return $self;
}

sub read {
  my $self = shift;
  my ($path) = @_;

  open my $fh, '<', $path
    or croak "Cannot open .pc file $path: $!";

  while (my $line = <$fh>) {
    if ($line =~ /^([^=:]+?)=([^\n\r]*)/) {
      $self->{vars}{$1} = $2;
    } elsif ($line =~ /^([^=:]+?):\s*([^\n\r]*)/) {
      $self->{keywords}{$1} = $2;
    }
  }
}

# getter/setter for vars
sub var {
  my $self = shift;
  my ($var, $newval) = @_;
  if (defined $newval) {
    $self->{vars}{$var} = $newval;
  }
  return $self->{vars}{$var};
}

# abstract keywords and other vars in terms of "pure" vars
sub make_abstract {
  my $self = shift;
  die "make_abstract needs a key (and possibly a value)" unless @_;
  my ($var, $value) = @_;

  $value = defined $value ? $value : $self->{vars}{$var};

  # convert other vars
  foreach my $key (keys %{ $self->{vars} }) {
    next if $key eq $var; # don't overwrite the current var
    $self->{vars}{$key} =~ s/\Q$value\E/\$\{$var\}/g;
  }

  # convert keywords
  foreach my $key (keys %{ $self->{keywords} }) {
    $self->{keywords}{$key} =~ s/\Q$value\E/\$\{$var\}/g;
  }

}

sub _interpolate_vars {
  my $self = shift;
  my ($string, $override) = @_;

  $override ||= {};

  foreach my $key (keys %$override) {
    carp "Overriden pkg-config variable $key, contains no data"
      unless $override->{$key};
  }

  if (defined $string) {
    1 while $string =~ s/\$\{(.*?)\}/$override->{$1} || $self->{vars}{$1}/e;
  }
  return $string;
}

sub keyword {
  my $self = shift;
  my ($keyword, $override) = @_;

  {
    no warnings 'uninitialized';
    croak "overrides passed to 'keyword' must be a hashref"
      if defined $override and ref $override ne 'HASH';
  }

  return $self->_interpolate_vars( $self->{keywords}{$keyword}, $override );
}

my $pkg_config_command;

sub pkg_config_command {
  unless (defined $pkg_config_command) {
    capture_stderr {

      # For now we prefer PkgConfig.pm over pkg-config on
      # Solaris 64 bit Perls.  We may need to do this on
      # other platforms, in which case this logic should
      # be abstracted so that it can be shared here and
      # in Build.PL

      if (`pkg-config --version` && $? == 0 && !($^O eq 'solaris' && $Config{ptrsize} == 8)) {
        $pkg_config_command = 'pkg-config';
      } else {
        require PkgConfig;
        $pkg_config_command = "$^X $INC{'PkgConfig.pm'}";
      }
    }
  }

  $pkg_config_command;
}

sub TO_JSON
{
  my($self) = @_;
  my %hash = %$self;
  $hash{'__CLASS__'} = ref($self);
  \%hash;
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Base::PkgConfig - Private legacy pkg-config class for Alien::Base

=head1 VERSION

version 2.84

=head1 DESCRIPTION

This class is used internally by L<Alien::Base> and L<Alien::Base::ModuleBuild>
to store information from pkg-config about installed Aliens.  It is not used
internally by the newer L<alienfile> and L<Alien::Build>.  It should never
be used externally, should not be used for code new inside of C<Alien-Build>.

=head1 SEE ALSO

=over

=item L<Alien::Base>

=item L<alienfile>

=item L<Alien::Build>

=back

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK9N%[��z3��perl5/Alien/Base/FAQ.podnu��6�$# ABSTRACT: Frequently asked questions
# VERSION
# PODNAME: Alien::Base::FAQ

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Base::FAQ - Frequently asked questions

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 % perldoc Alien::Build::Manual::FAQ
 % perldoc Alien::Base::ModuleBuild::FAQ

=head1 DESCRIPTION

This used to answer FAQs regarding the only way to author an L<Alien::Build>
distribution, which was with L<Alien::Base::ModuleBuild>.  You should now
seriously consider using the newer more reliable method which is via
L<Alien::Build> and L<alienfile>.

=over 4

=item L<Alien::Build::Manual::FAQ>

=item L<Alien::Base::ModuleBuild::FAQ>

=back

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK9N%[���Q�4�4perl5/Alien/Base/Wrapper.pmnu��6�$package Alien::Base::Wrapper;

use strict;
use warnings;
use 5.006;
use Config;
use Text::ParseWords qw( shellwords );

# NOTE: Although this module is now distributed with Alien-Build,
# it should have NO non-perl-core dependencies for all Perls
# 5.6.0-5.30.1 (as of this writing, and any Perl more recent).
# You should be able to extract this module from the rest of
# Alien-Build and use it by itself.  (There is a dzil plugin
# for this [AlienBase::Wrapper::Bundle]

# ABSTRACT: Compiler and linker wrapper for Alien
our $VERSION = '2.84'; # VERSION


sub _join
{
  join ' ',
    map {
      my $x = $_;
      $x =~ s/(\s)/\\$1/g;
      $x;
    } @_;
}

sub new
{
  my($class, @aliens) = @_;

  my $export = 1;
  my $writemakefile = 0;

  my @cflags_I;
  my @cflags_other;
  my @ldflags_L;
  my @ldflags_l;
  my @ldflags_other;
  my %requires = (
    'ExtUtils::MakeMaker'  => '6.52',
    'Alien::Base::Wrapper' => '1.97',
  );

  foreach my $alien (@aliens)
  {
    if($alien eq '!export')
    {
      $export = 0;
      next;
    }
    if($alien eq 'WriteMakefile')
    {
      $writemakefile = 1;
      next;
    }
    my $version = 0;
    if($alien =~ s/=(.*)$//)
    {
      $version = $1;
    }
    $alien = "Alien::$alien" unless $alien =~ /::/;
    $requires{$alien} = $version;
    my $alien_pm = $alien . '.pm';
    $alien_pm =~ s/::/\//g;
    require $alien_pm unless eval { $alien->can('cflags') } && eval { $alien->can('libs') };
    my $cflags;
    my $libs;
    if($alien->install_type eq 'share' && $alien->can('cflags_static'))
    {
      $cflags = $alien->cflags_static;
      $libs   = $alien->libs_static;
    }
    else
    {
      $cflags = $alien->cflags;
      $libs   = $alien->libs;
    }

    $cflags = '' unless defined $cflags;
    $libs = '' unless defined $libs;

    push @cflags_I,     grep  /^-I/, shellwords $cflags;
    push @cflags_other, grep !/^-I/, shellwords $cflags;

    push @ldflags_L,     grep  /^-L/,    shellwords $libs;
    push @ldflags_l,     grep  /^-l/,    shellwords $libs;
    push @ldflags_other, grep !/^-[Ll]/, shellwords $libs;
  }

  my @cflags_define = grep  /^-D/, @cflags_other;
  my @cflags_other2 = grep !/^-D/, @cflags_other;

  my @mm;

  push @mm, INC       => _join @cflags_I                             if @cflags_I;
  push @mm, CCFLAGS   => _join(@cflags_other2) . " $Config{ccflags}" if @cflags_other2;
  push @mm, DEFINE    => _join(@cflags_define)                       if @cflags_define;

  # TODO: handle spaces in -L paths
  push @mm, LIBS      => ["@ldflags_L @ldflags_l"];
  my @ldflags = (@ldflags_L, @ldflags_other);
  push @mm, LDDLFLAGS => _join(@ldflags) . " $Config{lddlflags}"     if @ldflags;
  push @mm, LDFLAGS   => _join(@ldflags) . " $Config{ldflags}"       if @ldflags;

  my @mb;

  push @mb, extra_compiler_flags => _join(@cflags_I, @cflags_other);
  push @mb, extra_linker_flags   => _join(@ldflags_l);

  if(@ldflags)
  {
    push @mb, config => {
      lddlflags => _join(@ldflags) . " $Config{lddlflags}",
      ldflags   => _join(@ldflags) . " $Config{ldflags}",
    },
  }

  bless {
    cflags_I       => \@cflags_I,
    cflags_other   => \@cflags_other,
    ldflags_L      => \@ldflags_L,
    ldflags_l      => \@ldflags_l,
    ldflags_other  => \@ldflags_other,
    mm             => \@mm,
    mb             => \@mb,
    _export        => $export,
    _writemakefile => $writemakefile,
    requires       => \%requires,
  }, $class;
}

my $default_abw = __PACKAGE__->new;

# for testing only
sub _reset { __PACKAGE__->new }


sub _myexec
{
  my @command = @_;
  if($^O eq 'MSWin32')
  {
    # To handle weird quoting on MSWin32
    # this logic needs to be improved.
    my $command = "@command";
    $command =~ s{"}{\\"}g;
    system $command;

    if($? == -1 )
    {
      die "failed to execute: $!\n";
    }
    elsif($? & 127)
    {
      die "child died with signal @{[ $? & 128 ]}";
    }
    else
    {
      exit($? >> 8);
    }
  }
  else
  {
    exec @command;
  }
}

sub cc
{
  my @command = (
    shellwords($Config{cc}),
    @{ $default_abw->{cflags_I} },
    @{ $default_abw->{cflags_other} },
    @ARGV,
  );
  print "@command\n" unless $ENV{ALIEN_BASE_WRAPPER_QUIET};
  _myexec @command;
}


sub ld
{
  my @command = (
    shellwords($Config{ld}),
    @{ $default_abw->{ldflags_L} },
    @{ $default_abw->{ldflags_other} },
    @ARGV,
    @{ $default_abw->{ldflags_l} },
  );
  print "@command\n" unless $ENV{ALIEN_BASE_WRAPPER_QUIET};
  _myexec @command;
}


sub mm_args
{
  my $self = ref $_[0] ? shift : $default_abw;
  @{ $self->{mm} };
}


sub mm_args2
{
  my $self = shift;
  $self = $default_abw unless ref $self;
  my %args = @_;

  my @mm = @{ $self->{mm} };

  while(@mm)
  {
    my $key = shift @mm;
    my $value = shift @mm;
    if(defined $args{$key})
    {
      if($args{$key} eq 'LIBS')
      {
        require Carp;
        # Todo: support this maybe?
        Carp::croak("please do not specify your own LIBS key with mm_args2");
      }
      else
      {
        $args{$key} = join ' ', $value, $args{$key};
      }
    }
    else
    {
      $args{$key} = $value;
    }
  }

  foreach my $module (keys %{ $self->{requires} })
  {
    $args{CONFIGURE_REQUIRES}->{$module} = $self->{requires}->{$module};
  }

  %args;
}


sub mb_args
{
  my $self = ref $_[0] ? shift : $default_abw;
  @{ $self->{mb} };
}

sub import
{
  shift;
  my $abw = $default_abw = __PACKAGE__->new(@_);
  if($abw->_export)
  {
    my $caller = caller;
    no strict 'refs';
    *{"${caller}::cc"} = \&cc;
    *{"${caller}::ld"} = \&ld;
  }
  if($abw->_writemakefile)
  {
    my $caller = caller;
    no strict 'refs';
    *{"${caller}::WriteMakefile"} = \&WriteMakefile;
  }
}


sub WriteMakefile
{
  my %args = @_;

  require ExtUtils::MakeMaker;
  ExtUtils::MakeMaker->VERSION('6.52');

  my @aliens;

  if(my $reqs = delete $args{alien_requires})
  {
    if(ref $reqs eq 'HASH')
    {
      @aliens = map {
        my $module  = $_;
        my $version = $reqs->{$module};
        $version ? "$module=$version" : "$module";
      } sort keys %$reqs;
    }
    elsif(ref $reqs eq 'ARRAY')
    {
      @aliens = @$reqs;
    }
    else
    {
      require Carp;
      Carp::croak("aliens_require must be either a hash or array reference");
    }
  }
  else
  {
    require Carp;
    Carp::croak("You are using Alien::Base::Wrapper::WriteMakefile, but didn't specify any alien requirements");
  }

  ExtUtils::MakeMaker::WriteMakefile(
    Alien::Base::Wrapper->new(@aliens)->mm_args2(%args),
  );
}

sub _export        { shift->{_export} }
sub _writemakefile { shift->{_writemakefile} }

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Base::Wrapper - Compiler and linker wrapper for Alien

=head1 VERSION

version 2.84

=head1 SYNOPSIS

From the command line:

 % perl -MAlien::Base::Wrapper=Alien::Foo,Alien::Bar -e cc -- -o foo.o -c foo.c
 % perl -MAlien::Base::Wrapper=Alien::Foo,Alien::Bar -e ld -- -o foo foo.o

From Makefile.PL (static):

 use ExtUtils::MakeMaker;
 use Alien::Base::Wrapper ();
 
 WriteMakefile(
   Alien::Base::Wrapper->new( 'Alien::Foo', 'Alien::Bar')->mm_args2(
     'NAME'              => 'Foo::XS',
     'VERSION_FROM'      => 'lib/Foo/XS.pm',
   ),
 );

From Makefile.PL (static with wrapper)

 use Alien::Base::Wrapper qw( WriteMakefile);
 
 WriteMakefile(
   'NAME'              => 'Foo::XS',
   'VERSION_FROM'      => 'lib/Foo/XS.pm',
   'alien_requires'    => {
     'Alien::Foo' => 0,
     'Alien::Bar' => 0,
   },
 );

From Makefile.PL (dynamic):

 use Devel::CheckLib qw( check_lib );
 use ExtUtils::MakeMaker 6.52;
 
 my @mm_args;
 my @libs;
 
 if(check_lib( lib => [ 'foo' ] )
 {
   push @mm_args, LIBS => [ '-lfoo' ];
 }
 else
 {
   push @mm_args,
     CC => '$(FULLPERL) -MAlien::Base::Wrapper=Alien::Foo -e cc --',
     LD => '$(FULLPERL) -MAlien::Base::Wrapper=Alien::Foo -e ld --',
     BUILD_REQUIRES => {
       'Alien::Foo'           => 0,
       'Alien::Base::Wrapper' => 0,
     }
   ;
 }
 
 WriteMakefile(
   'NAME'         => 'Foo::XS',
   'VERSION_FROM' => 'lib/Foo/XS.pm',
   'CONFIGURE_REQUIRES => {
     'ExtUtils::MakeMaker' => 6.52,
   },
   @mm_args,
 );

=head1 DESCRIPTION

This module acts as a wrapper around one or more L<Alien> modules.  It is designed to work
with L<Alien::Base> based aliens, but it should work with any L<Alien> which uses the same
essential API.

In the first example (from the command line), this class acts as a wrapper around the
compiler and linker that Perl is configured to use.  It takes the normal compiler and
linker flags and adds the flags provided by the Aliens specified, and then executes the
command.  It will print the command to the console so that you can see exactly what is
happening.

In the second example (from Makefile.PL non-dynamic), this class is used to generate the
appropriate L<ExtUtils::MakeMaker> (EUMM) arguments needed to C<WriteMakefile>.

In the third example (from Makefile.PL dynamic), we do a quick check to see if the simple
linker flag C<-lfoo> will work, if so we use that.  If not, we use a wrapper around the
compiler and linker that will use the alien flags that are known at build time.  The
problem that this form attempts to solve is that compiler and linker flags typically
need to be determined at I<configure> time, when a distribution is installed, meaning
if you are going to use an L<Alien> module then it needs to be a configure prerequisite,
even if the library is already installed and easily detected on the operating system.

The author of this module believes that the third (from Makefile.PL dynamic) form is
somewhat unnecessary.  L<Alien> modules based on L<Alien::Base> have a few prerequisites,
but they are well maintained and reliable, so while there is a small cost in terms of extra
dependencies, the overall reliability thanks to reduced overall complexity.

=head1 CONSTRUCTOR

=head2 new

 my $abw = Alien::Base::Wrapper->new(@aliens);

Instead of passing the aliens you want to use into this modules import you can create
a non-global instance of C<Alien::Base::Wrapper> using the OO interface.

=head1 FUNCTIONS

=head2 cc

 % perl -MAlien::Base::Wrapper=Alien::Foo -e cc -- cflags

Invoke the C compiler with the appropriate flags from C<Alien::Foo> and what
is provided on the command line.

=head2 ld

 % perl -MAlien::Base::Wrapper=Alien::Foo -e ld -- ldflags

Invoke the linker with the appropriate flags from C<Alien::Foo> and what
is provided on the command line.

=head2 mm_args

 my %args = $abw->mm_args;
 my %args = Alien::Base::Wrapper->mm_args;

Returns arguments that you can pass into C<WriteMakefile> to compile/link against
the specified Aliens.  Note that this does not set  C<CONFIGURE_REQUIRES>.  You
probably want to use C<mm_args2> below instead for that reason.

=head2 mm_args2

 my %args = $abw->mm_args2(%args);
 my %args = Alien::Base::Wrapper->mm_args2(%args);

Returns arguments that you can pass into C<WriteMakefile> to compile/link against.  It works
a little differently from C<mm_args> above in that you can pass in arguments.  It also adds
the appropriate C<CONFIGURE_REQUIRES> for you so you do not have to do that explicitly.

=head2 mb_args

 my %args = $abw->mb_args;
 my %args = Alien::Base::Wrapper->mb_args;

Returns arguments that you can pass into the constructor to L<Module::Build>.

=head2 WriteMakefile

 use Alien::Base::Wrapper qw( WriteMakefile );
 WriteMakefile(%args, alien_requires => \%aliens);
 WriteMakefile(%args, alien_requires => \@aliens);

This is a thin wrapper around C<WriteMakefile> from L<ExtUtils::MakeMaker>, which adds the
given aliens to the configure requirements and sets the appropriate compiler and linker
flags.

If the aliens are specified as a hash reference, then the keys are the module names and the
values are the versions.  For a list it is just the name of the aliens.

For the list form you can specify a version by appending C<=version> to the name of the
Aliens, that is:

 WriteMakefile(
   alien_requires => [ 'Alien::libfoo=1.23', 'Alien::libbar=4.56' ],
 );

The list form is recommended if the ordering of the aliens matter.  The aliens are sorted in
the hash form to make it consistent, but it may not be the order that you want.

=head1 ENVIRONMENT

Alien::Base::Wrapper responds to these environment variables:

=over 4

=item ALIEN_BASE_WRAPPER_QUIET

If set to true, do not print the command before executing

=back

=head1 SEE ALSO

L<Alien::Base>, L<Alien::Base>

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK9N%[(�����perl5/Alien/Util.pmnu��6�$package Alien::Util;

use strict;
use warnings;
use Exporter qw( import );

# ABSTRACT: Alien Utilities used at build and runtime
our $VERSION = '2.84'; # VERSION


our @EXPORT_OK = qw( version_cmp );


# Sort::Versions isn't quite the same algorithm because it differs in
# behaviour with leading zeroes.
#   See also  https://dev.gentoo.org/~mgorny/pkg-config-spec.html#version-comparison
sub version_cmp {
  my @x = (shift =~ m/([0-9]+|[a-z]+)/ig);
  my @y = (shift =~ m/([0-9]+|[a-z]+)/ig);

  while(@x and @y) {
    my $x = shift @x; my $x_isnum = $x =~ m/[0-9]/;
    my $y = shift @y; my $y_isnum = $y =~ m/[0-9]/;

    if($x_isnum and $y_isnum) {
      # Numerical comparison
      return $x <=> $y if $x != $y;
    }
    elsif(!$x_isnum && !$y_isnum) {
      # Alphabetic comparison
      return $x cmp $y if $x ne $y;
    }
    else {
      # Of differing types, the numeric one is newer
      return $x_isnum - $y_isnum;
    }
  }

  # Equal so far; the longer is newer
  return @x <=> @y;
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Alien::Util - Alien Utilities used at build and runtime

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 use Alien::Util qw( version_cmp );

=head1 DESCRIPTION

This module contains some functions used by both the L<Alien::Build> build-time and <Alien::Base>
run-time for Alien.

=head2 version_cmp

  $cmp = version_cmp($x, $y)

Comparison method used by L<Alien::Base/atleast_version>, L<Alien::Base/exact_version> and
L<Alien::Base/max_version>. May be useful to implement custom comparisons, or for
subclasses to overload to get different version comparison semantics than the
default rules, for packages that have some other rules than the F<pkg-config>
behaviour.

Should return a number less than, equal to, or greater than zero; similar in
behaviour to the C<< <=> >> and C<cmp> operators.

=head1 SEE ALSO

L<Alien::Base>, L<alienfile>, L<Alien::Build>

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut
PK9N%[3 D9�r�rperl5/Alien/Base.pmnu��6�$package Alien::Base;

use strict;
use warnings;
use 5.008004;
use Carp;
use Path::Tiny ();
use Scalar::Util qw/blessed/;
use Capture::Tiny 0.17 qw/capture_stdout/;
use Text::ParseWords qw/shellwords/;
use Alien::Util;

# ABSTRACT: Base classes for Alien:: modules
our $VERSION = '2.84'; # VERSION


sub import {
  my $class = shift;

  return if $class eq __PACKAGE__;

  return if $class->runtime_prop;

  return if $class->install_type('system');

  require DynaLoader;

  # Sanity check in order to ensure that dist_dir can be found.
  # This will throw an exception otherwise.
  $class->dist_dir;

  # get a reference to %Alien::MyLibrary::AlienLoaded
  # which contains names of already loaded libraries
  # this logic may be replaced by investigating the DynaLoader arrays
  my $loaded = do {
    no strict 'refs';
    no warnings 'once';
    \%{ $class . "::AlienLoaded" };
  };

  my @libs = $class->split_flags( $class->libs );

  my @L = grep { s/^-L// } map { "$_" } @libs;  ## no critic (ControlStructures::ProhibitMutatingListFunctions)
  my @l = grep { /^-l/ } @libs;

  unshift @DynaLoader::dl_library_path, @L;

  my @libpaths;
  foreach my $l (@l) {
    next if $loaded->{$l};

    my $path = DynaLoader::dl_findfile( $l );
    unless ($path) {
      carp "Could not resolve $l";
      next;
    }

    push @libpaths, $path;
    $loaded->{$l} = $path;
  }

  push @DynaLoader::dl_resolve_using, @libpaths;

  my @librefs = map { DynaLoader::dl_load_file( $_, 0x01 ) } grep !/\.(a|lib)$/, @libpaths;
  push @DynaLoader::dl_librefs, @librefs;

}


sub _dist_dir ($)
{
  my($dist_name) = @_;

  my @pm = split /-/, $dist_name;
  $pm[-1] .= ".pm";

  foreach my $inc (@INC)
  {
    my $pm = Path::Tiny->new($inc, @pm);
    if(-f $pm)
    {
      my $share = Path::Tiny->new($inc, qw( auto share dist ), $dist_name );
      if(-d $share)
      {
        return $share->absolute->stringify;
      }
      last;
    }
  }
  Carp::croak("unable to find dist share directory for $dist_name");
}

sub dist_dir {
  my $class = shift;

  my $dist = blessed $class || $class;
  $dist =~ s/::/-/g;

  my $dist_dir =
    $class->config('finished_installing')
      ? _dist_dir $dist
      : $class->config('working_directory');

  croak "Failed to find share dir for dist '$dist'"
    unless defined $dist_dir && -d $dist_dir;

  return $dist_dir;
}


sub new { return bless {}, $_[0] }

sub _flags
{
  my($class, $key) = @_;

  my $config = $class->runtime_prop;
  my $flags = $config->{$key};

  my $prefix = $config->{prefix};
  $prefix =~ s{\\}{/}g if $^O =~ /^(MSWin32|msys)$/;
  my $distdir = $config->{distdir};
  $distdir =~ s{\\}{/}g if $^O =~ /^(MSWin32|msys)$/;

  if(defined $flags && $prefix ne $distdir)
  {
    $flags = join ' ', map {
      my $flag = $_;
      $flag =~ s/^(-I|-L|-LIBPATH:)?\Q$prefix\E/$1$distdir/;
      $flag =~ s/(\s)/\\$1/g;
      $flag;
    } $class->split_flags($flags);
  }

  $flags;
}


sub cflags {
  my $class = shift;
  return $class->runtime_prop ? $class->_flags('cflags') : $class->_pkgconfig_keyword('Cflags');
}


sub cflags_static {
  my $class = shift;
  return $class->runtime_prop ? $class->_flags('cflags_static') : $class->_pkgconfig_keyword('Cflags', 'static');
}


sub libs {
  my $class = shift;
  return $class->runtime_prop ? $class->_flags('libs') : $class->_pkgconfig_keyword('Libs');
}


sub libs_static {
  my $class = shift;
  return $class->runtime_prop ? $class->_flags('libs_static') : $class->_pkgconfig_keyword('Libs', 'static');
}


sub version {
  my $self = shift;
  return $self->runtime_prop
    ? $self->runtime_prop->{version}
    : do {
      my $version = $self->config('version');
      chomp $version;
      $version;
    };
}


sub atleast_version {
  my $self = shift;
  my ($wantver) = @_;

  defined(my $version = $self->version) or
    croak "$self has no defined ->version";

  return $self->version_cmp($version, $wantver) >= 0;
}

sub exact_version {
  my $self = shift;
  my ($wantver) = @_;

  defined(my $version = $self->version) or
    croak "$self has no defined ->version";

  return $self->version_cmp($version, $wantver) == 0;
}

sub max_version {
  my $self = shift;
  my ($wantver) = @_;

  defined(my $version = $self->version) or
    croak "$self has no defined ->version";

  return $self->version_cmp($version, $wantver) <= 0;
}


sub version_cmp {
  shift;
  goto &Alien::Util::version_cmp;
}


sub install_type {
  my $self = shift;
  my $type = $self->config('install_type');
  return @_ ? $type eq $_[0] : $type;
}



sub is_system_install
{
  my($self) = @_;
  $self->install_type('system');
}


sub is_share_install
{
  my($self) = @_;
  $self->install_type('share');
}


sub _pkgconfig_keyword {
  my $self = shift;
  my $keyword = shift;
  my $static = shift;

  # use pkg-config if installed system-wide
  if ($self->install_type('system')) {
    my $name = $self->config('name');
    require Alien::Base::PkgConfig;
    my $command = Alien::Base::PkgConfig->pkg_config_command . " @{[ $static ? '--static' : '' ]} --\L$keyword\E $name";

    $! = 0;
    chomp ( my $pcdata = capture_stdout { system( $command ) } );

    # if pkg-config fails for whatever reason, then we try to
    # fallback on alien_provides_*
    $pcdata = '' if $! || $?;

    $pcdata =~ s/\s*$//;

    if($self->config('system_provides')) {
      if(my $system_provides = $self->config('system_provides')->{$keyword}) {
        $pcdata = length $pcdata ? "$pcdata $system_provides" : $system_provides;
      }
    }

    return $pcdata;
  }

  # use parsed info from build .pc file
  my $dist_dir = $self->dist_dir;
  my @pc = $self->_pkgconfig(@_);
  my @strings =
    grep defined,
    map { $_->keyword($keyword,
      #{ pcfiledir => $dist_dir }
    ) }
    @pc;

  if(defined $self->config('original_prefix') && $self->config('original_prefix') ne $self->dist_dir)
  {
    my $dist_dir = $self->dist_dir;
    $dist_dir =~ s{\\}{/}g if $^O eq 'MSWin32';
    my $old = quotemeta $self->config('original_prefix');
    @strings = map {
      my $flag = $_;
      $flag =~ s{^(-I|-L|-LIBPATH:)?($old)}{$1.$dist_dir}e;
      $flag =~ s/(\s)/\\$1/g;
      $flag;
    } map { $self->split_flags($_) } @strings;
  }

  return join( ' ', @strings );
}

sub _pkgconfig {
  my $self = shift;
  my %all = %{ $self->config('pkgconfig') };

  # merge in found pc files
  require File::Find;
  my $wanted = sub {
    return if ( -d or not /\.pc$/ );
    require Alien::Base::PkgConfig;
    my $pkg = Alien::Base::PkgConfig->new($_);
    $all{$pkg->{package}} = $pkg;
  };
  File::Find::find( $wanted, $self->dist_dir );

  croak "No Alien::Base::PkgConfig objects are stored!"
    unless keys %all;

  # Run through all pkgconfig objects and ensure that their modules are loaded:
  for my $pkg_obj (values %all) {
    my $perl_module_name = blessed $pkg_obj;
    my $pm = "$perl_module_name.pm";
    $pm =~ s/::/\//g;
    eval { require $pm };
  }

  return @all{@_} if @_;

  my $manual = delete $all{_manual};

  if (keys %all) {
    return values %all;
  } else {
    return $manual;
  }
}


# helper method to call Alien::MyLib::ConfigData->config(@_)
sub config {
  my $class = shift;
  $class = blessed $class || $class;

  if(my $ab_config = $class->runtime_prop)
  {
    my $key = shift;
    return $ab_config->{legacy}->{$key};
  }

  my $config = $class . '::ConfigData';
  my $pm = "$class/ConfigData.pm";
  $pm =~ s{::}{/}g;
  eval { require $pm };

  if($@)
  {
    warn "Cannot find either a share directory or a ConfigData module for $class.\n";
    my $pm = "$class.pm";
    $pm =~ s{::}{/}g;
    warn "($class loaded from $INC{$pm})\n" if $INC{$pm};
    warn "Please see https://metacpan.org/pod/distribution/Alien-Build/lib/Alien/Build/Manual/FAQ.pod#Cannot-find-either-a-share-directory-or-a-ConfigData-module\n";
    die $@;
  }

  return $config->config(@_);
}

# helper method to split flags based on the OS
sub split_flags {
  my ($class, $line) = @_;
  if( $^O eq 'MSWin32' ) {
    $class->split_flags_windows($line);
  } else {
    # $os eq 'Unix'
    $class->split_flags_unix($line);
  }
}

sub split_flags_unix {
  my ($class, $line) = @_;
  shellwords($line);
}

sub split_flags_windows {
  # NOTE a better approach would be to write a function that understands cmd.exe metacharacters.
  my ($class, $line) = @_;

  # Double the backslashes so that when they are unescaped by shellwords(),
  # they become a single backslash. This should be fine on Windows since
  # backslashes are not used to escape metacharacters in cmd.exe.
  $line =~ s,\\,\\\\,g;
  shellwords($line);
}


sub dynamic_libs {
  my ($class) = @_;

  require FFI::CheckLib;

  my @find_lib_flags;

  if($class->install_type('system')) {

    if(my $prop = $class->runtime_prop)
    {
      if($prop->{ffi_checklib}->{system})
      {
        push @find_lib_flags, @{ $prop->{ffi_checklib}->{system} };
      }
      return FFI::CheckLib::find_lib( lib => $prop->{ffi_name}, @find_lib_flags )
        if defined $prop->{ffi_name};
    }

    my $name = $class->config('ffi_name');
    unless(defined $name)
    {
      $name = $class->config('name');
      $name = '' unless defined $name;
      # strip leading lib from things like libarchive or libffi
      $name =~ s/^lib//;
      # strip trailing version numbers
      $name =~ s/-[0-9\.]+$//;
    }

    my @libpath;
    if(defined $class->libs)
    {
      foreach my $flag ($class->split_flags($class->libs))
      {
        if($flag =~ /^-L(.*)$/)
        {
          push @libpath, $1;
        }
      }
    }

    return FFI::CheckLib::find_lib(lib => $name, libpath => \@libpath, @find_lib_flags );

  } else {

    my $dir = $class->dist_dir;
    my $dynamic = Path::Tiny->new($class->dist_dir, 'dynamic');

    if(my $prop = $class->runtime_prop)
    {
      if($prop->{ffi_checklib}->{share})
      {
        push @find_lib_flags, @{ $prop->{ffi_checklib}->{share_flags} };
      }
    }

    if(-d $dynamic)
    {
      return FFI::CheckLib::find_lib(
        lib        => '*',
        libpath    => "$dynamic",
        systempath => [],
      );
    }

    return FFI::CheckLib::find_lib(
      lib        => '*',
      libpath    => $dir,
      systempath => [],
      recursive  => 1,
    );
  }
}


sub bin_dir {
  my ($class) = @_;
  if($class->install_type('system'))
  {
    my $prop = $class->runtime_prop;
    return () unless defined $prop;
    return () unless defined $prop->{system_bin_dir};
    return ref $prop->{system_bin_dir} ? @{ $prop->{system_bin_dir} } : ($prop->{system_bin_dir});
  }
  else
  {
    my $dir = Path::Tiny->new($class->dist_dir, 'bin');
    return -d $dir ? ("$dir") : ();
  }
}



sub dynamic_dir {
  my ($class) = @_;
  if($class->install_type('system'))
  {
    return ();
  }
  else
  {
    my $dir = Path::Tiny->new($class->dist_dir, 'dynamic');
    return -d $dir ? ("$dir") : ();
  }
}


sub alien_helper {
  {};
}


sub inline_auto_include {
  my ($class) = @_;
  $class->runtime_prop->{inline_auto_include} || $class->config('inline_auto_include') || []
}

sub Inline {
  my ($class, $language) = @_;
  return unless defined $language;
  return if $language !~ /^(C|CPP)$/;
  my $config = {
    # INC should arguably be for -I flags only, but
    # this improves compat with ExtUtils::Depends.
    # see gh#107, gh#108
    INC          => $class->cflags,
    LIBS         => $class->libs,
  };

  if (@{ $class->inline_auto_include } > 0) {
    $config->{AUTO_INCLUDE} = join "\n", map { "#include \"$_\"" } @{ $class->inline_auto_include };
  }

  $config;
}


{
  my %alien_build_config_cache;

  sub runtime_prop
  {
    my($class) = @_;

    if(ref($class))
    {
      # called as an instance method.
      my $self = $class;
      $class = ref $self;
      return $self->{_alt}->{runtime_prop} if defined $self->{_alt};
    }

    return $alien_build_config_cache{$class} if
      exists $alien_build_config_cache{$class};

    $alien_build_config_cache{$class} ||= do {
      my $dist = ref $class ? ref $class : $class;
      $dist =~ s/::/-/g;
      my $dist_dir = eval { _dist_dir $dist };
      return if $@;
      my $alien_json = Path::Tiny->new($dist_dir, '_alien', 'alien.json');
      return unless -r $alien_json;
      my $json = $alien_json->slurp;
      require JSON::PP;
      my $config = JSON::PP::decode_json($json);
      $config->{distdir} = $dist_dir;
      $config;
    };
  }
}


sub alt
{
  my($old, $name) = @_;
  my $new = ref $old ? (ref $old)->new : $old->new;

  my $orig;

  if(ref($old) && defined $old->{_alt})
  { $orig = $old->{_alt}->{orig} }
  else
  { $orig = $old->runtime_prop }

  require Storable;
  my $runtime_prop = Storable::dclone($orig);

  if($runtime_prop->{alt}->{$name})
  {
    foreach my $key (keys %{ $runtime_prop->{alt}->{$name} })
    {
      $runtime_prop->{$key} = $runtime_prop->{alt}->{$name}->{$key};
    }
  }
  else
  {
    Carp::croak("no such alt: $name");
  }

  $new->{_alt} = {
    runtime_prop => $runtime_prop,
    orig         => $orig,
  };

  $new;
}


sub alt_names
{
  my($class) = @_;
  my $alts = $class->runtime_prop->{alt};
  defined $alts
    ? sort keys %$alts
    : ();
}


sub alt_exists
{
  my($class, $alt_name) = @_;
  my $alts = $class->runtime_prop->{alt};
  defined $alts
    ? exists $alts->{$alt_name} && defined $alts->{$alt_name}
    : 0;
}

1;

=pod

=encoding UTF-8

=head1 NAME

Alien::Base - Base classes for Alien:: modules

=head1 VERSION

version 2.84

=head1 SYNOPSIS

 package Alien::MyLibrary;
 
 use strict;
 use warnings;
 
 use parent 'Alien::Base';
 
 1;

(for details on the C<Makefile.PL> or C<Build.PL> and L<alienfile>
that should be bundled with your L<Alien::Base> subclass, please see
L<Alien::Build::Manual::AlienAuthor>).

Then a C<MyLibrary::XS> can use C<Alien::MyLibrary> in its C<Makefile.PL>:

 use Alien::MyLibrary
 use ExtUtils::MakeMaker;
 use Alien::Base::Wrapper qw( Alien::MyLibrary !export );
 use Config;
 
 WriteMakefile(
   ...
   Alien::Base::Wrapper->mm_args,
   ...
 );

Or if you prefer L<Module::Build>, in its C<Build.PL>:

 use Alien::MyLibrary;
 use Module::Build 0.28; # need at least 0.28
 use Alien::Base::Wrapper qw( Alien::MyLibrary !export );
 
 my $builder = Module::Build->new(
   ...
   Alien::Base::Wrapper->mb_args,
   ...
 );
 
 $builder->create_build_script;

Or if you are using L<ExtUtils::Depends>:

 use ExtUtils::MakeMaker;
 use ExtUtils::Depends;
 my $eud = ExtUtils::Depends->new(qw( MyLibrary::XS Alien::MyLibrary ));
 WriteMakefile(
   ...
   $eud->get_makefile_vars
 );

If you are using L<Alien::Base::ModuleBuild> instead of the recommended L<Alien::Build>
and L<alienfile>, then in your C<MyLibrary::XS> module, you may need something like
this in your main C<.pm> file IF your library uses dynamic libraries:

 package MyLibrary::XS;
 
 use Alien::MyLibrary; # may only be needed if you are using Alien::Base::ModuleBuild
 
 ...

Or you can use it from an FFI module:

 package MyLibrary::FFI;
 
 use Alien::MyLibrary;
 use FFI::Platypus;
 use FFI::CheckLib 0.28 qw( find_lib_or_die );
 
 my $ffi = FFI::Platypus->new;
 $ffi->lib(find_lib_or_die lib => 'mylib', alien => ['Alien::MyLibrary']);
 
 $ffi->attach( 'my_library_function' => [] => 'void' );

You can even use it with L<Inline> (C and C++ languages are supported):

 package MyLibrary::Inline;
 
 use Alien::MyLibrary;
 # Inline 0.56 or better is required
 use Inline 0.56 with => 'Alien::MyLibrary';
 ...

=head1 DESCRIPTION

B<NOTE>: L<Alien::Base::ModuleBuild> is no longer bundled with L<Alien::Base> and has been spun off into a separate distribution.
L<Alien::Base::ModuleBuild> will be a prerequisite for L<Alien::Base> until October 1, 2017.  If you are using L<Alien::Base::ModuleBuild>
you need to make sure it is declared as a C<configure_requires> in your C<Build.PL>.  You may want to also consider using L<Alien::Base> and
L<alienfile> as a more modern alternative.

L<Alien::Base> comprises base classes to help in the construction of C<Alien::> modules. Modules in the L<Alien> namespace are used to locate and install (if necessary) external libraries needed by other Perl modules.

This is the documentation for the L<Alien::Base> module itself. If you
are starting out you probably want to do so from one of these documents:

=over 4

=item L<Alien::Build::Manual::AlienUser>

For users of an C<Alien::libfoo> that is implemented using L<Alien::Base>.
(The developer of C<Alien::libfoo> I<should> provide the documentation
necessary, but if not, this is the place to start).

=item L<Alien::Build::Manual::AlienAuthor>

If you are writing your own L<Alien> based on L<Alien::Build> and L<Alien::Base>.

=item L<Alien::Build::Manual::FAQ>

If you have a common question that has already been answered, like
"How do I use L<alienfile> with some build system".

=item L<Alien::Build::Manual::PluginAuthor>

This is for the brave souls who want to write plugins that will work with
L<Alien::Build> + L<alienfile>.

=back

Before using an L<Alien::Base> based L<Alien> directly, please consider the following advice:

If you are wanting to use an L<Alien::Base> based L<Alien> with an XS module using L<ExtUtils::MakeMaker> or L<Module::Build>, it is highly
recommended that you use L<Alien::Base::Wrapper>, rather than using the L<Alien> directly, because it handles a number of sharp edges and avoids
pitfalls common when trying to use an L<Alien> directly with L<ExtUtils::MakeMaker>.

In the same vein, if you are wanting to use an L<Alien::Base> based L<Alien> with an XS module using L<Dist::Zilla> it is highly recommended
that you use L<Dist::Zilla::Plugin::AlienBase::Wrapper> for the same reasons.

As of version 0.28, L<FFI::CheckLib> has a good interface for working with L<Alien::Base> based L<Alien>s in fallback mode, which is
recommended.

You should typically only be using an L<Alien::Base> based L<Alien> directly, if you need to integrate it with some other system, or if it
is a tool based L<Alien> that you don't need to link.

The above synopsis and linked manual documents will lead you down the right path, but it is worth knowing before you read further in this
document.

=head1 METHODS

In the example snippets here, C<Alien::MyLibrary> represents any
subclass of L<Alien::Base>.

=head2 dist_dir

 my $dir = Alien::MyLibrary->dist_dir;

Returns the directory that contains the install root for
the packaged software, if it was built from install (i.e., if
C<install_type> is C<share>).

=head2 new

 my $alien = Alien::MyLibrary->new;

Creates an instance of an L<Alien::Base> object.  This is typically
unnecessary.

=head2 cflags

 my $cflags = Alien::MyLibrary->cflags;
 
 use Text::ParseWords qw( shellwords );
 my @cflags = shellwords( Alien::MyLibrary->cflags );

Returns the C compiler flags necessary to compile an XS
module using the alien software.  If you need this in list
form (for example if you are calling system with a list
argument) you can pass this value into C<shellwords> from
the Perl core L<Text::ParseWords> module.

=head2 cflags_static

 my $cflags = Alien::MyLibrary->cflags_static;

Same as C<cflags> above, but gets the static compiler flags,
if they are different.

=head2 libs

 my $libs = Alien::MyLibrary->libs;
 
 use Text::ParseWords qw( shellwords );
 my @cflags = shellwords( Alien::MyLibrary->libs );

Returns the library linker flags necessary to link an XS
module against the alien software.  If you need this in list
form (for example if you are calling system with a list
argument) you can pass this value into C<shellwords> from
the Perl core L<Text::ParseWords> module.

=head2 libs_static

 my $libs = Alien::MyLibrary->libs_static;

Same as C<libs> above, but gets the static linker flags,
if they are different.

=head2 version

 my $version = Alien::MyLibrary->version;

Returns the version of the alienized library or tool that was
determined at install time.

=head2 atleast_version

=head2 exact_version

=head2 max_version

 my $ok = Alien::MyLibrary->atleast_version($wanted_version);
 my $ok = Alien::MyLibrary->exact_version($wanted_version);
 my $ok = Alien::MyLibrary->max_version($wanted_version);

Returns true if the version of the alienized library or tool is at least,
exactly, or at most the version specified, respectively.

=head2 version_cmp

  $cmp = Alien::MyLibrary->version_cmp($x, $y)

Comparison method used by L</atleast_version>, L</exact_version> and
L</max_version>. May be useful to implement custom comparisons, or for
subclasses to overload to get different version comparison semantics than the
default rules, for packages that have some other rules than the F<pkg-config>
behaviour.

Should return a number less than, equal to, or greater than zero; similar in
behaviour to the C<< <=> >> and C<cmp> operators.

=head2 install_type

 my $install_type = Alien::MyLibrary->install_type;
 my $bool = Alien::MyLibrary->install_type($install_type);

Returns the install type that was used when C<Alien::MyLibrary> was
installed.  

If a type is provided (the second form in the synopsis)
returns true if the actual install type matches.  
For this use case it is recommended to use C<is_system_install> 
or C<is_share_install> instead as these are less prone to 
typographical errors.

Types include:

=over 4

=item system

The library was provided by the operating system

=item share

The library was not available when C<Alien::MyLibrary> was installed, so
it was built from source code, either downloaded from the Internet
or bundled with C<Alien::MyLibrary>.

=back

=head2 is_system_install

 my $type = $build->is_system_install;

Returns true if the alien is a system install type.  

=head2 is_share_install

 my $type = $build->is_share_install;

Returns true if the alien is a share install type.  

=head2 config

 my $value = Alien::MyLibrary->config($key);

Returns the configuration data as determined during the install
of C<Alien::MyLibrary>.  For the appropriate config keys, see
L<Alien::Base::ModuleBuild::API/"CONFIG DATA">.

This is not typically used by L<Alien::Base> and L<alienfile>,
but a compatible interface will be provided.

=head2 dynamic_libs

 my @dlls = Alien::MyLibrary->dynamic_libs;
 my($dll) = Alien::MyLibrary->dynamic_libs;

Returns a list of the dynamic library or shared object files for the
alien software.

=head2 bin_dir

 my(@dir) = Alien::MyLibrary->bin_dir

Returns a list of directories with executables in them.  For a C<system>
install this will be an empty list.  For a C<share> install this will be
a directory under C<dist_dir> named C<bin> if it exists.  You may wish
to override the default behavior if you have executables or scripts that
get installed into non-standard locations.

Example usage:

 use Env qw( @PATH );
 
 unshift @PATH, Alien::MyLibrary->bin_dir;

=head2 dynamic_dir

 my(@dir) = Alien::MyLibrary->dynamic_dir

Returns the dynamic dir for a dynamic build (if the main
build is static).  For a C<share> install this will be a
directory under C<dist_dir> named C<dynamic> if it exists.
System builds return an empty list.

Example usage:

 use Env qw( @PATH );
 
 unshift @PATH, Alien::MyLibrary->dynamic_dir;

=head2 alien_helper

 my $helpers = Alien::MyLibrary->alien_helper;

Returns a hash reference of helpers provided by the Alien module.
The keys are helper names and the values are code references.  The
code references will be executed at command time and the return value
will be interpolated into the command before execution.  The default
implementation returns an empty hash reference, and you are expected
to override the method to create your own helpers.

For use with commands specified in and L<alienfile> or in your C<Build.Pl>
when used with L<Alien::Base::ModuleBuild>.

Helpers allow users of your Alien module to use platform or environment
determined logic to compute command names or arguments in your installer
logic.  Helpers allow you to do this without making your Alien module a
requirement when a build from source code is not necessary.

As a concrete example, consider L<Alien::gmake>, which provides the
helper C<gmake>:

 package Alien::gmake;
 
 ...
 
 sub alien_helper {
   my($class) = @_;
   return {
     gmake => sub {
       # return the executable name for GNU make,
       # usually either make or gmake depending on
       # the platform and environment
       $class->exe;
     }
   },
 }

Now consider L<Alien::nasm>.  C<nasm> requires GNU Make to build from
source code, but if the system C<nasm> package is installed we don't
need it.  From the L<alienfile> of C<Alien::nasm>:

 use alienfile;
 
 plugin 'Probe::CommandLine' => (
   command => 'nasm',
   args    => ['-v'],
   match   => qr/NASM version/,
 );
 
 share {
   ...
   plugin 'Extract' => 'tar.gz';
   plugin 'Build::MSYS';
 
   build [
     'sh configure --prefix=%{alien.install.prefix}',
     '%{gmake}',
     '%{gmake} install',
   ];
 };
 
 ...

=head2 inline_auto_include

 my(@headers) = Alien::MyLibrary->inline_auto_include;

List of header files to automatically include in inline C and C++
code when using L<Inline::C> or L<Inline::CPP>.  This is provided
as a public interface primarily so that it can be overridden at run
time.  This can also be specified in your C<Build.PL> with
L<Alien::Base::ModuleBuild> using the C<alien_inline_auto_include>
property.

=head2 runtime_prop

 my $hashref = Alien::MyLibrary->runtime_prop;

Returns a hash reference of the runtime properties computed by L<Alien::Build> during its
install process.  If the L<Alien::Base> based L<Alien> was not built using L<Alien::Build>,
then this will return undef.

=head2 alt

 my $new_alien = Alien::MyLibrary->alt($alt_name);
 my $new_alien = $old_alien->alt($alt_name);

Returns an L<Alien::Base> instance with the alternate configuration.

Some packages come with multiple libraries, and multiple C<.pc> files to
use with them.  This method can be used with C<pkg-config> plugins to
access different configurations.  (It could also be used with non-pkg-config
based packages too, though there are not as of this writing any build
time plugins that take advantage of this feature).

From your L<alienfile>

 use alienfile;
 
 plugin 'PkgConfig' => (
   pkg_name => [ 'libfoo', 'libbar', ],
 );

Then in your base class works like normal:

 package Alien::MyLibrary;
 
 use parent qw( Alien::Base );
 
 1;

Then you can use it:

 use Alien::MyLibrary;
 
 my $cflags = Alien::MyLibrary->alt('foo1')->cflags;
 my $libs   = Alien::MyLibrary->alt('foo1')->libs;

=head2 alt_names

 my @alt_names = Alien::MyLibrary->alt_names

Returns the list of all available alternative configuration names.

=head2 alt_exists

 my $bool = Alien::MyLibrary->alt_exists($alt_name)

Returns true if the given alternative configuration exists.

=head1 SUPPORT AND CONTRIBUTING

First check the L<Alien::Build::Manual::FAQ> for questions that have already been answered.

IRC: #native on irc.perl.org

L<(click for instant chatroom login)|http://chat.mibbit.com/#native@irc.perl.org>

If you find a bug, please report it on the projects issue tracker on GitHub:

=over 4

=item L<https://github.com/PerlAlien/Alien-Build/issues>

=back

Development is discussed on the projects google groups.  This is also
a reasonable place to post a question if you don't want to open an issue
in GitHub.

=over 4

=item L<https://groups.google.com/forum/#!forum/perl5-alien>

=back

If you have implemented a new feature or fixed a bug, please open a pull
request.

=over 4

=item L<https://github.com/PerlAlien/Alien-Build/pulls>

=back

=head1 SEE ALSO

=over

=item *

L<Alien::Build>

=item *

L<alienfile>

=item *

L<Alien>

=item *

L<Alien::Build::Manual::FAQ>

=back

=head1 THANKS

C<Alien::Base> was originally written by Joel Berger, and that
code is still Copyright (C) 2012-2017 Joel Berger.  It has the
same license as the rest of the L<Alien::Build>.

Special thanks for the early development of C<Alien::Base> go to:

=over

=item Christian Walde (Mithaldu)

For productive conversations about component interoperability.

=item kmx

For writing Alien::Tidyp from which I drew many of my initial ideas.

=item David Mertens (run4flat)

For productive conversations about implementation.

=item Mark Nunberg (mordy, mnunberg)

For graciously teaching me about rpath and dynamic loading,

=back

=head1 AUTHOR

Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>

Contributors:

Diab Jerius (DJERIUS)

Roy Storey (KIWIROY)

Ilya Pavlov

David Mertens (run4flat)

Mark Nunberg (mordy, mnunberg)

Christian Walde (Mithaldu)

Brian Wightman (MidLifeXis)

Zaki Mughal (zmughal)

mohawk (mohawk2, ETJ)

Vikas N Kumar (vikasnkumar)

Flavio Poletti (polettix)

Salvador Fandiño (salva)

Gianni Ceccarelli (dakkar)

Pavel Shaydo (zwon, trinitum)

Kang-min Liu (劉康民, gugod)

Nicholas Shipp (nshp)

Juan Julián Merelo Guervós (JJ)

Joel Berger (JBERGER)

Petr Písař (ppisar)

Lance Wicks (LANCEW)

Ahmad Fatoum (a3f, ATHREEF)

José Joaquín Atria (JJATRIA)

Duke Leto (LETO)

Shoichi Kaji (SKAJI)

Shawn Laffan (SLAFFAN)

Paul Evans (leonerd, PEVANS)

Håkon Hægland (hakonhagland, HAKONH)

nick nauwelaerts (INPHOBIA)

Florian Weimer

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011-2022 by Graham Ollis.

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

=cut

__END__
__POD__

PK9N%[�nP� � perl5/Time/Zone.pmnu��6�$
package Time::Zone;

=head1 NAME

Time::Zone -- miscellaneous timezone manipulations routines

=head1 SYNOPSIS

	use Time::Zone;
	print tz2zone();
	print tz2zone($ENV{'TZ'});
	print tz2zone($ENV{'TZ'}, time());
	print tz2zone($ENV{'TZ'}, undef, $isdst);
	$offset = tz_local_offset();
	$offset = tz_offset($TZ);

=head1 DESCRIPTION

This is a collection of miscellaneous timezone manipulation routines.

C<tz2zone()> parses the TZ environment variable and returns a timezone
string suitable for inclusion in L<date(1)>-like output.  It opionally takes
a timezone string, a time, and a is-dst flag.

C<tz_local_offset()> determins the offset from GMT time in seconds.  It
only does the calculation once.

C<tz_offset()> determines the offset from GMT in seconds of a specified
timezone.  

C<tz_name()> determines the name of the timezone based on its offset

=head1 AUTHORS

Graham Barr <gbarr@pobox.com>
David Muir Sharnoff <muir@idiom.com>
Paul Foley <paul@ascent.com>

=cut

require 5.002;

require Exporter;
use Carp;
use strict;
use vars qw(@ISA @EXPORT $VERSION @tz_local);

@ISA = qw(Exporter);
@EXPORT = qw(tz2zone tz_local_offset tz_offset tz_name);
$VERSION = "2.24";

# Parts stolen from code by Paul Foley <paul@ascent.com>

sub tz2zone (;$$$)
{
	my($TZ, $time, $isdst) = @_;

	use vars qw(%tzn_cache);

	$TZ = defined($ENV{'TZ'}) ? ( $ENV{'TZ'} ? $ENV{'TZ'} : 'GMT' ) : ''
	    unless $TZ;

	# Hack to deal with 'PST8PDT' format of TZ
	# Note that this can't deal with all the esoteric forms, but it
	# does recognize the most common: [:]STDoff[DST[off][,rule]]

	if (! defined $isdst) {
		my $j;
		$time = time() unless $time;
		($j, $j, $j, $j, $j, $j, $j, $j, $isdst) = localtime($time);
	}

	if (defined $tzn_cache{$TZ}->[$isdst]) {
		return $tzn_cache{$TZ}->[$isdst];
	}
      
	if ($TZ =~ /^
		    ( [^:\d+\-,] {3,} )
		    ( [+-] ?
		      \d {1,2}
		      ( : \d {1,2} ) {0,2} 
		    )
		    ( [^\d+\-,] {3,} )?
		    /x
	    ) {
		my $dsttz = defined($4) ? $4 : $1;
		$TZ = $isdst ? $dsttz : $1;
		$tzn_cache{$TZ} = [ $1, $dsttz ];
	} else {
		$tzn_cache{$TZ} = [ $TZ, $TZ ];
	}
	return $TZ;
}

sub tz_local_offset (;$)
{
	my ($time) = @_;

	$time = time() unless $time;
	my (@l) = localtime($time);
	my $isdst = $l[8];

	if (defined($tz_local[$isdst])) {
		return $tz_local[$isdst];
	}

	$tz_local[$isdst] = &calc_off($time);

	return $tz_local[$isdst];
}

sub calc_off
{
	my ($time) = @_;

	my (@l) = localtime($time);
	my (@g) = gmtime($time);

	my $off;

	$off =     $l[0] - $g[0]
		+ ($l[1] - $g[1]) * 60
		+ ($l[2] - $g[2]) * 3600;

	# subscript 7 is yday.

	if ($l[7] == $g[7]) {
		# done
	} elsif ($l[7] == $g[7] + 1) {
		$off += 86400;
	} elsif ($l[7] == $g[7] - 1) {
		$off -= 86400;
	} elsif ($l[7] < $g[7]) {
		# crossed over a year boundry!
		# localtime is beginning of year, gmt is end
		# therefore local is ahead
		$off += 86400;
	} else {
		$off -= 86400;
	}

	return $off;
}

# constants

CONFIG: {
	use vars qw(%dstZone %zoneOff %dstZoneOff %Zone);

	my @dstZone = (
	#   "ndt"  =>   -2*3600-1800,	 # Newfoundland Daylight   
	    "brst" =>   -2*3600,         # Brazil Summer Time (East Daylight)
	    "adt"  =>   -3*3600,  	 # Atlantic Daylight   
	    "edt"  =>   -4*3600,  	 # Eastern Daylight
	    "cdt"  =>   -5*3600,  	 # Central Daylight
	    "mdt"  =>   -6*3600,  	 # Mountain Daylight
	    "pdt"  =>   -7*3600,  	 # Pacific Daylight
	    "akdt" =>   -8*3600,         # Alaska Daylight
	    "ydt"  =>   -8*3600,  	 # Yukon Daylight
	    "hdt"  =>   -9*3600,  	 # Hawaii Daylight
	    "bst"  =>   +1*3600,  	 # British Summer   
	    "mest" =>   +2*3600,  	 # Middle European Summer   
	    "metdst" => +2*3600, 	 # Middle European DST
	    "sst"  =>   +2*3600,  	 # Swedish Summer
	    "fst"  =>   +2*3600,  	 # French Summer
            "cest" =>   +2*3600,         # Central European Daylight
            "eest" =>   +3*3600,         # Eastern European Summer
            "msd"  =>   +4*3600,         # Moscow Daylight
	    "wadt" =>   +8*3600,  	 # West Australian Daylight
	    "kdt"  =>  +10*3600,	 # Korean Daylight
	#   "cadt" =>  +10*3600+1800,	 # Central Australian Daylight
	    "aedt" =>  +11*3600,  	 # Eastern Australian Daylight
	    "eadt" =>  +11*3600,  	 # Eastern Australian Daylight
	    "nzd"  =>  +13*3600,  	 # New Zealand Daylight   
	    "nzdt" =>  +13*3600,  	 # New Zealand Daylight   
	);

	my @Zone = (
	    "gmt"	=>   0,  	 # Greenwich Mean
	    "ut"        =>   0,  	 # Universal (Coordinated)
	    "utc"       =>   0,
	    "wet"       =>   0,  	 # Western European
	    "wat"       =>  -1*3600,	 # West Africa
	    "at"        =>  -2*3600,	 # Azores
	    "fnt"	=>  -2*3600,	 # Brazil Time (Extreme East - Fernando Noronha)
	    "brt"	=>  -3*3600,	 # Brazil Time (East Standard - Brasilia)
	# For completeness.  BST is also British Summer, and GST is also Guam Standard.
	#   "bst"       =>  -3*3600,	 # Brazil Standard
	#   "gst"       =>  -3*3600,	 # Greenland Standard
	#   "nft"       =>  -3*3600-1800,# Newfoundland
	#   "nst"       =>  -3*3600-1800,# Newfoundland Standard
	    "mnt"	=>  -4*3600,	 # Brazil Time (West Standard - Manaus)
	    "ewt"       =>  -4*3600,	 # U.S. Eastern War Time
	    "ast"       =>  -4*3600,	 # Atlantic Standard
	    "est"       =>  -5*3600,	 # Eastern Standard
	    "act"	=>  -5*3600,	 # Brazil Time (Extreme West - Acre)
	    "cst"       =>  -6*3600,	 # Central Standard
	    "mst"       =>  -7*3600,	 # Mountain Standard
	    "pst"       =>  -8*3600,	 # Pacific Standard
	    "akst"      =>  -9*3600,     # Alaska Standard
	    "yst"	=>  -9*3600,	 # Yukon Standard
	    "hst"	=> -10*3600,	 # Hawaii Standard
	    "cat"	=> -10*3600,	 # Central Alaska
	    "ahst"	=> -10*3600,	 # Alaska-Hawaii Standard
	    "nt"	=> -11*3600,	 # Nome
	    "idlw"	=> -12*3600,	 # International Date Line West
	    "cet"	=>  +1*3600, 	 # Central European
	    "mez"	=>  +1*3600, 	 # Central European (German)
	    "ect"	=>  +1*3600, 	 # Central European (French)
	    "met"	=>  +1*3600, 	 # Middle European
	    "mewt"	=>  +1*3600, 	 # Middle European Winter
	    "swt"	=>  +1*3600, 	 # Swedish Winter
	    "set"	=>  +1*3600, 	 # Seychelles
	    "fwt"	=>  +1*3600, 	 # French Winter
	    "eet"	=>  +2*3600, 	 # Eastern Europe, USSR Zone 1
	    "ukr"	=>  +2*3600, 	 # Ukraine
	    "bt"	=>  +3*3600, 	 # Baghdad, USSR Zone 2
            "msk"       =>  +3*3600,     # Moscow
	#   "it"	=>  +3*3600+1800,# Iran
	    "zp4"	=>  +4*3600, 	 # USSR Zone 3
	    "zp5"	=>  +5*3600, 	 # USSR Zone 4
	#   "ist"	=>  +5*3600+1800,# Indian Standard
	    "zp6"	=>  +6*3600, 	 # USSR Zone 5
	# For completeness.  NST is also Newfoundland Stanard, and SST is also Swedish Summer.
	#   "nst"	=>  +6*3600+1800,# North Sumatra
	#   "sst"	=>  +7*3600, 	 # South Sumatra, USSR Zone 6
	#   "jt"	=>  +7*3600+1800,# Java (3pm in Cronusland!)
	    "wst"	=>  +8*3600, 	 # West Australian Standard
	    "hkt"	=>  +8*3600, 	 # Hong Kong
	    "cct"	=>  +8*3600, 	 # China Coast, USSR Zone 7
	    "jst"	=>  +9*3600,	 # Japan Standard, USSR Zone 8
	    "kst"	=>  +9*3600,	 # Korean Standard
	#   "cast"	=>  +9*3600+1800,# Central Australian Standard
	    "aest"	=> +10*3600,	 # Eastern Australian Standard
	    "east"	=> +10*3600,	 # Eastern Australian Standard
	    "gst"	=> +10*3600,	 # Guam Standard, USSR Zone 9
	    "nzt"	=> +12*3600,	 # New Zealand
	    "nzst"	=> +12*3600,	 # New Zealand Standard
	    "idle"	=> +12*3600,	 # International Date Line East
	);

	%Zone = @Zone;
	%dstZone = @dstZone;
	%zoneOff = reverse(@Zone);
	%dstZoneOff = reverse(@dstZone);

}

sub tz_offset (;$$)
{
	my ($zone, $time) = @_;

	return &tz_local_offset($time) unless($zone);

	$time = time() unless $time;
	my(@l) = localtime($time);
	my $dst = $l[8];

	$zone = lc $zone;

	if($zone =~ /^(([\-\+])\d\d?)(\d\d)$/) {
		my $v = $2 . $3;
		return $1 * 3600 + $v * 60;
	} elsif (exists $dstZone{$zone} && ($dst || !exists $Zone{$zone})) {
		return $dstZone{$zone};
	} elsif(exists $Zone{$zone}) {
		return $Zone{$zone};
	}
	undef;
}

sub tz_name (;$$)
{
	my ($off, $dst) = @_;

	$off = tz_offset()
		unless(defined $off);

	$dst = (localtime(time))[8]
		unless(defined $dst);

	if (exists $dstZoneOff{$off} && ($dst || !exists $zoneOff{$off})) {
		return $dstZoneOff{$off};
	} elsif (exists $zoneOff{$off}) {
		return $zoneOff{$off};
	}
	sprintf("%+05d", int($off / 60) * 100 + $off % 60);
}

1;
PK9N%[����perl5/IO/InnerFile.pmnu��6�$package IO::InnerFile;

use strict;
use warnings;
use Symbol;

our $VERSION = '2.113';

sub new {
   my ($class, $fh, $start, $lg) = @_;
   $start = 0 if (!$start or ($start < 0));
   $lg    = 0 if (!$lg    or ($lg    < 0));

   ### Create the underlying "object":
   my $a = {
      FH 	=> 	$fh,
      CRPOS 	=> 	0,
      START	=>	$start,
      LG	=>	$lg,
   };

   ### Create a new filehandle tied to this object:
   $fh = gensym;
   tie(*$fh, $class, $a);
   return bless($fh, $class);
}

sub TIEHANDLE {
   my ($class, $data) = @_;
   return bless($data, $class);
}

sub DESTROY {
   my ($self) = @_;
   $self->close() if (ref($self) eq 'SCALAR');
}

sub set_length { tied(${$_[0]})->{LG} = $_[1]; }
sub get_length { tied(${$_[0]})->{LG}; }
sub add_length { tied(${$_[0]})->{LG} += $_[1]; }

sub set_start  { tied(${$_[0]})->{START} = $_[1]; }
sub get_start  { tied(${$_[0]})->{START}; }
sub set_end    { tied(${$_[0]})->{LG} =  $_[1] - tied(${$_[0]})->{START}; }
sub get_end    { tied(${$_[0]})->{LG} + tied(${$_[0]})->{START}; }

sub write    { shift->WRITE(@_) }
sub print    { shift->PRINT(@_) }
sub printf   { shift->PRINTF(@_) }
sub flush    { "0 but true"; }
sub fileno   { }
sub binmode  { 1; }
sub getc     { return GETC(tied(${$_[0]}) ); }
sub read     { return READ(     tied(${$_[0]}), @_[1,2,3] ); }
sub readline { return READLINE( tied(${$_[0]}) ); }

sub getline  { return READLINE( tied(${$_[0]}) ); }
sub close    { return CLOSE(tied(${$_[0]}) ); }

sub seek {
   my ($self, $ofs, $whence) = @_;
   $self = tied( $$self );

   $self->{CRPOS} = $ofs if ($whence == 0);
   $self->{CRPOS}+= $ofs if ($whence == 1);
   $self->{CRPOS} = $self->{LG} + $ofs if ($whence == 2);

   $self->{CRPOS} = 0 if ($self->{CRPOS} < 0);
   $self->{CRPOS} = $self->{LG} if ($self->{CRPOS} > $self->{LG});
   return 1;
}

sub tell {
    return tied(${$_[0]})->{CRPOS};
}

sub WRITE  {
    die "inner files can only open for reading\n";
}

sub PRINT  {
    die "inner files can only open for reading\n";
}

sub PRINTF {
    die "inner files can only open for reading\n";
}

sub GETC   {
    my ($self) = @_;
    return 0 if ($self->{CRPOS} >= $self->{LG});

    my $data;

    ### Save and seek...
    my $old_pos = $self->{FH}->tell;
    $self->{FH}->seek($self->{CRPOS}+$self->{START}, 0);

    ### ...read...
    my $lg = $self->{FH}->read($data, 1);
    $self->{CRPOS} += $lg;

    ### ...and restore:
    $self->{FH}->seek($old_pos, 0);

    $self->{LG} = $self->{CRPOS} unless ($lg);
    return ($lg ? $data : undef);
}

sub READ   {
    my ($self, $undefined, $lg, $ofs) = @_;
    $undefined = undef;

    return 0 if ($self->{CRPOS} >= $self->{LG});
    $lg = $self->{LG} - $self->{CRPOS} if ($self->{CRPOS} + $lg > $self->{LG});
    return 0 unless ($lg);

    ### Save and seek...
    my $old_pos = $self->{FH}->tell;
    $self->{FH}->seek($self->{CRPOS}+$self->{START}, 0);

    ### ...read...
    $lg = $self->{FH}->read($_[1], $lg, $_[3] );
    $self->{CRPOS} += $lg;

    ### ...and restore:
    $self->{FH}->seek($old_pos, 0);

    $self->{LG} = $self->{CRPOS} unless ($lg);
    return $lg;
}

sub READLINE {
    my ($self) = @_;
    return $self->_readline_helper() unless wantarray;
    my @arr;
    while(defined(my $line = $self->_readline_helper())) {
	    push(@arr, $line);
    }
    return @arr;
}

sub _readline_helper {
    my ($self) = @_;
    return undef if ($self->{CRPOS} >= $self->{LG});

    # Handle slurp mode (CPAN ticket #72710)
    if (! defined($/)) {
	    my $text;
	    $self->READ($text, $self->{LG} - $self->{CRPOS});
	    return $text;
    }

    ### Save and seek...
    my $old_pos = $self->{FH}->tell;
    $self->{FH}->seek($self->{CRPOS}+$self->{START}, 0);

    ### ...read...
    my $text = $self->{FH}->getline;

    ### ...and restore:
    $self->{FH}->seek($old_pos, 0);

    #### If we detected a new EOF ...
    unless (defined $text) {
       $self->{LG} = $self->{CRPOS};
       return undef;
    }

    my $lg=length($text);

    $lg = $self->{LG} - $self->{CRPOS} if ($self->{CRPOS} + $lg > $self->{LG});
    $self->{CRPOS} += $lg;

    return substr($text, 0,$lg);
}

sub CLOSE { %{$_[0]}=(); }



1;
__END__

__END__


=head1 NAME

IO::InnerFile - define a file inside another file

=head1 SYNOPSIS

    use strict;
    use warnings;
    use IO::InnerFile;

    # Read a subset of a file:
    my $fh = _some_file_handle;
    my $start = 10;
    my $length = 50;
    my $inner = IO::InnerFile->new($fh, $start, $length);
    while (my $line = <$inner>) {
        # ...
    }


=head1 DESCRIPTION

If you have a file handle that can C<seek> and C<tell>, then you
can open an L<IO::InnerFile> on a range of the underlying file.

=head1 CONSTRUCTORS

L<IO::InnerFile> implements the following constructors.

=head2 new

    my $inner = IO::InnerFile->new($fh);
    $inner = IO::InnerFile->new($fh, 10);
    $inner = IO::InnerFile->new($fh, 10, 50);

Create a new L<IO::InnerFile> opened on the given file handle.
The file handle supplied B<MUST> be able to both C<seek> and C<tell>.

The second and third parameters are start and length. Both are defaulted
to zero (C<0>). Negative values are silently coerced to zero.

=head1 METHODS

L<IO::InnerFile> implements the following methods.

=head2 add_length

    $inner->add_length(30);

Add to the virtual length of the inner file by the number given in bytes.

=head2 add_start

    $inner->add_start(30);

Add to the virtual position of the inner file by the number given in bytes.

=head2 binmode

    $inner->binmode();

This is a NOOP method just to satisfy the normal L<IO::File> interface.

=head2 close

=head2 fileno

    $inner->fileno();

This is a NOOP method just to satisfy the normal L<IO::File> interface.

=head2 flush

    $inner->flush();

This is a NOOP method just to satisfy the normal L<IO::File> interface.

=head2 get_end

    my $num_bytes = $inner->get_end();

Get the virtual end position of the inner file in bytes.

=head2 get_length

    my $num_bytes = $inner->get_length();

Get the virtual length of the inner file in bytes.

=head2 get_start

    my $num_bytes = $inner->get_start();

Get the virtual position of the inner file in bytes.

=head2 getc

=head2 getline

=head2 print LIST

=head2 printf

=head2 read

=head2 readline

=head2 seek

=head2 set_end

    $inner->set_end(30);

Set the virtual end of the inner file in bytes (this basically just alters the length).

=head2 set_length

    $inner->set_length(30);

Set the virtual length of the inner file in bytes.

=head2 set_start

    $inner->set_start(30);

Set the virtual start position of the inner file in bytes.

=head2 tell

=head2 write

=head1 AUTHOR

Eryq (F<eryq@zeegee.com>).
President, ZeeGee Software Inc (F<http://www.zeegee.com>).

=head1 CONTRIBUTORS

Dianne Skoll (F<dfs@roaringpenguin.com>).

=head1 COPYRIGHT & LICENSE

Copyright (c) 1997 Erik (Eryq) Dorfman, ZeeGee Software, Inc. All rights reserved.

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

=cut
PK9N%[��[|9|9perl5/IO/WrapTie.pmnu��6�$package IO::WrapTie;

use strict;
use Exporter;

# Inheritance, exporting, and package version:
our @ISA     = qw(Exporter);
our @EXPORT  = qw(wraptie);
our $VERSION = '2.113';

# Function, exported.
sub wraptie {
    IO::WrapTie::Master->new(@_);
}

# Class method; BACKWARDS-COMPATIBILITY ONLY!
sub new {
    shift;
    IO::WrapTie::Master->new(@_);
}



#------------------------------------------------------------
package # hide from pause
    IO::WrapTie::Master;
#------------------------------------------------------------

use strict;
use vars qw($AUTOLOAD);
use IO::Handle;

# We inherit from IO::Handle to get methods which invoke i/o operators,
# like print(), on our tied handle:
our @ISA = qw(IO::Handle);

#------------------------------
# new SLAVE, TIEARGS...
#------------------------------
# Create a new subclass of IO::Handle which...
#
#   (1) Handles i/o OPERATORS because it is tied to an instance of
#       an i/o-like class, like IO::Scalar.
#
#   (2) Handles i/o METHODS by delegating them to that same tied object!.
#
# Arguments are the slave class (e.g., IO::Scalar), followed by all
# the arguments normally sent into that class's C<TIEHANDLE> method.
# In other words, much like the arguments to tie().  :-)
#
# NOTE:
# The thing $x we return must be a BLESSED REF, for ($x->print()).
# The underlying symbol must be a FILEHANDLE, for (print $x "foo").
# It has to have a way of getting to the "real" back-end object...
#
sub new {
    my $master = shift;
    my $io = IO::Handle->new;   ### create a new handle
    my $slave = shift;
    tie *$io, $slave, @_;       ### tie: will invoke slave's TIEHANDLE
    bless $io, $master;         ### return a master
}

#------------------------------
# AUTOLOAD
#------------------------------
# Delegate method invocations on the master to the underlying slave.
#
sub AUTOLOAD {
    my $method = $AUTOLOAD;
    $method =~ s/.*:://;
    my $self = shift; tied(*$self)->$method(\@_);
}

#------------------------------
# PRELOAD
#------------------------------
# Utility.
#
# Most methods like print(), getline(), etc. which work on the tied object
# via Perl's i/o operators (like 'print') are inherited from IO::Handle.
#
# Other methods, like seek() and sref(), we must delegate ourselves.
# AUTOLOAD takes care of these.
#
# However, it may be necessary to preload delegators into your
# own class.  PRELOAD will do this.
#
sub PRELOAD {
    my $class = shift;
    foreach (@_) {
	eval "sub ${class}::$_ { my \$s = shift; tied(*\$s)->$_(\@_) }";
    }
}

# Preload delegators for some standard methods which we can't simply
# inherit from IO::Handle... for example, some IO::Handle methods
# assume that there is an underlying file descriptor.
#
PRELOAD IO::WrapTie::Master
    qw(open opened close read clearerr eof seek tell setpos getpos);



#------------------------------------------------------------
package # hide from pause
    IO::WrapTie::Slave;
#------------------------------------------------------------
# Teeny private class providing a new_tie constructor...
#
# HOW IT ALL WORKS:
#
# Slaves inherit from this class.
#
# When you send a new_tie() message to a tie-slave class (like IO::Scalar),
# it first determines what class should provide its master, via TIE_MASTER.
# In this case, IO::Scalar->TIE_MASTER would return IO::Scalar::Master.
# Then, we create a new master (an IO::Scalar::Master) with the same args
# sent to new_tie.
#
# In general, the new() method of the master is inherited directly
# from IO::WrapTie::Master.
#
sub new_tie {
    my $self = shift;
    $self->TIE_MASTER->new($self,@_);     ### e.g., IO::Scalar::Master->new(@_)
}

# Default class method for new_tie().
# All your tie-slave class (like IO::Scalar) has to do is override this
# method with a method that returns the name of an appropriate "master"
# class for tying that slave.
#
sub TIE_MASTER { 'IO::WrapTie::Master' }

#------------------------------
1;
__END__


package IO::WrapTie;      ### for doc generator


=head1 NAME

IO::WrapTie - wrap tieable objects in IO::Handle interface

I<This is currently Alpha code, released for comments.
  Please give me your feedback!>


=head1 SYNOPSIS

First of all, you'll need tie(), so:

   require 5.004;

I<Function interface (experimental).>
Use this with any existing class...

   use IO::WrapTie;
   use FooHandle;                  ### implements TIEHANDLE interface

   ### Suppose we want a "FooHandle->new(&FOO_RDWR, 2)".
   ### We can instead say...

   $FH = wraptie('FooHandle', &FOO_RDWR, 2);

   ### Now we can use...
   print $FH "Hello, ";            ### traditional operator syntax...
   $FH->print("world!\n");         ### ...and OO syntax as well!

I<OO interface (preferred).>
You can inherit from the L<IO::WrapTie/"Slave"> mixin to get a
nifty C<new_tie()> constructor...

   #------------------------------
   package FooHandle;                        ### a class which can TIEHANDLE

   use IO::WrapTie;
   @ISA = qw(IO::WrapTie::Slave);            ### inherit new_tie()
   ...


   #------------------------------
   package main;

   $FH = FooHandle->new_tie(&FOO_RDWR, 2);   ### $FH is an IO::WrapTie::Master
   print $FH "Hello, ";                      ### traditional operator syntax
   $FH->print("world!\n");                   ### OO syntax

See IO::Scalar as an example.  It also shows you how to create classes
which work both with and without 5.004.


=head1 DESCRIPTION

Suppose you have a class C<FooHandle>, where...

=over 4

=item *

C<FooHandle> does not inherit from L<IO::Handle>. That is, it performs
file handle-like I/O, but to something other than an underlying
file descriptor. Good examples are L<IO::Scalar> (for printing to a
string) and L<IO::Lines> (for printing to an array of lines).

=item *

C<FooHandle> implements the C<TIEHANDLE> interface (see L<perltie>).
That is, it provides methods C<TIEHANDLE>, C<GETC>, C<PRINT>, C<PRINTF>,
C<READ>, and C<READLINE>.

=item *

C<FooHandle> implements the traditional OO interface of
L<FileHandle> and L<IO::Handle>. i.e., it contains methods like C<getline>,
C<read>, C<print>, C<seek>, C<tell>, C<eof>, etc.

=back


Normally, users of your class would have two options:


=over 4

=item *

B<Use only OO syntax,> and forsake named I/O operators like C<print>.

=item *

B<Use with tie,> and forsake treating it as a first-class object
(i.e., class-specific methods can only be invoked through the underlying
object via C<tied>... giving the object a "split personality").

=back


But now with L<IO::WrapTie>, you can say:

    $WT = wraptie('FooHandle', &FOO_RDWR, 2);
    $WT->print("Hello, world\n");   ### OO syntax
    print $WT "Yes!\n";             ### Named operator syntax too!
    $WT->weird_stuff;               ### Other methods!

And if you're authoring a class like C<FooHandle>, just have it inherit
from C<IO::WrapTie::Slave> and that first line becomes even prettier:

    $WT = FooHandle->new_tie(&FOO_RDWR, 2);

B<The bottom line:> now, almost any class can look and work exactly like
an L<IO::Handle> and be used both with OO and non-OO file handle syntax.


=head1 HOW IT ALL WORKS


=head2 The data structures

Consider this example code, using classes in this distribution:

    use IO::Scalar;
    use IO::WrapTie;

    $WT = wraptie('IO::Scalar',\$s);
    print $WT "Hello, ";
    $WT->print("world!\n");

In it, the C<wraptie> function creates a data structure as follows:

                          * $WT is a blessed reference to a tied filehandle
              $WT           glob; that glob is tied to the "Slave" object.
               |          * You would do all your i/o with $WT directly.
               |
               |
               |     ,---isa--> IO::WrapTie::Master >--isa--> IO::Handle
               V    /
        .-------------.
        |             |
        |             |   * Perl i/o operators work on the tied object,
        |  "Master"   |     invoking the C<TIEHANDLE> methods.
        |             |   * Method invocations are delegated to the tied
        |             |     slave.
        `-------------'
               |
    tied(*$WT) |     .---isa--> IO::WrapTie::Slave
               V    /
        .-------------.
        |             |
        |   "Slave"   |   * Instance of FileHandle-like class which doesn't
        |             |     actually use file descriptors, like IO::Scalar.
        |  IO::Scalar |   * The slave can be any kind of object.
        |             |   * Must implement the C<TIEHANDLE> interface.
        `-------------'


I<NOTE:> just as an L<IO::Handle> is really just a blessed reference to a
I<traditional> file handle glob. So also, an C<IO::WrapTie::Master>
is really just a blessed reference to a file handle
glob I<which has been tied to some "slave" class.>


=head2 How C<wraptie> works

=over 4

=item 1.

The call to function C<wraptie(SLAVECLASS, TIEARGS...)> is
passed onto C<IO::WrapTie::Master::new()>.
Note that class C<IO::WrapTie::Master> is a subclass of L<IO::Handle>.

=item 2.

The C<< IO::WrapTie::Master->new >> method creates a new L<IO::Handle> object,
re-blessed into class C<IO::WrapTie::Master>. This object is the I<master>,
which will be returned from the constructor. At the same time...

=item 3.

The C<new> method also creates the I<slave>: this is an instance
of C<SLAVECLASS> which is created by tying the master's L<IO::Handle>
to C<SLAVECLASS> via C<tie>.
This call to C<tie> creates the slave in the following manner:

=item 4.

Class C<SLAVECLASS> is sent the message C<TIEHANDLE>; it
will usually delegate this to C<< SLAVECLASS->new(TIEARGS) >>, resulting
in a new instance of C<SLAVECLASS> being created and returned.

=item 5.

Once both master and slave have been created, the master is returned
to the caller.

=back


=head2 How I/O operators work (on the master)

Consider using an i/o operator on the master:

    print $WT "Hello, world!\n";

Since the master C<$WT> is really a C<blessed> reference to a glob,
the normal Perl I/O operators like C<print> may be used on it.
They will just operate on the symbol part of the glob.

Since the glob is tied to the slave, the slave's C<PRINT> method
(part of the C<TIEHANDLE> interface) will be automatically invoked.

If the slave is an L<IO::Scalar>, that means L<IO::Scalar/"PRINT"> will be
invoked, and that method happens to delegate to the C<print> method
of the same class.  So the I<real> work is ultimately done by
L<IO::Scalar/"print">.


=head2 How methods work (on the master)

Consider using a method on the master:

    $WT->print("Hello, world!\n");

Since the master C<$WT> is blessed into the class C<IO::WrapTie::Master>,
Perl first attempts to find a C<print> method there.  Failing that,
Perl next attempts to find a C<print> method in the super class,
L<IO::Handle>.  It just so happens that there I<is> such a method;
that method merely invokes the C<print> I/O operator on the self object...
and for that, see above!

But let's suppose we're dealing with a method which I<isn't> part
of L<IO::Handle>... for example:

    my $sref = $WT->sref;

In this case, the intuitive behavior is to have the master delegate the
method invocation to the slave (now do you see where the designations
come from?).  This is indeed what happens: C<IO::WrapTie::Master> contains
an C<AUTOLOAD> method which performs the delegation.

So: when C<sref> can't be found in L<IO::Handle>, the C<AUTOLOAD> method
of C<IO::WrapTie::Master> is invoked, and the standard behavior of
delegating the method to the underlying slave (here, an L<IO::Scalar>)
is done.

Sometimes, to get this to work properly, you may need to create
a subclass of C<IO::WrapTie::Master> which is an effective master for
I<your> class, and do the delegation there.

=head1 NOTES

B<Why not simply use the object's OO interface?>

Because that means forsaking the use of named operators
like C<print>, and you may need to pass the object to a subroutine
which will attempt to use those operators:

    $O = FooHandle->new(&FOO_RDWR, 2);
    $O->print("Hello, world\n");  ### OO syntax is okay, BUT....

    sub nope { print $_[0] "Nope!\n" }
 X  nope($O);                     ### ERROR!!! (not a glob ref)


B<Why not simply use tie()?>
    Because (1) you have to use C<tied> to invoke methods in the
object's public interface (yuck), and (2) you may need to pass
the tied symbol to another subroutine which will attempt to treat
it in an OO-way... and that will break it:

    tie *T, 'FooHandle', &FOO_RDWR, 2;
    print T "Hello, world\n";   ### Operator is okay, BUT...

    tied(*T)->other_stuff;      ### yuck! AND...

    sub nope { shift->print("Nope!\n") }
 X  nope(\*T);                  ### ERROR!!! (method "print" on unblessed ref)


B<Why a master and slave?>

    Why not simply write C<FooHandle> to inherit from L<IO::Handle?>
I tried this, with an implementation similar to that of L<IO::Socket>.
The problem is that I<the whole point is to use this with objects
that don't have an underlying file/socket descriptor.>.
Subclassing L<IO::Handle> will work fine for the OO stuff, and fine with
named operators I<if> you C<tie>... but if you just attempt to say:

    $IO = FooHandle->new(&FOO_RDWR, 2);
    print $IO "Hello!\n";

you get a warning from Perl like:

    Filehandle GEN001 never opened

because it's trying to do system-level I/O on an (unopened) file
descriptor.  To avoid this, you apparently have to C<tie> the handle...
which brings us right back to where we started!  At least the
L<IO::WrapTie> mixin lets us say:

    $IO = FooHandle->new_tie(&FOO_RDWR, 2);
    print $IO "Hello!\n";

and so is not I<too> bad.  C<:-)>


=head1 WARNINGS

Remember: this stuff is for doing L<FileHandle>-like I/O on things
I<without underlying file descriptors>.  If you have an underlying
file descriptor, you're better off just inheriting from L<IO::Handle>.

B<Be aware that new_tie() always returns an instance of a
kind of IO::WrapTie::Master...> it does B<not> return an instance
of the I/O class you're tying to!

Invoking some methods on the master object causes C<AUTOLOAD> to delegate
them to the slave object... so it I<looks> like you're manipulating a
C<FooHandle> object directly, but you're not.

I have not explored all the ramifications of this use of C<tie>.
I<Here there be dragons>.

=head1 AUTHOR

Eryq (F<eryq@zeegee.com>).
President, ZeeGee Software Inc (F<http://www.zeegee.com>).

=head1 CONTRIBUTORS

Dianne Skoll (F<dfs@roaringpenguin.com>).

=head1 COPYRIGHT & LICENSE

Copyright (c) 1997 Erik (Eryq) Dorfman, ZeeGee Software, Inc. All rights reserved.

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

=cut
PK9N%[�����L�Lperl5/IO/HTML.pmnu��6�$#---------------------------------------------------------------------
package IO::HTML;
#
# Copyright 2020 Christopher J. Madsen
#
# Author: Christopher J. Madsen <perl@cjmweb.net>
# Created: 14 Jan 2012
#
# This program is free software; you can redistribute it and/or modify
# it under the same terms as Perl itself.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See either the
# GNU General Public License or the Artistic License for more details.
#
# ABSTRACT: Open an HTML file with automatic charset detection
#---------------------------------------------------------------------

use 5.008;
use strict;
use warnings;

use Carp 'croak';
use Encode 2.10 qw(decode find_encoding); # need utf-8-strict encoding
use Exporter 5.57 'import';

our $VERSION = '1.004';
# This file is part of IO-HTML 1.004 (September 26, 2020)


our $bytes_to_check   ||= 1024;
our $default_encoding ||= 'cp1252';

our @EXPORT    = qw(html_file);
our @EXPORT_OK = qw(find_charset_in html_file_and_encoding html_outfile
                    sniff_encoding);

our %EXPORT_TAGS = (
  rw  => [qw( html_file html_file_and_encoding html_outfile )],
  all => [ @EXPORT, @EXPORT_OK ],
);

#=====================================================================


sub html_file
{
  (&html_file_and_encoding)[0]; # return just the filehandle
} # end html_file


# Note: I made html_file and html_file_and_encoding separate functions
# (instead of making html_file context-sensitive) because I wanted to
# use html_file in function calls (i.e. list context) without having
# to write "scalar html_file" all the time.

sub html_file_and_encoding
{
  my ($filename, $options) = @_;

  $options ||= {};

  open(my $in, '<:raw', $filename) or croak "Failed to open $filename: $!";


  my ($encoding, $bom) = sniff_encoding($in, $filename, $options);

  if (not defined $encoding) {
    croak "No default encoding specified"
        unless defined($encoding = $default_encoding);
    $encoding = find_encoding($encoding) if $options->{encoding};
  } # end if we didn't find an encoding

  binmode $in, sprintf(":encoding(%s):crlf",
                       $options->{encoding} ? $encoding->name : $encoding);

  return ($in, $encoding, $bom);
} # end html_file_and_encoding
#---------------------------------------------------------------------


sub html_outfile
{
  my ($filename, $encoding, $bom) = @_;

  if (not defined $encoding) {
    croak "No default encoding specified"
        unless defined($encoding = $default_encoding);
  } # end if we didn't find an encoding
  elsif (ref $encoding) {
    $encoding = $encoding->name;
  }

  open(my $out, ">:encoding($encoding)", $filename)
      or croak "Failed to open $filename: $!";

  print $out "\x{FeFF}" if $bom;

  return $out;
} # end html_outfile
#---------------------------------------------------------------------


sub sniff_encoding
{
  my ($in, $filename, $options) = @_;

  $filename = 'file' unless defined $filename;
  $options ||= {};

  my $pos = tell $in;
  croak "Could not seek $filename: $!" if $pos < 0;

  croak "Could not read $filename: $!"
      unless defined read $in, my($buf), $bytes_to_check;

  seek $in, $pos, 0 or croak "Could not seek $filename: $!";


  # Check for BOM:
  my $bom;
  my $encoding = do {
    if ($buf =~ /^\xFe\xFF/) {
      $bom = 2;
      'UTF-16BE';
    } elsif ($buf =~ /^\xFF\xFe/) {
      $bom = 2;
      'UTF-16LE';
    } elsif ($buf =~ /^\xEF\xBB\xBF/) {
      $bom = 3;
      'utf-8-strict';
    } else {
      find_charset_in($buf, $options); # check for <meta charset>
    }
  }; # end $encoding

  if ($bom) {
    seek $in, $bom, 1 or croak "Could not seek $filename: $!";
    $bom = 1;
  }
  elsif (not defined $encoding) { # try decoding as UTF-8
    my $test = decode('utf-8-strict', $buf, Encode::FB_QUIET);
    if ($buf =~ /^(?:                   # nothing left over
         | [\xC2-\xDF]                  # incomplete 2-byte char
         | [\xE0-\xEF] [\x80-\xBF]?     # incomplete 3-byte char
         | [\xF0-\xF4] [\x80-\xBF]{0,2} # incomplete 4-byte char
        )\z/x and $test =~ /[^\x00-\x7F]/) {
      $encoding = 'utf-8-strict';
    } # end if valid UTF-8 with at least one multi-byte character:
  } # end if testing for UTF-8

  if (defined $encoding and $options->{encoding} and not ref $encoding) {
    $encoding = find_encoding($encoding);
  } # end if $encoding is a string and we want an object

  return wantarray ? ($encoding, $bom) : $encoding;
} # end sniff_encoding

#=====================================================================
# Based on HTML5 8.2.2.2 Determining the character encoding:

# Get attribute from current position of $_
sub _get_attribute
{
  m!\G[\x09\x0A\x0C\x0D /]+!gc; # skip whitespace or /

  return if /\G>/gc or not /\G(=?[^\x09\x0A\x0C\x0D =]*)/gc;

  my ($name, $value) = (lc $1, '');

  if (/\G[\x09\x0A\x0C\x0D ]*=[\x09\x0A\x0C\x0D ]*/gc) {
    if (/\G"/gc) {
      # Double-quoted attribute value
      /\G([^"]*)("?)/gc;
      return unless $2; # Incomplete attribute (missing closing quote)
      $value = lc $1;
    } elsif (/\G'/gc) {
      # Single-quoted attribute value
      /\G([^']*)('?)/gc;
      return unless $2; # Incomplete attribute (missing closing quote)
      $value = lc $1;
    } else {
      # Unquoted attribute value
      /\G([^\x09\x0A\x0C\x0D >]*)/gc;
      $value = lc $1;
    }
  } # end if attribute has value

  return wantarray ? ($name, $value) : 1;
} # end _get_attribute

# Examine a meta value for a charset:
sub _get_charset_from_meta
{
  for (shift) {
    while (/charset[\x09\x0A\x0C\x0D ]*=[\x09\x0A\x0C\x0D ]*/ig) {
      return $1 if (/\G"([^"]*)"/gc or
                    /\G'([^']*)'/gc or
                    /\G(?!['"])([^\x09\x0A\x0C\x0D ;]+)/gc);
    }
  } # end for value

  return undef;
} # end _get_charset_from_meta
#---------------------------------------------------------------------


sub find_charset_in
{
  for (shift) {
    my $options = shift || {};
    # search only the first $bytes_to_check bytes (default 1024)
    my $stop = length > $bytes_to_check ? $bytes_to_check : length;

    my $expect_pragma = (defined $options->{need_pragma}
                         ? $options->{need_pragma} : 1);

    pos() = 0;
    while (pos() < $stop) {
      if (/\G<!--.*?(?<=--)>/sgc) {
      } # Skip comment
      elsif (m!\G<meta(?=[\x09\x0A\x0C\x0D /])!gic) {
        my ($got_pragma, $need_pragma, $charset);

        while (my ($name, $value) = &_get_attribute) {
          if ($name eq 'http-equiv' and $value eq 'content-type') {
            $got_pragma = 1;
          } elsif ($name eq 'content' and not defined $charset) {
            $need_pragma = $expect_pragma
                if defined($charset = _get_charset_from_meta($value));
          } elsif ($name eq 'charset') {
            $charset = $value;
            $need_pragma = 0;
          }
        } # end while more attributes in this <meta> tag

        if (defined $need_pragma and (not $need_pragma or $got_pragma)) {
          $charset = 'UTF-8'  if $charset =~ /^utf-?16/;
          $charset = 'cp1252' if $charset eq 'iso-8859-1'; # people lie
          if (my $encoding = find_encoding($charset)) {
            return $options->{encoding} ? $encoding : $encoding->name;
          } # end if charset is a recognized encoding
        } # end if found charset
      } # end elsif <meta
      elsif (m!\G</?[a-zA-Z][^\x09\x0A\x0C\x0D >]*!gc) {
        1 while &_get_attribute;
      } # end elsif some other tag
      elsif (m{\G<[!/?][^>]*}gc) {
      } # skip unwanted things
      elsif (m/\G</gc) {
      } # skip < that doesn't open anything we recognize

      # Advance to the next <:
      m/\G[^<]+/gc;
    } # end while not at search boundary
  } # end for string

  return undef;                 # Couldn't find a charset
} # end find_charset_in
#---------------------------------------------------------------------


# Shortcuts for people who don't like exported functions:
*file               = \&html_file;
*file_and_encoding  = \&html_file_and_encoding;
*outfile            = \&html_outfile;

#=====================================================================
# Package Return Value:

1;

__END__

=head1 NAME

IO::HTML - Open an HTML file with automatic charset detection

=head1 VERSION

This document describes version 1.004 of
IO::HTML, released September 26, 2020.

=head1 SYNOPSIS

  use IO::HTML;                 # exports html_file by default
  use HTML::TreeBuilder;

  my $tree = HTML::TreeBuilder->new_from_file(
               html_file('foo.html')
             );

  # Alternative interface:
  open(my $in, '<:raw', 'bar.html');
  my $encoding = IO::HTML::sniff_encoding($in, 'bar.html');

=head1 DESCRIPTION

IO::HTML provides an easy way to open a file containing HTML while
automatically determining its encoding.  It uses the HTML5 encoding
sniffing algorithm specified in section 8.2.2.2 of the draft standard.

The algorithm as implemented here is:

=over

=item 1.

If the file begins with a byte order mark indicating UTF-16LE,
UTF-16BE, or UTF-8, then that is the encoding.

=item 2.

If the first C<$bytes_to_check> bytes of the file contain a C<< <meta> >> tag that
indicates the charset, and Encode recognizes the specified charset
name, then that is the encoding.  (This portion of the algorithm is
implemented by C<find_charset_in>.)

The C<< <meta> >> tag can be in one of two formats:

  <meta charset="...">
  <meta http-equiv="Content-Type" content="...charset=...">

The search is case-insensitive, and the order of attributes within the
tag is irrelevant.  Any additional attributes of the tag are ignored.
The first matching tag with a recognized encoding ends the search.

=item 3.

If the first C<$bytes_to_check> bytes of the file are valid UTF-8 (with at least 1
non-ASCII character), then the encoding is UTF-8.

=item 4.

If all else fails, use the default character encoding.  The HTML5
standard suggests the default encoding should be locale dependent, but
currently it is always C<cp1252> unless you set
C<$IO::HTML::default_encoding> to a different value.  Note:
C<sniff_encoding> does not apply this step; only C<html_file> does
that.

=back

=head1 SUBROUTINES

=head2 html_file

  $filehandle = html_file($filename, \%options);

This function (exported by default) is the primary entry point.  It
opens the file specified by C<$filename> for reading, uses
C<sniff_encoding> to find a suitable encoding layer, and applies it.
It also applies the C<:crlf> layer.  If the file begins with a BOM,
the filehandle is positioned just after the BOM.

The optional second argument is a hashref containing options.  The
possible keys are described under C<find_charset_in>.

If C<sniff_encoding> is unable to determine the encoding, it defaults
to C<$IO::HTML::default_encoding>, which is set to C<cp1252>
(a.k.a. Windows-1252) by default.  According to the standard, the
default should be locale dependent, but that is not currently
implemented.

It dies if the file cannot be opened, or if C<sniff_encoding> cannot
determine the encoding and C<$IO::HTML::default_encoding> has been set
to C<undef>.


=head2 html_file_and_encoding

  ($filehandle, $encoding, $bom)
    = html_file_and_encoding($filename, \%options);

This function (exported only by request) is just like C<html_file>,
but returns more information.  In addition to the filehandle, it
returns the name of the encoding used, and a flag indicating whether a
byte order mark was found (if C<$bom> is true, the file began with a
BOM).  This may be useful if you want to write the file out again
(especially in conjunction with the C<html_outfile> function).

The optional second argument is a hashref containing options.  The
possible keys are described under C<find_charset_in>.

It dies if the file cannot be opened, or if C<sniff_encoding> cannot
determine the encoding and C<$IO::HTML::default_encoding> has been set
to C<undef>.

The result of calling C<html_file_and_encoding> in scalar context is undefined
(in the C sense of there is no guarantee what you'll get).


=head2 html_outfile

  $filehandle = html_outfile($filename, $encoding, $bom);

This function (exported only by request) opens C<$filename> for output
using C<$encoding>, and writes a BOM to it if C<$bom> is true.
If C<$encoding> is C<undef>, it defaults to C<$IO::HTML::default_encoding>.
C<$encoding> may be either an encoding name or an Encode::Encoding object.

It dies if the file cannot be opened, or if both C<$encoding> and
C<$IO::HTML::default_encoding> are C<undef>.


=head2 sniff_encoding

  ($encoding, $bom) = sniff_encoding($filehandle, $filename, \%options);

This function (exported only by request) runs the HTML5 encoding
sniffing algorithm on C<$filehandle> (which must be seekable, and
should have been opened in C<:raw> mode).  C<$filename> is used only
for error messages (if there's a problem using the filehandle), and
defaults to "file" if omitted.  The optional third argument is a
hashref containing options.  The possible keys are described under
C<find_charset_in>.

It returns Perl's canonical name for the encoding, which is not
necessarily the same as the MIME or IANA charset name.  It returns
C<undef> if the encoding cannot be determined.  C<$bom> is true if the
file began with a byte order mark.  In scalar context, it returns only
C<$encoding>.

The filehandle's position is restored to its original position
(normally the beginning of the file) unless C<$bom> is true.  In that
case, the position is immediately after the BOM.

Tip: If you want to run C<sniff_encoding> on a file you've already
loaded into a string, open an in-memory file on the string, and pass
that handle:

  ($encoding, $bom) = do {
    open(my $fh, '<', \$string);  sniff_encoding($fh)
  };

(This only makes sense if C<$string> contains bytes, not characters.)


=head2 find_charset_in

  $encoding = find_charset_in($string_containing_HTML, \%options);

This function (exported only by request) looks for charset information
in a C<< <meta> >> tag in a possibly-incomplete HTML document using
the "two step" algorithm specified by HTML5.  It does not look for a BOM.
The C<< <meta> >> tag must begin within the first C<$IO::HTML::bytes_to_check>
bytes of the string.

It returns Perl's canonical name for the encoding, which is not
necessarily the same as the MIME or IANA charset name.  It returns
C<undef> if no charset is specified or if the specified charset is not
recognized by the Encode module.

The optional second argument is a hashref containing options.  The
following keys are recognized:

=over

=item C<encoding>

If true, return the L<Encode::Encoding> object instead of its name.
Defaults to false.

=item C<need_pragma>

If true (the default), follow the HTML5 spec and examine the
C<content> attribute only of C<< <meta http-equiv="Content-Type" >>.
If set to 0, relax the HTML5 spec, and look for "charset=" in the
C<content> attribute of I<every> meta tag.

=back

=head1 EXPORTS

By default, only C<html_file> is exported.  Other functions may be
exported on request.

For people who prefer not to export functions, all functions beginning
with C<html_> have an alias without that prefix (e.g. you can call
C<IO::HTML::file(...)> instead of C<IO::HTML::html_file(...)>.  These
aliases are not exportable.

=for Pod::Coverage
file
file_and_encoding
outfile

The following export tags are available:

=over

=item C<:all>

All exportable functions.

=item C<:rw>

C<html_file>, C<html_file_and_encoding>, C<html_outfile>.

=back

=head1 SEE ALSO

The HTML5 specification, section 8.2.2.2 Determining the character encoding:
L<http://www.w3.org/TR/html5/syntax.html#determining-the-character-encoding>

=head1 DIAGNOSTICS

=over

=item C<< Could not read %s: %s >>

The specified file could not be read from for the reason specified by C<$!>.


=item C<< Could not seek %s: %s >>

The specified file could not be rewound for the reason specified by C<$!>.


=item C<< Failed to open %s: %s >>

The specified file could not be opened for reading for the reason
specified by C<$!>.


=item C<< No default encoding specified >>

The C<sniff_encoding> algorithm didn't find an encoding to use, and
you set C<$IO::HTML::default_encoding> to C<undef>.


=back

=head1 CONFIGURATION AND ENVIRONMENT

There are two global variables that affect IO::HTML.  If you need to
change them, you should do so using C<local> if possible:

  my $file = do {
    # This file may define the charset later in the header
    local $IO::HTML::bytes_to_check = 4096;
    html_file(...);
  };

=over

=item C<$bytes_to_check>

This is the number of bytes that C<sniff_encoding> will read from the
stream.  It is also the number of bytes that C<find_charset_in> will
search for a C<< <meta> >> tag containing charset information.
It must be a positive integer.

The HTML 5 specification recommends using the default value of 1024,
but some pages do not follow the specification.

=item C<$default_encoding>

This is the encoding that C<html_file> and C<html_file_and_encoding>
will use if no encoding can be detected by C<sniff_encoding>.
The default value is C<cp1252> (a.k.a. Windows-1252).

Setting it to C<undef> will cause the file subroutines to croak if
C<sniff_encoding> fails to determine the encoding.  (C<sniff_encoding>
itself does not use C<$default_encoding>).

=back

=head1 DEPENDENCIES

IO::HTML has no non-core dependencies for Perl 5.8.7+.  With earlier
versions of Perl 5.8, you need to upgrade L<Encode> to at least
version 2.10, and
you may need to upgrade L<Exporter> to at least version
5.57.

=head1 INCOMPATIBILITIES

None reported.

=head1 BUGS AND LIMITATIONS

No bugs have been reported.

=head1 AUTHOR

Christopher J. Madsen  S<C<< <perl AT cjmweb.net> >>>

Please report any bugs or feature requests
to S<C<< <bug-IO-HTML AT rt.cpan.org> >>>
or through the web interface at
L<< http://rt.cpan.org/Public/Bug/Report.html?Queue=IO-HTML >>.

You can follow or contribute to IO-HTML's development at
L<< https://github.com/madsen/io-html >>.

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2020 by Christopher J. Madsen.

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

=head1 DISCLAIMER OF WARRANTY

BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH
YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
NECESSARY SERVICING, REPAIR, OR CORRECTION.

IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENSE, BE
LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL,
OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.

=cut
PK9N%[��G�JJperl5/IO/Lines.pmnu��6�$package IO::Lines;

use strict;
use Carp;
use IO::ScalarArray;

# The package version, both in 1.23 style *and* usable by MakeMaker:
our $VERSION = '2.113';

# Inheritance:
our @ISA = qw(IO::ScalarArray);     ### also gets us new_tie  :-)


=head1 NAME

IO::Lines - IO:: interface for reading/writing an array of lines


=head1 SYNOPSIS

    use IO::Lines;

    ### See IO::ScalarArray for details


=head1 DESCRIPTION

This class implements objects which behave just like FileHandle
(or IO::Handle) objects, except that you may use them to write to
(or read from) an array of lines.  C<tiehandle> capable as well.

This is a subclass of L<IO::ScalarArray|IO::ScalarArray>
in which the underlying
array has its data stored in a line-oriented-format: that is,
every element ends in a C<"\n">, with the possible exception of the
final element.  This makes C<getline()> I<much> more efficient;
if you plan to do line-oriented reading/printing, you want this class.

The C<print()> method will enforce this rule, so you can print
arbitrary data to the line-array: it will break the data at
newlines appropriately.

See L<IO::ScalarArray> for full usage and warnings.

=cut


#------------------------------
#
# getline
#
# Instance method, override.
# Return the next line, or undef on end of data.
# Can safely be called in an array context.
# Currently, lines are delimited by "\n".
#
sub getline {
    my $self = shift;

    if (!defined $/) {
	return join( '', $self->_getlines_for_newlines );
    }
    elsif ($/ eq "\n") {
	if (!*$self->{Pos}) {      ### full line...
	    return *$self->{AR}[*$self->{Str}++];
	}
	else {                     ### partial line...
	    my $partial = substr(*$self->{AR}[*$self->{Str}++], *$self->{Pos});
	    *$self->{Pos} = 0;
	    return $partial;
	}
    }
    else {
	croak 'unsupported $/: must be "\n" or undef';
    }
}

#------------------------------
#
# getlines
#
# Instance method, override.
# Return an array comprised of the remaining lines, or () on end of data.
# Must be called in an array context.
# Currently, lines are delimited by "\n".
#
sub getlines {
    my $self = shift;
    wantarray or croak("can't call getlines in scalar context!");

    if ((defined $/) and ($/ eq "\n")) {
	return $self->_getlines_for_newlines(@_);
    }
    else {         ### slow but steady
	return $self->SUPER::getlines(@_);
    }
}

#------------------------------
#
# _getlines_for_newlines
#
# Instance method, private.
# If $/ is newline, do fast getlines.
# This CAN NOT invoke getline!
#
sub _getlines_for_newlines {
    my $self = shift;
    my ($rArray, $Str, $Pos) = @{*$self}{ qw( AR Str Pos ) };
    my @partial = ();

    if ($Pos) {				### partial line...
	@partial = (substr( $rArray->[ $Str++ ], $Pos ));
	*$self->{Pos} = 0;
    }
    *$self->{Str} = scalar @$rArray;	### about to exhaust @$rArray
    return (@partial,
	    @$rArray[ $Str .. $#$rArray ]);	### remaining full lines...
}

#------------------------------
#
# print ARGS...
#
# Instance method, override.
# Print ARGS to the underlying line array.
#
sub print {
    if (defined $\ && $\ ne "\n") {
	croak 'unsupported $\: must be "\n" or undef';
    }

    my $self = shift;
    ### print STDERR "\n[[ARRAY WAS...\n", @{*$self->{AR}}, "<<EOF>>\n";
    my @lines = split /^/, join('', @_); @lines or return 1;

    ### Did the previous print not end with a newline?
    ### If so, append first line:
    if (@{*$self->{AR}} and (*$self->{AR}[-1] !~ /\n\Z/)) {
	*$self->{AR}[-1] .= shift @lines;
    }
    push @{*$self->{AR}}, @lines;       ### add the remainder
    ### print STDERR "\n[[ARRAY IS NOW...\n", @{*$self->{AR}}, "<<EOF>>\n";
    1;
}

#------------------------------
1;

__END__


=head1 VERSION

$Id: Lines.pm,v 1.3 2005/02/10 21:21:53 dfs Exp $


=head1 AUTHOR

Eryq (F<eryq@zeegee.com>).
President, ZeeGee Software Inc (F<http://www.zeegee.com>).

=head1 CONTRIBUTORS

Dianne Skoll (F<dfs@roaringpenguin.com>).

=head1 COPYRIGHT & LICENSE

Copyright (c) 1997 Erik (Eryq) Dorfman, ZeeGee Software, Inc. All rights reserved.

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

=cut
PK9N%[l��]?@?@perl5/IO/ScalarArray.pmnu��6�$package IO::ScalarArray;

use strict;
use Carp;
use IO::Handle;

# The package version, both in 1.23 style *and* usable by MakeMaker:
our $VERSION = '2.113';

# Inheritance:
our @ISA = qw(IO::Handle);
require IO::WrapTie and push @ISA, 'IO::WrapTie::Slave' if ($] >= 5.004);

=head1 NAME

IO::ScalarArray - IO:: interface for reading/writing an array of scalars


=head1 SYNOPSIS

Perform I/O on strings, using the basic OO interface...

    use IO::ScalarArray;
    @data = ("My mes", "sage:\n");

    ### Open a handle on an array, and append to it:
    $AH = new IO::ScalarArray \@data;
    $AH->print("Hello");
    $AH->print(", world!\nBye now!\n");
    print "The array is now: ", @data, "\n";

    ### Open a handle on an array, read it line-by-line, then close it:
    $AH = new IO::ScalarArray \@data;
    while (defined($_ = $AH->getline)) {
	print "Got line: $_";
    }
    $AH->close;

    ### Open a handle on an array, and slurp in all the lines:
    $AH = new IO::ScalarArray \@data;
    print "All lines:\n", $AH->getlines;

    ### Get the current position (either of two ways):
    $pos = $AH->getpos;
    $offset = $AH->tell;

    ### Set the current position (either of two ways):
    $AH->setpos($pos);
    $AH->seek($offset, 0);

    ### Open an anonymous temporary array:
    $AH = new IO::ScalarArray;
    $AH->print("Hi there!");
    print "I printed: ", @{$AH->aref}, "\n";      ### get at value


Don't like OO for your I/O?  No problem.
Thanks to the magic of an invisible tie(), the following now
works out of the box, just as it does with IO::Handle:

    use IO::ScalarArray;
    @data = ("My mes", "sage:\n");

    ### Open a handle on an array, and append to it:
    $AH = new IO::ScalarArray \@data;
    print $AH "Hello";
    print $AH ", world!\nBye now!\n";
    print "The array is now: ", @data, "\n";

    ### Open a handle on a string, read it line-by-line, then close it:
    $AH = new IO::ScalarArray \@data;
    while (<$AH>) {
	print "Got line: $_";
    }
    close $AH;

    ### Open a handle on a string, and slurp in all the lines:
    $AH = new IO::ScalarArray \@data;
    print "All lines:\n", <$AH>;

    ### Get the current position (WARNING: requires 5.6):
    $offset = tell $AH;

    ### Set the current position (WARNING: requires 5.6):
    seek $AH, $offset, 0;

    ### Open an anonymous temporary scalar:
    $AH = new IO::ScalarArray;
    print $AH "Hi there!";
    print "I printed: ", @{$AH->aref}, "\n";      ### get at value


And for you folks with 1.x code out there: the old tie() style still works,
though this is I<unnecessary and deprecated>:

    use IO::ScalarArray;

    ### Writing to a scalar...
    my @a;
    tie *OUT, 'IO::ScalarArray', \@a;
    print OUT "line 1\nline 2\n", "line 3\n";
    print "Array is now: ", @a, "\n"

    ### Reading and writing an anonymous scalar...
    tie *OUT, 'IO::ScalarArray';
    print OUT "line 1\nline 2\n", "line 3\n";
    tied(OUT)->seek(0,0);
    while (<OUT>) {
        print "Got line: ", $_;
    }



=head1 DESCRIPTION

This class is part of the IO::Stringy distribution;
see L<IO::Stringy> for change log and general information.

The IO::ScalarArray class implements objects which behave just like
IO::Handle (or FileHandle) objects, except that you may use them
to write to (or read from) arrays of scalars.  Logically, an
array of scalars defines an in-core "file" whose contents are
the concatenation of the scalars in the array.  The handles created by
this class are automatically C<tiehandle>d (though please see L<"WARNINGS">
for information relevant to your Perl version).

For writing large amounts of data with individual print() statements,
this class is likely to be more efficient than IO::Scalar.

Basically, this:

    my @a;
    $AH = new IO::ScalarArray \@a;
    $AH->print("Hel", "lo, ");         ### OO style
    $AH->print("world!\n");            ### ditto

Or this:

    my @a;
    $AH = new IO::ScalarArray \@a;
    print $AH "Hel", "lo, ";           ### non-OO style
    print $AH "world!\n";              ### ditto

Causes @a to be set to the following array of 3 strings:

    ( "Hel" ,
      "lo, " ,
      "world!\n" )

See L<IO::Scalar> and compare with this class.


=head1 PUBLIC INTERFACE

=head2 Construction

=over 4

=cut

#------------------------------

=item new [ARGS...]

I<Class method.>
Return a new, unattached array handle.
If any arguments are given, they're sent to open().

=cut

sub new {
    my $proto = shift;
    my $class = ref($proto) || $proto;
    my $self = bless \do { local *FH }, $class;
    tie *$self, $class, $self;
    $self->open(@_);  ### open on anonymous by default
    $self;
}
sub DESTROY {
    shift->close;
}


#------------------------------

=item open [ARRAYREF]

I<Instance method.>
Open the array handle on a new array, pointed to by ARRAYREF.
If no ARRAYREF is given, a "private" array is created to hold
the file data.

Returns the self object on success, undefined on error.

=cut

sub open {
    my ($self, $aref) = @_;

    ### Sanity:
    defined($aref) or do {my @a; $aref = \@a};
    (ref($aref) eq "ARRAY") or croak "open needs a ref to a array";

    ### Setup:
    $self->setpos([0,0]);
    *$self->{AR} = $aref;
    $self;
}

#------------------------------

=item opened

I<Instance method.>
Is the array handle opened on something?

=cut

sub opened {
    *{shift()}->{AR};
}

#------------------------------

=item close

I<Instance method.>
Disassociate the array handle from its underlying array.
Done automatically on destroy.

=cut

sub close {
    my $self = shift;
    %{*$self} = ();
    1;
}

=back

=cut



#==============================

=head2 Input and output

=over 4

=cut

#------------------------------

=item flush

I<Instance method.>
No-op, provided for OO compatibility.

=cut

sub flush { "0 but true" }

#------------------------------

=item fileno

I<Instance method.>
No-op, returns undef

=cut

sub fileno { }

#------------------------------

=item getc

I<Instance method.>
Return the next character, or undef if none remain.
This does a read(1), which is somewhat costly.

=cut

sub getc {
    my $buf = '';
    ($_[0]->read($buf, 1) ? $buf : undef);
}

#------------------------------

=item getline

I<Instance method.>
Return the next line, or undef on end of data.
Can safely be called in an array context.
Currently, lines are delimited by "\n".

=cut

sub getline {
    my $self = shift;
    my ($str, $line) = (undef, '');


    ### Minimal impact implementation!
    ### We do the fast thing (no regexps) if using the
    ### classic input record separator.

    ### Case 1: $/ is undef: slurp all...
    if    (!defined($/)) {

        return undef if ($self->eof);

	### Get the rest of the current string, followed by remaining strings:
	my $ar = *$self->{AR};
	my @slurp = (
		     substr($ar->[*$self->{Str}], *$self->{Pos}),
		     @$ar[(1 + *$self->{Str}) .. $#$ar ]
		     );

	### Seek to end:
	$self->_setpos_to_eof;
	return join('', @slurp);
    }

    ### Case 2: $/ is "\n":
    elsif ($/ eq "\012") {

	### Until we hit EOF (or exited because of a found line):
	until ($self->eof) {
	    ### If at end of current string, go fwd to next one (won't be EOF):
	    if ($self->_eos) {++*$self->{Str}, *$self->{Pos}=0};

	    ### Get ref to current string in array, and set internal pos mark:
	    $str = \(*$self->{AR}[*$self->{Str}]); ### get current string
	    pos($$str) = *$self->{Pos};            ### start matching from here

	    ### Get from here to either \n or end of string, and add to line:
	    $$str =~ m/\G(.*?)((\n)|\Z)/g;         ### match to 1st \n or EOS
	    $line .= $1.$2;                        ### add it
	    *$self->{Pos} += length($1.$2);        ### move fwd by len matched
	    return $line if $3;                    ### done, got line with "\n"
        }
        return ($line eq '') ? undef : $line;  ### return undef if EOF
    }

    ### Case 3: $/ is ref to int.  Bail out.
    elsif (ref($/)) {
        croak '$/ given as a ref to int; currently unsupported';
    }

    ### Case 4: $/ is either "" (paragraphs) or something weird...
    ###         Bail for now.
    else {
        croak '$/ as given is currently unsupported';
    }
}

#------------------------------

=item getlines

I<Instance method.>
Get all remaining lines.
It will croak() if accidentally called in a scalar context.

=cut

sub getlines {
    my $self = shift;
    wantarray or croak("can't call getlines in scalar context!");
    my ($line, @lines);
    push @lines, $line while (defined($line = $self->getline));
    @lines;
}

#------------------------------

=item print ARGS...

I<Instance method.>
Print ARGS to the underlying array.

Currently, this always causes a "seek to the end of the array"
and generates a new array entry.  This may change in the future.

=cut

sub print {
    my $self = shift;
    push @{*$self->{AR}}, join('', @_) . (defined($\) ? $\ : "");      ### add the data
    $self->_setpos_to_eof;
    1;
}

#------------------------------

=item read BUF, NBYTES, [OFFSET];

I<Instance method.>
Read some bytes from the array.
Returns the number of bytes actually read, 0 on end-of-file, undef on error.

=cut

sub read {
    my $self = $_[0];
    ### we must use $_[1] as a ref
    my $n    = $_[2];
    my $off  = $_[3] || 0;

    ### print "getline\n";
    my $justread;
    my $len;
    ($off ? substr($_[1], $off) : $_[1]) = '';

    ### Stop when we have zero bytes to go, or when we hit EOF:
    my @got;
    until (!$n or $self->eof) {
        ### If at end of current string, go forward to next one (won't be EOF):
        if ($self->_eos) {
            ++*$self->{Str};
            *$self->{Pos} = 0;
        }

        ### Get longest possible desired substring of current string:
        $justread = substr(*$self->{AR}[*$self->{Str}], *$self->{Pos}, $n);
        $len = length($justread);
        push @got, $justread;
        $n            -= $len;
        *$self->{Pos} += $len;
    }
    $_[1] .= join('', @got);
    return length($_[1])-$off;
}

#------------------------------

=item write BUF, NBYTES, [OFFSET];

I<Instance method.>
Write some bytes into the array.

=cut

sub write {
    my $self = $_[0];
    my $n    = $_[2];
    my $off  = $_[3] || 0;

    my $data = substr($_[1], $n, $off);
    $n = length($data);
    $self->print($data);
    return $n;
}


=back

=cut



#==============================

=head2 Seeking/telling and other attributes

=over 4

=cut

#------------------------------

=item autoflush

I<Instance method.>
No-op, provided for OO compatibility.

=cut

sub autoflush {}

#------------------------------

=item binmode

I<Instance method.>
No-op, provided for OO compatibility.

=cut

sub binmode {}

#------------------------------

=item clearerr

I<Instance method.>  Clear the error and EOF flags.  A no-op.

=cut

sub clearerr { 1 }

#------------------------------

=item eof

I<Instance method.>  Are we at end of file?

=cut

sub eof {
    ### print "checking EOF [*$self->{Str}, *$self->{Pos}]\n";
    ### print "SR = ", $#{*$self->{AR}}, "\n";

    return 0 if (*{$_[0]}->{Str} < $#{*{$_[0]}->{AR}});  ### before EOA
    return 1 if (*{$_[0]}->{Str} > $#{*{$_[0]}->{AR}});  ### after EOA
    ###                                                  ### at EOA, past EOS:
    ((*{$_[0]}->{Str} == $#{*{$_[0]}->{AR}}) && ($_[0]->_eos));
}

#------------------------------
#
# _eos
#
# I<Instance method, private.>  Are we at end of the CURRENT string?
#
sub _eos {
    (*{$_[0]}->{Pos} >= length(*{$_[0]}->{AR}[*{$_[0]}->{Str}])); ### past last char
}

#------------------------------

=item seek POS,WHENCE

I<Instance method.>
Seek to a given position in the stream.
Only a WHENCE of 0 (SEEK_SET) is supported.

=cut

sub seek {
    my ($self, $pos, $whence) = @_;

    ### Seek:
    if    ($whence == 0) { $self->_seek_set($pos); }
    elsif ($whence == 1) { $self->_seek_cur($pos); }
    elsif ($whence == 2) { $self->_seek_end($pos); }
    else                 { croak "bad seek whence ($whence)" }
    return 1;
}

#------------------------------
#
# _seek_set POS
#
# Instance method, private.
# Seek to $pos relative to start:
#
sub _seek_set {
    my ($self, $pos) = @_;

    ### Advance through array until done:
    my $istr = 0;
    while (($pos >= 0) && ($istr < scalar(@{*$self->{AR}}))) {
	if (length(*$self->{AR}[$istr]) > $pos) {   ### it's in this string!
	    return $self->setpos([$istr, $pos]);
	}
	else {                                      ### it's in next string
	    $pos -= length(*$self->{AR}[$istr++]);  ### move forward one string
	}
    }
    ### If we reached this point, pos is at or past end; zoom to EOF:
    return $self->_setpos_to_eof;
}

#------------------------------
#
# _seek_cur POS
#
# Instance method, private.
# Seek to $pos relative to current position.
#
sub _seek_cur {
    my ($self, $pos) = @_;
    $self->_seek_set($self->tell + $pos);
}

#------------------------------
#
# _seek_end POS
#
# Instance method, private.
# Seek to $pos relative to end.
# We actually seek relative to beginning, which is simple.
#
sub _seek_end {
    my ($self, $pos) = @_;
    $self->_seek_set($self->_tell_eof + $pos);
}

#------------------------------

=item tell

I<Instance method.>
Return the current position in the stream, as a numeric offset.

=cut

sub tell {
    my $self = shift;
    my $off = 0;
    my ($s, $str_s);
    for ($s = 0; $s < *$self->{Str}; $s++) {   ### count all "whole" scalars
	defined($str_s = *$self->{AR}[$s]) or $str_s = '';
	###print STDERR "COUNTING STRING $s (". length($str_s) . ")\n";
	$off += length($str_s);
    }
    ###print STDERR "COUNTING POS ($self->{Pos})\n";
    return ($off += *$self->{Pos});            ### plus the final, partial one
}

#------------------------------
#
# _tell_eof
#
# Instance method, private.
# Get position of EOF, as a numeric offset.
# This is identical to the size of the stream - 1.
#
sub _tell_eof {
    my $self = shift;
    my $len = 0;
    foreach (@{*$self->{AR}}) { $len += length($_) }
    $len;
}

#------------------------------

=item setpos POS

I<Instance method.>
Seek to a given position in the array, using the opaque getpos() value.
Don't expect this to be a number.

=cut

sub setpos {
    my ($self, $pos) = @_;
    (ref($pos) eq 'ARRAY') or
	die "setpos: only use a value returned by getpos!\n";
    (*$self->{Str}, *$self->{Pos}) = @$pos;
}

#------------------------------
#
# _setpos_to_eof
#
# Fast-forward to EOF.
#
sub _setpos_to_eof {
    my $self = shift;
    $self->setpos([scalar(@{*$self->{AR}}), 0]);
}

#------------------------------

=item getpos

I<Instance method.>
Return the current position in the array, as an opaque value.
Don't expect this to be a number.

=cut

sub getpos {
    [*{$_[0]}->{Str}, *{$_[0]}->{Pos}];
}

#------------------------------

=item aref

I<Instance method.>
Return a reference to the underlying array.

=cut

sub aref {
    *{shift()}->{AR};
}

=back

=cut

#------------------------------
# Tied handle methods...
#------------------------------

### Conventional tiehandle interface:
sub TIEHANDLE { (defined($_[1]) && UNIVERSAL::isa($_[1],"IO::ScalarArray"))
		    ? $_[1]
		    : shift->new(@_) }
sub GETC      { shift->getc(@_) }
sub PRINT     { shift->print(@_) }
sub PRINTF    { shift->print(sprintf(shift, @_)) }
sub READ      { shift->read(@_) }
sub READLINE  { wantarray ? shift->getlines(@_) : shift->getline(@_) }
sub WRITE     { shift->write(@_); }
sub CLOSE     { shift->close(@_); }
sub SEEK      { shift->seek(@_); }
sub TELL      { shift->tell(@_); }
sub EOF       { shift->eof(@_); }
sub BINMODE   { 1; }

#------------------------------------------------------------

1;
__END__

# SOME PRIVATE NOTES:
#
#     * The "current position" is the position before the next
#       character to be read/written.
#
#     * Str gives the string index of the current position, 0-based
#
#     * Pos gives the offset within AR[Str], 0-based.
#
#     * Inital pos is [0,0].  After print("Hello"), it is [1,0].

=head1 AUTHOR

Eryq (F<eryq@zeegee.com>).
President, ZeeGee Software Inc (F<http://www.zeegee.com>).

=head1 CONTRIBUTORS

Dianne Skoll (F<dfs@roaringpenguin.com>).

=head1 COPYRIGHT & LICENSE

Copyright (c) 1997 Erik (Eryq) Dorfman, ZeeGee Software, Inc. All rights reserved.

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

=cut
PK9N%[*�2U"U"perl5/IO/Wrap.pmnu��6�$package IO::Wrap;

use strict;
use Exporter;
use FileHandle;
use Carp;

our $VERSION = '2.113';
our @ISA = qw(Exporter);
our @EXPORT = qw(wraphandle);


#------------------------------
# wraphandle RAW
#------------------------------
sub wraphandle {
    my $raw = shift;
    new IO::Wrap $raw;
}

#------------------------------
# new STREAM
#------------------------------
sub new {
    my ($class, $stream) = @_;
    no strict 'refs';

    ### Convert raw scalar to globref:
    ref($stream) or $stream = \*$stream;

    ### Wrap globref and incomplete objects:
    if ((ref($stream) eq 'GLOB') or      ### globref
	(ref($stream) eq 'FileHandle') && !defined(&FileHandle::read)) {
	return bless \$stream, $class;
    }
    $stream;           ### already okay!
}

#------------------------------
# I/O methods...
#------------------------------
sub close {
    my $self = shift;
    return close($$self);
}
sub fileno {
    my $self = shift;
    my $fh = $$self;
    return fileno($fh);
}

sub getline {
    my $self = shift;
    my $fh = $$self;
    return scalar(<$fh>);
}
sub getlines {
    my $self = shift;
    wantarray or croak("Can't call getlines in scalar context!");
    my $fh = $$self;
    <$fh>;
}
sub print {
    my $self = shift;
    print { $$self } @_;
}
sub read {
    my $self = shift;
    return read($$self, $_[0], $_[1]);
}
sub seek {
    my $self = shift;
    return seek($$self, $_[0], $_[1]);
}
sub tell {
    my $self = shift;
    return tell($$self);
}

1;
__END__


=head1 NAME

IO::Wrap - Wrap raw filehandles in the IO::Handle interface

=head1 SYNOPSIS

    use strict;
    use warnings;
    use IO::Wrap;

    # this is a fairly senseless use case as IO::Handle already does this.
    my $wrap_fh = IO::Wrap->new(\*STDIN);
    my $line = $wrap_fh->getline();

    # Do stuff with any kind of filehandle (including a bare globref), or
    # any kind of blessed object that responds to a print() message.

    # already have a globref? a FileHandle? a scalar filehandle name?
    $wrap_fh = IO::Wrap->new($some_unknown_thing);

    # At this point, we know we have an IO::Handle-like object! YAY
    $wrap_fh->print("Hey there!");

You can also do this using a convenience wrapper function

    use strict;
    use warnings;
    use IO::Wrap qw(wraphandle);

    # this is a fairly senseless use case as IO::Handle already does this.
    my $wrap_fh = wraphandle(\*STDIN);
    my $line = $wrap_fh->getline();

    # Do stuff with any kind of filehandle (including a bare globref), or
    # any kind of blessed object that responds to a print() message.

    # already have a globref? a FileHandle? a scalar filehandle name?
    $wrap_fh = wraphandle($some_unknown_thing);

    # At this point, we know we have an IO::Handle-like object! YAY
    $wrap_fh->print("Hey there!");

=head1 DESCRIPTION

Let's say you want to write some code which does I/O, but you don't
want to force the caller to provide you with a L<FileHandle> or L<IO::Handle>
object.  You want them to be able to say:

    do_stuff(\*STDOUT);
    do_stuff('STDERR');
    do_stuff($some_FileHandle_object);
    do_stuff($some_IO_Handle_object);

And even:

    do_stuff($any_object_with_a_print_method);

Sure, one way to do it is to force the caller to use C<tiehandle()>.
But that puts the burden on them.  Another way to do it is to
use B<IO::Wrap>.

Clearly, when wrapping a raw external filehandle (like C<\*STDOUT>),
I didn't want to close the file descriptor when the wrapper object is
destroyed; the user might not appreciate that! Hence, there's no
C<DESTROY> method in this class.

When wrapping a L<FileHandle> object, however, I believe that Perl will
invoke the C<FileHandle::DESTROY> when the last reference goes away,
so in that case, the filehandle is closed if the wrapped L<FileHandle>
really was the last reference to it.

=head1 FUNCTIONS

L<IO::Wrap> makes the following functions available.

=head2 wraphandle

    # wrap a filehandle glob
    my $fh = wraphandle(\*STDIN);
    # wrap a raw filehandle glob by name
    $fh = wraphandle('STDIN');
    # wrap a handle in an object
    $fh = wraphandle('Class::HANDLE');

    # wrap a blessed FileHandle object
    use FileHandle;
    my $fho = FileHandle->new("/tmp/foo.txt", "r");
    $fh = wraphandle($fho);

    # wrap any other blessed object that shares IO::Handle's interface
    $fh = wraphandle($some_object);

This function is simply a wrapper to the L<IO::Wrap/"new"> constructor method.

=head1 METHODS

L<IO::Wrap> implements the following methods.

=head2 close

    $fh->close();

The C<close> method will attempt to close the system file descriptor. For a
more complete description, read L<perlfunc/close>.

=head2 fileno

    my $int = $fh->fileno();

The C<fileno> method returns the file descriptor for the wrapped filehandle.
See L<perlfunc/fileno> for more information.

=head2 getline

    my $data = $fh->getline();

The C<getline> method mimics the function by the same name in L<IO::Handle>.
It's like calling C<< my $data = <$fh>; >> but only in scalar context.

=head2 getlines

    my @data = $fh->getlines();

The C<getlines> method mimics the function by the same name in L<IO::Handle>.
It's like calling C<< my @data = <$fh>; >> but only in list context. Calling
this method in scalar context will result in a croak.

=head2 new

    # wrap a filehandle glob
    my $fh = IO::Wrap->new(\*STDIN);
    # wrap a raw filehandle glob by name
    $fh = IO::Wrap->new('STDIN');
    # wrap a handle in an object
    $fh = IO::Wrap->new('Class::HANDLE');

    # wrap a blessed FileHandle object
    use FileHandle;
    my $fho = FileHandle->new("/tmp/foo.txt", "r");
    $fh = IO::Wrap->new($fho);

    # wrap any other blessed object that shares IO::Handle's interface
    $fh = IO::Wrap->new($some_object);

The C<new> constructor method takes in a single argument and decides to wrap
it or not it based on what it seems to be.

A raw scalar file handle name, like C<"STDOUT"> or C<"Class::HANDLE"> can be
wrapped, returning an L<IO::Wrap> object instance.

A raw filehandle glob, like C<\*STDOUT> can also be wrapped, returning an
L<IO::Wrawp> object instance.

A blessed L<FileHandle> object can also be wrapped. This is a special case
where an L<IO::Wrap> object instance will only be returned in the case that
your L<FileHandle> object doesn't support the C<read> method.

Also, any other kind of blessed object that conforms to the
L<IO::Handle> interface can be passed in. In this case, you just get back
that object.

In other words, we only wrap it into an L<IO::Wrap> object when what you've
supplied doesn't already conform to the L<IO::Handle> interface.

If you get back an L<IO::Wrap> object, it will obey a basic subset of
the C<IO::> interface. It will do so with object B<methods>, not B<operators>.

=head3 CAVEATS

This module does not allow you to wrap filehandle names which are given
as strings that lack the package they were opened in. That is, if a user
opens FOO in package Foo, they must pass it to you either as C<\*FOO>
or as C<"Foo::FOO">.  However, C<"STDIN"> and friends will work just fine.

=head2 print

    $fh->print("Some string");
    $fh->print("more", " than one", " string");

The C<print> method will attempt to print a string or list of strings to the
filehandle. For a more complete description, read
L<perlfunc/print>.

=head2 read

    my $buffer;
    # try to read 30 chars into the buffer starting at the
    # current cursor position.
    my $num_chars_read = $fh->read($buffer, 30);

The L<read> method attempts to read a number of characters, starting at the
filehandle's current cursor position. It returns the number of characters
actually read. See L<perlfunc/read> for more information.

=head2 seek

    use Fcntl qw(:seek); # import the SEEK_CUR, SEEK_SET, SEEK_END constants
    # seek to the position in bytes
    $fh->seek(0, SEEK_SET);
    # seek to the position in bytes from the current position
    $fh->seek(22, SEEK_CUR);
    # seek to the EOF plus bytes
    $fh->seek(0, SEEK_END);

The C<seek> method will attempt to set the cursor to a given position in bytes
for the wrapped file handle. See L<perlfunc/seek> for more information.

=head2 tell

    my $bytes = $fh->tell();

The C<tell> method will attempt to return the current position of the cursor
in bytes for the wrapped file handle. See L<perlfunc/tell> for more
information.

=head1 AUTHOR

Eryq (F<eryq@zeegee.com>).
President, ZeeGee Software Inc (F<http://www.zeegee.com>).

=head1 CONTRIBUTORS

Dianne Skoll (F<dfs@roaringpenguin.com>).

=head1 COPYRIGHT & LICENSE

Copyright (c) 1997 Erik (Eryq) Dorfman, ZeeGee Software, Inc. All rights reserved.

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

=cut
PK9N%[��^�:�:perl5/IO/Scalar.pmnu��6�$package IO::Scalar;

use strict;

use Carp;
use IO::Handle;

### Stringification, courtesy of B. K. Oxley (binkley):  :-)
use overload '""'   => sub { ${*{$_[0]}->{SR}} };
use overload 'bool' => sub { 1 };      ### have to do this, so object is true!

### The package version, both in 1.23 style *and* usable by MakeMaker:
our $VERSION = '2.113';

### Inheritance:
our @ISA = qw(IO::Handle);

### This stuff should be got rid of ASAP.
require IO::WrapTie and push @ISA, 'IO::WrapTie::Slave' if ($] >= 5.004);

#==============================



=head1 NAME

IO::Scalar - IO:: interface for reading/writing a scalar


=head1 SYNOPSIS

Perform I/O on strings, using the basic OO interface...

    use 5.005;
    use IO::Scalar;
    $data = "My message:\n";

    ### Open a handle on a string, and append to it:
    $SH = new IO::Scalar \$data;
    $SH->print("Hello");
    $SH->print(", world!\nBye now!\n");
    print "The string is now: ", $data, "\n";

    ### Open a handle on a string, read it line-by-line, then close it:
    $SH = new IO::Scalar \$data;
    while (defined($_ = $SH->getline)) {
	print "Got line: $_";
    }
    $SH->close;

    ### Open a handle on a string, and slurp in all the lines:
    $SH = new IO::Scalar \$data;
    print "All lines:\n", $SH->getlines;

    ### Get the current position (either of two ways):
    $pos = $SH->getpos;
    $offset = $SH->tell;

    ### Set the current position (either of two ways):
    $SH->setpos($pos);
    $SH->seek($offset, 0);

    ### Open an anonymous temporary scalar:
    $SH = new IO::Scalar;
    $SH->print("Hi there!");
    print "I printed: ", ${$SH->sref}, "\n";      ### get at value


Don't like OO for your I/O?  No problem.
Thanks to the magic of an invisible tie(), the following now
works out of the box, just as it does with IO::Handle:

    use 5.005;
    use IO::Scalar;
    $data = "My message:\n";

    ### Open a handle on a string, and append to it:
    $SH = new IO::Scalar \$data;
    print $SH "Hello";
    print $SH ", world!\nBye now!\n";
    print "The string is now: ", $data, "\n";

    ### Open a handle on a string, read it line-by-line, then close it:
    $SH = new IO::Scalar \$data;
    while (<$SH>) {
	print "Got line: $_";
    }
    close $SH;

    ### Open a handle on a string, and slurp in all the lines:
    $SH = new IO::Scalar \$data;
    print "All lines:\n", <$SH>;

    ### Get the current position (WARNING: requires 5.6):
    $offset = tell $SH;

    ### Set the current position (WARNING: requires 5.6):
    seek $SH, $offset, 0;

    ### Open an anonymous temporary scalar:
    $SH = new IO::Scalar;
    print $SH "Hi there!";
    print "I printed: ", ${$SH->sref}, "\n";      ### get at value


And for you folks with 1.x code out there: the old tie() style still works,
though this is I<unnecessary and deprecated>:

    use IO::Scalar;

    ### Writing to a scalar...
    my $s;
    tie *OUT, 'IO::Scalar', \$s;
    print OUT "line 1\nline 2\n", "line 3\n";
    print "String is now: $s\n"

    ### Reading and writing an anonymous scalar...
    tie *OUT, 'IO::Scalar';
    print OUT "line 1\nline 2\n", "line 3\n";
    tied(OUT)->seek(0,0);
    while (<OUT>) {
        print "Got line: ", $_;
    }


Stringification works, too!

    my $SH = new IO::Scalar \$data;
    print $SH "Hello, ";
    print $SH "world!";
    print "I printed: $SH\n";



=head1 DESCRIPTION

This class is part of the IO::Stringy distribution;
see L<IO::Stringy> for change log and general information.

The IO::Scalar class implements objects which behave just like
IO::Handle (or FileHandle) objects, except that you may use them
to write to (or read from) scalars.  These handles are
automatically C<tiehandle>d (though please see L<"WARNINGS">
for information relevant to your Perl version).


Basically, this:

    my $s;
    $SH = new IO::Scalar \$s;
    $SH->print("Hel", "lo, ");         ### OO style
    $SH->print("world!\n");            ### ditto

Or this:

    my $s;
    $SH = tie *OUT, 'IO::Scalar', \$s;
    print OUT "Hel", "lo, ";           ### non-OO style
    print OUT "world!\n";              ### ditto

Causes $s to be set to:

    "Hello, world!\n"


=head1 PUBLIC INTERFACE

=head2 Construction

=over 4

=cut

#------------------------------

=item new [ARGS...]

I<Class method.>
Return a new, unattached scalar handle.
If any arguments are given, they're sent to open().

=cut

sub new {
    my $proto = shift;
    my $class = ref($proto) || $proto;
    my $self = bless \do { local *FH }, $class;
    tie *$self, $class, $self;
    $self->open(@_);   ### open on anonymous by default
    $self;
}
sub DESTROY {
    shift->close;
}

#------------------------------

=item open [SCALARREF]

I<Instance method.>
Open the scalar handle on a new scalar, pointed to by SCALARREF.
If no SCALARREF is given, a "private" scalar is created to hold
the file data.

Returns the self object on success, undefined on error.

=cut

sub open {
    my ($self, $sref) = @_;

    ### Sanity:
    defined($sref) or do {my $s = ''; $sref = \$s};
    (ref($sref) eq "SCALAR") or croak "open() needs a ref to a scalar";

    ### Setup:
    *$self->{Pos} = 0;          ### seek position
    *$self->{SR}  = $sref;      ### scalar reference
    $self;
}

#------------------------------

=item opened

I<Instance method.>
Is the scalar handle opened on something?

=cut

sub opened {
    *{shift()}->{SR};
}

#------------------------------

=item close

I<Instance method.>
Disassociate the scalar handle from its underlying scalar.
Done automatically on destroy.

=cut

sub close {
    my $self = shift;
    %{*$self} = ();
    1;
}

=back

=cut



#==============================

=head2 Input and output

=over 4

=cut


#------------------------------

=item flush

I<Instance method.>
No-op, provided for OO compatibility.

=cut

sub flush { "0 but true" }

#------------------------------

=item fileno

I<Instance method.>
No-op, returns undef

=cut

sub fileno { }

#------------------------------

=item getc

I<Instance method.>
Return the next character, or undef if none remain.

=cut

sub getc {
    my $self = shift;

    ### Return undef right away if at EOF; else, move pos forward:
    return undef if $self->eof;
    substr(${*$self->{SR}}, *$self->{Pos}++, 1);
}

#------------------------------

=item getline

I<Instance method.>
Return the next line, or undef on end of string.
Can safely be called in an array context.
Currently, lines are delimited by "\n".

=cut

sub getline {
    my $self = shift;

    ### Return undef right away if at EOF:
    return undef if $self->eof;

    ### Get next line:
    my $sr = *$self->{SR};
    my $i  = *$self->{Pos};	        ### Start matching at this point.

    ### Minimal impact implementation!
    ### We do the fast thing (no regexps) if using the
    ### classic input record separator.

    ### Case 1: $/ is undef: slurp all...
    if    (!defined($/)) {
	*$self->{Pos} = length $$sr;
        return substr($$sr, $i);
    }

    ### Case 2: $/ is "\n": zoom zoom zoom...
    elsif ($/ eq "\012") {

        ### Seek ahead for "\n"... yes, this really is faster than regexps.
        my $len = length($$sr);
        for (; $i < $len; ++$i) {
           last if ord (substr ($$sr, $i, 1)) == 10;
        }

        ### Extract the line:
        my $line;
        if ($i < $len) {                ### We found a "\n":
            $line = substr ($$sr, *$self->{Pos}, $i - *$self->{Pos} + 1);
            *$self->{Pos} = $i+1;            ### Remember where we finished up.
        }
        else {                          ### No "\n"; slurp the remainder:
            $line = substr ($$sr, *$self->{Pos}, $i - *$self->{Pos});
            *$self->{Pos} = $len;
        }
        return $line;
    }

    ### Case 3: $/ is ref to int. Do fixed-size records.
    ###        (Thanks to Dominique Quatravaux.)
    elsif (ref($/)) {
        my $len = length($$sr);
		my $i = ${$/} + 0;
		my $line = substr ($$sr, *$self->{Pos}, $i);
		*$self->{Pos} += $i;
        *$self->{Pos} = $len if (*$self->{Pos} > $len);
		return $line;
    }

    ### Case 4: $/ is either "" (paragraphs) or something weird...
    ###         This is Graham's general-purpose stuff, which might be
    ###         a tad slower than Case 2 for typical data, because
    ###         of the regexps.
    else {
        pos($$sr) = $i;

	### If in paragraph mode, skip leading lines (and update i!):
        length($/) or
	    (($$sr =~ m/\G\n*/g) and ($i = pos($$sr)));

        ### If we see the separator in the buffer ahead...
        if (length($/)
	    ?  $$sr =~ m,\Q$/\E,g          ###   (ordinary sep) TBD: precomp!
            :  $$sr =~ m,\n\n,g            ###   (a paragraph)
            ) {
            *$self->{Pos} = pos $$sr;
            return substr($$sr, $i, *$self->{Pos}-$i);
        }
        ### Else if no separator remains, just slurp the rest:
        else {
            *$self->{Pos} = length $$sr;
            return substr($$sr, $i);
        }
    }
}

#------------------------------

=item getlines

I<Instance method.>
Get all remaining lines.
It will croak() if accidentally called in a scalar context.

=cut

sub getlines {
    my $self = shift;
    wantarray or croak("can't call getlines in scalar context!");
    my ($line, @lines);
    push @lines, $line while (defined($line = $self->getline));
    @lines;
}

#------------------------------

=item print ARGS...

I<Instance method.>
Print ARGS to the underlying scalar.

B<Warning:> this continues to always cause a seek to the end
of the string, but if you perform seek()s and tell()s, it is
still safer to explicitly seek-to-end before subsequent print()s.

=cut

sub print {
    my $self = shift;
    *$self->{Pos} = length(${*$self->{SR}} .= join('', @_) . (defined($\) ? $\ : ""));
    1;
}
sub _unsafe_print {
    my $self = shift;
    my $append = join('', @_) . $\;
    ${*$self->{SR}} .= $append;
    *$self->{Pos}   += length($append);
    1;
}
sub _old_print {
    my $self = shift;
    ${*$self->{SR}} .= join('', @_) . $\;
    *$self->{Pos} = length(${*$self->{SR}});
    1;
}


#------------------------------

=item read BUF, NBYTES, [OFFSET]

I<Instance method.>
Read some bytes from the scalar.
Returns the number of bytes actually read, 0 on end-of-file, undef on error.

=cut

sub read {
    my $self = $_[0];
    my $n    = $_[2];
    my $off  = $_[3] || 0;

    my $read = substr(${*$self->{SR}}, *$self->{Pos}, $n);
    $n = length($read);
    *$self->{Pos} += $n;
    ($off ? substr($_[1], $off) : $_[1]) = $read;
    return $n;
}

#------------------------------

=item write BUF, NBYTES, [OFFSET]

I<Instance method.>
Write some bytes to the scalar.

=cut

sub write {
    my $self = $_[0];
    my $n    = $_[2];
    my $off  = $_[3] || 0;

    my $data = substr($_[1], $off, $n);
    $n = length($data);
    $self->print($data);
    return $n;
}

#------------------------------

=item sysread BUF, LEN, [OFFSET]

I<Instance method.>
Read some bytes from the scalar.
Returns the number of bytes actually read, 0 on end-of-file, undef on error.

=cut

sub sysread {
  my $self = shift;
  $self->read(@_);
}

#------------------------------

=item syswrite BUF, NBYTES, [OFFSET]

I<Instance method.>
Write some bytes to the scalar.

=cut

sub syswrite {
  my $self = shift;
  $self->write(@_);
}

=back

=cut


#==============================

=head2 Seeking/telling and other attributes

=over 4

=cut


#------------------------------

=item autoflush

I<Instance method.>
No-op, provided for OO compatibility.

=cut

sub autoflush {}

#------------------------------

=item binmode

I<Instance method.>
No-op, provided for OO compatibility.

=cut

sub binmode {}

#------------------------------

=item clearerr

I<Instance method.>  Clear the error and EOF flags.  A no-op.

=cut

sub clearerr { 1 }

#------------------------------

=item eof

I<Instance method.>  Are we at end of file?

=cut

sub eof {
    my $self = shift;
    (*$self->{Pos} >= length(${*$self->{SR}}));
}

#------------------------------

=item seek OFFSET, WHENCE

I<Instance method.>  Seek to a given position in the stream.

=cut

sub seek {
    my ($self, $pos, $whence) = @_;
    my $eofpos = length(${*$self->{SR}});

    ### Seek:
    if    ($whence == 0) { *$self->{Pos} = $pos }             ### SEEK_SET
    elsif ($whence == 1) { *$self->{Pos} += $pos }            ### SEEK_CUR
    elsif ($whence == 2) { *$self->{Pos} = $eofpos + $pos}    ### SEEK_END
    else                 { croak "bad seek whence ($whence)" }

    ### Fixup:
    if (*$self->{Pos} < 0)       { *$self->{Pos} = 0 }
    if (*$self->{Pos} > $eofpos) { *$self->{Pos} = $eofpos }
    return 1;
}

#------------------------------

=item sysseek OFFSET, WHENCE

I<Instance method.> Identical to C<seek OFFSET, WHENCE>, I<q.v.>

=cut

sub sysseek {
    my $self = shift;
    $self->seek (@_);
}

#------------------------------

=item tell

I<Instance method.>
Return the current position in the stream, as a numeric offset.

=cut

sub tell { *{shift()}->{Pos} }

#------------------------------
#
# use_RS [YESNO]
#
# I<Instance method.>
# Obey the current setting of $/, like IO::Handle does?
# Default is false in 1.x, but cold-welded true in 2.x and later.
#
sub use_RS {
    my ($self, $yesno) = @_;
    carp "use_RS is deprecated and ignored; \$/ is always consulted\n";
 }

#------------------------------

=item setpos POS

I<Instance method.>
Set the current position, using the opaque value returned by C<getpos()>.

=cut

sub setpos { shift->seek($_[0],0) }

#------------------------------

=item getpos

I<Instance method.>
Return the current position in the string, as an opaque object.

=cut

*getpos = \&tell;


#------------------------------

=item sref

I<Instance method.>
Return a reference to the underlying scalar.

=cut

sub sref { *{shift()}->{SR} }


#------------------------------
# Tied handle methods...
#------------------------------

# Conventional tiehandle interface:
sub TIEHANDLE {
    ((defined($_[1]) && UNIVERSAL::isa($_[1], "IO::Scalar"))
     ? $_[1]
     : shift->new(@_));
}
sub GETC      { shift->getc(@_) }
sub PRINT     { shift->print(@_) }
sub PRINTF    { shift->print(sprintf(shift, @_)) }
sub READ      { shift->read(@_) }
sub READLINE  { wantarray ? shift->getlines(@_) : shift->getline(@_) }
sub WRITE     { shift->write(@_); }
sub CLOSE     { shift->close(@_); }
sub SEEK      { shift->seek(@_); }
sub TELL      { shift->tell(@_); }
sub EOF       { shift->eof(@_); }
sub BINMODE   { 1; }

#------------------------------------------------------------

1;

__END__



=back

=cut


=head1 AUTHOR

Eryq (F<eryq@zeegee.com>).
President, ZeeGee Software Inc (F<http://www.zeegee.com>).

=head1 CONTRIBUTORS

Dianne Skoll (F<dfs@roaringpenguin.com>).

=head1 COPYRIGHT & LICENSE

Copyright (c) 1997 Erik (Eryq) Dorfman, ZeeGee Software, Inc. All rights reserved.

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

=cut
PK9N%[���r��perl5/IO/AtomicFile.pmnu��6�$package IO::AtomicFile;

use strict;
use warnings;
use parent 'IO::File';

our $VERSION = '2.113';

#------------------------------
# new ARGS...
#------------------------------
# Class method, constructor.
# Any arguments are sent to open().
#
sub new {
    my $class = shift;
    my $self = $class->SUPER::new();
    ${*$self}{'io_atomicfile_suffix'} = '';
    $self->open(@_) if @_;
    $self;
}

#------------------------------
# DESTROY
#------------------------------
# Destructor.
#
sub DESTROY {
    shift->close(1);   ### like close, but raises fatal exception on failure
}

#------------------------------
# open PATH, MODE
#------------------------------
# Class/instance method.
#
sub open {
    my ($self, $path, $mode) = @_;
    ref($self) or $self = $self->new;    ### now we have an instance!

    ### Create tmp path, and remember this info:
    my $temp = "${path}..TMP" . ${*$self}{'io_atomicfile_suffix'};
    ${*$self}{'io_atomicfile_temp'} = $temp;
    ${*$self}{'io_atomicfile_path'} = $path;

    ### Open the file!  Returns filehandle on success, for use as a constructor:
    $self->SUPER::open($temp, $mode) ? $self : undef;
}

#------------------------------
# _closed [YESNO]
#------------------------------
# Instance method, private.
# Are we already closed?  Argument sets new value, returns previous one.
#
sub _closed {
    my $self = shift;
    my $oldval = ${*$self}{'io_atomicfile_closed'};
    ${*$self}{'io_atomicfile_closed'} = shift if @_;
    $oldval;
}

#------------------------------
# close
#------------------------------
# Instance method.
# Close the handle, and rename the temp file to its final name.
#
sub close {
    my ($self, $die) = @_;
    unless ($self->_closed(1)) {             ### sentinel...
	    if ($self->SUPER::close()) {
		    rename(${*$self}{'io_atomicfile_temp'},
			   ${*$self}{'io_atomicfile_path'})
			or ($die ? die "close (rename) atomic file: $!\n" : return undef);
	    } else {
		    ($die ? die "close atomic file: $!\n" : return undef);
	    }
    }
    1;
}

#------------------------------
# delete
#------------------------------
# Instance method.
# Close the handle, and delete the temp file.
#
sub delete {
    my $self = shift;
    unless ($self->_closed(1)) {             ### sentinel...
        $self->SUPER::close();
        return unlink(${*$self}{'io_atomicfile_temp'});
    }
    1;
}

#------------------------------
# detach
#------------------------------
# Instance method.
# Close the handle, but DO NOT delete the temp file.
#
sub detach {
    my $self = shift;
    $self->SUPER::close() unless ($self->_closed(1));
    1;
}

#------------------------------
1;
__END__


=head1 NAME

IO::AtomicFile - write a file which is updated atomically

=head1 SYNOPSIS

    use strict;
    use warnings;
    use feature 'say';
    use IO::AtomicFile;

    # Write a temp file, and have it install itself when closed:
    my $fh = IO::AtomicFile->open("bar.dat", "w");
    $fh->say("Hello!");
    $fh->close || die "couldn't install atomic file: $!";

    # Write a temp file, but delete it before it gets installed:
    my $fh = IO::AtomicFile->open("bar.dat", "w");
    $fh->say("Hello!");
    $fh->delete;

    # Write a temp file, but neither install it nor delete it:
    my $fh = IO::AtomicFile->open("bar.dat", "w");
    $fh->say("Hello!");
    $fh->detach;

=head1 DESCRIPTION

This module is intended for people who need to update files
reliably in the face of unexpected program termination.

For example, you generally don't want to be halfway in the middle of
writing I</etc/passwd> and have your program terminate!  Even
the act of writing a single scalar to a filehandle is I<not> atomic.

But this module gives you true atomic updates, via C<rename>.
When you open a file I</foo/bar.dat> via this module, you are I<actually>
opening a temporary file I</foo/bar.dat..TMP>, and writing your
output there. The act of closing this file (either explicitly
via C<close>, or implicitly via the destruction of the object)
will cause C<rename> to be called... therefore, from the point
of view of the outside world, the file's contents are updated
in a single time quantum.

To ensure that problems do not go undetected, the C<close> method
done by the destructor will raise a fatal exception if the C<rename>
fails.  The explicit C<close> just returns C<undef>.

You can also decide at any point to trash the file you've been
building.

=head1 METHODS

L<IO::AtomicFile> inherits all methods from L<IO::File> and
implements the following new ones.

=head2 close

    $fh->close();

This method calls its parent L<IO::File/"close"> and then renames its temporary file
as the original file name.

=head2 delete

    $fh->delete();

This method calls its parent L<IO::File/"close"> and then deletes the temporary file.

=head2 detach

    $fh->detach();

This method calls its parent L<IO::File/"close">. Unlike L<IO::AtomicFile/"delete"> it
does not then delete the temporary file.

=head1 AUTHOR

Eryq (F<eryq@zeegee.com>).
President, ZeeGee Software Inc (F<http://www.zeegee.com>).

=head1 CONTRIBUTORS

Dianne Skoll (F<dfs@roaringpenguin.com>).

=head1 COPYRIGHT & LICENSE

Copyright (c) 1997 Erik (Eryq) Dorfman, ZeeGee Software, Inc. All rights reserved.

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

=cut
PK9N%[�h�perl5/IO/Stringy.pmnu��6�$package IO::Stringy;
use strict;
use Exporter;

our $VERSION = '2.113';

1;
__END__

=head1 NAME

IO-stringy - I/O on in-core objects like strings and arrays

=head1 SYNOPSIS

    use strict;
    use warnings;

    use IO::AtomicFile; # Write a file which is updated atomically
    use IO::InnerFile; # define a file inside another file
    use IO::Lines; # I/O handle to read/write to array of lines
    use IO::Scalar; # I/O handle to read/write to a string
    use IO::ScalarArray; # I/O handle to read/write to array of scalars
    use IO::Wrap; # Wrap old-style FHs in standard OO interface
    use IO::WrapTie; # Tie your handles & retain full OO interface

    # ...

=head1 DESCRIPTION

This toolkit primarily provides modules for performing both traditional
and object-oriented i/o) on things I<other> than normal filehandles;
in particular, L<IO::Scalar|IO::Scalar>, L<IO::ScalarArray|IO::ScalarArray>,
and L<IO::Lines|IO::Lines>.

In the more-traditional IO::Handle front, we
have L<IO::AtomicFile|IO::AtomicFile>
which may be used to painlessly create files which are updated
atomically.

And in the "this-may-prove-useful" corner, we have L<IO::Wrap|IO::Wrap>,
whose exported wraphandle() function will clothe anything that's not
a blessed object in an IO::Handle-like wrapper... so you can just
use OO syntax and stop worrying about whether your function's caller
handed you a string, a globref, or a FileHandle.

=head1 AUTHOR

Eryq (F<eryq@zeegee.com>).
President, ZeeGee Software Inc (F<http://www.zeegee.com>).

=head1 CONTRIBUTORS

Dianne Skoll (F<dfs@roaringpenguin.com>).

=head1 COPYRIGHT & LICENSE

Copyright (c) 1997 Erik (Eryq) Dorfman, ZeeGee Software, Inc. All rights reserved.

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

=cut
PK�U%[�XH��doc/alt-libgd/CONTRIBUTORSnu�[���Ben Morss (morsssss)
chapg
Chen Pingping (Wilson)
Chris Reuter
Christoph M. Becker
Colin Watson
Dimitar Dobrev
edink
Gilles Espinasse
guenter
Kornel Lesiński
kshepherd
lhecking
Marcin Wojdyr
Martin Reboredo (YakoYakoYokuYoku)
mattias
Mike Frysinger
Mateusz Loskot (mloskot)
Nathanael Jones
nlopess
Ondřej Surý
Pierre Joye
pornel
Remi Collet
scottmac
tabe
Takeshi Abe
Tim Toohey
tostercx
Vincent Bernat
PK�U%[�z��doc/alt-libgd/README.TXTnu�[���For documentation, browse index.html.

Quick install guide:

If the sources have been fetched from git, run bootstrap.sh [options].

From a released source, use:
1. Type './configure'
2. Type 'make install'

Generic configuration instructions are in the file INSTALL.

The following 3rd-party libraries will be used by gd if found by configure.
While gd will compile and install even without these, we suggest that at
least zlib and libpng are installed, and recommend that freetype and jpeg
are installed as well:

1. zlib, available from http://www.gzip.org/zlib/
   Data compression library

2. libpng, available from http://www.libpng.org/pub/png/
   Portable Network Graphics library; requires zlib

3. FreeType 2.x, available from http://www.freetype.org/
   Free, high-quality, and portable font engine

4. JPEG library, available from http://www.ijg.org/
   Portable JPEG compression/decompression library
   jpeg-turbo is our recommended choise. version 2.x is required. It may build with earlier version however we do not support it (in case quality or other bugs could be seen).
   LibJpeg 6.2 required. It may compile with earlier version but we do not support it.

5. XPM, available from http://koala.ilog.fr/lehors/xpm.html
   X Pixmap library

If any of these libraries are installed, but not detected by configure,
you can use the following command line options:

--with-png=DIR

  Without the DIR argument, configure will check for png header files and
  libraries in a default location. To switch off png support, use
  --without-png, or --with-png=no.

  If the DIR argument is specified, configure tries to find the png header
  files in DIR/include, and the libraries in DIR/lib. To accommodate
  OpenBSD ports, DIR/include/libpng is also checked if necessary.

--with-freetype=DIR

  Dto. for freetype 2.x library. The search path for include files is
  DIR/include/freetype2.

--with-jpeg=DIR

  Dto. for jpeg library.

--with-xpm=DIR

  Dto. for xpm library.

 --with-tiff=DIR

Dto. for TIFF library.
PK�U%[�Y�$��doc/alt-libgd/COPYINGnu�[���Title: License
Credits and license terms:

In order to resolve any possible confusion regarding the authorship of
gd, the following copyright statement covers all of the authors who
have required such a statement. If you are aware of any oversights in
this copyright notice, please contact Pierre-A. Joye who will be
pleased to correct them.

* Portions copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
  2002, 2003, 2004 by Cold Spring Harbor Laboratory. Funded under
  Grant P41-RR02188 by the National Institutes of Health.

* Portions copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
  2004 by Boutell.Com, Inc.

* Portions relating to GD2 format copyright 1999, 2000, 2001, 2002,
  2003, 2004 Philip Warner.

* Portions relating to PNG copyright 1999, 2000, 2001, 2002, 2003,
  2004 Greg Roelofs.

* Portions relating to gdttf.c copyright 1999, 2000, 2001, 2002,
  2003, 2004 John Ellson (ellson@graphviz.org).

* Portions relating to gdft.c copyright 2001, 2002, 2003, 2004 John
  Ellson (ellson@graphviz.org).

* Portions copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
  2008 Pierre-Alain Joye (pierre@libgd.org).

* Portions relating to JPEG and to color quantization copyright
  2000, 2001, 2002, 2003, 2004, Doug Becker and copyright (C) 1994,
  1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 Thomas
  G. Lane. This software is based in part on the work of the
  Independent JPEG Group. See the file README-JPEG.TXT for more
  information.

* Portions relating to GIF compression copyright 1989 by Jef
  Poskanzer and David Rowley, with modifications for thread safety
  by Thomas Boutell.

* Portions relating to GIF decompression copyright 1990, 1991, 1993
  by David Koblas, with modifications for thread safety by Thomas
  Boutell.

* Portions relating to WBMP copyright 2000, 2001, 2002, 2003, 2004
  Maurice Szmurlo and Johan Van den Brande.

* Portions relating to GIF animations copyright 2004 Jaakko Hyvätti
  (jaakko.hyvatti@iki.fi)

Permission has been granted to copy, distribute and modify gd in
any context without fee, including a commercial application,
provided that this notice is present in user-accessible supporting
documentation.

This does not affect your ownership of the derived work itself,
and the intent is to assure proper credit for the authors of gd,
not to interfere with your productive use of gd. If you have
questions, ask. "Derived works" includes all programs that utilize
the library. Credit must be given in user-accessible
documentation.

This software is provided "AS IS." The copyright holders disclaim
all warranties, either express or implied, including but not
limited to implied warranties of merchantability and fitness for a
particular purpose, with respect to this code and accompanying
documentation.

Although their code does not appear in the current release, the
authors wish to thank David Koblas, David Rowley, and Hutchison
Avenue Software Corporation for their prior contributions.
PK�U%[i]�Ɂ� doc/alt-libgd/ChangeLog.historicnu�[���4d29684 CVE-2015-8874
fe199ed release gd-2.2.0
6556574 ChangeLog: update for gd-2.2 branching
c6c52b3 dist: drop bzip2 tarball
7932944 libtool: set revision based on package version
119b38e travis: switch to the local bootstrap script
f79d0a8 m4: use an older openmp macro
e6bf771 docs: clean up a bit and support `NaturalDocs`
c9a4a85 libimagequant: fix integration
6e054c4 gdlib-config: mark it as deprecated #140
b64c996 build: fix GDLIB_REVISION collision
10a4915 tests: rework handling of temp output files
1239832 configure/cmake: unify header checks and config.h generation
32c5072 bootstrap: switch to autoreconf
f7471f2 tests: add missing gdimagesetpixel tests
e59a0e8 tests: add missing test files to dist
2733b62 tga: cleanup/simplify a bit
96d5687 tga: fix two memory corruption bugs #159
8f50777 tests: get working under lsan (leak sanitizer)
e530663 png: fix some memory leaks w/invalid images
82b80dc gif: avoid out-of-bound reads of masks array #209
4dc1a2d xbm: avoid stack overflow (read) with large names #211
b083ec1 cmake: update build files to match autotools more
2db153a webpng: rewrite & cleanup to use getopt
b12f217 configure: enable -Werror by default when available
75c38f6 fix various gcc/clang warnings found with -Wall
8bdfede cmake: document the common build/install steps #179
6f3552d travis: drop multiarch settings
d549193 travis: drop nasm apt install
cd15d9b drop unused make_drone.io
b32324d travis: enable the clang compiler
05d70f6 tests: fix leaks in test code
4e61c9b tiff: fix leak in gdImageCreateFromTiffCtx()
658f168 gd2: fix double free when processing invalid headers
0315e44 tests: gd2: add general read test helpers #208
3c47bb4 tests: do not build libgdtest.a all the time
09d2d01 webp: fix double free
cd1d964 libgd: update & sort cmake installed headers #164
161ac24 travis: rework & improve main script logic
613e8c9 tests: split up makefile entries
92c3209 tests: fix distclean errors
3768c9e travis: switch to non-sudo mode
adc8598 tests: unify cmake test code into a single macro
ef9b000 build: handle renamed README file
e16310b libgd: update & sort source lists
a44e1ba tests: gdimageline: add missing -lm linkage
3b0eabf tests: add missing cmake files gdimagefile/gdimagefilter
4c6a07b gitignore: split up test entries
6455304 tests: drop EXTRA_PROGRAMS
982d488 revert... unneeded
a5b5c27 Fix memory leak
2bb97f4 gd2: handle corrupt images better (CVE-2016-3074)
fc14a8c README: document supported image formats
5277b6f Merge pull request #199 from mattbo/tiff_dpi_support
4e53ed7 Added support for reading and writing TIFFTAG_XRESOLUTION and TIFFTAG_YRESOLUTION.  Includes a unit test.
6913dd3 bmp: use double variant of ceil func
f29f7db Merge pull request #198 from sherif-elmetainy/master
e87ec88 :fix and unit test for crash issue in gdImageFillTiled
258dbf2 README: link to the CONTRIBUTORS file
6895576 README: reformat in markdown for better github display
73ab7c7 Merge pull request #182 from leoyanggit/fix_build_static
e08acb0 Merge pull request #153 from davidchappelle/master
78dad44 circletexttest: check image creation return value
a9346dd travis: build/check in parallel
e5d1e9d Fail Travis builds if make check fails
b6211d9 tests: fix build failures when jpeg/freetype are disabled
3667974 Merge pull request #193 from vapier/master
f732d74 Merge pull request #194 from jasonwilliams200OK/master
859bcf7 git,repo: Ignore build spew.
10a8761 Merge pull request #192 from jasonwilliams200OK/master
8f69034 code: Adds missing methods for absent libz case.
a4f5d5d configure: unify library tests
a9205e5 configure: require autoconf-2.64/automake-1.11
2e04a67 win: Use an external snprintf hook.
9104bba configure: use AS_HELP_STRING everywhere
1dc5280 Merge pull request #191 from jitendarKumar/patch-8
dd48286 Logical Operation && has no Impact on expression result .
52dad8b Update git ignore file to exclude cmake build directory
9ea3097 Prevent duplicate macro definition errors/warnings
40f42c0 Fix compiler warnings when checking interpolation_id
7147b64 Make BUILD_SHARED_LIBS configurable
4751b60 gdImageScaleTwoPass memory leak fix
4e1ce66 Merge pull request #166 from jitendarKumar/patch-5
1219113 Merge pull request #155 from jitendarKumar/patch-2
38e016f Merge pull request #156 from jitendarKumar/patch-3
4e70131 Merge pull request #157 from jitendarKumar/patch-4
895be03 Indentation corrected.
7b6261c Dereference null return value in gdtest.c
7297c94 Merge pull request #163 from wangkun611/webp_cmake
917fa11 fix CMake error when ENABLE_WEBP
7ec030c add gdImageCreateFromWebpPtr impl
eaca20f Remove Deadcode in gd.c
312b020 Update gd_topal.c
18bbbfa Merge pull request #148 from smcdow/master
f2712a6 Remove Deadcode in gd_nnquant.c
4f99667 Merge pull request #154 from jitendarKumar/patch-1
4cf5307 Missing nullcheck in gd_topal.c
d403501 Dereference null return value in gdfx.c
ac527e6 delete webpimg.c references
c9dac2d Fix segfault in gdImageFlipVertical() for non-TrueColor images.
a9f3a83 Merge pull request #146 from dmelani/rotation_fix
4e833d3 Added missing zero.
b12712e Merge pull request #143 from vapier/master
2618996 missing file in archive, need for autoreconf
6bdfa68 ignore new tests
1c33d94 tests: fix header inclusion
e0aafd0 Add Debian/Ubuntu M-A specific configure options
3a72f64 lint.travis-ci.org doesn't know version and description in Coverity addon
87804f6 Comment-out Coverity encrypted token
2b8bfd4 Don't fail when make check fails; Add coverity configuration for coverity_scan branch
10a92e7 Even more missing semicolons
09783e4 Add missing semicolons to .travis.yml
25cfac5 Replace <TAB> with 8*<SPACE>
2be44f0 Don't upgrade build environment now
5edbc3f Use autotools on linux to build libgd
9201900 Change issue tracker URL to github
ba081d9 Merge branch 'GD-2.1'
1481c41 fix #140, versions placeholder not replaced in gdlib-config
88fb8fc typo
4ef5903 fix some leaks on error
824a3aa remove remaining libvpx related code
a79232c fix #129, drop VPX usage in favor of libwebp
9a205a1 Merge branch 'GD-2.1'
511160e fix #82, fix 1 bit tiff support
7a567db Merge branch 'GD-2.1'
aa1d71c fix #135, fix logic in gdkanji
58990de Merge branch 'master' of https://bitbucket.org/libgd/gd-libgd
2f85291 fix #139, patch by Peter Breitenlohner
255a9e4 fix visibility test
358950c remove this test, too big
5c48b49 fix #91, actually add tests, bug already fixed
f680978 fix #94, HAVE_VISIBILITY may be defined but set to 0
b126726 fix #89, fix leaks on tiff read
acdebc8 fix #84, double free and overrun due to wrong alloc type, uint8_t instead of int
490bc3e free palette on error
289c829 port fix for saner boolean usage from https://reviews.facebook.net/D31695
2b3130e fix #90, actually copy src to dst
b1f4313 add tests for #111
3d7c3f5 fix #111, invalid quantization
ac1ff44 update results to match modern freetype builds
c7e5dc6  fix #111, invalid default quantization
81d341c fix #113, NULL deref in gdfx
2f40d52 Fix #138, VS 2010 build error due to double semi column
0e9c4e0 master is now 2.2.0-dev
06b2e4f back to dev
PK�h%[5��߸$�$!doc/alt-cyrus-sasl/LDAP_SASLAUTHDnu�[���auth_ldap module for saslauthd
------------------------------

Saslauthd can use an LDAP directory for authentication/authorization.

Sections:
1. Build saslauthd with ldap support
2. Start saslauthd with ldap
3. Testing
4. Parameters
5. Examples
6. Notes
7. Todo
8. Feedback
8. Author


1. BUILD SASLAUTHD WITH LDAP SUPPORT
------------------------------------

Ensure that you have the OpenLDAP (http://www.openldap.org) libraries 2.1 or
higher.  Fetch the latest cyrus-sasl package, 2.1.17 or higher,
ftp://ftp.andrew.cmu.edu/pub/cyrus-mail/.

Unpack cyrus-sasl:
gzip -dc cyrus-sasl-2.1.17.tar.gz | tar xf -
or
tar zxf cyrus-sasl-2.1.17.tar.gz (if your tar supportz gzip)

cd cyrus-sasl-2.1.17
./configure --with-ldap  (you may need to add other options, check doc/index.html for more)
make
make install


2. START SASLAUTHD WITH LDAP
----------------------------

Create /usr/local/etc/saslauthd.conf and add the following (modify to fit your
environment):
ldap_servers: ldap://10.1.1.15/ ldap://10.1.1.25/
ldap_bind_dn: cn=operator,ou=Profile,o=foo.com
ldap_password: secret

Do not specify ldap_bind_*/ldap_password if you want to bind anonymously to
your ldap server(s). 

Run saslauthd:
saslauthd -a ldap

If you want to specify a different configuration file, you can do something
like:
saslauthd -a ldap -O /etc/saslauthd.conf

For more command line options, check 'man saslauthd'


3. TESTING
----------

First build testsaslauthd:
cd $sasl_src/saslauthd
make testsaslauthd

Run test utility:
./testsaslauthd -u igor -p secret
0: OK "Success."

If you get output other then Success, turn debug level for the auth syslog
facility and check the syslog file.  Hopefully this will give you enough
information to make adjustements in the startup and/or configuration files.  


4. PARAMETERS
-------------

The following are available ldap parameters.  There are quite a few of those,
but only ldap_servers may need to be specified. The defaults for all other
parameters are adequate for most installations.  

Do not use quotes (\"\') in the parameter values.  The defaults are specified
within the first set of <>.  There may be a second set of <> which provide
available values.

ldap_auth_method: <bind|fastbind> <bind|custom|fastbind>
	Specify an authentication method.

    The bind method uses the LDAP bind facility to verify the password.  The
    bind method is not available when ldap_use_sasl is turned on.  In that case
    saslauthd will use fastbind.

    'bind' is the default auth method. When ldap_use_sasl is enabled,
    'fastbind' is the default.

    The custom method uses userPassword attribute to verify the password.
    Suppored hashes: crypt, md5, smd5, sha and ssha.  Cleartext is supported as
    well.

    The fastbind method (when 'ldap_use_sasl: no') does away with the search
    and an extra anonymous bind in auth_bind, but makes two assumptions:
	  1. Expanding the ldap_filter expression gives the user's fully-qualified DN
	  2. There is no cost to staying bound as a named user

ldap_bind_dn: <none>
	Specify DN (distinguished name) to bind to the LDAP directory.  Do not
	specify this parameter for the anonymous bind.

ldap_bind_pw: <none>
	Alias for ldap_password.

ldap_default_domain: <none>
	Alias for ldap_default_realm.

ldap_default_realm: <none>
	The default realm is assigned to the %r token when realm is not
	available.  See ldap_filter for more.

ldap_deref: <none> <search|find|always|never>
	Specify how aliases dereferencing is handled during search.

ldap_filter: <uid=%u>
	Specify a filter.  The following tokens can be used in the filter string:

	%%   = %
	%u   = user
	%U   = user portion of %u (%U = test when %u = test@domain.tld)
	%d   = domain portion of %u if available (%d = domain.tld when %u =
	       %test@domain.tld), otherwise same as %r
	%1-9 = domain tokens (%1 = tld, %2 = domain when %d = domain.tld)
	%s   = service
	%r   = realm
	%D   = user DN (available for group checks)
	
	The %u token has to be used at minimum for the filter to be useful.  If
	ldap_auth_method is 'bind', the filter will search for the DN
	(distinguished name) attribute.  Otherwise, the search will look for
	the 'ldap_password_attr' (see below) attribute.

ldap_group_attr: <uniqueMember>
    Specify what attribute to compare the user DN against in the group. If
    ldap_group_dn is not specified, this parameter is ignored.  If
    ldap_group_match_method is not attr, this parameter is ignored.
 
ldap_group_dn: <none>
    If specified, the user has to be part of the group in order to authenticate
    successfully.  Tokens described in 'ldap_filter' (see above) can be used
    for substitution.

ldap_group_filter: <none>
    Specify a filter. If a filter match is found then the user is in the group.
    Tokens described in 'ldap_filter' (see above) can be used for for
    substitution. If ldap_group_dn is not specified, this parameter is ignored.
    If ldap_group_match_method is not filter, this parameter is ignored.

ldap_group_match_method: <attr> <attr|filter>
    Specify whether the group match method uses ldap_group_attr or
    ldap_group_search.  If ldap_group_dn is not specified, this parameter is
    ignored.

ldap_group_search_base: <if not specified, it defaults to ldap_search_base>
    Specify a starting point for the group search: e.g. dc=foo,dc=com.  Tokens
    described in 'ldap_filter' (see below) can be used for substitution.

ldap_group_scope: <sub> <sub|one|base>
	Group search scope.

ldap_password: <none>
	Specify the password for ldap_bind_dn or ldap_id if
	ldap_use_sasl is turned on.  Do not specify this parameter for the
	anonymous bind.

ldap_password_attr: <userPassword>
        Specify what password attribute to use for password verification.
 
ldap_referrals: <no>
	Specify whether or not the client should follow referrals.

ldap_restart: <yes>
	Specify whether or not LDAP I/O operations are automatically restarted
	if they abort prematurely.

ldap_id: <none>
	Specify the authentication ID for SASL bind.

ldap_authz_id: <none>
	Specify the proxy authorization ID for SASL bind.

ldap_mech: <none>
	Specify the authentication mechanism for SASL bind.

ldap_realm: <none>
	Specify the realm of authentication ID for SASL bind.

ldap_scope: <sub> <sub|one|base>
	Search scope.

ldap_search_base: <none>
	Specify a starting point for the search: e.g. dc=foo,dc=com.  Tokens
	described in 'ldap_filter' (see below) can be used for substitution.

ldap_servers: <ldap://localhost/>
	Specify URI(s) refering to LDAP server(s), e.g. ldaps://10.1.1.2:999/.
	You can specify multiple servers separated by a space.

ldap_start_tls: <no>
	Use StartTLS extended operation.  Do not use ldaps: ldap_servers when
	this option is turned on.

ldap_time_limit: <5>
	Specify a number of seconds for a search request to complete.

ldap_timeout: <5>
	Specify a number of seconds a search can take before timing out.

ldap_tls_check_peer: <no> <yes|no>
	Require and verify server certificate.  If this option is yes,
	you must specify ldap_tls_cacert_file or ldap_tls_cacert_dir.

ldap_tls_cacert_file: <none>
	File containing CA (Certificate Authority) certificate(s).

ldap_tls_cacert_dir: <none>
	Path to directory with CA (Certificate Authority) certificates.

ldap_tls_ciphers: <DEFAULT>
	List of SSL/TLS ciphers to allow.  The format of the string is
	described in ciphers(1).

ldap_tls_cert: <none>
	File containing the client certificate.

ldap_tls_key: <none>
	File containing the private client key.

ldap_use_sasl: <no>
	Use SASL bind rather than simple bind when connecting to the ldap
	server.

ldap_version: <3> <2|3>
	Specify the LDAP protocol version.  If ldap_start_tls and/or
	ldap_use_sasl are enabled, ldap_version will be automatiacally set to
	3.

5. NOTES
--------

For better performance ensure that the attributes specified in ldap_filter are
indexed.

My testing shows that 'custom' is 2-3 times faster than 'bind'
ldap_auth_method.  The 'fastbind' auth_method is just as fast or faster.  The
slower performace of the 'bind' auth_method is caused by two extra calls to
ldap_bind() per each authentication.

SASL bind should be used with the 'fastbind' auth_method:

ldap_servers: ldaps://10.1.1.2/
ldap_use_sasl: yes
ldap_mech: DIGEST_MD5
ldap_auth_method: fastbind

At this time this is not the best performing solution because openldap (2.1.x)
cannot reuse existing connection for multiple ldap_sasl_bind()s.  This will
hopefully change when openldap 2.2 comes out.

6. TODO
-------

- Port to other ldap libraries
- There may be bind problems when following referrals.  Normally this is not an
  issue.
- Allow to specify an attribute other than userPassword for use in the custom
  authentication method. (Done)
- Add more password hashes such as md5, sha etc (Done)
- Make a suggestion (possibly another authentication method?) (added fastbind)
  thanks to Simon Brady <simon.brady@otago.ac.nz>


7. FEEDBACK
-----------

Feedback is much appreciated!  Please drop me a note if you are successfully
using ldap-enabled saslauthd.  Any code improvements and/or suggestion are welcome.

If you have questions, send email to cyrus-sasl@lists.andrew.cmu.edu.  Please
include relevant information about your saslauthd setup: at minimum provide
your saslauth.conf, output from syslog and which directory server you're using.


8. AUTHOR
---------

Igor Brezac <igor@ipass.net>.
PK�h%[�|8�8�"doc/alt-cyrus-sasl-lib/search.htmlnu�[���

<!DOCTYPE html>
<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
<head>
  <meta charset="utf-8">
  
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  
  <title>Search &mdash; Cyrus SASL 2.1.27 documentation</title>
  

  
  
    <link rel="shortcut icon" href="_static/favicon.ico"/>
  

  

  
  
    

  

  
  
    <link rel="stylesheet" href="_static/css/theme.css" type="text/css" />
  

  
    <link rel="stylesheet" href="_static/cyrus.css" type="text/css" />
  

  
        <link rel="index" title="Index"
              href="genindex.html"/>
        <link rel="search" title="Search" href="#"/>
    <link rel="top" title="Cyrus SASL 2.1.27 documentation" href="index.html"/> 

  
  
  

</head>

<body class="wy-body-for-nav" role="document">

  
  
<div class="pageheader">
  <ul>
    <li><a href="index.html">Home</a></li>
    <li><a href="http://www.cyrusimap.org">Cyrus IMAP</a></li>
    <li><a href="download.html">Download</a></li>
    <li><a href="contribute.html">Contribute</a></li>
  </ul>
  <div>
    <a href="index.html">
      <img src="_static/logo.gif" alt="CYRUS SASL" />
    </a>
  </div>
</div>
<div style="clear: both;"></div>


  <div class="wy-grid-for-nav">

    
    <nav data-toggle="wy-nav-shift" class="wy-nav-side">
      <div class="wy-side-nav-search">
        

        
 
          <a href="index.html">
 

  
          
          <img src="_static/logo.gif"  />
     
        </a>

        
<div role="search">
  <form id="rtd-search-form" class="wy-form" action="#" method="get">
    <input type="text" name="q" placeholder="Search docs" />
    <input type="hidden" name="check_keywords" value="yes" />
    <input type="hidden" name="area" value="default" />
  </form>
</div>

        
      </div>

      <div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
        
          
          
              <p class="caption"><span class="caption-text">Cyrus SASL</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="download.html">Download</a><ul>
<li class="toctree-l2"><a class="reference internal" href="getsasl.html">Get SASL</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html">Installation</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#quick-install-guide">Quick install guide</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#detailed-installation-guide">Detailed installation guide</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#supported-platforms">Supported platforms</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/release-notes/index.html">Release Notes</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/release-notes/index.html#supported-product-series">Supported Product Series</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/release-notes/index.html#series-2-1">Series 2.1</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/release-notes/index.html#older-versions">Older Versions</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/release-notes/index.html#series-2-2-0">Series 2: 2.0</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/release-notes/index.html#series-1">Series 1</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="packager.html">Note for Packagers</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="sasl/quickstart.html">Quickstart guide</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/quickstart.html#features">Features</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/quickstart.html#typical-installation">Typical Installation</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/quickstart.html#configuration">Configuration</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="sasl/concepts.html">Concepts</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#sasl">SASL</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#sasl-authentication-mechanisms">SASL Authentication Mechanisms</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#security-layers">Security Layers</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#channel-binding">Channel Binding</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#realms">Realms</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#protocols">Protocols</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#cyrus-sasl">Cyrus SASL</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#the-glue-library">The Glue Library</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#auxiliary-properties">Auxiliary Properties</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#plugins">Plugins</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="setup.html">Setup</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/installation.html">Installation</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html#quick-install-guide">Quick install guide</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#tarball-installation">Tarball installation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#unix-package-installation">Unix package Installation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#configuration">Configuration</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html#detailed-installation-guide">Detailed installation guide</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#requirements">Requirements</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#build-configuration">Build Configuration</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#building-and-installation">Building and Installation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#compilation-hints">Compilation Hints</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#application-configuration">Application Configuration</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html#supported-platforms">Supported platforms</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/upgrading.html">Upgrading from v1 to v2</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/upgrading.html#backwards-compatibility">Backwards Compatibility</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/upgrading.html#coexistence-with-saslv1">Coexistence with SASLv1</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/upgrading.html#database-upgrades">Database Upgrades</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/upgrading.html#errors-on-migration">Errors on migration</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/components.html">Components</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/components.html#the-application">The Application</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/components.html#the-sasl-glue-layer">The SASL Glue Layer</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/components.html#plugins">Plugins</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/components.html#plugins-general">Plugins: General</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/components.html#plugins-sasl-mechanisms">Plugins: SASL Mechanisms</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/components.html#plugins-auxiliary-property">Plugins: Auxiliary Property</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/components.html#plugins-username-canonicalization">Plugins: Username Canonicalization</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/components.html#password-verification-services">Password Verification Services</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/options.html">Options</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#sasl-library">SASL Library</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#auxiliary-property-plugin">Auxiliary Property Plugin</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#gssapi">GSSAPI</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#ldapdb">LDAPDB</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/options.html#notes-on-ldapdb">Notes on LDAPDB</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/options.html#examples">Examples</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#ntlm">NTLM</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#otp">OTP</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#digest-md5">Digest-md5</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#sasldb">SASLDB</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/options.html#notes-on-sasldb-with-lmdb">Notes on sasldb with LMDB</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#sql-plugin">SQL Plugin</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/options.html#notes-on-sql">Notes on SQL</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/options.html#id2">Examples</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#srp">SRP</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#kerberos-v4">Kerberos V4</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/advanced.html">Advanced Usage</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/advanced.html#notes-for-advanced-usage-of-libsasl">Notes for Advanced Usage of libsasl</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/advanced.html#using-cyrus-sasl-as-a-static-library">Using Cyrus SASL as a static library</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="operations.html">Operations</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/sysadmin.html">System Administrators</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#what-sasl-is">What SASL is</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#authentication-and-authorization-identifiers">Authentication and authorization identifiers</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#realms">Realms</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#how-sasl-works">How SASL works</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#the-plain-mechanism-sasl-checkpass-and-plaintext-passwords">The PLAIN mechanism, <code class="docutils literal"><span class="pre">sasl_checkpass()</span></code>, and plaintext passwords</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#shared-secrets-mechanisms">Shared secrets mechanisms</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#kerberos-mechanisms">Kerberos mechanisms</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#the-otp-mechanism">The OTP mechanism</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#auxiliary-properties">Auxiliary Properties</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#how-to-set-configuration-options">How to set configuration options</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#the-default-configuration-file">The default configuration file</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#application-configuration">Application configuration</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#troubleshooting">Troubleshooting</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/manpages.html">Man pages</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/manpages.html#library-files">(3) Library Files</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl.html"><strong>SASL</strong> - SASL Authentication Library</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_authorize_t.html"><strong>sasl_authorize_t</strong> - The SASL authorization callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_auxprop.html"><strong>sasl_auxprop</strong> - How to work with SASL auxiliary properties</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_auxprop_add_plugin.html"><strong>sasl_auxprop_add_plugin</strong> - add a SASL auxiliary property plugin</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_auxprop_getctx.html"><strong>sasl_auxprop_getctx</strong> - Acquire an auxiliary property context</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_auxprop_request.html"><strong>sasl_auxprop_request</strong> - Request auxiliary properties from SASL</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_callbacks.html"><strong>sasl_callbacks</strong> - How to work with SASL callbacks</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_canon_user_t.html"><strong>sasl_canon_user_t</strong> - Application-supplied user canonicalization function</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_canonuser_add_plugin.html"><strong>sasl_canonuser_add_plugin</strong> - add a SASL user canonicalization plugin</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_chalprompt_t.html"><strong>sasl_chalprompt_t</strong> - Realm acquisition callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_checkapop.html"><strong>sasl_checkapop</strong> - Check an APOP challenge/response</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_checkpass.html"><strong>sasl_checkpass</strong> - Check a plaintext password</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_add_plugin.html"><strong>sasl_client_add_plugin</strong> - add a SASL client plugin</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_done.html"><strong>sasl_client_done</strong> - Cleanup function</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_init.html"><strong>sasl_client_init</strong> - SASL client authentication initialization</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_new.html"><strong>sasl_client_new</strong> - Create a new client authentication object</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_plug_init_t.html"><strong>sasl_client_plug_init_t</strong> - client plug‐in entry point</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_start.html"><strong>sasl_client_start</strong> - Begin an authentication negotiation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_step.html"><strong>sasl_client_step</strong> - Perform a step in the authentication negotiation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_decode.html"><strong>sasl_decode</strong> - Decode data received</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_decode64.html"><strong>sasl_decode64</strong> - Decode base64 string</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_dispose.html"><strong>sasl_dispose</strong> - Dispose of a SASL connection object</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_done.html"><strong>sasl_done</strong> - Dispose of a SASL connection object</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_encode.html"><strong>sasl_encode</strong> - Encode data for transport to authenticated host</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_encode64.html"><strong>sasl_encode64</strong> - Encode base64 string</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_encodev.html"><strong>sasl_encodev</strong> - Encode data for transport to authenticated host</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_erasebuffer.html"><strong>sasl_erasebuffer</strong> - erase buffer</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_errdetail.html"><strong>sasl_errdetail</strong> - Retrieve  detailed information about an error</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_errors.html"><strong>sasl_errors</strong> - SASL error codes</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_errstring.html"><strong>sasl_errstring</strong> - Translate a SASL return code to a human-readable form</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getcallback_t.html"><strong>sasl_getcallback_t</strong> - callback function to lookup a sasl_callback_t for a connection</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getconfpath_t.html"><strong>sasl_getconfpath_t</strong> - The SASL callback to indicate location of the config files</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getopt_t.html"><strong>sasl_getopt_t</strong> - The SASL get option callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getpath_t.html"><strong>sasl_getpath_t</strong> - The SASL callback to indicate location of the mechanism drivers</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getprop.html"><strong>sasl_getprop</strong> - Get a SASL property</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getrealm_t.html"><strong>sasl_getrealm_t</strong> - Realm Acquisition Callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getsecret_t.html"><strong>sasl_getsecret_t</strong> - The SASL callback for secrets (passwords)</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getsimple_t.html"><strong>sasl_getsimple_t</strong> - The SASL callback for username/authname/realm</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_global_listmech.html"><strong>sasl_global_listmech</strong> - Retrieve a list of the supported SASL mechanisms</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_idle.html"><strong>sasl_idle</strong> - Perform precalculations during an idle period</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_listmech.html"><strong>sasl_listmech</strong> - Retrieve a list of the supported SASL mechanisms</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_log_t.html"><strong>sasl_log_t</strong> - The SASL logging callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_add_plugin.html"><strong>sasl_server_add_plugin</strong> - add a SASL server plugin</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_done.html"><strong>sasl_server_done</strong> - Cleanup function</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_init.html"><strong>sasl_server_init</strong> - SASL server authentication initialization</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_new.html"><strong>sasl_server_new</strong> - Create a new server authentication object</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_plug_init_t.html"><strong>sasl_server_plug_init_t</strong> - server plug‐in entry point</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_start.html"><strong>sasl_server_start</strong> - Begin an authentication negotiation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_step.html"><strong>sasl_server_step</strong> - Perform a step in the authentication negotiation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_userdb_checkpass_t.html"><strong>sasl_server_userdb_checkpass_t</strong> - Plaintext Password Verification Callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_userdb_setpass_t.html"><strong>sasl_server_userdb_setpass_t</strong> - UserDB Plaintext Password Setting Callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_set_alloc.html"><strong>sasl_set_alloc</strong> - set the memory allocation functions used by the SASL library</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_set_mutex.html"><strong>sasl_set_mutex</strong> - set the mutex lock functions used by the SASL library</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_seterror.html"><strong>sasl_seterror</strong> - set the error string</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_setpass.html"><strong>sasl_setpass</strong> - Check a plaintext password</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_setprop.html"><strong>sasl_setprop</strong> - Set a SASL property</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_user_exists.html"><strong>sasl_user_exists</strong> - Check if a user exists on server</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_usererr.html"><strong>sasl_usererr</strong> - Remove information leak about accounts from sasl error codes</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_utf8verify.html"><strong>sasl_utf8verify</strong> - Verify a string is valid utf8</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_verifyfile_t.html"><strong>sasl_verifyfile_t</strong> - The SASL file verification</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/auxiliary_properties.html">Auxiliary Properties</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#auxiliary-properties-and-the-glue-layer">Auxiliary Properties and the Glue Layer</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#passwords-and-other-data">Passwords and other Data</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#sasldb">sasldb</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#ldapdb">ldapdb</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#sql">sql</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#user-canonicalization">User Canonicalization</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/authentication_mechanisms.html">Authentication Mechanisms</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/authentication_mechanisms.html#mechanisms">Mechanisms</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#anonymous">ANONYMOUS</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#cram-md5">CRAM-MD5</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#digest-md5">DIGEST-MD5</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#external">EXTERNAL</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#g2">G2</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#gssapi">GSSAPI</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#gss-spegno">GSS-SPEGNO</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#kerberos-v4">KERBEROS_V4</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#login">LOGIN</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#ntlm">NTLM</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#otp">OTP</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#passdss">PASSDSS</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#plain">PLAIN</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#scram">SCRAM</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#srp">SRP</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#non-sasl-authentication">Non-SASL Authentication</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/authentication_mechanisms.html#summary">Summary</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/pwcheck.html">Pwcheck</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#auxprop">Auxprop</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#auxprop-hashed">Auxprop-hashed</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#saslauthd">Saslauthd</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#authdaemon">Authdaemon</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#alwaystrue">Alwaystrue</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#auto-transition">Auto Transition</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/faq.html">Frequently Asked Questions</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/authorize-vs-authenticate.html">What is the difference between an Authorization ID and a Authentication ID?</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/crammd5-digestmd5.html">Why do CRAM-MD5 and DIGEST-MD5 not work with CyrusSaslauthd?</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/openldap-sasl-gssapi.html">How do I configure OpenLDAP +SASL+GSSAPI?</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/plaintextpasswords.html">Why does CyrusSasl store plaintext passwords in its databases?</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/rfcs.html">RFCs and drafts</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/upgrade-saslv2.html">Why am I having a problem running dbconverter-2 to upgrade from SASLv1 to SASLv2?</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/resources.html">Other Documentation &amp; Resources</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="developer.html">Developers</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/appconvert.html">Converting Applications from v1 to v2</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/appconvert.html#tips-for-both-clients-and-servers">Tips for both clients and servers</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/appconvert.html#tips-for-clients">Tips for clients</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/appconvert.html#tips-for-servers">Tips for Servers</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/developer/programming.html">Application Programmer’s Guide</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#introduction">Introduction</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#about-this-guide">About this Guide</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#what-is-sasl">What is SASL?</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#background">Background</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#how-did-the-world-work-before-sasl">How did the world work before SASL?</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#sasl-to-the-rescue">SASL to the rescue!</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#briefly">Briefly</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#what-is-the-cyrus-sasl-library-good-for">What is the Cyrus SASL library good for?</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#what-does-the-cyrus-sasl-library-do">What does the Cyrus SASL library do?</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#what-doesn-t-the-cyrus-sasl-library-do">What doesn’t the Cyrus SASL library do?</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#client-only-section">Client-only Section</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#a-typical-interaction-from-the-client-s-perspective">A typical interaction from the client’s perspective</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#how-does-this-look-in-code">How does this look in code</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#server-only-section">Server-only Section</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#a-typical-interaction-from-the-server-s-perspective">A typical interaction from the server’s perspective</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#id1">How does this look in code?</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#common-section">Common Section</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#callbacks-and-interactions">Callbacks and Interactions</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#security-layers">Security layers</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#example-applications-that-come-with-the-cyrus-sasl-library">Example applications that come with the Cyrus SASL library</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#sample-client-and-sample-server"><cite>sample-client</cite> and <cite>sample-server</cite></a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#cyrus-imapd-v2-1-0-or-later">Cyrus imapd v2.1.0 or later</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#imtest-from-cyrus-2-1-0-or-later"><cite>imtest</cite>, from Cyrus 2.1.0 or later</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#miscellaneous-information">Miscellaneous Information</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#empty-exchanges">Empty exchanges</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#idle">Idle</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/developer/plugprog.html">Plugin Programmer’s Guide</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#introduction">Introduction</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#about-this-guide">About this Guide</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#what-is-sasl">What is SASL?</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#common-section">Common Section</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#overview-of-plugin-programming">Overview of Plugin Programming</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#use-of-sasl-utils-t">Use of sasl_utils_t</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#error-reporting">Error Reporting</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#memory-allocation">Memory Allocation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#client-send-first-server-send-last">Client Send First / Server Send Last</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#client-plugins">Client Plugins</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#server-plugins">Server Plugins</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#user-canonicalization-canon-user-plugins">User Canonicalization (canon_user) Plugins</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#auxiliary-property-auxprop-plugins">Auxiliary Property (auxprop) Plugins</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/developer/testing.html">Testing</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/testing.html#testing-the-cmu-sasl-library-with-the-included-sample-applications">Testing the CMU SASL Library with the included sample applications</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/testing.html#example">Example</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/testing.html#running-the-testsuite-application">Running the Testsuite application</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="support.html">Support/Community</a></li>
</ul>
<p class="caption"><span class="caption-text">IMAP</span></p>
<ul>
<li class="toctree-l1"><a class="reference external" href="http://www.cyrusimap.org">Cyrus IMAP</a></li>
</ul>

          
        
      </div>
      &nbsp;
    </nav>

    <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">

      
      <nav class="wy-nav-top" role="navigation" aria-label="top navigation">
        <i data-toggle="wy-nav-top" class="fa fa-bars"></i>
        <a href="index.html">Cyrus SASL</a>
      </nav>


      
      <div class="wy-nav-content">
        <div class="rst-content">
          
          <div role="navigation" aria-label="breadcrumbs navigation">
  <ul class="wy-breadcrumbs">
      <li><a href="index.html">Docs v2.1.27</a> &raquo;</li>
      
    <li>Search</li>
      <li class="wy-breadcrumbs-aside">
        
      </li>
  </ul>
  <hr/>
</div>
          <div role="main" class="document">
            
  <noscript>
  <div id="fallback" class="admonition warning">
    <p class="last">
      Please activate JavaScript to enable the search
      functionality.
    </p>
  </div>
  </noscript>

  
  <div id="search-results">
  
  </div>

          </div>
          <footer>
  

  <hr/>

  <div role="contentinfo">
    <p>
        &copy; Copyright 1993-2016, The Cyrus Team.
    </p>
  </div>
  Built with <a href="http://sphinx-doc.org/">Sphinx</a> 1.6.6 using a modified <a href="https://readthedocs.org">Read the Docs</a> <a href="https://github.com/snide/sphinx_rtd_theme">theme</a>.

</footer>

        </div>
      </div>

    </section>

  </div>
  


  

    <script type="text/javascript">
        var DOCUMENTATION_OPTIONS = {
            URL_ROOT:'./',
            VERSION:'2.1.27',
            COLLAPSE_INDEX:false,
            FILE_SUFFIX:'.html',
            HAS_SOURCE:  true
        };
    </script>
      <script type="text/javascript" src="_static/jquery.js"></script>
      <script type="text/javascript" src="_static/underscore.js"></script>
      <script type="text/javascript" src="_static/doctools.js"></script>
      <script type="text/javascript" src="https://cdn.mathjax.org/mathjax/latest/MathJax.js"></script>
      <script type="text/javascript" src="_static/searchtools.js"></script>

  

  
  
    <script type="text/javascript" src="_static/js/theme.js"></script>
  

  
  
  <script type="text/javascript">
<!--      jQuery(function () {
          SphinxRtdTheme.StickyNav.enable();
      }); -->
  </script>
  
  <script type="text/javascript">
    jQuery(function() { Search.loadIndex("searchindex.js"); });
  </script>
  
  <script type="text/javascript" id="searchindexloader"></script>
  
 




</body>
</html>PK�h%[ �r�r�&doc/alt-cyrus-sasl-lib/operations.htmlnu�[���

<!DOCTYPE html>
<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
<head>
  <meta charset="utf-8">
  
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  
  <title>Operations &mdash; Cyrus SASL 2.1.27 documentation</title>
  

  
  
    <link rel="shortcut icon" href="_static/favicon.ico"/>
  

  

  
  
    

  

  
  
    <link rel="stylesheet" href="_static/css/theme.css" type="text/css" />
  

  
    <link rel="stylesheet" href="_static/cyrus.css" type="text/css" />
  

  
        <link rel="index" title="Index"
              href="genindex.html"/>
        <link rel="search" title="Search" href="search.html"/>
    <link rel="top" title="Cyrus SASL 2.1.27 documentation" href="index.html"/>
        <link rel="next" title="System Administrators" href="sasl/sysadmin.html"/>
        <link rel="prev" title="Advanced Usage" href="sasl/advanced.html"/> 

  
  
  

</head>

<body class="wy-body-for-nav" role="document">

  
  
<div class="pageheader">
  <ul>
    <li><a href="index.html">Home</a></li>
    <li><a href="http://www.cyrusimap.org">Cyrus IMAP</a></li>
    <li><a href="download.html">Download</a></li>
    <li><a href="contribute.html">Contribute</a></li>
  </ul>
  <div>
    <a href="index.html">
      <img src="_static/logo.gif" alt="CYRUS SASL" />
    </a>
  </div>
</div>
<div style="clear: both;"></div>


  <div class="wy-grid-for-nav">

    
    <nav data-toggle="wy-nav-shift" class="wy-nav-side">
      <div class="wy-side-nav-search">
        

        
 
          <a href="index.html">
 

  
          
          <img src="_static/logo.gif"  />
     
        </a>

        
<div role="search">
  <form id="rtd-search-form" class="wy-form" action="search.html" method="get">
    <input type="text" name="q" placeholder="Search docs" />
    <input type="hidden" name="check_keywords" value="yes" />
    <input type="hidden" name="area" value="default" />
  </form>
</div>

        
      </div>

      <div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
        
          
          
              <p class="caption"><span class="caption-text">Cyrus SASL</span></p>
<ul class="current">
<li class="toctree-l1"><a class="reference internal" href="download.html">Download</a><ul>
<li class="toctree-l2"><a class="reference internal" href="getsasl.html">Get SASL</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html">Installation</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#quick-install-guide">Quick install guide</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#detailed-installation-guide">Detailed installation guide</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#supported-platforms">Supported platforms</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/release-notes/index.html">Release Notes</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/release-notes/index.html#supported-product-series">Supported Product Series</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/release-notes/index.html#series-2-1">Series 2.1</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/release-notes/index.html#older-versions">Older Versions</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/release-notes/index.html#series-2-2-0">Series 2: 2.0</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/release-notes/index.html#series-1">Series 1</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="packager.html">Note for Packagers</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="sasl/quickstart.html">Quickstart guide</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/quickstart.html#features">Features</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/quickstart.html#typical-installation">Typical Installation</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/quickstart.html#configuration">Configuration</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="sasl/concepts.html">Concepts</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#sasl">SASL</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#sasl-authentication-mechanisms">SASL Authentication Mechanisms</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#security-layers">Security Layers</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#channel-binding">Channel Binding</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#realms">Realms</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#protocols">Protocols</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#cyrus-sasl">Cyrus SASL</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#the-glue-library">The Glue Library</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#auxiliary-properties">Auxiliary Properties</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#plugins">Plugins</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="setup.html">Setup</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/installation.html">Installation</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html#quick-install-guide">Quick install guide</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#tarball-installation">Tarball installation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#unix-package-installation">Unix package Installation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#configuration">Configuration</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html#detailed-installation-guide">Detailed installation guide</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#requirements">Requirements</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#build-configuration">Build Configuration</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#building-and-installation">Building and Installation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#compilation-hints">Compilation Hints</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#application-configuration">Application Configuration</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html#supported-platforms">Supported platforms</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/upgrading.html">Upgrading from v1 to v2</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/upgrading.html#backwards-compatibility">Backwards Compatibility</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/upgrading.html#coexistence-with-saslv1">Coexistence with SASLv1</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/upgrading.html#database-upgrades">Database Upgrades</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/upgrading.html#errors-on-migration">Errors on migration</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/components.html">Components</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/components.html#the-application">The Application</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/components.html#the-sasl-glue-layer">The SASL Glue Layer</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/components.html#plugins">Plugins</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/components.html#plugins-general">Plugins: General</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/components.html#plugins-sasl-mechanisms">Plugins: SASL Mechanisms</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/components.html#plugins-auxiliary-property">Plugins: Auxiliary Property</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/components.html#plugins-username-canonicalization">Plugins: Username Canonicalization</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/components.html#password-verification-services">Password Verification Services</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/options.html">Options</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#sasl-library">SASL Library</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#auxiliary-property-plugin">Auxiliary Property Plugin</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#gssapi">GSSAPI</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#ldapdb">LDAPDB</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/options.html#notes-on-ldapdb">Notes on LDAPDB</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/options.html#examples">Examples</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#ntlm">NTLM</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#otp">OTP</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#digest-md5">Digest-md5</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#sasldb">SASLDB</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/options.html#notes-on-sasldb-with-lmdb">Notes on sasldb with LMDB</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#sql-plugin">SQL Plugin</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/options.html#notes-on-sql">Notes on SQL</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/options.html#id2">Examples</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#srp">SRP</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#kerberos-v4">Kerberos V4</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/advanced.html">Advanced Usage</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/advanced.html#notes-for-advanced-usage-of-libsasl">Notes for Advanced Usage of libsasl</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/advanced.html#using-cyrus-sasl-as-a-static-library">Using Cyrus SASL as a static library</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l1 current"><a class="current reference internal" href="#">Operations</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/sysadmin.html">System Administrators</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#what-sasl-is">What SASL is</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#authentication-and-authorization-identifiers">Authentication and authorization identifiers</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#realms">Realms</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#how-sasl-works">How SASL works</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#the-plain-mechanism-sasl-checkpass-and-plaintext-passwords">The PLAIN mechanism, <code class="docutils literal"><span class="pre">sasl_checkpass()</span></code>, and plaintext passwords</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#shared-secrets-mechanisms">Shared secrets mechanisms</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#kerberos-mechanisms">Kerberos mechanisms</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#the-otp-mechanism">The OTP mechanism</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#auxiliary-properties">Auxiliary Properties</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#how-to-set-configuration-options">How to set configuration options</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#the-default-configuration-file">The default configuration file</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#application-configuration">Application configuration</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#troubleshooting">Troubleshooting</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/manpages.html">Man pages</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/manpages.html#library-files">(3) Library Files</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl.html"><strong>SASL</strong> - SASL Authentication Library</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_authorize_t.html"><strong>sasl_authorize_t</strong> - The SASL authorization callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_auxprop.html"><strong>sasl_auxprop</strong> - How to work with SASL auxiliary properties</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_auxprop_add_plugin.html"><strong>sasl_auxprop_add_plugin</strong> - add a SASL auxiliary property plugin</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_auxprop_getctx.html"><strong>sasl_auxprop_getctx</strong> - Acquire an auxiliary property context</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_auxprop_request.html"><strong>sasl_auxprop_request</strong> - Request auxiliary properties from SASL</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_callbacks.html"><strong>sasl_callbacks</strong> - How to work with SASL callbacks</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_canon_user_t.html"><strong>sasl_canon_user_t</strong> - Application-supplied user canonicalization function</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_canonuser_add_plugin.html"><strong>sasl_canonuser_add_plugin</strong> - add a SASL user canonicalization plugin</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_chalprompt_t.html"><strong>sasl_chalprompt_t</strong> - Realm acquisition callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_checkapop.html"><strong>sasl_checkapop</strong> - Check an APOP challenge/response</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_checkpass.html"><strong>sasl_checkpass</strong> - Check a plaintext password</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_add_plugin.html"><strong>sasl_client_add_plugin</strong> - add a SASL client plugin</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_done.html"><strong>sasl_client_done</strong> - Cleanup function</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_init.html"><strong>sasl_client_init</strong> - SASL client authentication initialization</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_new.html"><strong>sasl_client_new</strong> - Create a new client authentication object</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_plug_init_t.html"><strong>sasl_client_plug_init_t</strong> - client plug‐in entry point</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_start.html"><strong>sasl_client_start</strong> - Begin an authentication negotiation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_step.html"><strong>sasl_client_step</strong> - Perform a step in the authentication negotiation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_decode.html"><strong>sasl_decode</strong> - Decode data received</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_decode64.html"><strong>sasl_decode64</strong> - Decode base64 string</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_dispose.html"><strong>sasl_dispose</strong> - Dispose of a SASL connection object</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_done.html"><strong>sasl_done</strong> - Dispose of a SASL connection object</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_encode.html"><strong>sasl_encode</strong> - Encode data for transport to authenticated host</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_encode64.html"><strong>sasl_encode64</strong> - Encode base64 string</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_encodev.html"><strong>sasl_encodev</strong> - Encode data for transport to authenticated host</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_erasebuffer.html"><strong>sasl_erasebuffer</strong> - erase buffer</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_errdetail.html"><strong>sasl_errdetail</strong> - Retrieve  detailed information about an error</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_errors.html"><strong>sasl_errors</strong> - SASL error codes</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_errstring.html"><strong>sasl_errstring</strong> - Translate a SASL return code to a human-readable form</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getcallback_t.html"><strong>sasl_getcallback_t</strong> - callback function to lookup a sasl_callback_t for a connection</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getconfpath_t.html"><strong>sasl_getconfpath_t</strong> - The SASL callback to indicate location of the config files</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getopt_t.html"><strong>sasl_getopt_t</strong> - The SASL get option callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getpath_t.html"><strong>sasl_getpath_t</strong> - The SASL callback to indicate location of the mechanism drivers</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getprop.html"><strong>sasl_getprop</strong> - Get a SASL property</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getrealm_t.html"><strong>sasl_getrealm_t</strong> - Realm Acquisition Callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getsecret_t.html"><strong>sasl_getsecret_t</strong> - The SASL callback for secrets (passwords)</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getsimple_t.html"><strong>sasl_getsimple_t</strong> - The SASL callback for username/authname/realm</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_global_listmech.html"><strong>sasl_global_listmech</strong> - Retrieve a list of the supported SASL mechanisms</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_idle.html"><strong>sasl_idle</strong> - Perform precalculations during an idle period</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_listmech.html"><strong>sasl_listmech</strong> - Retrieve a list of the supported SASL mechanisms</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_log_t.html"><strong>sasl_log_t</strong> - The SASL logging callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_add_plugin.html"><strong>sasl_server_add_plugin</strong> - add a SASL server plugin</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_done.html"><strong>sasl_server_done</strong> - Cleanup function</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_init.html"><strong>sasl_server_init</strong> - SASL server authentication initialization</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_new.html"><strong>sasl_server_new</strong> - Create a new server authentication object</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_plug_init_t.html"><strong>sasl_server_plug_init_t</strong> - server plug‐in entry point</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_start.html"><strong>sasl_server_start</strong> - Begin an authentication negotiation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_step.html"><strong>sasl_server_step</strong> - Perform a step in the authentication negotiation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_userdb_checkpass_t.html"><strong>sasl_server_userdb_checkpass_t</strong> - Plaintext Password Verification Callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_userdb_setpass_t.html"><strong>sasl_server_userdb_setpass_t</strong> - UserDB Plaintext Password Setting Callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_set_alloc.html"><strong>sasl_set_alloc</strong> - set the memory allocation functions used by the SASL library</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_set_mutex.html"><strong>sasl_set_mutex</strong> - set the mutex lock functions used by the SASL library</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_seterror.html"><strong>sasl_seterror</strong> - set the error string</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_setpass.html"><strong>sasl_setpass</strong> - Check a plaintext password</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_setprop.html"><strong>sasl_setprop</strong> - Set a SASL property</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_user_exists.html"><strong>sasl_user_exists</strong> - Check if a user exists on server</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_usererr.html"><strong>sasl_usererr</strong> - Remove information leak about accounts from sasl error codes</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_utf8verify.html"><strong>sasl_utf8verify</strong> - Verify a string is valid utf8</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_verifyfile_t.html"><strong>sasl_verifyfile_t</strong> - The SASL file verification</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/auxiliary_properties.html">Auxiliary Properties</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#auxiliary-properties-and-the-glue-layer">Auxiliary Properties and the Glue Layer</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#passwords-and-other-data">Passwords and other Data</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#sasldb">sasldb</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#ldapdb">ldapdb</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#sql">sql</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#user-canonicalization">User Canonicalization</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/authentication_mechanisms.html">Authentication Mechanisms</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/authentication_mechanisms.html#mechanisms">Mechanisms</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#anonymous">ANONYMOUS</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#cram-md5">CRAM-MD5</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#digest-md5">DIGEST-MD5</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#external">EXTERNAL</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#g2">G2</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#gssapi">GSSAPI</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#gss-spegno">GSS-SPEGNO</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#kerberos-v4">KERBEROS_V4</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#login">LOGIN</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#ntlm">NTLM</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#otp">OTP</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#passdss">PASSDSS</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#plain">PLAIN</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#scram">SCRAM</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#srp">SRP</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#non-sasl-authentication">Non-SASL Authentication</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/authentication_mechanisms.html#summary">Summary</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/pwcheck.html">Pwcheck</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#auxprop">Auxprop</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#auxprop-hashed">Auxprop-hashed</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#saslauthd">Saslauthd</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#authdaemon">Authdaemon</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#alwaystrue">Alwaystrue</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#auto-transition">Auto Transition</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/faq.html">Frequently Asked Questions</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/authorize-vs-authenticate.html">What is the difference between an Authorization ID and a Authentication ID?</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/crammd5-digestmd5.html">Why do CRAM-MD5 and DIGEST-MD5 not work with CyrusSaslauthd?</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/openldap-sasl-gssapi.html">How do I configure OpenLDAP +SASL+GSSAPI?</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/plaintextpasswords.html">Why does CyrusSasl store plaintext passwords in its databases?</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/rfcs.html">RFCs and drafts</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/upgrade-saslv2.html">Why am I having a problem running dbconverter-2 to upgrade from SASLv1 to SASLv2?</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/resources.html">Other Documentation &amp; Resources</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="developer.html">Developers</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/appconvert.html">Converting Applications from v1 to v2</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/appconvert.html#tips-for-both-clients-and-servers">Tips for both clients and servers</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/appconvert.html#tips-for-clients">Tips for clients</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/appconvert.html#tips-for-servers">Tips for Servers</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/developer/programming.html">Application Programmer’s Guide</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#introduction">Introduction</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#about-this-guide">About this Guide</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#what-is-sasl">What is SASL?</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#background">Background</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#how-did-the-world-work-before-sasl">How did the world work before SASL?</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#sasl-to-the-rescue">SASL to the rescue!</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#briefly">Briefly</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#what-is-the-cyrus-sasl-library-good-for">What is the Cyrus SASL library good for?</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#what-does-the-cyrus-sasl-library-do">What does the Cyrus SASL library do?</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#what-doesn-t-the-cyrus-sasl-library-do">What doesn’t the Cyrus SASL library do?</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#client-only-section">Client-only Section</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#a-typical-interaction-from-the-client-s-perspective">A typical interaction from the client’s perspective</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#how-does-this-look-in-code">How does this look in code</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#server-only-section">Server-only Section</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#a-typical-interaction-from-the-server-s-perspective">A typical interaction from the server’s perspective</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#id1">How does this look in code?</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#common-section">Common Section</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#callbacks-and-interactions">Callbacks and Interactions</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#security-layers">Security layers</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#example-applications-that-come-with-the-cyrus-sasl-library">Example applications that come with the Cyrus SASL library</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#sample-client-and-sample-server"><cite>sample-client</cite> and <cite>sample-server</cite></a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#cyrus-imapd-v2-1-0-or-later">Cyrus imapd v2.1.0 or later</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#imtest-from-cyrus-2-1-0-or-later"><cite>imtest</cite>, from Cyrus 2.1.0 or later</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#miscellaneous-information">Miscellaneous Information</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#empty-exchanges">Empty exchanges</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#idle">Idle</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/developer/plugprog.html">Plugin Programmer’s Guide</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#introduction">Introduction</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#about-this-guide">About this Guide</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#what-is-sasl">What is SASL?</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#common-section">Common Section</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#overview-of-plugin-programming">Overview of Plugin Programming</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#use-of-sasl-utils-t">Use of sasl_utils_t</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#error-reporting">Error Reporting</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#memory-allocation">Memory Allocation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#client-send-first-server-send-last">Client Send First / Server Send Last</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#client-plugins">Client Plugins</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#server-plugins">Server Plugins</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#user-canonicalization-canon-user-plugins">User Canonicalization (canon_user) Plugins</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#auxiliary-property-auxprop-plugins">Auxiliary Property (auxprop) Plugins</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/developer/testing.html">Testing</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/testing.html#testing-the-cmu-sasl-library-with-the-included-sample-applications">Testing the CMU SASL Library with the included sample applications</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/testing.html#example">Example</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/testing.html#running-the-testsuite-application">Running the Testsuite application</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="support.html">Support/Community</a></li>
</ul>
<p class="caption"><span class="caption-text">IMAP</span></p>
<ul>
<li class="toctree-l1"><a class="reference external" href="http://www.cyrusimap.org">Cyrus IMAP</a></li>
</ul>

          
        
      </div>
      &nbsp;
    </nav>

    <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">

      
      <nav class="wy-nav-top" role="navigation" aria-label="top navigation">
        <i data-toggle="wy-nav-top" class="fa fa-bars"></i>
        <a href="index.html">Cyrus SASL</a>
      </nav>


      
      <div class="wy-nav-content">
        <div class="rst-content">
          
          <div role="navigation" aria-label="breadcrumbs navigation">
  <ul class="wy-breadcrumbs">
      <li><a href="index.html">Docs v2.1.27</a> &raquo;</li>
      
    <li>Operations</li>
      <li class="wy-breadcrumbs-aside">
        
          
            <a href="https://github.com/cyrusimap/cyrus-sasl/blob/master/docsrc/operations.rst" class="fa fa-github"> Edit on GitHub</a>
          
        
      </li>
  </ul>
  <hr/>
</div>
          <div role="main" class="document">
            
  <div class="section" id="operations">
<h1>Operations<a class="headerlink" href="#operations" title="Permalink to this headline">¶</a></h1>
<div class="toctree-wrapper compound">
<ul>
<li class="toctree-l1"><a class="reference internal" href="sasl/sysadmin.html">System Administrators</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/sysadmin.html#what-sasl-is">What SASL is</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#authentication-and-authorization-identifiers">Authentication and authorization identifiers</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#realms">Realms</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/sysadmin.html#how-sasl-works">How SASL works</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#the-plain-mechanism-sasl-checkpass-and-plaintext-passwords">The PLAIN mechanism, <code class="docutils literal"><span class="pre">sasl_checkpass()</span></code>, and plaintext passwords</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#shared-secrets-mechanisms">Shared secrets mechanisms</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#kerberos-mechanisms">Kerberos mechanisms</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#the-otp-mechanism">The OTP mechanism</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/sysadmin.html#auxiliary-properties">Auxiliary Properties</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/sysadmin.html#how-to-set-configuration-options">How to set configuration options</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#the-default-configuration-file">The default configuration file</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#application-configuration">Application configuration</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/sysadmin.html#troubleshooting">Troubleshooting</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="sasl/manpages.html">Man pages</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/manpages.html#library-files">(3) Library Files</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl.html"><strong>SASL</strong> - SASL Authentication Library</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_authorize_t.html"><strong>sasl_authorize_t</strong> - The SASL authorization callback</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_auxprop.html"><strong>sasl_auxprop</strong> - How to work with SASL auxiliary properties</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_auxprop_add_plugin.html"><strong>sasl_auxprop_add_plugin</strong> - add a SASL auxiliary property plugin</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_auxprop_getctx.html"><strong>sasl_auxprop_getctx</strong> - Acquire an auxiliary property context</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_auxprop_request.html"><strong>sasl_auxprop_request</strong> - Request auxiliary properties from SASL</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_callbacks.html"><strong>sasl_callbacks</strong> - How to work with SASL callbacks</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_canon_user_t.html"><strong>sasl_canon_user_t</strong> - Application-supplied user canonicalization function</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_canonuser_add_plugin.html"><strong>sasl_canonuser_add_plugin</strong> - add a SASL user canonicalization plugin</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_chalprompt_t.html"><strong>sasl_chalprompt_t</strong> - Realm acquisition callback</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_checkapop.html"><strong>sasl_checkapop</strong> - Check an APOP challenge/response</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_checkpass.html"><strong>sasl_checkpass</strong> - Check a plaintext password</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_add_plugin.html"><strong>sasl_client_add_plugin</strong> - add a SASL client plugin</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_done.html"><strong>sasl_client_done</strong> - Cleanup function</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_init.html"><strong>sasl_client_init</strong> - SASL client authentication initialization</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_new.html"><strong>sasl_client_new</strong> - Create a new client authentication object</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_plug_init_t.html"><strong>sasl_client_plug_init_t</strong> - client plug‐in entry point</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_start.html"><strong>sasl_client_start</strong> - Begin an authentication negotiation</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_step.html"><strong>sasl_client_step</strong> - Perform a step in the authentication negotiation</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_decode.html"><strong>sasl_decode</strong> - Decode data received</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_decode64.html"><strong>sasl_decode64</strong> - Decode base64 string</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_dispose.html"><strong>sasl_dispose</strong> - Dispose of a SASL connection object</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_done.html"><strong>sasl_done</strong> - Dispose of a SASL connection object</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_encode.html"><strong>sasl_encode</strong> - Encode data for transport to authenticated host</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_encode64.html"><strong>sasl_encode64</strong> - Encode base64 string</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_encodev.html"><strong>sasl_encodev</strong> - Encode data for transport to authenticated host</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_erasebuffer.html"><strong>sasl_erasebuffer</strong> - erase buffer</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_errdetail.html"><strong>sasl_errdetail</strong> - Retrieve  detailed information about an error</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_errors.html"><strong>sasl_errors</strong> - SASL error codes</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_errstring.html"><strong>sasl_errstring</strong> - Translate a SASL return code to a human-readable form</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getcallback_t.html"><strong>sasl_getcallback_t</strong> - callback function to lookup a sasl_callback_t for a connection</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getconfpath_t.html"><strong>sasl_getconfpath_t</strong> - The SASL callback to indicate location of the config files</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getopt_t.html"><strong>sasl_getopt_t</strong> - The SASL get option callback</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getpath_t.html"><strong>sasl_getpath_t</strong> - The SASL callback to indicate location of the mechanism drivers</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getprop.html"><strong>sasl_getprop</strong> - Get a SASL property</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getrealm_t.html"><strong>sasl_getrealm_t</strong> - Realm Acquisition Callback</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getsecret_t.html"><strong>sasl_getsecret_t</strong> - The SASL callback for secrets (passwords)</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getsimple_t.html"><strong>sasl_getsimple_t</strong> - The SASL callback for username/authname/realm</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_global_listmech.html"><strong>sasl_global_listmech</strong> - Retrieve a list of the supported SASL mechanisms</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_idle.html"><strong>sasl_idle</strong> - Perform precalculations during an idle period</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_listmech.html"><strong>sasl_listmech</strong> - Retrieve a list of the supported SASL mechanisms</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_log_t.html"><strong>sasl_log_t</strong> - The SASL logging callback</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_add_plugin.html"><strong>sasl_server_add_plugin</strong> - add a SASL server plugin</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_done.html"><strong>sasl_server_done</strong> - Cleanup function</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_init.html"><strong>sasl_server_init</strong> - SASL server authentication initialization</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_new.html"><strong>sasl_server_new</strong> - Create a new server authentication object</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_plug_init_t.html"><strong>sasl_server_plug_init_t</strong> - server plug‐in entry point</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_start.html"><strong>sasl_server_start</strong> - Begin an authentication negotiation</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_step.html"><strong>sasl_server_step</strong> - Perform a step in the authentication negotiation</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_userdb_checkpass_t.html"><strong>sasl_server_userdb_checkpass_t</strong> - Plaintext Password Verification Callback</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_userdb_setpass_t.html"><strong>sasl_server_userdb_setpass_t</strong> - UserDB Plaintext Password Setting Callback</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_set_alloc.html"><strong>sasl_set_alloc</strong> - set the memory allocation functions used by the SASL library</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_set_mutex.html"><strong>sasl_set_mutex</strong> - set the mutex lock functions used by the SASL library</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_seterror.html"><strong>sasl_seterror</strong> - set the error string</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_setpass.html"><strong>sasl_setpass</strong> - Check a plaintext password</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_setprop.html"><strong>sasl_setprop</strong> - Set a SASL property</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_user_exists.html"><strong>sasl_user_exists</strong> - Check if a user exists on server</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_usererr.html"><strong>sasl_usererr</strong> - Remove information leak about accounts from sasl error codes</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_utf8verify.html"><strong>sasl_utf8verify</strong> - Verify a string is valid utf8</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/reference/manpages/library/sasl_verifyfile_t.html"><strong>sasl_verifyfile_t</strong> - The SASL file verification</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="sasl/auxiliary_properties.html">Auxiliary Properties</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/auxiliary_properties.html#auxiliary-properties-and-the-glue-layer">Auxiliary Properties and the Glue Layer</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/auxiliary_properties.html#passwords-and-other-data">Passwords and other Data</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/auxiliary_properties.html#sasldb">sasldb</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/auxiliary_properties.html#ldapdb">ldapdb</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/auxiliary_properties.html#sql">sql</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/auxiliary_properties.html#user-canonicalization">User Canonicalization</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="sasl/authentication_mechanisms.html">Authentication Mechanisms</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/authentication_mechanisms.html#mechanisms">Mechanisms</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/authentication_mechanisms.html#anonymous">ANONYMOUS</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/authentication_mechanisms.html#cram-md5">CRAM-MD5</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/authentication_mechanisms.html#digest-md5">DIGEST-MD5</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/authentication_mechanisms.html#external">EXTERNAL</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/authentication_mechanisms.html#g2">G2</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/authentication_mechanisms.html#gssapi">GSSAPI</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/authentication_mechanisms.html#gss-spegno">GSS-SPEGNO</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/authentication_mechanisms.html#kerberos-v4">KERBEROS_V4</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/authentication_mechanisms.html#login">LOGIN</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/authentication_mechanisms.html#ntlm">NTLM</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/authentication_mechanisms.html#otp">OTP</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/authentication_mechanisms.html#passdss">PASSDSS</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/authentication_mechanisms.html#plain">PLAIN</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/authentication_mechanisms.html#scram">SCRAM</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/authentication_mechanisms.html#srp">SRP</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/authentication_mechanisms.html#non-sasl-authentication">Non-SASL Authentication</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/authentication_mechanisms.html#summary">Summary</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="sasl/pwcheck.html">Pwcheck</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/pwcheck.html#auxprop">Auxprop</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/pwcheck.html#auxprop-hashed">Auxprop-hashed</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/pwcheck.html#saslauthd">Saslauthd</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/pwcheck.html#authdaemon">Authdaemon</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/pwcheck.html#alwaystrue">Alwaystrue</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/pwcheck.html#auto-transition">Auto Transition</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="sasl/faq.html">Frequently Asked Questions</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/faqs/authorize-vs-authenticate.html">What is the difference between an Authorization ID and a Authentication ID?</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/faqs/crammd5-digestmd5.html">Why do CRAM-MD5 and DIGEST-MD5 not work with CyrusSaslauthd?</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/faqs/openldap-sasl-gssapi.html">How do I configure OpenLDAP +SASL+GSSAPI?</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/faqs/plaintextpasswords.html">Why does CyrusSasl store plaintext passwords in its databases?</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/faqs/rfcs.html">RFCs and drafts</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/faqs/upgrade-saslv2.html">Why am I having a problem running dbconverter-2 to upgrade from SASLv1 to SASLv2?</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="sasl/resources.html">Other Documentation &amp; Resources</a></li>
</ul>
</div>
</div>


          </div>
          <footer>
  
    <div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
      
        <a href="sasl/sysadmin.html" class="btn btn-neutral float-right" title="System Administrators" accesskey="n">Next <span class="fa fa-arrow-circle-right"></span></a>
      
      
        <a href="sasl/advanced.html" class="btn btn-neutral" title="Advanced Usage" accesskey="p"><span class="fa fa-arrow-circle-left"></span> Previous</a>
      
    </div>
  

  <hr/>

  <div role="contentinfo">
    <p>
        &copy; Copyright 1993-2016, The Cyrus Team.
    </p>
  </div>
  Built with <a href="http://sphinx-doc.org/">Sphinx</a> 1.6.6 using a modified <a href="https://readthedocs.org">Read the Docs</a> <a href="https://github.com/snide/sphinx_rtd_theme">theme</a>.

</footer>

        </div>
      </div>

    </section>

  </div>
  


  

    <script type="text/javascript">
        var DOCUMENTATION_OPTIONS = {
            URL_ROOT:'./',
            VERSION:'2.1.27',
            COLLAPSE_INDEX:false,
            FILE_SUFFIX:'.html',
            HAS_SOURCE:  true
        };
    </script>
      <script type="text/javascript" src="_static/jquery.js"></script>
      <script type="text/javascript" src="_static/underscore.js"></script>
      <script type="text/javascript" src="_static/doctools.js"></script>
      <script type="text/javascript" src="https://cdn.mathjax.org/mathjax/latest/MathJax.js"></script>

  

  
  
    <script type="text/javascript" src="_static/js/theme.js"></script>
  

  
  
  <script type="text/javascript">
<!--      jQuery(function () {
          SphinxRtdTheme.StickyNav.enable();
      }); -->
  </script>
  
 



</body>
</html>PK�h%[Z��T����!doc/alt-cyrus-sasl-lib/index.htmlnu�[���

<!DOCTYPE html>
<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
<head>
  <meta charset="utf-8">
  
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  
  <title>Cyrus SASL &mdash; Cyrus SASL 2.1.27 documentation</title>
  

  
  
    <link rel="shortcut icon" href="_static/favicon.ico"/>
  

  

  
  
    

  

  
  
    <link rel="stylesheet" href="_static/css/theme.css" type="text/css" />
  

  
    <link rel="stylesheet" href="_static/cyrus.css" type="text/css" />
  

  
        <link rel="index" title="Index"
              href="genindex.html"/>
        <link rel="search" title="Search" href="search.html"/>
    <link rel="top" title="Cyrus SASL 2.1.27 documentation" href="#"/>
        <link rel="next" title="Download" href="download.html"/> 

  
  
  

</head>

<body class="wy-body-for-nav" role="document">

  
  
<div class="pageheader">
  <ul>
    <li><a href="#">Home</a></li>
    <li><a href="http://www.cyrusimap.org">Cyrus IMAP</a></li>
    <li><a href="download.html">Download</a></li>
    <li><a href="contribute.html">Contribute</a></li>
  </ul>
  <div>
    <a href="#">
      <img src="_static/logo.gif" alt="CYRUS SASL" />
    </a>
  </div>
</div>
<div style="clear: both;"></div>


  <div class="wy-grid-for-nav">

    
    <nav data-toggle="wy-nav-shift" class="wy-nav-side">
      <div class="wy-side-nav-search">
        

        
 
          <a href="#">
 

  
          
          <img src="_static/logo.gif"  />
     
        </a>

        
<div role="search">
  <form id="rtd-search-form" class="wy-form" action="search.html" method="get">
    <input type="text" name="q" placeholder="Search docs" />
    <input type="hidden" name="check_keywords" value="yes" />
    <input type="hidden" name="area" value="default" />
  </form>
</div>

        
      </div>

      <div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
        
          
          
              <p class="caption"><span class="caption-text">Cyrus SASL</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="download.html">Download</a><ul>
<li class="toctree-l2"><a class="reference internal" href="getsasl.html">Get SASL</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html">Installation</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#quick-install-guide">Quick install guide</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#detailed-installation-guide">Detailed installation guide</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#supported-platforms">Supported platforms</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/release-notes/index.html">Release Notes</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/release-notes/index.html#supported-product-series">Supported Product Series</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/release-notes/index.html#series-2-1">Series 2.1</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/release-notes/index.html#older-versions">Older Versions</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/release-notes/index.html#series-2-2-0">Series 2: 2.0</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/release-notes/index.html#series-1">Series 1</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="packager.html">Note for Packagers</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="sasl/quickstart.html">Quickstart guide</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/quickstart.html#features">Features</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/quickstart.html#typical-installation">Typical Installation</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/quickstart.html#configuration">Configuration</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="sasl/concepts.html">Concepts</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#sasl">SASL</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#sasl-authentication-mechanisms">SASL Authentication Mechanisms</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#security-layers">Security Layers</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#channel-binding">Channel Binding</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#realms">Realms</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#protocols">Protocols</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#cyrus-sasl">Cyrus SASL</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#the-glue-library">The Glue Library</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#auxiliary-properties">Auxiliary Properties</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#plugins">Plugins</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="setup.html">Setup</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/installation.html">Installation</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html#quick-install-guide">Quick install guide</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#tarball-installation">Tarball installation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#unix-package-installation">Unix package Installation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#configuration">Configuration</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html#detailed-installation-guide">Detailed installation guide</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#requirements">Requirements</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#build-configuration">Build Configuration</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#building-and-installation">Building and Installation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#compilation-hints">Compilation Hints</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#application-configuration">Application Configuration</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html#supported-platforms">Supported platforms</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/upgrading.html">Upgrading from v1 to v2</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/upgrading.html#backwards-compatibility">Backwards Compatibility</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/upgrading.html#coexistence-with-saslv1">Coexistence with SASLv1</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/upgrading.html#database-upgrades">Database Upgrades</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/upgrading.html#errors-on-migration">Errors on migration</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/components.html">Components</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/components.html#the-application">The Application</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/components.html#the-sasl-glue-layer">The SASL Glue Layer</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/components.html#plugins">Plugins</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/components.html#plugins-general">Plugins: General</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/components.html#plugins-sasl-mechanisms">Plugins: SASL Mechanisms</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/components.html#plugins-auxiliary-property">Plugins: Auxiliary Property</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/components.html#plugins-username-canonicalization">Plugins: Username Canonicalization</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/components.html#password-verification-services">Password Verification Services</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/options.html">Options</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#sasl-library">SASL Library</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#auxiliary-property-plugin">Auxiliary Property Plugin</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#gssapi">GSSAPI</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#ldapdb">LDAPDB</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/options.html#notes-on-ldapdb">Notes on LDAPDB</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/options.html#examples">Examples</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#ntlm">NTLM</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#otp">OTP</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#digest-md5">Digest-md5</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#sasldb">SASLDB</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/options.html#notes-on-sasldb-with-lmdb">Notes on sasldb with LMDB</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#sql-plugin">SQL Plugin</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/options.html#notes-on-sql">Notes on SQL</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/options.html#id2">Examples</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#srp">SRP</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#kerberos-v4">Kerberos V4</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/advanced.html">Advanced Usage</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/advanced.html#notes-for-advanced-usage-of-libsasl">Notes for Advanced Usage of libsasl</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/advanced.html#using-cyrus-sasl-as-a-static-library">Using Cyrus SASL as a static library</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="operations.html">Operations</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/sysadmin.html">System Administrators</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#what-sasl-is">What SASL is</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#authentication-and-authorization-identifiers">Authentication and authorization identifiers</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#realms">Realms</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#how-sasl-works">How SASL works</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#the-plain-mechanism-sasl-checkpass-and-plaintext-passwords">The PLAIN mechanism, <code class="docutils literal"><span class="pre">sasl_checkpass()</span></code>, and plaintext passwords</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#shared-secrets-mechanisms">Shared secrets mechanisms</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#kerberos-mechanisms">Kerberos mechanisms</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#the-otp-mechanism">The OTP mechanism</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#auxiliary-properties">Auxiliary Properties</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#how-to-set-configuration-options">How to set configuration options</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#the-default-configuration-file">The default configuration file</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#application-configuration">Application configuration</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#troubleshooting">Troubleshooting</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/manpages.html">Man pages</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/manpages.html#library-files">(3) Library Files</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl.html"><strong>SASL</strong> - SASL Authentication Library</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_authorize_t.html"><strong>sasl_authorize_t</strong> - The SASL authorization callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_auxprop.html"><strong>sasl_auxprop</strong> - How to work with SASL auxiliary properties</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_auxprop_add_plugin.html"><strong>sasl_auxprop_add_plugin</strong> - add a SASL auxiliary property plugin</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_auxprop_getctx.html"><strong>sasl_auxprop_getctx</strong> - Acquire an auxiliary property context</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_auxprop_request.html"><strong>sasl_auxprop_request</strong> - Request auxiliary properties from SASL</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_callbacks.html"><strong>sasl_callbacks</strong> - How to work with SASL callbacks</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_canon_user_t.html"><strong>sasl_canon_user_t</strong> - Application-supplied user canonicalization function</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_canonuser_add_plugin.html"><strong>sasl_canonuser_add_plugin</strong> - add a SASL user canonicalization plugin</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_chalprompt_t.html"><strong>sasl_chalprompt_t</strong> - Realm acquisition callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_checkapop.html"><strong>sasl_checkapop</strong> - Check an APOP challenge/response</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_checkpass.html"><strong>sasl_checkpass</strong> - Check a plaintext password</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_add_plugin.html"><strong>sasl_client_add_plugin</strong> - add a SASL client plugin</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_done.html"><strong>sasl_client_done</strong> - Cleanup function</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_init.html"><strong>sasl_client_init</strong> - SASL client authentication initialization</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_new.html"><strong>sasl_client_new</strong> - Create a new client authentication object</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_plug_init_t.html"><strong>sasl_client_plug_init_t</strong> - client plug‐in entry point</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_start.html"><strong>sasl_client_start</strong> - Begin an authentication negotiation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_step.html"><strong>sasl_client_step</strong> - Perform a step in the authentication negotiation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_decode.html"><strong>sasl_decode</strong> - Decode data received</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_decode64.html"><strong>sasl_decode64</strong> - Decode base64 string</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_dispose.html"><strong>sasl_dispose</strong> - Dispose of a SASL connection object</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_done.html"><strong>sasl_done</strong> - Dispose of a SASL connection object</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_encode.html"><strong>sasl_encode</strong> - Encode data for transport to authenticated host</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_encode64.html"><strong>sasl_encode64</strong> - Encode base64 string</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_encodev.html"><strong>sasl_encodev</strong> - Encode data for transport to authenticated host</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_erasebuffer.html"><strong>sasl_erasebuffer</strong> - erase buffer</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_errdetail.html"><strong>sasl_errdetail</strong> - Retrieve  detailed information about an error</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_errors.html"><strong>sasl_errors</strong> - SASL error codes</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_errstring.html"><strong>sasl_errstring</strong> - Translate a SASL return code to a human-readable form</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getcallback_t.html"><strong>sasl_getcallback_t</strong> - callback function to lookup a sasl_callback_t for a connection</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getconfpath_t.html"><strong>sasl_getconfpath_t</strong> - The SASL callback to indicate location of the config files</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getopt_t.html"><strong>sasl_getopt_t</strong> - The SASL get option callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getpath_t.html"><strong>sasl_getpath_t</strong> - The SASL callback to indicate location of the mechanism drivers</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getprop.html"><strong>sasl_getprop</strong> - Get a SASL property</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getrealm_t.html"><strong>sasl_getrealm_t</strong> - Realm Acquisition Callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getsecret_t.html"><strong>sasl_getsecret_t</strong> - The SASL callback for secrets (passwords)</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getsimple_t.html"><strong>sasl_getsimple_t</strong> - The SASL callback for username/authname/realm</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_global_listmech.html"><strong>sasl_global_listmech</strong> - Retrieve a list of the supported SASL mechanisms</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_idle.html"><strong>sasl_idle</strong> - Perform precalculations during an idle period</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_listmech.html"><strong>sasl_listmech</strong> - Retrieve a list of the supported SASL mechanisms</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_log_t.html"><strong>sasl_log_t</strong> - The SASL logging callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_add_plugin.html"><strong>sasl_server_add_plugin</strong> - add a SASL server plugin</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_done.html"><strong>sasl_server_done</strong> - Cleanup function</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_init.html"><strong>sasl_server_init</strong> - SASL server authentication initialization</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_new.html"><strong>sasl_server_new</strong> - Create a new server authentication object</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_plug_init_t.html"><strong>sasl_server_plug_init_t</strong> - server plug‐in entry point</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_start.html"><strong>sasl_server_start</strong> - Begin an authentication negotiation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_step.html"><strong>sasl_server_step</strong> - Perform a step in the authentication negotiation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_userdb_checkpass_t.html"><strong>sasl_server_userdb_checkpass_t</strong> - Plaintext Password Verification Callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_userdb_setpass_t.html"><strong>sasl_server_userdb_setpass_t</strong> - UserDB Plaintext Password Setting Callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_set_alloc.html"><strong>sasl_set_alloc</strong> - set the memory allocation functions used by the SASL library</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_set_mutex.html"><strong>sasl_set_mutex</strong> - set the mutex lock functions used by the SASL library</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_seterror.html"><strong>sasl_seterror</strong> - set the error string</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_setpass.html"><strong>sasl_setpass</strong> - Check a plaintext password</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_setprop.html"><strong>sasl_setprop</strong> - Set a SASL property</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_user_exists.html"><strong>sasl_user_exists</strong> - Check if a user exists on server</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_usererr.html"><strong>sasl_usererr</strong> - Remove information leak about accounts from sasl error codes</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_utf8verify.html"><strong>sasl_utf8verify</strong> - Verify a string is valid utf8</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_verifyfile_t.html"><strong>sasl_verifyfile_t</strong> - The SASL file verification</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/auxiliary_properties.html">Auxiliary Properties</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#auxiliary-properties-and-the-glue-layer">Auxiliary Properties and the Glue Layer</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#passwords-and-other-data">Passwords and other Data</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#sasldb">sasldb</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#ldapdb">ldapdb</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#sql">sql</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#user-canonicalization">User Canonicalization</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/authentication_mechanisms.html">Authentication Mechanisms</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/authentication_mechanisms.html#mechanisms">Mechanisms</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#anonymous">ANONYMOUS</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#cram-md5">CRAM-MD5</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#digest-md5">DIGEST-MD5</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#external">EXTERNAL</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#g2">G2</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#gssapi">GSSAPI</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#gss-spegno">GSS-SPEGNO</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#kerberos-v4">KERBEROS_V4</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#login">LOGIN</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#ntlm">NTLM</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#otp">OTP</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#passdss">PASSDSS</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#plain">PLAIN</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#scram">SCRAM</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#srp">SRP</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#non-sasl-authentication">Non-SASL Authentication</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/authentication_mechanisms.html#summary">Summary</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/pwcheck.html">Pwcheck</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#auxprop">Auxprop</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#auxprop-hashed">Auxprop-hashed</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#saslauthd">Saslauthd</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#authdaemon">Authdaemon</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#alwaystrue">Alwaystrue</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#auto-transition">Auto Transition</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/faq.html">Frequently Asked Questions</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/authorize-vs-authenticate.html">What is the difference between an Authorization ID and a Authentication ID?</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/crammd5-digestmd5.html">Why do CRAM-MD5 and DIGEST-MD5 not work with CyrusSaslauthd?</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/openldap-sasl-gssapi.html">How do I configure OpenLDAP +SASL+GSSAPI?</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/plaintextpasswords.html">Why does CyrusSasl store plaintext passwords in its databases?</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/rfcs.html">RFCs and drafts</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/upgrade-saslv2.html">Why am I having a problem running dbconverter-2 to upgrade from SASLv1 to SASLv2?</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/resources.html">Other Documentation &amp; Resources</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="developer.html">Developers</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/appconvert.html">Converting Applications from v1 to v2</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/appconvert.html#tips-for-both-clients-and-servers">Tips for both clients and servers</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/appconvert.html#tips-for-clients">Tips for clients</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/appconvert.html#tips-for-servers">Tips for Servers</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/developer/programming.html">Application Programmer’s Guide</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#introduction">Introduction</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#about-this-guide">About this Guide</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#what-is-sasl">What is SASL?</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#background">Background</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#how-did-the-world-work-before-sasl">How did the world work before SASL?</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#sasl-to-the-rescue">SASL to the rescue!</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#briefly">Briefly</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#what-is-the-cyrus-sasl-library-good-for">What is the Cyrus SASL library good for?</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#what-does-the-cyrus-sasl-library-do">What does the Cyrus SASL library do?</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#what-doesn-t-the-cyrus-sasl-library-do">What doesn’t the Cyrus SASL library do?</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#client-only-section">Client-only Section</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#a-typical-interaction-from-the-client-s-perspective">A typical interaction from the client’s perspective</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#how-does-this-look-in-code">How does this look in code</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#server-only-section">Server-only Section</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#a-typical-interaction-from-the-server-s-perspective">A typical interaction from the server’s perspective</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#id1">How does this look in code?</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#common-section">Common Section</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#callbacks-and-interactions">Callbacks and Interactions</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#security-layers">Security layers</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#example-applications-that-come-with-the-cyrus-sasl-library">Example applications that come with the Cyrus SASL library</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#sample-client-and-sample-server"><cite>sample-client</cite> and <cite>sample-server</cite></a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#cyrus-imapd-v2-1-0-or-later">Cyrus imapd v2.1.0 or later</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#imtest-from-cyrus-2-1-0-or-later"><cite>imtest</cite>, from Cyrus 2.1.0 or later</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#miscellaneous-information">Miscellaneous Information</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#empty-exchanges">Empty exchanges</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#idle">Idle</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/developer/plugprog.html">Plugin Programmer’s Guide</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#introduction">Introduction</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#about-this-guide">About this Guide</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#what-is-sasl">What is SASL?</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#common-section">Common Section</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#overview-of-plugin-programming">Overview of Plugin Programming</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#use-of-sasl-utils-t">Use of sasl_utils_t</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#error-reporting">Error Reporting</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#memory-allocation">Memory Allocation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#client-send-first-server-send-last">Client Send First / Server Send Last</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#client-plugins">Client Plugins</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#server-plugins">Server Plugins</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#user-canonicalization-canon-user-plugins">User Canonicalization (canon_user) Plugins</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#auxiliary-property-auxprop-plugins">Auxiliary Property (auxprop) Plugins</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/developer/testing.html">Testing</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/testing.html#testing-the-cmu-sasl-library-with-the-included-sample-applications">Testing the CMU SASL Library with the included sample applications</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/testing.html#example">Example</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/testing.html#running-the-testsuite-application">Running the Testsuite application</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="support.html">Support/Community</a></li>
</ul>
<p class="caption"><span class="caption-text">IMAP</span></p>
<ul>
<li class="toctree-l1"><a class="reference external" href="http://www.cyrusimap.org">Cyrus IMAP</a></li>
</ul>

          
        
      </div>
      &nbsp;
    </nav>

    <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">

      
      <nav class="wy-nav-top" role="navigation" aria-label="top navigation">
        <i data-toggle="wy-nav-top" class="fa fa-bars"></i>
        <a href="#">Cyrus SASL</a>
      </nav>


      
      <div class="wy-nav-content">
        <div class="rst-content">
          
          <div role="navigation" aria-label="breadcrumbs navigation">
  <ul class="wy-breadcrumbs">
      <li><a href="#">Docs v2.1.27</a> &raquo;</li>
      
    <li>Cyrus SASL</li>
      <li class="wy-breadcrumbs-aside">
        
          
            <a href="https://github.com/cyrusimap/cyrus-sasl/blob/master/docsrc/index.rst" class="fa fa-github"> Edit on GitHub</a>
          
        
      </li>
  </ul>
  <hr/>
</div>
          <div role="main" class="document">
            
  <div class="section" id="cyrus-sasl">
<span id="sasl-index"></span><h1>Cyrus SASL<a class="headerlink" href="#cyrus-sasl" title="Permalink to this headline">¶</a></h1>
<p>Welcome to Cyrus SASL.</p>
<div class="section" id="what-is-cyrus-sasl">
<h2>What is Cyrus SASL?<a class="headerlink" href="#what-is-cyrus-sasl" title="Permalink to this headline">¶</a></h2>
<p>Simple Authentication and Security Layer (<a class="reference external" href="https://en.wikipedia.org/wiki/Simple_Authentication_and_Security_Layer">SASL</a>) is a specification that describes how authentication mechanisms can be plugged into an application protocol on the wire. Cyrus SASL is an implementation of SASL that makes it easy for application developers to integrate authentication mechanisms into their application in a generic way.</p>
<p>The latest stable version of Cyrus SASL is 2.1.26.</p>
<p><a class="reference external" href="https://www.cyrusimap.org/index.html#imap-index" title="(in Cyrus IMAP v3.0.8)"><span class="xref std std-ref">Cyrus IMAP</span></a> uses Cyrus SASL to provide authentication support to the mail server, however it is just one project using Cyrus SASL.</p>
<div class="section" id="features">
<h3>Features<a class="headerlink" href="#features" title="Permalink to this headline">¶</a></h3>
<p>Cyrus SASL provides a number of authentication plugins out of the box.</p>
<blockquote>
<div>Berkeley DB, GDBM, or NDBM (sasldb), PAM, MySQL, PostgreSQL, SQLite, LDAP, Active Directory(LDAP), DCE, Kerberos 4 and 5, proxied IMAP auth, getpwent, shadow, SIA, Courier Authdaemon, httpform, APOP and SASL mechanisms: ANONYMOUS, CRAM-MD5, DIGEST-MD5, EXTERNAL, GSSAPI, LOGIN, NTLM, OTP, PASSDSS, PLAIN, SR</div></blockquote>
<p>This document is an introduction to <strong>Cyrus SASL</strong>. It is not intended to be an exhaustive reference for the SASL Application Programming Interface (API), which is detailed in the SASL manual pages, and the libsasl.h header file.</p>
</div>
<div class="section" id="known-bugs">
<h3>Known Bugs<a class="headerlink" href="#known-bugs" title="Permalink to this headline">¶</a></h3>
<p><code class="docutils literal"><span class="pre">libtool</span></code> doesn’t always link libraries together.  In our environment,
we only have static Krb5 libraries; the GSSAPI plugin should link
these libraries in on platforms that support it (Solaris and Linux
among them) but it does not.  It also doesn’t always get the runpath
of libraries correct.</p>
<div class="toctree-wrapper compound">
<p class="caption"><span class="caption-text">Cyrus SASL</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="download.html">Download</a><ul>
<li class="toctree-l2"><a class="reference internal" href="getsasl.html">Get SASL</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html">Installation</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/release-notes/index.html">Release Notes</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/release-notes/index.html#supported-product-series">Supported Product Series</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/release-notes/index.html#older-versions">Older Versions</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="packager.html">Note for Packagers</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="sasl/quickstart.html">Quickstart guide</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/quickstart.html#features">Features</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/quickstart.html#typical-installation">Typical Installation</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/quickstart.html#configuration">Configuration</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="sasl/concepts.html">Concepts</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#sasl">SASL</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#sasl-authentication-mechanisms">SASL Authentication Mechanisms</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#security-layers">Security Layers</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#channel-binding">Channel Binding</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#realms">Realms</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#protocols">Protocols</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#cyrus-sasl">Cyrus SASL</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#the-glue-library">The Glue Library</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#auxiliary-properties">Auxiliary Properties</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#plugins">Plugins</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="setup.html">Setup</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/installation.html">Installation</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html#quick-install-guide">Quick install guide</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html#detailed-installation-guide">Detailed installation guide</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html#supported-platforms">Supported platforms</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/upgrading.html">Upgrading from v1 to v2</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/upgrading.html#backwards-compatibility">Backwards Compatibility</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/upgrading.html#coexistence-with-saslv1">Coexistence with SASLv1</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/upgrading.html#database-upgrades">Database Upgrades</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/upgrading.html#errors-on-migration">Errors on migration</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/components.html">Components</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/components.html#the-application">The Application</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/components.html#the-sasl-glue-layer">The SASL Glue Layer</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/components.html#plugins">Plugins</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/components.html#password-verification-services">Password Verification Services</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/options.html">Options</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#sasl-library">SASL Library</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#auxiliary-property-plugin">Auxiliary Property Plugin</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#gssapi">GSSAPI</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#ldapdb">LDAPDB</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#ntlm">NTLM</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#otp">OTP</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#digest-md5">Digest-md5</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#sasldb">SASLDB</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#sql-plugin">SQL Plugin</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#srp">SRP</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#kerberos-v4">Kerberos V4</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/advanced.html">Advanced Usage</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/advanced.html#notes-for-advanced-usage-of-libsasl">Notes for Advanced Usage of libsasl</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="operations.html">Operations</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/sysadmin.html">System Administrators</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#what-sasl-is">What SASL is</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#how-sasl-works">How SASL works</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#auxiliary-properties">Auxiliary Properties</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#how-to-set-configuration-options">How to set configuration options</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#troubleshooting">Troubleshooting</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/manpages.html">Man pages</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/manpages.html#library-files">(3) Library Files</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/auxiliary_properties.html">Auxiliary Properties</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#auxiliary-properties-and-the-glue-layer">Auxiliary Properties and the Glue Layer</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#passwords-and-other-data">Passwords and other Data</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#sasldb">sasldb</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#ldapdb">ldapdb</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#sql">sql</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#user-canonicalization">User Canonicalization</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/authentication_mechanisms.html">Authentication Mechanisms</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/authentication_mechanisms.html#mechanisms">Mechanisms</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/authentication_mechanisms.html#summary">Summary</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/pwcheck.html">Pwcheck</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#auxprop">Auxprop</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#auxprop-hashed">Auxprop-hashed</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#saslauthd">Saslauthd</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#authdaemon">Authdaemon</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#alwaystrue">Alwaystrue</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#auto-transition">Auto Transition</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/faq.html">Frequently Asked Questions</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/authorize-vs-authenticate.html">What is the difference between an Authorization ID and a Authentication ID?</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/crammd5-digestmd5.html">Why do CRAM-MD5 and DIGEST-MD5 not work with CyrusSaslauthd?</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/openldap-sasl-gssapi.html">How do I configure OpenLDAP +SASL+GSSAPI?</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/plaintextpasswords.html">Why does CyrusSasl store plaintext passwords in its databases?</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/rfcs.html">RFCs and drafts</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/upgrade-saslv2.html">Why am I having a problem running dbconverter-2 to upgrade from SASLv1 to SASLv2?</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/resources.html">Other Documentation &amp; Resources</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="developer.html">Developers</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/appconvert.html">Converting Applications from v1 to v2</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/appconvert.html#tips-for-both-clients-and-servers">Tips for both clients and servers</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/appconvert.html#tips-for-clients">Tips for clients</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/appconvert.html#tips-for-servers">Tips for Servers</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/developer/programming.html">Application Programmer’s Guide</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#introduction">Introduction</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#background">Background</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#briefly">Briefly</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#client-only-section">Client-only Section</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#server-only-section">Server-only Section</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#common-section">Common Section</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#example-applications-that-come-with-the-cyrus-sasl-library">Example applications that come with the Cyrus SASL library</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#miscellaneous-information">Miscellaneous Information</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/developer/plugprog.html">Plugin Programmer’s Guide</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#introduction">Introduction</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#common-section">Common Section</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#client-plugins">Client Plugins</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#server-plugins">Server Plugins</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#user-canonicalization-canon-user-plugins">User Canonicalization (canon_user) Plugins</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#auxiliary-property-auxprop-plugins">Auxiliary Property (auxprop) Plugins</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/developer/testing.html">Testing</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/testing.html#testing-the-cmu-sasl-library-with-the-included-sample-applications">Testing the CMU SASL Library with the included sample applications</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/testing.html#running-the-testsuite-application">Running the Testsuite application</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="support.html">Support/Community</a></li>
</ul>
</div>
<div class="toctree-wrapper compound">
<p class="caption"><span class="caption-text">IMAP</span></p>
<ul>
<li class="toctree-l1"><a class="reference external" href="http://www.cyrusimap.org">Cyrus IMAP</a></li>
</ul>
</div>
</div>
</div>
</div>


          </div>
          <footer>
  
    <div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
      
        <a href="download.html" class="btn btn-neutral float-right" title="Download" accesskey="n">Next <span class="fa fa-arrow-circle-right"></span></a>
      
      
    </div>
  

  <hr/>

  <div role="contentinfo">
    <p>
        &copy; Copyright 1993-2016, The Cyrus Team.
    </p>
  </div>
  Built with <a href="http://sphinx-doc.org/">Sphinx</a> 1.6.6 using a modified <a href="https://readthedocs.org">Read the Docs</a> <a href="https://github.com/snide/sphinx_rtd_theme">theme</a>.

</footer>

        </div>
      </div>

    </section>

  </div>
  


  

    <script type="text/javascript">
        var DOCUMENTATION_OPTIONS = {
            URL_ROOT:'./',
            VERSION:'2.1.27',
            COLLAPSE_INDEX:false,
            FILE_SUFFIX:'.html',
            HAS_SOURCE:  true
        };
    </script>
      <script type="text/javascript" src="_static/jquery.js"></script>
      <script type="text/javascript" src="_static/underscore.js"></script>
      <script type="text/javascript" src="_static/doctools.js"></script>
      <script type="text/javascript" src="https://cdn.mathjax.org/mathjax/latest/MathJax.js"></script>

  

  
  
    <script type="text/javascript" src="_static/js/theme.js"></script>
  

  
  
  <script type="text/javascript">
<!--      jQuery(function () {
          SphinxRtdTheme.StickyNav.enable();
      }); -->
  </script>
  
 



</body>
</html>PK�h%[vu,��$doc/alt-cyrus-sasl-lib/genindex.htmlnu�[���


<!DOCTYPE html>
<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
<head>
  <meta charset="utf-8">
  
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  
  <title>Index &mdash; Cyrus SASL 2.1.27 documentation</title>
  

  
  
    <link rel="shortcut icon" href="_static/favicon.ico"/>
  

  

  
  
    

  

  
  
    <link rel="stylesheet" href="_static/css/theme.css" type="text/css" />
  

  
    <link rel="stylesheet" href="_static/cyrus.css" type="text/css" />
  

  
        <link rel="index" title="Index"
              href="#"/>
        <link rel="search" title="Search" href="search.html"/>
    <link rel="top" title="Cyrus SASL 2.1.27 documentation" href="index.html"/> 

  
  
  

</head>

<body class="wy-body-for-nav" role="document">

  
  
<div class="pageheader">
  <ul>
    <li><a href="index.html">Home</a></li>
    <li><a href="http://www.cyrusimap.org">Cyrus IMAP</a></li>
    <li><a href="download.html">Download</a></li>
    <li><a href="contribute.html">Contribute</a></li>
  </ul>
  <div>
    <a href="index.html">
      <img src="_static/logo.gif" alt="CYRUS SASL" />
    </a>
  </div>
</div>
<div style="clear: both;"></div>


  <div class="wy-grid-for-nav">

    
    <nav data-toggle="wy-nav-shift" class="wy-nav-side">
      <div class="wy-side-nav-search">
        

        
 
          <a href="index.html">
 

  
          
          <img src="_static/logo.gif"  />
     
        </a>

        
<div role="search">
  <form id="rtd-search-form" class="wy-form" action="search.html" method="get">
    <input type="text" name="q" placeholder="Search docs" />
    <input type="hidden" name="check_keywords" value="yes" />
    <input type="hidden" name="area" value="default" />
  </form>
</div>

        
      </div>

      <div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
        
          
          
              <p class="caption"><span class="caption-text">Cyrus SASL</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="download.html">Download</a><ul>
<li class="toctree-l2"><a class="reference internal" href="getsasl.html">Get SASL</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html">Installation</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#quick-install-guide">Quick install guide</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#detailed-installation-guide">Detailed installation guide</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#supported-platforms">Supported platforms</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/release-notes/index.html">Release Notes</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/release-notes/index.html#supported-product-series">Supported Product Series</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/release-notes/index.html#series-2-1">Series 2.1</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/release-notes/index.html#older-versions">Older Versions</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/release-notes/index.html#series-2-2-0">Series 2: 2.0</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/release-notes/index.html#series-1">Series 1</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="packager.html">Note for Packagers</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="sasl/quickstart.html">Quickstart guide</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/quickstart.html#features">Features</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/quickstart.html#typical-installation">Typical Installation</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/quickstart.html#configuration">Configuration</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="sasl/concepts.html">Concepts</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#sasl">SASL</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#sasl-authentication-mechanisms">SASL Authentication Mechanisms</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#security-layers">Security Layers</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#channel-binding">Channel Binding</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#realms">Realms</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#protocols">Protocols</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#cyrus-sasl">Cyrus SASL</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#the-glue-library">The Glue Library</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#auxiliary-properties">Auxiliary Properties</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#plugins">Plugins</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="setup.html">Setup</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/installation.html">Installation</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html#quick-install-guide">Quick install guide</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#tarball-installation">Tarball installation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#unix-package-installation">Unix package Installation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#configuration">Configuration</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html#detailed-installation-guide">Detailed installation guide</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#requirements">Requirements</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#build-configuration">Build Configuration</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#building-and-installation">Building and Installation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#compilation-hints">Compilation Hints</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#application-configuration">Application Configuration</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html#supported-platforms">Supported platforms</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/upgrading.html">Upgrading from v1 to v2</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/upgrading.html#backwards-compatibility">Backwards Compatibility</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/upgrading.html#coexistence-with-saslv1">Coexistence with SASLv1</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/upgrading.html#database-upgrades">Database Upgrades</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/upgrading.html#errors-on-migration">Errors on migration</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/components.html">Components</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/components.html#the-application">The Application</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/components.html#the-sasl-glue-layer">The SASL Glue Layer</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/components.html#plugins">Plugins</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/components.html#plugins-general">Plugins: General</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/components.html#plugins-sasl-mechanisms">Plugins: SASL Mechanisms</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/components.html#plugins-auxiliary-property">Plugins: Auxiliary Property</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/components.html#plugins-username-canonicalization">Plugins: Username Canonicalization</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/components.html#password-verification-services">Password Verification Services</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/options.html">Options</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#sasl-library">SASL Library</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#auxiliary-property-plugin">Auxiliary Property Plugin</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#gssapi">GSSAPI</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#ldapdb">LDAPDB</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/options.html#notes-on-ldapdb">Notes on LDAPDB</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/options.html#examples">Examples</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#ntlm">NTLM</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#otp">OTP</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#digest-md5">Digest-md5</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#sasldb">SASLDB</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/options.html#notes-on-sasldb-with-lmdb">Notes on sasldb with LMDB</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#sql-plugin">SQL Plugin</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/options.html#notes-on-sql">Notes on SQL</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/options.html#id2">Examples</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#srp">SRP</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#kerberos-v4">Kerberos V4</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/advanced.html">Advanced Usage</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/advanced.html#notes-for-advanced-usage-of-libsasl">Notes for Advanced Usage of libsasl</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/advanced.html#using-cyrus-sasl-as-a-static-library">Using Cyrus SASL as a static library</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="operations.html">Operations</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/sysadmin.html">System Administrators</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#what-sasl-is">What SASL is</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#authentication-and-authorization-identifiers">Authentication and authorization identifiers</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#realms">Realms</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#how-sasl-works">How SASL works</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#the-plain-mechanism-sasl-checkpass-and-plaintext-passwords">The PLAIN mechanism, <code class="docutils literal"><span class="pre">sasl_checkpass()</span></code>, and plaintext passwords</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#shared-secrets-mechanisms">Shared secrets mechanisms</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#kerberos-mechanisms">Kerberos mechanisms</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#the-otp-mechanism">The OTP mechanism</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#auxiliary-properties">Auxiliary Properties</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#how-to-set-configuration-options">How to set configuration options</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#the-default-configuration-file">The default configuration file</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#application-configuration">Application configuration</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#troubleshooting">Troubleshooting</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/manpages.html">Man pages</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/manpages.html#library-files">(3) Library Files</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl.html"><strong>SASL</strong> - SASL Authentication Library</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_authorize_t.html"><strong>sasl_authorize_t</strong> - The SASL authorization callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_auxprop.html"><strong>sasl_auxprop</strong> - How to work with SASL auxiliary properties</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_auxprop_add_plugin.html"><strong>sasl_auxprop_add_plugin</strong> - add a SASL auxiliary property plugin</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_auxprop_getctx.html"><strong>sasl_auxprop_getctx</strong> - Acquire an auxiliary property context</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_auxprop_request.html"><strong>sasl_auxprop_request</strong> - Request auxiliary properties from SASL</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_callbacks.html"><strong>sasl_callbacks</strong> - How to work with SASL callbacks</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_canon_user_t.html"><strong>sasl_canon_user_t</strong> - Application-supplied user canonicalization function</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_canonuser_add_plugin.html"><strong>sasl_canonuser_add_plugin</strong> - add a SASL user canonicalization plugin</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_chalprompt_t.html"><strong>sasl_chalprompt_t</strong> - Realm acquisition callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_checkapop.html"><strong>sasl_checkapop</strong> - Check an APOP challenge/response</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_checkpass.html"><strong>sasl_checkpass</strong> - Check a plaintext password</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_add_plugin.html"><strong>sasl_client_add_plugin</strong> - add a SASL client plugin</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_done.html"><strong>sasl_client_done</strong> - Cleanup function</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_init.html"><strong>sasl_client_init</strong> - SASL client authentication initialization</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_new.html"><strong>sasl_client_new</strong> - Create a new client authentication object</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_plug_init_t.html"><strong>sasl_client_plug_init_t</strong> - client plug‐in entry point</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_start.html"><strong>sasl_client_start</strong> - Begin an authentication negotiation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_step.html"><strong>sasl_client_step</strong> - Perform a step in the authentication negotiation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_decode.html"><strong>sasl_decode</strong> - Decode data received</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_decode64.html"><strong>sasl_decode64</strong> - Decode base64 string</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_dispose.html"><strong>sasl_dispose</strong> - Dispose of a SASL connection object</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_done.html"><strong>sasl_done</strong> - Dispose of a SASL connection object</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_encode.html"><strong>sasl_encode</strong> - Encode data for transport to authenticated host</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_encode64.html"><strong>sasl_encode64</strong> - Encode base64 string</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_encodev.html"><strong>sasl_encodev</strong> - Encode data for transport to authenticated host</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_erasebuffer.html"><strong>sasl_erasebuffer</strong> - erase buffer</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_errdetail.html"><strong>sasl_errdetail</strong> - Retrieve  detailed information about an error</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_errors.html"><strong>sasl_errors</strong> - SASL error codes</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_errstring.html"><strong>sasl_errstring</strong> - Translate a SASL return code to a human-readable form</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getcallback_t.html"><strong>sasl_getcallback_t</strong> - callback function to lookup a sasl_callback_t for a connection</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getconfpath_t.html"><strong>sasl_getconfpath_t</strong> - The SASL callback to indicate location of the config files</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getopt_t.html"><strong>sasl_getopt_t</strong> - The SASL get option callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getpath_t.html"><strong>sasl_getpath_t</strong> - The SASL callback to indicate location of the mechanism drivers</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getprop.html"><strong>sasl_getprop</strong> - Get a SASL property</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getrealm_t.html"><strong>sasl_getrealm_t</strong> - Realm Acquisition Callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getsecret_t.html"><strong>sasl_getsecret_t</strong> - The SASL callback for secrets (passwords)</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getsimple_t.html"><strong>sasl_getsimple_t</strong> - The SASL callback for username/authname/realm</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_global_listmech.html"><strong>sasl_global_listmech</strong> - Retrieve a list of the supported SASL mechanisms</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_idle.html"><strong>sasl_idle</strong> - Perform precalculations during an idle period</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_listmech.html"><strong>sasl_listmech</strong> - Retrieve a list of the supported SASL mechanisms</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_log_t.html"><strong>sasl_log_t</strong> - The SASL logging callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_add_plugin.html"><strong>sasl_server_add_plugin</strong> - add a SASL server plugin</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_done.html"><strong>sasl_server_done</strong> - Cleanup function</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_init.html"><strong>sasl_server_init</strong> - SASL server authentication initialization</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_new.html"><strong>sasl_server_new</strong> - Create a new server authentication object</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_plug_init_t.html"><strong>sasl_server_plug_init_t</strong> - server plug‐in entry point</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_start.html"><strong>sasl_server_start</strong> - Begin an authentication negotiation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_step.html"><strong>sasl_server_step</strong> - Perform a step in the authentication negotiation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_userdb_checkpass_t.html"><strong>sasl_server_userdb_checkpass_t</strong> - Plaintext Password Verification Callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_userdb_setpass_t.html"><strong>sasl_server_userdb_setpass_t</strong> - UserDB Plaintext Password Setting Callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_set_alloc.html"><strong>sasl_set_alloc</strong> - set the memory allocation functions used by the SASL library</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_set_mutex.html"><strong>sasl_set_mutex</strong> - set the mutex lock functions used by the SASL library</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_seterror.html"><strong>sasl_seterror</strong> - set the error string</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_setpass.html"><strong>sasl_setpass</strong> - Check a plaintext password</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_setprop.html"><strong>sasl_setprop</strong> - Set a SASL property</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_user_exists.html"><strong>sasl_user_exists</strong> - Check if a user exists on server</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_usererr.html"><strong>sasl_usererr</strong> - Remove information leak about accounts from sasl error codes</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_utf8verify.html"><strong>sasl_utf8verify</strong> - Verify a string is valid utf8</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_verifyfile_t.html"><strong>sasl_verifyfile_t</strong> - The SASL file verification</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/auxiliary_properties.html">Auxiliary Properties</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#auxiliary-properties-and-the-glue-layer">Auxiliary Properties and the Glue Layer</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#passwords-and-other-data">Passwords and other Data</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#sasldb">sasldb</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#ldapdb">ldapdb</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#sql">sql</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#user-canonicalization">User Canonicalization</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/authentication_mechanisms.html">Authentication Mechanisms</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/authentication_mechanisms.html#mechanisms">Mechanisms</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#anonymous">ANONYMOUS</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#cram-md5">CRAM-MD5</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#digest-md5">DIGEST-MD5</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#external">EXTERNAL</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#g2">G2</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#gssapi">GSSAPI</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#gss-spegno">GSS-SPEGNO</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#kerberos-v4">KERBEROS_V4</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#login">LOGIN</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#ntlm">NTLM</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#otp">OTP</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#passdss">PASSDSS</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#plain">PLAIN</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#scram">SCRAM</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#srp">SRP</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#non-sasl-authentication">Non-SASL Authentication</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/authentication_mechanisms.html#summary">Summary</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/pwcheck.html">Pwcheck</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#auxprop">Auxprop</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#auxprop-hashed">Auxprop-hashed</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#saslauthd">Saslauthd</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#authdaemon">Authdaemon</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#alwaystrue">Alwaystrue</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#auto-transition">Auto Transition</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/faq.html">Frequently Asked Questions</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/authorize-vs-authenticate.html">What is the difference between an Authorization ID and a Authentication ID?</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/crammd5-digestmd5.html">Why do CRAM-MD5 and DIGEST-MD5 not work with CyrusSaslauthd?</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/openldap-sasl-gssapi.html">How do I configure OpenLDAP +SASL+GSSAPI?</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/plaintextpasswords.html">Why does CyrusSasl store plaintext passwords in its databases?</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/rfcs.html">RFCs and drafts</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/upgrade-saslv2.html">Why am I having a problem running dbconverter-2 to upgrade from SASLv1 to SASLv2?</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/resources.html">Other Documentation &amp; Resources</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="developer.html">Developers</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/appconvert.html">Converting Applications from v1 to v2</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/appconvert.html#tips-for-both-clients-and-servers">Tips for both clients and servers</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/appconvert.html#tips-for-clients">Tips for clients</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/appconvert.html#tips-for-servers">Tips for Servers</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/developer/programming.html">Application Programmer’s Guide</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#introduction">Introduction</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#about-this-guide">About this Guide</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#what-is-sasl">What is SASL?</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#background">Background</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#how-did-the-world-work-before-sasl">How did the world work before SASL?</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#sasl-to-the-rescue">SASL to the rescue!</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#briefly">Briefly</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#what-is-the-cyrus-sasl-library-good-for">What is the Cyrus SASL library good for?</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#what-does-the-cyrus-sasl-library-do">What does the Cyrus SASL library do?</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#what-doesn-t-the-cyrus-sasl-library-do">What doesn’t the Cyrus SASL library do?</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#client-only-section">Client-only Section</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#a-typical-interaction-from-the-client-s-perspective">A typical interaction from the client’s perspective</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#how-does-this-look-in-code">How does this look in code</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#server-only-section">Server-only Section</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#a-typical-interaction-from-the-server-s-perspective">A typical interaction from the server’s perspective</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#id1">How does this look in code?</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#common-section">Common Section</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#callbacks-and-interactions">Callbacks and Interactions</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#security-layers">Security layers</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#example-applications-that-come-with-the-cyrus-sasl-library">Example applications that come with the Cyrus SASL library</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#sample-client-and-sample-server"><cite>sample-client</cite> and <cite>sample-server</cite></a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#cyrus-imapd-v2-1-0-or-later">Cyrus imapd v2.1.0 or later</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#imtest-from-cyrus-2-1-0-or-later"><cite>imtest</cite>, from Cyrus 2.1.0 or later</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#miscellaneous-information">Miscellaneous Information</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#empty-exchanges">Empty exchanges</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#idle">Idle</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/developer/plugprog.html">Plugin Programmer’s Guide</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#introduction">Introduction</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#about-this-guide">About this Guide</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#what-is-sasl">What is SASL?</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#common-section">Common Section</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#overview-of-plugin-programming">Overview of Plugin Programming</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#use-of-sasl-utils-t">Use of sasl_utils_t</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#error-reporting">Error Reporting</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#memory-allocation">Memory Allocation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#client-send-first-server-send-last">Client Send First / Server Send Last</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#client-plugins">Client Plugins</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#server-plugins">Server Plugins</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#user-canonicalization-canon-user-plugins">User Canonicalization (canon_user) Plugins</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#auxiliary-property-auxprop-plugins">Auxiliary Property (auxprop) Plugins</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/developer/testing.html">Testing</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/testing.html#testing-the-cmu-sasl-library-with-the-included-sample-applications">Testing the CMU SASL Library with the included sample applications</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/testing.html#example">Example</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/testing.html#running-the-testsuite-application">Running the Testsuite application</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="support.html">Support/Community</a></li>
</ul>
<p class="caption"><span class="caption-text">IMAP</span></p>
<ul>
<li class="toctree-l1"><a class="reference external" href="http://www.cyrusimap.org">Cyrus IMAP</a></li>
</ul>

          
        
      </div>
      &nbsp;
    </nav>

    <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">

      
      <nav class="wy-nav-top" role="navigation" aria-label="top navigation">
        <i data-toggle="wy-nav-top" class="fa fa-bars"></i>
        <a href="index.html">Cyrus SASL</a>
      </nav>


      
      <div class="wy-nav-content">
        <div class="rst-content">
          
          <div role="navigation" aria-label="breadcrumbs navigation">
  <ul class="wy-breadcrumbs">
      <li><a href="index.html">Docs v2.1.27</a> &raquo;</li>
      
    <li>Index</li>
      <li class="wy-breadcrumbs-aside">
        
          
            <a href="https://github.com/cyrusimap/cyrus-sasl/blob/master/docsrc/genindex.rst" class="fa fa-github"> Edit on GitHub</a>
          
        
      </li>
  </ul>
  <hr/>
</div>
          <div role="main" class="document">
            

<h1 id="index">Index</h1>

<div class="genindex-jumpbox">
 <a href="#Symbols"><strong>Symbols</strong></a>
 | <a href="#A"><strong>A</strong></a>
 | <a href="#C"><strong>C</strong></a>
 | <a href="#K"><strong>K</strong></a>
 | <a href="#L"><strong>L</strong></a>
 | <a href="#M"><strong>M</strong></a>
 | <a href="#N"><strong>N</strong></a>
 | <a href="#O"><strong>O</strong></a>
 | <a href="#P"><strong>P</strong></a>
 | <a href="#R"><strong>R</strong></a>
 | <a href="#S"><strong>S</strong></a>
 
</div>
<h2 id="Symbols">Symbols</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
  <td style="width: 33%; vertical-align: top;"><ul>
      <li>
    -C config-file

      <ul>
        <li><a href="sasl/reference/manpages/template.html#cmdoption-cmd-c">CMD command line option</a>
</li>
      </ul></li>
  </ul></td>
</tr></table>

<h2 id="A">A</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
  <td style="width: 33%; vertical-align: top;"><ul>
      <li>
    authdaemon_path [&lt;path&gt;]

      <ul>
        <li><a href="sasl/options.html#cmdoption-arg-authdaemon-path">command line option</a>
</li>
      </ul></li>
      <li>
    auto_transition [yes|noplain|no]

      <ul>
        <li><a href="sasl/options.html#cmdoption-arg-auto-transition">command line option</a>
</li>
      </ul></li>
  </ul></td>
  <td style="width: 33%; vertical-align: top;"><ul>
      <li>
    auxprop_plugin [&lt;list of plugin names&gt;]

      <ul>
        <li><a href="sasl/options.html#cmdoption-arg-auxprop-plugin">command line option</a>
</li>
      </ul></li>
  </ul></td>
</tr></table>

<h2 id="C">C</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
  <td style="width: 33%; vertical-align: top;"><ul>
      <li>
    canon_user_plugin [&lt;name&gt;]

      <ul>
        <li><a href="sasl/options.html#cmdoption-arg-canon-user-plugin">command line option</a>
</li>
      </ul></li>
      <li>
    CMD command line option

      <ul>
        <li><a href="sasl/reference/manpages/template.html#cmdoption-cmd-c">-C config-file</a>
</li>
      </ul></li>
      <li><a href="sasl/reference/manpages/template.html#std:saslman-CMDNAME(3)">CMDNAME(3)</a>
</li>
      <li>
    command line option

      <ul>
        <li><a href="sasl/options.html#cmdoption-arg-authdaemon-path">authdaemon_path [&lt;path&gt;]</a>
</li>
        <li><a href="sasl/options.html#cmdoption-arg-auto-transition">auto_transition [yes|noplain|no]</a>
</li>
        <li><a href="sasl/options.html#cmdoption-arg-auxprop-plugin">auxprop_plugin [&lt;list of plugin names&gt;]</a>
</li>
        <li><a href="sasl/options.html#cmdoption-arg-canon-user-plugin">canon_user_plugin [&lt;name&gt;]</a>
</li>
        <li><a href="sasl/options.html#cmdoption-arg-keytab">keytab [&lt;path&gt;]</a>
</li>
        <li><a href="sasl/options.html#cmdoption-arg-ldapdb-canon-attr">ldapdb_canon_attr [&lt;user&#39;s canonical name&gt;]</a>
</li>
        <li><a href="sasl/options.html#cmdoption-arg-ldapdb-id">ldapdb_id [&lt;auth id&gt;]</a>
</li>
        <li><a href="sasl/options.html#cmdoption-arg-ldapdb-mech">ldapdb_mech [&lt;mechanism&gt;]</a>
</li>
        <li><a href="sasl/options.html#cmdoption-arg-ldapdb-pw">ldapdb_pw [&lt;password&gt;]</a>
</li>
        <li><a href="sasl/options.html#cmdoption-arg-ldapdb-rc">ldapdb_rc [&lt;filename&gt;]</a>
</li>
        <li><a href="sasl/options.html#cmdoption-arg-ldapdb-starttls">ldapdb_starttls [try|demand]</a>
</li>
        <li><a href="sasl/options.html#cmdoption-arg-ldapdb-uri">ldapdb_uri [&lt;list of URIs&gt;]</a>
</li>
        <li><a href="sasl/options.html#cmdoption-arg-log-level">log_level [&lt;numeric log level&gt;]</a>
</li>
        <li><a href="sasl/options.html#cmdoption-arg-mech-list">mech_list [&lt;mechanism list&gt;]</a>
</li>
        <li><a href="sasl/options.html#cmdoption-arg-ntlm-server">ntlm_server [&lt;list of server names&gt;]</a>
</li>
        <li><a href="sasl/options.html#cmdoption-arg-ntlm-v2">ntlm_v2 [yes|no]</a>
</li>
        <li><a href="sasl/options.html#cmdoption-arg-opiekeys">opiekeys [&lt;path&gt;]</a>
</li>
        <li><a href="sasl/options.html#cmdoption-arg-otp-mda">otp_mda [md4 | md5 | sha1]</a>
</li>
        <li><a href="sasl/options.html#cmdoption-arg-plugin-list">plugin_list [&lt;path&gt;]</a>
</li>
        <li><a href="sasl/options.html#cmdoption-arg-pwcheck-method">pwcheck_method [&lt;list of mechanisms&gt;]</a>
</li>
        <li><a href="sasl/options.html#cmdoption-arg-reauth-timeout">reauth_timeout [&lt;minutes&gt;]</a>
</li>
        <li><a href="sasl/options.html#cmdoption-arg-saslauthd-path">saslauthd_path [&lt;path&gt;]</a>
</li>
        <li><a href="sasl/options.html#cmdoption-arg-sasldb-mapsize">sasldb_mapsize [&lt;size in bytes&gt;]</a>
</li>
        <li><a href="sasl/options.html#cmdoption-arg-sasldb-maxreaders">sasldb_maxreaders [&lt;max threads&gt;]</a>
</li>
        <li><a href="sasl/options.html#cmdoption-arg-sasldb-path">sasldb_path [&lt;path to sasldb file&gt;]</a>
</li>
        <li><a href="sasl/options.html#cmdoption-arg-sql-database">sql_database &lt;database name&gt;</a>
</li>
        <li><a href="sasl/options.html#cmdoption-arg-sql-engine">sql_engine [&lt;name&gt;]</a>
</li>
        <li><a href="sasl/options.html#cmdoption-arg-sql-hostnames">sql_hostnames [&lt;list of SQL servers&gt;]</a>
</li>
        <li><a href="sasl/options.html#cmdoption-arg-sql-insert">sql_insert &lt;statement&gt;</a>
</li>
        <li><a href="sasl/options.html#cmdoption-arg-sql-passwd">sql_passwd &lt;password&gt;</a>
</li>
        <li><a href="sasl/options.html#cmdoption-arg-sql-select">sql_select &lt;statement&gt;</a>
</li>
        <li><a href="sasl/options.html#cmdoption-arg-sql-update">sql_update &lt;statement&gt;</a>
</li>
        <li><a href="sasl/options.html#cmdoption-arg-sql-user">sql_user &lt;username&gt;</a>
</li>
        <li><a href="sasl/options.html#cmdoption-arg-srp-mda">srp_mda [md5 | sha1 | rmd160]</a>
</li>
        <li><a href="sasl/options.html#cmdoption-arg-srvtab">srvtab [&lt;path&gt;]</a>
</li>
      </ul></li>
  </ul></td>
</tr></table>

<h2 id="K">K</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
  <td style="width: 33%; vertical-align: top;"><ul>
      <li>
    keytab [&lt;path&gt;]

      <ul>
        <li><a href="sasl/options.html#cmdoption-arg-keytab">command line option</a>
</li>
      </ul></li>
  </ul></td>
</tr></table>

<h2 id="L">L</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
  <td style="width: 33%; vertical-align: top;"><ul>
      <li>
    ldapdb_canon_attr [&lt;user&#39;s canonical name&gt;]

      <ul>
        <li><a href="sasl/options.html#cmdoption-arg-ldapdb-canon-attr">command line option</a>
</li>
      </ul></li>
      <li>
    ldapdb_id [&lt;auth id&gt;]

      <ul>
        <li><a href="sasl/options.html#cmdoption-arg-ldapdb-id">command line option</a>
</li>
      </ul></li>
      <li>
    ldapdb_mech [&lt;mechanism&gt;]

      <ul>
        <li><a href="sasl/options.html#cmdoption-arg-ldapdb-mech">command line option</a>
</li>
      </ul></li>
      <li>
    ldapdb_pw [&lt;password&gt;]

      <ul>
        <li><a href="sasl/options.html#cmdoption-arg-ldapdb-pw">command line option</a>
</li>
      </ul></li>
  </ul></td>
  <td style="width: 33%; vertical-align: top;"><ul>
      <li>
    ldapdb_rc [&lt;filename&gt;]

      <ul>
        <li><a href="sasl/options.html#cmdoption-arg-ldapdb-rc">command line option</a>
</li>
      </ul></li>
      <li>
    ldapdb_starttls [try|demand]

      <ul>
        <li><a href="sasl/options.html#cmdoption-arg-ldapdb-starttls">command line option</a>
</li>
      </ul></li>
      <li>
    ldapdb_uri [&lt;list of URIs&gt;]

      <ul>
        <li><a href="sasl/options.html#cmdoption-arg-ldapdb-uri">command line option</a>
</li>
      </ul></li>
      <li>
    log_level [&lt;numeric log level&gt;]

      <ul>
        <li><a href="sasl/options.html#cmdoption-arg-log-level">command line option</a>
</li>
      </ul></li>
  </ul></td>
</tr></table>

<h2 id="M">M</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
  <td style="width: 33%; vertical-align: top;"><ul>
      <li>
    mech_list [&lt;mechanism list&gt;]

      <ul>
        <li><a href="sasl/options.html#cmdoption-arg-mech-list">command line option</a>
</li>
      </ul></li>
  </ul></td>
</tr></table>

<h2 id="N">N</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
  <td style="width: 33%; vertical-align: top;"><ul>
      <li>
    ntlm_server [&lt;list of server names&gt;]

      <ul>
        <li><a href="sasl/options.html#cmdoption-arg-ntlm-server">command line option</a>
</li>
      </ul></li>
  </ul></td>
  <td style="width: 33%; vertical-align: top;"><ul>
      <li>
    ntlm_v2 [yes|no]

      <ul>
        <li><a href="sasl/options.html#cmdoption-arg-ntlm-v2">command line option</a>
</li>
      </ul></li>
  </ul></td>
</tr></table>

<h2 id="O">O</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
  <td style="width: 33%; vertical-align: top;"><ul>
      <li>
    opiekeys [&lt;path&gt;]

      <ul>
        <li><a href="sasl/options.html#cmdoption-arg-opiekeys">command line option</a>
</li>
      </ul></li>
  </ul></td>
  <td style="width: 33%; vertical-align: top;"><ul>
      <li>
    otp_mda [md4 | md5 | sha1]

      <ul>
        <li><a href="sasl/options.html#cmdoption-arg-otp-mda">command line option</a>
</li>
      </ul></li>
  </ul></td>
</tr></table>

<h2 id="P">P</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
  <td style="width: 33%; vertical-align: top;"><ul>
      <li>
    plugin_list [&lt;path&gt;]

      <ul>
        <li><a href="sasl/options.html#cmdoption-arg-plugin-list">command line option</a>
</li>
      </ul></li>
      <li><a href="sasl/reference/manpages/library/sasl_auxprop.html#c.prop_clear">prop_clear (C function)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_auxprop.html#c.prop_dispose">prop_dispose (C function)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_auxprop.html#c.prop_dup">prop_dup (C function)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_auxprop.html#c.prop_erase">prop_erase (C function)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_auxprop.html#c.prop_format">prop_format (C function)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_auxprop.html#c.prop_get">prop_get (C function)</a>
</li>
  </ul></td>
  <td style="width: 33%; vertical-align: top;"><ul>
      <li><a href="sasl/reference/manpages/library/sasl_auxprop.html#c.prop_getnames">prop_getnames (C function)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_auxprop.html#c.prop_new">prop_new (C function)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_auxprop.html#c.prop_request">prop_request (C function)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_auxprop.html#c.prop_set">prop_set (C function)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_auxprop.html#c.prop_setvals">prop_setvals (C function)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_auxprop.html#c.propctx">propctx (C type)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_auxprop.html#c.propval">propval (C type)</a>
</li>
      <li>
    pwcheck_method [&lt;list of mechanisms&gt;]

      <ul>
        <li><a href="sasl/options.html#cmdoption-arg-pwcheck-method">command line option</a>
</li>
      </ul></li>
  </ul></td>
</tr></table>

<h2 id="R">R</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
  <td style="width: 33%; vertical-align: top;"><ul>
      <li>
    reauth_timeout [&lt;minutes&gt;]

      <ul>
        <li><a href="sasl/options.html#cmdoption-arg-reauth-timeout">command line option</a>
</li>
      </ul></li>
      <li>
    RFC

      <ul>
        <li><a href="sasl/reference/manpages/library/sasl_errstring.html#index-0">RFC 1766</a>, <a href="sasl/reference/manpages/library/sasl_getsimple_t.html#index-0">[1]</a>
</li>
        <li><a href="sasl/reference/manpages/library/sasl_checkapop.html#index-0">RFC 1939</a>, <a href="sasl/reference/manpages/library/sasl_checkapop.html#index-2">[1]</a>
</li>
        <li><a href="sasl/faqs/rfcs.html#index-13">RFC 1939#page-15</a>
</li>
        <li><a href="sasl/developer/programming.html#index-0">RFC 2222</a>, <a href="sasl/developer/programming.html#index-1">[1]</a>, <a href="sasl/reference/manpages/library/sasl.html#index-0">[2]</a>
</li>
        <li><a href="sasl/faqs/rfcs.html#index-12">RFC 2222#section-7.1</a>
</li>
        <li><a href="sasl/faqs/rfcs.html#index-8">RFC 2444</a>
</li>
        <li><a href="sasl/reference/manpages/library/sasl_seterror.html#index-0">RFC 2482</a>, <a href="sasl/reference/manpages/library/sasl_seterror.html#index-1">[1]</a>
</li>
        <li><a href="sasl/faqs/rfcs.html#index-9">RFC 2808</a>
</li>
        <li><a href="sasl/faqs/rfcs.html#index-10">RFC 2831</a>
</li>
        <li><a href="sasl/faqs/rfcs.html#index-0">RFC 4422</a>, <a href="sasl/reference/manpages/library/sasl_auxprop.html#index-0">[1]</a>, <a href="sasl/reference/manpages/library/sasl_auxprop_add_plugin.html#index-0">[2]</a>, <a href="sasl/reference/manpages/library/sasl_auxprop_getctx.html#index-0">[3]</a>, <a href="sasl/reference/manpages/library/sasl_auxprop_request.html#index-0">[4]</a>, <a href="sasl/reference/manpages/library/sasl_callbacks.html#index-0">[5]</a>, <a href="sasl/reference/manpages/library/sasl_canon_user_t.html#index-0">[6]</a>, <a href="sasl/reference/manpages/library/sasl_canonuser_add_plugin.html#index-0">[7]</a>, <a href="sasl/reference/manpages/library/sasl_checkapop.html#index-1">[8]</a>, <a href="sasl/reference/manpages/library/sasl_checkpass.html#index-0">[9]</a>, <a href="sasl/reference/manpages/library/sasl_client_add_plugin.html#index-0">[10]</a>, <a href="sasl/reference/manpages/library/sasl_client_done.html#index-0">[11]</a>, <a href="sasl/reference/manpages/library/sasl_client_init.html#index-0">[12]</a>, <a href="sasl/reference/manpages/library/sasl_client_new.html#index-0">[13]</a>, <a href="sasl/reference/manpages/library/sasl_client_plug_init_t.html#index-0">[14]</a>, <a href="sasl/reference/manpages/library/sasl_client_start.html#index-0">[15]</a>, <a href="sasl/reference/manpages/library/sasl_client_step.html#index-0">[16]</a>, <a href="sasl/reference/manpages/library/sasl_decode.html#index-0">[17]</a>, <a href="sasl/reference/manpages/library/sasl_decode64.html#index-0">[18]</a>, <a href="sasl/reference/manpages/library/sasl_dispose.html#index-0">[19]</a>, <a href="sasl/reference/manpages/library/sasl_done.html#index-0">[20]</a>, <a href="sasl/reference/manpages/library/sasl_encode.html#index-0">[21]</a>, <a href="sasl/reference/manpages/library/sasl_encode64.html#index-0">[22]</a>, <a href="sasl/reference/manpages/library/sasl_encodev.html#index-0">[23]</a>, <a href="sasl/reference/manpages/library/sasl_errdetail.html#index-0">[24]</a>, <a href="sasl/reference/manpages/library/sasl_errors.html#index-0">[25]</a>, <a href="sasl/reference/manpages/library/sasl_errstring.html#index-1">[26]</a>, <a href="sasl/reference/manpages/library/sasl_getcallback_t.html#index-0">[27]</a>, <a href="sasl/reference/manpages/library/sasl_getconfpath_t.html#index-0">[28]</a>, <a href="sasl/reference/manpages/library/sasl_getopt_t.html#index-0">[29]</a>, <a href="sasl/reference/manpages/library/sasl_getpath_t.html#index-0">[30]</a>, <a href="sasl/reference/manpages/library/sasl_getprop.html#index-0">[31]</a>, <a href="sasl/reference/manpages/library/sasl_getrealm_t.html#index-0">[32]</a>, <a href="sasl/reference/manpages/library/sasl_getsecret_t.html#index-0">[33]</a>, <a href="sasl/reference/manpages/library/sasl_getsimple_t.html#index-1">[34]</a>, <a href="sasl/reference/manpages/library/sasl_global_listmech.html#index-0">[35]</a>, <a href="sasl/reference/manpages/library/sasl_idle.html#index-0">[36]</a>, <a href="sasl/reference/manpages/library/sasl_listmech.html#index-0">[37]</a>, <a href="sasl/reference/manpages/library/sasl_log_t.html#index-0">[38]</a>, <a href="sasl/reference/manpages/library/sasl_server_add_plugin.html#index-0">[39]</a>, <a href="sasl/reference/manpages/library/sasl_server_done.html#index-0">[40]</a>, <a href="sasl/reference/manpages/library/sasl_server_init.html#index-0">[41]</a>, <a href="sasl/reference/manpages/library/sasl_server_new.html#index-0">[42]</a>, <a href="sasl/reference/manpages/library/sasl_server_plug_init_t.html#index-0">[43]</a>, <a href="sasl/reference/manpages/library/sasl_server_start.html#index-0">[44]</a>, <a href="sasl/reference/manpages/library/sasl_server_step.html#index-0">[45]</a>, <a href="sasl/reference/manpages/library/sasl_server_userdb_checkpass_t.html#index-0">[46]</a>, <a href="sasl/reference/manpages/library/sasl_server_userdb_setpass_t.html#index-0">[47]</a>, <a href="sasl/reference/manpages/library/sasl_setpass.html#index-0">[48]</a>, <a href="sasl/reference/manpages/library/sasl_setprop.html#index-0">[49]</a>, <a href="sasl/reference/manpages/library/sasl_user_exists.html#index-0">[50]</a>, <a href="sasl/reference/manpages/library/sasl_usererr.html#index-0">[51]</a>, <a href="sasl/reference/manpages/library/sasl_verifyfile_t.html#index-0">[52]</a>
</li>
        <li><a href="sasl/faqs/rfcs.html#index-3">RFC 4505</a>
</li>
        <li><a href="sasl/faqs/rfcs.html#index-4">RFC 4616</a>
</li>
        <li><a href="sasl/faqs/rfcs.html#index-5">RFC 4752</a>
</li>
        <li><a href="sasl/faqs/rfcs.html#index-2">RFC 4846#section-4</a>
</li>
        <li><a href="sasl/faqs/rfcs.html#index-6">RFC 5801</a>
</li>
        <li><a href="sasl/faqs/rfcs.html#index-7">RFC 5802</a>
</li>
        <li><a href="sasl/faqs/rfcs.html#index-11">RFC 6331</a>
</li>
        <li><a href="sasl/faqs/rfcs.html#index-1">RFC 7613</a>
</li>
      </ul></li>
  </ul></td>
</tr></table>

<h2 id="S">S</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
  <td style="width: 33%; vertical-align: top;"><ul>
      <li><a href="sasl/reference/manpages/library/sasl.html#std:saslman-sasl(3)">sasl(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_authorize_t.html#std:saslman-sasl_authorize_t(3)">sasl_authorize_t(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_auxprop.html#std:saslman-sasl_auxprop(3)">sasl_auxprop(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_auxprop_add_plugin.html#std:saslman-sasl_auxprop_add_plugin(3)">sasl_auxprop_add_plugin(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_auxprop_getctx.html#c.sasl_auxprop_getctx">sasl_auxprop_getctx (C function)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_auxprop_getctx.html#std:saslman-sasl_auxprop_getctx(3)">sasl_auxprop_getctx(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_auxprop_request.html#c.sasl_auxprop_request">sasl_auxprop_request (C function)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_auxprop_request.html#std:saslman-sasl_auxprop_request(3)">sasl_auxprop_request(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_errors.html#c.SASL_BADAUTH">SASL_BADAUTH (C macro)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_errors.html#c.SASL_BADMAC">SASL_BADMAC (C macro)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_errors.html#c.SASL_BADPARAM">SASL_BADPARAM (C macro)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_errors.html#c.SASL_BADPROT">SASL_BADPROT (C macro)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_errors.html#c.SASL_BADSERV">SASL_BADSERV (C macro)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_errors.html#c.SASL_BADVERS">SASL_BADVERS (C macro)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_errors.html#c.SASL_BUFOVER">SASL_BUFOVER (C macro)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_callbacks.html#std:saslman-sasl_callbacks(3)">sasl_callbacks(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_canon_user_t.html#std:saslman-sasl_canon_user_t(3)">sasl_canon_user_t(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_canonuser_add_plugin.html#std:saslman-sasl_canonuser_add_plugin(3)">sasl_canonuser_add_plugin(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_chalprompt_t.html#std:saslman-sasl_chalprompt_t(3)">sasl_chalprompt_t(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_checkapop.html#std:saslman-sasl_checkapop(3)">sasl_checkapop(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_checkpass.html#std:saslman-sasl_checkpass(3)">sasl_checkpass(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_client_add_plugin.html#std:saslman-sasl_client_add_plugin(3)">sasl_client_add_plugin(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_client_done.html#std:saslman-sasl_client_done(3)">sasl_client_done(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_client_init.html#std:saslman-sasl_client_init(3)">sasl_client_init(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_client_new.html#std:saslman-sasl_client_new(3)">sasl_client_new(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_client_plug_init_t.html#std:saslman-sasl_client_plug_init_t(3)">sasl_client_plug_init_t(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_client_start.html#std:saslman-sasl_client_start(3)">sasl_client_start(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_client_step.html#std:saslman-sasl_client_step(3)">sasl_client_step(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_auxprop_getctx.html#c.sasl_conn_t">sasl_conn_t (C type)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_errors.html#c.SASL_CONTINUE">SASL_CONTINUE (C macro)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_decode.html#std:saslman-sasl_decode(3)">sasl_decode(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_decode64.html#std:saslman-sasl_decode64(3)">sasl_decode64(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_errors.html#c.SASL_DISABLED">SASL_DISABLED (C macro)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_dispose.html#std:saslman-sasl_dispose(3)">sasl_dispose(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_done.html#std:saslman-sasl_done(3)">sasl_done(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_encode.html#std:saslman-sasl_encode(3)">sasl_encode(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_encode64.html#std:saslman-sasl_encode64(3)">sasl_encode64(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_encodev.html#std:saslman-sasl_encodev(3)">sasl_encodev(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_errors.html#c.SASL_ENCRYPT">SASL_ENCRYPT (C macro)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_erasebuffer.html#std:saslman-sasl_erasebuffer(3)">sasl_erasebuffer(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_errdetail.html#std:saslman-sasl_errdetail(3)">sasl_errdetail(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_errors.html#std:saslman-sasl_errors(3)">sasl_errors(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_errstring.html#std:saslman-sasl_errstring(3)">sasl_errstring(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_errors.html#c.SASL_EXPIRED">SASL_EXPIRED (C macro)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_errors.html#c.SASL_FAIL">SASL_FAIL (C macro)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_getcallback_t.html#std:saslman-sasl_getcallback_t(3)">sasl_getcallback_t(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_getconfpath_t.html#std:saslman-sasl_getconfpath_t(3)">sasl_getconfpath_t(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_getopt_t.html#std:saslman-sasl_getopt_t(3)">sasl_getopt_t(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_getpath_t.html#std:saslman-sasl_getpath_t(3)">sasl_getpath_t(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_getprop.html#std:saslman-sasl_getprop(3)">sasl_getprop(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_getrealm_t.html#std:saslman-sasl_getrealm_t(3)">sasl_getrealm_t(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_getsecret_t.html#std:saslman-sasl_getsecret_t(3)">sasl_getsecret_t(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_getsimple_t.html#std:saslman-sasl_getsimple_t(3)">sasl_getsimple_t(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_global_listmech.html#std:saslman-sasl_global_listmech(3)">sasl_global_listmech(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_idle.html#c.sasl_idle">sasl_idle (C function)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_idle.html#std:saslman-sasl_idle(3)">sasl_idle(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_errors.html#c.SASL_INTERACT">SASL_INTERACT (C macro)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_listmech.html#std:saslman-sasl_listmech(3)">sasl_listmech(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_log_t.html#std:saslman-sasl_log_t(3)">sasl_log_t(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_errors.html#c.SASL_NOAUTHZ">SASL_NOAUTHZ (C macro)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_errors.html#c.SASL_NOCHANGE">SASL_NOCHANGE (C macro)</a>
</li>
  </ul></td>
  <td style="width: 33%; vertical-align: top;"><ul>
      <li><a href="sasl/reference/manpages/library/sasl_errors.html#c.SASL_NOMECH">SASL_NOMECH (C macro)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_errors.html#c.SASL_NOMEM">SASL_NOMEM (C macro)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_errors.html#c.SASL_NOTDONE">SASL_NOTDONE (C macro)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_errors.html#c.SASL_NOTINIT">SASL_NOTINIT (C macro)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_errors.html#c.SASL_NOUSER">SASL_NOUSER (C macro)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_errors.html#c.SASL_NOUSERPASS">SASL_NOUSERPASS (C macro)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_errors.html#c.SASL_NOVERIFY">SASL_NOVERIFY (C macro)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_errors.html#c.SASL_OK">SASL_OK (C macro)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_errors.html#c.SASL_PWLOCK">SASL_PWLOCK (C macro)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_server_add_plugin.html#std:saslman-sasl_server_add_plugin(3)">sasl_server_add_plugin(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_server_done.html#std:saslman-sasl_server_done(3)">sasl_server_done(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_server_init.html#std:saslman-sasl_server_init(3)">sasl_server_init(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_server_new.html#std:saslman-sasl_server_new(3)">sasl_server_new(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_server_plug_init_t.html#std:saslman-sasl_server_plug_init_t(3)">sasl_server_plug_init_t(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_server_start.html#std:saslman-sasl_server_start(3)">sasl_server_start(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_server_step.html#std:saslman-sasl_server_step(3)">sasl_server_step(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_server_userdb_checkpass_t.html#std:saslman-sasl_server_userdb_checkpass_t(3)">sasl_server_userdb_checkpass_t(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_server_userdb_setpass_t.html#std:saslman-sasl_server_userdb_setpass_t(3)">sasl_server_userdb_setpass_t(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_set_alloc.html#std:saslman-sasl_set_alloc(3)">sasl_set_alloc(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_set_mutex.html#std:saslman-sasl_set_mutex(3)">sasl_set_mutex(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_seterror.html#std:saslman-sasl_seterror(3)">sasl_seterror(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_setpass.html#std:saslman-sasl_setpass(3)">sasl_setpass(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_setprop.html#std:saslman-sasl_setprop(3)">sasl_setprop(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_errors.html#c.SASL_TOOWEAK">SASL_TOOWEAK (C macro)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_errors.html#c.SASL_TRANS">SASL_TRANS (C macro)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_errors.html#c.SASL_TRYAGAIN">SASL_TRYAGAIN (C macro)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_user_exists.html#std:saslman-sasl_user_exists(3)">sasl_user_exists(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_usererr.html#c.sasl_usererr">sasl_usererr (C function)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_usererr.html#std:saslman-sasl_usererr(3)">sasl_usererr(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_utf8verify.html#std:saslman-sasl_utf8verify(3)">sasl_utf8verify(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_verifyfile_t.html#std:saslman-sasl_verifyfile_t(3)">sasl_verifyfile_t(3)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_errors.html#c.SASL_WEAKPASS">SASL_WEAKPASS (C macro)</a>
</li>
      <li><a href="sasl/reference/manpages/library/sasl_errors.html#c.SASL_WRONGMECH">SASL_WRONGMECH (C macro)</a>
</li>
      <li>
    saslauthd_path [&lt;path&gt;]

      <ul>
        <li><a href="sasl/options.html#cmdoption-arg-saslauthd-path">command line option</a>
</li>
      </ul></li>
      <li>
    sasldb_mapsize [&lt;size in bytes&gt;]

      <ul>
        <li><a href="sasl/options.html#cmdoption-arg-sasldb-mapsize">command line option</a>
</li>
      </ul></li>
      <li>
    sasldb_maxreaders [&lt;max threads&gt;]

      <ul>
        <li><a href="sasl/options.html#cmdoption-arg-sasldb-maxreaders">command line option</a>
</li>
      </ul></li>
      <li>
    sasldb_path [&lt;path to sasldb file&gt;]

      <ul>
        <li><a href="sasl/options.html#cmdoption-arg-sasldb-path">command line option</a>
</li>
      </ul></li>
      <li>
    sql_database &lt;database name&gt;

      <ul>
        <li><a href="sasl/options.html#cmdoption-arg-sql-database">command line option</a>
</li>
      </ul></li>
      <li>
    sql_engine [&lt;name&gt;]

      <ul>
        <li><a href="sasl/options.html#cmdoption-arg-sql-engine">command line option</a>
</li>
      </ul></li>
      <li>
    sql_hostnames [&lt;list of SQL servers&gt;]

      <ul>
        <li><a href="sasl/options.html#cmdoption-arg-sql-hostnames">command line option</a>
</li>
      </ul></li>
      <li>
    sql_insert &lt;statement&gt;

      <ul>
        <li><a href="sasl/options.html#cmdoption-arg-sql-insert">command line option</a>
</li>
      </ul></li>
      <li>
    sql_passwd &lt;password&gt;

      <ul>
        <li><a href="sasl/options.html#cmdoption-arg-sql-passwd">command line option</a>
</li>
      </ul></li>
      <li>
    sql_select &lt;statement&gt;

      <ul>
        <li><a href="sasl/options.html#cmdoption-arg-sql-select">command line option</a>
</li>
      </ul></li>
      <li>
    sql_update &lt;statement&gt;

      <ul>
        <li><a href="sasl/options.html#cmdoption-arg-sql-update">command line option</a>
</li>
      </ul></li>
      <li>
    sql_user &lt;username&gt;

      <ul>
        <li><a href="sasl/options.html#cmdoption-arg-sql-user">command line option</a>
</li>
      </ul></li>
      <li>
    srp_mda [md5 | sha1 | rmd160]

      <ul>
        <li><a href="sasl/options.html#cmdoption-arg-srp-mda">command line option</a>
</li>
      </ul></li>
      <li>
    srvtab [&lt;path&gt;]

      <ul>
        <li><a href="sasl/options.html#cmdoption-arg-srvtab">command line option</a>
</li>
      </ul></li>
  </ul></td>
</tr></table>



          </div>
          <footer>
  

  <hr/>

  <div role="contentinfo">
    <p>
        &copy; Copyright 1993-2016, The Cyrus Team.
    </p>
  </div>
  Built with <a href="http://sphinx-doc.org/">Sphinx</a> 1.6.6 using a modified <a href="https://readthedocs.org">Read the Docs</a> <a href="https://github.com/snide/sphinx_rtd_theme">theme</a>.

</footer>

        </div>
      </div>

    </section>

  </div>
  


  

    <script type="text/javascript">
        var DOCUMENTATION_OPTIONS = {
            URL_ROOT:'./',
            VERSION:'2.1.27',
            COLLAPSE_INDEX:false,
            FILE_SUFFIX:'.html',
            HAS_SOURCE:  true
        };
    </script>
      <script type="text/javascript" src="_static/jquery.js"></script>
      <script type="text/javascript" src="_static/underscore.js"></script>
      <script type="text/javascript" src="_static/doctools.js"></script>
      <script type="text/javascript" src="https://cdn.mathjax.org/mathjax/latest/MathJax.js"></script>

  

  
  
    <script type="text/javascript" src="_static/js/theme.js"></script>
  

  
  
  <script type="text/javascript">
<!--      jQuery(function () {
          SphinxRtdTheme.StickyNav.enable();
      }); -->
  </script>
  
 



</body>
</html>PK�h%[K�6���$doc/alt-cyrus-sasl-lib/download.htmlnu�[���

<!DOCTYPE html>
<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
<head>
  <meta charset="utf-8">
  
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  
  <title>Download &mdash; Cyrus SASL 2.1.27 documentation</title>
  

  
  
    <link rel="shortcut icon" href="_static/favicon.ico"/>
  

  

  
  
    

  

  
  
    <link rel="stylesheet" href="_static/css/theme.css" type="text/css" />
  

  
    <link rel="stylesheet" href="_static/cyrus.css" type="text/css" />
  

  
        <link rel="index" title="Index"
              href="genindex.html"/>
        <link rel="search" title="Search" href="search.html"/>
    <link rel="top" title="Cyrus SASL 2.1.27 documentation" href="index.html"/>
        <link rel="next" title="Get SASL" href="getsasl.html"/>
        <link rel="prev" title="Cyrus SASL" href="index.html"/> 

  
  
  

</head>

<body class="wy-body-for-nav" role="document">

  
  
<div class="pageheader">
  <ul>
    <li><a href="index.html">Home</a></li>
    <li><a href="http://www.cyrusimap.org">Cyrus IMAP</a></li>
    <li><a href="#">Download</a></li>
    <li><a href="contribute.html">Contribute</a></li>
  </ul>
  <div>
    <a href="index.html">
      <img src="_static/logo.gif" alt="CYRUS SASL" />
    </a>
  </div>
</div>
<div style="clear: both;"></div>


  <div class="wy-grid-for-nav">

    
    <nav data-toggle="wy-nav-shift" class="wy-nav-side">
      <div class="wy-side-nav-search">
        

        
 
          <a href="index.html">
 

  
          
          <img src="_static/logo.gif"  />
     
        </a>

        
<div role="search">
  <form id="rtd-search-form" class="wy-form" action="search.html" method="get">
    <input type="text" name="q" placeholder="Search docs" />
    <input type="hidden" name="check_keywords" value="yes" />
    <input type="hidden" name="area" value="default" />
  </form>
</div>

        
      </div>

      <div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
        
          
          
              <p class="caption"><span class="caption-text">Cyrus SASL</span></p>
<ul class="current">
<li class="toctree-l1 current"><a class="current reference internal" href="#">Download</a><ul>
<li class="toctree-l2"><a class="reference internal" href="getsasl.html">Get SASL</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html">Installation</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#quick-install-guide">Quick install guide</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#detailed-installation-guide">Detailed installation guide</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#supported-platforms">Supported platforms</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/release-notes/index.html">Release Notes</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/release-notes/index.html#supported-product-series">Supported Product Series</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/release-notes/index.html#series-2-1">Series 2.1</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/release-notes/index.html#older-versions">Older Versions</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/release-notes/index.html#series-2-2-0">Series 2: 2.0</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/release-notes/index.html#series-1">Series 1</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="packager.html">Note for Packagers</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="sasl/quickstart.html">Quickstart guide</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/quickstart.html#features">Features</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/quickstart.html#typical-installation">Typical Installation</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/quickstart.html#configuration">Configuration</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="sasl/concepts.html">Concepts</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#sasl">SASL</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#sasl-authentication-mechanisms">SASL Authentication Mechanisms</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#security-layers">Security Layers</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#channel-binding">Channel Binding</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#realms">Realms</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#protocols">Protocols</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#cyrus-sasl">Cyrus SASL</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#the-glue-library">The Glue Library</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#auxiliary-properties">Auxiliary Properties</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#plugins">Plugins</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="setup.html">Setup</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/installation.html">Installation</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html#quick-install-guide">Quick install guide</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#tarball-installation">Tarball installation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#unix-package-installation">Unix package Installation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#configuration">Configuration</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html#detailed-installation-guide">Detailed installation guide</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#requirements">Requirements</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#build-configuration">Build Configuration</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#building-and-installation">Building and Installation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#compilation-hints">Compilation Hints</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#application-configuration">Application Configuration</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html#supported-platforms">Supported platforms</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/upgrading.html">Upgrading from v1 to v2</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/upgrading.html#backwards-compatibility">Backwards Compatibility</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/upgrading.html#coexistence-with-saslv1">Coexistence with SASLv1</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/upgrading.html#database-upgrades">Database Upgrades</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/upgrading.html#errors-on-migration">Errors on migration</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/components.html">Components</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/components.html#the-application">The Application</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/components.html#the-sasl-glue-layer">The SASL Glue Layer</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/components.html#plugins">Plugins</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/components.html#plugins-general">Plugins: General</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/components.html#plugins-sasl-mechanisms">Plugins: SASL Mechanisms</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/components.html#plugins-auxiliary-property">Plugins: Auxiliary Property</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/components.html#plugins-username-canonicalization">Plugins: Username Canonicalization</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/components.html#password-verification-services">Password Verification Services</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/options.html">Options</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#sasl-library">SASL Library</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#auxiliary-property-plugin">Auxiliary Property Plugin</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#gssapi">GSSAPI</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#ldapdb">LDAPDB</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/options.html#notes-on-ldapdb">Notes on LDAPDB</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/options.html#examples">Examples</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#ntlm">NTLM</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#otp">OTP</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#digest-md5">Digest-md5</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#sasldb">SASLDB</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/options.html#notes-on-sasldb-with-lmdb">Notes on sasldb with LMDB</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#sql-plugin">SQL Plugin</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/options.html#notes-on-sql">Notes on SQL</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/options.html#id2">Examples</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#srp">SRP</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#kerberos-v4">Kerberos V4</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/advanced.html">Advanced Usage</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/advanced.html#notes-for-advanced-usage-of-libsasl">Notes for Advanced Usage of libsasl</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/advanced.html#using-cyrus-sasl-as-a-static-library">Using Cyrus SASL as a static library</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="operations.html">Operations</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/sysadmin.html">System Administrators</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#what-sasl-is">What SASL is</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#authentication-and-authorization-identifiers">Authentication and authorization identifiers</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#realms">Realms</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#how-sasl-works">How SASL works</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#the-plain-mechanism-sasl-checkpass-and-plaintext-passwords">The PLAIN mechanism, <code class="docutils literal"><span class="pre">sasl_checkpass()</span></code>, and plaintext passwords</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#shared-secrets-mechanisms">Shared secrets mechanisms</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#kerberos-mechanisms">Kerberos mechanisms</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#the-otp-mechanism">The OTP mechanism</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#auxiliary-properties">Auxiliary Properties</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#how-to-set-configuration-options">How to set configuration options</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#the-default-configuration-file">The default configuration file</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#application-configuration">Application configuration</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#troubleshooting">Troubleshooting</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/manpages.html">Man pages</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/manpages.html#library-files">(3) Library Files</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl.html"><strong>SASL</strong> - SASL Authentication Library</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_authorize_t.html"><strong>sasl_authorize_t</strong> - The SASL authorization callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_auxprop.html"><strong>sasl_auxprop</strong> - How to work with SASL auxiliary properties</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_auxprop_add_plugin.html"><strong>sasl_auxprop_add_plugin</strong> - add a SASL auxiliary property plugin</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_auxprop_getctx.html"><strong>sasl_auxprop_getctx</strong> - Acquire an auxiliary property context</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_auxprop_request.html"><strong>sasl_auxprop_request</strong> - Request auxiliary properties from SASL</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_callbacks.html"><strong>sasl_callbacks</strong> - How to work with SASL callbacks</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_canon_user_t.html"><strong>sasl_canon_user_t</strong> - Application-supplied user canonicalization function</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_canonuser_add_plugin.html"><strong>sasl_canonuser_add_plugin</strong> - add a SASL user canonicalization plugin</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_chalprompt_t.html"><strong>sasl_chalprompt_t</strong> - Realm acquisition callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_checkapop.html"><strong>sasl_checkapop</strong> - Check an APOP challenge/response</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_checkpass.html"><strong>sasl_checkpass</strong> - Check a plaintext password</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_add_plugin.html"><strong>sasl_client_add_plugin</strong> - add a SASL client plugin</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_done.html"><strong>sasl_client_done</strong> - Cleanup function</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_init.html"><strong>sasl_client_init</strong> - SASL client authentication initialization</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_new.html"><strong>sasl_client_new</strong> - Create a new client authentication object</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_plug_init_t.html"><strong>sasl_client_plug_init_t</strong> - client plug‐in entry point</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_start.html"><strong>sasl_client_start</strong> - Begin an authentication negotiation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_step.html"><strong>sasl_client_step</strong> - Perform a step in the authentication negotiation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_decode.html"><strong>sasl_decode</strong> - Decode data received</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_decode64.html"><strong>sasl_decode64</strong> - Decode base64 string</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_dispose.html"><strong>sasl_dispose</strong> - Dispose of a SASL connection object</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_done.html"><strong>sasl_done</strong> - Dispose of a SASL connection object</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_encode.html"><strong>sasl_encode</strong> - Encode data for transport to authenticated host</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_encode64.html"><strong>sasl_encode64</strong> - Encode base64 string</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_encodev.html"><strong>sasl_encodev</strong> - Encode data for transport to authenticated host</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_erasebuffer.html"><strong>sasl_erasebuffer</strong> - erase buffer</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_errdetail.html"><strong>sasl_errdetail</strong> - Retrieve  detailed information about an error</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_errors.html"><strong>sasl_errors</strong> - SASL error codes</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_errstring.html"><strong>sasl_errstring</strong> - Translate a SASL return code to a human-readable form</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getcallback_t.html"><strong>sasl_getcallback_t</strong> - callback function to lookup a sasl_callback_t for a connection</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getconfpath_t.html"><strong>sasl_getconfpath_t</strong> - The SASL callback to indicate location of the config files</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getopt_t.html"><strong>sasl_getopt_t</strong> - The SASL get option callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getpath_t.html"><strong>sasl_getpath_t</strong> - The SASL callback to indicate location of the mechanism drivers</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getprop.html"><strong>sasl_getprop</strong> - Get a SASL property</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getrealm_t.html"><strong>sasl_getrealm_t</strong> - Realm Acquisition Callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getsecret_t.html"><strong>sasl_getsecret_t</strong> - The SASL callback for secrets (passwords)</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getsimple_t.html"><strong>sasl_getsimple_t</strong> - The SASL callback for username/authname/realm</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_global_listmech.html"><strong>sasl_global_listmech</strong> - Retrieve a list of the supported SASL mechanisms</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_idle.html"><strong>sasl_idle</strong> - Perform precalculations during an idle period</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_listmech.html"><strong>sasl_listmech</strong> - Retrieve a list of the supported SASL mechanisms</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_log_t.html"><strong>sasl_log_t</strong> - The SASL logging callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_add_plugin.html"><strong>sasl_server_add_plugin</strong> - add a SASL server plugin</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_done.html"><strong>sasl_server_done</strong> - Cleanup function</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_init.html"><strong>sasl_server_init</strong> - SASL server authentication initialization</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_new.html"><strong>sasl_server_new</strong> - Create a new server authentication object</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_plug_init_t.html"><strong>sasl_server_plug_init_t</strong> - server plug‐in entry point</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_start.html"><strong>sasl_server_start</strong> - Begin an authentication negotiation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_step.html"><strong>sasl_server_step</strong> - Perform a step in the authentication negotiation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_userdb_checkpass_t.html"><strong>sasl_server_userdb_checkpass_t</strong> - Plaintext Password Verification Callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_userdb_setpass_t.html"><strong>sasl_server_userdb_setpass_t</strong> - UserDB Plaintext Password Setting Callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_set_alloc.html"><strong>sasl_set_alloc</strong> - set the memory allocation functions used by the SASL library</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_set_mutex.html"><strong>sasl_set_mutex</strong> - set the mutex lock functions used by the SASL library</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_seterror.html"><strong>sasl_seterror</strong> - set the error string</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_setpass.html"><strong>sasl_setpass</strong> - Check a plaintext password</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_setprop.html"><strong>sasl_setprop</strong> - Set a SASL property</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_user_exists.html"><strong>sasl_user_exists</strong> - Check if a user exists on server</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_usererr.html"><strong>sasl_usererr</strong> - Remove information leak about accounts from sasl error codes</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_utf8verify.html"><strong>sasl_utf8verify</strong> - Verify a string is valid utf8</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_verifyfile_t.html"><strong>sasl_verifyfile_t</strong> - The SASL file verification</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/auxiliary_properties.html">Auxiliary Properties</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#auxiliary-properties-and-the-glue-layer">Auxiliary Properties and the Glue Layer</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#passwords-and-other-data">Passwords and other Data</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#sasldb">sasldb</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#ldapdb">ldapdb</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#sql">sql</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#user-canonicalization">User Canonicalization</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/authentication_mechanisms.html">Authentication Mechanisms</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/authentication_mechanisms.html#mechanisms">Mechanisms</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#anonymous">ANONYMOUS</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#cram-md5">CRAM-MD5</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#digest-md5">DIGEST-MD5</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#external">EXTERNAL</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#g2">G2</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#gssapi">GSSAPI</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#gss-spegno">GSS-SPEGNO</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#kerberos-v4">KERBEROS_V4</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#login">LOGIN</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#ntlm">NTLM</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#otp">OTP</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#passdss">PASSDSS</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#plain">PLAIN</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#scram">SCRAM</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#srp">SRP</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#non-sasl-authentication">Non-SASL Authentication</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/authentication_mechanisms.html#summary">Summary</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/pwcheck.html">Pwcheck</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#auxprop">Auxprop</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#auxprop-hashed">Auxprop-hashed</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#saslauthd">Saslauthd</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#authdaemon">Authdaemon</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#alwaystrue">Alwaystrue</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#auto-transition">Auto Transition</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/faq.html">Frequently Asked Questions</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/authorize-vs-authenticate.html">What is the difference between an Authorization ID and a Authentication ID?</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/crammd5-digestmd5.html">Why do CRAM-MD5 and DIGEST-MD5 not work with CyrusSaslauthd?</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/openldap-sasl-gssapi.html">How do I configure OpenLDAP +SASL+GSSAPI?</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/plaintextpasswords.html">Why does CyrusSasl store plaintext passwords in its databases?</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/rfcs.html">RFCs and drafts</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/upgrade-saslv2.html">Why am I having a problem running dbconverter-2 to upgrade from SASLv1 to SASLv2?</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/resources.html">Other Documentation &amp; Resources</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="developer.html">Developers</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/appconvert.html">Converting Applications from v1 to v2</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/appconvert.html#tips-for-both-clients-and-servers">Tips for both clients and servers</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/appconvert.html#tips-for-clients">Tips for clients</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/appconvert.html#tips-for-servers">Tips for Servers</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/developer/programming.html">Application Programmer’s Guide</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#introduction">Introduction</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#about-this-guide">About this Guide</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#what-is-sasl">What is SASL?</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#background">Background</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#how-did-the-world-work-before-sasl">How did the world work before SASL?</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#sasl-to-the-rescue">SASL to the rescue!</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#briefly">Briefly</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#what-is-the-cyrus-sasl-library-good-for">What is the Cyrus SASL library good for?</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#what-does-the-cyrus-sasl-library-do">What does the Cyrus SASL library do?</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#what-doesn-t-the-cyrus-sasl-library-do">What doesn’t the Cyrus SASL library do?</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#client-only-section">Client-only Section</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#a-typical-interaction-from-the-client-s-perspective">A typical interaction from the client’s perspective</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#how-does-this-look-in-code">How does this look in code</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#server-only-section">Server-only Section</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#a-typical-interaction-from-the-server-s-perspective">A typical interaction from the server’s perspective</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#id1">How does this look in code?</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#common-section">Common Section</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#callbacks-and-interactions">Callbacks and Interactions</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#security-layers">Security layers</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#example-applications-that-come-with-the-cyrus-sasl-library">Example applications that come with the Cyrus SASL library</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#sample-client-and-sample-server"><cite>sample-client</cite> and <cite>sample-server</cite></a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#cyrus-imapd-v2-1-0-or-later">Cyrus imapd v2.1.0 or later</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#imtest-from-cyrus-2-1-0-or-later"><cite>imtest</cite>, from Cyrus 2.1.0 or later</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#miscellaneous-information">Miscellaneous Information</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#empty-exchanges">Empty exchanges</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#idle">Idle</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/developer/plugprog.html">Plugin Programmer’s Guide</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#introduction">Introduction</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#about-this-guide">About this Guide</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#what-is-sasl">What is SASL?</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#common-section">Common Section</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#overview-of-plugin-programming">Overview of Plugin Programming</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#use-of-sasl-utils-t">Use of sasl_utils_t</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#error-reporting">Error Reporting</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#memory-allocation">Memory Allocation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#client-send-first-server-send-last">Client Send First / Server Send Last</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#client-plugins">Client Plugins</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#server-plugins">Server Plugins</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#user-canonicalization-canon-user-plugins">User Canonicalization (canon_user) Plugins</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#auxiliary-property-auxprop-plugins">Auxiliary Property (auxprop) Plugins</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/developer/testing.html">Testing</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/testing.html#testing-the-cmu-sasl-library-with-the-included-sample-applications">Testing the CMU SASL Library with the included sample applications</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/testing.html#example">Example</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/testing.html#running-the-testsuite-application">Running the Testsuite application</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="support.html">Support/Community</a></li>
</ul>
<p class="caption"><span class="caption-text">IMAP</span></p>
<ul>
<li class="toctree-l1"><a class="reference external" href="http://www.cyrusimap.org">Cyrus IMAP</a></li>
</ul>

          
        
      </div>
      &nbsp;
    </nav>

    <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">

      
      <nav class="wy-nav-top" role="navigation" aria-label="top navigation">
        <i data-toggle="wy-nav-top" class="fa fa-bars"></i>
        <a href="index.html">Cyrus SASL</a>
      </nav>


      
      <div class="wy-nav-content">
        <div class="rst-content">
          
          <div role="navigation" aria-label="breadcrumbs navigation">
  <ul class="wy-breadcrumbs">
      <li><a href="index.html">Docs v2.1.27</a> &raquo;</li>
      
    <li>Download</li>
      <li class="wy-breadcrumbs-aside">
        
          
            <a href="https://github.com/cyrusimap/cyrus-sasl/blob/master/docsrc/download.rst" class="fa fa-github"> Edit on GitHub</a>
          
        
      </li>
  </ul>
  <hr/>
</div>
          <div role="main" class="document">
            
  <div class="section" id="download">
<h1>Download<a class="headerlink" href="#download" title="Permalink to this headline">¶</a></h1>
<div class="toctree-wrapper compound">
<ul>
<li class="toctree-l1"><a class="reference internal" href="getsasl.html">Get SASL</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/installation.html">Installation</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html#quick-install-guide">Quick install guide</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#tarball-installation">Tarball installation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#unix-package-installation">Unix package Installation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#configuration">Configuration</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html#detailed-installation-guide">Detailed installation guide</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#requirements">Requirements</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#build-configuration">Build Configuration</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#building-and-installation">Building and Installation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#compilation-hints">Compilation Hints</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#application-configuration">Application Configuration</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html#supported-platforms">Supported platforms</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="sasl/release-notes/index.html">Release Notes</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/release-notes/index.html#supported-product-series">Supported Product Series</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/release-notes/index.html#series-2-1">Series 2.1</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/release-notes/2.1/index.html">Cyrus SASL 2.1.x Release Notes</a><ul>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/2.1/index.html#new-in-2-1-27">New in 2.1.27</a></li>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/2.1/index.html#new-in-2-1-26">New in 2.1.26</a></li>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/2.1/index.html#new-in-2-1-25">New in 2.1.25</a></li>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/2.1/index.html#new-in-2-1-24">New in 2.1.24</a></li>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/2.1/index.html#new-in-2-1-23">New in 2.1.23</a></li>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/2.1/index.html#new-in-2-1-22">New in 2.1.22</a></li>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/2.1/index.html#new-in-2-1-21">New in 2.1.21</a></li>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/2.1/index.html#new-in-2-1-20">New in 2.1.20</a></li>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/2.1/index.html#new-in-2-1-19">New in 2.1.19</a></li>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/2.1/index.html#new-in-2-1-18">New in 2.1.18</a></li>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/2.1/index.html#new-in-2-1-17">New in 2.1.17</a></li>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/2.1/index.html#new-in-2-1-16-beta">New in 2.1.16-BETA</a></li>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/2.1/index.html#new-in-2-1-15">New in 2.1.15</a></li>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/2.1/index.html#new-in-2-1-14">New in 2.1.14</a></li>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/2.1/index.html#new-in-2-1-13">New in 2.1.13</a></li>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/2.1/index.html#new-in-2-1-12">New in 2.1.12</a></li>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/2.1/index.html#new-in-2-1-11">New in 2.1.11</a></li>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/2.1/index.html#new-in-2-1-10">New in 2.1.10</a></li>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/2.1/index.html#new-in-2-1-9">New in 2.1.9</a></li>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/2.1/index.html#new-in-2-1-8">New in 2.1.8</a></li>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/2.1/index.html#new-in-2-1-7">New in 2.1.7</a></li>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/2.1/index.html#new-in-2-1-6">New in 2.1.6</a></li>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/2.1/index.html#new-in-2-1-5">New in 2.1.5</a></li>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/2.1/index.html#new-in-2-1-4">New in 2.1.4</a></li>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/2.1/index.html#new-in-2-1-3-beta">New in 2.1.3-BETA</a></li>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/2.1/index.html#new-in-2-1-2">New in 2.1.2</a></li>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/2.1/index.html#new-in-2-1-1">New in 2.1.1</a></li>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/2.1/index.html#new-in-2-1-0">New in 2.1.0</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/release-notes/index.html#older-versions">Older Versions</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/release-notes/index.html#series-2-2-0">Series 2: 2.0</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/release-notes/2.0/index.html">Cyrus SASL 2.0.x Release Notes</a><ul>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/2.0/index.html#new-in-2-0-5-beta">New in 2.0.5-BETA</a></li>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/2.0/index.html#new-in-2-0-4-beta">New in 2.0.4-BETA</a></li>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/2.0/index.html#new-in-2-0-3-beta">New in 2.0.3-BETA</a></li>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/2.0/index.html#new-in-2-0-2-alpha">New in 2.0.2-ALPHA</a></li>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/2.0/index.html#new-in-2-0-0-alpha">New in 2.0.0-ALPHA</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/release-notes/index.html#series-1">Series 1</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/release-notes/1/index.html">Cyrus SASL 1.x Release Notes</a><ul>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/1/index.html#new-in-1-5-26">New in 1.5.26</a></li>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/1/index.html#new-in-1-5-25">New in 1.5.25</a></li>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/1/index.html#new-in-1-5-24">New in 1.5.24</a></li>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/1/index.html#new-in-1-5-22">New in 1.5.22</a></li>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/1/index.html#new-in-1-5-21">New in 1.5.21</a></li>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/1/index.html#new-in-1-5-20">New in 1.5.20</a></li>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/1/index.html#new-in-1-5-19">New in 1.5.19</a></li>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/1/index.html#new-in-1-5-18">New in 1.5.18</a></li>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/1/index.html#new-in-1-5-17">New in 1.5.17</a></li>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/1/index.html#new-in-1-5-16">New in 1.5.16</a></li>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/1/index.html#new-in-1-5-15">New in 1.5.15</a></li>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/1/index.html#new-in-1-5-14">New in 1.5.14</a></li>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/1/index.html#new-in-1-5-13">New in 1.5.13</a></li>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/1/index.html#new-in-1-5-12">New in 1.5.12</a></li>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/1/index.html#new-in-1-5-11">New in 1.5.11</a></li>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/1/index.html#new-in-1-5-10">New in 1.5.10</a></li>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/1/index.html#new-in-1-5-9">New in 1.5.9</a></li>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/1/index.html#new-in-1-5-5">New in 1.5.5</a></li>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/1/index.html#new-in-1-5-3">New in 1.5.3</a></li>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/1/index.html#new-in-1-5-2">New in 1.5.2</a></li>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/1/index.html#new-in-1-5-0">New in 1.5.0</a></li>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/1/index.html#new-in-1-4-1">New in 1.4.1</a></li>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/1/index.html#new-in-1-3b1">New in 1.3b1</a></li>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/1/index.html#new-in-1-2b3">New in 1.2b3</a></li>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/1/index.html#new-in-1-2b2">New in 1.2b2</a></li>
<li class="toctree-l5"><a class="reference internal" href="sasl/release-notes/1/index.html#new-in-1-2b1">New in 1.2b1</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="packager.html">Note for Packagers</a></li>
</ul>
</div>
</div>


          </div>
          <footer>
  
    <div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
      
        <a href="getsasl.html" class="btn btn-neutral float-right" title="Get SASL" accesskey="n">Next <span class="fa fa-arrow-circle-right"></span></a>
      
      
        <a href="index.html" class="btn btn-neutral" title="Cyrus SASL" accesskey="p"><span class="fa fa-arrow-circle-left"></span> Previous</a>
      
    </div>
  

  <hr/>

  <div role="contentinfo">
    <p>
        &copy; Copyright 1993-2016, The Cyrus Team.
    </p>
  </div>
  Built with <a href="http://sphinx-doc.org/">Sphinx</a> 1.6.6 using a modified <a href="https://readthedocs.org">Read the Docs</a> <a href="https://github.com/snide/sphinx_rtd_theme">theme</a>.

</footer>

        </div>
      </div>

    </section>

  </div>
  


  

    <script type="text/javascript">
        var DOCUMENTATION_OPTIONS = {
            URL_ROOT:'./',
            VERSION:'2.1.27',
            COLLAPSE_INDEX:false,
            FILE_SUFFIX:'.html',
            HAS_SOURCE:  true
        };
    </script>
      <script type="text/javascript" src="_static/jquery.js"></script>
      <script type="text/javascript" src="_static/underscore.js"></script>
      <script type="text/javascript" src="_static/doctools.js"></script>
      <script type="text/javascript" src="https://cdn.mathjax.org/mathjax/latest/MathJax.js"></script>

  

  
  
    <script type="text/javascript" src="_static/js/theme.js"></script>
  

  
  
  <script type="text/javascript">
<!--      jQuery(function () {
          SphinxRtdTheme.StickyNav.enable();
      }); -->
  </script>
  
 



</body>
</html>PK�h%[c����!doc/alt-cyrus-sasl-lib/setup.htmlnu�[���

<!DOCTYPE html>
<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
<head>
  <meta charset="utf-8">
  
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  
  <title>Setup &mdash; Cyrus SASL 2.1.27 documentation</title>
  

  
  
    <link rel="shortcut icon" href="_static/favicon.ico"/>
  

  

  
  
    

  

  
  
    <link rel="stylesheet" href="_static/css/theme.css" type="text/css" />
  

  
    <link rel="stylesheet" href="_static/cyrus.css" type="text/css" />
  

  
        <link rel="index" title="Index"
              href="genindex.html"/>
        <link rel="search" title="Search" href="search.html"/>
    <link rel="top" title="Cyrus SASL 2.1.27 documentation" href="index.html"/>
        <link rel="next" title="Upgrading from v1 to v2" href="sasl/upgrading.html"/>
        <link rel="prev" title="Concepts" href="sasl/concepts.html"/> 

  
  
  

</head>

<body class="wy-body-for-nav" role="document">

  
  
<div class="pageheader">
  <ul>
    <li><a href="index.html">Home</a></li>
    <li><a href="http://www.cyrusimap.org">Cyrus IMAP</a></li>
    <li><a href="download.html">Download</a></li>
    <li><a href="contribute.html">Contribute</a></li>
  </ul>
  <div>
    <a href="index.html">
      <img src="_static/logo.gif" alt="CYRUS SASL" />
    </a>
  </div>
</div>
<div style="clear: both;"></div>


  <div class="wy-grid-for-nav">

    
    <nav data-toggle="wy-nav-shift" class="wy-nav-side">
      <div class="wy-side-nav-search">
        

        
 
          <a href="index.html">
 

  
          
          <img src="_static/logo.gif"  />
     
        </a>

        
<div role="search">
  <form id="rtd-search-form" class="wy-form" action="search.html" method="get">
    <input type="text" name="q" placeholder="Search docs" />
    <input type="hidden" name="check_keywords" value="yes" />
    <input type="hidden" name="area" value="default" />
  </form>
</div>

        
      </div>

      <div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
        
          
          
              <p class="caption"><span class="caption-text">Cyrus SASL</span></p>
<ul class="current">
<li class="toctree-l1"><a class="reference internal" href="download.html">Download</a><ul>
<li class="toctree-l2"><a class="reference internal" href="getsasl.html">Get SASL</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html">Installation</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#quick-install-guide">Quick install guide</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#detailed-installation-guide">Detailed installation guide</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#supported-platforms">Supported platforms</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/release-notes/index.html">Release Notes</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/release-notes/index.html#supported-product-series">Supported Product Series</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/release-notes/index.html#series-2-1">Series 2.1</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/release-notes/index.html#older-versions">Older Versions</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/release-notes/index.html#series-2-2-0">Series 2: 2.0</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/release-notes/index.html#series-1">Series 1</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="packager.html">Note for Packagers</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="sasl/quickstart.html">Quickstart guide</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/quickstart.html#features">Features</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/quickstart.html#typical-installation">Typical Installation</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/quickstart.html#configuration">Configuration</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="sasl/concepts.html">Concepts</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#sasl">SASL</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#sasl-authentication-mechanisms">SASL Authentication Mechanisms</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#security-layers">Security Layers</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#channel-binding">Channel Binding</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#realms">Realms</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#protocols">Protocols</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#cyrus-sasl">Cyrus SASL</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#the-glue-library">The Glue Library</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#auxiliary-properties">Auxiliary Properties</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#plugins">Plugins</a></li>
</ul>
</li>
<li class="toctree-l1 current"><a class="current reference internal" href="#">Setup</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/installation.html">Installation</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html#quick-install-guide">Quick install guide</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#tarball-installation">Tarball installation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#unix-package-installation">Unix package Installation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#configuration">Configuration</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html#detailed-installation-guide">Detailed installation guide</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#requirements">Requirements</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#build-configuration">Build Configuration</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#building-and-installation">Building and Installation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#compilation-hints">Compilation Hints</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#application-configuration">Application Configuration</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html#supported-platforms">Supported platforms</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/upgrading.html">Upgrading from v1 to v2</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/upgrading.html#backwards-compatibility">Backwards Compatibility</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/upgrading.html#coexistence-with-saslv1">Coexistence with SASLv1</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/upgrading.html#database-upgrades">Database Upgrades</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/upgrading.html#errors-on-migration">Errors on migration</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/components.html">Components</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/components.html#the-application">The Application</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/components.html#the-sasl-glue-layer">The SASL Glue Layer</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/components.html#plugins">Plugins</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/components.html#plugins-general">Plugins: General</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/components.html#plugins-sasl-mechanisms">Plugins: SASL Mechanisms</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/components.html#plugins-auxiliary-property">Plugins: Auxiliary Property</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/components.html#plugins-username-canonicalization">Plugins: Username Canonicalization</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/components.html#password-verification-services">Password Verification Services</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/options.html">Options</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#sasl-library">SASL Library</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#auxiliary-property-plugin">Auxiliary Property Plugin</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#gssapi">GSSAPI</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#ldapdb">LDAPDB</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/options.html#notes-on-ldapdb">Notes on LDAPDB</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/options.html#examples">Examples</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#ntlm">NTLM</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#otp">OTP</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#digest-md5">Digest-md5</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#sasldb">SASLDB</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/options.html#notes-on-sasldb-with-lmdb">Notes on sasldb with LMDB</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#sql-plugin">SQL Plugin</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/options.html#notes-on-sql">Notes on SQL</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/options.html#id2">Examples</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#srp">SRP</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#kerberos-v4">Kerberos V4</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/advanced.html">Advanced Usage</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/advanced.html#notes-for-advanced-usage-of-libsasl">Notes for Advanced Usage of libsasl</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/advanced.html#using-cyrus-sasl-as-a-static-library">Using Cyrus SASL as a static library</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="operations.html">Operations</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/sysadmin.html">System Administrators</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#what-sasl-is">What SASL is</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#authentication-and-authorization-identifiers">Authentication and authorization identifiers</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#realms">Realms</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#how-sasl-works">How SASL works</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#the-plain-mechanism-sasl-checkpass-and-plaintext-passwords">The PLAIN mechanism, <code class="docutils literal"><span class="pre">sasl_checkpass()</span></code>, and plaintext passwords</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#shared-secrets-mechanisms">Shared secrets mechanisms</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#kerberos-mechanisms">Kerberos mechanisms</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#the-otp-mechanism">The OTP mechanism</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#auxiliary-properties">Auxiliary Properties</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#how-to-set-configuration-options">How to set configuration options</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#the-default-configuration-file">The default configuration file</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#application-configuration">Application configuration</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#troubleshooting">Troubleshooting</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/manpages.html">Man pages</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/manpages.html#library-files">(3) Library Files</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl.html"><strong>SASL</strong> - SASL Authentication Library</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_authorize_t.html"><strong>sasl_authorize_t</strong> - The SASL authorization callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_auxprop.html"><strong>sasl_auxprop</strong> - How to work with SASL auxiliary properties</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_auxprop_add_plugin.html"><strong>sasl_auxprop_add_plugin</strong> - add a SASL auxiliary property plugin</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_auxprop_getctx.html"><strong>sasl_auxprop_getctx</strong> - Acquire an auxiliary property context</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_auxprop_request.html"><strong>sasl_auxprop_request</strong> - Request auxiliary properties from SASL</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_callbacks.html"><strong>sasl_callbacks</strong> - How to work with SASL callbacks</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_canon_user_t.html"><strong>sasl_canon_user_t</strong> - Application-supplied user canonicalization function</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_canonuser_add_plugin.html"><strong>sasl_canonuser_add_plugin</strong> - add a SASL user canonicalization plugin</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_chalprompt_t.html"><strong>sasl_chalprompt_t</strong> - Realm acquisition callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_checkapop.html"><strong>sasl_checkapop</strong> - Check an APOP challenge/response</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_checkpass.html"><strong>sasl_checkpass</strong> - Check a plaintext password</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_add_plugin.html"><strong>sasl_client_add_plugin</strong> - add a SASL client plugin</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_done.html"><strong>sasl_client_done</strong> - Cleanup function</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_init.html"><strong>sasl_client_init</strong> - SASL client authentication initialization</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_new.html"><strong>sasl_client_new</strong> - Create a new client authentication object</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_plug_init_t.html"><strong>sasl_client_plug_init_t</strong> - client plug‐in entry point</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_start.html"><strong>sasl_client_start</strong> - Begin an authentication negotiation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_step.html"><strong>sasl_client_step</strong> - Perform a step in the authentication negotiation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_decode.html"><strong>sasl_decode</strong> - Decode data received</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_decode64.html"><strong>sasl_decode64</strong> - Decode base64 string</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_dispose.html"><strong>sasl_dispose</strong> - Dispose of a SASL connection object</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_done.html"><strong>sasl_done</strong> - Dispose of a SASL connection object</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_encode.html"><strong>sasl_encode</strong> - Encode data for transport to authenticated host</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_encode64.html"><strong>sasl_encode64</strong> - Encode base64 string</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_encodev.html"><strong>sasl_encodev</strong> - Encode data for transport to authenticated host</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_erasebuffer.html"><strong>sasl_erasebuffer</strong> - erase buffer</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_errdetail.html"><strong>sasl_errdetail</strong> - Retrieve  detailed information about an error</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_errors.html"><strong>sasl_errors</strong> - SASL error codes</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_errstring.html"><strong>sasl_errstring</strong> - Translate a SASL return code to a human-readable form</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getcallback_t.html"><strong>sasl_getcallback_t</strong> - callback function to lookup a sasl_callback_t for a connection</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getconfpath_t.html"><strong>sasl_getconfpath_t</strong> - The SASL callback to indicate location of the config files</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getopt_t.html"><strong>sasl_getopt_t</strong> - The SASL get option callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getpath_t.html"><strong>sasl_getpath_t</strong> - The SASL callback to indicate location of the mechanism drivers</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getprop.html"><strong>sasl_getprop</strong> - Get a SASL property</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getrealm_t.html"><strong>sasl_getrealm_t</strong> - Realm Acquisition Callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getsecret_t.html"><strong>sasl_getsecret_t</strong> - The SASL callback for secrets (passwords)</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getsimple_t.html"><strong>sasl_getsimple_t</strong> - The SASL callback for username/authname/realm</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_global_listmech.html"><strong>sasl_global_listmech</strong> - Retrieve a list of the supported SASL mechanisms</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_idle.html"><strong>sasl_idle</strong> - Perform precalculations during an idle period</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_listmech.html"><strong>sasl_listmech</strong> - Retrieve a list of the supported SASL mechanisms</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_log_t.html"><strong>sasl_log_t</strong> - The SASL logging callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_add_plugin.html"><strong>sasl_server_add_plugin</strong> - add a SASL server plugin</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_done.html"><strong>sasl_server_done</strong> - Cleanup function</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_init.html"><strong>sasl_server_init</strong> - SASL server authentication initialization</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_new.html"><strong>sasl_server_new</strong> - Create a new server authentication object</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_plug_init_t.html"><strong>sasl_server_plug_init_t</strong> - server plug‐in entry point</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_start.html"><strong>sasl_server_start</strong> - Begin an authentication negotiation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_step.html"><strong>sasl_server_step</strong> - Perform a step in the authentication negotiation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_userdb_checkpass_t.html"><strong>sasl_server_userdb_checkpass_t</strong> - Plaintext Password Verification Callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_userdb_setpass_t.html"><strong>sasl_server_userdb_setpass_t</strong> - UserDB Plaintext Password Setting Callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_set_alloc.html"><strong>sasl_set_alloc</strong> - set the memory allocation functions used by the SASL library</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_set_mutex.html"><strong>sasl_set_mutex</strong> - set the mutex lock functions used by the SASL library</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_seterror.html"><strong>sasl_seterror</strong> - set the error string</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_setpass.html"><strong>sasl_setpass</strong> - Check a plaintext password</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_setprop.html"><strong>sasl_setprop</strong> - Set a SASL property</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_user_exists.html"><strong>sasl_user_exists</strong> - Check if a user exists on server</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_usererr.html"><strong>sasl_usererr</strong> - Remove information leak about accounts from sasl error codes</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_utf8verify.html"><strong>sasl_utf8verify</strong> - Verify a string is valid utf8</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_verifyfile_t.html"><strong>sasl_verifyfile_t</strong> - The SASL file verification</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/auxiliary_properties.html">Auxiliary Properties</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#auxiliary-properties-and-the-glue-layer">Auxiliary Properties and the Glue Layer</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#passwords-and-other-data">Passwords and other Data</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#sasldb">sasldb</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#ldapdb">ldapdb</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#sql">sql</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#user-canonicalization">User Canonicalization</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/authentication_mechanisms.html">Authentication Mechanisms</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/authentication_mechanisms.html#mechanisms">Mechanisms</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#anonymous">ANONYMOUS</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#cram-md5">CRAM-MD5</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#digest-md5">DIGEST-MD5</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#external">EXTERNAL</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#g2">G2</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#gssapi">GSSAPI</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#gss-spegno">GSS-SPEGNO</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#kerberos-v4">KERBEROS_V4</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#login">LOGIN</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#ntlm">NTLM</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#otp">OTP</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#passdss">PASSDSS</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#plain">PLAIN</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#scram">SCRAM</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#srp">SRP</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#non-sasl-authentication">Non-SASL Authentication</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/authentication_mechanisms.html#summary">Summary</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/pwcheck.html">Pwcheck</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#auxprop">Auxprop</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#auxprop-hashed">Auxprop-hashed</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#saslauthd">Saslauthd</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#authdaemon">Authdaemon</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#alwaystrue">Alwaystrue</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#auto-transition">Auto Transition</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/faq.html">Frequently Asked Questions</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/authorize-vs-authenticate.html">What is the difference between an Authorization ID and a Authentication ID?</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/crammd5-digestmd5.html">Why do CRAM-MD5 and DIGEST-MD5 not work with CyrusSaslauthd?</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/openldap-sasl-gssapi.html">How do I configure OpenLDAP +SASL+GSSAPI?</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/plaintextpasswords.html">Why does CyrusSasl store plaintext passwords in its databases?</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/rfcs.html">RFCs and drafts</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/upgrade-saslv2.html">Why am I having a problem running dbconverter-2 to upgrade from SASLv1 to SASLv2?</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/resources.html">Other Documentation &amp; Resources</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="developer.html">Developers</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/appconvert.html">Converting Applications from v1 to v2</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/appconvert.html#tips-for-both-clients-and-servers">Tips for both clients and servers</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/appconvert.html#tips-for-clients">Tips for clients</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/appconvert.html#tips-for-servers">Tips for Servers</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/developer/programming.html">Application Programmer’s Guide</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#introduction">Introduction</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#about-this-guide">About this Guide</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#what-is-sasl">What is SASL?</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#background">Background</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#how-did-the-world-work-before-sasl">How did the world work before SASL?</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#sasl-to-the-rescue">SASL to the rescue!</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#briefly">Briefly</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#what-is-the-cyrus-sasl-library-good-for">What is the Cyrus SASL library good for?</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#what-does-the-cyrus-sasl-library-do">What does the Cyrus SASL library do?</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#what-doesn-t-the-cyrus-sasl-library-do">What doesn’t the Cyrus SASL library do?</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#client-only-section">Client-only Section</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#a-typical-interaction-from-the-client-s-perspective">A typical interaction from the client’s perspective</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#how-does-this-look-in-code">How does this look in code</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#server-only-section">Server-only Section</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#a-typical-interaction-from-the-server-s-perspective">A typical interaction from the server’s perspective</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#id1">How does this look in code?</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#common-section">Common Section</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#callbacks-and-interactions">Callbacks and Interactions</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#security-layers">Security layers</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#example-applications-that-come-with-the-cyrus-sasl-library">Example applications that come with the Cyrus SASL library</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#sample-client-and-sample-server"><cite>sample-client</cite> and <cite>sample-server</cite></a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#cyrus-imapd-v2-1-0-or-later">Cyrus imapd v2.1.0 or later</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#imtest-from-cyrus-2-1-0-or-later"><cite>imtest</cite>, from Cyrus 2.1.0 or later</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#miscellaneous-information">Miscellaneous Information</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#empty-exchanges">Empty exchanges</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#idle">Idle</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/developer/plugprog.html">Plugin Programmer’s Guide</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#introduction">Introduction</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#about-this-guide">About this Guide</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#what-is-sasl">What is SASL?</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#common-section">Common Section</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#overview-of-plugin-programming">Overview of Plugin Programming</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#use-of-sasl-utils-t">Use of sasl_utils_t</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#error-reporting">Error Reporting</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#memory-allocation">Memory Allocation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#client-send-first-server-send-last">Client Send First / Server Send Last</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#client-plugins">Client Plugins</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#server-plugins">Server Plugins</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#user-canonicalization-canon-user-plugins">User Canonicalization (canon_user) Plugins</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#auxiliary-property-auxprop-plugins">Auxiliary Property (auxprop) Plugins</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/developer/testing.html">Testing</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/testing.html#testing-the-cmu-sasl-library-with-the-included-sample-applications">Testing the CMU SASL Library with the included sample applications</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/testing.html#example">Example</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/testing.html#running-the-testsuite-application">Running the Testsuite application</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="support.html">Support/Community</a></li>
</ul>
<p class="caption"><span class="caption-text">IMAP</span></p>
<ul>
<li class="toctree-l1"><a class="reference external" href="http://www.cyrusimap.org">Cyrus IMAP</a></li>
</ul>

          
        
      </div>
      &nbsp;
    </nav>

    <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">

      
      <nav class="wy-nav-top" role="navigation" aria-label="top navigation">
        <i data-toggle="wy-nav-top" class="fa fa-bars"></i>
        <a href="index.html">Cyrus SASL</a>
      </nav>


      
      <div class="wy-nav-content">
        <div class="rst-content">
          
          <div role="navigation" aria-label="breadcrumbs navigation">
  <ul class="wy-breadcrumbs">
      <li><a href="index.html">Docs v2.1.27</a> &raquo;</li>
      
    <li>Setup</li>
      <li class="wy-breadcrumbs-aside">
        
          
            <a href="https://github.com/cyrusimap/cyrus-sasl/blob/master/docsrc/setup.rst" class="fa fa-github"> Edit on GitHub</a>
          
        
      </li>
  </ul>
  <hr/>
</div>
          <div role="main" class="document">
            
  <div class="section" id="setup">
<h1>Setup<a class="headerlink" href="#setup" title="Permalink to this headline">¶</a></h1>
<div class="toctree-wrapper compound">
<ul>
<li class="toctree-l1"><a class="reference internal" href="sasl/installation.html">Installation</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/installation.html#quick-install-guide">Quick install guide</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html#tarball-installation">Tarball installation</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html#unix-package-installation">Unix package Installation</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html#configuration">Configuration</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/installation.html#detailed-installation-guide">Detailed installation guide</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html#requirements">Requirements</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html#build-configuration">Build Configuration</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html#building-and-installation">Building and Installation</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html#compilation-hints">Compilation Hints</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html#application-configuration">Application Configuration</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/installation.html#supported-platforms">Supported platforms</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="sasl/upgrading.html">Upgrading from v1 to v2</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/upgrading.html#backwards-compatibility">Backwards Compatibility</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/upgrading.html#coexistence-with-saslv1">Coexistence with SASLv1</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/upgrading.html#database-upgrades">Database Upgrades</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/upgrading.html#errors-on-migration">Errors on migration</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="sasl/components.html">Components</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/components.html#the-application">The Application</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/components.html#the-sasl-glue-layer">The SASL Glue Layer</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/components.html#plugins">Plugins</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/components.html#plugins-general">Plugins: General</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/components.html#plugins-sasl-mechanisms">Plugins: SASL Mechanisms</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/components.html#plugins-auxiliary-property">Plugins: Auxiliary Property</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/components.html#plugins-username-canonicalization">Plugins: Username Canonicalization</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/components.html#password-verification-services">Password Verification Services</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="sasl/options.html">Options</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/options.html#sasl-library">SASL Library</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/options.html#auxiliary-property-plugin">Auxiliary Property Plugin</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/options.html#gssapi">GSSAPI</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/options.html#ldapdb">LDAPDB</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#notes-on-ldapdb">Notes on LDAPDB</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#examples">Examples</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/options.html#ntlm">NTLM</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/options.html#otp">OTP</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/options.html#digest-md5">Digest-md5</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/options.html#sasldb">SASLDB</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#notes-on-sasldb-with-lmdb">Notes on sasldb with LMDB</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/options.html#sql-plugin">SQL Plugin</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#notes-on-sql">Notes on SQL</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#id2">Examples</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/options.html#srp">SRP</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/options.html#kerberos-v4">Kerberos V4</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="sasl/advanced.html">Advanced Usage</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/advanced.html#notes-for-advanced-usage-of-libsasl">Notes for Advanced Usage of libsasl</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/advanced.html#using-cyrus-sasl-as-a-static-library">Using Cyrus SASL as a static library</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
</div>


          </div>
          <footer>
  
    <div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
      
        <a href="sasl/upgrading.html" class="btn btn-neutral float-right" title="Upgrading from v1 to v2" accesskey="n">Next <span class="fa fa-arrow-circle-right"></span></a>
      
      
        <a href="sasl/concepts.html" class="btn btn-neutral" title="Concepts" accesskey="p"><span class="fa fa-arrow-circle-left"></span> Previous</a>
      
    </div>
  

  <hr/>

  <div role="contentinfo">
    <p>
        &copy; Copyright 1993-2016, The Cyrus Team.
    </p>
  </div>
  Built with <a href="http://sphinx-doc.org/">Sphinx</a> 1.6.6 using a modified <a href="https://readthedocs.org">Read the Docs</a> <a href="https://github.com/snide/sphinx_rtd_theme">theme</a>.

</footer>

        </div>
      </div>

    </section>

  </div>
  


  

    <script type="text/javascript">
        var DOCUMENTATION_OPTIONS = {
            URL_ROOT:'./',
            VERSION:'2.1.27',
            COLLAPSE_INDEX:false,
            FILE_SUFFIX:'.html',
            HAS_SOURCE:  true
        };
    </script>
      <script type="text/javascript" src="_static/jquery.js"></script>
      <script type="text/javascript" src="_static/underscore.js"></script>
      <script type="text/javascript" src="_static/doctools.js"></script>
      <script type="text/javascript" src="https://cdn.mathjax.org/mathjax/latest/MathJax.js"></script>

  

  
  
    <script type="text/javascript" src="_static/js/theme.js"></script>
  

  
  
  <script type="text/javascript">
<!--      jQuery(function () {
          SphinxRtdTheme.StickyNav.enable();
      }); -->
  </script>
  
 



</body>
</html>PK�h%[H{���doc/alt-cyrus-sasl-lib/AUTHORSnu�[���Rob Siemborski <rjs3+@andrew.cmu.edu> wrote and tested the conversion
to the SASLv2 API.

Ken Murchison <murch@andrew.cmu.edu> worked on the OTP, NTLM, SRP and SQL
plugins, as well as helping to track down bugs as they appear. He also
added support for HTTP authentication.

Rob Earhart <earhart@cmu.edu> wrote the build/installation procedure,
wrote and tested some of the code, and provided general guidance and
coding advice.

Leif Johansson <leifj@matematik.su.se> wrote the GSSAPI plugin, with
contributions from Sam Hartman <hartmans@fundsxpress.com>.

Leandro Santi <lesanti@sinectis.com.ar> added Courier authdaemon support.

Alexey Melnikov <alexey.melnikov@isode.com> wrote the first pass of the
DIGEST-MD5 plugin and continues to work on it.  He also wrote
a good deal of the current Windows support.

Rainer Schoepf <schoepf@uni-mainz.de> contributed the LOGIN plugin,
based on Tim Martin's PLAIN plugin.

Simon Loader <simon@surf.org.uk> wrote the MySQL auxprop module.

Rolf Braun <rbraun@andrew.cmu.edu> wrote the MacOS ports.

Howard Chu <hyc@highlandsun.com> put a good deal of work into OS/390
portability, correct building of static libraries, and a slew
of misc. bugfixes.

Tim Martin <tmartin@andrew.cmu.edu> wrote, debugged, and tested
most of the SASLv1 code.

Larry Greenfield <leg+sasl@andrew.cmu.edu> complained. a lot.

Chris Newman <chris.newman@oracle.com> wrote the initial version of the
SASL API, as well as the version 2 SASL API (documented in sasl.h,
saslutil.h, saslplug.h, and prop.h).

Ryan Troll <ryan@andrew.cmu.edu> started the Windows port,
and both Larry Greenfield and Alexey Melnikov have done more work on it.

getaddrinfo.c was written by Hajimu UMEMOTO <ume@mahoroba.org>
which is based on the IPv6 code written by KIKUCHI Takahiro
<kick@kyoto.wide.ad.jp>

Igor Brezac <igor@ipass.net> has done a good deal of work on the saslauthd
LDAP module.

Jeremy Rumpf <jrumpf@heavyload.net> implemented the credential cache, unified
the different IPC methods under a common framework.

Fabian Knittel <fknittel@gmx.de> wrote auth_pam plugin, based on
Debian's pwcheck_pam daemon by Michael-John Turner <mj@debian.org>.

saslauthd was originally contributed by Lyndon Nerenberg on
behalf of MessagingDirect Ltd.
PK�h%[���4�4�#doc/alt-cyrus-sasl-lib/support.htmlnu�[���

<!DOCTYPE html>
<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
<head>
  <meta charset="utf-8">
  
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  
  <title>Support/Community &mdash; Cyrus SASL 2.1.27 documentation</title>
  

  
  
    <link rel="shortcut icon" href="_static/favicon.ico"/>
  

  

  
  
    

  

  
  
    <link rel="stylesheet" href="_static/css/theme.css" type="text/css" />
  

  
    <link rel="stylesheet" href="_static/cyrus.css" type="text/css" />
  

  
        <link rel="index" title="Index"
              href="genindex.html"/>
        <link rel="search" title="Search" href="search.html"/>
    <link rel="top" title="Cyrus SASL 2.1.27 documentation" href="index.html"/>
        <link rel="prev" title="Testing" href="sasl/developer/testing.html"/> 

  
  
  

</head>

<body class="wy-body-for-nav" role="document">

  
  
<div class="pageheader">
  <ul>
    <li><a href="index.html">Home</a></li>
    <li><a href="http://www.cyrusimap.org">Cyrus IMAP</a></li>
    <li><a href="download.html">Download</a></li>
    <li><a href="contribute.html">Contribute</a></li>
  </ul>
  <div>
    <a href="index.html">
      <img src="_static/logo.gif" alt="CYRUS SASL" />
    </a>
  </div>
</div>
<div style="clear: both;"></div>


  <div class="wy-grid-for-nav">

    
    <nav data-toggle="wy-nav-shift" class="wy-nav-side">
      <div class="wy-side-nav-search">
        

        
 
          <a href="index.html">
 

  
          
          <img src="_static/logo.gif"  />
     
        </a>

        
<div role="search">
  <form id="rtd-search-form" class="wy-form" action="search.html" method="get">
    <input type="text" name="q" placeholder="Search docs" />
    <input type="hidden" name="check_keywords" value="yes" />
    <input type="hidden" name="area" value="default" />
  </form>
</div>

        
      </div>

      <div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
        
          
          
              <p class="caption"><span class="caption-text">Cyrus SASL</span></p>
<ul class="current">
<li class="toctree-l1"><a class="reference internal" href="download.html">Download</a><ul>
<li class="toctree-l2"><a class="reference internal" href="getsasl.html">Get SASL</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html">Installation</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#quick-install-guide">Quick install guide</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#detailed-installation-guide">Detailed installation guide</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#supported-platforms">Supported platforms</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/release-notes/index.html">Release Notes</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/release-notes/index.html#supported-product-series">Supported Product Series</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/release-notes/index.html#series-2-1">Series 2.1</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/release-notes/index.html#older-versions">Older Versions</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/release-notes/index.html#series-2-2-0">Series 2: 2.0</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/release-notes/index.html#series-1">Series 1</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="packager.html">Note for Packagers</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="sasl/quickstart.html">Quickstart guide</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/quickstart.html#features">Features</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/quickstart.html#typical-installation">Typical Installation</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/quickstart.html#configuration">Configuration</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="sasl/concepts.html">Concepts</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#sasl">SASL</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#sasl-authentication-mechanisms">SASL Authentication Mechanisms</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#security-layers">Security Layers</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#channel-binding">Channel Binding</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#realms">Realms</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#protocols">Protocols</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#cyrus-sasl">Cyrus SASL</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#the-glue-library">The Glue Library</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#auxiliary-properties">Auxiliary Properties</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#plugins">Plugins</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="setup.html">Setup</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/installation.html">Installation</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html#quick-install-guide">Quick install guide</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#tarball-installation">Tarball installation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#unix-package-installation">Unix package Installation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#configuration">Configuration</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html#detailed-installation-guide">Detailed installation guide</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#requirements">Requirements</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#build-configuration">Build Configuration</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#building-and-installation">Building and Installation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#compilation-hints">Compilation Hints</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#application-configuration">Application Configuration</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html#supported-platforms">Supported platforms</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/upgrading.html">Upgrading from v1 to v2</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/upgrading.html#backwards-compatibility">Backwards Compatibility</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/upgrading.html#coexistence-with-saslv1">Coexistence with SASLv1</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/upgrading.html#database-upgrades">Database Upgrades</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/upgrading.html#errors-on-migration">Errors on migration</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/components.html">Components</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/components.html#the-application">The Application</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/components.html#the-sasl-glue-layer">The SASL Glue Layer</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/components.html#plugins">Plugins</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/components.html#plugins-general">Plugins: General</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/components.html#plugins-sasl-mechanisms">Plugins: SASL Mechanisms</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/components.html#plugins-auxiliary-property">Plugins: Auxiliary Property</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/components.html#plugins-username-canonicalization">Plugins: Username Canonicalization</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/components.html#password-verification-services">Password Verification Services</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/options.html">Options</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#sasl-library">SASL Library</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#auxiliary-property-plugin">Auxiliary Property Plugin</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#gssapi">GSSAPI</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#ldapdb">LDAPDB</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/options.html#notes-on-ldapdb">Notes on LDAPDB</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/options.html#examples">Examples</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#ntlm">NTLM</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#otp">OTP</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#digest-md5">Digest-md5</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#sasldb">SASLDB</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/options.html#notes-on-sasldb-with-lmdb">Notes on sasldb with LMDB</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#sql-plugin">SQL Plugin</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/options.html#notes-on-sql">Notes on SQL</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/options.html#id2">Examples</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#srp">SRP</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#kerberos-v4">Kerberos V4</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/advanced.html">Advanced Usage</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/advanced.html#notes-for-advanced-usage-of-libsasl">Notes for Advanced Usage of libsasl</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/advanced.html#using-cyrus-sasl-as-a-static-library">Using Cyrus SASL as a static library</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="operations.html">Operations</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/sysadmin.html">System Administrators</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#what-sasl-is">What SASL is</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#authentication-and-authorization-identifiers">Authentication and authorization identifiers</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#realms">Realms</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#how-sasl-works">How SASL works</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#the-plain-mechanism-sasl-checkpass-and-plaintext-passwords">The PLAIN mechanism, <code class="docutils literal"><span class="pre">sasl_checkpass()</span></code>, and plaintext passwords</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#shared-secrets-mechanisms">Shared secrets mechanisms</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#kerberos-mechanisms">Kerberos mechanisms</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#the-otp-mechanism">The OTP mechanism</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#auxiliary-properties">Auxiliary Properties</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#how-to-set-configuration-options">How to set configuration options</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#the-default-configuration-file">The default configuration file</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#application-configuration">Application configuration</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#troubleshooting">Troubleshooting</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/manpages.html">Man pages</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/manpages.html#library-files">(3) Library Files</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl.html"><strong>SASL</strong> - SASL Authentication Library</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_authorize_t.html"><strong>sasl_authorize_t</strong> - The SASL authorization callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_auxprop.html"><strong>sasl_auxprop</strong> - How to work with SASL auxiliary properties</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_auxprop_add_plugin.html"><strong>sasl_auxprop_add_plugin</strong> - add a SASL auxiliary property plugin</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_auxprop_getctx.html"><strong>sasl_auxprop_getctx</strong> - Acquire an auxiliary property context</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_auxprop_request.html"><strong>sasl_auxprop_request</strong> - Request auxiliary properties from SASL</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_callbacks.html"><strong>sasl_callbacks</strong> - How to work with SASL callbacks</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_canon_user_t.html"><strong>sasl_canon_user_t</strong> - Application-supplied user canonicalization function</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_canonuser_add_plugin.html"><strong>sasl_canonuser_add_plugin</strong> - add a SASL user canonicalization plugin</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_chalprompt_t.html"><strong>sasl_chalprompt_t</strong> - Realm acquisition callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_checkapop.html"><strong>sasl_checkapop</strong> - Check an APOP challenge/response</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_checkpass.html"><strong>sasl_checkpass</strong> - Check a plaintext password</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_add_plugin.html"><strong>sasl_client_add_plugin</strong> - add a SASL client plugin</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_done.html"><strong>sasl_client_done</strong> - Cleanup function</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_init.html"><strong>sasl_client_init</strong> - SASL client authentication initialization</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_new.html"><strong>sasl_client_new</strong> - Create a new client authentication object</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_plug_init_t.html"><strong>sasl_client_plug_init_t</strong> - client plug‐in entry point</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_start.html"><strong>sasl_client_start</strong> - Begin an authentication negotiation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_step.html"><strong>sasl_client_step</strong> - Perform a step in the authentication negotiation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_decode.html"><strong>sasl_decode</strong> - Decode data received</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_decode64.html"><strong>sasl_decode64</strong> - Decode base64 string</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_dispose.html"><strong>sasl_dispose</strong> - Dispose of a SASL connection object</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_done.html"><strong>sasl_done</strong> - Dispose of a SASL connection object</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_encode.html"><strong>sasl_encode</strong> - Encode data for transport to authenticated host</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_encode64.html"><strong>sasl_encode64</strong> - Encode base64 string</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_encodev.html"><strong>sasl_encodev</strong> - Encode data for transport to authenticated host</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_erasebuffer.html"><strong>sasl_erasebuffer</strong> - erase buffer</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_errdetail.html"><strong>sasl_errdetail</strong> - Retrieve  detailed information about an error</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_errors.html"><strong>sasl_errors</strong> - SASL error codes</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_errstring.html"><strong>sasl_errstring</strong> - Translate a SASL return code to a human-readable form</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getcallback_t.html"><strong>sasl_getcallback_t</strong> - callback function to lookup a sasl_callback_t for a connection</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getconfpath_t.html"><strong>sasl_getconfpath_t</strong> - The SASL callback to indicate location of the config files</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getopt_t.html"><strong>sasl_getopt_t</strong> - The SASL get option callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getpath_t.html"><strong>sasl_getpath_t</strong> - The SASL callback to indicate location of the mechanism drivers</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getprop.html"><strong>sasl_getprop</strong> - Get a SASL property</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getrealm_t.html"><strong>sasl_getrealm_t</strong> - Realm Acquisition Callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getsecret_t.html"><strong>sasl_getsecret_t</strong> - The SASL callback for secrets (passwords)</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getsimple_t.html"><strong>sasl_getsimple_t</strong> - The SASL callback for username/authname/realm</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_global_listmech.html"><strong>sasl_global_listmech</strong> - Retrieve a list of the supported SASL mechanisms</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_idle.html"><strong>sasl_idle</strong> - Perform precalculations during an idle period</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_listmech.html"><strong>sasl_listmech</strong> - Retrieve a list of the supported SASL mechanisms</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_log_t.html"><strong>sasl_log_t</strong> - The SASL logging callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_add_plugin.html"><strong>sasl_server_add_plugin</strong> - add a SASL server plugin</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_done.html"><strong>sasl_server_done</strong> - Cleanup function</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_init.html"><strong>sasl_server_init</strong> - SASL server authentication initialization</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_new.html"><strong>sasl_server_new</strong> - Create a new server authentication object</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_plug_init_t.html"><strong>sasl_server_plug_init_t</strong> - server plug‐in entry point</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_start.html"><strong>sasl_server_start</strong> - Begin an authentication negotiation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_step.html"><strong>sasl_server_step</strong> - Perform a step in the authentication negotiation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_userdb_checkpass_t.html"><strong>sasl_server_userdb_checkpass_t</strong> - Plaintext Password Verification Callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_userdb_setpass_t.html"><strong>sasl_server_userdb_setpass_t</strong> - UserDB Plaintext Password Setting Callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_set_alloc.html"><strong>sasl_set_alloc</strong> - set the memory allocation functions used by the SASL library</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_set_mutex.html"><strong>sasl_set_mutex</strong> - set the mutex lock functions used by the SASL library</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_seterror.html"><strong>sasl_seterror</strong> - set the error string</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_setpass.html"><strong>sasl_setpass</strong> - Check a plaintext password</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_setprop.html"><strong>sasl_setprop</strong> - Set a SASL property</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_user_exists.html"><strong>sasl_user_exists</strong> - Check if a user exists on server</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_usererr.html"><strong>sasl_usererr</strong> - Remove information leak about accounts from sasl error codes</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_utf8verify.html"><strong>sasl_utf8verify</strong> - Verify a string is valid utf8</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_verifyfile_t.html"><strong>sasl_verifyfile_t</strong> - The SASL file verification</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/auxiliary_properties.html">Auxiliary Properties</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#auxiliary-properties-and-the-glue-layer">Auxiliary Properties and the Glue Layer</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#passwords-and-other-data">Passwords and other Data</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#sasldb">sasldb</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#ldapdb">ldapdb</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#sql">sql</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#user-canonicalization">User Canonicalization</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/authentication_mechanisms.html">Authentication Mechanisms</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/authentication_mechanisms.html#mechanisms">Mechanisms</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#anonymous">ANONYMOUS</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#cram-md5">CRAM-MD5</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#digest-md5">DIGEST-MD5</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#external">EXTERNAL</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#g2">G2</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#gssapi">GSSAPI</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#gss-spegno">GSS-SPEGNO</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#kerberos-v4">KERBEROS_V4</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#login">LOGIN</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#ntlm">NTLM</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#otp">OTP</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#passdss">PASSDSS</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#plain">PLAIN</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#scram">SCRAM</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#srp">SRP</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#non-sasl-authentication">Non-SASL Authentication</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/authentication_mechanisms.html#summary">Summary</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/pwcheck.html">Pwcheck</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#auxprop">Auxprop</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#auxprop-hashed">Auxprop-hashed</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#saslauthd">Saslauthd</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#authdaemon">Authdaemon</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#alwaystrue">Alwaystrue</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#auto-transition">Auto Transition</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/faq.html">Frequently Asked Questions</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/authorize-vs-authenticate.html">What is the difference between an Authorization ID and a Authentication ID?</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/crammd5-digestmd5.html">Why do CRAM-MD5 and DIGEST-MD5 not work with CyrusSaslauthd?</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/openldap-sasl-gssapi.html">How do I configure OpenLDAP +SASL+GSSAPI?</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/plaintextpasswords.html">Why does CyrusSasl store plaintext passwords in its databases?</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/rfcs.html">RFCs and drafts</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/upgrade-saslv2.html">Why am I having a problem running dbconverter-2 to upgrade from SASLv1 to SASLv2?</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/resources.html">Other Documentation &amp; Resources</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="developer.html">Developers</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/appconvert.html">Converting Applications from v1 to v2</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/appconvert.html#tips-for-both-clients-and-servers">Tips for both clients and servers</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/appconvert.html#tips-for-clients">Tips for clients</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/appconvert.html#tips-for-servers">Tips for Servers</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/developer/programming.html">Application Programmer’s Guide</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#introduction">Introduction</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#about-this-guide">About this Guide</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#what-is-sasl">What is SASL?</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#background">Background</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#how-did-the-world-work-before-sasl">How did the world work before SASL?</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#sasl-to-the-rescue">SASL to the rescue!</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#briefly">Briefly</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#what-is-the-cyrus-sasl-library-good-for">What is the Cyrus SASL library good for?</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#what-does-the-cyrus-sasl-library-do">What does the Cyrus SASL library do?</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#what-doesn-t-the-cyrus-sasl-library-do">What doesn’t the Cyrus SASL library do?</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#client-only-section">Client-only Section</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#a-typical-interaction-from-the-client-s-perspective">A typical interaction from the client’s perspective</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#how-does-this-look-in-code">How does this look in code</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#server-only-section">Server-only Section</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#a-typical-interaction-from-the-server-s-perspective">A typical interaction from the server’s perspective</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#id1">How does this look in code?</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#common-section">Common Section</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#callbacks-and-interactions">Callbacks and Interactions</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#security-layers">Security layers</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#example-applications-that-come-with-the-cyrus-sasl-library">Example applications that come with the Cyrus SASL library</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#sample-client-and-sample-server"><cite>sample-client</cite> and <cite>sample-server</cite></a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#cyrus-imapd-v2-1-0-or-later">Cyrus imapd v2.1.0 or later</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#imtest-from-cyrus-2-1-0-or-later"><cite>imtest</cite>, from Cyrus 2.1.0 or later</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#miscellaneous-information">Miscellaneous Information</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#empty-exchanges">Empty exchanges</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#idle">Idle</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/developer/plugprog.html">Plugin Programmer’s Guide</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#introduction">Introduction</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#about-this-guide">About this Guide</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#what-is-sasl">What is SASL?</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#common-section">Common Section</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#overview-of-plugin-programming">Overview of Plugin Programming</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#use-of-sasl-utils-t">Use of sasl_utils_t</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#error-reporting">Error Reporting</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#memory-allocation">Memory Allocation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#client-send-first-server-send-last">Client Send First / Server Send Last</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#client-plugins">Client Plugins</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#server-plugins">Server Plugins</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#user-canonicalization-canon-user-plugins">User Canonicalization (canon_user) Plugins</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#auxiliary-property-auxprop-plugins">Auxiliary Property (auxprop) Plugins</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/developer/testing.html">Testing</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/testing.html#testing-the-cmu-sasl-library-with-the-included-sample-applications">Testing the CMU SASL Library with the included sample applications</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/testing.html#example">Example</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/testing.html#running-the-testsuite-application">Running the Testsuite application</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l1 current"><a class="current reference internal" href="#">Support/Community</a></li>
</ul>
<p class="caption"><span class="caption-text">IMAP</span></p>
<ul>
<li class="toctree-l1"><a class="reference external" href="http://www.cyrusimap.org">Cyrus IMAP</a></li>
</ul>

          
        
      </div>
      &nbsp;
    </nav>

    <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">

      
      <nav class="wy-nav-top" role="navigation" aria-label="top navigation">
        <i data-toggle="wy-nav-top" class="fa fa-bars"></i>
        <a href="index.html">Cyrus SASL</a>
      </nav>


      
      <div class="wy-nav-content">
        <div class="rst-content">
          
          <div role="navigation" aria-label="breadcrumbs navigation">
  <ul class="wy-breadcrumbs">
      <li><a href="index.html">Docs v2.1.27</a> &raquo;</li>
      
    <li>Support/Community</li>
      <li class="wy-breadcrumbs-aside">
        
          
            <a href="https://github.com/cyrusimap/cyrus-sasl/blob/master/docsrc/support.rst" class="fa fa-github"> Edit on GitHub</a>
          
        
      </li>
  </ul>
  <hr/>
</div>
          <div role="main" class="document">
            
  <div class="section" id="support-community">
<h1>Support/Community<a class="headerlink" href="#support-community" title="Permalink to this headline">¶</a></h1>
<p>Please read our support and bug reporting guidelines in the <a class="reference external" href="https://www.cyrusimap.org/support.html#support" title="(in Cyrus IMAP v3.0.8)"><span class="xref std std-ref">Cyrus IMAP project</span></a>.</p>
</div>


          </div>
          <footer>
  
    <div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
      
      
        <a href="sasl/developer/testing.html" class="btn btn-neutral" title="Testing" accesskey="p"><span class="fa fa-arrow-circle-left"></span> Previous</a>
      
    </div>
  

  <hr/>

  <div role="contentinfo">
    <p>
        &copy; Copyright 1993-2016, The Cyrus Team.
    </p>
  </div>
  Built with <a href="http://sphinx-doc.org/">Sphinx</a> 1.6.6 using a modified <a href="https://readthedocs.org">Read the Docs</a> <a href="https://github.com/snide/sphinx_rtd_theme">theme</a>.

</footer>

        </div>
      </div>

    </section>

  </div>
  


  

    <script type="text/javascript">
        var DOCUMENTATION_OPTIONS = {
            URL_ROOT:'./',
            VERSION:'2.1.27',
            COLLAPSE_INDEX:false,
            FILE_SUFFIX:'.html',
            HAS_SOURCE:  true
        };
    </script>
      <script type="text/javascript" src="_static/jquery.js"></script>
      <script type="text/javascript" src="_static/underscore.js"></script>
      <script type="text/javascript" src="_static/doctools.js"></script>
      <script type="text/javascript" src="https://cdn.mathjax.org/mathjax/latest/MathJax.js"></script>

  

  
  
    <script type="text/javascript" src="_static/js/theme.js"></script>
  

  
  
  <script type="text/javascript">
<!--      jQuery(function () {
          SphinxRtdTheme.StickyNav.enable();
      }); -->
  </script>
  
 



</body>
</html>PK�h%[.�	��$doc/alt-cyrus-sasl-lib/packager.htmlnu�[���

<!DOCTYPE html>
<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
<head>
  <meta charset="utf-8">
  
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  
  <title>Note for Packagers &mdash; Cyrus SASL 2.1.27 documentation</title>
  

  
  
    <link rel="shortcut icon" href="_static/favicon.ico"/>
  

  

  
  
    

  

  
  
    <link rel="stylesheet" href="_static/css/theme.css" type="text/css" />
  

  
    <link rel="stylesheet" href="_static/cyrus.css" type="text/css" />
  

  
        <link rel="index" title="Index"
              href="genindex.html"/>
        <link rel="search" title="Search" href="search.html"/>
    <link rel="top" title="Cyrus SASL 2.1.27 documentation" href="index.html"/>
        <link rel="up" title="Download" href="download.html"/>
        <link rel="next" title="Quickstart guide" href="sasl/quickstart.html"/>
        <link rel="prev" title="Cyrus SASL 1.x Release Notes" href="sasl/release-notes/1/index.html"/> 

  
  
  

</head>

<body class="wy-body-for-nav" role="document">

  
  
<div class="pageheader">
  <ul>
    <li><a href="index.html">Home</a></li>
    <li><a href="http://www.cyrusimap.org">Cyrus IMAP</a></li>
    <li><a href="download.html">Download</a></li>
    <li><a href="contribute.html">Contribute</a></li>
  </ul>
  <div>
    <a href="index.html">
      <img src="_static/logo.gif" alt="CYRUS SASL" />
    </a>
  </div>
</div>
<div style="clear: both;"></div>


  <div class="wy-grid-for-nav">

    
    <nav data-toggle="wy-nav-shift" class="wy-nav-side">
      <div class="wy-side-nav-search">
        

        
 
          <a href="index.html">
 

  
          
          <img src="_static/logo.gif"  />
     
        </a>

        
<div role="search">
  <form id="rtd-search-form" class="wy-form" action="search.html" method="get">
    <input type="text" name="q" placeholder="Search docs" />
    <input type="hidden" name="check_keywords" value="yes" />
    <input type="hidden" name="area" value="default" />
  </form>
</div>

        
      </div>

      <div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
        
          
          
              <p class="caption"><span class="caption-text">Cyrus SASL</span></p>
<ul class="current">
<li class="toctree-l1 current"><a class="reference internal" href="download.html">Download</a><ul class="current">
<li class="toctree-l2"><a class="reference internal" href="getsasl.html">Get SASL</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html">Installation</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#quick-install-guide">Quick install guide</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#detailed-installation-guide">Detailed installation guide</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#supported-platforms">Supported platforms</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/release-notes/index.html">Release Notes</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/release-notes/index.html#supported-product-series">Supported Product Series</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/release-notes/index.html#series-2-1">Series 2.1</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/release-notes/index.html#older-versions">Older Versions</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/release-notes/index.html#series-2-2-0">Series 2: 2.0</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/release-notes/index.html#series-1">Series 1</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l2 current"><a class="current reference internal" href="#">Note for Packagers</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="sasl/quickstart.html">Quickstart guide</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/quickstart.html#features">Features</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/quickstart.html#typical-installation">Typical Installation</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/quickstart.html#configuration">Configuration</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="sasl/concepts.html">Concepts</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#sasl">SASL</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#sasl-authentication-mechanisms">SASL Authentication Mechanisms</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#security-layers">Security Layers</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#channel-binding">Channel Binding</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#realms">Realms</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#protocols">Protocols</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#cyrus-sasl">Cyrus SASL</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#the-glue-library">The Glue Library</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#auxiliary-properties">Auxiliary Properties</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#plugins">Plugins</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="setup.html">Setup</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/installation.html">Installation</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html#quick-install-guide">Quick install guide</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#tarball-installation">Tarball installation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#unix-package-installation">Unix package Installation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#configuration">Configuration</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html#detailed-installation-guide">Detailed installation guide</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#requirements">Requirements</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#build-configuration">Build Configuration</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#building-and-installation">Building and Installation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#compilation-hints">Compilation Hints</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#application-configuration">Application Configuration</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html#supported-platforms">Supported platforms</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/upgrading.html">Upgrading from v1 to v2</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/upgrading.html#backwards-compatibility">Backwards Compatibility</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/upgrading.html#coexistence-with-saslv1">Coexistence with SASLv1</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/upgrading.html#database-upgrades">Database Upgrades</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/upgrading.html#errors-on-migration">Errors on migration</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/components.html">Components</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/components.html#the-application">The Application</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/components.html#the-sasl-glue-layer">The SASL Glue Layer</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/components.html#plugins">Plugins</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/components.html#plugins-general">Plugins: General</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/components.html#plugins-sasl-mechanisms">Plugins: SASL Mechanisms</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/components.html#plugins-auxiliary-property">Plugins: Auxiliary Property</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/components.html#plugins-username-canonicalization">Plugins: Username Canonicalization</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/components.html#password-verification-services">Password Verification Services</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/options.html">Options</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#sasl-library">SASL Library</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#auxiliary-property-plugin">Auxiliary Property Plugin</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#gssapi">GSSAPI</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#ldapdb">LDAPDB</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/options.html#notes-on-ldapdb">Notes on LDAPDB</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/options.html#examples">Examples</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#ntlm">NTLM</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#otp">OTP</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#digest-md5">Digest-md5</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#sasldb">SASLDB</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/options.html#notes-on-sasldb-with-lmdb">Notes on sasldb with LMDB</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#sql-plugin">SQL Plugin</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/options.html#notes-on-sql">Notes on SQL</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/options.html#id2">Examples</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#srp">SRP</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#kerberos-v4">Kerberos V4</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/advanced.html">Advanced Usage</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/advanced.html#notes-for-advanced-usage-of-libsasl">Notes for Advanced Usage of libsasl</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/advanced.html#using-cyrus-sasl-as-a-static-library">Using Cyrus SASL as a static library</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="operations.html">Operations</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/sysadmin.html">System Administrators</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#what-sasl-is">What SASL is</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#authentication-and-authorization-identifiers">Authentication and authorization identifiers</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#realms">Realms</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#how-sasl-works">How SASL works</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#the-plain-mechanism-sasl-checkpass-and-plaintext-passwords">The PLAIN mechanism, <code class="docutils literal"><span class="pre">sasl_checkpass()</span></code>, and plaintext passwords</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#shared-secrets-mechanisms">Shared secrets mechanisms</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#kerberos-mechanisms">Kerberos mechanisms</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#the-otp-mechanism">The OTP mechanism</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#auxiliary-properties">Auxiliary Properties</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#how-to-set-configuration-options">How to set configuration options</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#the-default-configuration-file">The default configuration file</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#application-configuration">Application configuration</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#troubleshooting">Troubleshooting</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/manpages.html">Man pages</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/manpages.html#library-files">(3) Library Files</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl.html"><strong>SASL</strong> - SASL Authentication Library</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_authorize_t.html"><strong>sasl_authorize_t</strong> - The SASL authorization callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_auxprop.html"><strong>sasl_auxprop</strong> - How to work with SASL auxiliary properties</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_auxprop_add_plugin.html"><strong>sasl_auxprop_add_plugin</strong> - add a SASL auxiliary property plugin</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_auxprop_getctx.html"><strong>sasl_auxprop_getctx</strong> - Acquire an auxiliary property context</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_auxprop_request.html"><strong>sasl_auxprop_request</strong> - Request auxiliary properties from SASL</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_callbacks.html"><strong>sasl_callbacks</strong> - How to work with SASL callbacks</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_canon_user_t.html"><strong>sasl_canon_user_t</strong> - Application-supplied user canonicalization function</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_canonuser_add_plugin.html"><strong>sasl_canonuser_add_plugin</strong> - add a SASL user canonicalization plugin</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_chalprompt_t.html"><strong>sasl_chalprompt_t</strong> - Realm acquisition callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_checkapop.html"><strong>sasl_checkapop</strong> - Check an APOP challenge/response</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_checkpass.html"><strong>sasl_checkpass</strong> - Check a plaintext password</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_add_plugin.html"><strong>sasl_client_add_plugin</strong> - add a SASL client plugin</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_done.html"><strong>sasl_client_done</strong> - Cleanup function</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_init.html"><strong>sasl_client_init</strong> - SASL client authentication initialization</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_new.html"><strong>sasl_client_new</strong> - Create a new client authentication object</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_plug_init_t.html"><strong>sasl_client_plug_init_t</strong> - client plug‐in entry point</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_start.html"><strong>sasl_client_start</strong> - Begin an authentication negotiation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_step.html"><strong>sasl_client_step</strong> - Perform a step in the authentication negotiation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_decode.html"><strong>sasl_decode</strong> - Decode data received</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_decode64.html"><strong>sasl_decode64</strong> - Decode base64 string</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_dispose.html"><strong>sasl_dispose</strong> - Dispose of a SASL connection object</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_done.html"><strong>sasl_done</strong> - Dispose of a SASL connection object</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_encode.html"><strong>sasl_encode</strong> - Encode data for transport to authenticated host</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_encode64.html"><strong>sasl_encode64</strong> - Encode base64 string</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_encodev.html"><strong>sasl_encodev</strong> - Encode data for transport to authenticated host</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_erasebuffer.html"><strong>sasl_erasebuffer</strong> - erase buffer</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_errdetail.html"><strong>sasl_errdetail</strong> - Retrieve  detailed information about an error</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_errors.html"><strong>sasl_errors</strong> - SASL error codes</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_errstring.html"><strong>sasl_errstring</strong> - Translate a SASL return code to a human-readable form</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getcallback_t.html"><strong>sasl_getcallback_t</strong> - callback function to lookup a sasl_callback_t for a connection</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getconfpath_t.html"><strong>sasl_getconfpath_t</strong> - The SASL callback to indicate location of the config files</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getopt_t.html"><strong>sasl_getopt_t</strong> - The SASL get option callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getpath_t.html"><strong>sasl_getpath_t</strong> - The SASL callback to indicate location of the mechanism drivers</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getprop.html"><strong>sasl_getprop</strong> - Get a SASL property</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getrealm_t.html"><strong>sasl_getrealm_t</strong> - Realm Acquisition Callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getsecret_t.html"><strong>sasl_getsecret_t</strong> - The SASL callback for secrets (passwords)</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getsimple_t.html"><strong>sasl_getsimple_t</strong> - The SASL callback for username/authname/realm</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_global_listmech.html"><strong>sasl_global_listmech</strong> - Retrieve a list of the supported SASL mechanisms</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_idle.html"><strong>sasl_idle</strong> - Perform precalculations during an idle period</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_listmech.html"><strong>sasl_listmech</strong> - Retrieve a list of the supported SASL mechanisms</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_log_t.html"><strong>sasl_log_t</strong> - The SASL logging callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_add_plugin.html"><strong>sasl_server_add_plugin</strong> - add a SASL server plugin</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_done.html"><strong>sasl_server_done</strong> - Cleanup function</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_init.html"><strong>sasl_server_init</strong> - SASL server authentication initialization</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_new.html"><strong>sasl_server_new</strong> - Create a new server authentication object</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_plug_init_t.html"><strong>sasl_server_plug_init_t</strong> - server plug‐in entry point</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_start.html"><strong>sasl_server_start</strong> - Begin an authentication negotiation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_step.html"><strong>sasl_server_step</strong> - Perform a step in the authentication negotiation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_userdb_checkpass_t.html"><strong>sasl_server_userdb_checkpass_t</strong> - Plaintext Password Verification Callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_userdb_setpass_t.html"><strong>sasl_server_userdb_setpass_t</strong> - UserDB Plaintext Password Setting Callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_set_alloc.html"><strong>sasl_set_alloc</strong> - set the memory allocation functions used by the SASL library</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_set_mutex.html"><strong>sasl_set_mutex</strong> - set the mutex lock functions used by the SASL library</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_seterror.html"><strong>sasl_seterror</strong> - set the error string</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_setpass.html"><strong>sasl_setpass</strong> - Check a plaintext password</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_setprop.html"><strong>sasl_setprop</strong> - Set a SASL property</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_user_exists.html"><strong>sasl_user_exists</strong> - Check if a user exists on server</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_usererr.html"><strong>sasl_usererr</strong> - Remove information leak about accounts from sasl error codes</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_utf8verify.html"><strong>sasl_utf8verify</strong> - Verify a string is valid utf8</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_verifyfile_t.html"><strong>sasl_verifyfile_t</strong> - The SASL file verification</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/auxiliary_properties.html">Auxiliary Properties</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#auxiliary-properties-and-the-glue-layer">Auxiliary Properties and the Glue Layer</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#passwords-and-other-data">Passwords and other Data</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#sasldb">sasldb</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#ldapdb">ldapdb</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#sql">sql</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#user-canonicalization">User Canonicalization</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/authentication_mechanisms.html">Authentication Mechanisms</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/authentication_mechanisms.html#mechanisms">Mechanisms</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#anonymous">ANONYMOUS</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#cram-md5">CRAM-MD5</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#digest-md5">DIGEST-MD5</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#external">EXTERNAL</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#g2">G2</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#gssapi">GSSAPI</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#gss-spegno">GSS-SPEGNO</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#kerberos-v4">KERBEROS_V4</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#login">LOGIN</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#ntlm">NTLM</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#otp">OTP</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#passdss">PASSDSS</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#plain">PLAIN</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#scram">SCRAM</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#srp">SRP</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#non-sasl-authentication">Non-SASL Authentication</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/authentication_mechanisms.html#summary">Summary</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/pwcheck.html">Pwcheck</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#auxprop">Auxprop</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#auxprop-hashed">Auxprop-hashed</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#saslauthd">Saslauthd</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#authdaemon">Authdaemon</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#alwaystrue">Alwaystrue</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#auto-transition">Auto Transition</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/faq.html">Frequently Asked Questions</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/authorize-vs-authenticate.html">What is the difference between an Authorization ID and a Authentication ID?</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/crammd5-digestmd5.html">Why do CRAM-MD5 and DIGEST-MD5 not work with CyrusSaslauthd?</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/openldap-sasl-gssapi.html">How do I configure OpenLDAP +SASL+GSSAPI?</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/plaintextpasswords.html">Why does CyrusSasl store plaintext passwords in its databases?</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/rfcs.html">RFCs and drafts</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/upgrade-saslv2.html">Why am I having a problem running dbconverter-2 to upgrade from SASLv1 to SASLv2?</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/resources.html">Other Documentation &amp; Resources</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="developer.html">Developers</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/appconvert.html">Converting Applications from v1 to v2</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/appconvert.html#tips-for-both-clients-and-servers">Tips for both clients and servers</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/appconvert.html#tips-for-clients">Tips for clients</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/appconvert.html#tips-for-servers">Tips for Servers</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/developer/programming.html">Application Programmer’s Guide</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#introduction">Introduction</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#about-this-guide">About this Guide</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#what-is-sasl">What is SASL?</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#background">Background</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#how-did-the-world-work-before-sasl">How did the world work before SASL?</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#sasl-to-the-rescue">SASL to the rescue!</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#briefly">Briefly</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#what-is-the-cyrus-sasl-library-good-for">What is the Cyrus SASL library good for?</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#what-does-the-cyrus-sasl-library-do">What does the Cyrus SASL library do?</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#what-doesn-t-the-cyrus-sasl-library-do">What doesn’t the Cyrus SASL library do?</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#client-only-section">Client-only Section</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#a-typical-interaction-from-the-client-s-perspective">A typical interaction from the client’s perspective</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#how-does-this-look-in-code">How does this look in code</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#server-only-section">Server-only Section</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#a-typical-interaction-from-the-server-s-perspective">A typical interaction from the server’s perspective</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#id1">How does this look in code?</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#common-section">Common Section</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#callbacks-and-interactions">Callbacks and Interactions</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#security-layers">Security layers</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#example-applications-that-come-with-the-cyrus-sasl-library">Example applications that come with the Cyrus SASL library</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#sample-client-and-sample-server"><cite>sample-client</cite> and <cite>sample-server</cite></a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#cyrus-imapd-v2-1-0-or-later">Cyrus imapd v2.1.0 or later</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#imtest-from-cyrus-2-1-0-or-later"><cite>imtest</cite>, from Cyrus 2.1.0 or later</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#miscellaneous-information">Miscellaneous Information</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#empty-exchanges">Empty exchanges</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#idle">Idle</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/developer/plugprog.html">Plugin Programmer’s Guide</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#introduction">Introduction</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#about-this-guide">About this Guide</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#what-is-sasl">What is SASL?</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#common-section">Common Section</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#overview-of-plugin-programming">Overview of Plugin Programming</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#use-of-sasl-utils-t">Use of sasl_utils_t</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#error-reporting">Error Reporting</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#memory-allocation">Memory Allocation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#client-send-first-server-send-last">Client Send First / Server Send Last</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#client-plugins">Client Plugins</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#server-plugins">Server Plugins</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#user-canonicalization-canon-user-plugins">User Canonicalization (canon_user) Plugins</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#auxiliary-property-auxprop-plugins">Auxiliary Property (auxprop) Plugins</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/developer/testing.html">Testing</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/testing.html#testing-the-cmu-sasl-library-with-the-included-sample-applications">Testing the CMU SASL Library with the included sample applications</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/testing.html#example">Example</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/testing.html#running-the-testsuite-application">Running the Testsuite application</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="support.html">Support/Community</a></li>
</ul>
<p class="caption"><span class="caption-text">IMAP</span></p>
<ul>
<li class="toctree-l1"><a class="reference external" href="http://www.cyrusimap.org">Cyrus IMAP</a></li>
</ul>

          
        
      </div>
      &nbsp;
    </nav>

    <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">

      
      <nav class="wy-nav-top" role="navigation" aria-label="top navigation">
        <i data-toggle="wy-nav-top" class="fa fa-bars"></i>
        <a href="index.html">Cyrus SASL</a>
      </nav>


      
      <div class="wy-nav-content">
        <div class="rst-content">
          
          <div role="navigation" aria-label="breadcrumbs navigation">
  <ul class="wy-breadcrumbs">
      <li><a href="index.html">Docs v2.1.27</a> &raquo;</li>
      
          <li><a href="download.html">Download</a> &raquo;</li>
      
    <li>Note for Packagers</li>
      <li class="wy-breadcrumbs-aside">
        
          
            <a href="https://github.com/cyrusimap/cyrus-sasl/blob/master/docsrc/packager.rst" class="fa fa-github"> Edit on GitHub</a>
          
        
      </li>
  </ul>
  <hr/>
</div>
          <div role="main" class="document">
            
  <div class="section" id="note-for-packagers">
<h1>Note for Packagers<a class="headerlink" href="#note-for-packagers" title="Permalink to this headline">¶</a></h1>
<p>People considering doing binary distributions that include saslauthd
should be aware that the code is covered by several slightly different
(but compatible) licenses, due to how it was contributed.  Details can
be found within the source code.</p>
</div>


          </div>
          <footer>
  
    <div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
      
        <a href="sasl/quickstart.html" class="btn btn-neutral float-right" title="Quickstart guide" accesskey="n">Next <span class="fa fa-arrow-circle-right"></span></a>
      
      
        <a href="sasl/release-notes/1/index.html" class="btn btn-neutral" title="Cyrus SASL 1.x Release Notes" accesskey="p"><span class="fa fa-arrow-circle-left"></span> Previous</a>
      
    </div>
  

  <hr/>

  <div role="contentinfo">
    <p>
        &copy; Copyright 1993-2016, The Cyrus Team.
    </p>
  </div>
  Built with <a href="http://sphinx-doc.org/">Sphinx</a> 1.6.6 using a modified <a href="https://readthedocs.org">Read the Docs</a> <a href="https://github.com/snide/sphinx_rtd_theme">theme</a>.

</footer>

        </div>
      </div>

    </section>

  </div>
  


  

    <script type="text/javascript">
        var DOCUMENTATION_OPTIONS = {
            URL_ROOT:'./',
            VERSION:'2.1.27',
            COLLAPSE_INDEX:false,
            FILE_SUFFIX:'.html',
            HAS_SOURCE:  true
        };
    </script>
      <script type="text/javascript" src="_static/jquery.js"></script>
      <script type="text/javascript" src="_static/underscore.js"></script>
      <script type="text/javascript" src="_static/doctools.js"></script>
      <script type="text/javascript" src="https://cdn.mathjax.org/mathjax/latest/MathJax.js"></script>

  

  
  
    <script type="text/javascript" src="_static/js/theme.js"></script>
  

  
  
  <script type="text/javascript">
<!--      jQuery(function () {
          SphinxRtdTheme.StickyNav.enable();
      }); -->
  </script>
  
 



</body>
</html>PK�h%[�R �ÿÿ%doc/alt-cyrus-sasl-lib/developer.htmlnu�[���

<!DOCTYPE html>
<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
<head>
  <meta charset="utf-8">
  
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  
  <title>Developers &mdash; Cyrus SASL 2.1.27 documentation</title>
  

  
  
    <link rel="shortcut icon" href="_static/favicon.ico"/>
  

  

  
  
    

  

  
  
    <link rel="stylesheet" href="_static/css/theme.css" type="text/css" />
  

  
    <link rel="stylesheet" href="_static/cyrus.css" type="text/css" />
  

  
        <link rel="index" title="Index"
              href="genindex.html"/>
        <link rel="search" title="Search" href="search.html"/>
    <link rel="top" title="Cyrus SASL 2.1.27 documentation" href="index.html"/>
        <link rel="next" title="Converting Applications from v1 to v2" href="sasl/appconvert.html"/>
        <link rel="prev" title="Other Documentation &amp; Resources" href="sasl/resources.html"/> 

  
  
  

</head>

<body class="wy-body-for-nav" role="document">

  
  
<div class="pageheader">
  <ul>
    <li><a href="index.html">Home</a></li>
    <li><a href="http://www.cyrusimap.org">Cyrus IMAP</a></li>
    <li><a href="download.html">Download</a></li>
    <li><a href="contribute.html">Contribute</a></li>
  </ul>
  <div>
    <a href="index.html">
      <img src="_static/logo.gif" alt="CYRUS SASL" />
    </a>
  </div>
</div>
<div style="clear: both;"></div>


  <div class="wy-grid-for-nav">

    
    <nav data-toggle="wy-nav-shift" class="wy-nav-side">
      <div class="wy-side-nav-search">
        

        
 
          <a href="index.html">
 

  
          
          <img src="_static/logo.gif"  />
     
        </a>

        
<div role="search">
  <form id="rtd-search-form" class="wy-form" action="search.html" method="get">
    <input type="text" name="q" placeholder="Search docs" />
    <input type="hidden" name="check_keywords" value="yes" />
    <input type="hidden" name="area" value="default" />
  </form>
</div>

        
      </div>

      <div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
        
          
          
              <p class="caption"><span class="caption-text">Cyrus SASL</span></p>
<ul class="current">
<li class="toctree-l1"><a class="reference internal" href="download.html">Download</a><ul>
<li class="toctree-l2"><a class="reference internal" href="getsasl.html">Get SASL</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html">Installation</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#quick-install-guide">Quick install guide</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#detailed-installation-guide">Detailed installation guide</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#supported-platforms">Supported platforms</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/release-notes/index.html">Release Notes</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/release-notes/index.html#supported-product-series">Supported Product Series</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/release-notes/index.html#series-2-1">Series 2.1</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/release-notes/index.html#older-versions">Older Versions</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/release-notes/index.html#series-2-2-0">Series 2: 2.0</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/release-notes/index.html#series-1">Series 1</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="packager.html">Note for Packagers</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="sasl/quickstart.html">Quickstart guide</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/quickstart.html#features">Features</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/quickstart.html#typical-installation">Typical Installation</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/quickstart.html#configuration">Configuration</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="sasl/concepts.html">Concepts</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#sasl">SASL</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#sasl-authentication-mechanisms">SASL Authentication Mechanisms</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#security-layers">Security Layers</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#channel-binding">Channel Binding</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#realms">Realms</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#protocols">Protocols</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#cyrus-sasl">Cyrus SASL</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#the-glue-library">The Glue Library</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#auxiliary-properties">Auxiliary Properties</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#plugins">Plugins</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="setup.html">Setup</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/installation.html">Installation</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html#quick-install-guide">Quick install guide</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#tarball-installation">Tarball installation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#unix-package-installation">Unix package Installation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#configuration">Configuration</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html#detailed-installation-guide">Detailed installation guide</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#requirements">Requirements</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#build-configuration">Build Configuration</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#building-and-installation">Building and Installation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#compilation-hints">Compilation Hints</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#application-configuration">Application Configuration</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html#supported-platforms">Supported platforms</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/upgrading.html">Upgrading from v1 to v2</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/upgrading.html#backwards-compatibility">Backwards Compatibility</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/upgrading.html#coexistence-with-saslv1">Coexistence with SASLv1</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/upgrading.html#database-upgrades">Database Upgrades</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/upgrading.html#errors-on-migration">Errors on migration</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/components.html">Components</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/components.html#the-application">The Application</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/components.html#the-sasl-glue-layer">The SASL Glue Layer</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/components.html#plugins">Plugins</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/components.html#plugins-general">Plugins: General</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/components.html#plugins-sasl-mechanisms">Plugins: SASL Mechanisms</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/components.html#plugins-auxiliary-property">Plugins: Auxiliary Property</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/components.html#plugins-username-canonicalization">Plugins: Username Canonicalization</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/components.html#password-verification-services">Password Verification Services</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/options.html">Options</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#sasl-library">SASL Library</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#auxiliary-property-plugin">Auxiliary Property Plugin</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#gssapi">GSSAPI</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#ldapdb">LDAPDB</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/options.html#notes-on-ldapdb">Notes on LDAPDB</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/options.html#examples">Examples</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#ntlm">NTLM</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#otp">OTP</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#digest-md5">Digest-md5</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#sasldb">SASLDB</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/options.html#notes-on-sasldb-with-lmdb">Notes on sasldb with LMDB</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#sql-plugin">SQL Plugin</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/options.html#notes-on-sql">Notes on SQL</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/options.html#id2">Examples</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#srp">SRP</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#kerberos-v4">Kerberos V4</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/advanced.html">Advanced Usage</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/advanced.html#notes-for-advanced-usage-of-libsasl">Notes for Advanced Usage of libsasl</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/advanced.html#using-cyrus-sasl-as-a-static-library">Using Cyrus SASL as a static library</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="operations.html">Operations</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/sysadmin.html">System Administrators</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#what-sasl-is">What SASL is</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#authentication-and-authorization-identifiers">Authentication and authorization identifiers</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#realms">Realms</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#how-sasl-works">How SASL works</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#the-plain-mechanism-sasl-checkpass-and-plaintext-passwords">The PLAIN mechanism, <code class="docutils literal"><span class="pre">sasl_checkpass()</span></code>, and plaintext passwords</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#shared-secrets-mechanisms">Shared secrets mechanisms</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#kerberos-mechanisms">Kerberos mechanisms</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#the-otp-mechanism">The OTP mechanism</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#auxiliary-properties">Auxiliary Properties</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#how-to-set-configuration-options">How to set configuration options</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#the-default-configuration-file">The default configuration file</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#application-configuration">Application configuration</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#troubleshooting">Troubleshooting</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/manpages.html">Man pages</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/manpages.html#library-files">(3) Library Files</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl.html"><strong>SASL</strong> - SASL Authentication Library</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_authorize_t.html"><strong>sasl_authorize_t</strong> - The SASL authorization callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_auxprop.html"><strong>sasl_auxprop</strong> - How to work with SASL auxiliary properties</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_auxprop_add_plugin.html"><strong>sasl_auxprop_add_plugin</strong> - add a SASL auxiliary property plugin</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_auxprop_getctx.html"><strong>sasl_auxprop_getctx</strong> - Acquire an auxiliary property context</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_auxprop_request.html"><strong>sasl_auxprop_request</strong> - Request auxiliary properties from SASL</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_callbacks.html"><strong>sasl_callbacks</strong> - How to work with SASL callbacks</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_canon_user_t.html"><strong>sasl_canon_user_t</strong> - Application-supplied user canonicalization function</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_canonuser_add_plugin.html"><strong>sasl_canonuser_add_plugin</strong> - add a SASL user canonicalization plugin</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_chalprompt_t.html"><strong>sasl_chalprompt_t</strong> - Realm acquisition callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_checkapop.html"><strong>sasl_checkapop</strong> - Check an APOP challenge/response</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_checkpass.html"><strong>sasl_checkpass</strong> - Check a plaintext password</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_add_plugin.html"><strong>sasl_client_add_plugin</strong> - add a SASL client plugin</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_done.html"><strong>sasl_client_done</strong> - Cleanup function</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_init.html"><strong>sasl_client_init</strong> - SASL client authentication initialization</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_new.html"><strong>sasl_client_new</strong> - Create a new client authentication object</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_plug_init_t.html"><strong>sasl_client_plug_init_t</strong> - client plug‐in entry point</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_start.html"><strong>sasl_client_start</strong> - Begin an authentication negotiation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_step.html"><strong>sasl_client_step</strong> - Perform a step in the authentication negotiation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_decode.html"><strong>sasl_decode</strong> - Decode data received</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_decode64.html"><strong>sasl_decode64</strong> - Decode base64 string</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_dispose.html"><strong>sasl_dispose</strong> - Dispose of a SASL connection object</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_done.html"><strong>sasl_done</strong> - Dispose of a SASL connection object</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_encode.html"><strong>sasl_encode</strong> - Encode data for transport to authenticated host</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_encode64.html"><strong>sasl_encode64</strong> - Encode base64 string</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_encodev.html"><strong>sasl_encodev</strong> - Encode data for transport to authenticated host</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_erasebuffer.html"><strong>sasl_erasebuffer</strong> - erase buffer</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_errdetail.html"><strong>sasl_errdetail</strong> - Retrieve  detailed information about an error</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_errors.html"><strong>sasl_errors</strong> - SASL error codes</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_errstring.html"><strong>sasl_errstring</strong> - Translate a SASL return code to a human-readable form</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getcallback_t.html"><strong>sasl_getcallback_t</strong> - callback function to lookup a sasl_callback_t for a connection</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getconfpath_t.html"><strong>sasl_getconfpath_t</strong> - The SASL callback to indicate location of the config files</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getopt_t.html"><strong>sasl_getopt_t</strong> - The SASL get option callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getpath_t.html"><strong>sasl_getpath_t</strong> - The SASL callback to indicate location of the mechanism drivers</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getprop.html"><strong>sasl_getprop</strong> - Get a SASL property</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getrealm_t.html"><strong>sasl_getrealm_t</strong> - Realm Acquisition Callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getsecret_t.html"><strong>sasl_getsecret_t</strong> - The SASL callback for secrets (passwords)</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getsimple_t.html"><strong>sasl_getsimple_t</strong> - The SASL callback for username/authname/realm</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_global_listmech.html"><strong>sasl_global_listmech</strong> - Retrieve a list of the supported SASL mechanisms</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_idle.html"><strong>sasl_idle</strong> - Perform precalculations during an idle period</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_listmech.html"><strong>sasl_listmech</strong> - Retrieve a list of the supported SASL mechanisms</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_log_t.html"><strong>sasl_log_t</strong> - The SASL logging callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_add_plugin.html"><strong>sasl_server_add_plugin</strong> - add a SASL server plugin</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_done.html"><strong>sasl_server_done</strong> - Cleanup function</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_init.html"><strong>sasl_server_init</strong> - SASL server authentication initialization</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_new.html"><strong>sasl_server_new</strong> - Create a new server authentication object</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_plug_init_t.html"><strong>sasl_server_plug_init_t</strong> - server plug‐in entry point</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_start.html"><strong>sasl_server_start</strong> - Begin an authentication negotiation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_step.html"><strong>sasl_server_step</strong> - Perform a step in the authentication negotiation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_userdb_checkpass_t.html"><strong>sasl_server_userdb_checkpass_t</strong> - Plaintext Password Verification Callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_userdb_setpass_t.html"><strong>sasl_server_userdb_setpass_t</strong> - UserDB Plaintext Password Setting Callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_set_alloc.html"><strong>sasl_set_alloc</strong> - set the memory allocation functions used by the SASL library</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_set_mutex.html"><strong>sasl_set_mutex</strong> - set the mutex lock functions used by the SASL library</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_seterror.html"><strong>sasl_seterror</strong> - set the error string</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_setpass.html"><strong>sasl_setpass</strong> - Check a plaintext password</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_setprop.html"><strong>sasl_setprop</strong> - Set a SASL property</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_user_exists.html"><strong>sasl_user_exists</strong> - Check if a user exists on server</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_usererr.html"><strong>sasl_usererr</strong> - Remove information leak about accounts from sasl error codes</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_utf8verify.html"><strong>sasl_utf8verify</strong> - Verify a string is valid utf8</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_verifyfile_t.html"><strong>sasl_verifyfile_t</strong> - The SASL file verification</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/auxiliary_properties.html">Auxiliary Properties</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#auxiliary-properties-and-the-glue-layer">Auxiliary Properties and the Glue Layer</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#passwords-and-other-data">Passwords and other Data</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#sasldb">sasldb</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#ldapdb">ldapdb</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#sql">sql</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#user-canonicalization">User Canonicalization</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/authentication_mechanisms.html">Authentication Mechanisms</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/authentication_mechanisms.html#mechanisms">Mechanisms</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#anonymous">ANONYMOUS</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#cram-md5">CRAM-MD5</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#digest-md5">DIGEST-MD5</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#external">EXTERNAL</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#g2">G2</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#gssapi">GSSAPI</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#gss-spegno">GSS-SPEGNO</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#kerberos-v4">KERBEROS_V4</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#login">LOGIN</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#ntlm">NTLM</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#otp">OTP</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#passdss">PASSDSS</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#plain">PLAIN</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#scram">SCRAM</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#srp">SRP</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#non-sasl-authentication">Non-SASL Authentication</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/authentication_mechanisms.html#summary">Summary</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/pwcheck.html">Pwcheck</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#auxprop">Auxprop</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#auxprop-hashed">Auxprop-hashed</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#saslauthd">Saslauthd</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#authdaemon">Authdaemon</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#alwaystrue">Alwaystrue</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#auto-transition">Auto Transition</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/faq.html">Frequently Asked Questions</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/authorize-vs-authenticate.html">What is the difference between an Authorization ID and a Authentication ID?</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/crammd5-digestmd5.html">Why do CRAM-MD5 and DIGEST-MD5 not work with CyrusSaslauthd?</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/openldap-sasl-gssapi.html">How do I configure OpenLDAP +SASL+GSSAPI?</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/plaintextpasswords.html">Why does CyrusSasl store plaintext passwords in its databases?</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/rfcs.html">RFCs and drafts</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/upgrade-saslv2.html">Why am I having a problem running dbconverter-2 to upgrade from SASLv1 to SASLv2?</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/resources.html">Other Documentation &amp; Resources</a></li>
</ul>
</li>
<li class="toctree-l1 current"><a class="current reference internal" href="#">Developers</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/appconvert.html">Converting Applications from v1 to v2</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/appconvert.html#tips-for-both-clients-and-servers">Tips for both clients and servers</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/appconvert.html#tips-for-clients">Tips for clients</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/appconvert.html#tips-for-servers">Tips for Servers</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/developer/programming.html">Application Programmer’s Guide</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#introduction">Introduction</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#about-this-guide">About this Guide</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#what-is-sasl">What is SASL?</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#background">Background</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#how-did-the-world-work-before-sasl">How did the world work before SASL?</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#sasl-to-the-rescue">SASL to the rescue!</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#briefly">Briefly</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#what-is-the-cyrus-sasl-library-good-for">What is the Cyrus SASL library good for?</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#what-does-the-cyrus-sasl-library-do">What does the Cyrus SASL library do?</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#what-doesn-t-the-cyrus-sasl-library-do">What doesn’t the Cyrus SASL library do?</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#client-only-section">Client-only Section</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#a-typical-interaction-from-the-client-s-perspective">A typical interaction from the client’s perspective</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#how-does-this-look-in-code">How does this look in code</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#server-only-section">Server-only Section</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#a-typical-interaction-from-the-server-s-perspective">A typical interaction from the server’s perspective</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#id1">How does this look in code?</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#common-section">Common Section</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#callbacks-and-interactions">Callbacks and Interactions</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#security-layers">Security layers</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#example-applications-that-come-with-the-cyrus-sasl-library">Example applications that come with the Cyrus SASL library</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#sample-client-and-sample-server"><cite>sample-client</cite> and <cite>sample-server</cite></a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#cyrus-imapd-v2-1-0-or-later">Cyrus imapd v2.1.0 or later</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#imtest-from-cyrus-2-1-0-or-later"><cite>imtest</cite>, from Cyrus 2.1.0 or later</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#miscellaneous-information">Miscellaneous Information</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#empty-exchanges">Empty exchanges</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#idle">Idle</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/developer/plugprog.html">Plugin Programmer’s Guide</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#introduction">Introduction</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#about-this-guide">About this Guide</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#what-is-sasl">What is SASL?</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#common-section">Common Section</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#overview-of-plugin-programming">Overview of Plugin Programming</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#use-of-sasl-utils-t">Use of sasl_utils_t</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#error-reporting">Error Reporting</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#memory-allocation">Memory Allocation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#client-send-first-server-send-last">Client Send First / Server Send Last</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#client-plugins">Client Plugins</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#server-plugins">Server Plugins</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#user-canonicalization-canon-user-plugins">User Canonicalization (canon_user) Plugins</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#auxiliary-property-auxprop-plugins">Auxiliary Property (auxprop) Plugins</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/developer/testing.html">Testing</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/testing.html#testing-the-cmu-sasl-library-with-the-included-sample-applications">Testing the CMU SASL Library with the included sample applications</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/testing.html#example">Example</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/testing.html#running-the-testsuite-application">Running the Testsuite application</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="support.html">Support/Community</a></li>
</ul>
<p class="caption"><span class="caption-text">IMAP</span></p>
<ul>
<li class="toctree-l1"><a class="reference external" href="http://www.cyrusimap.org">Cyrus IMAP</a></li>
</ul>

          
        
      </div>
      &nbsp;
    </nav>

    <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">

      
      <nav class="wy-nav-top" role="navigation" aria-label="top navigation">
        <i data-toggle="wy-nav-top" class="fa fa-bars"></i>
        <a href="index.html">Cyrus SASL</a>
      </nav>


      
      <div class="wy-nav-content">
        <div class="rst-content">
          
          <div role="navigation" aria-label="breadcrumbs navigation">
  <ul class="wy-breadcrumbs">
      <li><a href="index.html">Docs v2.1.27</a> &raquo;</li>
      
    <li>Developers</li>
      <li class="wy-breadcrumbs-aside">
        
          
            <a href="https://github.com/cyrusimap/cyrus-sasl/blob/master/docsrc/developer.rst" class="fa fa-github"> Edit on GitHub</a>
          
        
      </li>
  </ul>
  <hr/>
</div>
          <div role="main" class="document">
            
  <div class="section" id="developers">
<h1>Developers<a class="headerlink" href="#developers" title="Permalink to this headline">¶</a></h1>
<div class="toctree-wrapper compound">
<ul>
<li class="toctree-l1"><a class="reference internal" href="sasl/appconvert.html">Converting Applications from v1 to v2</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/appconvert.html#tips-for-both-clients-and-servers">Tips for both clients and servers</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/appconvert.html#tips-for-clients">Tips for clients</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/appconvert.html#tips-for-servers">Tips for Servers</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="sasl/developer/programming.html">Application Programmer’s Guide</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/developer/programming.html#introduction">Introduction</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#about-this-guide">About this Guide</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#what-is-sasl">What is SASL?</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/developer/programming.html#background">Background</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#how-did-the-world-work-before-sasl">How did the world work before SASL?</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#sasl-to-the-rescue">SASL to the rescue!</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/developer/programming.html#briefly">Briefly</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#what-is-the-cyrus-sasl-library-good-for">What is the Cyrus SASL library good for?</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#what-does-the-cyrus-sasl-library-do">What does the Cyrus SASL library do?</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#what-doesn-t-the-cyrus-sasl-library-do">What doesn’t the Cyrus SASL library do?</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/developer/programming.html#client-only-section">Client-only Section</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#a-typical-interaction-from-the-client-s-perspective">A typical interaction from the client’s perspective</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#how-does-this-look-in-code">How does this look in code</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/developer/programming.html#server-only-section">Server-only Section</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#a-typical-interaction-from-the-server-s-perspective">A typical interaction from the server’s perspective</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#id1">How does this look in code?</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/developer/programming.html#common-section">Common Section</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#callbacks-and-interactions">Callbacks and Interactions</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#security-layers">Security layers</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/developer/programming.html#example-applications-that-come-with-the-cyrus-sasl-library">Example applications that come with the Cyrus SASL library</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#sample-client-and-sample-server"><cite>sample-client</cite> and <cite>sample-server</cite></a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#cyrus-imapd-v2-1-0-or-later">Cyrus imapd v2.1.0 or later</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#imtest-from-cyrus-2-1-0-or-later"><cite>imtest</cite>, from Cyrus 2.1.0 or later</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/developer/programming.html#miscellaneous-information">Miscellaneous Information</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#empty-exchanges">Empty exchanges</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#idle">Idle</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="sasl/developer/plugprog.html">Plugin Programmer’s Guide</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/developer/plugprog.html#introduction">Introduction</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#about-this-guide">About this Guide</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#what-is-sasl">What is SASL?</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/developer/plugprog.html#common-section">Common Section</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#overview-of-plugin-programming">Overview of Plugin Programming</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#use-of-sasl-utils-t">Use of sasl_utils_t</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#error-reporting">Error Reporting</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#memory-allocation">Memory Allocation</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#client-send-first-server-send-last">Client Send First / Server Send Last</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/developer/plugprog.html#client-plugins">Client Plugins</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/developer/plugprog.html#server-plugins">Server Plugins</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/developer/plugprog.html#user-canonicalization-canon-user-plugins">User Canonicalization (canon_user) Plugins</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/developer/plugprog.html#auxiliary-property-auxprop-plugins">Auxiliary Property (auxprop) Plugins</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="sasl/developer/testing.html">Testing</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/developer/testing.html#testing-the-cmu-sasl-library-with-the-included-sample-applications">Testing the CMU SASL Library with the included sample applications</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/testing.html#example">Example</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/developer/testing.html#running-the-testsuite-application">Running the Testsuite application</a></li>
</ul>
</li>
</ul>
</div>
</div>


          </div>
          <footer>
  
    <div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
      
        <a href="sasl/appconvert.html" class="btn btn-neutral float-right" title="Converting Applications from v1 to v2" accesskey="n">Next <span class="fa fa-arrow-circle-right"></span></a>
      
      
        <a href="sasl/resources.html" class="btn btn-neutral" title="Other Documentation &amp; Resources" accesskey="p"><span class="fa fa-arrow-circle-left"></span> Previous</a>
      
    </div>
  

  <hr/>

  <div role="contentinfo">
    <p>
        &copy; Copyright 1993-2016, The Cyrus Team.
    </p>
  </div>
  Built with <a href="http://sphinx-doc.org/">Sphinx</a> 1.6.6 using a modified <a href="https://readthedocs.org">Read the Docs</a> <a href="https://github.com/snide/sphinx_rtd_theme">theme</a>.

</footer>

        </div>
      </div>

    </section>

  </div>
  


  

    <script type="text/javascript">
        var DOCUMENTATION_OPTIONS = {
            URL_ROOT:'./',
            VERSION:'2.1.27',
            COLLAPSE_INDEX:false,
            FILE_SUFFIX:'.html',
            HAS_SOURCE:  true
        };
    </script>
      <script type="text/javascript" src="_static/jquery.js"></script>
      <script type="text/javascript" src="_static/underscore.js"></script>
      <script type="text/javascript" src="_static/doctools.js"></script>
      <script type="text/javascript" src="https://cdn.mathjax.org/mathjax/latest/MathJax.js"></script>

  

  
  
    <script type="text/javascript" src="_static/js/theme.js"></script>
  

  
  
  <script type="text/javascript">
<!--      jQuery(function () {
          SphinxRtdTheme.StickyNav.enable();
      }); -->
  </script>
  
 



</body>
</html>PK�h%[�7ll��#doc/alt-cyrus-sasl-lib/getsasl.htmlnu�[���

<!DOCTYPE html>
<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
<head>
  <meta charset="utf-8">
  
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  
  <title>Get SASL &mdash; Cyrus SASL 2.1.27 documentation</title>
  

  
  
    <link rel="shortcut icon" href="_static/favicon.ico"/>
  

  

  
  
    

  

  
  
    <link rel="stylesheet" href="_static/css/theme.css" type="text/css" />
  

  
    <link rel="stylesheet" href="_static/cyrus.css" type="text/css" />
  

  
        <link rel="index" title="Index"
              href="genindex.html"/>
        <link rel="search" title="Search" href="search.html"/>
    <link rel="top" title="Cyrus SASL 2.1.27 documentation" href="index.html"/>
        <link rel="up" title="Download" href="download.html"/>
        <link rel="next" title="Installation" href="sasl/installation.html"/>
        <link rel="prev" title="Download" href="download.html"/> 

  
  
  

</head>

<body class="wy-body-for-nav" role="document">

  
  
<div class="pageheader">
  <ul>
    <li><a href="index.html">Home</a></li>
    <li><a href="http://www.cyrusimap.org">Cyrus IMAP</a></li>
    <li><a href="download.html">Download</a></li>
    <li><a href="contribute.html">Contribute</a></li>
  </ul>
  <div>
    <a href="index.html">
      <img src="_static/logo.gif" alt="CYRUS SASL" />
    </a>
  </div>
</div>
<div style="clear: both;"></div>


  <div class="wy-grid-for-nav">

    
    <nav data-toggle="wy-nav-shift" class="wy-nav-side">
      <div class="wy-side-nav-search">
        

        
 
          <a href="index.html">
 

  
          
          <img src="_static/logo.gif"  />
     
        </a>

        
<div role="search">
  <form id="rtd-search-form" class="wy-form" action="search.html" method="get">
    <input type="text" name="q" placeholder="Search docs" />
    <input type="hidden" name="check_keywords" value="yes" />
    <input type="hidden" name="area" value="default" />
  </form>
</div>

        
      </div>

      <div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
        
          
          
              <p class="caption"><span class="caption-text">Cyrus SASL</span></p>
<ul class="current">
<li class="toctree-l1 current"><a class="reference internal" href="download.html">Download</a><ul class="current">
<li class="toctree-l2 current"><a class="current reference internal" href="#">Get SASL</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html">Installation</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#quick-install-guide">Quick install guide</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#detailed-installation-guide">Detailed installation guide</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#supported-platforms">Supported platforms</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/release-notes/index.html">Release Notes</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/release-notes/index.html#supported-product-series">Supported Product Series</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/release-notes/index.html#series-2-1">Series 2.1</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/release-notes/index.html#older-versions">Older Versions</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/release-notes/index.html#series-2-2-0">Series 2: 2.0</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/release-notes/index.html#series-1">Series 1</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="packager.html">Note for Packagers</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="sasl/quickstart.html">Quickstart guide</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/quickstart.html#features">Features</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/quickstart.html#typical-installation">Typical Installation</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/quickstart.html#configuration">Configuration</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="sasl/concepts.html">Concepts</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#sasl">SASL</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#sasl-authentication-mechanisms">SASL Authentication Mechanisms</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#security-layers">Security Layers</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#channel-binding">Channel Binding</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#realms">Realms</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#protocols">Protocols</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#cyrus-sasl">Cyrus SASL</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#the-glue-library">The Glue Library</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#auxiliary-properties">Auxiliary Properties</a></li>
<li class="toctree-l2"><a class="reference internal" href="sasl/concepts.html#plugins">Plugins</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="setup.html">Setup</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/installation.html">Installation</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html#quick-install-guide">Quick install guide</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#tarball-installation">Tarball installation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#unix-package-installation">Unix package Installation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#configuration">Configuration</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html#detailed-installation-guide">Detailed installation guide</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#requirements">Requirements</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#build-configuration">Build Configuration</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#building-and-installation">Building and Installation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#compilation-hints">Compilation Hints</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/installation.html#application-configuration">Application Configuration</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html#supported-platforms">Supported platforms</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/upgrading.html">Upgrading from v1 to v2</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/upgrading.html#backwards-compatibility">Backwards Compatibility</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/upgrading.html#coexistence-with-saslv1">Coexistence with SASLv1</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/upgrading.html#database-upgrades">Database Upgrades</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/upgrading.html#errors-on-migration">Errors on migration</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/components.html">Components</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/components.html#the-application">The Application</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/components.html#the-sasl-glue-layer">The SASL Glue Layer</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/components.html#plugins">Plugins</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/components.html#plugins-general">Plugins: General</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/components.html#plugins-sasl-mechanisms">Plugins: SASL Mechanisms</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/components.html#plugins-auxiliary-property">Plugins: Auxiliary Property</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/components.html#plugins-username-canonicalization">Plugins: Username Canonicalization</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/components.html#password-verification-services">Password Verification Services</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/options.html">Options</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#sasl-library">SASL Library</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#auxiliary-property-plugin">Auxiliary Property Plugin</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#gssapi">GSSAPI</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#ldapdb">LDAPDB</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/options.html#notes-on-ldapdb">Notes on LDAPDB</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/options.html#examples">Examples</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#ntlm">NTLM</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#otp">OTP</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#digest-md5">Digest-md5</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#sasldb">SASLDB</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/options.html#notes-on-sasldb-with-lmdb">Notes on sasldb with LMDB</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#sql-plugin">SQL Plugin</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/options.html#notes-on-sql">Notes on SQL</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/options.html#id2">Examples</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#srp">SRP</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/options.html#kerberos-v4">Kerberos V4</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/advanced.html">Advanced Usage</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/advanced.html#notes-for-advanced-usage-of-libsasl">Notes for Advanced Usage of libsasl</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/advanced.html#using-cyrus-sasl-as-a-static-library">Using Cyrus SASL as a static library</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="operations.html">Operations</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/sysadmin.html">System Administrators</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#what-sasl-is">What SASL is</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#authentication-and-authorization-identifiers">Authentication and authorization identifiers</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#realms">Realms</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#how-sasl-works">How SASL works</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#the-plain-mechanism-sasl-checkpass-and-plaintext-passwords">The PLAIN mechanism, <code class="docutils literal"><span class="pre">sasl_checkpass()</span></code>, and plaintext passwords</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#shared-secrets-mechanisms">Shared secrets mechanisms</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#kerberos-mechanisms">Kerberos mechanisms</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#the-otp-mechanism">The OTP mechanism</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#auxiliary-properties">Auxiliary Properties</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#how-to-set-configuration-options">How to set configuration options</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#the-default-configuration-file">The default configuration file</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/sysadmin.html#application-configuration">Application configuration</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/sysadmin.html#troubleshooting">Troubleshooting</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/manpages.html">Man pages</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/manpages.html#library-files">(3) Library Files</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl.html"><strong>SASL</strong> - SASL Authentication Library</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_authorize_t.html"><strong>sasl_authorize_t</strong> - The SASL authorization callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_auxprop.html"><strong>sasl_auxprop</strong> - How to work with SASL auxiliary properties</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_auxprop_add_plugin.html"><strong>sasl_auxprop_add_plugin</strong> - add a SASL auxiliary property plugin</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_auxprop_getctx.html"><strong>sasl_auxprop_getctx</strong> - Acquire an auxiliary property context</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_auxprop_request.html"><strong>sasl_auxprop_request</strong> - Request auxiliary properties from SASL</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_callbacks.html"><strong>sasl_callbacks</strong> - How to work with SASL callbacks</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_canon_user_t.html"><strong>sasl_canon_user_t</strong> - Application-supplied user canonicalization function</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_canonuser_add_plugin.html"><strong>sasl_canonuser_add_plugin</strong> - add a SASL user canonicalization plugin</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_chalprompt_t.html"><strong>sasl_chalprompt_t</strong> - Realm acquisition callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_checkapop.html"><strong>sasl_checkapop</strong> - Check an APOP challenge/response</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_checkpass.html"><strong>sasl_checkpass</strong> - Check a plaintext password</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_add_plugin.html"><strong>sasl_client_add_plugin</strong> - add a SASL client plugin</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_done.html"><strong>sasl_client_done</strong> - Cleanup function</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_init.html"><strong>sasl_client_init</strong> - SASL client authentication initialization</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_new.html"><strong>sasl_client_new</strong> - Create a new client authentication object</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_plug_init_t.html"><strong>sasl_client_plug_init_t</strong> - client plug‐in entry point</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_start.html"><strong>sasl_client_start</strong> - Begin an authentication negotiation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_client_step.html"><strong>sasl_client_step</strong> - Perform a step in the authentication negotiation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_decode.html"><strong>sasl_decode</strong> - Decode data received</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_decode64.html"><strong>sasl_decode64</strong> - Decode base64 string</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_dispose.html"><strong>sasl_dispose</strong> - Dispose of a SASL connection object</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_done.html"><strong>sasl_done</strong> - Dispose of a SASL connection object</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_encode.html"><strong>sasl_encode</strong> - Encode data for transport to authenticated host</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_encode64.html"><strong>sasl_encode64</strong> - Encode base64 string</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_encodev.html"><strong>sasl_encodev</strong> - Encode data for transport to authenticated host</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_erasebuffer.html"><strong>sasl_erasebuffer</strong> - erase buffer</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_errdetail.html"><strong>sasl_errdetail</strong> - Retrieve  detailed information about an error</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_errors.html"><strong>sasl_errors</strong> - SASL error codes</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_errstring.html"><strong>sasl_errstring</strong> - Translate a SASL return code to a human-readable form</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getcallback_t.html"><strong>sasl_getcallback_t</strong> - callback function to lookup a sasl_callback_t for a connection</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getconfpath_t.html"><strong>sasl_getconfpath_t</strong> - The SASL callback to indicate location of the config files</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getopt_t.html"><strong>sasl_getopt_t</strong> - The SASL get option callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getpath_t.html"><strong>sasl_getpath_t</strong> - The SASL callback to indicate location of the mechanism drivers</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getprop.html"><strong>sasl_getprop</strong> - Get a SASL property</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getrealm_t.html"><strong>sasl_getrealm_t</strong> - Realm Acquisition Callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getsecret_t.html"><strong>sasl_getsecret_t</strong> - The SASL callback for secrets (passwords)</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_getsimple_t.html"><strong>sasl_getsimple_t</strong> - The SASL callback for username/authname/realm</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_global_listmech.html"><strong>sasl_global_listmech</strong> - Retrieve a list of the supported SASL mechanisms</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_idle.html"><strong>sasl_idle</strong> - Perform precalculations during an idle period</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_listmech.html"><strong>sasl_listmech</strong> - Retrieve a list of the supported SASL mechanisms</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_log_t.html"><strong>sasl_log_t</strong> - The SASL logging callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_add_plugin.html"><strong>sasl_server_add_plugin</strong> - add a SASL server plugin</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_done.html"><strong>sasl_server_done</strong> - Cleanup function</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_init.html"><strong>sasl_server_init</strong> - SASL server authentication initialization</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_new.html"><strong>sasl_server_new</strong> - Create a new server authentication object</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_plug_init_t.html"><strong>sasl_server_plug_init_t</strong> - server plug‐in entry point</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_start.html"><strong>sasl_server_start</strong> - Begin an authentication negotiation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_step.html"><strong>sasl_server_step</strong> - Perform a step in the authentication negotiation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_userdb_checkpass_t.html"><strong>sasl_server_userdb_checkpass_t</strong> - Plaintext Password Verification Callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_server_userdb_setpass_t.html"><strong>sasl_server_userdb_setpass_t</strong> - UserDB Plaintext Password Setting Callback</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_set_alloc.html"><strong>sasl_set_alloc</strong> - set the memory allocation functions used by the SASL library</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_set_mutex.html"><strong>sasl_set_mutex</strong> - set the mutex lock functions used by the SASL library</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_seterror.html"><strong>sasl_seterror</strong> - set the error string</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_setpass.html"><strong>sasl_setpass</strong> - Check a plaintext password</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_setprop.html"><strong>sasl_setprop</strong> - Set a SASL property</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_user_exists.html"><strong>sasl_user_exists</strong> - Check if a user exists on server</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_usererr.html"><strong>sasl_usererr</strong> - Remove information leak about accounts from sasl error codes</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_utf8verify.html"><strong>sasl_utf8verify</strong> - Verify a string is valid utf8</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/reference/manpages/library/sasl_verifyfile_t.html"><strong>sasl_verifyfile_t</strong> - The SASL file verification</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/auxiliary_properties.html">Auxiliary Properties</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#auxiliary-properties-and-the-glue-layer">Auxiliary Properties and the Glue Layer</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#passwords-and-other-data">Passwords and other Data</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#sasldb">sasldb</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#ldapdb">ldapdb</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#sql">sql</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/auxiliary_properties.html#user-canonicalization">User Canonicalization</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/authentication_mechanisms.html">Authentication Mechanisms</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/authentication_mechanisms.html#mechanisms">Mechanisms</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#anonymous">ANONYMOUS</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#cram-md5">CRAM-MD5</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#digest-md5">DIGEST-MD5</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#external">EXTERNAL</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#g2">G2</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#gssapi">GSSAPI</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#gss-spegno">GSS-SPEGNO</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#kerberos-v4">KERBEROS_V4</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#login">LOGIN</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#ntlm">NTLM</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#otp">OTP</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#passdss">PASSDSS</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#plain">PLAIN</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#scram">SCRAM</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#srp">SRP</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/authentication_mechanisms.html#non-sasl-authentication">Non-SASL Authentication</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/authentication_mechanisms.html#summary">Summary</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/pwcheck.html">Pwcheck</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#auxprop">Auxprop</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#auxprop-hashed">Auxprop-hashed</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#saslauthd">Saslauthd</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#authdaemon">Authdaemon</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#alwaystrue">Alwaystrue</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/pwcheck.html#auto-transition">Auto Transition</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/faq.html">Frequently Asked Questions</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/authorize-vs-authenticate.html">What is the difference between an Authorization ID and a Authentication ID?</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/crammd5-digestmd5.html">Why do CRAM-MD5 and DIGEST-MD5 not work with CyrusSaslauthd?</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/openldap-sasl-gssapi.html">How do I configure OpenLDAP +SASL+GSSAPI?</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/plaintextpasswords.html">Why does CyrusSasl store plaintext passwords in its databases?</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/rfcs.html">RFCs and drafts</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/faqs/upgrade-saslv2.html">Why am I having a problem running dbconverter-2 to upgrade from SASLv1 to SASLv2?</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/resources.html">Other Documentation &amp; Resources</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="developer.html">Developers</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/appconvert.html">Converting Applications from v1 to v2</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/appconvert.html#tips-for-both-clients-and-servers">Tips for both clients and servers</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/appconvert.html#tips-for-clients">Tips for clients</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/appconvert.html#tips-for-servers">Tips for Servers</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/developer/programming.html">Application Programmer’s Guide</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#introduction">Introduction</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#about-this-guide">About this Guide</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#what-is-sasl">What is SASL?</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#background">Background</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#how-did-the-world-work-before-sasl">How did the world work before SASL?</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#sasl-to-the-rescue">SASL to the rescue!</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#briefly">Briefly</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#what-is-the-cyrus-sasl-library-good-for">What is the Cyrus SASL library good for?</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#what-does-the-cyrus-sasl-library-do">What does the Cyrus SASL library do?</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#what-doesn-t-the-cyrus-sasl-library-do">What doesn’t the Cyrus SASL library do?</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#client-only-section">Client-only Section</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#a-typical-interaction-from-the-client-s-perspective">A typical interaction from the client’s perspective</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#how-does-this-look-in-code">How does this look in code</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#server-only-section">Server-only Section</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#a-typical-interaction-from-the-server-s-perspective">A typical interaction from the server’s perspective</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#id1">How does this look in code?</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#common-section">Common Section</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#callbacks-and-interactions">Callbacks and Interactions</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#security-layers">Security layers</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#example-applications-that-come-with-the-cyrus-sasl-library">Example applications that come with the Cyrus SASL library</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#sample-client-and-sample-server"><cite>sample-client</cite> and <cite>sample-server</cite></a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#cyrus-imapd-v2-1-0-or-later">Cyrus imapd v2.1.0 or later</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#imtest-from-cyrus-2-1-0-or-later"><cite>imtest</cite>, from Cyrus 2.1.0 or later</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/programming.html#miscellaneous-information">Miscellaneous Information</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#empty-exchanges">Empty exchanges</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/programming.html#idle">Idle</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/developer/plugprog.html">Plugin Programmer’s Guide</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#introduction">Introduction</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#about-this-guide">About this Guide</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#what-is-sasl">What is SASL?</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#common-section">Common Section</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#overview-of-plugin-programming">Overview of Plugin Programming</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#use-of-sasl-utils-t">Use of sasl_utils_t</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#error-reporting">Error Reporting</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#memory-allocation">Memory Allocation</a></li>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/plugprog.html#client-send-first-server-send-last">Client Send First / Server Send Last</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#client-plugins">Client Plugins</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#server-plugins">Server Plugins</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#user-canonicalization-canon-user-plugins">User Canonicalization (canon_user) Plugins</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/plugprog.html#auxiliary-property-auxprop-plugins">Auxiliary Property (auxprop) Plugins</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/developer/testing.html">Testing</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/testing.html#testing-the-cmu-sasl-library-with-the-included-sample-applications">Testing the CMU SASL Library with the included sample applications</a><ul>
<li class="toctree-l4"><a class="reference internal" href="sasl/developer/testing.html#example">Example</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="sasl/developer/testing.html#running-the-testsuite-application">Running the Testsuite application</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="support.html">Support/Community</a></li>
</ul>
<p class="caption"><span class="caption-text">IMAP</span></p>
<ul>
<li class="toctree-l1"><a class="reference external" href="http://www.cyrusimap.org">Cyrus IMAP</a></li>
</ul>

          
        
      </div>
      &nbsp;
    </nav>

    <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">

      
      <nav class="wy-nav-top" role="navigation" aria-label="top navigation">
        <i data-toggle="wy-nav-top" class="fa fa-bars"></i>
        <a href="index.html">Cyrus SASL</a>
      </nav>


      
      <div class="wy-nav-content">
        <div class="rst-content">
          
          <div role="navigation" aria-label="breadcrumbs navigation">
  <ul class="wy-breadcrumbs">
      <li><a href="index.html">Docs v2.1.27</a> &raquo;</li>
      
          <li><a href="download.html">Download</a> &raquo;</li>
      
    <li>Get SASL</li>
      <li class="wy-breadcrumbs-aside">
        
          
            <a href="https://github.com/cyrusimap/cyrus-sasl/blob/master/docsrc/getsasl.rst" class="fa fa-github"> Edit on GitHub</a>
          
        
      </li>
  </ul>
  <hr/>
</div>
          <div role="main" class="document">
            
  <div class="section" id="get-sasl">
<h1>Get SASL<a class="headerlink" href="#get-sasl" title="Permalink to this headline">¶</a></h1>
<div class="toctree-wrapper compound">
<ul>
<li class="toctree-l1"><a class="reference internal" href="sasl/installation.html">Installation</a><ul>
<li class="toctree-l2"><a class="reference internal" href="sasl/installation.html#quick-install-guide">Quick install guide</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html#tarball-installation">Tarball installation</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html#unix-package-installation">Unix package Installation</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html#configuration">Configuration</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/installation.html#detailed-installation-guide">Detailed installation guide</a><ul>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html#requirements">Requirements</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html#build-configuration">Build Configuration</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html#building-and-installation">Building and Installation</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html#compilation-hints">Compilation Hints</a></li>
<li class="toctree-l3"><a class="reference internal" href="sasl/installation.html#application-configuration">Application Configuration</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="sasl/installation.html#supported-platforms">Supported platforms</a></li>
</ul>
</li>
</ul>
</div>
</div>


          </div>
          <footer>
  
    <div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
      
        <a href="sasl/installation.html" class="btn btn-neutral float-right" title="Installation" accesskey="n">Next <span class="fa fa-arrow-circle-right"></span></a>
      
      
        <a href="download.html" class="btn btn-neutral" title="Download" accesskey="p"><span class="fa fa-arrow-circle-left"></span> Previous</a>
      
    </div>
  

  <hr/>

  <div role="contentinfo">
    <p>
        &copy; Copyright 1993-2016, The Cyrus Team.
    </p>
  </div>
  Built with <a href="http://sphinx-doc.org/">Sphinx</a> 1.6.6 using a modified <a href="https://readthedocs.org">Read the Docs</a> <a href="https://github.com/snide/sphinx_rtd_theme">theme</a>.

</footer>

        </div>
      </div>

    </section>

  </div>
  


  

    <script type="text/javascript">
        var DOCUMENTATION_OPTIONS = {
            URL_ROOT:'./',
            VERSION:'2.1.27',
            COLLAPSE_INDEX:false,
            FILE_SUFFIX:'.html',
            HAS_SOURCE:  true
        };
    </script>
      <script type="text/javascript" src="_static/jquery.js"></script>
      <script type="text/javascript" src="_static/underscore.js"></script>
      <script type="text/javascript" src="_static/doctools.js"></script>
      <script type="text/javascript" src="https://cdn.mathjax.org/mathjax/latest/MathJax.js"></script>

  

  
  
    <script type="text/javascript" src="_static/js/theme.js"></script>
  

  
  
  <script type="text/javascript">
<!--      jQuery(function () {
          SphinxRtdTheme.StickyNav.enable();
      }); -->
  </script>
  
 



</body>
</html>PK�h%[��j�$$man/man3/sasl_getrealm_t.3nu�[���.\" Man page generated from reStructuredText.
.
.TH "SASL_GETREALM_T" "3" "November 08, 2018" "2.1.27" "Cyrus SASL"
.SH NAME
sasl_getrealm_t \- Cyrus SASL documentation
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.SH SYNOPSIS
.sp
.nf
#include <sasl/sasl.h>

int sasl_getrealm_t(void *context,
    int id,
    const char **availrealms,
    const char **result)
.fi
.SH DESCRIPTION
.INDENT 0.0
.TP
.B int sasl_getrealm_t(void *context,
.TP
.B int id,
.TP
.B const char **availrealms,
.TP
.B const char **result)
\fBsasl_getrealm_t()\fP is used when there is an interaction with
SASL_CB_GETREALM as the type.
.sp
If a mechanism would use this  callback,  but  it  is  not
present,  then  the  first  realm  listed is automatically
selected.  (Note that a  mechanism  may  still  force  the
existence  of  a  getrealm callback by SASL_CB_GETREALM to
its required_prompts list).
.INDENT 7.0
.TP
.B Parameters
.INDENT 7.0
.IP \(bu 2
\fBcontext\fP – context from the callback record
.IP \(bu 2
\fBid\fP – callback ID (SASL_CB_GETREALM)
.IP \(bu 2
\fBavailrealms\fP – A string list of the available  realms.   NULL
terminated, may be empty.
.IP \(bu 2
\fBresult\fP – The chosen realm. (a NUL terminated string)
.UNINDENT
.UNINDENT
.UNINDENT
.SH RETURN VALUE
.sp
SASL  callback  functions should return SASL return codes.
See sasl.h for a complete list. \fBSASL_OK\fP indicates success.
.sp
Other return codes indicate errors and should be handled.
.SH SEE ALSO
.sp
\fI\%RFC 4422\fP,:saslman:\fIsasl(3)\fP, sasl_callbacks(3)
.SH AUTHOR
The Cyrus Team
.SH COPYRIGHT
1993-2016, The Cyrus Team
.\" Generated by docutils manpage writer.
.
PK�h%[^AEEman/man3/sasl_getsimple_t.3nu�[���.\" Man page generated from reStructuredText.
.
.TH "SASL_GETSIMPLE_T" "3" "November 08, 2018" "2.1.27" "Cyrus SASL"
.SH NAME
sasl_getsimple_t \- Cyrus SASL documentation
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.SH SYNOPSIS
.sp
.nf
#include <sasl/sasl.h>

int sasl_getsimple_t(void *context,
                    int id,
                    const char ** result,
                    unsigned * len);
.fi
.SH DESCRIPTION
.INDENT 0.0
.TP
.B int sasl_getsimple_t(void *context,
.TP
.B int id,
.TP
.B const char ** result,
.TP
.B unsigned * len);
\fBsasl_getsimple_t\fP is used to retrieve simple things from
the application. In practice this is authentication name,
authorization name, and realm.
.INDENT 7.0
.TP
.B Parameters
.INDENT 7.0
.IP \(bu 2
\fBcontext\fP – SASL connection context
.IP \(bu 2
\fBid\fP – 
.sp
indicates which value is being requested.  Possible values
include:
.INDENT 2.0
.IP \(bu 2
SASL_CB_USER     ‐ Client user identity to login as
.IP \(bu 2
SASL_CB_AUTHNAME ‐ Client authentication name
.IP \(bu 2
SASL_CB_LANGUAGE ‐ Comma‐separated list of \fI\%RFC 1766\fP languages
.IP \(bu 2
SASL_CB_CNONCE   ‐ Client‐nonce (for testing mostly)
.UNINDENT

.IP \(bu 2
\fBresult\fP – value of the item requested
.IP \(bu 2
\fBlen\fP – lenth of the result
.UNINDENT
.UNINDENT
.UNINDENT
.SH RETURN VALUE
.sp
SASL  callback  functions should return SASL return codes.
See sasl.h for a complete list. \fBSASL_OK\fP indicates success.
.SH SEE ALSO
.sp
\fI\%RFC 4422\fP,:saslman:\fIsasl(3)\fP, sasl_callbacks(3),
sasl_errors(3)
.SH AUTHOR
The Cyrus Team
.SH COPYRIGHT
1993-2016, The Cyrus Team
.\" Generated by docutils manpage writer.
.
PK�h%[����man/man3/sasl_auxprop_getctx.3nu�[���.\" Man page generated from reStructuredText.
.
.TH "SASL_AUXPROP_GETCTX" "3" "November 08, 2018" "2.1.27" "Cyrus SASL"
.SH NAME
sasl_auxprop_getctx \- Cyrus SASL documentation
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.SH SYNOPSIS
.sp
.nf
#include <sasl/sasl.h>

int sasl_auxprop_getctx(sasl_conn_t *conn)
.fi
.SH DESCRIPTION
.INDENT 0.0
.TP
.B int sasl_auxprop_getctx(\fI\%sasl_conn_t\fP\fI\ *conn\fP)
Fetches an auxiliary property context for the connection on which the functions
described in sasl_auxprop(3) can operate.
.INDENT 7.0
.TP
.B Parameters
.INDENT 7.0
.IP \(bu 2
\fBconn\fP – pointer to the \fI\%sasl_conn_t\fP for which the request is being made.
.UNINDENT
.TP
.B Returns
A pointer to the context on success. Returns NULL on failure.
.UNINDENT
.UNINDENT
.INDENT 0.0
.TP
.B sasl_conn_t
Context for a SASL connection negotiation
.UNINDENT
.SH CONFORMING TO
.sp
\fI\%RFC 4422\fP
.SH SEE ALSO
.sp
sasl(3), sasl_auxprop(3), sasl_auxprop_request(3)
.SH AUTHOR
The Cyrus Team
.SH COPYRIGHT
1993-2016, The Cyrus Team
.\" Generated by docutils manpage writer.
.
PK�h%[߱�4man/man3/sasl_encodev.3nu�[���.\" Man page generated from reStructuredText.
.
.TH "SASL_ENCODEV" "3" "November 08, 2018" "2.1.27" "Cyrus SASL"
.SH NAME
sasl_encodev \- Cyrus SASL documentation
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.SH SYNOPSIS
.sp
.nf
#include <sasl/sasl.h>

int sasl_encode(sasl_conn_t *conn,
                const char * input,
                unsigned inputlen,
                const char ** output,
                unsigned * outputlen);

int sasl_encodev(sasl_conn_t *conn,
                const struct iovec * invec,
                unsigned numiov,
                const char ** output,
                unsigned * outputlen);
.fi
.SH DESCRIPTION
.sp
\fBsasl_encode\fP encodes data to be sent to be sent to a remote host  who  we’ve
had  a successful authentication session with. If there  is  a  negotiated
security  the  data  in signed/encrypted  and  the  output  should be sent
without modification to the remote host. If there is  no  security layer the
output is identical to the input.
.sp
\fBsasl_encodev\fP does the same, but for a \fIstruct iovec\fP instead
of a character buffer.
.INDENT 0.0
.TP
.B int sasl_encode(sasl_conn_t *conn,
.TP
.B const char * input,
.TP
.B unsigned inputlen,
.TP
.B const char ** output,
.TP
.B unsigned * outputlen);
.INDENT 7.0
.TP
.B Parameters
.INDENT 7.0
.IP \(bu 2
\fBconn\fP – is the SASL connection context
.IP \(bu 2
\fBoutput\fP – contains the decoded data and is allocated/freed by
the library.
.IP \(bu 2
\fBoutputlen\fP – length of \fIoutput\fP\&.
.UNINDENT
.UNINDENT
.INDENT 7.0
.TP
.B int sasl_encodev(sasl_conn_t *conn,
.TP
.B const struct iovec * invec,
.TP
.B unsigned numiov,
.TP
.B const char ** output,
.TP
.B unsigned * outputlen);
.UNINDENT
.INDENT 7.0
.TP
.B Parameters
.INDENT 7.0
.IP \(bu 2
\fBconn\fP – is the SASL connection context
.IP \(bu 2
\fBoutput\fP – contains the decoded data and is allocated/freed by
the library.
.IP \(bu 2
\fBoutputlen\fP – length of \fIoutput\fP\&.
.UNINDENT
.UNINDENT
.UNINDENT
.SH RETURN VALUE
.sp
SASL  callback  functions should return SASL return codes.
See sasl.h for a complete list. \fBSASL_OK\fP indicates success.
.sp
Other return codes indicate errors and should be handled.
.SH SEE ALSO
.sp
\fI\%RFC 4422\fP,:saslman:\fIsasl(3)\fP, sasl_decode(3),
sasl_errors(3)
.SH AUTHOR
The Cyrus Team
.SH COPYRIGHT
1993-2016, The Cyrus Team
.\" Generated by docutils manpage writer.
.
PK�h%[����BBman/man3/sasl_global_listmech.3nu�[���.\" Man page generated from reStructuredText.
.
.TH "SASL_GLOBAL_LISTMECH" "3" "November 08, 2018" "2.1.27" "Cyrus SASL"
.SH NAME
sasl_global_listmech \- Cyrus SASL documentation
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.SH SYNOPSIS
.sp
.nf
#include <sasl/sasl.h>

const char ** sasl_global_listmech();
.fi
.SH DESCRIPTION
.INDENT 0.0
.TP
.B const char ** sasl_global_listmech();
\fBsasl_global_listmech\fP returns a null‐terminated array of
strings that lists all mechanisms that are loaded by
either the client or server side of the library.
.UNINDENT
.SH RETURN VALUE
.sp
Returns a pointer to the array on success. NULL on failure
(sasl library uninitialized).
.SH SEE ALSO
.sp
\fI\%RFC 4422\fP,:saslman:\fIsasl(3)\fP, sasl_server_init(3),
sasl_listmech(3), sasl_client_init(3)
.SH AUTHOR
The Cyrus Team
.SH COPYRIGHT
1993-2016, The Cyrus Team
.\" Generated by docutils manpage writer.
.
PK�h%[��T"�	�	man/man3/sasl_authorize_t.3nu�[���.\" Man page generated from reStructuredText.
.
.TH "SASL_AUTHORIZE_T" "3" "November 08, 2018" "2.1.27" "Cyrus SASL"
.SH NAME
sasl_authorize_t \- Cyrus SASL documentation
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.SH SYNOPSIS
.sp
.nf
#include <sasl/sasl.h>


int sasl_authorize_t(void *context,
                    const char *requested_user, unsigned alen,
                    const char *auth_identity, unsigned alen,
                    const char *def_realm, unsigned urlen,
                    struct propctx *propctx)
.fi
.SH DESCRIPTION
.sp
\fBsasl_authorize_t\fP  is  used to check whether the authorized
user auth_identity may act  as  the  user  requested_user.
For  example  the  user root may wish to authenticate with
his credentials but act as the user mmercer (with  all  of
mmercer’s  rights  not roots). A server application should
be very careful, and probably err on the side of  caution,
when determining which users may proxy as whom.
.SH RETURN VALUE
.sp
SASL  callback  functions should return SASL return codes.
See sasl.h for a complete list. \fBSASL_OK\fP indicates success.
.SH SEE ALSO
.sp
sasl(3), sasl_callbacks(3)
.SH AUTHOR
The Cyrus Team
.SH COPYRIGHT
1993-2016, The Cyrus Team
.\" Generated by docutils manpage writer.
.
PK�h%[��<���man/man3/sasl_decode.3nu�[���.\" Man page generated from reStructuredText.
.
.TH "SASL_DECODE" "3" "November 08, 2018" "2.1.27" "Cyrus SASL"
.SH NAME
sasl_decode \- Cyrus SASL documentation
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.SH SYNOPSIS
.sp
.nf
#include <sasl/sasl.h>

int sasl_decode(sasl_conn_t *conn,
               const char * input,
                unsigned inputlen,
               const char ** output,
               unsigned * outputlen);
.fi
.SH DESCRIPTION
.INDENT 0.0
.TP
.B int sasl_decode(sasl_conn_t *conn,
.TP
.B const char * input,
.TP
.B unsigned inputlen,
.TP
.B const char ** output,
.TP
.B unsigned * outputlen);
\fBsasl_decode\fP decodes   data  received.  After  successful authentication
this function should be called on all  data received.  It  decodes  the
data from encrypted or signed form to plain data. If there was no security
layer negotiated the \fIoutput\fP is identical to the \fIinput\fP\&.
.INDENT 7.0
.TP
.B Parameters
.INDENT 7.0
.IP \(bu 2
\fBconn\fP – is the SASL connection context
.IP \(bu 2
\fBoutput\fP – contains the decoded data and is allocated/freed by
the library.
.IP \(bu 2
\fBoutputlen\fP – length of \fIoutput\fP\&.
.UNINDENT
.UNINDENT
.sp
One should not give  sasl_decode  more  data  than  the
negotiated \fImaxbufsize\fP (see sasl_getprop(3)).
.sp
Note  that  sasl_decode  can  succeed and outputlen can be
zero. If this is the case simply wait for  more  data  and
call sasl_decode again.
.UNINDENT
.SH RETURN VALUE
.sp
SASL  callback  functions should return SASL return codes.
See sasl.h for a complete list. \fBSASL_OK\fP indicates success.
.sp
Other return codes indicate errors and should be handled.
.SH SEE ALSO
.sp
\fI\%RFC 4422\fP,:saslman:\fIsasl(3)\fP, sasl_encode(3),
sasl_errors(3)
.SH AUTHOR
The Cyrus Team
.SH COPYRIGHT
1993-2016, The Cyrus Team
.\" Generated by docutils manpage writer.
.
PK�h%[#��-((man/man3/sasl_auxprop.3nu�[���.\" Man page generated from reStructuredText.
.
.TH "SASL_AUXPROP" "3" "November 08, 2018" "2.1.27" "Cyrus SASL"
.SH NAME
sasl_auxprop \- Cyrus SASL documentation
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.SH SYNOPSIS
.sp
.nf
#include <sasl/prop.h>

struct propctx *prop_new(unsigned estimate)

int prop_dup(struct propctx *src_ctx,
             struct propctx *dst_ctx)

int prop_request(struct propctx *ctx,
                 const char **names)

const struct propval *prop_get(struct propctx *ctx)

int prop_getnames(struct propctx *ctx, const char **names,
                  struct propval *vals)

void prop_clear(struct propctx *ctx, int requests)

void prop_erase(struct propctx *ctx, const char *name)

void prop_dispose(struct propctx **ctx)

int prop_format(struct propctx *ctx, const char *sep, int seplen,
                char *outbuf, unsigned outmax, unsigned *outlen)

int prop_set(struct propctx *ctx, const char *name,
             const char *value, int vallen)

int prop_setvals(struct propctx *ctx, const char *name,
                 const char **values)
.fi
.SH DESCRIPTION
.sp
SASL auxiliary properties are used to obtain properties
from external sources during the authentication process.
For example,  a mechanism might need to query an LDAP
server to obtain the authentication secret.  The application probably needs other information from there as well,
such as home directory or UID.   The auxiliary property
interface allows the two to cooperate, and only results in
a single query against the LDAP server (or other property
sources).
.sp
Property lookups take place directly after user canonicalization occurs.  Therefore, all requests should be
registered with the context before that time.   Note that
requests can also be registered using the
sasl_auxprop_request(3)  function.   Most of the functions listed
below, however, require a property context which can be
obtained by calling sasl_auxprop_getctx(3)\&.
.SH API DESCRIPTION
.INDENT 0.0
.TP
.B struct \fI\%propctx\fP *prop_new(unsigned\fI\ estimate\fP)
Create a new property context.  Probably unnecessary for application developers
to call this at any point.
.INDENT 7.0
.TP
.B Parameters
.INDENT 7.0
.IP \(bu 2
\fBestimate\fP – is the estimate of storage needed in total for requests & responses.  A value of 0 implies the library default.
.UNINDENT
.TP
.B Returns
a new property context: \fI\%propctx\fP
.UNINDENT
.UNINDENT
.INDENT 0.0
.TP
.B int prop_dup(struct \fI\%propctx\fP\fI\ *src_ctx\fP, struct \fI\%propctx\fP\fI\ *dst_ctx\fP)
Duplicate a given property context.
.INDENT 7.0
.TP
.B Parameters
.INDENT 7.0
.IP \(bu 2
\fBsrc_ctx\fP (\fI\%propctx\fP) – Property context to copy.
.IP \(bu 2
\fBdst_ctx\fP (\fI\%propctx\fP) – Destination context to copy into.
.UNINDENT
.TP
.B Returns
SASL error code.
.UNINDENT
.UNINDENT
.INDENT 0.0
.TP
.B int prop_request(struct \fI\%propctx\fP\fI\ *ctx\fP, const char\fI\ **names\fP)
Add properties to the request list of a given context.
.INDENT 7.0
.TP
.B Parameters
.INDENT 7.0
.IP \(bu 2
\fBctx\fP (\fI\%propctx\fP) – The property context to add add the request list to.
.IP \(bu 2
\fBnames\fP – is the NULL\-terminated array of property names,  and must persist until the requests are cleared or the context is disposed of with a call to \fI\%prop_dispose()\fP\&.
.UNINDENT
.TP
.B Returns
SASL error code
.UNINDENT
.UNINDENT
.INDENT 0.0
.TP
.B const struct \fI\%propval\fP *prop_get(struct \fI\%propctx\fP\fI\ *ctx\fP)
Fetch out the property values from a context.
.INDENT 7.0
.TP
.B Parameters
.INDENT 7.0
.IP \(bu 2
\fBctx\fP (\fI\%propctx\fP) – The property context to fetch from.
.UNINDENT
.TP
.B Returns
a NULL\-terminated array of property values from the given context.
.UNINDENT
.UNINDENT
.INDENT 0.0
.TP
.B int prop_getnames(struct \fI\%propctx\fP\fI\ *ctx\fP, const char\fI\ **names\fP, struct \fI\%propval\fP\fI\ *vals\fP)
Fill in a (provided) array of property values based
on a list of property names.  This implies that
the \fBvals\fP array is at least as long as the  \fBnames\fP
array.  The values that are filled in by this call
persist   until   next   call   to   \fI\%prop_request()\fP,
\fI\%prop_clear()\fP, or \fI\%prop_dispose()\fP on context.  If a name
specified here was never requested, then its associated
values entry will be set to NULL.
.INDENT 7.0
.TP
.B Parameters
.INDENT 7.0
.IP \(bu 2
\fBctx\fP (\fI\%propctx\fP) – The property context to fill in.
.UNINDENT
.TP
.B Returns
number of matching properties that were found, or a SASL error code.
.UNINDENT
.UNINDENT
.INDENT 0.0
.TP
.B void prop_clear(struct \fI\%propctx\fP\fI\ *ctx\fP, int\fI\ requests\fP)
Clear values and (optionally) requests from a property context.
.INDENT 7.0
.TP
.B Parameters
.INDENT 7.0
.IP \(bu 2
\fBctx\fP (\fI\%propctx\fP) – The property context to clear.
.IP \(bu 2
\fBrequests\fP – set to 1 if the requests should be cleared, 0 otherwise.
.UNINDENT
.UNINDENT
.UNINDENT
.INDENT 0.0
.TP
.B void prop_erase(struct \fI\%propctx\fP\fI\ *ctx\fP, const char\fI\ *name\fP)
Securely erase the value of a property from a context.
.INDENT 7.0
.TP
.B Parameters
.INDENT 7.0
.IP \(bu 2
\fBctx\fP (\fI\%propctx\fP) – The property context to find the property in.
.IP \(bu 2
\fBname\fP – is the name of the property to erase.
.UNINDENT
.UNINDENT
.UNINDENT
.INDENT 0.0
.TP
.B void prop_dispose(struct \fI\%propctx\fP\fI\ **ctx\fP)
Disposes of a property context and NULLifys the pointer.
.INDENT 7.0
.TP
.B Parameters
.INDENT 7.0
.IP \(bu 2
\fBctx\fP (\fI\%propctx\fP) – The property context to clear.
.UNINDENT
.UNINDENT
.UNINDENT
.INDENT 0.0
.TP
.B int prop_format(struct \fI\%propctx\fP\fI\ *ctx\fP, const char\fI\ *sep\fP, int\fI\ seplen\fP, char\fI\ *outbuf\fP, unsigned\fI\ outmax\fP, unsigned\fI\ *outlen\fP)
Format the requested property names into a string.
This not intended for use by the application (\fIonly
by auxprop plugins\fP).
.INDENT 7.0
.TP
.B Parameters
.INDENT 7.0
.IP \(bu 2
\fBctx\fP (\fI\%propctx\fP) – The property context to extract values from.
.IP \(bu 2
\fBsep\fP – the separator to use for the string
.IP \(bu 2
\fBoutbuf\fP – destination string. Caller must allocate the buffer of length \fBoutmax\fP (including NUL terminator).
.IP \(bu 2
\fBoutlen\fP – if non\-NULL, will contain the length of the resulting string (excluding NUL terminator).
.UNINDENT
.TP
.B Returns
SASL error code.
.UNINDENT
.UNINDENT
.INDENT 0.0
.TP
.B int prop_set(struct \fI\%propctx\fP\fI\ *ctx\fP, const char\fI\ *name\fP, const char\fI\ *value\fP, int\fI\ vallen\fP)
Adds a property value to the context.  \fIThis is intended for use by auxprop plugins only.\fP
.INDENT 7.0
.TP
.B Parameters
.INDENT 7.0
.IP \(bu 2
\fBctx\fP (\fI\%propctx\fP) – The property context to add a value to.
.IP \(bu 2
\fBname\fP – the name of the property to receive the new value,  or NULL, which implies that the value will be added to the same property as the last call to either \fI\%prop_set()\fP or \fI\%prop_setvals()\fP\&.
.IP \(bu 2
\fBvalue\fP – the new value (of length \fIvallen\fP)
.IP \(bu 2
\fBvallen\fP – the length of the string \fIvalue\fP\&.
.UNINDENT
.TP
.B Returns
SASL error code
.UNINDENT
.UNINDENT
.INDENT 0.0
.TP
.B int prop_setvals(struct \fI\%propctx\fP\fI\ *ctx\fP, const char\fI\ *name\fP, const char\fI\ **values\fP)
Adds multiple values to a single property.  \fIThis is intended for use by auxprop plugins only\fP\&.
.INDENT 7.0
.TP
.B Parameters
.INDENT 7.0
.IP \(bu 2
\fBctx\fP (\fI\%propctx\fP) – The property context to add values to.
.IP \(bu 2
\fBname\fP – The name of the property to receive the new value, or NULL, which implies that the values will be added to the same property as the last call to either \fI\%prop_set()\fP or \fI\%prop_setvals()\fP\&.
.IP \(bu 2
\fBvalues\fP – A NULL\-terminated array of values to be added the property.
.UNINDENT
.TP
.B Returns
SASL error code
.UNINDENT
.UNINDENT
.SH DATA STRUCTURES
.INDENT 0.0
.TP
.B propval
A struct holding a name and its property values. A name can have zero or more values.
.INDENT 7.0
.TP
.B Parameters
.INDENT 7.0
.IP \(bu 2
\fBname\fP – \fBconst char *\fP\&. Name of this propval. NULL means end of list.
.IP \(bu 2
\fBvalues\fP – \fBconst char **\fP\&. List of string values. If property not found, values == NULL. If property found with no values, then *values == NULL
.UNINDENT
.UNINDENT
.UNINDENT
.INDENT 0.0
.TP
.B propctx
A property context.
.INDENT 7.0
.TP
.B Parameters
.INDENT 7.0
.IP \(bu 2
\fBvalues\fP (\fI\%propval\fP *) – List of property values in this context.
.UNINDENT
.UNINDENT
.UNINDENT
.SH RETURN VALUE
.sp
The property functions that return an int return SASL error codes.   See  sasl_errors(3)\&.   Those that return
pointers will return a valid pointer on success, or NULL on any error.
.SH CONFORMING TO
.sp
\fI\%RFC 4422\fP
.SH SEE ALSO
.sp
sasl(3), sasl_errors(3),
sasl_auxprop_request(3), sasl_auxprop_getctx(3)
.SH AUTHOR
The Cyrus Team
.SH COPYRIGHT
1993-2016, The Cyrus Team
.\" Generated by docutils manpage writer.
.
PK�h%[���Q		man/man3/sasl_getpath_t.3nu�[���.\" Man page generated from reStructuredText.
.
.TH "SASL_GETPATH_T" "3" "November 08, 2018" "2.1.27" "Cyrus SASL"
.SH NAME
sasl_getpath_t \- Cyrus SASL documentation
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.SH SYNOPSIS
.sp
.nf
#include <sasl/sasl.h>

int sasl_getpath_t(void *context,
                  char ** path);
.fi
.SH DESCRIPTION
.INDENT 0.0
.TP
.B int sasl_getpath_t(void *context, char ** path);
\fBsasl_getpath_t()\fP is used if the application wishes to use  a
different  location  for  the  SASL mechanism drivers (the
shared library files). If this callback is not used SASL
will either use the location in the environment variable
SASL_PATH or \fI/usr/lib/sasl2\fP by default.
.UNINDENT
.SH RETURN VALUE
.sp
SASL  callback  functions should return SASL return codes.
See sasl.h for a complete list. \fBSASL_OK\fP indicates success.
.sp
Other return codes indicate errors and should be handled.
.SH SEE ALSO
.sp
\fI\%RFC 4422\fP,:saslman:\fIsasl(3)\fP, sasl_callbacks(3)
.SH AUTHOR
The Cyrus Team
.SH COPYRIGHT
1993-2016, The Cyrus Team
.\" Generated by docutils manpage writer.
.
PK�h%[>��8:
:
man/man3/sasl_client_init.3nu�[���.\" Man page generated from reStructuredText.
.
.TH "SASL_CLIENT_INIT" "3" "November 08, 2018" "2.1.27" "Cyrus SASL"
.SH NAME
sasl_client_init \- Cyrus SASL documentation
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.SH SYNOPSIS
.sp
.nf
#include <sasl/sasl.h>

int sasl_client_init(const  sasl_callback_t *callbacks )
.fi
.SH DESCRIPTION
.sp
\fBsasl_client_init\fP initializes SASL.
.sp
It  must  be  called  before  any  calls  to
sasl_client_start(3)\&. This call initializes all SASL client  drivers
(e.g.  authentication mechanisms). These are usually found in the
\fI/usr/lib/sasl2\fP directory but the directory may be overridden with
the \fISASL_PATH\fP environment variable.
.SH RETURN VALUE
.sp
SASL  callback  functions should return SASL return codes.
See sasl.h for a complete list. \fBSASL_OK\fP indicates success.
.sp
The following return codes indicate errors and should either be handled or the authentication
session should be quit:
.INDENT 0.0
.IP \(bu 2
\fBSASL_BADVERS\fP: Mechanism version mismatch
.IP \(bu 2
\fBSASL_BADPARAM\fP: Error in config file
.IP \(bu 2
\fBSASL_NOMEM\fP: Not enough memory to complete operation
.UNINDENT
.SH SEE ALSO
.sp
\fI\%RFC 4422\fP,:saslman:\fIsasl(3)\fP, sasl_callbacks(3),
sasl_client_new(3), sasl_client_start(3),
sasl_client_step(3)
.SH AUTHOR
The Cyrus Team
.SH COPYRIGHT
1993-2016, The Cyrus Team
.\" Generated by docutils manpage writer.
.
PK�h%[;����
�
man/man3/sasl_auxprop_request.3nu�[���.\" Man page generated from reStructuredText.
.
.TH "SASL_AUXPROP_REQUEST" "3" "November 08, 2018" "2.1.27" "Cyrus SASL"
.SH NAME
sasl_auxprop_request \- Cyrus SASL documentation
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.SH SYNOPSIS
.sp
.nf
#include <sasl/sasl.h>

int sasl_auxprop_request(sasl_conn_t *conn, const char ** propnames)
.fi
.SH DESCRIPTION
.INDENT 0.0
.TP
.B int sasl_auxprop_request(sasl_conn_t\fI\ *conn\fP, const char **\fI\ propnames\fP)
\fBsasl_auxprop_request\fP will request that the SASL library
obtain properties from any auxiliary property plugins that
might be installed (such as the user’s home directory from
an LDAP server for example). Such lookup occurs just
after username canonicalization is complete. Therefore,
the request should be made before the call to
sasl_server_start(3), but after the call to
sasl_server_new(3)\&.
.INDENT 7.0
.TP
.B Parameters
.INDENT 7.0
.IP \(bu 2
\fBconn\fP – the \fBsasl_conn_t\fP for which the request is being made.
.IP \(bu 2
\fBpropnames\fP – a NULL\-terminated array of property names to
request.  Note that this array must persist until a call to
sasl_dispose(3) on the \fBsasl_conn_t\fP\&.
.UNINDENT
.TP
.B Returns
Returns  \fBSASL_OK\fP on success. See sasl_errors(3) for meanings of other return codes.
.UNINDENT
.UNINDENT
.SH CONFORMING TO
.sp
\fI\%RFC 4422\fP
.SH SEE ALSO
.sp
sasl(3), sasl_errors(3), sasl_auxprop(3), sasl_auxprop_getctx(3),
sasl_server_new(3), sasl_server_start(3)
.SH AUTHOR
The Cyrus Team
.SH COPYRIGHT
1993-2016, The Cyrus Team
.\" Generated by docutils manpage writer.
.
PK�h%[
�xxman/man3/sasl_verifyfile_t.3nu�[���.\" Man page generated from reStructuredText.
.
.TH "SASL_VERIFYFILE_T" "3" "November 08, 2018" "2.1.27" "Cyrus SASL"
.SH NAME
sasl_verifyfile_t \- Cyrus SASL documentation
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.SH SYNOPSIS
.sp
.nf
#include <sasl/sasl.h>

typedef enum {
    SASL_VRFY_PLUGIN, /* a DLL/shared library plugin */
    SASL_VRFY_CONF,   /* a configuration file */
    SASL_VRFY_PASSWD, /* a password storage file */
    SASL_VRFY_OTHER   /* some other file type */
} sasl_verify_type_t

int sasl_verifyfile_t(void *context,
                const char *file,
                sasl_verify_type_t type)
.fi
.SH DESCRIPTION
.INDENT 0.0
.TP
.B int sasl_verifyfile_t(void *context,
.TP
.B const char *file,
.TP
.B sasl_verify_type_t type)
\fBsasl_verifyfile_t()\fP is used to check whether a given file is
okay for use by the SASL library.   This  is  intended  to
allow  applications  to  sanity  check  the environment. For example, to
ensure that plugins or the config file cannot  be  written
to.
.INDENT 7.0
.TP
.B Parameters
.INDENT 7.0
.IP \(bu 2
\fBcontext\fP – context from the callback record
.IP \(bu 2
\fBcontext\fP – context from the callback record
.IP \(bu 2
\fBfile\fP – full path of the file to verify
.IP \(bu 2
\fBtype\fP – type of the file.
.UNINDENT
.UNINDENT
.UNINDENT
.SH RETURN VALUE
.sp
SASL  callback  functions should return SASL return codes.
See sasl.h for a complete list. \fBSASL_OK\fP indicates success.
.sp
Other return codes indicate errors and should be handled.
.SH SEE ALSO
.sp
\fI\%RFC 4422\fP,:saslman:\fIsasl(3)\fP, sasl_callbacks(3)
sasl_errors(3)
.SH AUTHOR
The Cyrus Team
.SH COPYRIGHT
1993-2016, The Cyrus Team
.\" Generated by docutils manpage writer.
.
PK�h%[��mmman/man3/sasl_getopt_t.3nu�[���.\" Man page generated from reStructuredText.
.
.TH "SASL_GETOPT_T" "3" "November 08, 2018" "2.1.27" "Cyrus SASL"
.SH NAME
sasl_getopt_t \- Cyrus SASL documentation
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.SH SYNOPSIS
.sp
.nf
#include <sasl/sasl.h>

int sasl_getopt_t(void *context,
               const char *plugin_name,
               const char *option,
               const char ** result,
               unsigned * len);
.fi
.SH DESCRIPTION
.INDENT 0.0
.TP
.B int sasl_getopt_t(void *context,
.TP
.B const char *plugin_name,
.TP
.B const char *option,
.TP
.B const char ** result,
.TP
.B unsigned * len);
\fBsasl_getopt_t\fP is used to retrieve an option, often mechanism specific,
from the application. An example of this is
requesting what KERBEROS_V4 srvtab file to use.
.INDENT 7.0
.TP
.B Parameters
.INDENT 7.0
.IP \(bu 2
\fBcontext\fP – is the SASL connection context
.IP \(bu 2
\fBplugin_name\fP – is the plugin this value is for.
.IP \(bu 2
\fBoption\fP – is a string representing the option. A common option that all
server applications should handle is the method for checking
plaintext passwords.  See the \fI\%administrators
guide\fP for a
full description of this option.
.UNINDENT
.UNINDENT
.sp
Memory management of options supplied by the getopt callback
should be done by the application, however, any
requested option must remain available until the callback
is no longer valid.  That is, when sasl_dispose(3) is called
for a the connection it is associated with,  or  sasl_done(3)
is called for global callbacks.
.UNINDENT
.SH RETURN VALUE
.sp
SASL callback functions should return SASL return codes.
See sasl.h for a complete list. \fBSASL_OK\fP indicates success.
.sp
Other return codes indicate errors and should be handled.
.SH SEE ALSO
.sp
\fI\%RFC 4422\fP,:saslman:\fIsasl(3)\fP, sasl_errors(3)
sasl_callbacks(3)
.SH AUTHOR
The Cyrus Team
.SH COPYRIGHT
1993-2016, The Cyrus Team
.\" Generated by docutils manpage writer.
.
PK�h%[�]�K��man/man3/sasl_server_start.3nu�[���.\" Man page generated from reStructuredText.
.
.TH "SASL_SERVER_START" "3" "November 08, 2018" "2.1.27" "Cyrus SASL"
.SH NAME
sasl_server_start \- Cyrus SASL documentation
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.SH SYNOPSIS
.sp
.nf
#include <sasl/sasl.h>

int sasl_server_start(sasl_conn_t * conn,
             const char * mech,
             const char * clientin,
             unsigned clientinlen,
             const char ** serverout,
             unsigned * serveroutlen);
.fi
.SH DESCRIPTION
.INDENT 0.0
.TP
.B int sasl_server_start(sasl_conn_t * conn,
.TP
.B const char * mech,
.TP
.B const char * clientin,
.TP
.B unsigned * clientinlen,
.TP
.B const char ** serverout,
.TP
.B unsigned * serveroutlen);
\fBsasl_server_start()\fP begins  the  authentication  with the
mechanism specified with mech. This fails if the mechanism
is  not  supported.
.INDENT 7.0
.TP
.B Parameters
.INDENT 7.0
.IP \(bu 2
\fBconn\fP – is the SASL connection context
.IP \(bu 2
\fBmech\fP – is the mechanism name that the client requested
.IP \(bu 2
\fBclientin\fP – is the client initial response, NULL if the protocol
lacks support for client‐send‐first or if the  other
end  did  not  have an initial send.  Note that no initial
client send is distinct from an initial  send  of  a  null
string, and the protocol MUST account for this difference.
.IP \(bu 2
\fBclientinlen\fP – is the length of initial response
.IP \(bu 2
\fBserverout\fP – is created by the plugin library. It is the initial
server response to send to the client. This is  allocated/freed by the
library and it is the job of the client
to send it over the network to the server.  Also  protocol
specific  encoding (such as base64 encoding) must needs to
be done by the server.
.IP \(bu 2
\fBserveroutlen\fP – is set to the length of initial server challenge
.UNINDENT
.UNINDENT
.UNINDENT
.SH RETURN VALUE
.sp
SASL  callback  functions should return SASL return codes. See sasl.h for a
complete list. \fBSASL_OK\fP is returned if the authentication is complete
and the user is authenticated.  \fBSASL_CONTINUE\fP  is returned if one or
more steps are still required in the authentication.
.sp
All other return values indicate errors and should be handled or the
authentication session should be quit.
.SH SEE ALSO
.sp
\fI\%RFC 4422\fP,:saslman:\fIsasl(3)\fP,
sasl_server_init(3), sasl_server_new(3),
sasl_server_step(3), sasl_errors(3)
.SH AUTHOR
The Cyrus Team
.SH COPYRIGHT
1993-2016, The Cyrus Team
.\" Generated by docutils manpage writer.
.
PK�h%[��6��'man/man3/sasl_server_userdb_setpass_t.3nu�[���.\" Man page generated from reStructuredText.
.
.TH "SASL_SERVER_USERDB_SETPASS_T" "3" "November 08, 2018" "2.1.27" "Cyrus SASL"
.SH NAME
sasl_server_userdb_setpass_t \- Cyrus SASL documentation
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.SH SYNOPSIS
.sp
.nf
#include <sasl/sasl.h>

int sasl_server_userdb_setpass_t(sasl_conn_t *conn,
                                 void *context,
                                 const char *user,
                                 const char *pass,
                                 unsigned passlen,
                                 struct propctx *propctx,
                                 unsigned flags)
.fi
.SH DESCRIPTION
.INDENT 0.0
.TP
.B int sasl_server_userdb_setpass_t(sasl_conn_t *conn,
.TP
.B void *context,
.TP
.B const char *user,
.TP
.B const char *pass,
.TP
.B unsigned passlen,
.TP
.B struct propctx *propctx,
.TP
.B unsigned flags)
\fBsasl_server_userdb_setpass_t\fP is used to store or change  a plaintext
password  in the callback‐supplier’s user database.
.INDENT 7.0
.TP
.B Parameters
.INDENT 7.0
.IP \(bu 2
\fBconn\fP – is the SASL connection
.IP \(bu 2
\fBcontext\fP – context from the callback record
.IP \(bu 2
\fBuser\fP – NUL terminated user name with \fIuser@realm\fP syntax
.IP \(bu 2
\fBpass\fP – password to check (may not be NUL terminated)
.IP \(bu 2
\fBpasslen\fP – length of the password
.IP \(bu 2
\fBpropctx\fP – Auxilliary Properties (not stored)
.IP \(bu 2
\fBflags\fP – These  are  the  same  flags  that  are  passed  to
sasl_setpass(3), and are documented on that man page.
.UNINDENT
.UNINDENT
.UNINDENT
.SH RETURN VALUE
.sp
SASL  callback  functions should return SASL return codes.
See sasl.h for a complete list. \fBSASL_OK\fP indicates success.
.sp
Other return codes indicate errors and should be handled.
.SH SEE ALSO
.sp
\fI\%RFC 4422\fP,:saslman:\fIsasl(3)\fP, sasl_errors(3)
sasl_callbacks(3), sasl_server_userdb_checkpass_t(3),
sasl_setpass(3)
.SH AUTHOR
The Cyrus Team
.SH COPYRIGHT
1993-2016, The Cyrus Team
.\" Generated by docutils manpage writer.
.
PK�h%[�c�,O
O
man/man3/sasl_getsecret_t.3nu�[���.\" Man page generated from reStructuredText.
.
.TH "SASL_GETSECRET_T" "3" "November 08, 2018" "2.1.27" "Cyrus SASL"
.SH NAME
sasl_getsecret_t \- Cyrus SASL documentation
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.SH SYNOPSIS
.sp
.nf
#include <sasl/sasl.h>

int sasl_getsecret_t(sasl_conn_t *conn,
                    void *context,
                    int id,
                    sasl_secret_t ** psecret);
.fi
.SH DESCRIPTION
.INDENT 0.0
.TP
.B int sasl_getsecret_t(sasl_conn_t *conn,
.TP
.B void *context,
.TP
.B int id,
.TP
.B sasl_secret_t ** psecret);
\fBsasl_getsecret_t()\fP is used to retrieve the secret  from  the
application. A sasl_secret_t should be allocated to length
\fIsizeof(sasl_secret_t) + <length of secret>\fP\&.  It  has two
fields: \fIlen\fP which is the length of the secret in bytes and
\fIdata\fP which contains the secret itself (does not need to be
null terminated).
.INDENT 7.0
.TP
.B Parameters
.INDENT 7.0
.IP \(bu 2
\fBconn\fP – is the SASL connection context
.UNINDENT
.UNINDENT
.UNINDENT
.SH RETURN VALUE
.sp
SASL  callback  functions should return SASL return codes.
See sasl.h for a complete list. \fBSASL_OK\fP indicates success.
.sp
Other return codes indicate errors and should be handled.
.SH SEE ALSO
.sp
\fI\%RFC 4422\fP,:saslman:\fIsasl(3)\fP, sasl_callbacks(3)
.SH AUTHOR
The Cyrus Team
.SH COPYRIGHT
1993-2016, The Cyrus Team
.\" Generated by docutils manpage writer.
.
PK�h%["	����man/man3/sasl_setprop.3nu�[���.\" Man page generated from reStructuredText.
.
.TH "SASL_SETPROP" "3" "November 08, 2018" "2.1.27" "Cyrus SASL"
.SH NAME
sasl_setprop \- Cyrus SASL documentation
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.SH SYNOPSIS
.sp
.nf
#include <sasl/sasl.h>

int sasl_setprop(sasl_conn_t *conn,
                int propnum,
                const void * pvalue)
.fi
.SH DESCRIPTION
.INDENT 0.0
.TP
.B int sasl_setprop(sasl_conn_t *conn,
.TP
.B int propnum,
.TP
.B const void * pvalue)
\fBsasl_setprop\fP  sets the value of a SASL property. For example an
application should tell the SASL library about  any external negotiated
security layer (i.e. TLS).
.INDENT 7.0
.TP
.B Parameters
.INDENT 7.0
.IP \(bu 2
\fBconn\fP – is the SASL connection context
.IP \(bu 2
\fBpropnum\fP – is the identifier for the property requested
.IP \(bu 2
\fBpvalue\fP – 
.sp
contains  a pointer  to  the  data. It is the applications
job to make sure this type is correct. This is an easy way to crash  a
program.
.INDENT 2.0
.IP \(bu 2
SASL_AUTH_EXTERNAL ‐ external authentication ID (const char *)
.IP \(bu 2
SASL_SSF_EXTERNAL ‐  external SSF active ‐‐ (sasl_ssf_t)
.IP \(bu 2
SASL_DEFUSERREALM ‐ user realm (const char *)
.IP \(bu 2
SASL_SEC_PROPS  ‐    \fIsasl_security_properties_t\fP (may be freed after call)
.IP \(bu 2
.INDENT 2.0
.TP
.B SASL_IPLOCALPORT ‐   string describing the local ip and port in the form
”a.b.c.d;p”, or “e:f:g:h:i:j:k:l;port”
.UNINDENT
.IP \(bu 2
.INDENT 2.0
.TP
.B SASL_IPREMOTEPORT ‐  string describing the remote ip and port in the form
”a.b.c.d;p”, or “e:f:g:h:i:j:k:l;port”
.UNINDENT
.UNINDENT

.UNINDENT
.UNINDENT
.UNINDENT
.SH RETURN VALUE
.sp
SASL  callback  functions should return SASL return codes.
See sasl.h for a complete list. \fBSASL_OK\fP indicates success.
.sp
Other return codes indicate errors and should be handled.
.SH SEE ALSO
.sp
\fI\%RFC 4422\fP,:saslman:\fIsasl(3)\fP, sasl_errors(3)
.SH AUTHOR
The Cyrus Team
.SH COPYRIGHT
1993-2016, The Cyrus Team
.\" Generated by docutils manpage writer.
.
PK�h%[A�ʟSSman/man3/sasl_server_step.3nu�[���.\" Man page generated from reStructuredText.
.
.TH "SASL_SERVER_STEP" "3" "November 08, 2018" "2.1.27" "Cyrus SASL"
.SH NAME
sasl_server_step \- Cyrus SASL documentation
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.SH SYNOPSIS
.sp
.nf
#include <sasl/sasl.h>

int sasl_server_step(sasl_conn_t *conn,
    const char *clientin,
    unsigned clientinlen,
    const char ** serverout,
    unsigned * serveroutlen);
.fi
.SH DESCRIPTION
.INDENT 0.0
.TP
.B int sasl_server_step(sasl_conn_t *conn,
.TP
.B const char *clientin,
.TP
.B unsigned clientinlen,
.TP
.B const char ** serverout,
.TP
.B unsigned * serveroutlen);
\fBsasl_server_step()\fP performs a step in  the  authentication negotiation.  It
returns \fBSASL_OK\fP if the whole negotiation is successful and
\fBSASL_CONTINUE\fP if
this step is ok but  at least  one more step is needed.
.INDENT 7.0
.TP
.B Parameters
.INDENT 7.0
.IP \(bu 2
\fBconn\fP – is the SASL connection context
.IP \(bu 2
\fBclientin\fP – is the data given by the client (decoded  if  the
protocol encodes requests sent over the wire)
.IP \(bu 2
\fBclientinlen\fP – is the length of \fIclientin\fP
.IP \(bu 2
\fBserverout\fP – set by the library and should be sent to the client.
.IP \(bu 2
\fBserveroutlen\fP – length of \fIserverout\fP\&.
.UNINDENT
.UNINDENT
.UNINDENT
.SH RETURN VALUE
.sp
SASL  callback  functions should return SASL return codes.
See sasl.h for a complete list. \fBSASL_CONTINUE\fP indicates success
and that there are more steps needed in the authentication. \fBSASL_OK\fP
indicates that the authentication is complete.
.sp
Other return codes indicate errors and should either be handled or the authentication
session should be quit.
.SH SEE ALSO
.sp
\fI\%RFC 4422\fP,:saslman:\fIsasl(3)\fP,
sasl_server_init(3), sasl_server_new(3),
sasl_server_start(3), sasl_errors(3)
.SH AUTHOR
The Cyrus Team
.SH COPYRIGHT
1993-2016, The Cyrus Team
.\" Generated by docutils manpage writer.
.
PK�h%[�s�M�
�
man/man3/sasl_chalprompt_t.3nu�[���.\" Man page generated from reStructuredText.
.
.TH "SASL_CHALPROMPT_T" "3" "November 08, 2018" "2.1.27" "Cyrus SASL"
.SH NAME
sasl_chalprompt_t \- Cyrus SASL documentation
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.SH SYNOPSIS
.sp
.nf
#include <sasl/prop.h>

int sasl_chalprompt_t(void *context, int id,
    const char *challenge,
    const char *prompt, const char *defresult,
    const char **result, unsigned *len)
.fi
.SH DESCRIPTION
.INDENT 0.0
.TP
.B int sasl_chalprompt_t(void *context,
.TP
.B int id,
.TP
.B const char *challenge,
.TP
.B const char *prompt,
.TP
.B const char *defresult,
.TP
.B const char **result,
.TP
.B unsigned *len)
\fBsasl_chalprompt_t\fP  is used to prompt for input in response to a server challenge.
.INDENT 7.0
.TP
.B Parameters
.INDENT 7.0
.IP \(bu 2
\fBcontext\fP – is the context from the callback record
.IP \(bu 2
\fBid\fP – is the callback id (either SASL_CB_ECHOPROMPT or  SASL_CB_NOECHOPROMPT)
.IP \(bu 2
\fBchallenge\fP – the server’s challenge
.IP \(bu 2
\fBprompt\fP – A prompt for the user
.IP \(bu 2
\fBdefresult\fP – Default result (may be NULL)
.IP \(bu 2
\fBlen\fP – Length of the user’s response.
.UNINDENT
.TP
.B Result
The user’s response (a NUL terminated string) or SASL error code.
.UNINDENT
.UNINDENT
.SH RETURN VALUE
.sp
The user’s response (NUL terminated), or a SASL error code. See sasl_errors(3)\&.
.SH SEE ALSO
.sp
sasl(3), sasl_errors(3), sasl_callbacks(3)
.SH AUTHOR
The Cyrus Team
.SH COPYRIGHT
1993-2016, The Cyrus Team
.\" Generated by docutils manpage writer.
.
PK�h%[c��j66man/man3/sasl_server_new.3nu�[���.\" Man page generated from reStructuredText.
.
.TH "SASL_SERVER_NEW" "3" "November 08, 2018" "2.1.27" "Cyrus SASL"
.SH NAME
sasl_server_new \- Cyrus SASL documentation
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.SH SYNOPSIS
.sp
.nf
#include <sasl/sasl.h>

int sasl_server_new(const char *service,
                const char *serverFQDN,
                const char *user_realm,
                const char *iplocalport,
                const char *ipremoteport,
                const sasl_callback_t *callbacks,
                unsigned flags,
                sasl_conn_t ** pconn);
.fi
.SH DESCRIPTION
.INDENT 0.0
.TP
.B int sasl_server_new(const char *service,
.TP
.B const char *serverFQDN,
.TP
.B const char *user_realm,
.TP
.B const char *iplocalport,
.TP
.B const char *ipremoteport,
.TP
.B const sasl_callback_t *callbacks,
.TP
.B unsigned flags,
.TP
.B sasl_conn_t ** pconn);
\fBsasl_server_new()\fP creates a new SASL context. This context will  be
used  for  all SASL calls for one connection. It handles both authentication
and integrity/encryption  layers after authentication.
.INDENT 7.0
.TP
.B Parameters
.INDENT 7.0
.IP \(bu 2
\fBservice\fP – is the registered name of the service (usually the
protocol name) using SASL (e.g. “imap”).
.IP \(bu 2
\fBserverFQDN\fP – is the  fully  qualified  server  domain  name.
NULL  means  use gethostname().  This is useful for multi\-homed servers.
.IP \(bu 2
\fBuser_realm\fP – is the domain of the user agent. This  is  usually
not necessary (NULL is default)
.IP \(bu 2
\fBiplocalport\fP – 
.sp
is  the  IP and port of the local side of the
connection, or NULL.  If iplocalport is NULL it will  disable mechanisms
that require IP address information.  This strings  must  be  in  one
of the following formats:
.INDENT 2.0
.IP \(bu 2
”a.b.c.d;port”  (IPv4),
.IP \(bu 2
”e:f:g:h:i:j:k:l;port” (IPv6), or
.IP \(bu 2
”e:f:g:h:i:j:a.b.c.d;port” (IPv6)
.UNINDENT

.IP \(bu 2
\fBipremoteport\fP – is the IP and port of the remote side of  the
connection, or NULL (see iplocalport)
.IP \(bu 2
\fBflags\fP – are connection flags (see below)
.IP \(bu 2
\fBpconn\fP – is a pointer to the connection context allocated by
the library. This structure will be used  for  all  future
SASL calls for this connection.
.UNINDENT
.UNINDENT
.UNINDENT
.SS Connection flags
.sp
Flags that may be passed to \fBsasl_server_new()\fP:
.INDENT 0.0
.IP \(bu 2
\fISASL_SUCCESS_DATA\fP: The protocol supports a server‐last send
.IP \(bu 2
.INDENT 2.0
.TP
.B \fISASL_NEED_PROXY\fP: Force the use of  a  mechanism  that  supports  an
authorization  id  that  is not the authentication id.
.UNINDENT
.UNINDENT
.SH RETURN VALUE
.sp
SASL  callback  functions should return SASL return codes.
See sasl.h for a complete list. \fBSASL_OK\fP indicates success.
.sp
Other return codes indicate errors and should either be handled or the
authentication session should be quit.
.SH SEE ALSO
.sp
\fI\%RFC 4422\fP,:saslman:\fIsasl(3)\fP, sasl_server_init(3),
sasl_server_start(3), sasl_server_step(3),
sasl_setprop(3), sasl_errors(3)
.SH AUTHOR
The Cyrus Team
.SH COPYRIGHT
1993-2016, The Cyrus Team
.\" Generated by docutils manpage writer.
.
PK�h%[PVH���man/man3/sasl_client_start.3nu�[���.\" Man page generated from reStructuredText.
.
.TH "SASL_CLIENT_START" "3" "November 08, 2018" "2.1.27" "Cyrus SASL"
.SH NAME
sasl_client_start \- Cyrus SASL documentation
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.SH SYNOPSIS
.sp
.nf
#include <sasl/sasl.h>

int sasl_client_start(sasl_conn_t * conn,
        const char * mechlist,
        sasl_interact_t ** prompt_need,
        const char ** clientout,
        unsigned * clientoutlen,
        const char ** mech);
.fi
.SH DESCRIPTION
.INDENT 0.0
.TP
.B int sasl_client_start(sasl_conn_t * conn,
.TP
.B const char * mechlist,
.TP
.B sasl_interact_t ** prompt_need,
.TP
.B const char ** clientout,
.TP
.B unsigned * clientoutlen,
.TP
.B const char ** mech);
\fBsasl_client_start()\fP selects a mechanism for authentication and starts the
authentication session. The mechlist is the list of mechanisms the client
might like to use. The mech‐ anisms in the list are not necessarily  supported
by  the client  or  even  valid. SASL determines which of these to use based
upon the security preferences specified earlier. The  list  of mechanisms is
typically a list of mechanisms the server supports acquired from a capability
request.
.sp
If \fBSASL_INTERACT\fP is returned the library needs some values to  be
filled  in  before it can proceed. The \fIprompt_need\fP structure will be filled in
with requests. The application should  fulfill  these requests and call
sasl_client_start again with identical parameters (the \fIprompt_need\fP parameter
will  be  the  same pointer as before but filled in by the application).
.INDENT 7.0
.TP
.B Parameters
.INDENT 7.0
.IP \(bu 2
\fBconn\fP – is the SASL connection context
.IP \(bu 2
\fBmechlist\fP – is a list of mechanisms the server has available.
Punctuation is ignored.
.IP \(bu 2
\fBprompt_need\fP – is filled in with a list of prompts needed to
continue (if necessary).
.IP \(bu 2
\fBclientout\fP – 
.sp
is created. It is  the  initial
client  response  to  send to the server. It is the job of
the client to send it over the network to the server.  Any
protocol  specific encoding (such as base64 encoding) necessary
needs to be done by the client.
.sp
If the protocol lacks client‐send‐first  capability,  then
set clientout to NULL.
.sp
If  there  is no initial client‐send, then *clientout will
be set to NULL on return.

.IP \(bu 2
\fBclientoutlen\fP – length of \fIclientout\fP\&.
.IP \(bu 2
\fBmech\fP – contains the name of the chosen  SASL
mechanism  (on success)
.UNINDENT
.UNINDENT
.UNINDENT
.SH RETURN VALUE
.sp
SASL  callback  functions should return SASL return codes.
See sasl.h for a complete list. \fBSASL_CONTINUE\fP indicates success
and that there are more steps needed in the authentication.
.sp
Other return codes indicate errors and should either be handled or the authentication
session should be quit.
.SH SEE ALSO
.sp
\fI\%RFC 4422\fP,:saslman:\fIsasl(3)\fP, sasl_callbacks(3),
sasl_client_init(3), sasl_client_new(3),
sasl_client_step(3), sasl_errors(3)
.SH AUTHOR
The Cyrus Team
.SH COPYRIGHT
1993-2016, The Cyrus Team
.\" Generated by docutils manpage writer.
.
PK�h%[E��ePPman/man3/sasl_idle.3nu�[���.\" Man page generated from reStructuredText.
.
.TH "SASL_IDLE" "3" "November 08, 2018" "2.1.27" "Cyrus SASL"
.SH NAME
sasl_idle \- Cyrus SASL documentation
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.SH SYNOPSIS
.sp
.nf
#include <sasl/sasl.h>

int sasl_idle( sasl_conn_t *conn)
.fi
.SH DESCRIPTION
.INDENT 0.0
.TP
.B int sasl_idle(sasl_conn_t\fI\ *conn\fP)
\fBsasl_idle()\fP may be called during an idle period to allow the
SASL library or any mechanisms to perform any necessary
precalculation.
.INDENT 7.0
.TP
.B Parameters
.INDENT 7.0
.IP \(bu 2
\fBconn\fP – may be NULL to do precalculation prior to a
connection taking place.
.UNINDENT
.UNINDENT
.UNINDENT
.SH RETURN VALUE
.sp
Returns 1 if action was taken, 0 if no action was taken.
.SH SEE ALSO
.sp
\fI\%RFC 4422\fP,:saslman:\fIsasl(3)\fP
.SH AUTHOR
The Cyrus Team
.SH COPYRIGHT
1993-2016, The Cyrus Team
.\" Generated by docutils manpage writer.
.
PK�h%[�,��man/man3/sasl_setpass.3nu�[���.\" Man page generated from reStructuredText.
.
.TH "SASL_SETPASS" "3" "November 08, 2018" "2.1.27" "Cyrus SASL"
.SH NAME
sasl_setpass \- Cyrus SASL documentation
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.SH SYNOPSIS
.sp
.nf
#include <sasl/sasl.h>

int sasl_setpass(sasl_conn_t *conn,
                 const char *user,
                 const char *pass, unsigned passlen,
                  const char *oldpass, unsigned oldpasslen,
                  unsigned flags)
.fi
.SH DESCRIPTION
.INDENT 0.0
.TP
.B int sasl_setpass(sasl_conn_t *conn,
.TP
.B const char *user,
.TP
.B const char *pass, unsigned passlen,
.TP
.B const char *oldpass, unsigned oldpasslen,
.TP
.B unsigned flags)
\fBsasl_setpass\fP will set passwords in the sasldb, and trigger the setpass
callbacks for all available mechanisms.
.INDENT 7.0
.TP
.B Parameters
.INDENT 7.0
.IP \(bu 2
\fBconn\fP – is the SASL connection context
.IP \(bu 2
\fBuser\fP – is the username to set the password for
.IP \(bu 2
\fBpass\fP – the password to set
.IP \(bu 2
\fBpasslen\fP – length of the password to set (\fIpass\fP)
.IP \(bu 2
\fBoldpass\fP – optional. The old password.
.IP \(bu 2
\fBoldpasslen\fP – optional. The old password length.
.IP \(bu 2
\fBflags\fP – 
.sp
are flags including \fISASL_SET_CREATE\fP and
\fISASL_SET_DISABLE\fP (to cause the creating of nonexistent accounts and the
disabling of an account, respectively)
.sp
\fIoldpass\fP and \fIoldpasslen\fP are unused in the Cyrus SASL implementation, though
are passed on to any mechanisms that may require them.

.UNINDENT
.UNINDENT
.UNINDENT
.SH RETURN VALUE
.sp
SASL  callback  functions should return SASL return codes.
See sasl.h for a complete list. \fBSASL_OK\fP indicates success.
.sp
Other return codes indicate errors and should be handled.
.SH SEE ALSO
.sp
\fI\%RFC 4422\fP,:saslman:\fIsasl(3)\fP, sasl_errors(3),
sasl_checkpass(3)
.SH AUTHOR
The Cyrus Team
.SH COPYRIGHT
1993-2016, The Cyrus Team
.\" Generated by docutils manpage writer.
.
PK�h%[�-H��
�
man/man3/sasl_listmech.3nu�[���.\" Man page generated from reStructuredText.
.
.TH "SASL_LISTMECH" "3" "November 08, 2018" "2.1.27" "Cyrus SASL"
.SH NAME
sasl_listmech \- Cyrus SASL documentation
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.SH SYNOPSIS
.sp
.nf
#include <sasl/sasl.h>

int sasl_listmech(sasl_conn_t *conn,
                 const char *user,
                 const char *prefix,
                 const char *sep,
                 const char *suffix,
                 const char **result,
                 unsigned *plen,
                 int *pcount);
.fi
.SH DESCRIPTION
.INDENT 0.0
.TP
.B int sasl_listmech(sasl_conn_t *conn,
.TP
.B const char *user,
.TP
.B const char *prefix,
.TP
.B const char *sep,
.TP
.B const char *suffix,
.TP
.B const char **result,
.TP
.B unsigned *plen,
.TP
.B int *pcount);
\fBsasl_listmech\fP returns a string listing the SASL names of
all the mechanisms available to the specified user. This
is typically given to the client through a capability command
or initial server response. Client applications need
this list so that they know what mechanisms the server
supports.
.INDENT 7.0
.TP
.B Parameters
.INDENT 7.0
.IP \(bu 2
\fBconn\fP – the SASL context for this connection
.IP \(bu 2
\fBuser\fP – (optional) restricts the mechanism list to only those
available to the user.
.IP \(bu 2
\fBprefix\fP – appended to beginning of result
.IP \(bu 2
\fBsep\fP – appended between mechanisms
.IP \(bu 2
\fBsuffix\fP – appended to end of result
.IP \(bu 2
\fBresult\fP – NULL terminated result string (allocated/freed by
library)
.IP \(bu 2
\fBplen\fP – length of result filled in by library. May be NULL
.IP \(bu 2
\fBpcount\fP – Number of mechanisms available (filled in by library).
May be NULL
.UNINDENT
.UNINDENT
.UNINDENT
.SH EXAMPLE
.sp
.nf
sasl_listmech(conn,NULL,"(",",",")",&mechlist,NULL,NULL);
.fi
.sp
may give the following string as a result:
.INDENT 0.0
.INDENT 3.5
\fI(ANONYMOUS,KERBEROS_V4,DIGEST‐MD5)\fP
.UNINDENT
.UNINDENT
.SH RETURN VALUE
.sp
SASL functions should return SASL return codes.
See sasl.h for a complete list. \fBSASL_OK\fP indicates success.
.SH SEE ALSO
.sp
\fI\%RFC 4422\fP,:saslman:\fIsasl(3)\fP, sasl_server_new(3),
sasl_errors(3), sasl_client_new(3)
.SH AUTHOR
The Cyrus Team
.SH COPYRIGHT
1993-2016, The Cyrus Team
.\" Generated by docutils manpage writer.
.
PK�h%[�		man/man3/sasl_getconfpath_t.3nu�[���.\" Man page generated from reStructuredText.
.
.TH "SASL_GETCONFPATH_T" "3" "November 08, 2018" "2.1.27" "Cyrus SASL"
.SH NAME
sasl_getconfpath_t \- Cyrus SASL documentation
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.SH SYNOPSIS
.sp
.nf
#include <sasl/sasl.h>

int sasl_getconfpath_t(void *context, char ** path);
.fi
.SH DESCRIPTION
.INDENT 0.0
.TP
.B int sasl_getconfpath_t(void *context, char ** path);
\fBsasl_getconfpath_t()\fP is used if the  application  wishes  to
use a different location for the SASL configuration files.
If this callback is not used  SASL  will  either  use  the
location  in the environment variable SASL_CONF_PATH (provided
we are not SUID or SGID) or \fI/etc/sasl2\fP by default.
.UNINDENT
.SH RETURN VALUE
.sp
SASL  callback  functions should return SASL return codes.
See sasl.h for a complete list. \fBSASL_OK\fP indicates success.
.sp
Other return codes indicate errors and should be handled.
.SH SEE ALSO
.sp
\fI\%RFC 4422\fP,:saslman:\fIsasl(3)\fP, sasl_callbacks(3)
.SH AUTHOR
The Cyrus Team
.SH COPYRIGHT
1993-2016, The Cyrus Team
.\" Generated by docutils manpage writer.
.
PK�h%[�2qrrman/man3/sasl_server_init.3nu�[���.\" Man page generated from reStructuredText.
.
.TH "SASL_SERVER_INIT" "3" "November 08, 2018" "2.1.27" "Cyrus SASL"
.SH NAME
sasl_server_init \- Cyrus SASL documentation
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.SH SYNOPSIS
.sp
.nf
#include <sasl/sasl.h>

int sasl_server_init(const sasl_callback_t *callbacks,
                     const char *appname);
.fi
.SH DESCRIPTION
.INDENT 0.0
.TP
.B int sasl_server_init(const sasl_callback_t *callbacks,
.TP
.B const char *appname);
\fBsasl_server_init()\fP initializes SASL.  It  must  be  called
before  any  calls to sasl_server_start, and only once per
process.  This call initializes all SASL mechanism drivers
(e.g.  authentication mechanisms). These are usually found
in the /usr/lib/sasl2 directory but the directory  may  be
overridden  with the SASL_PATH environment variable (or at
compile time).
.INDENT 7.0
.TP
.B Parameters
.INDENT 7.0
.IP \(bu 2
\fBcallbacks\fP – specifies the base callbacks for all client connections.
See the sasl_callbacks(3) man page for more information.
.IP \(bu 2
\fBappname\fP – is the name of the application.  It  is  used to find the
default configuration file.
.UNINDENT
.UNINDENT
.UNINDENT
.SH RETURN VALUE
.sp
SASL  callback  functions should return SASL return codes.
See sasl.h for a complete list. \fBSASL_OK\fP indicates success.
.sp
Other return codes indicate errors and should either be handled or the authentication
session should be quit.
.SH SEE ALSO
.sp
\fI\%RFC 4422\fP,:saslman:\fIsasl(3)\fP, sasl_callbacks(3),
sasl_server_new(3), sasl_server_start(3),
sasl_server_step(3), sasl_errors(3)
.SH AUTHOR
The Cyrus Team
.SH COPYRIGHT
1993-2016, The Cyrus Team
.\" Generated by docutils manpage writer.
.
PK�h%[��^��man/man3/sasl_errdetail.3nu�[���.\" Man page generated from reStructuredText.
.
.TH "SASL_ERRDETAIL" "3" "November 08, 2018" "2.1.27" "Cyrus SASL"
.SH NAME
sasl_errdetail \- Cyrus SASL documentation
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.SH SYNOPSIS
.sp
.nf
#include <sasl/sasl.h>

const char *sasl_errdetail( sasl_conn_t *conn );
.fi
.SH DESCRIPTION
.INDENT 0.0
.TP
.B const char *sasl_errdetail( sasl_conn_t *conn );
\fBsasl_errdetail\fP provides more  detailed  information  about
the  most  recent  error  to occur, beyond the information
contained in the SASL result code.
.INDENT 7.0
.TP
.B Parameters
.INDENT 7.0
.IP \(bu 2
\fBconn\fP – the SASL connection context to inquire about.
.UNINDENT
.UNINDENT
.UNINDENT
.SH RETURN VALUE
.sp
Returns the string describing the error that occurred,  or NULL  if  no  error
has  occurred,  or there was an error retrieving it.
.SH SEE ALSO
.sp
\fI\%RFC 4422\fP,:saslman:\fIsasl(3)\fP
.SH AUTHOR
The Cyrus Team
.SH COPYRIGHT
1993-2016, The Cyrus Team
.\" Generated by docutils manpage writer.
.
PK�h%[{���ZZman/man3/sasl_client_step.3nu�[���.\" Man page generated from reStructuredText.
.
.TH "SASL_CLIENT_STEP" "3" "November 08, 2018" "2.1.27" "Cyrus SASL"
.SH NAME
sasl_client_step \- Cyrus SASL documentation
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.SH SYNOPSIS
.sp
.nf
#include <sasl/sasl.h>

int sasl_client_step(sasl_conn_t *conn,
               const char *serverin,
               unsigned serverinlen,
               sasl_interact_t ** prompt_need,
               const char ** clientout,
               unsigned * clientoutlen);
.fi
.SH DESCRIPTION
.INDENT 0.0
.TP
.B int sasl_client_step(sasl_conn_t *conn,
.TP
.B const char *serverin,
.TP
.B unsigned serverinlen,
.TP
.B sasl_interact_t ** prompt_need,
.TP
.B const char ** clientout,
.TP
.B unsigned * clientoutlen);
\fBsasl_client_step()\fP performs a step in  the  authentication negotiation.  It
returns \fBSASL_OK\fP if the whole negotiation is successful and
\fBSASL_CONTINUE\fP if
this step is ok but  at least  one more step is needed. A client should not
assume an authentication negotiation is successful  just  because the
server  signaled  success  via  protocol (i.e. if the server  said  “.  OK
Authentication  succeeded”  in  IMAP, sasl_client_step should still be called
one more time with a \fIserverinlen\fP of zero.
.sp
If \fBSASL_INTERACT\fP is returned the library needs some values
to  be  filled  in  before it can proceed. \fIThe prompt_need\fP
structure will be filled in with requests. The application
should  fulfill  these requests and call sasl_client_start
again with identical parameters (the \fIprompt_need\fP parameter
will  be  the  same pointer as before but filled in by the
application).
.INDENT 7.0
.TP
.B Parameters
.INDENT 7.0
.IP \(bu 2
\fBconn\fP – is the SASL connection context
.IP \(bu 2
\fBserverin\fP – is the data given by the server (decoded  if  the
protocol encodes requests sent over the wire)
.IP \(bu 2
\fBserverinlen\fP – is the length of \fIserverin\fP
.IP \(bu 2
\fBclientout\fP – is created. It is  the  initial
client  response  to  send to the server. It is the job of
the client to send it over the network to the server.  Any
protocol  specific encoding (such as base64 encoding) nec‐
essary needs to be done by the client.
.IP \(bu 2
\fBclientoutlen\fP – length of \fIclientout\fP\&.
.UNINDENT
.UNINDENT
.UNINDENT
.SH RETURN VALUE
.sp
SASL  callback  functions should return SASL return codes.
See sasl.h for a complete list. \fBSASL_CONTINUE\fP indicates success
and that there are more steps needed in the authentication. \fBSASL_OK\fP
indicates that the authentication is complete.
.sp
Other return codes indicate errors and should either be handled or the authentication
session should be quit.
.SH SEE ALSO
.sp
\fI\%RFC 4422\fP,:saslman:\fIsasl(3)\fP, sasl_callbacks(3),
sasl_client_init(3), sasl_client_new(3),
sasl_client_start(3), sasl_errors(3)
.SH AUTHOR
The Cyrus Team
.SH COPYRIGHT
1993-2016, The Cyrus Team
.\" Generated by docutils manpage writer.
.
PK�h%[@ؾ���man/man3/sasl_client_new.3nu�[���.\" Man page generated from reStructuredText.
.
.TH "SASL_CLIENT_NEW" "3" "November 08, 2018" "2.1.27" "Cyrus SASL"
.SH NAME
sasl_client_new \- Cyrus SASL documentation
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.SH SYNOPSIS
.sp
.nf
#include <sasl/sasl.h>

int sasl_client_new(const char *service,
                    const char *serverFQDN,
                    const char *iplocalport,
                    const char *ipremoteport,
                    const sasl_callback_t *prompt_supp,
                    unsigned flags,
                    sasl_conn_t ** pconn);
.fi
.SH DESCRIPTION
.INDENT 0.0
.TP
.B int sasl_client_new(const char *service,
.TP
.B const char *serverFQDN,
.TP
.B const char *iplocalport,
.TP
.B const char *ipremoteport,
.TP
.B const sasl_callback_t *prompt_supp,
.TP
.B unsigned flags,
.TP
.B sasl_conn_t ** pconn);
\fBsasl_client_new()\fP creates a new SASL context. This context will be
used for all SASL calls for one connection. It handles both
authentication and integrity/encryption layers after authentication.
.INDENT 7.0
.TP
.B Parameters
.INDENT 7.0
.IP \(bu 2
\fBservice\fP – the registered name of the service (usually the protocol name) using SASL (e.g. “imap”).
.IP \(bu 2
\fBserverFQDN\fP – the fully qualified domain name of the server (e.g. “serverhost.example.com”).
.IP \(bu 2
\fBiplocalport\fP – the IP and port of the local side of the
connection, or NULL.  If iplocalport is NULL it will disable
mechanisms that require IP address information.  This
string must be in one of the   following   formats:
“a.b.c.d;port”  (IPv4),  “e:f:g:h:i:j:k:l;port” (IPv6), or
“e:f:g:h:i:j:a.b.c.d;port” (IPv6)
.IP \(bu 2
\fBipremoteport\fP – the IP and port of the remote side of the
connection, or NULL (see iplocalport)
.IP \(bu 2
\fBprompt_supp\fP – a list of client interactions supported
that is unique to this connection. If this parameter is
NULL the global callbacks (specified in sasl_client_init(3))
will be used. See sasl_callbacks(3) for more information.
.IP \(bu 2
\fBflags\fP – are connection flags (see below)
.IP \(bu 2
\fBpconn\fP – the connection context allocated by the library.
This structure will be used for all future SASL calls for
this connection.
.UNINDENT
.UNINDENT
.UNINDENT
.SS Connection Flags
.sp
Flags that may be passed to \fBsasl_client_new()\fP:
.INDENT 0.0
.IP \(bu 2
\fISASL_SUCCESS_DATA\fP: The protocol supports a server‐last send
.IP \(bu 2
.INDENT 2.0
.TP
.B \fISASL_NEED_PROXY\fP: Force the use of a mechanism that supports an
authorization id that is not the authentication id.
.UNINDENT
.UNINDENT
.SH RETURN VALUE
.sp
SASL callback functions should return SASL return codes.
See sasl.h for a complete list. \fBSASL_OK\fP indicates success.
.sp
The following return codes indicate errors and should either be handled or the authentication
session should be quit:
.INDENT 0.0
.IP \(bu 2
\fBSASL_NOMECH\fP: No mechanism meets requested properties
.IP \(bu 2
\fBSASL_BADPARAM\fP: Error in config file
.IP \(bu 2
\fBSASL_NOMEM\fP: Not enough memory to complete operation
.UNINDENT
.SH SEE ALSO
.sp
\fI\%RFC 4422\fP,:saslman:\fIsasl(3)\fP, sasl_callbacks(3),
sasl_client_init(3), sasl_client_start(3),
sasl_client_step(3), sasl_setprop(3)
.SH AUTHOR
The Cyrus Team
.SH COPYRIGHT
1993-2016, The Cyrus Team
.\" Generated by docutils manpage writer.
.
PK�h%[�
��man/man3/sasl_errstring.3nu�[���.\" Man page generated from reStructuredText.
.
.TH "SASL_ERRSTRING" "3" "November 08, 2018" "2.1.27" "Cyrus SASL"
.SH NAME
sasl_errstring \- Cyrus SASL documentation
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.SH SYNOPSIS
.sp
.nf
#include <sasl/sasl.h>

const char * sasl_errstring(int saslerr,
    const char * langlist,
    const char ** outlang);
.fi
.SH DESCRIPTION
.INDENT 0.0
.TP
.B const char * sasl_errstring(int saslerr,
.TP
.B const char * langlist,
.TP
.B const char ** outlang);
\fBsasl_errstring\fP is called to convert a SASL return code (an
integer) into a human readable string. At this time the
only language available is American English. Note that if the string is
going to be sent to the client, a server should
call sasl_usererr(3) on a return code first.
.INDENT 7.0
.TP
.B Parameters
.INDENT 7.0
.IP \(bu 2
\fBsaslerr\fP – specifies the error number to convert.
.IP \(bu 2
\fBlanglist\fP – is currently unused; Use NULL.
.IP \(bu 2
\fBoutlang\fP – specifies  the desired \fI\%RFC 1766\fP language for
output.  NULL defaults to “en‐us”; currently the only supported
language.
.UNINDENT
.UNINDENT
.sp
This function is not the recommended means of extracting error code
information from SASL,  instead  application  should use
sasl_errdetail(3), which contains this information (and more).
.UNINDENT
.SH RETURN VALUE
.sp
Returns the string.  If  langlist  is  NULL,  US‐ASCII  is used.
.SH SEE ALSO
.sp
\fI\%RFC 4422\fP,:saslman:\fIsasl(3)\fP, sasl_errdetail(3),
sasl_errors(3)
.SH AUTHOR
The Cyrus Team
.SH COPYRIGHT
1993-2016, The Cyrus Team
.\" Generated by docutils manpage writer.
.
PK�h%[���ooman/man3/sasl_done.3nu�[���.\" Man page generated from reStructuredText.
.
.TH "SASL_DONE" "3" "November 08, 2018" "2.1.27" "Cyrus SASL"
.SH NAME
sasl_done \- Cyrus SASL documentation
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.SH SYNOPSIS
.sp
.nf
#include <sasl/sasl.h>

void sasl_done( void );
.fi
.SH DESCRIPTION
.INDENT 0.0
.TP
.B void sasl_done( void );
\fBsasl_done()\fP is  called  when  the application is completely
done with the SASL library.
.UNINDENT
.SH RETURN VALUE
.sp
No return values.
.SH SEE ALSO
.sp
\fI\%RFC 4422\fP,:saslman:\fIsasl(3)\fP,
sasl_server_init(3), sasl_client_init(3)
.SH AUTHOR
The Cyrus Team
.SH COPYRIGHT
1993-2016, The Cyrus Team
.\" Generated by docutils manpage writer.
.
PK�h%[��:���man/man3/sasl_canon_user_t.3nu�[���.\" Man page generated from reStructuredText.
.
.TH "SASL_CANON_USER_T" "3" "November 08, 2018" "2.1.27" "Cyrus SASL"
.SH NAME
sasl_canon_user_t \- Cyrus SASL documentation
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.SH SYNOPSIS
.sp
.nf
#include <sasl/sasl.h>

int sasl_canon_user_t(sasl_conn_t *conn, void *context, const char *user, unsigned ulen,
                      unsigned flags, const char *user_realm, char *out_user,
                      unsigned out_umax, unsigned *out_ulen)
.fi
.SH DESCRIPTION
.INDENT 0.0
.TP
.B int sasl_canon_user_t(sasl_conn_t *conn,
.TP
.B void *context,
.TP
.B const char *user,
.TP
.B unsigned ulen,
.TP
.B unsigned flags,
.TP
.B const char *user_realm,
.TP
.B char *out_user,
.TP
.B unsigned out_umax,
.TP
.B unsigned *out_ulen)
\fBsasl_canon_user_t\fP is the callback for an  application\-supplied  user  canonicalization  function.  This function is
subject to the requirements that all user canonicalization
functions  are:  It  must  copy the result into the output
buffers, but the output buffers and the input buffers  may
be the same.
.INDENT 7.0
.TP
.B Parameters
.INDENT 7.0
.IP \(bu 2
\fBcontext\fP – context from the callback record
.IP \(bu 2
\fBuser\fP – un\-canonicalized username
.IP \(bu 2
\fBulen\fP – length of user
.IP \(bu 2
\fBflags\fP – Either SASL_CU_AUTHID (indicating the authentication ID is being canonicalized) or SASL_CU_AUTHZID  (indicating the  authorization ID is to be canonicalized) or a bitwise OR of the the two.
.IP \(bu 2
\fBuser_realm\fP – Realm of authentication.
.IP \(bu 2
\fBout_user\fP – The output buffer for the canonicalized username
.IP \(bu 2
\fBout_umax\fP – Maximum length for out_user
.IP \(bu 2
\fBout_ulen\fP – Actual length of out_user
.UNINDENT
.TP
.B Returns
\fBSASL_OK\fP indicates success. See sasl_errors(3) for a full list of SASL error codes.
.UNINDENT
.UNINDENT
.SH CONFORMING TO
.sp
\fI\%RFC 4422\fP
.SH SEE ALSO
.sp
sasl(3), sasl_errors(3), sasl_callbacks(3)
.SH AUTHOR
The Cyrus Team
.SH COPYRIGHT
1993-2016, The Cyrus Team
.\" Generated by docutils manpage writer.
.
PK�h%[�[�##man/man3/sasl_errors.3nu�[���.\" Man page generated from reStructuredText.
.
.TH "SASL_ERRORS" "3" "November 08, 2018" "2.1.27" "Cyrus SASL"
.SH NAME
sasl_errors \- Cyrus SASL documentation
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.SH SYNOPSIS
.sp
.nf
#include <sasl/sasl.h>
.fi
.SH DESCRIPTION
.sp
The  following  are  the  general  error codes that may be
returned by calls into the SASL library, and  their  meanings (that may vary slightly based on context).
.SS Common Result Codes
.INDENT 0.0
.TP
.B SASL_OK
Success
.UNINDENT
.INDENT 0.0
.TP
.B SASL_CONTINUE
Another step is needed in authentication
.UNINDENT
.INDENT 0.0
.TP
.B SASL_FAIL
Generic Failure
.UNINDENT
.INDENT 0.0
.TP
.B SASL_NOMEM
Memory shortage failure
.UNINDENT
.INDENT 0.0
.TP
.B SASL_BUFOVER
Overflowed buffer
.UNINDENT
.INDENT 0.0
.TP
.B SASL_NOMECH
Mechanism  not  supported  / No mechanisms matched
requirements
.UNINDENT
.INDENT 0.0
.TP
.B SASL_BADPROT
Bad / Invalid Protocol or Protocol cancel
.UNINDENT
.INDENT 0.0
.TP
.B SASL_NOTDONE
Cannot request information / Not  applicable  until
later in exchange
.UNINDENT
.INDENT 0.0
.TP
.B SASL_BADPARAM
Invalid Parameter Supplied
.UNINDENT
.INDENT 0.0
.TP
.B SASL_TRYAGAIN
Transient Failure (e.g. weak key)
.UNINDENT
.INDENT 0.0
.TP
.B SASL_BADMAC
Integrity Check Failed
.UNINDENT
.INDENT 0.0
.TP
.B SASL_NOTINIT
SASL library not initialized
.UNINDENT
.SS Client\-only Result Codes
.INDENT 0.0
.TP
.B SASL_INTERACT
Needs user interaction
.UNINDENT
.INDENT 0.0
.TP
.B SASL_BADSERV
Server failed mutual authentication step
.UNINDENT
.INDENT 0.0
.TP
.B SASL_WRONGMECH
Mechanism does not support requested feature
.UNINDENT
.SS Server\-only Result Codes
.INDENT 0.0
.TP
.B SASL_BADAUTH
Authentication Failure
.UNINDENT
.INDENT 0.0
.TP
.B SASL_NOAUTHZ
Authorization Failure
.UNINDENT
.INDENT 0.0
.TP
.B SASL_TOOWEAK
Mechanism too weak for this user
.UNINDENT
.INDENT 0.0
.TP
.B SASL_ENCRYPT
Encryption needed to use mechanism
.UNINDENT
.INDENT 0.0
.TP
.B SASL_TRANS
One  time  use of a plaintext password will enable
requested mechanism for user
.UNINDENT
.INDENT 0.0
.TP
.B SASL_EXPIRED
Passphrase expired, must be reset
.UNINDENT
.INDENT 0.0
.TP
.B SASL_DISABLED
Account Disabled
.UNINDENT
.INDENT 0.0
.TP
.B SASL_NOUSER
User Not Found
.UNINDENT
.INDENT 0.0
.TP
.B SASL_BADVERS
Version mismatch with plug\-in
.UNINDENT
.INDENT 0.0
.TP
.B SASL_NOVERIFY
User exists, but no verifier for user
.UNINDENT
.SS Password Setting Result Codes
.INDENT 0.0
.TP
.B SASL_PWLOCK
Passphrase locked
.UNINDENT
.INDENT 0.0
.TP
.B SASL_NOCHANGE
Requested change was not needed
.UNINDENT
.INDENT 0.0
.TP
.B SASL_WEAKPASS
Passphrase is too week for security policy.
.UNINDENT
.INDENT 0.0
.TP
.B SASL_NOUSERPASS
User supplied passwords are not permitted
.UNINDENT
.SH CONFORMING TO
.sp
\fI\%RFC 4422\fP
.SH SEE ALSO
.sp
sasl(3)
.SH AUTHOR
The Cyrus Team
.SH COPYRIGHT
1993-2016, The Cyrus Team
.\" Generated by docutils manpage writer.
.
PK�h%[���55man/man3/sasl_callbacks.3nu�[���.\" Man page generated from reStructuredText.
.
.TH "SASL_CALLBACKS" "3" "November 08, 2018" "2.1.27" "Cyrus SASL"
.SH NAME
sasl_callbacks \- Cyrus SASL documentation
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.SH SYNOPSIS
.sp
.nf
#include <sasl/sasl.h>
.fi
.SH DESCRIPTION
.sp
\fBsasl_callbacks\fP  are  used  when the application needs some
information from the application. Common reasons are  getting
for  getting  usernames and passwords. A client MUST
specify   what   callbacks    they    support    in    the
sasl_client_init(3)/sasl_server_init(3)
or   sasl_client_new(3)/sasl_server_new(3)
calls. If an authentication  mechanism  needs  a  callback
that  the application does not state it supports it cannot
be used.
.sp
If a callback has an id parameter that should  be  checked
to make sure you are giving the appropriate value.
.sp
If  an application is using the client side of the library
functions to  handle  the  callbacks  are  not  necessary.
Instead  the  application  may  deal  with  callbacks  via
SASL_INTERACT’s.  See  sasl_client_start(3)/sasl_client_step(3)  for  more
information.
.SS Common Callbacks
.INDENT 0.0
.TP
.B sasl_getopt_t
Get an option value
.TP
.B sasl_log_t
Log message handler
.TP
.B sasl_getpath_t
Get  path  to search for plugins (e.g. SASL mechanisms)
.TP
.B sasl_verifyfile_t
Verify files for use by SASL
.TP
.B sasl_canon_user_t(3)
Username canonicalization function
.UNINDENT
.SS Client\-only Callbacks
.INDENT 0.0
.TP
.B sasl_getsimple_t
Get user/language list
.TP
.B sasl_getsecret_t
Get authentication secret
.TP
.B sasl_chalprompt_t(3)
Display challenge and prompt for response
.TP
.B sasl_getrealm_t
Get the realm for authentication
.UNINDENT
.SS Server\-only Callbacks
.INDENT 0.0
.TP
.B sasl_authorize_t(3)
Authorize policy callback
.TP
.B sasl_server_userdb_checkpass_t
verify plaintext password
.TP
.B sasl_server_userdb_setpass_t
set plaintext password
.TP
.B sasl_getconfpath_t
Get path to search  for  SASL  configuration  file
(server side only). New in SASL 2.1.22.
.UNINDENT
.SH RETURN VALUE
.sp
SASL  callback  functions should return SASL return codes.
See sasl_errors(3) for a complete list.  \fBSASL_OK\fP  typically  indicates success.
.SH CONFORMING TO
.sp
\fI\%RFC 4422\fP
.SH SEE ALSO
.sp
sasl(3), sasl_errors(3), sasl_authorize_t(3),
sasl_log_t(3), sasl_getpath_t(3),
sasl_getconfpath_t(3), sasl_verifyfile_t(3),
sasl_canon_user_t(3),  sasl_getsimple_t(3),
sasl_getsecret_t(3), sasl_chalprompt_t(3),
sasl_getrealm_t(3), sasl_server_userdb_checkpass_t(3),
sasl_server_userdb_setpass_t(3)
.SH AUTHOR
The Cyrus Team
.SH COPYRIGHT
1993-2016, The Cyrus Team
.\" Generated by docutils manpage writer.
.
PK�h%[���**man/man3/sasl_getprop.3nu�[���.\" Man page generated from reStructuredText.
.
.TH "SASL_GETPROP" "3" "November 08, 2018" "2.1.27" "Cyrus SASL"
.SH NAME
sasl_getprop \- Cyrus SASL documentation
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.SH SYNOPSIS
.sp
.nf
#include <sasl/sasl.h>

int sasl_getprop(sasl_conn_t *conn,
                int propnum,
                const void ** pvalue);
.fi
.SH DESCRIPTION
.INDENT 0.0
.TP
.B int sasl_getprop(sasl_conn_t *conn,
.TP
.B int propnum,
.TP
.B const void ** pvalue);
\fBsasl_getprop\fP  gets the value of a SASL property. For example after
successful authentication a server may  wish  to know  the  authorization
name. Or a client application may wish to know  the  strength  of  the
negotiated  security layer.
.INDENT 7.0
.TP
.B Parameters
.INDENT 7.0
.IP \(bu 2
\fBconn\fP – is the SASL connection context
.IP \(bu 2
\fBpropnum\fP – is the identifier for the property requested
.IP \(bu 2
\fBpvalue\fP – 
.sp
is filled on success. List of properties:
.INDENT 2.0
.IP \(bu 2
SASL_USERNAME     ‐  pointer to NUL terminated user name
.IP \(bu 2
.INDENT 2.0
.TP
.B SASL_SSF          ‐  security layer security strength factor,
if 0, call to sasl_encode(3), sasl_decode(3)
unnecessary
.UNINDENT
.IP \(bu 2
SASL_MAXOUTBUF    ‐  security layer max output buf unsigned
.IP \(bu 2
SASL_DEFUSERREALM ‐  server authentication realm used
.IP \(bu 2
SASL_GETOPTCTX    ‐  context for getopt callback
.IP \(bu 2
SASL_IPLOCALPORT  ‐  local address string
.IP \(bu 2
SASL_IPREMOTEPORT ‐  remote address string
.IP \(bu 2
SASL_SERVICE      ‐  service passed to \fIsasl_*_new\fP
.IP \(bu 2
SASL_SERVERFQDN   ‐  serverFQDN passed to \fIsasl_*_new\fP
.IP \(bu 2
.INDENT 2.0
.TP
.B SASL_AUTHSOURCE   ‐  name of auth source last used, useful for failed
authentication tracking
.UNINDENT
.IP \(bu 2
SASL_MECHNAME     ‐  active mechanism name, if any
.IP \(bu 2
SASL_PLUGERR      ‐  similar to \fIsasl_errdetail\fP
.UNINDENT

.UNINDENT
.UNINDENT
.UNINDENT
.SH RETURN VALUE
.sp
SASL  callback  functions should return SASL return codes.
See sasl.h for a complete list. \fBSASL_OK\fP indicates success.
.sp
Other return codes indicate errors and should be handled.
.SH SEE ALSO
.sp
\fI\%RFC 4422\fP,:saslman:\fIsasl(3)\fP, sasl_errors(3)
sasl_server_new(3), sasl_client_new(3)
.SH AUTHOR
The Cyrus Team
.SH COPYRIGHT
1993-2016, The Cyrus Team
.\" Generated by docutils manpage writer.
.
PK�h%[�tQ.

man/man3/sasl_user_exists.3nu�[���.\" Man page generated from reStructuredText.
.
.TH "SASL_USER_EXISTS" "3" "November 08, 2018" "2.1.27" "Cyrus SASL"
.SH NAME
sasl_user_exists \- Cyrus SASL documentation
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.SH SYNOPSIS
.sp
.nf
#include <sasl/sasl.h>

int sasl_user_exists( sasl_conn_t *conn,
                      const char *service,
                      const char *user_realm,
                      const char *user)
.fi
.SH DESCRIPTION
.INDENT 0.0
.TP
.B int sasl_user_exists( sasl_conn_t *conn,
.TP
.B const char *service,
.TP
.B const char *user_realm,
.TP
.B const char *user)
\fBsasl_user_exists\fP will check if a user exists on the server.
.INDENT 7.0
.TP
.B Parameters
.INDENT 7.0
.IP \(bu 2
\fBconn\fP – the SASL context for this connection
.IP \(bu 2
\fBservice\fP – Service name or NULL (for service name of
connection context)
.IP \(bu 2
\fBuser_realm\fP – Realm to check in or NULL (for default realm)
.IP \(bu 2
\fBuser\fP – User name to check for existence.
.UNINDENT
.UNINDENT
.UNINDENT
.SH RETURN VALUE
.sp
SASL functions should return SASL return codes.
See sasl.h for a complete list. \fBSASL_OK\fP indicates success.
.SH SEE ALSO
.sp
\fI\%RFC 4422\fP,:saslman:\fIsasl(3)\fP,:saslman:\fIsasl_errors(3)\fP
.SH AUTHOR
The Cyrus Team
.SH COPYRIGHT
1993-2016, The Cyrus Team
.\" Generated by docutils manpage writer.
.
PK�h%[�W��~
~
man/man3/sasl_checkpass.3nu�[���.\" Man page generated from reStructuredText.
.
.TH "SASL_CHECKPASS" "3" "November 08, 2018" "2.1.27" "Cyrus SASL"
.SH NAME
sasl_checkpass \- Cyrus SASL documentation
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.SH SYNOPSIS
.sp
.nf
#include <sasl/sasl.h>

int sasl_checkpass(sasl_conn_t *conn,
                 const char *user,
                 unsigned userlen,
                 const char *pass,
                 unsigned passlen);
.fi
.SH DESCRIPTION
.INDENT 0.0
.TP
.B int sasl_checkpass(sasl_conn_t *conn,
.TP
.B const char *user,
.TP
.B unsigned userlen,
.TP
.B const char *pass,
.TP
.B unsigned passlen)
\fBsasl_checkpass\fP  will check a plaintext password. This is
needed for protocols that had a login method  before  SASL
(for  example  the LOGIN command in IMAP). The password is
checked with the pwcheck_method. See sasl_callbacks(3)  for
information on how this parameter is set.
.UNINDENT
.SH RETURN VALUE
.sp
sasl_checkpass returns an integer which corresponds to one
of the following codes. \fBSASL_OK\fP indicates that the authentication  is  complete.  All  other  return codes indicate
errors and should either be handled or the  authentication
session  should  be quit.  See sasl_errors(3) for meanings
of return codes.
.SH CONFORMING TO
.sp
\fI\%RFC 4422\fP
.SH SEE ALSO
.sp
sasl(3), sasl_errors(3), sasl_callbacks(3),
sasl_setpass(3)
.SH AUTHOR
The Cyrus Team
.SH COPYRIGHT
1993-2016, The Cyrus Team
.\" Generated by docutils manpage writer.
.
PK�h%[��K�{{man/man3/sasl.3nu�[���.\" Man page generated from reStructuredText.
.
.TH "SASL" "3" "November 08, 2018" "2.1.27" "Cyrus SASL"
.SH NAME
sasl \- Cyrus SASL documentation
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.SH DESCRIPTION
.sp
The CMU Cyrus SASL library is a general purpose authentication library for sever and client applications.
.sp
\fBSystem Administrators\fP
.sp
For information on setting up/configuring the SASL library see the System
Administrators Guide: \fI\%https://www.cyrusimap.org/sasl/sasl/sysadmin.html\fP
.sp
\fBProgrammers\fP
.sp
See man pages for individual sasl functions or the Programmers Guide in the doc/ directory of the SASL distribution.
.sp
Conforming to \fI\%RFC 2222\fP
.SH SEE ALSO
.sp
sasl_authorize_t(3), sasl_auxprop(3), sasl_auxprop_getctx(3), sasl_auxprop_request(3),
sasl_canon_user_t(3), sasl_callbacks(3), sasl_chalprompt_t(3), sasl_checkapop(3),
sasl_checkpass(3), sasl_client_init(3), sasl_client_new(3), sasl_client_start(3),
sasl_client_step(3), sasl_decode(3), sasl_dispose(3), sasl_done(3),
sasl_encode(3), sasl_encodev(3), sasl_errdetail(3), sasl_errors(3),
sasl_errstring(3), sasl_errors(3), sasl_getopt_t(3), sasl_getpath_t(3),
sasl_getprop(3), sasl_getrealm_t(3), sasl_getsecret_t(3), sasl_getsimple_t(3),
sasl_idle(3), sasl_listmech(3), sasl_log_t(3), sasl_server_init(3),
sasl_server_new(3), sasl_server_start(3), sasl_server_step(3), sasl_server_userdb_checkpass_t(3),
sasl_server_userdb_setpass_t(3), sasl_setpass(3), sasl_setprop(3), sasl_user_exists(3),
sasl_verifyfile_t(3), sasl_global_listmech(3)
.SH REFERENCED BY
.sp
ldap.conf(5), overload(3), sasl_getconfpath_t(3)
.SH AUTHOR
The Cyrus Team
.SH COPYRIGHT
1993-2016, The Cyrus Team
.\" Generated by docutils manpage writer.
.
PK�h%[�"�man/man3/sasl_encode.3nu�[���.\" Man page generated from reStructuredText.
.
.TH "SASL_ENCODE" "3" "November 08, 2018" "2.1.27" "Cyrus SASL"
.SH NAME
sasl_encode \- Cyrus SASL documentation
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.SH SYNOPSIS
.sp
.nf
#include <sasl/sasl.h>

int sasl_encode(sasl_conn_t *conn,
                const char * input,
                unsigned inputlen,
                const char ** output,
                unsigned * outputlen);

int sasl_encodev(sasl_conn_t *conn,
                const struct iovec * invec,
                unsigned numiov,
                const char ** output,
                unsigned * outputlen);
.fi
.SH DESCRIPTION
.sp
\fBsasl_encode\fP encodes data to be sent to be sent to a remote host  who  we’ve
had  a successful authentication session with. If there  is  a  negotiated
security  the  data  in signed/encrypted  and  the  output  should be sent
without modification to the remote host. If there is  no  security layer the
output is identical to the input.
.sp
\fBsasl_encodev\fP does the same, but for a \fIstruct iovec\fP instead
of a character buffer.
.INDENT 0.0
.TP
.B int sasl_encode(sasl_conn_t *conn,
.TP
.B const char * input,
.TP
.B unsigned inputlen,
.TP
.B const char ** output,
.TP
.B unsigned * outputlen);
.INDENT 7.0
.TP
.B Parameters
.INDENT 7.0
.IP \(bu 2
\fBconn\fP – is the SASL connection context
.IP \(bu 2
\fBoutput\fP – contains the decoded data and is allocated/freed by
the library.
.IP \(bu 2
\fBoutputlen\fP – length of \fIoutput\fP\&.
.UNINDENT
.UNINDENT
.INDENT 7.0
.TP
.B int sasl_encodev(sasl_conn_t *conn,
.TP
.B const struct iovec * invec,
.TP
.B unsigned numiov,
.TP
.B const char ** output,
.TP
.B unsigned * outputlen);
.UNINDENT
.INDENT 7.0
.TP
.B Parameters
.INDENT 7.0
.IP \(bu 2
\fBconn\fP – is the SASL connection context
.IP \(bu 2
\fBoutput\fP – contains the decoded data and is allocated/freed by
the library.
.IP \(bu 2
\fBoutputlen\fP – length of \fIoutput\fP\&.
.UNINDENT
.UNINDENT
.UNINDENT
.SH RETURN VALUE
.sp
SASL  callback  functions should return SASL return codes.
See sasl.h for a complete list. \fBSASL_OK\fP indicates success.
.sp
Other return codes indicate errors and should be handled.
.SH SEE ALSO
.sp
\fI\%RFC 4422\fP,:saslman:\fIsasl(3)\fP, sasl_decode(3),
sasl_errors(3)
.SH AUTHOR
The Cyrus Team
.SH COPYRIGHT
1993-2016, The Cyrus Team
.\" Generated by docutils manpage writer.
.
PK�h%[�(L�		man/man3/sasl_dispose.3nu�[���.\" Man page generated from reStructuredText.
.
.TH "SASL_DISPOSE" "3" "November 08, 2018" "2.1.27" "Cyrus SASL"
.SH NAME
sasl_dispose \- Cyrus SASL documentation
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.SH SYNOPSIS
.sp
.nf
#include <sasl/sasl.h>

void sasl_dispose(sasl_conn_t **pconn );
.fi
.SH DESCRIPTION
.INDENT 0.0
.TP
.B int sasl_encode(sasl_conn_t *conn,
.TP
.B const char * input,
.TP
.B unsigned inputlen,
.TP
.B const char ** output,
.TP
.B unsigned * outputlen);
\fBsasl_dispose\fP is called when a SASL connection object is no longer needed.
.sp
Note that this is usually when the protocol session is done NOT when the
authentication is done since a security layer may have been negotiated.
.INDENT 7.0
.TP
.B Parameters
.INDENT 7.0
.IP \(bu 2
\fBconn\fP – is the SASL connection context
.UNINDENT
.UNINDENT
.UNINDENT
.SH RETURN VALUE
.sp
No return values
.SH CONFORMING TO
.sp
\fI\%RFC 4422\fP
.SH SEE ALSO
.sp
sasl(3), sasl_server_new(3), sasl_client_new(3),
.SH AUTHOR
The Cyrus Team
.SH COPYRIGHT
1993-2016, The Cyrus Team
.\" Generated by docutils manpage writer.
.
PK�h%[�4���)man/man3/sasl_server_userdb_checkpass_t.3nu�[���.\" Man page generated from reStructuredText.
.
.TH "SASL_SERVER_USERDB_CHECKPASS_T" "3" "November 08, 2018" "2.1.27" "Cyrus SASL"
.SH NAME
sasl_server_userdb_checkpass_t \- Cyrus SASL documentation
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.SH SYNOPSIS
.sp
.nf
#include <sasl/sasl.h>

int sasl_server_userdb_checkpass_t(sasl_conn_t *conn,
        void *context,
        const char *user,
        const char *pass,
        unsigned passlen,
        struct propctx *propctx)
.fi
.SH DESCRIPTION
.INDENT 0.0
.TP
.B int sasl_server_userdb_checkpass_t(sasl_conn_t *conn,
.TP
.B void *context,
.TP
.B const char *user,
.TP
.B const char *pass,
.TP
.B unsigned passlen,
.TP
.B struct propctx *propctx)
\fBsasl_server_userdb_checkpass_t()\fP is used to verify a plaintext
password against the callback supplier’s user database. This is to
allow additional ways to encode the userPassword property.
.INDENT 7.0
.TP
.B Parameters
.INDENT 7.0
.IP \(bu 2
\fBconn\fP – is the SASL connection context
.IP \(bu 2
\fBcontext\fP – context from the callback record
.IP \(bu 2
\fBuser\fP – NUL terminated user name with \fIuser@realm\fP syntax
.IP \(bu 2
\fBpass\fP – password to check (may not be NUL terminated)
.IP \(bu 2
\fBpasslen\fP – length of the password
.IP \(bu 2
\fBpropctx\fP – property context to fill in with userPassword
.UNINDENT
.UNINDENT
.UNINDENT
.SH RETURN VALUE
.sp
SASL  callback  functions should return SASL return codes.
See sasl.h for a complete list. \fBSASL_OK\fP indicates success.
.sp
Other return codes indicate errors and should be handled.
.SH SEE ALSO
.sp
\fI\%RFC 4422\fP,:saslman:\fIsasl(3)\fP, sasl_callbacks(3)
sasl_errors(3), sasl_server_userdb_setpass_t(3)
.SH AUTHOR
The Cyrus Team
.SH COPYRIGHT
1993-2016, The Cyrus Team
.\" Generated by docutils manpage writer.
.
PK�h%[V�8man/man3/sasl_checkapop.3nu�[���.\" Man page generated from reStructuredText.
.
.TH "SASL_CHECKAPOP" "3" "November 08, 2018" "2.1.27" "Cyrus SASL"
.SH NAME
sasl_checkapop \- Cyrus SASL documentation
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.SH SYNOPSIS
.sp
.nf
#include <sasl/sasl.h>

int sasl_checkapop(sasl_conn_t *conn,
                 const char *challenge,
                 unsigned challen,
                 const char *response,
                 unsigned resplen)
.fi
.SH DESCRIPTION
.INDENT 0.0
.TP
.B int sasl_checkapop(sasl_conn_t *conn,
.TP
.B const char *challenge,
.TP
.B unsigned challen,
.TP
.B const char *response,
.TP
.B unsigned resplen)
\fBsasl_checkapop\fP  will  check  an APOP challenge/response.
APOP is an optional POP3 (\fI\%RFC 1939\fP) authentication command
which  uses  a  shared  secret (password). The password is
stored in the SASL secrets database.  For  information  on
the  SASL  shared secrets database see the System Administrators Guide\&.
.sp
If  called  with  a  NULL challenge, sasl_checkapop() will
check to see if the APOP mechanism is enabled.
.UNINDENT
.SH RETURN VALUE
.sp
sasl_checkapop returns an integer which corresponds to one
of the following codes. \fBSASL_OK\fP indicates that the authentication is complete.  All  other  return  codes  indicate
errors  and should either be handled or the authentication
session should be quit.  See sasl_errors(3)  for  meanings
of return codes.
.SH CONFORMING TO
.sp
\fI\%RFC 4422\fP, \fI\%RFC 1939\fP
.SH SEE ALSO
.sp
sasl(3), sasl_errors(3)
.SH AUTHOR
The Cyrus Team
.SH COPYRIGHT
1993-2016, The Cyrus Team
.\" Generated by docutils manpage writer.
.
PK�h%[�z���man/man3/sasl_log_t.3nu�[���.\" Man page generated from reStructuredText.
.
.TH "SASL_LOG_T" "3" "November 08, 2018" "2.1.27" "Cyrus SASL"
.SH NAME
sasl_log_t \- Cyrus SASL documentation
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.SH SYNOPSIS
.sp
.nf
#include <sasl/sasl.h>

int sasl_log_t(void *context,
              int level,
              const char * message);
.fi
.SH DESCRIPTION
.INDENT 0.0
.TP
.B int sasl_log_t(void *context,
.TP
.B int level,
.TP
.B const char * message);
.INDENT 7.0
.TP
\fBsasl_log_t\fP is used to log warning/error messages from the
SASL library. If not specified \fBsyslog\fP will be used.
.UNINDENT
.UNINDENT
.SH RETURN VALUE
.sp
SASL  callback  functions should return SASL return codes.
See sasl.h for a complete list. \fBSASL_OK\fP indicates success.
.SH SEE ALSO
.sp
\fI\%RFC 4422\fP,:saslman:\fIsasl(3)\fP, sasl_callbacks(3),
sasl_errors(3)
.SH AUTHOR
The Cyrus Team
.SH COPYRIGHT
1993-2016, The Cyrus Team
.\" Generated by docutils manpage writer.
.
PK�h%[�ƞ�A A man/man8/saslauthd.8nu�[���.\" $Id: saslauthd.mdoc,v 1.19 2009/04/11 20:08:48 mel Exp $
.\" Copyright 1997-2001 Messaging Direct Ltd. All rights reserved.
.\"
.\" This manpage uses the BSD mdoc manpage macros. Please don't
.\" downgrade it to -man. The -mdoc macros are included with
.\" GNU roff, and, of course, with the BSD distributions.
.\"
.\" To make life easier for sites that don't support -mdoc,
.\" please generate (and commit!) an updated pre-formatted
.\" manpage in saslauthd.8 whenever you change this source
.\" version. Only the pre-formatted manpage is installed.
.\"
.Dd 12 12 2005
.Dt SASLAUTHD 8
.Os "CMU-SASL"
.Sh NAME
.Nm saslauthd
.Nd sasl authentication server
.Sh SYNOPSIS
.Nm
.Fl a
.Ar authmech
.Op Fl \&Tvdchlr
.Op Fl O Ar option
.Op Fl m Ar mux_path
.Op Fl n Ar threads
.Op Fl s Ar size
.Op Fl t Ar timeout
.Sh DESCRIPTION
.Nm
is a daemon process that handles plaintext authentication requests
on behalf of the SASL library.
.Pp
The server fulfills two roles: it isolates all code requiring superuser
privileges into a single process, and it can be used to provide
.Em proxy
authentication services to clients that do not understand
SASL based authentication.
.Pp
.Nm
should be
started from the system boot scripts when going to
multi-user mode. When running against a protected authentication
database (e.g. the
.Li shadow
mechanism),
it must be run as the superuser. Otherwise it is recommended to run
daemon unprivileged as saslauth:saslauth, requiring the runtime directory
to have root:saslauthd owner. You can do so by following
these steps in machines using
.Xr systemd 1
:

.Bl -enum -compact
.It
create directory
.Pa /etc/systemd/system/saslauthd.service.d/
.It
create file
.Pa /etc/systemd/system/saslauthd.service.d/user.conf
with content
.Bd -literal
[Service]
User=saslauth
Group=saslauth

.Ed
.It
Reload systemd service file: run
.Dq systemctl daemon-reload
.El
.Ss Options
Options named by lower\-case letters configure the server itself.
Upper\-case options control the behavior of specific authentication
mechanisms; their applicability to a particular authentication
mechanism is described in the
.Sx AUTHENTICATION MECHANISMS
section.
.Bl -tag -width indent
.It Fl a Ar authmech
Use
.Ar authmech
as the authentication mechanism. (See the
.Sx AUTHENTICATION MECHANISMS
section below.) This parameter is mandatory.
.It Fl O Ar option
A mechanism specific option (e.g. rimap hostname or config file path)
.It Fl H Ar hostname
The remote host to be contacted by the
.Li rimap
authentication mechanism. (Deprecated, use -O instead)
.It Fl m Ar path
Use
.Ar path
as the pathname to the named socket to listen on for
connection requests. This must be an absolute pathname, and MUST NOT
include the trailing "/mux".  Note that the default for this value
is "/var/state/saslauthd" (or what was specified at compile time)
and that this directory must exist for saslauthd to function.
.It Fl n Ar threads
Use
.Ar threads
processes for responding to authentication queries. (default: 5)  A
value of zero will indicate that saslauthd should fork an individual
process for each connection.  This can solve leaks that occur in some
deployments.
.It Fl s Ar size
Use
.Ar size
as the table size of the hash table (in kilobytes)
.It Fl t Ar timeout
Use
.Ar timeout
as the expiration time of the authentication cache (in seconds)
.It Fl T
Honour time-of-day login restrictions.
.It Fl h
Show usage information
.It Fl c
Enable caching of authentication credentials
.It Fl l
Disable the use of a lock file for controlling access to accept().
.It Fl r
Combine the realm with the login (with an '@' sign in between).  e.g.
login: "foo" realm: "bar" will get passed as login: "foo@bar".  Note
that the realm will still be passed, which may lead to unexpected
behavior for authentication mechanisms that make use of the realm,
however for mechanisms which don't, such as
.Ar getpwent ,
this is the only way to authenticate domain-specific users sharing the
same userid.
.It Fl v
Print the version number and available authentication
mechanisms on standard error, then exit.
.It Fl d
Debugging mode.
.El
.Ss Logging
.Nm
logs its activities via
.Nm syslogd
using the
.Dv LOG_AUTH
facility.
.Sh AUTHENTICATION MECHANISMS
.Nm
supports one or more
.Qq authentication mechanisms ,
dependent upon the facilities provided by the underlying operating system.
The mechanism is selected by the
.Fl a
flag from the following list of choices:
.Bl -tag -width "kerberos4"
.It Li dce
.Em (AIX)
.Pp
Authenticate using the DCE authentication environment.
.It Li getpwent
.Em (All platforms)
.Pp
Authenticate using the
.Fn getpwent
library function. Typically this authenticates against the
local password file. See your system's
.Xr getpwent 3
man page for details.
.It Li kerberos4
.Em (All platforms)
.Pp
Authenticate against the local Kerberos 4 realm. (See the
.Sx NOTES
section for caveats about this driver.)
.It Li kerberos5
.Em (All platforms)
.Pp
Authenticate against the local Kerberos 5 realm.
.It Li pam
.Em (Linux, Solaris)
.Pp
Authenticate using Pluggable Authentication Modules (PAM).
.It Li rimap
.Em (All platforms)
.Pp
Forward authentication requests to a remote IMAP server. This driver
connects to a remote IMAP server, specified using the -O flag,
and attempts to login (via an IMAP
.Ql LOGIN
command) using the credentials 
supplied to the local
server. If the remote authentication succeeds the local connection
is also considered to be authenticated. The remote connection is closed
as soon as the tagged response from the
.Ql LOGIN
command is received from the remote
server.
.Pp
The
.Ar option
parameter to the
.Fl O
flag describes the remote server to forward
authentication requests to.
.Ar hostname
can be a hostname (imap.example.com) or a dotted\-quad IP address
(192.168.0.1). The latter is useful if the remote server is
multi\-homed and has network interfaces that are unreachable from
the local IMAP server. The remote host is contacted on the
.Ql imap
service port. A non\-default port can be specified by appending
a slash and the port name or number
to the
.Ar hostname
argument.
.Pp
The
.Fl O
flag and argument are mandatory when using the
.Li rimap
mechanism.
.It Li shadow
.Em (AIX, Irix, Linux, Solaris)
.Pp
Authenticate against the local
.Qq shadow password file .
The exact mechanism is system dependent.
.Nm
currently understands the
.Fn getspnam
and
.Fn getuserpw
library routines. Some systems
honour the
.Fl T
flag.
.It Li sasldb
.Em (All platforms)
.Pp
Authenticate against the
SASL authentication database.  Note that this is probably not what you
want to use, and is even disabled at compile-time by default.
If you want to use sasldb with the SASL library, you probably want to
use the pwcheck_method of "auxprop" along with the sasldb auxprop plugin
instead.
.It Li ldap
.Em (All platforms that support OpenLDAP 2.0 or higher)
.Pp
Authenticate against an ldap server.  The ldap configuration parameters are
read from /etc/saslauthd.conf.  The location of this file can be
changed with the -O parameter. See the LDAP_SASLAUTHD file included with the
distribution for the list of available parameters.
.It Li sia
.Em (Digital UNIX)
.Pp
Authenticate using the Digital
.Ux
Security Integration Architecture
(a.k.a.
.Qq enhanced security ) .
.El
.Sh NOTES
The
.Li kerberos4
authentication driver consumes considerable resources. To perform an
authentication it must obtain a ticket granting ticket
from the TGT server
.Sy on every authentication request.
The Kerberos library routines that obtain the TGT also create a
local ticket file, on the reasonable assumption that you will want
to save the TGT for use by other Kerberos applications. These ticket
files are unusable by
.Nm No ,
however there is no way not to create them. The overhead of creating
and removing
these ticket files can cause serious performance degradation on busy
servers. (Kerberos
was never intended to be used in this manner, anyway.)
.Sh FILES
.Bl -tag -width "/run/saslauthd/mux"
.It Pa /run/saslauthd/mux
The default communications socket.
.It Pa /etc/saslauthd.conf
The default configuration file for ldap support.
.El
.Sh SEE ALSO
.Xr passwd 1 ,
.Xr getpwent 3 ,
.Xr getspnam 3 ,
.Xr getuserpw 3 ,
.Xr sasl_checkpass 3
.Xr sia_authenticate_user 3 ,
PK�h%[S
�Ƌ�man/man8/testsaslauthd.8nu�[���.\"                                      Hey, EMACS: -*- nroff -*-
.TH TESTSASLAUTHD 8 "14 October 2006"
.SH NAME
testsaslauthd \- test utility for the SASL authentication server
.SH SYNOPSIS
.B testsaslauthd
.RI "[ " \(hyr " " realm " ] [ " \(hys " " servicename " ] [ " \(hyf " " socket " " path " ] [ " \(hyR " " repeatnum " ]"
.SH DESCRIPTION
This manual page documents briefly the
.B testsaslauthd
command.
.PP
.SH SEE ALSO
.BR saslauthd (8).
.br
.SH AUTHOR
testsaslauthd was written by Carnegie Mellon University.
.PP
This manual page was written by Roberto C. Sanchez <roberto@connexer.com>,
for the Debian project (but may be used by others).
PK�h%[�KKppman/man8/saslpasswd2.8nu�[���.\" saslpasswd.8 -- saslpasswd man page
.\" Rob Earhart
.\"

.\" Copyright (c) 2000 Carnegie Mellon University.  All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\"
.\" 1. Redistributions of source code must retain the above copyright
.\"    notice, this list of conditions and the following disclaimer. 
.\"
.\" 2. Redistributions in binary form must reproduce the above copyright
.\"    notice, this list of conditions and the following disclaimer in
.\"    the documentation and/or other materials provided with the
.\"    distribution.
.\"
.\" 3. The name ""Carnegie Mellon University"" must not be used to
.\"    endorse or promote products derived from this software without
.\"    prior written permission. For permission or any other legal
.\"    details, please contact  
.\"      Office of Technology Transfer
.\"      Carnegie Mellon University
.\"      5000 Forbes Avenue
.\"      Pittsburgh, PA  15213-3890
.\"      (412) 268-4387, fax: (412) 268-7395
.\"      tech-transfer@andrew.cmu.edu
.\"
.\" 4. Redistributions of any form whatsoever must retain the following
.\"    acknowledgment:
.\"    ""This product includes software developed by Computing Services
.\"     at Carnegie Mellon University (http://www.cmu.edu/computing/).""
.\"
.\" CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
.\" THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
.\" AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
.\" FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
.\" AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
.\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

.\"
.TH SASLPASSWD2 8 "Mar 7, 2005" "CMU SASL"
.SH NAME
saslpasswd2 \- set a user's sasl password
.SH SYNOPSIS
.B saslpasswd2
.RB [ -p ]
.RB [ -d ]
.RB [ -c ]
.RB [ -n ]
.RB [ -f\ file ]
.RB [ -u\ domain ]
.RB [ -a\ appname ]
.RB [ -v ]
.B userid
.SH DESCRIPTION
.I saslpasswd2
is used by a server administrator to set a user's sasl password for
server programs and SASL mechanisms which use the standard libsasl
database of user secrets.
.SH OPTIONS
.TP
.B -p
Pipe mode \- saslpasswd2 will neither prompt for the password nor
verify that it was entered correctly.  This is the default when
standard input is not a terminal.
.TP
.B -c
Creates an entry for the user if the user doesn't already exist.  This
is mutually exclusive with the
.B -d
(delete user) flag.
.TP
.B -d
Deletes the entry for the user.  This is mutually exclusive with the
.B -c
(create user) flag.
.TP
.B -n
Don't set the plaintext \fIuserPassword\fR property for the user.  Only
mechanism-specific secrets will be set (e.g. OTP, SRP)
.TP
.B -u domain
use
.B domain
for user domain (realm).
.TP
.B -f file
use
.B file
for sasldb
.TP
.B -a appname
use
.B appname
as application name.
.TP
.B -v
Print libsasl2 version number and exit.
.SH SEE ALSO
sasldblistusers2(8)
.TP
rfc4422 \- Simple Authentication and Security Layer (SASL)
PK�h%[ήiWWman/man8/pluginviewer.8nu�[���.\" pluginviewer.8 -- pluginviewer man page
.\" Alexey Melnikov
.\"

.\" Copyright (c) 2006 Carnegie Mellon University.  All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\"
.\" 1. Redistributions of source code must retain the above copyright
.\"    notice, this list of conditions and the following disclaimer. 
.\"
.\" 2. Redistributions in binary form must reproduce the above copyright
.\"    notice, this list of conditions and the following disclaimer in
.\"    the documentation and/or other materials provided with the
.\"    distribution.
.\"
.\" 3. The name ""Carnegie Mellon University"" must not be used to
.\"    endorse or promote products derived from this software without
.\"    prior written permission. For permission or any other legal
.\"    details, please contact  
.\"      Office of Technology Transfer
.\"      Carnegie Mellon University
.\"      5000 Forbes Avenue
.\"      Pittsburgh, PA  15213-3890
.\"      (412) 268-4387, fax: (412) 268-7395
.\"      tech-transfer@andrew.cmu.edu
.\"
.\" 4. Redistributions of any form whatsoever must retain the following
.\"    acknowledgment:
.\"    ""This product includes software developed by Computing Services
.\"     at Carnegie Mellon University (http://www.cmu.edu/computing/).""
.\"
.\" CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
.\" THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
.\" AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
.\" FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
.\" AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
.\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

.\"
.TH PLUGINVIEWER 8 "Apr 10, 2006" "CMU SASL"
.SH NAME
pluginviewer \- list loadable SASL plugins and their properties
.SH SYNOPSIS
.B pluginviewer
.RB [ -a ]
.RB [ -s ]
.RB [ -c ]
.RB [ -b\ min=N,max=N ]
.RB [ -e\ ssf=N,id=ID ]
.RB [ -m\ MECHS ]
.RB [ -x\ AUXPROP_MECH ]
.RB [ -f\ FLAGS ]
.RB [ -p\ PATH ]
.SH DESCRIPTION
.I pluginviewer
can be used by a server administrator to troubleshoot SASL installations.
The utility can list loadable (properly configured) client and server
side plugins, as well as auxprop plugins.
.
.SH OPTIONS
.TP
.B -a
List auxprop plugins.
.TP
.B -s
List server authentication (SASL) plugins.
.TP
.B -c
List client authentication (SASL) plugins.
.TP
.B -b min=N1,max=N2
List client authentication (SASL) plugins.
Strength of the SASL security layer in bits. min=N1 specifies the minumum strength
to use (1 => integrity protection). max=N2 specifies the maximum strength to use.
Only SASL mechanisms which support security layer with strength M such that N1 <= M <= N2
will be shown.
.TP
.B -e ssf=N,id=ID
Assume that an external security layer (e.g. TLS) with N-bit strength is installed.
The ID is the authentication identity used by the external security layer.
.TP
.B -m MECHS
Limit listed SASL plugins to the ones included in the MECHS (space separated) list.
.TP
.B -x AUXPROP_MECHS
Limit listed auxprop plugins to the one listed in the AUXPROP_MECHS (space separated) list.
.TP
.B -f FLAGS
Set security flags. FLAGS is a comma separated list of one or more of the following security flags:
noplain (SASL mechanism doesn\'t send password in the clear during authentication),
noactive (require protection from active attacks), nodict (require mechanisms which are
secure against passive dictionary attacks), forwardsec (require forward secrecy),
passcred (require mechanisms that can delegate client credentials),
maximum (require all security flags).
.TP
.B -p PATH
Specifies a colon-separated search path for plugins.
.SH SEE ALSO
.TP
rfc4422 \- Simple Authentication and Security Layer (SASL)
PK�h%[-�	�	man/man8/sasldblistusers2.8nu�[���.\" sasldblistusers - List users in sasldb file
.\" Tim Martin 3/8/00
.\"

.\" Copyright (c) 2000 Carnegie Mellon University.  All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\"
.\" 1. Redistributions of source code must retain the above copyright
.\"    notice, this list of conditions and the following disclaimer. 
.\"
.\" 2. Redistributions in binary form must reproduce the above copyright
.\"    notice, this list of conditions and the following disclaimer in
.\"    the documentation and/or other materials provided with the
.\"    distribution.
.\"
.\" 3. The name ""Carnegie Mellon University"" must not be used to
.\"    endorse or promote products derived from this software without
.\"    prior written permission. For permission or any other legal
.\"    details, please contact  
.\"      Office of Technology Transfer
.\"      Carnegie Mellon University
.\"      5000 Forbes Avenue
.\"      Pittsburgh, PA  15213-3890
.\"      (412) 268-4387, fax: (412) 268-7395
.\"      tech-transfer@andrew.cmu.edu
.\"
.\" 4. Redistributions of any form whatsoever must retain the following
.\"    acknowledgment:
.\"    ""This product includes software developed by Computing Services
.\"     at Carnegie Mellon University (http://www.cmu.edu/computing/).""
.\"
.\" CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
.\" THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
.\" AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
.\" FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
.\" AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
.\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

.\"
.TH SASLDBLISTUSERS2 8 "March 7, 2005" "CMU SASL"
.SH NAME
sasldblistusers2 \- list users in sasldb
.SH SYNOPSIS
.B sasldblistusers2
.RB [ -f\ file ]
.RB [ -v ]
.SH DESCRIPTION
.I sasldblistusers2
is used to list the users in the SASL password database (usually
/etc/sasldb2). This will NOT list all the users in /etc/passwd, shadow,
PAM, etc. only those created by SASL (via \fIsaslpasswd2\fR).
.SH OPTIONS
.TP
.B -f file
use
.B file
for sasldb
.TP
.B -v
Print libsasl2 version number and exit.
.SH SEE ALSO
saslpasswd2(8)
.TP
rfc4422 \- Simple Authentication and Security Layer (SASL)
PK�h%[�V�]EE#licenses/alt-cyrus-sasl-lib/COPYINGnu�[���/* CMU libsasl
 * Tim Martin
 * Rob Earhart
 * Rob Siemborski
 */
/* 
 * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer. 
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The name "Carnegie Mellon University" must not be used to
 *    endorse or promote products derived from this software without
 *    prior written permission. For permission or any other legal
 *    details, please contact  
 *      Office of Technology Transfer
 *      Carnegie Mellon University
 *      5000 Forbes Avenue
 *      Pittsburgh, PA  15213-3890
 *      (412) 268-4387, fax: (412) 268-7395
 *      tech-transfer@andrew.cmu.edu
 *
 * 4. Redistributions of any form whatsoever must retain the following
 *    acknowledgment:
 *    "This product includes software developed by Computing Services
 *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
 *
 * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */
PK�%[&�����doc/alt-libzip/LICENSEnu�[���PK�%[���s%%�licenses/alt-libdav1d/COPYINGnu�[���PK�%[_�H	bbflicenses/alt-libdav1d/PATENTSnu�[���PK� %[�_Nvnn"doc/alt-pcre/LICENCEnu�[���PK� %[�al���.doc/alt-pcre/READMEnu�[���PK� %[�m^�qq��doc/alt-pcre/NEWSnu�[���PK� %[�*��z�z�Rdoc/alt-pcre/ChangeLognu�[���PK� %[!���__��doc/alt-pcre/COPYINGnu�[���PK� %[ʿ��SS��doc/alt-pcre/AUTHORSnu�[���PK� %[1ⱐ�
�
�man/man1/pcre-config.1nu�[���PK� %[<��z�z��man/man1/pcregrep.1nu�[���PK� %[��0�0��gman/man1/pcretest.1nu�[���PK1N%[	������;)perl5/Expect.pmnu�7��mPK1N%[P��Y�!�!�perl5/Test/Needs.pmnu��6�$PK1N%[`�$�yy�perl5/Test/RequiresInternet.pmnu��6�$PK1N%[��n�t�t��perl5/Test/Alien.pmnu��6�$PK1N%[k��
X	perl5/Test/Alien/Diag.pmnu��6�$PK1N%[�!m�ddzi	perl5/Test/Alien/Run.pmnu��6�$PK1N%[�Ո��%�	perl5/Test/Alien/CanCompile.pmnu��6�$PK1N%[����pp�	perl5/Test/Alien/Synthetic.pmnu��6�$PK1N%[�\-�EEɛ	perl5/Test/Alien/Build.pmnu��6�$PK1N%[���m��!�	perl5/Test/Alien/CanPlatypus.pmnu��6�$PK1N%[o1D����	perl5/Scope/Guard.pmnu��6�$PK1N%[�߻lYHYH
"�	perl5/CPAN.pmnu��6�$PK1N%[���/�T�T�@perl5/LWP.pmnu��6�$PK1N%[av“+�+��perl5/WWW/RobotRules.pmnu��6�$PK1N%[�<��!!#g�perl5/WWW/RobotRules/AnyDBM_File.pmnu��6�$PK1N%[���\����perl5/AppConfig/Args.pmnu��6�$PK1N%[���L�perl5/AppConfig/CGI.pmnu��6�$PK1N%[�k��))g	
perl5/AppConfig/Sys.pmnu��6�$PK1N%[��f����(
perl5/AppConfig/State.pmnu��6�$PK1N%[f�OM^^*�
perl5/AppConfig/File.pmnu��6�$PK1N%[���3 3 @perl5/AppConfig/Getopt.pmnu��6�$PK1N%[��E�1$1$�`perl5/lwpcook.podnu��6�$PK1N%[�^�`R	R	m�perl5/Path/Class/Entity.pmnu��6�$PK1N%[K�+�k9k9	�perl5/Path/Class/File.pmnu��6�$PK1N%[f����a�a��perl5/Path/Class/Dir.pmnu��6�$PK1N%[6�����*perl5/Path/Tiny.pmnu��6�$PK1N%[!�<���(perl5/Path/Class.pmnu��6�$PK1N%[(�*�A�A�>perl5/alienfile.pmnu��6�$PK1N%[���vava�perl5/lwptut.podnu��6�$PK1N%[-�**��perl5/Canary/Stability.pmnu��6�$PK1N%[���O�O�B�perl5/local/lib.pmnu��6�$PK1N%[UD��NӠperl5/x86_64-linux-thread-multi/.meta/LWP-UserAgent-DNS-Hosts-0.14/MYMETA.jsonnu��6�$PK1N%[�
�ٴ�Oc�perl5/x86_64-linux-thread-multi/.meta/LWP-UserAgent-DNS-Hosts-0.14/install.jsonnu��6�$PK1N%[P��U??C��perl5/x86_64-linux-thread-multi/.meta/common-sense-3.75/MYMETA.jsonnu��6�$PK1N%[�*��DH�perl5/x86_64-linux-thread-multi/.meta/common-sense-3.75/install.jsonnu��6�$PK1N%[Q^����@��perl5/x86_64-linux-thread-multi/.meta/YAML-Syck-1.34/MYMETA.jsonnu��6�$PK1N%[ˊo�mmA�perl5/x86_64-linux-thread-multi/.meta/YAML-Syck-1.34/install.jsonnu��6�$PK1N%[I~�UoUoC��perl5/x86_64-linux-thread-multi/.meta/HTTP-Cookies-6.11/MYMETA.jsonnu��6�$PK1N%[�B҇}}D�+perl5/x86_64-linux-thread-multi/.meta/HTTP-Cookies-6.11/install.jsonnu��6�$PK2N%[����==Cz-perl5/x86_64-linux-thread-multi/.meta/Capture-Tiny-0.50/MYMETA.jsonnu��6�$PK2N%[�;/���D*<perl5/x86_64-linux-thread-multi/.meta/Capture-Tiny-0.50/install.jsonnu��6�$PK2N%[��"K|=perl5/x86_64-linux-thread-multi/.meta/XML-NamespaceSupport-1.12/MYMETA.jsonnu��6�$PK2N%[���LOperl5/x86_64-linux-thread-multi/.meta/XML-NamespaceSupport-1.12/install.jsonnu��6�$PK2N%[aE�|ppE�Pperl5/x86_64-linux-thread-multi/.meta/HTTP-Negotiate-6.01/MYMETA.jsonnu��6�$PK2N%[��ϧ��F}Uperl5/x86_64-linux-thread-multi/.meta/HTTP-Negotiate-6.01/install.jsonnu��6�$PK2N%[Y�lm��B�Vperl5/x86_64-linux-thread-multi/.meta/libwww-perl-6.78/MYMETA.jsonnu��6�$PK2N%[hhā��CJ�perl5/x86_64-linux-thread-multi/.meta/libwww-perl-6.78/install.jsonnu��6�$PK2N%[R�<��@��perl5/x86_64-linux-thread-multi/.meta/version-0.9933/MYMETA.jsonnu��6�$PK2N%[5:��||A��perl5/x86_64-linux-thread-multi/.meta/version-0.9933/install.jsonnu��6�$PK2N%[{�9����?��perl5/x86_64-linux-thread-multi/.meta/Try-Tiny-0.32/MYMETA.jsonnu��6�$PK2N%[�f^Z��@H�perl5/x86_64-linux-thread-multi/.meta/Try-Tiny-0.32/install.jsonnu��6�$PK2N%[�OS�w�w@{�perl5/x86_64-linux-thread-multi/.meta/HTTP-Date-6.06/MYMETA.jsonnu��6�$PK2N%[��PK��A�#perl5/x86_64-linux-thread-multi/.meta/HTTP-Date-6.06/install.jsonnu��6�$PK2N%[����=�$perl5/x86_64-linux-thread-multi/.meta/Encode-3.21/MYMETA.jsonnu��6�$PK2N%[A�=�SS>V8perl5/x86_64-linux-thread-multi/.meta/Encode-3.21/install.jsonnu��6�$PK2N%[��;k�]�]E@perl5/x86_64-linux-thread-multi/.meta/LWP-MediaTypes-6.04/MYMETA.jsonnu��6�$PK2N%[��3B��Fo�perl5/x86_64-linux-thread-multi/.meta/LWP-MediaTypes-6.04/install.jsonnu��6�$PK2N%[�{���CΟperl5/x86_64-linux-thread-multi/.meta/File-Listing-6.16/MYMETA.jsonnu��6�$PK2N%[ҾIg44D�perl5/x86_64-linux-thread-multi/.meta/File-Listing-6.16/install.jsonnu��6�$PK2N%[�����D��perl5/x86_64-linux-thread-multi/.meta/Alien-Libxml2-0.20/MYMETA.jsonnu��6�$PK2N%[����E��perl5/x86_64-linux-thread-multi/.meta/Alien-Libxml2-0.20/install.jsonnu��6�$PK2N%[���L�LB+�perl5/x86_64-linux-thread-multi/.meta/IO-Stringy-2.113/MYMETA.jsonnu��6�$PK2N%[�>�K��C].perl5/x86_64-linux-thread-multi/.meta/IO-Stringy-2.113/install.jsonnu��6�$PK2N%[p�]`Z*Z*?W1perl5/x86_64-linux-thread-multi/.meta/IO-HTML-1.004/MYMETA.jsonnu��6�$PK2N%[�^,��@ \perl5/x86_64-linux-thread-multi/.meta/IO-HTML-1.004/install.jsonnu��6�$PK2N%[�bxg"g"BK]perl5/x86_64-linux-thread-multi/.meta/Alien-Build-2.84/MYMETA.jsonnu��6�$PK2N%[)�ٺ��C$�perl5/x86_64-linux-thread-multi/.meta/Alien-Build-2.84/install.jsonnu��6�$PK2N%[���8��Cx�perl5/x86_64-linux-thread-multi/.meta/File-chdir-0.1011/MYMETA.jsonnu��6�$PK2N%[���eeD��perl5/x86_64-linux-thread-multi/.meta/File-chdir-0.1011/install.jsonnu��6�$PK2N%[�Q�EGZ�perl5/x86_64-linux-thread-multi/.meta/Canary-Stability-2013/MYMETA.jsonnu��6�$PK2N%[.A����H�perl5/x86_64-linux-thread-multi/.meta/Canary-Stability-2013/install.jsonnu��6�$PK2N%[e�����BM�perl5/x86_64-linux-thread-multi/.meta/Scope-Guard-0.21/MYMETA.jsonnu��6�$PK2N%[��\\��C��perl5/x86_64-linux-thread-multi/.meta/Scope-Guard-0.21/install.jsonnu��6�$PK2N%[V�Y�perl5/x86_64-linux-thread-multi/.meta/Alien-Build-Plugin-Download-GitLab-0.01/MYMETA.jsonnu��6�$PK2N%[�؀�ggZ��perl5/x86_64-linux-thread-multi/.meta/Alien-Build-Plugin-Download-GitLab-0.01/install.jsonnu��6�$PK2N%[h�d�DDF��perl5/x86_64-linux-thread-multi/.meta/CPAN-Meta-YAML-0.020/MYMETA.jsonnu��6�$PK2N%[|h�-��G��perl5/x86_64-linux-thread-multi/.meta/CPAN-Meta-YAML-0.020/install.jsonnu��6�$PK2N%[|��Wxx>�perl5/x86_64-linux-thread-multi/.meta/XML-SAX-1.02/MYMETA.jsonnu��6�$PK2N%[�q��?��perl5/x86_64-linux-thread-multi/.meta/XML-SAX-1.02/install.jsonnu��6�$PK2N%[��c/A"�perl5/x86_64-linux-thread-multi/.meta/XML-Parser-2.47/MYMETA.jsonnu��6�$PK2N%[�L|�44B��perl5/x86_64-linux-thread-multi/.meta/XML-Parser-2.47/install.jsonnu��6�$PK2N%[]��<V�perl5/x86_64-linux-thread-multi/.meta/Clone-0.47/MYMETA.jsonnu��6�$PK2N%[�:���=�perl5/x86_64-linux-thread-multi/.meta/Clone-0.47/install.jsonnu��6�$PK2N%[i�47�y�yC�perl5/x86_64-linux-thread-multi/.meta/HTTP-Message-7.00/MYMETA.jsonnu��6�$PK2N%[�}�KKD�~perl5/x86_64-linux-thread-multi/.meta/HTTP-Message-7.00/install.jsonnu��6�$PK2N%[�d��D��perl5/x86_64-linux-thread-multi/.meta/XML-SAX-Expat-0.51/MYMETA.jsonnu��6�$PK2N%[����EŇperl5/x86_64-linux-thread-multi/.meta/XML-SAX-Expat-0.51/install.jsonnu��6�$PK2N%[��T@��H�perl5/x86_64-linux-thread-multi/.meta/Template-Toolkit-3.102/MYMETA.jsonnu��6�$PK2N%[�
�UUIT�perl5/x86_64-linux-thread-multi/.meta/Template-Toolkit-3.102/install.jsonnu��6�$PK2N%[�"͟�C"�perl5/x86_64-linux-thread-multi/.meta/FFI-CheckLib-0.31/MYMETA.jsonnu��6�$PK2N%[pM6���D4�perl5/x86_64-linux-thread-multi/.meta/FFI-CheckLib-0.31/install.jsonnu��6�$PK2N%[�9�{?��perl5/x86_64-linux-thread-multi/.meta/TimeDate-2.33/MYMETA.jsonnu��6�$PK2N%[J�i@

@�perl5/x86_64-linux-thread-multi/.meta/TimeDate-2.33/install.jsonnu��6�$PK2N%[��BЧ	�	;g�perl5/x86_64-linux-thread-multi/.meta/CPAN-2.38/MYMETA.jsonnu��6�$PK2N%[�0��
�
<y�perl5/x86_64-linux-thread-multi/.meta/CPAN-2.38/install.jsonnu��6�$PK2N%[��H��A��perl5/x86_64-linux-thread-multi/.meta/HTTP-Tiny-0.090/MYMETA.jsonnu��6�$PK2N%[)f��B:�perl5/x86_64-linux-thread-multi/.meta/HTTP-Tiny-0.090/install.jsonnu��6�$PK2N%[|�	��>yperl5/x86_64-linux-thread-multi/.meta/JSON-XS-4.03/MYMETA.jsonnu��6�$PK2N%[�:����?�perl5/x86_64-linux-thread-multi/.meta/JSON-XS-4.03/install.jsonnu��6�$PK2N%[<����E�perl5/x86_64-linux-thread-multi/.meta/WWW-RobotRules-6.02/MYMETA.jsonnu��6�$PK2N%[�Ӕ��F#perl5/x86_64-linux-thread-multi/.meta/WWW-RobotRules-6.02/install.jsonnu��6�$PK3N%[|{�	�	C"
perl5/x86_64-linux-thread-multi/.meta/XML-LibXML-2.0210/MYMETA.jsonnu��6�$PK3N%[��aX�
�
DIperl5/x86_64-linux-thread-multi/.meta/XML-LibXML-2.0210/install.jsonnu��6�$PK3N%[VJ��Dj"perl5/x86_64-linux-thread-multi/.meta/local-lib-2.000029/MYMETA.jsonnu��6�$PK3N%[�CE�)perl5/x86_64-linux-thread-multi/.meta/local-lib-2.000029/install.jsonnu��6�$PK3N%[ǽ��AA=Q+perl5/x86_64-linux-thread-multi/.meta/IO-Tty-1.20/MYMETA.jsonnu��6�$PK3N%[I/�>�/perl5/x86_64-linux-thread-multi/.meta/IO-Tty-1.20/install.jsonnu��6�$PK3N%[򃫴��B�1perl5/x86_64-linux-thread-multi/.meta/HTML-Tagset-3.24/MYMETA.jsonnu��6�$PK3N%[LM��C7perl5/x86_64-linux-thread-multi/.meta/HTML-Tagset-3.24/install.jsonnu��6�$PK3N%[�5�A��B�8perl5/x86_64-linux-thread-multi/.meta/HTML-Parser-3.83/MYMETA.jsonnu��6�$PK3N%[�)�Հ�C�Lperl5/x86_64-linux-thread-multi/.meta/HTML-Parser-3.83/install.jsonnu��6�$PK3N%[�!�66=�Operl5/x86_64-linux-thread-multi/.meta/Expect-1.38/MYMETA.jsonnu��6�$PK3N%[4}(g��>UVperl5/x86_64-linux-thread-multi/.meta/Expect-1.38/install.jsonnu��6�$PK3N%[ِ֚^^@tWperl5/x86_64-linux-thread-multi/.meta/AppConfig-1.71/MYMETA.jsonnu��6�$PK3N%[��U�QQAB]perl5/x86_64-linux-thread-multi/.meta/AppConfig-1.71/install.jsonnu��6�$PK3N%[��h��A`perl5/x86_64-linux-thread-multi/.meta/XML-Simple-2.25/MYMETA.jsonnu��6�$PK3N%[eW����B�eperl5/x86_64-linux-thread-multi/.meta/XML-Simple-2.25/install.jsonnu��6�$PK3N%[&�9~~N7gperl5/x86_64-linux-thread-multi/.meta/CPAN-Meta-Requirements-2.143/MYMETA.jsonnu��6�$PK3N%[.���O3�perl5/x86_64-linux-thread-multi/.meta/CPAN-Meta-Requirements-2.143/install.jsonnu��6�$PK3N%[�V����G2�perl5/x86_64-linux-thread-multi/.meta/Types-Serialiser-1.01/MYMETA.jsonnu��6�$PK3N%[�R���HP�perl5/x86_64-linux-thread-multi/.meta/Types-Serialiser-1.01/install.jsonnu��6�$PK3N%[f�/qq?x�perl5/x86_64-linux-thread-multi/.meta/Net-HTTP-6.23/MYMETA.jsonnu��6�$PK3N%[���}}@��perl5/x86_64-linux-thread-multi/.meta/Net-HTTP-6.23/install.jsonnu��6�$PK3N%[���GC�perl5/x86_64-linux-thread-multi/.meta/XML-SAX-Base-1.09/MYMETA.jsonnu��6�$PK3N%[����nnD`perl5/x86_64-linux-thread-multi/.meta/XML-SAX-Base-1.09/install.jsonnu��6�$PK3N%[�Zw�bbABperl5/x86_64-linux-thread-multi/.meta/Path-Tiny-0.148/MYMETA.jsonnu��6�$PK4N%[q;gBperl5/x86_64-linux-thread-multi/.meta/Path-Tiny-0.148/install.jsonnu��6�$PK4N%[�?c��t�t�perl5/Capture/Tiny.pmnu��6�$PK4N%[?��#�#��perl5/Types/Serialiser.pmnu��6�$PK4N%[�Wy�����perl5/Types/Serialiser/Error.pmnu��6�$PK4N%[H�����perl5/Date/Language/Sidama.pmnu��6�$PK4N%[ϣ��ܼperl5/Date/Language/German.pmnu��6�$PK4N%[��C�

 9�perl5/Date/Language/Icelandic.pmnu��6�$PK4N%[|p�0����perl5/Date/Language/Tigrinya.pmnu��6�$PK4N%[U�!�>>�perl5/Date/Language/Dutch.pmnu��6�$PK4N%[�t�qhh	�perl5/Date/Language/Russian.pmnu��6�$PK4N%[������perl5/Date/Language/English.pmnu��6�$PK4N%[p½\����perl5/Date/Language/French.pmnu��6�$PK4N%[d���#�perl5/Date/Language/Czech.pmnu��6�$PK4N%[f0���� ��perl5/Date/Language/Norwegian.pmnu��6�$PK4N%[�73��!.�perl5/Date/Language/Chinese_GB.pmnu��6�$PK4N%[7��m���perl5/Date/Language/Spanish.pmnu��6�$PK4N%[����

 ��perl5/Date/Language/Bulgarian.pmnu��6�$PK4N%[�_bT�perl5/Date/Language/Turkish.pmnu�7��mPK4N%[��"h%�perl5/Date/Language/Russian_cp1251.pmnu�7��mPK4N%[(!p

"perl5/Date/Language/Greek.pmnu��6�$PK4N%[i[Wj��xperl5/Date/Language/Somali.pmnu��6�$PK4N%[҅���Hperl5/Date/Language/Austrian.pmnu��6�$PK4N%[ �9||yperl5/Date/Language/Romanian.pmnu��6�$PK4N%[����Dperl5/Date/Language/Chinese.pmnu��6�$PK4N%[���J��c#perl5/Date/Language/Amharic.pmnu��6�$PK4N%[4E&S�� 8+perl5/Date/Language/Brazilian.pmnu��6�$PK4N%[kEY4((N/perl5/Date/Language/Gedeo.pmnu��6�$PK4N%[��D`���3perl5/Date/Language/Finnish.pmnu��6�$PK4N%[?�Obb�8perl5/Date/Language/Swedish.pmnu��6�$PK4N%[<6�pp'�=perl5/Date/Language/TigrinyaEritrean.pmnu��6�$PK4N%[�po��(^Eperl5/Date/Language/TigrinyaEthiopian.pmnu��6�$PK4N%[���@Mperl5/Date/Language/Danish.pmnu��6�$PK4N%[{K�

$�Qperl5/Date/Language/Russian_koi8r.pmnu�7��mPK4N%[N�zz�Uperl5/Date/Language/Afar.pmnu��6�$PK4N%[�1UUU IZperl5/Date/Language/Hungarian.pmnu��6�$PK4N%[���<���bperl5/Date/Language/Italian.pmnu��6�$PK4N%[Ŵ�-��*gperl5/Date/Language/Oromo.pmnu��6�$PK4N%['`=���]kperl5/Date/Language/Occitan.pmnu��6�$PK4N%[�Y���%�%ooperl5/Date/Format.pmnu��6�$PK4N%[U�N��#�#c�perl5/Date/Parse.pmnu��6�$PK4N%[�� Wl
l
K�perl5/Date/Language.pmnu��6�$PK4N%[�Q�������perl5/App/Cpan.pmnu��6�$PK4N%[CP��>�>�bperl5/POD2/PT_BR/local/lib.podnu��6�$PK4N%[��(	�@�@�perl5/POD2/DE/local/lib.podnu��6�$PK4N%[q���"�perl5/cPanelUserConfig.pmnu�[���PK4N%[vy�!�1�1��perl5/HTML/Tagset.pmnu��6�$PK5N%[�H�[k?k?�perl5/HTTP/Request/Common.pmnu��6�$PK5N%[�8o��>�>uWperl5/HTTP/Negotiate.pmnu��6�$PK5N%[|�f�%.%.��perl5/HTTP/Config.pmnu��6�$PK5N%[�68��"�"	�perl5/HTTP/Request.pmnu��6�$PK5N%[d�zE>E>6�perl5/HTTP/Tiny.pmnu��6�$PK5N%[���w�w��&perl5/HTTP/Message.pmnu��6�$PK5N%[mO��CCy�perl5/HTTP/Response.pmnu��6�$PK5N%[����#�#��perl5/HTTP/Cookies/Microsoft.pmnu��6�$PK5N%[rL�HK
K
�perl5/HTTP/Cookies/Netscape.pmnu��6�$PK5N%[c`�L�^�^;!perl5/HTTP/Cookies.pmnu��6�$PK5N%[�|H��a�aL�perl5/HTTP/Headers.pmnu��6�$PK5N%[�e��M7M7�perl5/HTTP/Status.pmnu��6�$PK5N%[�i�.	.	� perl5/HTTP/Headers/Auth.pmnu��6�$PK5N%[��I��	�	# perl5/HTTP/Headers/ETag.pmnu��6�$PK5N%[�iq���^- perl5/HTTP/Headers/Util.pmnu��6�$PK5N%[t8��.�.�A perl5/HTTP/Date.pmnu��6�$PK5N%[����~�~�p perl5/AppConfig.pmnu��6�$PK5N%[Y�8��R�R�� perl5/Try/Tiny.pmnu��6�$PK5N%[D�O��	�	B!perl5/Net/HTTP/NB.pmnu��6�$PK5N%[@��iVDVD�L!perl5/Net/HTTP/Methods.pmnu��6�$PK5N%[����
�
6�!perl5/Net/HTTPS.pmnu��6�$PK5N%[K��((A�!perl5/Net/HTTP.pmnu��6�$PK5N%[����RRRR��!perl5/FFI/CheckLib.pmnu��6�$PK5N%[4;{g��*"perl5/lib/core/only.pmnu��6�$PK5N%[�
'"perl5/TimeDate.pmnu��6�$PK5N%[m���Y("perl5/LWP/MediaTypes.pmnu��6�$PK5N%[)l5�����C"perl5/LWP/media.typesnu��6�$PK5N%[}Q�bb{#perl5/LWP/Debug.pmnu��6�$PK6N%[����#perl5/LWP/RobotUA.pmnu��6�$PK6N%[��^YY61#perl5/LWP/Debug/TraceHTTP.pmnu��6�$PK6N%[R��3#perl5/LWP/Authen/Ntlm.pmnu��6�$PK6N%[Zэ<
<
9I#perl5/LWP/Authen/Basic.pmnu��6�$PK6N%[�s �S#perl5/LWP/Authen/Digest.pmnu��6�$PK6N%[��}/"/"�\#perl5/LWP/ConnCache.pmnu��6�$PK6N%[��3v�(�(�~#perl5/LWP/UserAgent.pmnu��6�$PK6N%[�� mm�$perl5/LWP/MemberMixin.pmnu��6�$PK6N%[��v%v%��$perl5/LWP/Protocol.pmnu��6�$PK6N%[����� Y�$perl5/LWP/Protocol/http/hosts.pmnu��6�$PK6N%[O+�O88��$perl5/LWP/Protocol/mailto.pmnu��6�$PK6N%[��w�bb�$perl5/LWP/Protocol/gopher.pmnu��6�$PK6N%[�N�dd�$perl5/LWP/Protocol/nogo.pmnu��6�$PK6N%[ɐS�LLp�$perl5/LWP/Protocol/loopback.pmnu��6�$PK6N%[-'G�
%perl5/LWP/Protocol/file.pmnu��6�$PK6N%[��Q�ffY%perl5/LWP/Protocol/nntp.pmnu��6�$PK6N%[Z����	!%perl5/LWP/Protocol/data.pmnu��6�$PK6N%[���SS&&%perl5/LWP/Protocol/cpan.pmnu��6�$PK6N%[��6��J�J�+%perl5/LWP/Protocol/ftp.pmnu��6�$PK6N%[�e�����v%perl5/LWP/Protocol/https.pmnu��6�$PK6N%[:,}}!Č%perl5/LWP/Protocol/https/hosts.pmnu��6�$PK6N%[��:�:��%perl5/LWP/Protocol/http.pmnu��6�$PK6N%[`m@�� ��%perl5/LWP/UserAgent/DNS/Hosts.pmnu��6�$PK6N%[!��CC��%perl5/LWP/DebugFile.pmnu��6�$PK6N%[m���$�%perl5/LWP/Simple.pmnu��6�$PK6N%[��45$5$}�%perl5/XML/SAX.pmnu��6�$PK6N%[ʛ��Q�Q�&perl5/XML/Simple/FAQ.podnu��6�$PK6N%[W||�o&perl5/XML/SAX/ParserDetails.ininu�[���PK6N%[����L�L�q&perl5/XML/SAX/Expat.pmnu�7��mPK6N%[�IWOkPkP��&perl5/XML/SAX/PurePerl.pmnu��6�$PK6N%[a�3tt&t'perl5/XML/SAX/PurePerl/NoUnicodeExt.pmnu��6�$PK6N%[	G��KK->'perl5/XML/SAX/PurePerl/Reader/NoUnicodeExt.pmnu��6�$PK6N%[Lk��FF+�'perl5/XML/SAX/PurePerl/Reader/UnicodeExt.pmnu��6�$PK6N%[`�$���$�'perl5/XML/SAX/PurePerl/Reader/URI.pmnu��6�$PK6N%['8��'�'perl5/XML/SAX/PurePerl/Reader/String.pmnu��6�$PK6N%[��'�		'�#'perl5/XML/SAX/PurePerl/Reader/Stream.pmnu��6�$PK6N%[�5+�22!�*'perl5/XML/SAX/PurePerl/DocType.pmnu��6�$PK6N%[�z]Xqq$f='perl5/XML/SAX/PurePerl/UnicodeExt.pmnu��6�$PK7N%[�6:o`B`B"+?'perl5/XML/SAX/PurePerl/DTDDecls.pmnu��6�$PK7N%[� ���	�	 ݁'perl5/XML/SAX/PurePerl/Reader.pmnu��6�$PK7N%[�.��D
D
(�'perl5/XML/SAX/PurePerl/EncodingDetect.pmnu��6�$PK7N%[�&��#��'perl5/XML/SAX/PurePerl/Exception.pmnu��6�$PK7N%[�N��=
=
!��'perl5/XML/SAX/PurePerl/XMLDecl.pmnu��6�$PK7N%[���k��%B�'perl5/XML/SAX/PurePerl/Productions.pmnu��6�$PK7N%[��*�WW&v�'perl5/XML/SAX/PurePerl/DebugHandler.pmnu��6�$PK7N%[h=�
��#�'perl5/XML/SAX/ParserFactory.pmnu��6�$PK7N%[�9ms����'perl5/XML/SAX/Exception.pmnu��6�$PK7N%[u��=�9�9�'perl5/XML/SAX/Intro.podnu��6�$PK7N%[Q��BB C-(perl5/XML/SAX/DocumentLocator.pmnu��6�$PK7N%[G������8(perl5/XML/SAX/Base.pmnu��6�$PK7N%[�~@pp/*perl5/XML/SAX/BuildSAXBase.plnu��6�$PK7N%[F��|�M�M��*perl5/XML/NamespaceSupport.pmnu��6�$PK7N%[�q�i����*perl5/XML/Simple.pmnu��6�$PK7N%[�]�/77c,perl5/File/Listing.pmnu��6�$PK7N%[dE
�*�*w�,perl5/File/chdir.pmnu��6�$PK7N%[�Y3�AA��,perl5/CPAN/Tarzip.pmnu��6�$PK7N%[B��3���-perl5/CPAN/Queue.pmnu��6�$PK7N%[�!+���#-perl5/CPAN/Shell.pmnu��6�$PK7N%[naX677&C.perl5/CPAN/Prompt.pmnu��6�$PK7N%[iۨD���E.perl5/CPAN/Distrostatus.pmnu��6�$PK7N%[}l�++�I.perl5/CPAN/API/HOWTO.podnu��6�$PK7N%[hz.η���*N.perl5/CPAN/FTP.pmnu��6�$PK7N%[�U�V�V"/perl5/CPAN/Index.pmnu��6�$PK7N%[�7=$$Ah/perl5/CPAN/FirstTime.pmnu��6�$PK7N%[�2]����0perl5/CPAN/Nox.pmnu��6�$PK7N%[��L������0perl5/CPAN/Distribution.pmnu��6�$PK7N%[C������\3perl5/CPAN/Plugin.pmnu��6�$PK7N%[z���66�i3perl5/CPAN/Debug.pmnu��6�$PK7N%[���((r3perl5/CPAN/HTTP/Client.pmnu��6�$PK7N%[3�y�I
I
}�3perl5/CPAN/HTTP/Credentials.pmnu��6�$PK7N%[ך�9LL�3perl5/CPAN/URL.pmnu��6�$PK7N%[4A��'�'��3perl5/CPAN/Bundle.pmnu��6�$PK7N%[�<����!��3perl5/CPAN/Kwalify/distroprefs.ddnu��6�$PK7N%[w)#99"q�3perl5/CPAN/Kwalify/distroprefs.ymlnu��6�$PK7N%[ٷ��^�^��3perl5/CPAN/HandleConfig.pmnu��6�$PK7N%[�$�d
d
�84perl5/CPAN/Kwalify.pmnu��6�$PK7N%[�����F4perl5/CPAN/InfoObj.pmnu��6�$PK7N%[>+����a4perl5/CPAN/LWP/UserAgent.pmnu��6�$PK7N%[*�^��'
j4perl5/CPAN/Exception/blocked_urllist.pmnu��6�$PK7N%[T����*�m4perl5/CPAN/Exception/yaml_not_installed.pmnu��6�$PK7N%[�ܑH��*=p4perl5/CPAN/Exception/yaml_process_error.pmnu��6�$PK7N%[���1..+>w4perl5/CPAN/Exception/RecursiveDependency.pmnu��6�$PK7N%[��Boodž4perl5/CPAN/Admin.pmnu��6�$PK7N%[7�S��y�4perl5/CPAN/Author.pmnu��6�$PK7N%[��Hw�4perl5/CPAN/FTP/netrc.pmnu��6�$PK7N%[��o����4perl5/CPAN/CacheMgr.pmnu��6�$PK7N%[���bJGJG�4perl5/CPAN/Mirrors.pmnu��6�$PK7N%[���CvWvW�,5perl5/CPAN/Module.pmnu��6�$PK7N%[n3�y..W�5perl5/CPAN/Version.pmnu��6�$PK7N%[< $l:M:M%ʕ5perl5/CPAN/Meta/Requirements/Range.pmnu��6�$PK7N%[�somFUFUY�5perl5/CPAN/Meta/Requirements.pmnu��6�$PK7N%[�:nn�i�i�86perl5/CPAN/Meta/YAML.pmnu��6�$PK7N%[z¤��!�!ߢ6perl5/CPAN/Plugin/Specfile.pmnu��6�$PK7N%[��:���6perl5/CPAN/Complete.pmnu��6�$PK7N%[��䍽���6perl5/CPAN/DeferredCode.pmnu��6�$PK7N%[M :�.�.��6perl5/CPAN/Distroprefs.pmnu��6�$PK7N%[�eE��"
7perl5/Alien/Build/Version/Basic.pmnu��6�$PK7N%[3�[c�#�#)U 7perl5/Alien/Build/Manual/Contributing.podnu��6�$PK7N%[��5WW"�D7perl5/Alien/Build/Manual/Alien.podnu��6�$PK7N%[=!�.�T�T)<P7perl5/Alien/Build/Manual/PluginAuthor.podnu��6�$PK7N%[1yjbjb(v�7perl5/Alien/Build/Manual/AlienAuthor.podnu��6�$PK7N%[����&88perl5/Alien/Build/Manual/AlienUser.podnu��6�$PK7N%[AMW�R�R #8perl5/Alien/Build/Manual/FAQ.podnu��6�$PK7N%[�6���"�"%Zv8perl5/Alien/Build/Manual/Security.podnu��6�$PK7N%[9��ROO��8perl5/Alien/Build/rc.pmnu��6�$PK7N%[)RM߂ � (�8perl5/Alien/Build/Interpolate/Default.pmnu��6�$PK7N%[���

 ��8perl5/Alien/Build/Log/Default.pmnu��6�$PK7N%[�>��<
<
#O�8perl5/Alien/Build/Log/Abbreviate.pmnu��6�$PK7N%[@�?����8perl5/Alien/Build/Plugin.pmnu��6�$PK7N%[�ݪ5�� ��8perl5/Alien/Build/Interpolate.pmnu��6�$PK7N%[�����$�9perl5/Alien/Build/CommandSequence.pmnu��6�$PK7N%[��2l�;�;� 9perl5/Alien/Build/MM.pmnu��6�$PK7N%[��x�pp�\9perl5/Alien/Build/Temp.pmnu��6�$PK7N%[3V��	�	"[h9perl5/Alien/Build/Plugin/Build.podnu��6�$PK7N%[��r9-9-%ar9perl5/Alien/Build/Plugin/Test/Mock.pmnu��6�$PK7N%[�[�		$�9perl5/Alien/Build/Plugin/Extract.podnu��6�$PK7N%[�QM:��#`�9perl5/Alien/Build/Plugin/Gather.podnu��6�$PK7N%[�*�)��&|�9perl5/Alien/Build/Plugin/PkgConfig.podnu��6�$PK7N%[M��(__-��9perl5/Alien/Build/Plugin/Extract/Negotiate.pmnu��6�$PK7N%[�u�xx.W�9perl5/Alien/Build/Plugin/Extract/ArchiveZip.pmnu��6�$PK7N%[�4��
�
--�9perl5/Alien/Build/Plugin/Extract/Directory.pmnu��6�$PK7N%[�.�i��(�9perl5/Alien/Build/Plugin/Extract/File.pmnu��6�$PK7N%[�Y

.��9perl5/Alien/Build/Plugin/Extract/ArchiveTar.pmnu��6�$PK7N%[ø.�Y5Y5/g:perl5/Alien/Build/Plugin/Extract/CommandLine.pmnu��6�$PK7N%[������'<:perl5/Alien/Build/Plugin/Build/CMake.pmnu��6�$PK7N%[��{&��&SS:perl5/Alien/Build/Plugin/Build/Make.pmnu��6�$PK7N%[1uNnn+Dd:perl5/Alien/Build/Plugin/Build/SearchDep.pmnu��6�$PK7N%[���%�%*
z:perl5/Alien/Build/Plugin/Build/Autoconf.pmnu��6�$PK7N%['��d��&�:perl5/Alien/Build/Plugin/Build/MSYS.pmnu��6�$PK7N%[y�ݮOO&7�:perl5/Alien/Build/Plugin/Build/Copy.pmnu��6�$PK7N%[00����!ܾ:perl5/Alien/Build/Plugin/Test.podnu��6�$PK7N%[{����$�$.��:perl5/Alien/Build/Plugin/Download/Negotiate.pmnu��6�$PK7N%[�V}KK+��:perl5/Alien/Build/Plugin/Download/GitLab.pmnu��6�$PK7N%[.���RR%s;perl5/Alien/Build/Plugin/Download.podnu��6�$PK7N%[�15��#	;perl5/Alien/Build/Plugin/Prefer.podnu��6�$PK7N%[V5�	�	#V;perl5/Alien/Build/Plugin/Decode.podnu��6�$PK7N%[�X�"SS/�;perl5/Alien/Build/Plugin/PkgConfig/Negotiate.pmnu��6�$PK8N%[�x¹cc(T1;perl5/Alien/Build/Plugin/PkgConfig/PP.pmnu��6�$PK8N%[�����0Q;perl5/Alien/Build/Plugin/PkgConfig/LibPkgConf.pmnu��6�$PK8N%[
l7�g
g
0Vo;perl5/Alien/Build/Plugin/PkgConfig/MakeStatic.pmnu��6�$PK8N%[�O*a��1};perl5/Alien/Build/Plugin/PkgConfig/CommandLine.pmnu��6�$PK8N%[�M��'X�;perl5/Alien/Build/Plugin/Probe/Vcpkg.pmnu��6�$PK8N%[�	M�*��;perl5/Alien/Build/Plugin/Probe/CBuilder.pmnu��6�$PK8N%[\1��-*�;perl5/Alien/Build/Plugin/Probe/CommandLine.pmnu��6�$PK8N%[��ٴ  'l�;perl5/Alien/Build/Plugin/Decode/Mojo.pmnu��6�$PK8N%[�> 
33'�;perl5/Alien/Build/Plugin/Decode/HTML.pmnu��6�$PK8N%[�B��

4m<perl5/Alien/Build/Plugin/Decode/DirListingFtpcopy.pmnu��6�$PK8N%[}�gg-�<perl5/Alien/Build/Plugin/Decode/DirListing.pmnu��6�$PK8N%[����%�<perl5/Alien/Build/Plugin/Core/Tail.pmnu��6�$PK8N%[��MUU&�$<perl5/Alien/Build/Plugin/Core/Setup.pmnu��6�$PK8N%[xn;��-hB<perl5/Alien/Build/Plugin/Core/CleanInstall.pmnu��6�$PK8N%[�����)wK<perl5/Alien/Build/Plugin/Core/Override.pmnu��6�$PK8N%[��P���'�R<perl5/Alien/Build/Plugin/Core/Gather.pmnu��6�$PK8N%[�Cb�	�	'�h<perl5/Alien/Build/Plugin/Core/Legacy.pmnu��6�$PK8N%[X�ߕ��)�r<perl5/Alien/Build/Plugin/Core/Download.pmnu��6�$PK8N%[�A]��$�<perl5/Alien/Build/Plugin/Core/FFI.pmnu��6�$PK8N%[s}W;	;	".�<perl5/Alien/Build/Plugin/Probe.podnu��6�$PK8N%[H̻)),��<perl5/Alien/Build/Plugin/Digest/Negotiate.pmnu��6�$PK8N%[���4t	t	(@�<perl5/Alien/Build/Plugin/Digest/SHAPP.pmnu��6�$PK8N%[~Oc�		&�<perl5/Alien/Build/Plugin/Digest/SHA.pmnu��6�$PK8N%[+'$5uu*h�<perl5/Alien/Build/Plugin/Fetch/LocalDir.pmnu��6�$PK9N%[�}T		%7�<perl5/Alien/Build/Plugin/Fetch/LWP.pmnu��6�$PK9N%[{����&��<perl5/Alien/Build/Plugin/Fetch/Wget.pmnu��6�$PK9N%[J4Ԫ� � -��<perl5/Alien/Build/Plugin/Fetch/CurlCommand.pmnu��6�$PK9N%[�׳�'�=perl5/Alien/Build/Plugin/Fetch/Local.pmnu��6�$PK9N%[�t_��*�$=perl5/Alien/Build/Plugin/Fetch/HTTPTiny.pmnu��6�$PK9N%[X;�X��()>=perl5/Alien/Build/Plugin/Fetch/NetFTP.pmnu��6�$PK9N%[Hk����!xT=perl5/Alien/Build/Plugin/Core.podnu��6�$PK9N%[Y����#K]=perl5/Alien/Build/Plugin/Digest.podnu��6�$PK9N%[��j
j
"Yf=perl5/Alien/Build/Plugin/Fetch.podnu��6�$PK9N%[-���E
E
1q=perl5/Alien/Build/Plugin/Gather/IsolateDynamic.pmnu��6�$PK9N%[7j����-�~=perl5/Alien/Build/Plugin/Prefer/BadVersion.pmnu��6�$PK9N%[át���.��=perl5/Alien/Build/Plugin/Prefer/GoodVersion.pmnu��6�$PK9N%[xotrgg/٠=perl5/Alien/Build/Plugin/Prefer/SortVersions.pmnu��6�$PK9N%[�
g�DD��=perl5/Alien/Build/Util.pmnu��6�$PK9N%[�x&�	�	,�=perl5/Alien/Build/Manual.podnu��6�$PK9N%[�J	���=perl5/Alien/Build/Log.pmnu��6�$PK9N%[b'e�		��=perl5/Alien/Role.pmnu��6�$PK9N%[�@{��,�=perl5/Alien/Build.pmnu��6�$PK9N%[���N�>perl5/Alien/Base/Authoring.podnu��6�$PK9N%[�ܖu((��>perl5/Alien/Base/PkgConfig.pmnu��6�$PK9N%[��z3��	?perl5/Alien/Base/FAQ.podnu��6�$PK9N%[���Q�4�4?perl5/Alien/Base/Wrapper.pmnu��6�$PK9N%[(�����6C?perl5/Alien/Util.pmnu��6�$PK9N%[3 D9�r�r"O?perl5/Alien/Base.pmnu��6�$PK9N%[�nP� � /�?perl5/Time/Zone.pmnu��6�$PK9N%[�����?perl5/IO/InnerFile.pmnu��6�$PK9N%[��[|9|9�?perl5/IO/WrapTie.pmnu��6�$PK9N%[�����L�L�8@perl5/IO/HTML.pmnu��6�$PK9N%[��G�JJ��@perl5/IO/Lines.pmnu��6�$PK9N%[l��]?@?@F�@perl5/IO/ScalarArray.pmnu��6�$PK9N%[*�2U"U"��@perl5/IO/Wrap.pmnu��6�$PK9N%[��^�:�:a�@perl5/IO/Scalar.pmnu��6�$PK9N%[���r��W4Aperl5/IO/AtomicFile.pmnu��6�$PK9N%[�h��IAperl5/IO/Stringy.pmnu��6�$PK�U%[�XH���PAdoc/alt-libgd/CONTRIBUTORSnu�[���PK�U%[�z���RAdoc/alt-libgd/README.TXTnu�[���PK�U%[�Y�$��[Adoc/alt-libgd/COPYINGnu�[���PK�U%[i]�Ɂ� �fAdoc/alt-libgd/ChangeLog.historicnu�[���PK�h%[5��߸$�$!̂Adoc/alt-cyrus-sasl/LDAP_SASLAUTHDnu�[���PK�h%[�|8�8�"էAdoc/alt-cyrus-sasl-lib/search.htmlnu�[���PK�h%[ �r�r�&_HBdoc/alt-cyrus-sasl-lib/operations.htmlnu�[���PK�h%[Z��T����!'6Cdoc/alt-cyrus-sasl-lib/index.htmlnu�[���PK�h%[vu,��$XDdoc/alt-cyrus-sasl-lib/genindex.htmlnu�[���PK�h%[K�6���$z7Edoc/alt-cyrus-sasl-lib/download.htmlnu�[���PK�h%[c����!�Fdoc/alt-cyrus-sasl-lib/setup.htmlnu�[���PK�h%[H{����Fdoc/alt-cyrus-sasl-lib/AUTHORSnu�[���PK�h%[���4�4�#/�Fdoc/alt-cyrus-sasl-lib/support.htmlnu�[���PK�h%[.�	��$�hGdoc/alt-cyrus-sasl-lib/packager.htmlnu�[���PK�h%[�R �ÿÿ%
Hdoc/alt-cyrus-sasl-lib/developer.htmlnu�[���PK�h%[�7ll��#3�Hdoc/alt-cyrus-sasl-lib/getsasl.htmlnu�[���PK�h%[��j�$$�vIman/man3/sasl_getrealm_t.3nu�[���PK�h%[^AEE�Iman/man3/sasl_getsimple_t.3nu�[���PK�h%[������Iman/man3/sasl_auxprop_getctx.3nu�[���PK�h%[߱�4�Iman/man3/sasl_encodev.3nu�[���PK�h%[����BBF�Iman/man3/sasl_global_listmech.3nu�[���PK�h%[��T"�	�	׭Iman/man3/sasl_authorize_t.3nu�[���PK�h%[��<���ϷIman/man3/sasl_decode.3nu�[���PK�h%[#��-((�Iman/man3/sasl_auxprop.3nu�[���PK�h%[���Q		b�Iman/man3/sasl_getpath_t.3nu�[���PK�h%[>��8:
:
��Iman/man3/sasl_client_init.3nu�[���PK�h%[;����
�
>Jman/man3/sasl_auxprop_request.3nu�[���PK�h%[
�xxyJman/man3/sasl_verifyfile_t.3nu�[���PK�h%[��mm=Jman/man3/sasl_getopt_t.3nu�[���PK�h%[�]�K���#Jman/man3/sasl_server_start.3nu�[���PK�h%[��6��'�2Jman/man3/sasl_server_userdb_setpass_t.3nu�[���PK�h%[�c�,O
O
@Jman/man3/sasl_getsecret_t.3nu�[���PK�h%["	�����JJman/man3/sasl_setprop.3nu�[���PK�h%[A�ʟSS�WJman/man3/sasl_server_step.3nu�[���PK�h%[�s�M�
�
OdJman/man3/sasl_chalprompt_t.3nu�[���PK�h%[c��j66poJman/man3/sasl_server_new.3nu�[���PK�h%[PVH����Jman/man3/sasl_client_start.3nu�[���PK�h%[E��ePP+�Jman/man3/sasl_idle.3nu�[���PK�h%[�,����Jman/man3/sasl_setpass.3nu�[���PK�h%[�-H��
�
��Jman/man3/sasl_listmech.3nu�[���PK�h%[�		��Jman/man3/sasl_getconfpath_t.3nu�[���PK�h%[�2qrr�Jman/man3/sasl_server_init.3nu�[���PK�h%[��^����Jman/man3/sasl_errdetail.3nu�[���PK�h%[{���ZZ��Jman/man3/sasl_client_step.3nu�[���PK�h%[@ؾ���}�Jman/man3/sasl_client_new.3nu�[���PK�h%[�
����Jman/man3/sasl_errstring.3nu�[���PK�h%[���oo	Kman/man3/sasl_done.3nu�[���PK�h%[��:����	Kman/man3/sasl_canon_user_t.3nu�[���PK�h%[�[�##�Kman/man3/sasl_errors.3nu�[���PK�h%[���55]'Kman/man3/sasl_callbacks.3nu�[���PK�h%[���**�6Kman/man3/sasl_getprop.3nu�[���PK�h%[�tQ.

LEKman/man3/sasl_user_exists.3nu�[���PK�h%[�W��~
~
�OKman/man3/sasl_checkpass.3nu�[���PK�h%[��K�{{kZKman/man3/sasl.3nu�[���PK�h%[�"�%fKman/man3/sasl_encode.3nu�[���PK�h%[�(L�		�tKman/man3/sasl_dispose.3nu�[���PK�h%[�4���)�}Kman/man3/sasl_server_userdb_checkpass_t.3nu�[���PK�h%[V�8��Kman/man3/sasl_checkapop.3nu�[���PK�h%[�z���V�Kman/man3/sasl_log_t.3nu�[���PK�h%[�ƞ�A A �Kman/man8/saslauthd.8nu�[���PK�h%[S
�Ƌ���Kman/man8/testsaslauthd.8nu�[���PK�h%[�KKppw�Kman/man8/saslpasswd2.8nu�[���PK�h%[ήiWW-�Kman/man8/pluginviewer.8nu�[���PK�h%[-�	�	��Kman/man8/sasldblistusers2.8nu�[���PK�h%[�V�]EE#��Klicenses/alt-cyrus-sasl-lib/COPYINGnu�[���PK��I�h�K